ir_deserializer can create a gl_shader structure out of binary data, this will be used by shader binary cache implementation.
Signed-off-by: Tapani Pälli <tapani.pa...@intel.com> --- src/glsl/Makefile.sources | 1 + src/glsl/ir_deserializer.cpp | 979 +++++++++++++++++++++++++++++++++++++++++++ src/glsl/ir_deserializer.h | 142 +++++++ 3 files changed, 1122 insertions(+) create mode 100644 src/glsl/ir_deserializer.cpp create mode 100644 src/glsl/ir_deserializer.h diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources index 5573d00..fd4c15e 100644 --- a/src/glsl/Makefile.sources +++ b/src/glsl/Makefile.sources @@ -33,6 +33,7 @@ LIBGLSL_FILES = \ $(GLSL_SRCDIR)/ir_clone.cpp \ $(GLSL_SRCDIR)/ir_constant_expression.cpp \ $(GLSL_SRCDIR)/ir.cpp \ + $(GLSL_SRCDIR)/ir_deserializer.cpp \ $(GLSL_SRCDIR)/ir_equals.cpp \ $(GLSL_SRCDIR)/ir_expression_flattening.cpp \ $(GLSL_SRCDIR)/ir_function_can_inline.cpp \ diff --git a/src/glsl/ir_deserializer.cpp b/src/glsl/ir_deserializer.cpp new file mode 100644 index 0000000..d1856d7 --- /dev/null +++ b/src/glsl/ir_deserializer.cpp @@ -0,0 +1,979 @@ +/* -*- 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_deserializer.h" +#include "shader_cache_magic.h" + + +/** + * Searches for ir_function with matching signature from exec_list + */ +static ir_function * +search_func(struct _mesa_glsl_parse_state *state, struct exec_list *list, + const char *name, struct exec_list *parameters) +{ + foreach_list_safe(node, list) { + ir_function *func = ((ir_instruction *) node)->as_function(); + if (func && strcmp(name, func->name) == 0 && + func->matching_signature(state, parameters)) + return func; + } + return NULL; +} + +/** + * Helper function to read a list of instructions + */ +int +ir_deserializer::deserialize_list(exec_list *list) +{ + uint32_t list_len = map->read_uint32_t(); + for (unsigned k = 0; k < list_len; k++) + if (read_instruction(list)) + return -1; + return 0; +} + + +/** + * Reads header part of the binary blob. Main purpose of this header is to + * validate that cached shader was produced with same Mesa driver version. + */ +int +ir_deserializer::read_header(struct gl_shader *shader) +{ + char *cache_magic_id = map->read_string(); + char *driver_vendor = map->read_string(); + char *driver_renderer = map->read_string(); + + /* only used or debug output, silence compiler warning */ + (void) driver_vendor; + (void) driver_renderer; + + shader->Version = map->read_uint32_t(); + shader->Type = map->read_uint32_t(); + shader->IsES = map->read_uint8_t(); + + CACHE_DEBUG("%s: version %d, type 0x%x, %s (mesa %s)\n[%s %s]\n", + __func__, shader->Version, shader->Type, + (shader->IsES) ? "glsl es" : "desktop glsl", + cache_magic_id, driver_vendor, driver_renderer); + + const char *magic = mesa_get_shader_cache_magic(); + + if (memcmp(cache_magic_id, magic, strlen(magic))) + return DIFFERENT_MESA_VER; + + /* post-link data */ + shader->num_samplers = map->read_uint32_t(); + shader->active_samplers = map->read_uint32_t(); + shader->shadow_samplers = map->read_uint32_t(); + shader->num_uniform_components = map->read_uint32_t(); + shader->num_combined_uniform_components = map->read_uint32_t(); + shader->uses_builtin_functions = map->read_uint8_t(); + + map->read(&shader->Geom, sizeof(shader->Geom)); + + for (unsigned i = 0; i < MAX_SAMPLERS; i++) + shader->SamplerUnits[i] = map->read_uint8_t(); + + for (unsigned i = 0; i < MAX_SAMPLERS; i++) + shader->SamplerTargets[i] = (gl_texture_index) map->read_int32_t(); + + return 0; +} + + +const glsl_type * +ir_deserializer::read_glsl_type() +{ + char *name = map->read_string(); + uint32_t type_size = map->read_uint32_t(); + + const glsl_type *existing_type = + state->symbols->get_type(name); + + /* if type exists, move read pointer forward and return type */ + if (existing_type) { + map->ffwd(type_size); + return existing_type; + } + + uint8_t base_type = map->read_uint8_t(); + uint32_t length = map->read_uint32_t(); + uint8_t vector_elms = map->read_uint8_t(); + uint8_t matrix_cols = map->read_uint8_t(); + uint8_t interface_packing = map->read_uint8_t(); + + /* array type has additional element_type information */ + if (base_type == GLSL_TYPE_ARRAY) { + const glsl_type *element_type = read_glsl_type(); + if (!element_type) { + CACHE_DEBUG("error reading array element type\n"); + return NULL; + } + return glsl_type::get_array_instance(element_type, length); + } + + /* structures have fields containing of names and types */ + else if (base_type == GLSL_TYPE_STRUCT || + base_type == GLSL_TYPE_INTERFACE) { + glsl_struct_field *fields = ralloc_array(mem_ctx, + glsl_struct_field, length); + + if (!fields) + return glsl_type::error_type; + + for (unsigned k = 0; k < length; k++) { + uint8_t row_major, interpolation, centroid; + int32_t location; + char *field_name = map->read_string(); + fields[k].name = _mesa_strdup(field_name); + fields[k].type = read_glsl_type(); + row_major = map->read_uint8_t(); + location = map->read_int32_t(); + interpolation = map->read_uint8_t(); + centroid = map->read_uint8_t(); + fields[k].row_major = row_major; + fields[k].location = location; + fields[k].interpolation = interpolation; + fields[k].centroid = centroid; + } + + const glsl_type *ret_type = NULL; + + if (base_type == GLSL_TYPE_STRUCT) + ret_type = glsl_type::get_record_instance(fields, length, name); + else if (base_type == GLSL_TYPE_INTERFACE) + ret_type = glsl_type::get_interface_instance(fields, + length, (glsl_interface_packing) interface_packing, name); + + /* free allocated memory */ + for (unsigned k = 0; k < length; k++) + free((void *)fields[k].name); + ralloc_free(fields); + + return ret_type; + } + + return glsl_type::get_instance(base_type, vector_elms, matrix_cols); +} + + +ir_instruction * +ir_deserializer::read_ir_variable() +{ + const glsl_type *type = read_glsl_type(); + + char *name = map->read_string(); + int64_t unique_id = map->read_int64_t(); + uint8_t mode = map->read_uint8_t(); + + ir_variable *var = new(mem_ctx)ir_variable(type, + name, (ir_variable_mode) mode); + + if (!var) + return NULL; + + map->read(&var->data, sizeof(var->data)); + + var->num_state_slots = map->read_uint32_t(); + uint8_t has_constant_value = map->read_uint8_t(); + uint8_t has_constant_initializer = map->read_uint8_t(); + + var->state_slots = NULL; + + if (var->num_state_slots > 0) { + var->state_slots = ralloc_array(var, ir_state_slot, + var->num_state_slots); + + for (unsigned i = 0; i < var->num_state_slots; i++) { + var->state_slots[i].swizzle = map->read_int32_t(); + for (int j = 0; j < 5; j++) { + var->state_slots[i].tokens[j] = map->read_int32_t(); + } + } + } + + if (has_constant_value) + var->constant_value = read_ir_constant(); + + if (has_constant_initializer) + var->constant_initializer = read_ir_constant(); + + uint8_t has_interface_type = map->read_uint8_t(); + + if (has_interface_type) + var->init_interface_type(read_glsl_type()); + + /** + * Store address to this variable so that variable + * dereference readers can find it later. + */ + _mesa_hash_table_insert(var_ht, hash_value, + (void*) (intptr_t) unique_id, var); + + return var; +} + + +ir_instruction * +ir_deserializer::read_ir_function(bool prototypes_only) +{ + uint8_t is_builtin = 0; + uint8_t ir_type; + uint32_t len; + + char *name = map->read_string(); + uint32_t num_signatures = map->read_uint32_t(); + + ir_function *f = new(mem_ctx) ir_function(name); + ir_function_signature *sig = NULL; + + /* add all signatures to the function */ + for (unsigned j = 0; j < num_signatures; j++) { + + /* ir_function_signature */ + ir_type = map->read_uint8_t(); + len = map->read_uint32_t(); + + /* used for debugging */ + (void) ir_type; + (void) len; + + is_builtin = map->read_uint8_t(); + + CACHE_DEBUG("%s: [%s] (is_builtin %d)\n", __func__, name, is_builtin); + + const glsl_type *return_type = read_glsl_type(); + + if (!return_type) { + CACHE_DEBUG("no return type found for [%s]\n", name); + return NULL; + } + + sig = new(mem_ctx) ir_function_signature(return_type); + + /* fill parameters for function signature */ + if (deserialize_list(&sig->parameters)) + goto read_errors; + + /* fill instructions for the function body */ + if (!prototypes_only) { + uint32_t body_count = map->read_uint32_t(); + for (unsigned k = 0; k < body_count; k++) + if (read_instruction(&sig->body, is_builtin ? true : false)) + goto read_errors; + sig->is_defined = body_count ? 1 : 0; + } + + if (!is_builtin) { + f->add_signature(sig); + } else { + ir_function_signature *builtin_sig = + _mesa_glsl_find_builtin_function(state, name, &sig->parameters); + + if (builtin_sig) { + CACHE_DEBUG("found builtin signature for [%s]\n", name); + f->add_signature(sig); + } else { + CACHE_DEBUG("cannot find builtin, function [%s]\n", name); + return NULL; + } + } + + } /* for each function signature */ + + CACHE_DEBUG("added %s function [%s]\n", + is_builtin ? "builtin" : "user", name); + + return f; + +read_errors: + CACHE_DEBUG("%s: read errors with [%s]\n", __func__, name); + if (sig) + ralloc_free(sig); + return NULL; + +} + + +ir_dereference_array * +ir_deserializer::read_ir_dereference_array() +{ + uint8_t ir_type = map->read_uint8_t(); + uint32_t len = map->read_uint32_t(); + + /* used for debugging */ + (void) ir_type; + (void) len; + + CACHE_DEBUG("%s: ir_type %d len %d\n", __func__, ir_type, len); + + ir_rvalue *array_rval = read_ir_rvalue(); + ir_rvalue *index_rval = read_ir_rvalue(); + + if (array_rval && index_rval) + return new(mem_ctx) ir_dereference_array(array_rval, index_rval); + + CACHE_DEBUG("%s: could not get rvalues", __func__); + return NULL; +} + + +ir_dereference_record * +ir_deserializer::read_ir_dereference_record() +{ + uint8_t ir_type = map->read_uint8_t(); + uint32_t len = map->read_uint32_t(); + + /* used for debugging */ + (void) ir_type; + (void) len; + + CACHE_DEBUG("%s: ir_type %d len %d\n", __func__, ir_type, len); + + char *name = map->read_string(); + + ir_rvalue *rval = read_ir_rvalue(); + + if (rval) + return new(mem_ctx) ir_dereference_record(rval, name); + + CACHE_DEBUG("%s: could not get rvalue", __func__); + return NULL; +} + + +/** + * Reads in a variable deref, seeks variable address + * from a map with it's unique_name + */ +ir_dereference_variable * +ir_deserializer::read_ir_dereference_variable() +{ + uint8_t ir_type = map->read_uint8_t(); + uint32_t len = map->read_uint32_t(); + int64_t unique_id = map->read_int64_t(); + + hash_entry *entry = _mesa_hash_table_search(var_ht, hash_value, + (void*) (intptr_t) unique_id); + + /* used for debugging */ + (void) ir_type; + (void) len; + + if (!entry) { + CACHE_DEBUG("%s: could not find variable\n", __func__); + return NULL; + } + + CACHE_DEBUG("%s: found addr %p\n", __func__, entry->data); + + return new(mem_ctx) ir_dereference_variable((ir_variable*) entry->data); +} + + +ir_constant * +ir_deserializer::read_ir_constant() +{ + ir_constant *con = NULL; + uint8_t ir_type = map->read_uint8_t(); + uint32_t len = map->read_uint32_t(); + + /* used for debugging */ + (void) ir_type; + (void) len; + + const glsl_type *constant_type = read_glsl_type(); + + /* data structure */ + ir_constant_data data; + map->read(&data, sizeof(data)); + + con = new(mem_ctx) ir_constant(constant_type, &data); + + /* constant with array of constants */ + if (constant_type->base_type == GLSL_TYPE_ARRAY) { + con->array_elements = ralloc_array(mem_ctx, ir_constant *, + constant_type->length); + + for (unsigned i = 0; i < constant_type->length; i++) + con->array_elements[i] = read_ir_constant(); + + } else if (constant_type->base_type == GLSL_TYPE_STRUCT) { + if (deserialize_list(&con->components)) { + ralloc_free(con); + return NULL; + } + } + + return con; +} + + +ir_swizzle * +ir_deserializer::read_ir_swizzle() +{ + uint8_t ir_type = map->read_uint8_t(); + uint32_t len = map->read_uint32_t(); + + /* used for debugging */ + (void) ir_type; + (void) len; + + CACHE_DEBUG("%s: ir_type %d len %d\n", __func__, + ir_type, len); + + /* swizzle mask, rvalue */ + struct ir_swizzle_mask mask; + map->read(&mask, sizeof(ir_swizzle_mask)); + + ir_rvalue *rval = read_ir_rvalue(); + + if (rval) + return new(mem_ctx) ir_swizzle(rval, + mask.x, mask.y, mask.z, mask.w, mask.num_components); + + CACHE_DEBUG("error, could not handle rvalue for swizzle\n"); + return NULL; +} + + +ir_texture * +ir_deserializer::read_ir_texture() +{ + uint8_t ir_type = map->read_uint8_t(); + uint32_t len = map->read_uint32_t(); + int32_t op = map->read_int32_t(); + + /* used for debugging */ + (void) ir_type; + (void) len; + + CACHE_DEBUG("%s: ir_type %d len %d op %d\n", __func__, ir_type, len, op); + + ir_texture *new_tex = new(mem_ctx) ir_texture((ir_texture_opcode)op); + + const glsl_type * type; + ir_dereference * sampler; + + if (!new_tex) + goto errors; + + type = read_glsl_type(); + sampler = (ir_dereference *) read_ir_rvalue(); + + if (!sampler) + goto errors; + + new_tex->set_sampler(sampler, type); + + new_tex->coordinate = read_ir_rvalue(); + new_tex->projector = read_ir_rvalue(); + new_tex->shadow_comparitor = read_ir_rvalue(); + new_tex->offset = read_ir_rvalue(); + + /* lod_info structure */ + memset(&new_tex->lod_info, 0, sizeof(ir_texture::lod_info)); + + new_tex->lod_info.lod = read_ir_rvalue(); + new_tex->lod_info.bias = read_ir_rvalue(); + new_tex->lod_info.sample_index = read_ir_rvalue(); + new_tex->lod_info.component = read_ir_rvalue(); + new_tex->lod_info.grad.dPdx = read_ir_rvalue(); + new_tex->lod_info.grad.dPdy = read_ir_rvalue(); + + return new_tex; + +errors: + CACHE_DEBUG("error, could not read ir_texture\n"); + return NULL; +} + + +ir_expression * +ir_deserializer::read_ir_expression() +{ + uint8_t ir_type = map->read_uint8_t(); + uint32_t len = map->read_uint32_t(); + + /* used for debugging */ + (void) ir_type; + (void) len; + + CACHE_DEBUG("%s: ir_type %d len %d\n", __func__, ir_type, len); + + /* glsl_type resulted from operation */ + const glsl_type *rval_type = read_glsl_type(); + + /* read operation type + all operands for creating ir_expression */ + uint32_t operation = map->read_uint32_t(); + uint32_t operands = map->read_int32_t(); + + CACHE_DEBUG("%s : operation %d, operands %d\n", + __func__, operation, operands); + + ir_rvalue *ir_rvalue_table[4] = { NULL }; + for (unsigned k = 0; k < operands; k++) { + ir_rvalue *val = read_ir_rvalue(); + + if (!val) + return NULL; + + ir_rvalue_table[k] = val; + } + + return new(mem_ctx) ir_expression(operation, + rval_type, + ir_rvalue_table[0], + ir_rvalue_table[1], + ir_rvalue_table[2], + ir_rvalue_table[3]); +} + + +ir_rvalue * +ir_deserializer::read_ir_rvalue() +{ + uint8_t ir_type = map->read_uint8_t(); + + CACHE_DEBUG("%s: ir_value %d\n", __func__, ir_type); + + switch(ir_type) { + case ir_type_constant: + return read_ir_constant(); + case ir_type_dereference_variable: + return read_ir_dereference_variable(); + case ir_type_dereference_record: + return read_ir_dereference_record(); + case ir_type_dereference_array: + return read_ir_dereference_array(); + case ir_type_expression: + return read_ir_expression(); + case ir_type_swizzle: + return read_ir_swizzle(); + case ir_type_texture: + return read_ir_texture(); + /* type is ir_type_unset ir rvalue is set to NULL */ + case ir_type_unset: + return NULL; + default: + CACHE_DEBUG("%s: error, unhandled type %d\n", + __func__, ir_type); + break; + } + return NULL; +} + + +ir_instruction * +ir_deserializer::read_ir_assignment() +{ + ir_dereference *lhs_deref = NULL; + ir_rvalue *cond = NULL; + + uint32_t write_mask = map->read_uint8_t(); + + lhs_deref = (ir_dereference *) read_ir_rvalue(); + + if (!lhs_deref) { + CACHE_DEBUG("could not find lhs variable, bailing out\n"); + return NULL; + } + + cond = read_ir_rvalue(); + + /* rvalue for assignment */ + ir_rvalue *rval = read_ir_rvalue(); + + /* if we managed to parse rvalue, then we can construct assignment */ + if (rval) + return new(mem_ctx) ir_assignment(lhs_deref, rval, cond, write_mask); + + CACHE_DEBUG("error reading assignment rhs\n"); + return NULL; +} + + +ir_instruction * +ir_deserializer::read_ir_if() +{ + CACHE_DEBUG("%s\n", __func__); + + ir_rvalue *cond = read_ir_rvalue(); + + if (!cond) { + CACHE_DEBUG("%s: error reading condition\n", __func__); + return NULL; + } + + ir_if *irif = new(mem_ctx) ir_if(cond); + + if (deserialize_list(&irif->then_instructions)) + goto read_errors; + if (deserialize_list(&irif->else_instructions)) + goto read_errors; + + return irif; + +read_errors: + CACHE_DEBUG("%s: read errors", __func__); + ralloc_free(irif); + return NULL; +} + + +ir_instruction * +ir_deserializer::read_ir_return() +{ + CACHE_DEBUG("%s\n", __func__); + ir_rvalue *rval = read_ir_rvalue(); + return new(mem_ctx) ir_return(rval); +} + + +/** + * Read a call to ir_function, finds the correct function + * signature from prototypes list and creates the call + */ +ir_instruction * +ir_deserializer::read_ir_call() +{ + struct exec_list parameters; + ir_dereference_variable *return_deref = NULL; + + char *name = map->read_string(); + + return_deref = read_ir_dereference_variable(); + + uint8_t list_len = map->read_uint8_t(); + + CACHE_DEBUG("call to function %s, %d parameters (ret deref %p)\n", + name, list_len, return_deref); + + /* read call parameters */ + for(unsigned k = 0; k < list_len; k++) { + + ir_rvalue *rval = read_ir_rvalue(); + if (rval) { + parameters.push_tail(rval); + } else { + CACHE_DEBUG("%s: error reading rvalue\n", __func__); + return NULL; + } + } + + uint8_t use_builtin = map->read_uint8_t(); + + if (use_builtin) { + ir_function_signature *builtin_sig = + _mesa_glsl_find_builtin_function(state, name, ¶meters); + + if (builtin_sig) { + CACHE_DEBUG("%s: found function %s from builtins\n", __func__, name); + + ir_function_signature *callee = builtin_sig; + + CACHE_DEBUG("function signature for builtin %s : %p\n", name, callee); + if (!callee) { + CACHE_DEBUG("sorry, cannot find signature for builtin ..\n"); + return NULL; + } + + ir_call *call = new(mem_ctx) ir_call(callee, return_deref, + ¶meters); + + call->use_builtin = true; + + return call; + } + } + + /* find the function from the prototypes */ + ir_function *func = search_func(state, prototypes, name, ¶meters); + + if (func) { + CACHE_DEBUG("found function with name %s (has user sig %d)\n", + name, func->has_user_signature()); + + ir_function_signature *callee = func->matching_signature(state, + ¶meters); + + /** + * This is a workaround for a call to empty user defined function, that + * happens with glb2.7 if dumping unlinked shaders, linking would fail + * if we would create a call, empty functions get removed only after + * linking .. this may look a bit strange thing todo but we just ignore + * the call here + */ + if (!callee->is_defined) + return NULL; + + return new(mem_ctx) ir_call(callee, return_deref, ¶meters); + } + + CACHE_DEBUG("%s:function %s not found for ir_call ...\n", + __func__, name); + return NULL; +} + + +ir_instruction * +ir_deserializer::read_ir_discard() +{ + CACHE_DEBUG("%s\n", __func__); + ir_rvalue *condition = read_ir_rvalue(); + return new(mem_ctx) ir_discard(condition); +} + + +ir_instruction * +ir_deserializer::read_ir_loop() +{ + ir_loop *loop = new(mem_ctx) ir_loop; + + if (deserialize_list(&loop->body_instructions)) { + CACHE_DEBUG("%s: read errors\n", __func__); + if (loop) + ralloc_free(loop); + return NULL; + } + + return loop; +} + + +ir_instruction * +ir_deserializer::read_ir_loop_jump() +{ + uint32_t mode = map->read_uint32_t(); + return new(mem_ctx) ir_loop_jump((ir_loop_jump::jump_mode)mode); +} + + +ir_instruction * +ir_deserializer::read_emit_vertex() +{ + return new(mem_ctx) ir_emit_vertex; +} + + +ir_instruction * +ir_deserializer::read_end_primitive() +{ + return new(mem_ctx) ir_end_primitive; +} + + +int +ir_deserializer::read_instruction(struct exec_list *list, bool ignore) +{ + uint8_t ir_type = map->read_uint8_t(); + uint32_t inst_dumpsize = map->read_uint32_t(); + + /* reader wants to jump over this instruction */ + if (ignore) { + map->ffwd(inst_dumpsize); + return 0; + } + + ir_instruction *ir; + + switch(ir_type) { + case ir_type_variable: + ir = read_ir_variable(); + break; + case ir_type_assignment: + ir = read_ir_assignment(); + break; + case ir_type_constant: + ir = read_ir_constant(); + break; + case ir_type_function: + ir = read_ir_function(); + break; + case ir_type_if: + ir = read_ir_if(); + break; + case ir_type_return: + ir = read_ir_return(); + break; + case ir_type_call: + ir = read_ir_call(); + break; + case ir_type_discard: + ir = read_ir_discard(); + break; + case ir_type_loop: + ir = read_ir_loop(); + break; + case ir_type_loop_jump: + ir = read_ir_loop_jump(); + break; + case ir_type_emit_vertex: + ir = read_emit_vertex(); + break; + case ir_type_end_primitive: + ir = read_end_primitive(); + break; + default: + CACHE_DEBUG("%s cannot read type %d, todo...\n", + __func__, ir_type); + return -1; + } + + if (!ir) { + CACHE_DEBUG("%s, failed with %d\n", __func__, ir_type); + return -1; + } + + list->push_tail(ir); + + return 0; +} + + +/** + * Go through the blob and read prototypes for the functions + */ +int +ir_deserializer::read_prototypes(unsigned list_len) +{ + uint32_t ir_start = map->position(); + + for (unsigned k = 0; k < list_len; k++) { + /* peek type of next instruction */ + uint8_t ir_type = map->read_uint8_t(); + uint32_t len = map->read_uint32_t(); + + /* ignore if not ir_function */ + if (ir_type != ir_type_function) { + map->ffwd(len); + continue; + } + + ir_instruction *func = read_ir_function(true); + if (!func) + return -1; + + prototypes->push_tail(func); + } + + /* go back to beginning */ + map->jump(ir_start); + return 0; +} + + +struct gl_shader * +ir_deserializer::deserialize(void *mem_ctx, memory_map *map, + uint32_t shader_size, int *error_code) +{ + int error = 0; + + *error_code = ir_deserializer::GENERAL_READ_ERROR; + + this->map = map; + + uint32_t type = map->read_uint32_t(); + uint32_t exec_list_len; + + GET_CURRENT_CONTEXT(ctx); + struct gl_shader *shader = ctx->Driver.NewShader(NULL, 0, type); + + if (!shader) + return NULL; + + shader->Source = NULL; + shader->Label = NULL; + shader->InfoLog = ralloc_strdup(mem_ctx, ""); + shader->ir = NULL; + + if (read_header(shader)) { + *error_code = ir_deserializer::DIFFERENT_MESA_VER; + goto error_deserialize; + } + + /** + * parse state is used to find builtin functions and + * existing types during reading + */ + state = new(mem_ctx) _mesa_glsl_parse_state(ctx, shader->Type, shader); + + /* fill parse state from shader header information */ + switch (shader->Type) { + case GL_VERTEX_SHADER: + state->target = MESA_SHADER_VERTEX; + break; + case GL_FRAGMENT_SHADER: + state->target = MESA_SHADER_FRAGMENT; + break; + case GL_GEOMETRY_SHADER_ARB: + state->target = MESA_SHADER_GEOMETRY; + break; + } + + state->uses_builtin_functions = true; + _mesa_glsl_initialize_builtin_functions(); + _mesa_glsl_initialize_types(state); + + /* allocations during reading */ + this->mem_ctx = mem_ctx; + + prototypes = new(mem_ctx) exec_list; + shader->ir = new(shader) exec_list; + + exec_list_len = map->read_uint32_t(); + + error = read_prototypes(exec_list_len); + + CACHE_DEBUG("reading %d IR instructions\n", exec_list_len); + + /* top level exec_list read loop, constructs a new list */ + while(map->position() < shader_size && error == 0) + error = read_instruction(shader->ir); + + ralloc_free(prototypes); + + if (error) + goto error_deserialize; + + *error_code = 0; + + shader->CompileStatus = GL_TRUE; + + /* allocates glsl_symbol_table internally */ + populate_symbol_table(shader); + + validate_ir_tree(shader->ir); + + CACHE_DEBUG("shader from cache\n"); + + return shader; + +error_deserialize: + ralloc_free(shader); + return NULL; +} diff --git a/src/glsl/ir_deserializer.h b/src/glsl/ir_deserializer.h new file mode 100644 index 0000000..4f043f5 --- /dev/null +++ b/src/glsl/ir_deserializer.h @@ -0,0 +1,142 @@ +/* -*- 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_DESERIALIZER_H +#define IR_CACHE_DESERIALIZER_H + +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> + +#include "glsl_parser_extras.h" +#include "main/hash_table.h" +#include "main/imports.h" +#include "linker.h" +#include "memory_map.h" + +#ifdef SHADER_CACHE_DEBUG +#define CACHE_DEBUG(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else +#define CACHE_DEBUG(fmt, ...) do {} while (0) +#endif + +#ifdef __cplusplus + +/** + * Class to deserialize gl_shader from a binary data blob + * + * Deserialization is done with a help of memory_map class that takes care + * of actual data reading. Class reads the blob header and checks that this + * blob was created with the same Mesa version we are running on, if this is + * true it continues and creates a gl_shader structure and fills it with all + * IR instructions from the binary blob. + */ +class ir_deserializer +{ +public: + ir_deserializer() : + state(NULL), + mem_ctx(NULL), + map(NULL) + { + var_ht = _mesa_hash_table_create(0, int_equal); + hash_value = _mesa_hash_data(this, sizeof(ir_deserializer)); + } + + ~ir_deserializer() + { + _mesa_hash_table_destroy(var_ht, NULL); + } + + /* unserialize gl_shader from mapped memory */ + struct gl_shader *deserialize(void *mem_ctx, memory_map *map, + uint32_t shader_size, int *error_code); + + enum cache_error { + GENERAL_READ_ERROR = -1, /* read failed, possible bug or data corrupt */ + DIFFERENT_MESA_VER = -2, /* blob created with different mesa */ + DIFFERENT_LANG_VER = -3, /* blob created using different GLSL version */ + }; + +private: + + struct _mesa_glsl_parse_state *state; + void *mem_ctx; + memory_map *map; + + /* pointer to list which contains prototypes of functions */ + struct exec_list *prototypes; + + int read_header(struct gl_shader *shader); + + int read_prototypes(unsigned list_len); + + int read_instruction(struct exec_list *list, bool ignore = false); + + int deserialize_list(struct exec_list *list); + + const glsl_type *read_glsl_type(); + + ir_instruction *read_ir_variable(); + ir_instruction *read_ir_assignment(); + ir_instruction *read_ir_function(bool prototypes_only = false); + ir_instruction *read_ir_if(); + ir_instruction *read_ir_return(); + ir_instruction *read_ir_call(); + ir_instruction *read_ir_discard(); + ir_instruction *read_ir_loop(); + ir_instruction *read_ir_loop_jump(); + ir_instruction *read_emit_vertex(); + ir_instruction *read_end_primitive(); + + /* rvalue readers */ + ir_rvalue *read_ir_rvalue(); + ir_constant *read_ir_constant(); + ir_swizzle *read_ir_swizzle(); + ir_texture *read_ir_texture(); + ir_expression *read_ir_expression(); + ir_dereference_array *read_ir_dereference_array(); + ir_dereference_record *read_ir_dereference_record(); + ir_dereference_variable *read_ir_dereference_variable(); + + /** + * var_ht is used to store created ir_variables with a unique_key for + * each so that ir_dereference_variable creation can find the variable + */ + struct hash_table *var_ht; + uint32_t hash_value; + + static bool int_equal(const void *a, const void *b) + { + return a == b; + } + +}; + + +#endif /* ifdef __cplusplus */ + +#endif /* IR_CACHE_DESERIALIZER_H */ -- 1.8.3.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev