[Mesa-dev] [v2 4/6] glsl: ir_deserializer class for the shader cache

Tapani Pälli tapani.palli at intel.com
Fri Nov 1 02:16:25 PDT 2013


ir_deserializer can create a gl_shader structure out of binary
data from ir_serializer, will be used by OES_get_program_binary
implementation.

Signed-off-by: Tapani Pälli <tapani.palli at intel.com>
---
 src/glsl/Makefile.sources          |    1 +
 src/glsl/ir_cache_deserializer.cpp | 1341 ++++++++++++++++++++++++++++++++++++
 src/glsl/ir_cache_deserializer.h   |  301 ++++++++
 3 files changed, 1643 insertions(+)
 create mode 100644 src/glsl/ir_cache_deserializer.cpp
 create mode 100644 src/glsl/ir_cache_deserializer.h

diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources
index 0014f6f..81d5753 100644
--- a/src/glsl/Makefile.sources
+++ b/src/glsl/Makefile.sources
@@ -31,6 +31,7 @@ LIBGLSL_FILES = \
 	$(GLSL_SRCDIR)/ir_basic_block.cpp \
 	$(GLSL_SRCDIR)/ir_builder.cpp \
 	$(GLSL_SRCDIR)/ir_cache_serializer.cpp \
+	$(GLSL_SRCDIR)/ir_cache_deserializer.cpp \
 	$(GLSL_SRCDIR)/ir_clone.cpp \
 	$(GLSL_SRCDIR)/ir_constant_expression.cpp \
 	$(GLSL_SRCDIR)/ir.cpp \
