[Mesa-dev] [RFC 11/20] glsl: functions to serialize gl_shader and gl_shader_program

Tapani Pälli tapani.palli at intel.com
Mon Jun 2 05:05:52 PDT 2014


These utility functions for serialization can be utilized by binary
shader cache and ARB_get_program_binary extension.

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

diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources
index 06e0ae5..f6a86f2 100644
--- a/src/glsl/Makefile.sources
+++ b/src/glsl/Makefile.sources
@@ -104,6 +104,7 @@ LIBGLSL_FILES = \
 	$(GLSL_SRCDIR)/opt_tree_grafting.cpp \
 	$(GLSL_SRCDIR)/opt_vectorize.cpp \
 	$(GLSL_SRCDIR)/s_expression.cpp \
+	$(GLSL_SRCDIR)/shader_serialize.cpp \
 	$(GLSL_SRCDIR)/strtod.c
 
 # glsl_compiler
diff --git a/src/glsl/shader_cache.h b/src/glsl/shader_cache.h
new file mode 100644
index 0000000..2f75e83
--- /dev/null
+++ b/src/glsl/shader_cache.h
@@ -0,0 +1,86 @@
+/* -*- 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
+
+#include "main/shaderobj.h"
+#include "main/uniforms.h"
+#include "main/macros.h"
+#include "program/hash_table.h"
+#include "ir.h"
+
+#ifdef __cplusplus
+#include "shader_cache_magic.h"
+const uint32_t cache_validation_data[] = {
+   ir_type_max,
+   GLSL_TYPE_ERROR,
+   sizeof(long),
+   sizeof(gl_shader),
+   sizeof(gl_program),
+   sizeof(gl_shader_program),
+   sizeof(gl_uniform_storage),
+   sizeof(gl_program_parameter_list),
+   sizeof(gl_program_parameter),
+   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 num_cache_validation_data_items\
+   sizeof(cache_validation_data)/sizeof(uint32_t)
+#endif
+
+/* C API for the cache */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char *
+mesa_shader_serialize(struct gl_shader *shader, size_t *size);
+
+char *
+mesa_program_serialize(struct gl_shader_program *prog, size_t *size);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SHADER_CACHE_H */
diff --git a/src/glsl/shader_serialize.cpp b/src/glsl/shader_serialize.cpp
new file mode 100644
index 0000000..842bc3a
--- /dev/null
+++ b/src/glsl/shader_serialize.cpp
@@ -0,0 +1,240 @@
+/* -*- 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 "shader_cache.h"
+#include "ir_serialize.h"
+
+
+static void
+serialize_program_parameters(struct gl_program_parameter_list *list,
+                             memory_writer &blob)
+{
+   for (unsigned i = 0; i < list->NumParameters; i++) {
+      blob.write_string(list->Parameters[i].Name);
+      blob.write(&list->Parameters[i], sizeof(struct gl_program_parameter));
+      blob.write(list->ParameterValues, 4 * sizeof(gl_constant_value));
+   }
+   blob.write_uint32_t(list->StateFlags);
+}
+
+
+/* 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);
+
+   uint8_t num_parameters = _mesa_num_parameters(shader->Program->Parameters);
+   blob.write_uint8_t(num_parameters);
+
+   if (num_parameters > 0)
+      serialize_program_parameters(shader->Program->Parameters, blob);
+}
+
+
+/**
+ * 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);
+
+   blob.write(shader, sizeof(struct gl_shader));
+
+   /* 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(uni, sizeof(gl_uniform_storage));
+   blob.write_string(uni->name);
+
+   /* note, type is not serialized, it is resolved during parsing */
+
+   /* 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());
+
+   blob.write_uint32_t(size);
+}
+
+
+/**
+ * Features not currently supported by the cache.
+ */
+static bool
+supported_by_cache(struct gl_shader_program *prog)
+{
+   /* No geometry shader support. */
+   if (prog->_LinkedShaders[MESA_SHADER_GEOMETRY])
+      return false;
+
+   /* No uniform block support. */
+   if (prog->NumUniformBlocks > 0)
+      return false;
+
+   /* No transform feedback support. */
+   if (prog->LinkedTransformFeedback.NumVarying > 0)
+      return false;
+
+   return true;
+}
+
+
+/**
+ * Serialize gl_shader_program structure
+ */
+extern "C" char *
+mesa_program_serialize(struct gl_shader_program *prog, size_t *size)
+{
+   if (!supported_by_cache(prog))
+      return NULL;
+
+   memory_writer blob;
+   blob.write(&cache_validation_data, sizeof(cache_validation_data));
+
+   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(prog, sizeof(gl_shader_program));
+
+   /* 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);
+
+   /* 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;
+
+      /* Set used GLSL version and IsES flag from gl_shader_program,
+       * this is required when deserializing the data.
+       */
+      prog->_LinkedShaders[i]->Version = prog->Version;
+      prog->_LinkedShaders[i]->IsES = prog->IsES;
+
+      char *data = mesa_shader_serialize(prog->_LinkedShaders[i], &sha_size);
+
+      if (!data)
+         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);
+}
-- 
1.8.3.1



More information about the mesa-dev mailing list