[Mesa-dev] [wip 6/9] glsl: ir_deserializer class for the binary shader cache
Tapani Pälli
tapani.palli at intel.com
Thu Jan 2 03:58:18 PST 2014
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.palli at 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
More information about the mesa-dev
mailing list