diff --git a/src/glsl/ir_cache_deserializer.cpp b/src/glsl/ir_cache_deserializer.cpp
new file mode 100644
index 0000000..a671df8
--- /dev/null
+++ b/src/glsl/ir_cache_deserializer.cpp
@@ -0,0 +1,1341 @@
+/* -*- 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_deserializer.h"
+
+/**
+ * Searches for ir_variable from given exec_list
+ */
+static ir_variable *
+search_var(struct exec_list *list, const char *name)
+{
+   foreach_list_safe(node, list) {
+      ir_variable *var = ((ir_instruction *) node)->as_variable();
+      if (var && strcmp(name, var->name) == 0)
+         return var;
+   }
+   return NULL;
+}
+
+/**
+ * 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;
+}
+
+
+/**
+ * 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, memory_map &map,
+   const char *mesa_sha)
+{
+   char *cache_mesa_sha = 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;
+
+   map.read(&shader->Version);
+   map.read(&shader->Type);
+   map.read(&shader->IsES);
+
+   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_mesa_sha, driver_vendor, driver_renderer);
+
+   int error = memcmp(cache_mesa_sha, mesa_sha, strlen(mesa_sha));
+   if (error)
+      return error;
+
+   /* post-link data */
+   map.read(&shader->num_samplers);
+   map.read(&shader->active_samplers);
+   map.read(&shader->shadow_samplers);
+   map.read(&shader->num_uniform_components);
+   map.read(&shader->num_combined_uniform_components);
+
+   for (unsigned i = 0; i < MAX_SAMPLERS; i++)
+      map.read(&shader->SamplerUnits[i]);
+
+   for (unsigned i = 0; i < MAX_SAMPLERS; i++)
+      map.read(&shader->SamplerTargets[i]);
+
+   return 0;
+}
+
+
+const glsl_type *
+ir_deserializer::read_glsl_type(memory_map &map,
+   struct _mesa_glsl_parse_state *_state)
+{
+   uint32_t type_size;
+
+   char *name = map.read_string();
+   map.read(&type_size);
+
+   const glsl_type *type_exists = NULL;
+
+   if (_state && _state->symbols)
+      type_exists = _state->symbols->get_type(name);
+
+   /* if type exists, move read pointer forward and return type */
+   if (type_exists) {
+      map.ffwd(type_size);
+      return type_exists;
+   }
+
+   uint32_t base_type;
+   uint32_t length;
+   uint8_t vector_elms;
+   uint8_t matrix_cols;
+   uint8_t sampler_dimensionality;
+   uint8_t sampler_shadow;
+   uint8_t sampler_array;
+   uint8_t sampler_type;
+   uint8_t interface_packing;
+
+   map.read(&base_type);
+   map.read(&length);
+   map.read(&vector_elms);
+   map.read(&matrix_cols);
+   map.read(&sampler_dimensionality);
+   map.read(&sampler_shadow);
+   map.read(&sampler_array);
+   map.read(&sampler_type);
+   map.read(&interface_packing);
+
+   if (base_type == GLSL_TYPE_SAMPLER) {
+
+      switch(sampler_dimensionality) {
+      case 0:
+         return glsl_type::sampler1D_type;
+      case 1:
+         return glsl_type::sampler2D_type;
+      case 2:
+         return glsl_type::sampler3D_type;
+      case 3:
+         return glsl_type::samplerCube_type;
+      default:
+         CACHE_DEBUG("%s: unknown sampler type (dim %d)\n",
+                     __func__, sampler_dimensionality);
+      }
+   }
+
+   /* array type has additional element_type information */
+   else if (base_type == GLSL_TYPE_ARRAY) {
+      const glsl_type *element_type = read_glsl_type(map, state);
+      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);
+      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(map, state);
+         map.read(&row_major);
+         map.read(&location);
+         map.read(&interpolation);
+         map.read(&centroid);
+         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);
+}
+
+
+int
+ir_deserializer::read_ir_variable(struct exec_list *list, memory_map &map)
+{
+   const glsl_type *type = read_glsl_type(map, state);
+
+   char *name = map.read_string();
+   char *unique_name = map.read_string();
+
+   uint8_t mode;
+   map.read(&mode);
+
+   ir_variable *var = new(mem_ctx)ir_variable(type,
+      name, (ir_variable_mode) mode);
+
+   if (!var)
+      return -1;
+
+   uint8_t read_only;
+   uint8_t centroid;
+   uint8_t invariant;
+   uint8_t interpolation;
+   uint8_t origin_upper_left;
+   uint8_t pixel_center_integer;
+   uint8_t explicit_location;
+   uint8_t explicit_index;
+   uint8_t explicit_binding;
+   uint8_t has_initializer;
+   int32_t depth_layout;
+   uint8_t location_frac;
+   uint8_t has_constant_value;
+   uint8_t has_constant_initializer;
+
+   map.read(&var->max_array_access);
+   map.read(&var->location);
+   map.read(&read_only);
+   map.read(&centroid);
+   map.read(&invariant);
+   map.read(&interpolation);
+   map.read(&origin_upper_left);
+   map.read(&pixel_center_integer);
+   map.read(&explicit_location);
+   map.read(&explicit_index);
+   map.read(&explicit_binding);
+   map.read(&has_initializer);
+   map.read(&depth_layout);
+   map.read(&location_frac);
+   map.read(&var->num_state_slots);
+   map.read(&has_constant_value);
+   map.read(&has_constant_initializer);
+
+   var->read_only = read_only;
+   var->centroid = centroid;
+   var->invariant = invariant;
+   var->interpolation = interpolation;
+   var->origin_upper_left = origin_upper_left;
+   var->pixel_center_integer = pixel_center_integer;
+   var->depth_layout = (ir_depth_layout) depth_layout;
+   var->has_initializer = has_initializer;
+   var->location_frac = location_frac;
+
+
+   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++) {
+         map.read(&var->state_slots[i].swizzle);
+         for (int j = 0; j < 5; j++) {
+            map.read(&var->state_slots[i].tokens[j]);
+         }
+      }
+   }
+
+   if (has_constant_value)
+      var->constant_value = read_ir_constant(map);
+
+   if (has_constant_initializer)
+      var->constant_initializer = read_ir_constant(map);
+
+   uint8_t has_interface_type;
+   map.read(&has_interface_type);
+
+   if (has_interface_type)
+      var->init_interface_type(read_glsl_type(map, state));
+
+   /**
+    * Store address to this variable so that variable
+    * dereference readers can find it later.
+    */
+   hash_store(var, unique_name);
+
+   list->push_tail(var);
+
+   return 0;
+}
+
+
+int
+ir_deserializer::read_ir_function(struct exec_list *list, memory_map &map)
+{
+   int32_t par_count = 0;
+   int32_t body_count = 0;
+   uint8_t is_builtin = 0;
+   uint32_t ir_type;
+   uint32_t len;
+   uint32_t sig_amount;
+
+   char *name = map.read_string();
+   map.read(&sig_amount);
+
+   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 < sig_amount; j++) {
+
+      /* ir_function_signature */
+      map.read(&ir_type);
+      map.read(&len);
+
+      if (ir_type != ir_type_function_signature) {
+         CACHE_DEBUG("cache format error with function %s\n", name);
+         return -1;
+      }
+
+      map.read(&par_count);
+      map.read(&body_count);
+      map.read(&is_builtin);
+
+      CACHE_DEBUG("%s: [%s] %d parameters, body size %d (is_builtin %d)\n",
+                  __func__, name, par_count, body_count, is_builtin);
+
+      const glsl_type *return_type = read_glsl_type(map, state);
+
+      if (!return_type) {
+         CACHE_DEBUG("no return type found for [%s]\n", name);
+         return -1;
+      }
+
+      sig = new(mem_ctx) ir_function_signature(return_type);
+
+      /* fill parameters for function signature */
+      for (int k = 0; k < par_count; k++)
+         if (read_instruction(&sig->parameters, map))
+            goto read_errors;
+
+      /* insert function parameter variables to prototypes list ... */
+      foreach_list_const(node, &sig->parameters) {
+         ir_variable *var = ((ir_instruction *) node)->as_variable();
+         if (var)
+            prototypes->push_tail(var->clone(mem_ctx, NULL));
+      }
+
+      current_function = &sig->body;
+
+      /* fill instructions for the function body */
+      if (!prototypes_only)
+         for (int k = 0; k < body_count; k++)
+            if (read_instruction(&sig->body, map, 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 -1;
+         }
+      }
+
+   } /* for each function signature */
+
+   CACHE_DEBUG("added %s function [%s]\n",
+               is_builtin ? "builtin" : "user", name);
+
+   /* push ready function to the IR exec_list */
+   list->push_tail(f);
+
+   return 0;
+
+read_errors:
+   CACHE_DEBUG("%s: read errors with [%s]\n", __func__, name);
+   if (sig)
+      ralloc_free(sig);
+   return -1;
+
+}
+
+
+ir_dereference_array *
+ir_deserializer::read_ir_dereference_array(memory_map &map)
+{
+   uint32_t ir_type;
+   uint32_t len;
+
+   CACHE_DEBUG("%s\n", __func__);
+
+   map.read(&ir_type);
+   map.read(&len);
+
+   ir_rvalue *array_rval = read_ir_rvalue(map);
+   ir_rvalue *index_rval = read_ir_rvalue(map);
+
+   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(memory_map &map)
+{
+   uint32_t ir_type;
+   uint32_t len;
+
+   CACHE_DEBUG("%s\n", __func__);
+
+   map.read(&ir_type);
+   map.read(&len);
+   char *name = map.read_string();
+
+   ir_rvalue *rval = read_ir_rvalue(map);
+
+   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(memory_map &map)
+{
+   uint32_t ir_type;
+   uint32_t len;
+
+   map.read(&ir_type);
+   map.read(&len);
+   char *unique_name = map.read_string();
+
+   const void *addr = hash_table_find(var_ht, (const void *) unique_name);
+
+   CACHE_DEBUG("found addr %p with name %s\n", addr, unique_name);
+
+   if (addr != 0) {
+      ir_variable *var = (ir_variable*) addr;
+      return new(mem_ctx) ir_dereference_variable(var);
+   }
+
+   CACHE_DEBUG("%s: could not find [%s]\n", __func__, unique_name);
+   return NULL;
+}
+
+
+ir_constant *
+ir_deserializer::read_ir_constant(memory_map &map, struct exec_list *list)
+{
+   ir_constant *con = NULL;
+   uint32_t ir_type;
+   uint32_t len;
+
+   map.read(&ir_type);
+   map.read(&len);
+
+   const glsl_type *constant_type = read_glsl_type(map, state);
+
+   /* 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(map);
+
+      goto read_return;
+   }
+
+   else if (constant_type->base_type == GLSL_TYPE_STRUCT) {
+      uint32_t components;
+      map.read(&components);
+      for (unsigned i = 0; i < components; i++)
+         if (read_instruction(&con->components, map))
+            goto read_errors;
+   }
+
+read_return:
+   if (list)
+      list->push_tail(con);
+
+   return con;
+
+read_errors:
+   ralloc_free(con);
+   return NULL;
+}
+
+
+ir_swizzle *
+ir_deserializer::read_ir_swizzle(memory_map &map)
+{
+   uint32_t swiz[4] = { 0 };
+   uint32_t count;
+   uint32_t ir_type;
+   uint32_t len;
+
+   CACHE_DEBUG("%s\n", __func__);
+
+   map.read(&ir_type);
+   map.read(&len);
+
+   /* num of components + swizzle mask, rvalue */
+   map.read(&count);
+   map.read(swiz, 4 * sizeof(uint32_t));
+
+   ir_rvalue *rval = read_ir_rvalue(map);
+
+   if (rval)
+      return new(mem_ctx) ir_swizzle(rval, swiz, count);
+
+   CACHE_DEBUG("error, could not handle rvalue for swizzle\n");
+   return NULL;
+}
+
+
+ir_texture *
+ir_deserializer::read_ir_texture(memory_map &map)
+{
+   uint32_t ir_type;
+   uint32_t len;
+   int32_t op;
+   uint8_t has_coordinate;
+   uint8_t has_projector;
+   uint8_t has_shadow_comp;
+   uint8_t has_offset;
+   const glsl_type *type = NULL;
+   ir_dereference *sampler = NULL;
+
+   map.read(&ir_type);
+   map.read(&len);
+
+   map.read(&op);
+   map.read(&has_coordinate);
+   map.read(&has_projector);
+   map.read(&has_shadow_comp);
+   map.read(&has_offset);
+
+   CACHE_DEBUG("%s: op %d coord %d proj %d shadow %d offset %d\n", __func__,
+               op, has_coordinate, has_projector,
+               has_shadow_comp, has_offset);
+
+   ir_texture *new_tex = new(mem_ctx) ir_texture((ir_texture_opcode)op);
+
+   if (!new_tex)
+      goto errors;
+
+   type = read_glsl_type(map, state);
+
+   /* sampler type */
+   map.read(&ir_type);
+
+   switch (ir_type) {
+   case ir_type_dereference_variable:
+      sampler = read_ir_dereference_variable(map);
+      break;
+   case ir_type_dereference_record:
+      sampler = read_ir_dereference_record(map);
+      break;
+   case ir_type_dereference_array:
+      sampler = read_ir_dereference_array(map);
+      break;
+   default:
+      CACHE_DEBUG("%s: error, unhandled sampler type %d\n",
+                  __func__, ir_type);
+   }
+
+   if (!sampler)
+      goto errors;
+
+   new_tex->set_sampler(sampler, type);
+
+   if (has_coordinate)
+      new_tex->coordinate = read_ir_rvalue(map);
+
+   if (has_projector)
+      new_tex->projector = read_ir_rvalue(map);
+
+   if (has_shadow_comp)
+      new_tex->shadow_comparitor = read_ir_rvalue(map);
+
+   if (has_offset)
+      new_tex->offset = read_ir_rvalue(map);
+
+   /* lod_info structure */
+   uint8_t has_lod;
+   uint8_t has_bias;
+   uint8_t has_sample_index;
+   uint8_t has_component;
+   uint8_t has_dpdx;
+   uint8_t has_dpdy;
+
+   map.read(&has_lod);
+   map.read(&has_bias);
+   map.read(&has_sample_index);
+   map.read(&has_component);
+   map.read(&has_dpdx);
+   map.read(&has_dpdy);
+
+   memset(&new_tex->lod_info, 0, sizeof(ir_texture::lod_info));
+
+   if (has_lod)
+      new_tex->lod_info.lod = read_ir_rvalue(map);
+   if (has_bias)
+      new_tex->lod_info.bias = read_ir_rvalue(map);
+   if (has_sample_index)
+      new_tex->lod_info.sample_index = read_ir_rvalue(map);
+   if (has_component)
+      new_tex->lod_info.component = read_ir_rvalue(map);
+   if (has_dpdx)
+      new_tex->lod_info.grad.dPdx = read_ir_rvalue(map);
+   if (has_dpdy)
+      new_tex->lod_info.grad.dPdy = read_ir_rvalue(map);
+
+   return new_tex;
+
+errors:
+   CACHE_DEBUG("error, could not read ir_texture\n");
+   return NULL;
+}
+
+
+ir_expression *
+ir_deserializer::read_ir_expression(memory_map &map)
+{
+   uint32_t operation;
+   ir_rvalue *ir_rvalue_table[4] = { NULL };
+   int32_t operands;
+   uint32_t ir_type;
+   uint32_t len;
+
+   CACHE_DEBUG("%s\n", __func__);
+
+   map.read(&ir_type);
+   map.read(&len);
+
+   /* glsl_type resulted from operation */
+   const glsl_type *rval_type = read_glsl_type(map, state);
+
+   /* read operation type + all operands for creating ir_expression */
+   map.read(&operation);
+   map.read(&operands);
+
+   CACHE_DEBUG("%s : operation %d, operands %d\n",
+               __func__, operation, operands);
+
+   for (int k = 0; k < operands; k++) {
+      ir_rvalue *val = read_ir_rvalue(map);
+
+      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(memory_map &map)
+{
+   uint32_t ir_type = ir_type_unset;
+
+   map.read(&ir_type);
+
+   CACHE_DEBUG("%s: ir_value %d\n", __func__, ir_type);
+
+   switch(ir_type) {
+   case ir_type_constant:
+      return read_ir_constant(map);
+   case ir_type_dereference_variable:
+      return read_ir_dereference_variable(map);
+   case ir_type_dereference_record:
+      return read_ir_dereference_record(map);
+   case ir_type_dereference_array:
+      return read_ir_dereference_array(map);
+   case ir_type_expression:
+      return read_ir_expression(map);
+   case ir_type_swizzle:
+      return read_ir_swizzle(map);
+   case ir_type_texture:
+      return read_ir_texture(map);
+   default:
+      CACHE_DEBUG("%s: error, unhandled type %d\n",
+                  __func__, ir_type);
+      break;
+   }
+   return NULL;
+}
+
+
+int
+ir_deserializer::read_ir_assignment(struct exec_list *list, memory_map &map)
+{
+   uint32_t write_mask = 0;
+   uint32_t lhs_type = 0;
+
+   ir_assignment *assign = NULL;
+   ir_dereference *lhs_deref = NULL;
+
+   map.read(&write_mask);
+   map.read(&lhs_type);
+
+   CACHE_DEBUG("%s: mask %d lhs_type %d\n", __func__, write_mask, lhs_type);
+
+   switch (lhs_type) {
+   case ir_type_dereference_variable:
+      lhs_deref = read_ir_dereference_variable(map);
+      break;
+   case ir_type_dereference_record:
+      lhs_deref = read_ir_dereference_record(map);
+      break;
+   case ir_type_dereference_array:
+      lhs_deref = read_ir_dereference_array(map);
+      break;
+   default:
+      CACHE_DEBUG("%s: error, unhandled lhs_type %d\n",
+                  __func__, lhs_type);
+   }
+
+   if (!lhs_deref) {
+      CACHE_DEBUG("could not find lhs variable, bailing out\n");
+      return -1;
+   }
+
+   /* rvalue for assignment */
+   ir_rvalue *rval = read_ir_rvalue(map);
+
+   /* if we managed to parse rvalue, then we can construct assignment */
+   if (rval) {
+
+      CACHE_DEBUG("%s: lhs type %d\n", __func__, lhs_type);
+
+      assign = new(mem_ctx) ir_assignment(lhs_deref, rval, NULL, write_mask);
+      list->push_tail(assign);
+      return 0;
+   }
+
+   CACHE_DEBUG("error reading assignment rhs\n");
+   return -1;
+}
+
+
+int
+ir_deserializer::read_ir_if(struct exec_list *list, memory_map &map)
+{
+   uint32_t then_len, else_len;
+
+   CACHE_DEBUG("%s\n", __func__);
+
+   map.read(&then_len);
+   map.read(&else_len);
+
+   ir_rvalue *cond = read_ir_rvalue(map);
+
+   if (!cond) {
+      CACHE_DEBUG("%s: error reading condition\n", __func__);
+      return -1;
+   }
+
+   ir_if *irif = new(mem_ctx) ir_if(cond);
+
+   for (unsigned k = 0; k < then_len; k++)
+      if (read_instruction(&irif->then_instructions, map))
+         goto read_errors;
+
+   for (unsigned k = 0; k < else_len; k++)
+      if (read_instruction(&irif->else_instructions, map))
+         goto read_errors;
+
+   list->push_tail(irif);
+   return 0;
+
+read_errors:
+   CACHE_DEBUG("%s: read errors(then %d else %d)\n",
+               __func__, then_len, else_len);
+   ralloc_free(irif);
+   return -1;
+}
+
+
+int
+ir_deserializer::read_ir_return(struct exec_list *list, memory_map &map)
+{
+   uint8_t has_rvalue = 0;
+   map.read(&has_rvalue);
+
+   CACHE_DEBUG("%s\n", __func__);
+
+   ir_rvalue *rval = NULL;
+   if (has_rvalue)
+      rval = read_ir_rvalue(map);
+
+   ir_return *ret = new(mem_ctx) ir_return(rval);
+   list->push_tail(ret);
+
+   return 0;
+}
+
+
+/**
+ * Read a call to ir_function, finds the correct function
+ * signature from prototypes list and creates the call
+ */
+int
+ir_deserializer::read_ir_call(struct exec_list *list, memory_map &map)
+{
+   uint8_t has_return_deref = 0;
+   uint8_t list_len = 0;
+   uint8_t use_builtin = 0;
+   struct exec_list parameters;
+   ir_dereference_variable *return_deref = NULL;
+
+   char *name = map.read_string();
+
+   map.read(&has_return_deref);
+
+   if (has_return_deref)
+      return_deref = read_ir_dereference_variable(map);
+
+   map.read(&list_len);
+
+   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(map);
+      if (rval) {
+         parameters.push_tail(rval);
+      } else {
+         CACHE_DEBUG("%s: error reading rvalue\n", __func__);
+         return -1;
+      }
+   }
+
+   map.read(&use_builtin);
+
+   if (use_builtin) {
+      ir_function_signature *builtin_sig =
+         _mesa_glsl_find_builtin_function(state, name, &parameters);
+
+      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 -1;
+         }
+
+         ir_call *call = new(mem_ctx) ir_call(callee, return_deref,
+            &parameters);
+
+         call->use_builtin = true;
+
+         list->push_tail(call);
+         return 0;
+      }
+   }
+
+   /* find the function from the prototypes */
+   ir_function *func = search_func(state, prototypes, name, &parameters);
+
+   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,
+         &parameters);
+
+      /**
+       * 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 afer linking
+       * .. this may look a bit strange thing todo here but we ignore call here
+       */
+      if (!callee->is_defined)
+         return 0;
+
+      ir_call *call = new(mem_ctx) ir_call(callee, return_deref, &parameters);
+      list->push_tail(call);
+      return 0;
+   }
+
+   CACHE_DEBUG("%s:function %s not found for ir_call ...\n",
+               __func__, name);
+   return -1;
+}
+
+
+int
+ir_deserializer::read_ir_discard(struct exec_list *list, memory_map &map)
+{
+   uint8_t has_condition;
+   map.read(&has_condition);
+   ir_rvalue *condition = NULL;
+
+   CACHE_DEBUG("%s\n", __func__);
+
+   if (has_condition)
+      condition = read_ir_rvalue(map);
+      if (!condition)
+         return -1;
+
+   list->push_tail(new(mem_ctx) ir_discard(condition));
+   return 0;
+}
+
+
+int
+ir_deserializer::read_ir_loop(struct exec_list *list, memory_map &map)
+{
+   uint8_t has_counter, has_from, has_to, has_increment;
+   uint32_t body_size;
+   int32_t cmp;
+   ir_loop *loop = NULL;
+
+   loop = new(mem_ctx) ir_loop;
+
+   map.read(&has_from);
+   map.read(&has_to);
+   map.read(&has_increment);
+   map.read(&has_counter);
+   map.read(&cmp);
+   map.read(&body_size);
+
+   /* comparison operation for loop termination */
+   loop->cmp = cmp;
+
+   /* ir_rvalues: from, to, increment + one ir_variable counter */
+   if (has_from) {
+      loop->from = read_ir_rvalue(map);
+      if (!loop->from)
+         return -1;
+   }
+
+   if (has_to) {
+      loop->to = read_ir_rvalue(map);
+      if (!loop->to)
+         return -1;
+   }
+
+   if (has_increment) {
+      loop->increment = read_ir_rvalue(map);
+      if (!loop->increment)
+         return -1;
+   }
+
+  /* read ir_variable to prototypes list and search from there */
+  if (has_counter) {
+      char *counter_name = map.read_string();
+      if (read_instruction(prototypes, map))
+         return -1;
+      loop->counter = search_var(prototypes, counter_name);
+      if (!loop->counter)
+         return -1;
+  }
+
+   CACHE_DEBUG("%s: from %p to %p increment %p counter %p size %d\n", __func__,
+               loop->from, loop->to, loop->increment, loop->counter, body_size);
+
+   for (unsigned k = 0; k < body_size; k++) {
+      if (read_instruction(&loop->body_instructions, map))
+         goto read_errors;
+   }
+
+   list->push_tail(loop);
+   return 0;
+
+read_errors:
+   CACHE_DEBUG("%s: read errors\n", __func__);
+   if (loop)
+      ralloc_free(loop);
+   return -1;
+}
+
+
+int
+ir_deserializer::read_ir_loop_jump(struct exec_list *list, memory_map &map)
+{
+   uint32_t mode;
+   map.read(&mode);
+   list->push_tail(new(mem_ctx) ir_loop_jump((ir_loop_jump::jump_mode)mode));
+   return 0;
+}
+
+
+int
+ir_deserializer::read_emit_vertex(struct exec_list *list, memory_map &map)
+{
+   list->push_tail(new(mem_ctx) ir_emit_vertex);
+   return 0;
+}
+
+
+int
+ir_deserializer::read_end_primitive(struct exec_list *list, memory_map &map)
+{
+   list->push_tail(new(mem_ctx) ir_end_primitive);
+   return 0;
+}
+
+
+int
+ir_deserializer::read_instruction(struct exec_list *list, memory_map &map,
+                              bool ignore)
+{
+   uint32_t ir_type = ir_type_unset;
+   uint32_t inst_dumpsize = 0;
+
+   map.read(&ir_type);
+   map.read(&inst_dumpsize);
+
+   /* reader wants to jump over this instruction */
+   if (ignore) {
+      map.ffwd(inst_dumpsize);
+      return 0;
+   }
+
+   switch(ir_type) {
+   case ir_type_variable:
+      return read_ir_variable(list, map);
+   case ir_type_assignment:
+      return read_ir_assignment(list, map);
+   case ir_type_constant:
+      return (read_ir_constant(map, list)) ? 0 : -1;
+   case ir_type_function:
+      return read_ir_function(list, map);
+   case ir_type_if:
+      return read_ir_if(list, map);
+   case ir_type_return:
+      return read_ir_return(list, map);
+   case ir_type_call:
+      return read_ir_call(list, map);
+   case ir_type_discard:
+      return read_ir_discard(list, map);
+   case ir_type_loop:
+      return read_ir_loop(list, map);
+   case ir_type_loop_jump:
+      return read_ir_loop_jump(list, map);
+   case ir_type_emit_vertex:
+      return read_emit_vertex(list, map);
+   case ir_type_end_primitive:
+      return read_end_primitive(list, map);
+   default:
+      CACHE_DEBUG("%s cannot read type %d, todo...\n",
+                  __func__, ir_type);
+   }
+
+   return -1;
+}
+
+
+/**
+ * Reads prototypes section of the dump that consists
+ * only of variables and functions
+ */
+int
+ir_deserializer::read_prototypes(memory_map &map)
+{
+   uint32_t total;
+   uint32_t ir_type;
+   uint32_t inst_dumpsize;
+
+   map.read(&total);
+
+   prototypes_only = true;
+
+   for (unsigned k = 0; k < total; k++) {
+
+      map.read(&ir_type);
+      map.read(&inst_dumpsize);
+
+      switch (ir_type) {
+      case ir_type_variable:
+         if (read_ir_variable(prototypes, map))
+            return -1;
+         break;
+      case ir_type_function:
+         if (read_ir_function(prototypes, map))
+            return -1;
+         break;
+      default:
+         CACHE_DEBUG("%s: error in cache data (ir %d)\n",
+                     __func__, ir_type);
+         return -1;
+      }
+   }
+
+   prototypes_only = false;
+
+   CACHE_DEBUG("%s: done\n", __func__);
+   return 0;
+}
+
+
+static uint8_t
+read_bool(memory_map &map)
+{
+   uint8_t value = 0;
+   map.read(&value);
+   return value;
+}
+
+
+static int
+_read_state(struct _mesa_glsl_parse_state *state, memory_map &map)
+{
+   uint32_t language_version;
+   map.read(&language_version);
+
+   /* if cache was produced with different glsl version */
+   if (language_version != state->language_version)
+      return -1;
+
+   /* would be cool to have these in a structure of it own */
+   state->ARB_draw_buffers_enable = read_bool(map);
+   state->ARB_draw_buffers_warn = read_bool(map);
+   state->ARB_draw_instanced_enable = read_bool(map);
+   state->ARB_draw_instanced_warn = read_bool(map);
+   state->ARB_explicit_attrib_location_enable = read_bool(map);
+   state->ARB_explicit_attrib_location_warn = read_bool(map);
+   state->ARB_fragment_coord_conventions_enable = read_bool(map);
+   state->ARB_fragment_coord_conventions_warn = read_bool(map);
+   state->ARB_texture_rectangle_enable = read_bool(map);
+   state->ARB_texture_rectangle_warn = read_bool(map);
+   state->EXT_texture_array_enable = read_bool(map);
+   state->EXT_texture_array_warn = read_bool(map);
+   state->ARB_shader_texture_lod_enable = read_bool(map);
+   state->ARB_shader_texture_lod_warn = read_bool(map);
+   state->ARB_shader_stencil_export_enable = read_bool(map);
+   state->ARB_shader_stencil_export_warn = read_bool(map);
+   state->AMD_conservative_depth_enable = read_bool(map);
+   state->AMD_conservative_depth_warn = read_bool(map);
+   state->ARB_conservative_depth_enable = read_bool(map);
+   state->ARB_conservative_depth_warn = read_bool(map);
+   state->AMD_shader_stencil_export_enable = read_bool(map);
+   state->AMD_shader_stencil_export_warn = read_bool(map);
+   state->OES_texture_3D_enable = read_bool(map);
+   state->OES_texture_3D_warn = read_bool(map);
+   state->OES_EGL_image_external_enable = read_bool(map);
+   state->OES_EGL_image_external_warn = read_bool(map);
+   state->ARB_shader_bit_encoding_enable = read_bool(map);
+   state->ARB_shader_bit_encoding_warn = read_bool(map);
+   state->ARB_uniform_buffer_object_enable = read_bool(map);
+   state->ARB_uniform_buffer_object_warn = read_bool(map);
+   state->OES_standard_derivatives_enable = read_bool(map);
+   state->OES_standard_derivatives_warn = read_bool(map);
+   state->ARB_texture_cube_map_array_enable = read_bool(map);
+   state->ARB_texture_cube_map_array_warn = read_bool(map);
+   state->ARB_shading_language_packing_enable = read_bool(map);
+   state->ARB_shading_language_packing_warn = read_bool(map);
+   state->ARB_texture_multisample_enable = read_bool(map);
+   state->ARB_texture_multisample_warn = read_bool(map);
+   state->ARB_texture_query_lod_enable = read_bool(map);
+   state->ARB_texture_query_lod_warn = read_bool(map);
+   state->ARB_gpu_shader5_enable = read_bool(map);
+   state->ARB_gpu_shader5_warn = read_bool(map);
+   state->AMD_vertex_shader_layer_enable = read_bool(map);
+   state->AMD_vertex_shader_layer_warn = read_bool(map);
+   state->ARB_shading_language_420pack_enable = read_bool(map);
+   state->ARB_shading_language_420pack_warn = read_bool(map);
+   state->EXT_shader_integer_mix_enable = read_bool(map);
+   state->EXT_shader_integer_mix_warn = read_bool(map);
+
+   return 0;
+}
+
+
+struct gl_shader *
+ir_deserializer::deserialize(void *mem_ctx, memory_map &map, uint32_t shader_size,
+   struct _mesa_glsl_parse_state *state, const char *mesa_sha,
+   int *error_code)
+{
+   int error = 0;
+   uint32_t is_es = 0;
+
+   *error_code = ir_deserializer::GENERAL_READ_ERROR;
+
+   struct _mesa_glsl_parse_state *_state = state;
+
+   uint32_t type = 0;
+   map.read(&type);
+
+   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, map, mesa_sha)) {
+      *error_code = ir_deserializer::DIFFERENT_MESA_SHA;
+      goto error_deserialize;
+   }
+
+   is_es = shader->IsES ? 1 : 0;
+
+   /* check if cache produced using different language version */
+   if (state) {
+      if (state->language_version != shader->Version ||
+         state->es_shader != is_es) {
+         *error_code = ir_deserializer::DIFFERENT_LANG_VER;
+         goto error_deserialize;
+      }
+   }
+
+   if (state) {
+      if (_read_state(state, map))
+         goto error_deserialize;
+      _state = state;
+   } else {
+      /* no existing parse state, we need to create one */
+      GET_CURRENT_CONTEXT(ctx);
+      _state = new(mem_ctx) _mesa_glsl_parse_state(ctx,
+         shader->Type, shader);
+   }
+   this->state = _state;
+
+   /* fill parse state from shader header information */
+   switch (shader->Type) {
+   case GL_VERTEX_SHADER:
+      _state->target = vertex_shader;
+      break;
+   case GL_FRAGMENT_SHADER:
+      _state->target = fragment_shader;
+      break;
+   case GL_GEOMETRY_SHADER_ARB:
+      _state->target = geometry_shader;
+      break;
+   }
+
+   _state->num_builtins_to_link = 0;
+
+   _mesa_glsl_initialize_builtin_functions();
+   _mesa_glsl_initialize_types(_state);
+
+   /**
+    * parser state is used to find builtin functions and
+    * existing types during reading
+    */
+   this->state = _state;
+
+   /* allocations during reading */
+   this->mem_ctx = mem_ctx;
+
+   prototypes = new(mem_ctx) exec_list;
+
+   error = read_prototypes(map);
+
+   shader->ir = new(shader) exec_list;
+   top_level = shader->ir;
+
+   /* top level exec_list read loop, constructs a new list */
+   while(map.position() < shader_size && error == 0)
+      error = read_instruction(shader->ir, map);
+
+   ralloc_free(prototypes);
+
+   if (error)
+      goto error_deserialize;
+
+   *error_code = 0;
+
+   shader->CompileStatus = GL_TRUE;
+
+   /* allocates glsl_symbol_table internally */
+   populate_symbol_table(shader);
+
+   memcpy(shader->builtins_to_link, _state->builtins_to_link,
+      sizeof(shader->builtins_to_link[0]) * _state->num_builtins_to_link);
+      shader->num_builtins_to_link = _state->num_builtins_to_link;
+
+   validate_ir_tree(shader->ir);
+
+   CACHE_DEBUG("shader from cache\n");
+
+   return shader;
+
+error_deserialize:
+   if (shader->ir)
+      ralloc_free(shader->ir);
+   ralloc_free(shader);
+   return NULL;
+}
diff --git a/src/glsl/ir_cache_deserializer.h b/src/glsl/ir_cache_deserializer.h
new file mode 100644
index 0000000..91d2c28
--- /dev/null
+++ b/src/glsl/ir_cache_deserializer.h
@@ -0,0 +1,301 @@
+/* -*- 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 "program/hash_table.h"
+#include "main/imports.h"
+#include "linker.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 memory_map;
+
+/**
+ * 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(bool prototypes = false) :
+      prototypes_only(prototypes)
+   {
+      var_ht = hash_table_ctor(0, hash_table_string_hash,
+         hash_table_string_compare);
+   }
+
+   ~ir_deserializer()
+   {
+      hash_table_call_foreach(this->var_ht, delete_key, NULL);
+      hash_table_dtor(this->var_ht);
+   }
+
+   /* unserialize gl_shader from mapped memory */
+   struct gl_shader *deserialize(void *mem_ctx, memory_map &map,
+                             uint32_t shader_size,
+                             struct _mesa_glsl_parse_state *state,
+                             const char *mesa_sha,
+                             int *error_code);
+
+   enum cache_error {
+      GENERAL_READ_ERROR = -1, /* read failed, possible bug or data corrupt */
+      DIFFERENT_MESA_SHA = -2, /* blob created with different mesa version  */
+      DIFFERENT_LANG_VER = -3, /* blob created using different GLSL version */
+   };
+
+   /**
+    * this method is public so that gl_shader_program
+    * unserialization can use it when reading the
+    * uniform storage
+    */
+   const glsl_type *read_glsl_type(memory_map &map,
+      struct _mesa_glsl_parse_state *state);
+
+private:
+
+   /* variables and methods required for unserialization */
+   bool prototypes_only;
+
+   struct _mesa_glsl_parse_state *state;
+   void *mem_ctx;
+
+   /* pointer to shader->ir list */
+   struct exec_list *top_level;
+
+   /* pointer to list which contains prototypes of functions */
+   struct exec_list *prototypes;
+
+   /* pointer to current functions body */
+   struct exec_list *current_function;
+
+   int read_header(struct gl_shader *shader, memory_map &map,
+               const char *mesa_sha);
+
+   int read_prototypes(memory_map &map);
+
+   int read_instruction(struct exec_list *list, memory_map &map,
+                    bool ignore = false);
+
+   int read_ir_variable(struct exec_list *list, memory_map &map);
+   int read_ir_assignment(struct exec_list *list, memory_map &map);
+   int read_ir_function(struct exec_list *list, memory_map &map);
+   int read_ir_if(struct exec_list *list, memory_map &map);
+   int read_ir_return(struct exec_list *list, memory_map &map);
+   int read_ir_call(struct exec_list *list, memory_map &map);
+   int read_ir_discard(struct exec_list *list, memory_map &map);
+   int read_ir_loop(struct exec_list *list, memory_map &map);
+   int read_ir_loop_jump(struct exec_list *list, memory_map &map);
+   int read_emit_vertex(struct exec_list *list, memory_map &map);
+   int read_end_primitive(struct exec_list *list, memory_map &map);
+
+   /* rvalue readers */
+   ir_rvalue *read_ir_rvalue(memory_map &map);
+   ir_constant *read_ir_constant(memory_map &map,
+      struct exec_list *list = NULL);
+   ir_swizzle *read_ir_swizzle(memory_map &map);
+   ir_texture *read_ir_texture(memory_map &map);
+   ir_expression *read_ir_expression(memory_map &map);
+   ir_dereference_array *read_ir_dereference_array(memory_map &map);
+   ir_dereference_record *read_ir_dereference_record(memory_map &map);
+   ir_dereference_variable *read_ir_dereference_variable(memory_map &map);
+
+   /**
+    * 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;
+
+   /**
+    * these 2 functions are copy pasted from string_to_uint_map,
+    * we need a hash here with a string key and pointer value
+    */
+   void hash_store(void * value, const char *key)
+   {
+      char *dup_key = _mesa_strdup(key);
+      bool result = hash_table_replace(this->var_ht, value, dup_key);
+      if (result)
+         free(dup_key);
+   }
+
+   static void delete_key(const void *key, void *data, void *closure)
+   {
+      (void) data;
+      (void) closure;
+      free((char *)key);
+   }
+
+};
+
+
+/**
+ * Helper class to read instructions
+ *
+ * Class can read either from user given memory or from a file. On Linux
+ * file reading wraps around the Posix functions for mapping a file into
+ * the process's address space. Other OS may need different implementation.
+ */
+class memory_map
+{
+public:
+   memory_map() :
+      mode(memory_map::READ_MEM),
+      fd(0),
+      cache_size(0),
+      cache_mmap(NULL),
+      cache_mmap_p(NULL)
+   {
+      /* only used by read_string() */
+      mem_ctx = ralloc_context(NULL);
+   }
+
+   /* read from disk */
+   int map(const char *path)
+   {
+      struct stat stat_info;
+      if (stat(path, &stat_info) != 0)
+         return -1;
+
+      mode = memory_map::READ_MAP;
+      cache_size = stat_info.st_size;
+
+      fd = open(path, O_RDONLY);
+      if (fd) {
+         cache_mmap_p = cache_mmap = (char *)
+            mmap(NULL, cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
+         return (cache_mmap == MAP_FAILED) ? -1 : 0;
+      }
+      return -1;
+   }
+
+   /* read from memory */
+   int map(const void *memory, size_t size)
+   {
+      cache_mmap_p = cache_mmap = (char *) memory;
+      cache_size = size;
+      return 0;
+   }
+
+   ~memory_map() {
+      if (cache_mmap && mode == READ_MAP) {
+         munmap(cache_mmap, cache_size);
+         close(fd);
+      }
+      ralloc_free(mem_ctx);
+   }
+
+   /* move read pointer forward */
+   inline void ffwd(int len)
+   {
+      cache_mmap_p += len;
+   }
+
+   /* position of read pointer */
+   inline uint32_t position()
+   {
+      return cache_mmap_p - cache_mmap;
+   }
+
+   inline char *read_string()
+   {
+      char *str = ralloc_strdup(mem_ctx, cache_mmap_p);
+      ffwd(strlen(str)+1);
+      return str;
+   }
+
+   /* read functions for different types */
+#define _READ_TYPE(type) inline void read(type *val) {\
+   *val = *(type *) cache_mmap_p;\
+   ffwd(sizeof(type));\
+}
+   _READ_TYPE(int32_t)
+   _READ_TYPE(uint32_t)
+   _READ_TYPE(bool)
+   _READ_TYPE(GLboolean)
+   _READ_TYPE(gl_texture_index)
+   _READ_TYPE(ir_expression_operation)
+
+   inline void read(void *dst, size_t size)
+   {
+      memcpy(dst, cache_mmap_p, size);
+      ffwd(size);
+   }
+
+   /* read and serialize a gl_shader */
+   inline struct gl_shader *read_shader(void *mem_ctx,
+                                    const char *mesa_sha)
+   {
+      uint32_t shader_size;
+      read(&shader_size);
+
+      ir_deserializer s;
+      memory_map map;
+      int error;
+
+      map.map(cache_mmap_p, shader_size);
+      struct gl_shader *sha = s.deserialize(mem_ctx,
+         map, shader_size, NULL, mesa_sha, &error);
+
+      ffwd(shader_size);
+      return sha;
+   }
+
+private:
+
+   void *mem_ctx;
+
+   /* specifies if we are reading mapped memory or user passed mem */
+   enum read_mode {
+      READ_MEM = 0,
+      READ_MAP
+   };
+
+   int32_t mode;
+   int32_t fd;
+   int32_t cache_size;
+   char *cache_mmap;
+   char *cache_mmap_p;
+};
+#endif /* ifdef __cplusplus */
+
+#endif /* IR_CACHE_DESERIALIZER_H */
-- 
1.8.1.4



More information about the mesa-dev mailing list