ir_serializer can serialize a gl_shader structure as binary data, will be used by OES_get_program_binary implementation.
Signed-off-by: Tapani Pälli <tapani.pa...@intel.com> --- src/glsl/Makefile.sources | 1 + src/glsl/ir_cache_serializer.cpp | 933 +++++++++++++++++++++++++++++++++++++++ src/glsl/ir_cache_serializer.h | 207 +++++++++ 3 files changed, 1141 insertions(+) create mode 100644 src/glsl/ir_cache_serializer.cpp create mode 100644 src/glsl/ir_cache_serializer.h diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources index 2f7bfa1..0014f6f 100644 --- a/src/glsl/Makefile.sources +++ b/src/glsl/Makefile.sources @@ -30,6 +30,7 @@ LIBGLSL_FILES = \ $(GLSL_SRCDIR)/hir_field_selection.cpp \ $(GLSL_SRCDIR)/ir_basic_block.cpp \ $(GLSL_SRCDIR)/ir_builder.cpp \ + $(GLSL_SRCDIR)/ir_cache_serializer.cpp \ $(GLSL_SRCDIR)/ir_clone.cpp \ $(GLSL_SRCDIR)/ir_constant_expression.cpp \ $(GLSL_SRCDIR)/ir.cpp \ diff --git a/src/glsl/ir_cache_serializer.cpp b/src/glsl/ir_cache_serializer.cpp new file mode 100644 index 0000000..60e1d06 --- /dev/null +++ b/src/glsl/ir_cache_serializer.cpp @@ -0,0 +1,933 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "ir_cache_serializer.h" + + +int +save_glsl_type(memory_writer &blob, const glsl_type *type) +{ + uint32_t ir_len = 666; + + blob.write_string(type->name); + + int32_t start_pos = blob.position(); + blob.write_uint32(&ir_len); + + /* actual glsl_type data */ + uint32_t base_type = type->base_type; + uint32_t length = type->length; + uint8_t vector_elms = type->vector_elements; + uint8_t matrix_cols = type->matrix_columns; + uint8_t sampler_dimensionality = type->sampler_dimensionality; + uint8_t sampler_shadow = type->sampler_shadow; + uint8_t sampler_array = type->sampler_array; + uint8_t sampler_type = type->sampler_type; + uint8_t interface_packing = type->interface_packing; + + blob.write_uint32(&base_type); + blob.write_uint32(&length); + blob.write_uint8(&vector_elms); + blob.write_uint8(&matrix_cols); + blob.write_uint8(&sampler_dimensionality); + blob.write_uint8(&sampler_shadow); + blob.write_uint8(&sampler_array); + blob.write_uint8(&sampler_type); + blob.write_uint8(&interface_packing); + + if (type->base_type == GLSL_TYPE_ARRAY) + save_glsl_type(blob, type->element_type()); + else if (type->base_type == GLSL_TYPE_STRUCT || + type->base_type == GLSL_TYPE_INTERFACE) { + glsl_struct_field *field = type->fields.structure; + for (unsigned k = 0; k < length; k++, field++) { + blob.write_string(field->name); + save_glsl_type(blob, field->type); + uint8_t row_major = field->row_major; + uint8_t interpolation = field->interpolation; + uint8_t centroid = field->centroid; + blob.write_uint8(&row_major); + blob.write_int32(&field->location); + blob.write_uint8(&interpolation); + blob.write_uint8(¢roid); + } + } + + ir_len = blob.position() - start_pos - sizeof(ir_len); + blob.overwrite(&ir_len, sizeof(ir_len), start_pos); + return 0; +} + + +/** + * Function to create an unique string for a ir_variable. This is + * used by variable dereferences to indicate the exact ir_variable + * when deserialization happens. + */ +static char *_unique_name(ir_variable *var) +{ + return ralloc_asprintf(NULL, + "%s_%ld", var->name ? var->name : "parameter", (intptr_t) var); +} + + +int +ir_serializer::save_ir(ir_variable *ir) +{ + /* name can be NULL, see ir_print_visitor for explanation */ + const char *non_null_name = ir->name ? ir->name : "parameter"; + char *uniq = _unique_name(ir); + + save_glsl_type(blob, ir->type); + + blob.write_string(non_null_name); + blob.write_string(uniq); + + uint8_t mode = ir->mode; + uint8_t read_only = ir->read_only; + uint8_t centroid = ir->centroid; + uint8_t invariant = ir->invariant; + uint8_t interpolation = ir->interpolation; + uint8_t origin_upper_left = ir->origin_upper_left; + uint8_t pixel_center_integer = ir->pixel_center_integer; + uint8_t explicit_location = ir->explicit_location; + uint8_t explicit_index = ir->explicit_index; + uint8_t explicit_binding = ir->explicit_binding; + uint8_t has_initializer = ir->has_initializer; + int32_t depth_layout = ir->depth_layout; + uint8_t location_frac = ir->location_frac; + uint8_t has_constant_value = ir->constant_value ? 1 : 0; + uint8_t has_constant_initializer = ir->constant_initializer ? 1 : 0; + + blob.write_uint8(&mode); + blob.write_uint32(&ir->max_array_access); + blob.write_int32(&ir->location); + blob.write_uint8(&read_only); + blob.write_uint8(¢roid); + blob.write_uint8(&invariant); + blob.write_uint8(&interpolation); + blob.write_uint8(&origin_upper_left); + blob.write_uint8(&pixel_center_integer); + blob.write_uint8(&explicit_location); + blob.write_uint8(&explicit_index); + blob.write_uint8(&explicit_binding); + blob.write_uint8(&has_initializer); + blob.write_int32(&depth_layout); + blob.write_uint8(&location_frac); + blob.write_uint32(&ir->num_state_slots); + blob.write_uint8(&has_constant_value); + blob.write_uint8(&has_constant_initializer); + + for (unsigned i = 0; i < ir->num_state_slots; i++) { + blob.write_int32(&ir->state_slots[i].swizzle); + for (unsigned j = 0; j < 5; j++) { + blob.write_int32(&ir->state_slots[i].tokens[j]); + } + } + + CACHE_DEBUG("save ir_variable [%s] [%s]\n", non_null_name, uniq); + + ralloc_free(uniq); + + if (ir->constant_value) + if (save(ir->constant_value)) + return -1; + + if (ir->constant_initializer) + if (save(ir->constant_initializer)) + return -1; + + uint8_t has_interface_type = + ir->is_interface_instance() ? 1 : 0; + + blob.write_uint8(&has_interface_type); + + if (has_interface_type) + save_glsl_type(blob, ir->get_interface_type()); + + return 0; +} + + +int +ir_serializer::save_ir(ir_dereference_array *ir) +{ + uint32_t array_type = ir->array->ir_type; + uint32_t array_index_type = ir->array_index->ir_type; + blob.write_uint32(&array_type); + save(ir->array); + blob.write_uint32(&array_index_type); + return save(ir->array_index); +} + + +int +ir_serializer::save_ir(ir_dereference_record *ir) +{ + uint32_t ir_record_type = ir->record->ir_type; + blob.write_string(ir->field); + blob.write_uint32(&ir_record_type); + return save(ir->record); +} + + +int +ir_serializer::save_ir(ir_dereference_variable *ir) +{ + char *uniq = _unique_name(ir->var); + blob.write_string(uniq); + + CACHE_DEBUG("save ir_dereference_variable [%s]\n", uniq); + + ralloc_free(uniq); + return 0; +} + + +int +ir_serializer::save_ir(ir_constant *ir) +{ + save_glsl_type(blob, ir->type); + + blob.write(&ir->value, sizeof(ir_constant_data)); + + if (ir->array_elements) { + for (unsigned i = 0; i < ir->type->length; i++) + if (save(ir->array_elements[i])) + return -1; + } + + uint32_t components = 0; + + /* struct constant, dump components exec_list */ + if (!ir->components.is_empty()) { + foreach_iter(exec_list_iterator, iter, ir->components) + components++; + blob.write_uint32(&components); + + foreach_iter(exec_list_iterator, iter, ir->components) { + ir_instruction *const inst = (ir_instruction *) iter.get(); + if (save(inst)) + return -1; + } + } + + return 0; +} + + +int +ir_serializer::save_ir(ir_expression *ir) +{ + int32_t num_operands = ir->get_num_operands(); + uint32_t exp_operation = ir->operation; + + save_glsl_type(blob, ir->type); + + blob.write_uint32(&exp_operation); + blob.write_int32(&num_operands); + + /* operand ir_type below is written to make parsing easier */ + for (unsigned i = 0; i < ir->get_num_operands(); i++) { + uint32_t ir_type = ir->operands[i]->ir_type; + blob.write_uint32(&ir_type); + if (save(ir->operands[i])) + return -1; + } + return 0; +} + + +int +ir_serializer::save_ir(ir_function *ir) +{ + uint32_t sig_amount = 0; + + foreach_iter(exec_list_iterator, iter, *ir) + sig_amount++; + + blob.write_string(ir->name); + blob.write_uint32(&sig_amount); + + CACHE_DEBUG("save ir_function [%s], %d sigs\n", ir->name, sig_amount); + + foreach_iter(exec_list_iterator, iter, *ir) { + ir_function_signature *const sig = (ir_function_signature *) iter.get(); + if (save(sig)) + return -1; + } + + return 0; +} + + +int +ir_serializer::save_ir(ir_function_signature *ir) +{ + int32_t par_count = 0; + int32_t body_size = 0; + uint8_t is_builtin = ir->is_builtin(); + + foreach_iter(exec_list_iterator, iter, ir->parameters) + par_count++; + + foreach_iter(exec_list_iterator, iter, ir->body) + body_size++; + + CACHE_DEBUG("signature (%s), returns %d, params %d size %d (builtin %d)\n", + ir->function_name(), ir->return_type->base_type, par_count, + body_size, is_builtin); + + blob.write_int32(&par_count); + blob.write_int32(&body_size); + blob.write_uint8(&is_builtin); + + /* dump the return type of function */ + save_glsl_type(blob, ir->return_type); + + /* function parameters */ + foreach_iter(exec_list_iterator, iter, ir->parameters) { + ir_variable *const inst = (ir_variable *) iter.get(); + CACHE_DEBUG(" parameter %s\n", inst->name); + if (save(inst)) + return -1; + } + + if (prototypes_only) + return 0; + + /* function body */ + foreach_iter(exec_list_iterator, iter, ir->body) { + ir_instruction *const inst = (ir_instruction *) iter.get(); + CACHE_DEBUG(" body instruction node type %d\n", inst->ir_type); + if (save(inst)) + return -1; + } + + return 0; +} + + +int +ir_serializer::save_ir(ir_assignment *ir) +{ + uint32_t write_mask = ir->write_mask; + + blob.write_uint32(&write_mask); + + /* lhs (ir_deference_*) */ + uint32_t lhs_type = ir->lhs->ir_type; + blob.write_uint32(&lhs_type); + + if (save(ir->lhs)) + return -1; + + if (ir->condition) { + CACHE_DEBUG("%s: assignment has condition, not supported", __func__); + } + + /* rhs (constant, expression ...) */ + uint32_t rhs_type = ir->rhs->ir_type; + blob.write_uint32(&rhs_type); + + if (save(ir->rhs)) + return -1; + + return 0; +} + + +int +ir_serializer::save_ir(ir_return *ir) +{ + ir_rvalue *const value = ir->get_value(); + uint8_t has_rvalue = value ? 1 : 0; + + blob.write_uint8(&has_rvalue); + + if (has_rvalue) { + uint32_t ir_type = value->ir_type; + blob.write_uint32(&ir_type); + return save(value); + } + return 0; +} + + +int +ir_serializer::save_ir(ir_swizzle *ir) +{ + uint32_t components = ir->mask.num_components; + const uint32_t mask[4] = { + ir->mask.x, + ir->mask.y, + ir->mask.z, + ir->mask.w + }; + uint32_t val_type = ir->val->ir_type; + + blob.write_uint32(&components); + blob.write(&mask, 4 * sizeof(mask[0])); + blob.write_uint32(&val_type); + + return save(ir->val); +} + + +int +ir_serializer::save_ir(ir_texture *ir) +{ + int32_t op = ir->op; + uint8_t has_coordinate = ir->coordinate ? 1 : 0; + uint8_t has_projector = ir->projector ? 1 : 0; + uint8_t has_shadow_comp = ir->shadow_comparitor ? 1 : 0; + uint8_t has_offset = ir->offset ? 1 : 0; + uint32_t ir_type; + + CACHE_DEBUG("save_ir_texture: op %d, coord %d proj %d shadow %d\n", + op, has_coordinate, has_projector, has_shadow_comp); + + blob.write_int32(&op); + blob.write_uint8(&has_coordinate); + blob.write_uint8(&has_projector); + blob.write_uint8(&has_shadow_comp); + blob.write_uint8(&has_offset); + + save_glsl_type(blob, ir->type); + + /* sampler */ + ir_type = ir->sampler->ir_type; + blob.write_uint32(&ir_type); + if (save(ir->sampler)) + return -1; + + if (has_coordinate) { + ir_type = ir->coordinate->ir_type; + blob.write_uint32(&ir_type); + if (save(ir->coordinate)) + return -1; + } + + if (has_projector) { + ir_type = ir->projector->ir_type; + blob.write_uint32(&ir_type); + if (save(ir->projector)) + return -1; + } + + if (has_shadow_comp) { + ir_type = ir->shadow_comparitor->ir_type; + blob.write_uint32(&ir_type); + if (save(ir->shadow_comparitor)) + return -1; + } + + if (has_offset) { + ir_type = ir->offset->ir_type; + blob.write_uint32(&ir_type); + if (save(ir->offset)) + return -1; + } + + /* lod_info structure */ + uint8_t has_lod = ir->lod_info.lod ? 1 : 0; + uint8_t has_bias = ir->lod_info.bias ? 1 : 0; + uint8_t has_sample_index = ir->lod_info.sample_index ? 1 : 0; + uint8_t has_component = ir->lod_info.component ? 1 : 0; + uint8_t has_dpdx = ir->lod_info.grad.dPdx ? 1 : 0; + uint8_t has_dpdy = ir->lod_info.grad.dPdy ? 1 : 0; + + blob.write_uint8(&has_lod); + blob.write_uint8(&has_bias); + blob.write_uint8(&has_sample_index); + blob.write_uint8(&has_component); + blob.write_uint8(&has_dpdx); + blob.write_uint8(&has_dpdy); + + if (has_lod) + if (save(ir->lod_info.lod)) + return -1; + if (has_bias) + if (save(ir->lod_info.bias)) + return -1; + if (has_sample_index) + if (save(ir->lod_info.sample_index)) + return -1; + if (has_component) + if (save(ir->lod_info.component)) + return -1; + if (has_dpdx) + if (save(ir->lod_info.grad.dPdx)) + return -1; + if (has_dpdy) + if (save(ir->lod_info.grad.dPdy)) + return -1; + + return 0; +} + + +int +ir_serializer::save_ir(ir_discard *ir) +{ + uint8_t has_condition = ir->condition ? 1 : 0; + blob.write_uint8(&has_condition); + + if (ir->condition != NULL) { + CACHE_DEBUG("%s: error, there is no cond support here yet...\n", + __func__); + if (save(ir->condition)) + return -1; + } + + return 0; +} + + +int +ir_serializer::save_ir(ir_call *ir) +{ + blob.write_string(ir->callee_name()); + + uint8_t has_return_deref = ir->return_deref ? 1 : 0; + uint8_t list_len = 0; + uint8_t use_builtin = ir->use_builtin; + + blob.write_uint8(&has_return_deref); + + if (ir->return_deref) + if (save(ir->return_deref)) + return -1; + + /* call parameter list */ + foreach_iter(exec_list_iterator, iter, *ir) + list_len++; + + blob.write_uint8(&list_len); + + foreach_iter(exec_list_iterator, iter, *ir) { + ir_instruction *const inst = (ir_instruction *) iter.get(); + + int32_t ir_type = inst->ir_type; + blob.write_int32(&ir_type); + + if (save(inst)) + return -1; + } + + blob.write_uint8(&use_builtin); + + return 0; +} + + +int +ir_serializer::save_ir(ir_if *ir) +{ + uint32_t then_len = 0, else_len = 0; + uint32_t cond_type = ir->condition->ir_type; + + /* then and else branch lengths */ + foreach_iter(exec_list_iterator, iter, ir->then_instructions) + then_len++; + foreach_iter(exec_list_iterator, iter, ir->else_instructions) + else_len++; + + blob.write_uint32(&then_len); + blob.write_uint32(&else_len); + blob.write_uint32(&cond_type); + + CACHE_DEBUG("dump ir_if (then %d else %d), condition ir_type %d\n", + then_len, else_len, ir->condition->ir_type); + + save(ir->condition); + + /* dump branch instruction lists */ + foreach_iter(exec_list_iterator, iter, ir->then_instructions) { + ir_instruction *const inst = (ir_instruction *) iter.get(); + CACHE_DEBUG(" ir_if then instruction node type %d\n", inst->ir_type); + if (save(inst)) + return -1; + } + + foreach_iter(exec_list_iterator, iter, ir->else_instructions) { + ir_instruction *const inst = (ir_instruction *) iter.get(); + CACHE_DEBUG(" ir_if else instruction node type %d\n", inst->ir_type); + if (save(inst)) + return -1; + } + + return 0; +} + + +int +ir_serializer::save_ir(ir_loop *ir) +{ + uint8_t has_counter = ir->counter ? 1 : 0; + uint8_t has_from = ir->from ? 1 : 0; + uint8_t has_to = ir->to ? 1 : 0; + uint8_t has_incr = ir->increment ? 1 : 0; + uint32_t body_size = 0; + uint32_t ir_type; + + foreach_iter(exec_list_iterator, iter, ir->body_instructions) + body_size++; + + blob.write_uint8(&has_from); + blob.write_uint8(&has_to); + blob.write_uint8(&has_incr); + blob.write_uint8(&has_counter); + blob.write_int32(&ir->cmp); + blob.write_uint32(&body_size); + + if (has_from) { + ir_type = ir->from->ir_type; + blob.write_uint32(&ir_type); + if (save(ir->from)) + return -1; + } + + if (has_to) { + ir_type = ir->to->ir_type; + blob.write_uint32(&ir_type); + if (save(ir->to)) + return -1; + } + + if (has_incr) { + ir_type = ir->increment->ir_type; + blob.write_uint32(&ir_type); + if (save(ir->increment)) + return -1; + } + + if (has_counter) { + blob.write_string(ir->counter->name); + if (save(ir->counter)) + return -1; + } + + foreach_iter(exec_list_iterator, iter, ir->body_instructions) { + ir_instruction *const inst = (ir_instruction *) iter.get(); + CACHE_DEBUG("save loop instruction type %d\n", inst->ir_type); + if (save(inst)) + return -1; + } + + return 0; +} + + +int ir_serializer::save_ir(ir_loop_jump *ir) +{ + uint32_t mode = ir->mode; + return blob.write_uint32(&mode); +} + + +int +ir_serializer::save_ir(ir_emit_vertex *ir) +{ + return 0; +} + + +int +ir_serializer::save_ir(ir_end_primitive *ir) +{ + return 0; +} + + +/** + * writes instruction type, packet size and calls + * save function for the instruction to save the data + */ +int +ir_serializer::save(ir_instruction *ir) +{ + uint32_t ir_len = 666; + uint32_t ir_type = ir->ir_type; + + blob.write_uint32(&ir_type); + + int32_t start_pos = blob.position(); + + blob.write_uint32(&ir_len); + +#define SAVE_IR(type)\ + if (save_ir(static_cast<type *>(ir))) goto write_errors; + + switch(ir->ir_type) { + + case ir_type_variable: + SAVE_IR(ir_variable); + break; + case ir_type_call: + SAVE_IR(ir_call); + break; + case ir_type_constant: + SAVE_IR(ir_constant); + break; + case ir_type_discard: + SAVE_IR(ir_discard); + break; + case ir_type_expression: + SAVE_IR(ir_expression); + break; + case ir_type_dereference_array: + SAVE_IR(ir_dereference_array); + break; + case ir_type_dereference_record: + SAVE_IR(ir_dereference_record); + break; + case ir_type_dereference_variable: + SAVE_IR(ir_dereference_variable); + break; + case ir_type_function: + SAVE_IR(ir_function); + break; + case ir_type_function_signature: + SAVE_IR(ir_function_signature); + break; + case ir_type_swizzle: + SAVE_IR(ir_swizzle); + break; + case ir_type_texture: + SAVE_IR(ir_texture); + break; + case ir_type_assignment: + SAVE_IR(ir_assignment); + break; + case ir_type_if: + SAVE_IR(ir_if); + break; + case ir_type_loop: + SAVE_IR(ir_loop); + break; + case ir_type_loop_jump: + SAVE_IR(ir_loop_jump); + break; + case ir_type_return: + SAVE_IR(ir_return); + break; + case ir_type_emit_vertex: + SAVE_IR(ir_emit_vertex); + break; + case ir_type_end_primitive: + SAVE_IR(ir_end_primitive); + break; + + default: + CACHE_DEBUG("%s: error, type %d not implemented\n", + __func__, ir->ir_type); + return -1; + } + + ir_len = blob.position() - start_pos - sizeof(ir_len); + + blob.overwrite(&ir_len, sizeof(ir_len), start_pos); + + return 0; + +write_errors: + CACHE_DEBUG("%s: write errors (ir type %d)\n", __func__, ir->ir_type); + return -1; +} + + +static void +_write_header(gl_shader *shader, const char *mesa_sha, memory_writer &blob) +{ + GET_CURRENT_CONTEXT(ctx); + + blob.write_string(mesa_sha); + blob.write_string((const char *)ctx->Driver.GetString(ctx, GL_VENDOR)); + blob.write_string((const char *)ctx->Driver.GetString(ctx, GL_RENDERER)); + blob.write_uint32(&shader->Version); + blob.write_uint32(&shader->Type); + blob.write_uint8(&shader->IsES); + + /* post-link data */ + blob.write_uint32(&shader->num_samplers); + blob.write_uint32(&shader->active_samplers); + blob.write_uint32(&shader->shadow_samplers); + blob.write_uint32(&shader->num_uniform_components); + blob.write_uint32(&shader->num_combined_uniform_components); + + for (unsigned i = 0; i < MAX_SAMPLERS; i++) + blob.write_uint8(&shader->SamplerUnits[i]); + + for (unsigned i = 0; i < MAX_SAMPLERS; i++) { + int32_t target = shader->SamplerTargets[i]; + blob.write_int32(&target); + } +} + + +static void +_dump_bool(bool value, memory_writer &blob) +{ + uint8_t val = value; + blob.write_uint8(&val); +} + + +/** + * some of the state such as extension bits is required from + * the preprocessing stage, this is when caching unlinked shaders + */ +static void +_write_state(struct _mesa_glsl_parse_state *state, memory_writer &blob) +{ + blob.write_uint32(&state->language_version); + + _dump_bool(state->ARB_draw_buffers_enable, blob); + _dump_bool(state->ARB_draw_buffers_warn, blob); + _dump_bool(state->ARB_draw_instanced_enable, blob); + _dump_bool(state->ARB_draw_instanced_warn, blob); + _dump_bool(state->ARB_explicit_attrib_location_enable, blob); + _dump_bool(state->ARB_explicit_attrib_location_warn, blob); + _dump_bool(state->ARB_fragment_coord_conventions_enable, blob); + _dump_bool(state->ARB_fragment_coord_conventions_warn, blob); + _dump_bool(state->ARB_texture_rectangle_enable, blob); + _dump_bool(state->ARB_texture_rectangle_warn, blob); + _dump_bool(state->EXT_texture_array_enable, blob); + _dump_bool(state->EXT_texture_array_warn, blob); + _dump_bool(state->ARB_shader_texture_lod_enable, blob); + _dump_bool(state->ARB_shader_texture_lod_warn, blob); + _dump_bool(state->ARB_shader_stencil_export_enable, blob); + _dump_bool(state->ARB_shader_stencil_export_warn, blob); + _dump_bool(state->AMD_conservative_depth_enable, blob); + _dump_bool(state->AMD_conservative_depth_warn, blob); + _dump_bool(state->ARB_conservative_depth_enable, blob); + _dump_bool(state->ARB_conservative_depth_warn, blob); + _dump_bool(state->AMD_shader_stencil_export_enable, blob); + _dump_bool(state->AMD_shader_stencil_export_warn, blob); + _dump_bool(state->OES_texture_3D_enable, blob); + _dump_bool(state->OES_texture_3D_warn, blob); + _dump_bool(state->OES_EGL_image_external_enable, blob); + _dump_bool(state->OES_EGL_image_external_warn, blob); + _dump_bool(state->ARB_shader_bit_encoding_enable, blob); + _dump_bool(state->ARB_shader_bit_encoding_warn, blob); + _dump_bool(state->ARB_uniform_buffer_object_enable, blob); + _dump_bool(state->ARB_uniform_buffer_object_warn, blob); + _dump_bool(state->OES_standard_derivatives_enable, blob); + _dump_bool(state->OES_standard_derivatives_warn, blob); + _dump_bool(state->ARB_texture_cube_map_array_enable, blob); + _dump_bool(state->ARB_texture_cube_map_array_warn, blob); + _dump_bool(state->ARB_shading_language_packing_enable, blob); + _dump_bool(state->ARB_shading_language_packing_warn, blob); + _dump_bool(state->ARB_texture_multisample_enable, blob); + _dump_bool(state->ARB_texture_multisample_warn, blob); + _dump_bool(state->ARB_texture_query_lod_enable, blob); + _dump_bool(state->ARB_texture_query_lod_warn, blob); + _dump_bool(state->ARB_gpu_shader5_enable, blob); + _dump_bool(state->ARB_gpu_shader5_warn, blob); + _dump_bool(state->AMD_vertex_shader_layer_enable, blob); + _dump_bool(state->AMD_vertex_shader_layer_warn, blob); + _dump_bool(state->ARB_shading_language_420pack_enable, blob); + _dump_bool(state->ARB_shading_language_420pack_warn, blob); + _dump_bool(state->EXT_shader_integer_mix_enable, blob); + _dump_bool(state->EXT_shader_integer_mix_warn, blob); +} + + +/** + * serializes a single gl_shader, writes shader header + * information and exec_list of instructions + */ +char * +ir_serializer::serialize(struct gl_shader *shader, + struct _mesa_glsl_parse_state *state, + const char *mesa_sha, size_t *size) +{ + uint32_t total = 0; + + prototypes_only = true; + + *size = 0; + + int32_t start_pos = blob.position(); + uint32_t shader_data_len = 666; + uint32_t shader_type = shader->Type; + + blob.write_uint32(&shader_data_len); + blob.write_uint32(&shader_type); + + _write_header(shader, mesa_sha, blob); + + if (state) + _write_state(state, blob); + + /* count variables + functions and dump prototypes */ + foreach_list_const(node, shader->ir) { + if (((ir_instruction *) node)->as_variable()) + total++; + if (((ir_instruction *) node)->as_function()) + total++; + } + + blob.write_uint32(&total); + + CACHE_DEBUG("write %d prototypes\n", total); + + foreach_list_const(node, shader->ir) { + ir_instruction *const inst = (ir_instruction *) node; + if (inst->as_variable()) + if (save(inst)) + goto write_errors; + } + + foreach_list_const(node, shader->ir) { + ir_instruction *const inst = (ir_instruction *) node; + if (inst->as_function()) + if (save(inst)) + goto write_errors; + } + + /* all shader instructions */ + prototypes_only = false; + foreach_list_const(node, shader->ir) { + ir_instruction *instruction = (ir_instruction *) node; + if (save(instruction)) + goto write_errors; + } + + CACHE_DEBUG("cached a shader\n"); + + /* how much has been written */ + *size = blob.position(); + + shader_data_len = blob.position() - + start_pos - sizeof(shader_data_len); + blob.overwrite(&shader_data_len, sizeof(shader_data_len), start_pos); + + return blob.release_memory(size); + +write_errors: + + return NULL; +} diff --git a/src/glsl/ir_cache_serializer.h b/src/glsl/ir_cache_serializer.h new file mode 100644 index 0000000..6e33ca9 --- /dev/null +++ b/src/glsl/ir_cache_serializer.h @@ -0,0 +1,207 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef IR_CACHE_SERIALIZER_H +#define IR_CACHE_SERIALIZER_H + +#include "ir.h" +#include "glsl_parser_extras.h" + +#ifdef SHADER_CACHE_DEBUG +#define CACHE_DEBUG(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else +#define CACHE_DEBUG(fmt, ...) do {} while (0) +#endif + +#ifdef __cplusplus +/** + * Helper class for writing data to memory + * + * This class maintains a dynamically-sized memory buffer and allows + * for data to be efficiently appended to it with automatic resizing. + */ +class memory_writer +{ +public: + memory_writer() : + memory(NULL), + curr_size(0), + pos(0) {} + + ~memory_writer() + { + free(memory); + } + + /* user wants to claim the memory */ + char *release_memory(size_t *size) + { + /* final realloc to free allocated but unused memory */ + char *result = (char *) realloc(memory, pos); + memory = NULL; + curr_size = 0; + pos = 0; + return result; + } + + /* write functions for different data types */ + int write_uint8(uint8_t *data) + { + return write(data, sizeof(uint8_t)); + } + int write_int32(int32_t *data) + { + return write(data, sizeof(int32_t)); + } + int write_uint32(uint32_t *data) + { + return write(data, sizeof(uint32_t)); + } + + /* write function that reallocates more memory if required */ + int write(const void *data, int32_t size) + { + if (!memory || pos > (int32_t)(curr_size - size)) + if (grow(size)) + return -1; + + memcpy(memory + pos, data, size); + + pos += size; + return 0; + } + + int overwrite(const void *data, int32_t size, int32_t offset) + { + if (offset < 0 || offset + size > pos) + return -1; + memcpy(memory + offset, data, size); + return 0; + } + + int write_string(const char *str) + { + if (!str) + return -1; + char terminator = '\0'; + write(str, strlen(str)); + write(&terminator, 1); + return 0; + } + + inline int32_t position() { return pos; } + +private: + + /* reallocate more memory */ + int grow(int32_t size) + { + int32_t new_size = 2 * (curr_size + size); + char *more_mem = (char *) realloc(memory, new_size); + if (more_mem == NULL) { + free(memory); + memory = NULL; + return -1; + } else { + memory = more_mem; + curr_size = new_size; + return 0; + } + } + + /* allocated memory */ + char *memory; + + /* current size of the whole allocation */ + int32_t curr_size; + + /* write position / size of the data written */ + int32_t pos; +}; + + +/** + * Utility function used both by ir_serializer and + * gl_shader_program structure serialization code + */ +int save_glsl_type(memory_writer &blob, const glsl_type *type); + +/** + * Class to serialize gl_shader as a binary data blob + * + * Serialization is done by writing small header data section, parser + * state data and all IR instructions of the shader including any relevant + * data to be able to deserialize them back. + */ +class ir_serializer +{ +public: + ir_serializer() : + prototypes_only(false) + { + } + + /* serialize gl_shader to memory */ + char *serialize(struct gl_shader *shader, + struct _mesa_glsl_parse_state *state, + const char *mesa_sha, size_t *size); + +private: + + memory_writer blob; + + bool prototypes_only; + + /** + * writes ir_type and instruction dump size as a 'header' + * for each instruction before calling save_ir with it + */ + int save(ir_instruction *ir); + + /* methods for each ir type */ + int save_ir(ir_variable *ir); + int save_ir(ir_assignment *ir); + int save_ir(ir_call *ir); + int save_ir(ir_constant *ir); + int save_ir(ir_dereference_array *ir); + int save_ir(ir_dereference_record *ir); + int save_ir(ir_dereference_variable *ir); + int save_ir(ir_discard *ir); + int save_ir(ir_expression *ir); + int save_ir(ir_function *ir); + int save_ir(ir_function_signature *ir); + int save_ir(ir_if *ir); + int save_ir(ir_loop *ir); + int save_ir(ir_loop_jump *ir); + int save_ir(ir_return *ir); + int save_ir(ir_swizzle *ir); + int save_ir(ir_texture *ir); + int save_ir(ir_emit_vertex *ir); + int save_ir(ir_end_primitive *ir); + +}; +#endif /* ifdef __cplusplus */ + +#endif /* IR_CACHE_SERIALIZER_H */ -- 1.8.1.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev