[Mesa-dev] [PATCH 09/10] glsl: functions to serialize gl_shader and gl_shader_program

Tapani Pälli tapani.palli at intel.com
Wed Jan 29 01:25:04 PST 2014


These utility functions can be used to (de)serialize gl_shader and
gl_shader_program structures. This makes it possible to implement a
shader compiler cache for individual shaders and functionality required
by OES_get_program_binary and ARB_get_program_binary extensions.

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

diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources
index 3c49a58..f4a6eb2 100644
--- a/src/glsl/Makefile.sources
+++ b/src/glsl/Makefile.sources
@@ -103,6 +103,7 @@ LIBGLSL_FILES = \
 	$(GLSL_SRCDIR)/opt_tree_grafting.cpp \
 	$(GLSL_SRCDIR)/opt_vectorize.cpp \
 	$(GLSL_SRCDIR)/s_expression.cpp \
+	$(GLSL_SRCDIR)/shader_cache.cpp \
 	$(GLSL_SRCDIR)/strtod.c
 
 # glsl_compiler
diff --git a/src/glsl/shader_cache.cpp b/src/glsl/shader_cache.cpp
new file mode 100644
index 0000000..c0675ff
--- /dev/null
+++ b/src/glsl/shader_cache.cpp
@@ -0,0 +1,734 @@
+/* -*- 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 "main/shaderobj.h"
+#include "main/uniforms.h"
+#include "main/macros.h"
+#include "program/hash_table.h"
+#include "program/prog_parameter.h"
+#include "ir_serialize.h"
+#include "ir_deserializer.h"
+#include "shader_cache_magic.h"
+
+
+static void
+write_header(gl_shader *shader, memory_writer &blob)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   blob.write_string(mesa_get_shader_cache_magic());
+   blob.write_string((const char *)ctx->Driver.GetString(ctx, GL_VENDOR));
+   blob.write_string((const char *)ctx->Driver.GetString(ctx, GL_RENDERER));
+   blob.write_uint32_t(shader->Version);
+   blob.write_uint32_t(shader->Type);
+   blob.write_uint8_t(shader->IsES);
+}
+
+
+/* gl_program contains post-link data populated by the driver */
+static void
+serialize_gl_program(struct gl_shader *shader, memory_writer &blob)
+{
+   blob.write(shader->Program, sizeof(struct gl_program));
+   blob.write_string((const char *)shader->Program->String);
+}
+
+
+static void
+serialize_shader_postlink_data(struct gl_shader *shader, memory_writer &blob)
+{
+   blob.write_uint32_t(shader->num_samplers);
+   blob.write_uint32_t(shader->active_samplers);
+   blob.write_uint32_t(shader->shadow_samplers);
+   blob.write_uint32_t(shader->num_uniform_components);
+   blob.write_uint32_t(shader->num_combined_uniform_components);
+   blob.write_uint8_t((uint8_t)shader->uses_builtin_functions);
+
+   /* ARB_get_program_binary supports geometry shaders */
+   blob.write(&shader->Geom, sizeof(shader->Geom));
+
+   for (unsigned i = 0; i < MAX_SAMPLERS; i++)
+      blob.write_uint8_t(shader->SamplerUnits[i]);
+
+   for (unsigned i = 0; i < MAX_SAMPLERS; i++)
+      blob.write_int32_t((int32_t)shader->SamplerTargets[i]);
+}
+
+
+/**
+ * Serializes gl_shader structure, writes shader header
+ * information and exec_list of instructions
+ */
+extern "C" char *
+mesa_shader_serialize(struct gl_shader *shader, size_t *size)
+{
+   *size = 0;
+
+   memory_writer blob;
+
+   int32_t start_pos = blob.position();
+   uint32_t shader_data_len = 0;
+   uint32_t shader_type = shader->Type;
+
+   blob.write_uint32_t(shader_data_len);
+   blob.write_uint32_t(shader_type);
+
+   write_header(shader, blob);
+
+   /* misc required post-link data */
+   serialize_shader_postlink_data(shader, blob);
+
+   /* gl_program structure */
+   serialize_gl_program(shader, blob);
+
+   /* dump all shader instructions */
+   serialize_list(shader->ir, blob);
+
+   shader_data_len = blob.position() -
+      start_pos - sizeof(shader_data_len);
+   blob.overwrite(&shader_data_len, sizeof(shader_data_len), start_pos);
+
+   return blob.release_memory(size);
+}
+
+
+/**
+ * helper structure for hash serialization, hash size is
+ * counted to item_count during serialization
+ */
+struct hash_serialize_data
+{
+   hash_serialize_data(void *memory_writer) :
+      writer(memory_writer),
+      item_count(0) { }
+
+   void *writer;
+   uint32_t item_count;
+};
+
+
+static void
+serialize_hash(const void *key, void *data, void *closure)
+{
+   hash_serialize_data *s_data = (hash_serialize_data *) closure;
+   memory_writer *blob = (memory_writer *) s_data->writer;
+
+   uint32_t value = ((intptr_t)data);
+
+   blob->write_string((char *)key);
+   blob->write_uint32_t(value);
+
+   s_data->item_count++;
+}
+
+
+static void
+serialize_hash_table(struct string_to_uint_map *map, memory_writer *blob)
+{
+   struct hash_serialize_data data(blob);
+   int32_t pos = blob->position();
+   blob->write_uint32_t(data.item_count);
+
+   map->iterate(serialize_hash, &data);
+
+   blob->overwrite(&data.item_count, sizeof(data.item_count), pos);
+}
+
+
+static void
+serialize_uniform_storage(gl_uniform_storage *uni, memory_writer &blob)
+{
+   blob.write_string(uni->name);
+
+   /* note, type is not serialized, it is resolved during parsing */
+
+   uint8_t initialized = uni->initialized;
+   uint8_t row_major = uni->row_major;
+
+   blob.write_uint32_t(uni->array_elements);
+   blob.write_uint8_t(initialized);
+   blob.write_int32_t(uni->block_index);
+   blob.write_int32_t(uni->offset);
+   blob.write_int32_t(uni->matrix_stride);
+   blob.write_uint8_t(row_major);
+   blob.write_int32_t(uni->atomic_buffer_index);
+
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      uint8_t active = uni->sampler[i].active;
+      blob.write_uint8_t(uni->sampler[i].index);
+      blob.write_uint8_t(active);
+   }
+
+   /* how many elements (1 if not array) * how many components in the type */
+   const unsigned elements = MAX2(1, uni->array_elements);
+   uint32_t size = elements * MAX2(1, uni->type->components());
+
+   CACHE_DEBUG("%s: size %ld\n", __func__,
+               size * sizeof(union gl_constant_value));
+
+   blob.write_uint32_t(size);
+}
+
+
+static void
+serialize_transform_feedback_info(struct gl_transform_feedback_info *info,
+   memory_writer &blob)
+{
+   blob.write(info, sizeof(struct gl_transform_feedback_info));
+
+   blob.write(info->Outputs,
+      info->NumOutputs * sizeof(gl_transform_feedback_output));
+
+   for (int i = 0; i < info->NumVarying; i++) {
+      blob.write(&info->Varyings[i],
+         sizeof(gl_transform_feedback_varying_info));
+      blob.write_string(info->Varyings[i].Name);
+   }
+}
+
+
+/**
+ * Validation header for the gl_shader_program, this data is used to verify
+ * that binary program is usable for the Mesa in use. It is intended to catch
+ * changes in some of the important structures and enums that would it hard
+ * or impossible to use the binary data.
+ */
+static const uint32_t validation_data[] = {
+   ir_type_max,
+   GLSL_TYPE_ERROR,
+   sizeof(gl_shader),
+   sizeof(gl_program),
+   sizeof(gl_shader_program),
+   sizeof(gl_uniform_storage),
+   sizeof(gl_program_parameter_list),
+   sizeof(ir_variable),
+   sizeof(ir_assignment),
+   sizeof(ir_call),
+   sizeof(ir_constant),
+   sizeof(ir_dereference_array),
+   sizeof(ir_dereference_record),
+   sizeof(ir_dereference_variable),
+   sizeof(ir_discard),
+   sizeof(ir_expression),
+   sizeof(ir_function),
+   sizeof(ir_function_signature),
+   sizeof(ir_if),
+   sizeof(ir_loop),
+   sizeof(ir_loop_jump),
+   sizeof(ir_return),
+   sizeof(ir_swizzle),
+   sizeof(ir_texture),
+   sizeof(ir_emit_vertex),
+   sizeof(ir_end_primitive)
+};
+#define validation_data_items sizeof(validation_data)/sizeof(uint32_t)
+
+
+/**
+ * Serialize gl_shader_program structure
+ */
+extern "C" char *
+mesa_program_serialize(struct gl_shader_program *prog, size_t *size,
+   const char *mesa_sha)
+{
+   memory_writer blob;
+
+   blob.write(&validation_data, sizeof(validation_data));
+
+   blob.write_uint32_t(prog->Type);
+   blob.write_uint8_t(prog->LinkStatus);
+   blob.write_uint32_t(prog->Version);
+   blob.write_uint8_t(prog->IsES);
+   blob.write_uint32_t(prog->NumUserUniformStorage);
+   blob.write_uint32_t(prog->UniformLocationBaseScale);
+   blob.write_uint32_t(prog->LastClipDistanceArraySize);
+   blob.write_uint8_t(prog->FragDepthLayout);
+
+   /* hash tables */
+   serialize_hash_table(prog->AttributeBindings, &blob);
+   serialize_hash_table(prog->FragDataBindings, &blob);
+   serialize_hash_table(prog->FragDataIndexBindings, &blob);
+   serialize_hash_table(prog->UniformHash, &blob);
+
+   /* post-link transform feedback information */
+   serialize_transform_feedback_info(&prog->LinkedTransformFeedback, blob);
+
+   blob.write(&prog->Geom, sizeof(prog->Geom));
+   blob.write(&prog->Vert, sizeof(prog->Vert));
+
+   /* uniform storage */
+   if (prog->UniformStorage) {
+      for (unsigned i = 0; i < prog->NumUserUniformStorage; ++i)
+         serialize_uniform_storage(&prog->UniformStorage[i], blob);
+   }
+
+   uint8_t shader_amount = 0;
+   unsigned shader_amount_pos = blob.position();
+   blob.write_uint8_t(shader_amount);
+
+   /* _LinkedShaders IR */
+   for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {
+      size_t sha_size = 0;
+
+      if (!prog->_LinkedShaders[i])
+         continue;
+
+      char *data = mesa_shader_serialize(prog->_LinkedShaders[i], &sha_size);
+
+      if (!data) {
+         CACHE_DEBUG("error serializing data for index %d\n", i);
+         return NULL;
+      }
+
+      shader_amount++;
+
+      /* index in _LinkedShaders list + shader blob */
+      if (data) {
+         blob.write_uint32_t(i);
+         blob.write(data, sha_size);
+         free(data);
+      }
+   }
+
+   blob.overwrite(&shader_amount, sizeof(shader_amount), shader_amount_pos);
+
+   *size = blob.position();
+   return blob.release_memory(size);
+}
+
+
+/**
+ * gl_program contains post-link data populated by the driver
+ */
+static bool
+deserialize_gl_program(struct gl_shader *shader, memory_map &map)
+{
+   map.read(shader->Program, sizeof(struct gl_program));
+   shader->Program->String = (GLubyte*) map.read_string();
+
+   shader->Program->Parameters = _mesa_new_parameter_list();
+
+   if (!shader->Program->Parameters)
+      return false;
+
+   shader->Program->Parameters->NumParameters = 0;
+   shader->Program->Parameters->Size = 0;
+   shader->Program->Parameters->StateFlags = 0;
+
+   if (map.errors())
+      return false;
+
+   return true;
+}
+
+
+/**
+ * Reads in header part of the shader blob, header contains misc data
+ * for the gl_shader structure and also validation data
+ */
+static bool
+read_header(struct gl_shader *shader, memory_map &map)
+{
+   char *cache_magic_id = map.read_string();
+   char *cache_vendor = map.read_string();
+   char *cache_renderer = map.read_string();
+
+   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, cache_vendor, cache_renderer);
+
+   const char *magic = mesa_get_shader_cache_magic();
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   const char *mesa_vendor =
+      (const char *) ctx->Driver.GetString(ctx, GL_VENDOR);
+   const char *mesa_renderer =
+      (const char *) ctx->Driver.GetString(ctx, GL_RENDERER);
+
+   /* check if cache was created with another driver */
+   if ((strcmp(mesa_vendor, cache_vendor)) ||
+      (strcmp(mesa_renderer, cache_renderer)))
+         return false;
+
+   /* check against different version of mesa */
+   if (strcmp(cache_magic_id, magic))
+      return false;
+
+   return true;
+}
+
+
+static bool
+deserialize_shader_postlink_data(struct gl_shader *shader, memory_map &map)
+{
+   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 success */
+   return !map.errors();
+}
+
+
+static bool
+read_hash_table(struct string_to_uint_map *hash, memory_map *map)
+{
+   if (map->errors())
+      return false;
+
+   uint32_t size = map->read_uint32_t();
+
+   for (unsigned i = 0; i < size; i++) {
+
+      char *key = map->read_string();
+      uint32_t value = map->read_uint32_t();
+
+      /* put() adds +1 bias on the value (see hash_table.h), this
+       * is taken care here when reading
+       */
+      hash->put(value-1, key);
+
+      /* break out in case of read errors */
+      if (map->errors())
+         return false;
+   }
+   return true;
+}
+
+
+static void
+read_uniform_storage(void *mem_ctx, gl_uniform_storage *uni, memory_map &map)
+{
+   char *name = map.read_string();
+   uni->name = strdup(name);
+
+   /* resolved later */
+   uni->type = NULL;
+
+   uni->array_elements = map.read_uint32_t();
+   uni->initialized = map.read_uint8_t();
+   uni->block_index = map.read_int32_t();
+   uni->offset = map.read_int32_t();
+   uni->matrix_stride = map.read_int32_t();
+   uni->row_major = map.read_uint8_t();
+   uni->atomic_buffer_index = map.read_int32_t();
+
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      uni->sampler[i].index = map.read_uint8_t();
+      uni->sampler[i].active = map.read_uint8_t();
+   }
+
+   uint32_t size = map.read_uint32_t();
+
+   CACHE_DEBUG("read uniform storage size %ld\n",
+               size * sizeof(union gl_constant_value));
+
+   uni->storage =
+      rzalloc_array(mem_ctx, union gl_constant_value, size);
+
+   /* initialize to zero for now, initializers will be propagated later */
+   memset(uni->storage, 0, size * sizeof(union gl_constant_value));
+
+   /* driver uniform storage gets generated and propagated later */
+   uni->driver_storage = NULL;
+   uni->num_driver_storage = 0;
+}
+
+
+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;
+}
+
+
+/**
+ * Resolve glsl_types for uniform_storage
+ */
+static void
+resolve_uniform_types(struct gl_shader_program *prog,
+   struct gl_shader *sha)
+{
+   /* for each storage, find corresponding uniform from the shader */
+   for (unsigned i = 0; i < prog->NumUserUniformStorage; i++) {
+      ir_variable *var = search_var(sha->ir, prog->UniformStorage[i].name);
+
+      if (var) {
+         /* for arrays, uniform storage type contains the element type */
+         if (var->type->is_array())
+            prog->UniformStorage[i].type = var->type->element_type();
+         else
+            prog->UniformStorage[i].type = var->type;
+      }
+   }
+}
+
+
+/* read and serialize a gl_shader */
+static gl_shader *
+read_shader(void *mem_ctx, memory_map &map, ir_deserializer &s)
+{
+   struct gl_shader *shader = NULL;
+   struct gl_program *prog = NULL;
+   gl_shader_stage stage;
+   GET_CURRENT_CONTEXT(ctx);
+   memory_map wrapper;
+
+   uint32_t shader_size = map.read_uint32_t();
+   uint32_t start = map.position();
+   uint32_t type = map.read_uint32_t();
+
+   /* verify that type is supported */
+   switch (type) {
+      case GL_VERTEX_SHADER:
+      case GL_FRAGMENT_SHADER:
+      case GL_GEOMETRY_SHADER:
+         break;
+      default:
+         goto error_deserialize;
+   }
+
+   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))
+      goto error_deserialize;
+
+   /* verify that type from header matches */
+   if (shader->Type != type)
+      goto error_deserialize;
+
+   /* misc post-link data */
+   if (!deserialize_shader_postlink_data(shader, map))
+      goto error_deserialize;
+
+   stage = _mesa_shader_enum_to_shader_stage(shader->Type);
+
+   prog =
+      ctx->Driver.NewProgram(ctx, _mesa_shader_stage_to_program(stage),
+                             shader->Name);
+
+   if (!prog)
+      goto error_deserialize;
+
+   _mesa_reference_program(ctx, &shader->Program, prog);
+
+   if (!deserialize_gl_program(shader, map))
+      goto error_deserialize;
+
+   /* decrement what we have already read */
+   shader_size -= map.position() - start;
+
+   /* read existing memory_map with another memory_map */
+   wrapper.map(map, shader_size);
+
+   if (!s.deserialize(mem_ctx, shader,
+      &wrapper, shader_size))
+      goto error_deserialize;
+
+   do_set_program_inouts(shader->ir, shader->Program, shader->Stage);
+
+   return shader;
+
+error_deserialize:
+
+   if (shader)
+      ctx->Driver.DeleteShader(ctx, shader);
+
+   return NULL;
+}
+
+
+/**
+ * Deserialize gl_shader structure
+ */
+extern "C" struct gl_shader *
+mesa_shader_deserialize(void *mem_ctx, void *blob, size_t size)
+{
+   memory_map map;
+   ir_deserializer s;
+   map.map(blob, size);
+   return read_shader(mem_ctx, map, s);
+}
+
+
+static int
+validate_binary_program(struct gl_shader_program *prog, memory_map &map)
+{
+   uint32_t data[validation_data_items];
+   map.read(&data, sizeof(validation_data));
+   return memcmp(&data, validation_data, sizeof(validation_data));
+}
+
+
+static void
+deserialize_transform_feedback_info(struct gl_shader_program *prog,
+   memory_map &map)
+{
+   map.read(&prog->LinkedTransformFeedback,
+      sizeof(gl_transform_feedback_info));
+
+   unsigned num_outputs = prog->LinkedTransformFeedback.NumOutputs;
+   GLint num_varying = prog->LinkedTransformFeedback.NumVarying;
+
+   prog->LinkedTransformFeedback.Outputs =
+      rzalloc_array(prog, struct gl_transform_feedback_output,
+                    num_outputs);
+
+   map.read(prog->LinkedTransformFeedback.Outputs,
+      num_outputs * sizeof(gl_transform_feedback_output));
+
+   prog->LinkedTransformFeedback.Varyings =
+      rzalloc_array(prog, struct gl_transform_feedback_varying_info,
+                    num_varying);
+   for (int i = 0; i < num_varying; i++) {
+      map.read(&prog->LinkedTransformFeedback.Varyings[i],
+         sizeof(gl_transform_feedback_varying_info));
+      prog->LinkedTransformFeedback.Varyings[i].Name = map.read_string();
+   }
+}
+
+
+/**
+ * Deserialize gl_shader_program structure
+ */
+extern "C" int
+mesa_program_deserialize(struct gl_shader_program *prog,
+   const GLvoid *blob, size_t size)
+{
+   memory_map map;
+   map.map((const void*)blob, size);
+
+   if(validate_binary_program(prog, map))
+      return -1;
+
+   prog->Type = map.read_uint32_t();
+   prog->LinkStatus = map.read_uint8_t();
+   prog->Version = map.read_uint32_t();
+   prog->IsES = map.read_uint8_t();
+   prog->NumUserUniformStorage = map.read_uint32_t();
+   prog->UniformLocationBaseScale = map.read_uint32_t();
+   prog->LastClipDistanceArraySize = map.read_uint32_t();
+   prog->FragDepthLayout = (gl_frag_depth_layout) map.read_uint8_t();
+
+   prog->UniformStorage = NULL;
+   prog->Label = NULL;
+
+   prog->UniformHash = new string_to_uint_map;
+
+   /* these already allocated by _mesa_init_shader_program */
+   read_hash_table(prog->AttributeBindings, &map);
+   read_hash_table(prog->FragDataBindings, &map);
+   read_hash_table(prog->FragDataIndexBindings, &map);
+
+   read_hash_table(prog->UniformHash, &map);
+
+   if (map.errors())
+      return -1;
+
+   deserialize_transform_feedback_info(prog, map);
+
+   map.read(&prog->Geom, sizeof(prog->Geom));
+   map.read(&prog->Vert, sizeof(prog->Vert));
+
+   /* uniform storage */
+   prog->UniformStorage = rzalloc_array(prog, struct gl_uniform_storage,
+      prog->NumUserUniformStorage);
+
+   for (unsigned i = 0; i < prog->NumUserUniformStorage; i++)
+      read_uniform_storage(prog, &prog->UniformStorage[i], map);
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   /* how many linked shaders does the binary contain */
+   uint8_t shader_amount = map.read_uint8_t();
+
+   /* use same deserializer to have same type_hash across shader stages */
+   ir_deserializer s;
+
+   /* init list, cache can contain only some shader types */
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++)
+      prog->_LinkedShaders[i] = NULL;
+
+   /* read _LinkedShaders */
+   for (unsigned i = 0; i < shader_amount; i++) {
+      uint32_t index = map.read_uint32_t();
+
+      struct gl_shader *sha = read_shader(prog, map, s);
+
+      /* note, for 'automatic cache' in case of failure we would
+       * need to fallback to compiling/linking the shaders in the
+       * prog->Shaders list
+       */
+      if (!sha) {
+         CACHE_DEBUG("failed to read shader (index %d)\n", index);
+         return -1;
+      }
+
+      resolve_uniform_types(prog, sha);
+
+      _mesa_reference_shader(ctx, &prog->_LinkedShaders[index], sha);
+      CACHE_DEBUG("%s: read a linked shader, index %d (%p)\n",
+                  __func__, index, sha);
+   }
+
+   /* set default values for uniforms that have initializer */
+   link_set_uniform_initializers(prog);
+
+#if 0
+   /* for debugging */
+   ctx->Driver.LinkShader(ctx, prog);
+#endif
+
+   return 0;
+}
diff --git a/src/glsl/shader_cache.h b/src/glsl/shader_cache.h
new file mode 100644
index 0000000..b65660d
--- /dev/null
+++ b/src/glsl/shader_cache.h
@@ -0,0 +1,58 @@
+/* -*- 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 SHADER_CACHE_H
+#define SHADER_CACHE_H
+
+/* cache specific debug output */
+#ifdef SHADER_CACHE_DEBUG
+#define CACHE_DEBUG(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define CACHE_DEBUG(fmt, ...) do {} while (0)
+#endif
+
+/* C API for the cache */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char *
+mesa_shader_serialize(struct gl_shader *shader, size_t *size);
+
+struct gl_shader *
+mesa_shader_deserialize(void *mem_ctx, void *blob, size_t size);
+
+char *
+mesa_program_serialize(struct gl_shader_program *prog, size_t *size);
+
+int
+mesa_program_deserialize(struct gl_shader_program *prog,
+   const GLvoid *blob, size_t size);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SHADER_CACHE_H */
-- 
1.8.5.3



More information about the mesa-dev mailing list