[Mesa-dev] [v2 3/6] glsl: ir_serializer class for the shader cache

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


ir_serializer can serialize a gl_shader structure as binary
data, 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_serializer.cpp | 933 +++++++++++++++++++++++++++++++++++++++
 src/glsl/ir_cache_serializer.h   | 207 +++++++++
 3 files changed, 1141 insertions(+)
 create mode 100644 src/glsl/ir_cache_serializer.cpp
 create mode 100644 src/glsl/ir_cache_serializer.h

diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources
index 2f7bfa1..0014f6f 100644
--- a/src/glsl/Makefile.sources
+++ b/src/glsl/Makefile.sources
@@ -30,6 +30,7 @@ LIBGLSL_FILES = \
 	$(GLSL_SRCDIR)/hir_field_selection.cpp \
 	$(GLSL_SRCDIR)/ir_basic_block.cpp \
 	$(GLSL_SRCDIR)/ir_builder.cpp \
+	$(GLSL_SRCDIR)/ir_cache_serializer.cpp \
 	$(GLSL_SRCDIR)/ir_clone.cpp \
 	$(GLSL_SRCDIR)/ir_constant_expression.cpp \
 	$(GLSL_SRCDIR)/ir.cpp \
diff --git a/src/glsl/ir_cache_serializer.cpp b/src/glsl/ir_cache_serializer.cpp
new file mode 100644
index 0000000..60e1d06
--- /dev/null
+++ b/src/glsl/ir_cache_serializer.cpp
@@ -0,0 +1,933 @@
+/* -*- 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_serializer.h"
+
+
+int
+save_glsl_type(memory_writer &blob, const glsl_type *type)
+{
+   uint32_t ir_len = 666;
+
+   blob.write_string(type->name);
+
+   int32_t start_pos = blob.position();
+   blob.write_uint32(&ir_len);
+
+   /* actual glsl_type data */
+   uint32_t base_type = type->base_type;
+   uint32_t length = type->length;
+   uint8_t vector_elms = type->vector_elements;
+   uint8_t matrix_cols = type->matrix_columns;
+   uint8_t sampler_dimensionality = type->sampler_dimensionality;
+   uint8_t sampler_shadow = type->sampler_shadow;
+   uint8_t sampler_array = type->sampler_array;
+   uint8_t sampler_type = type->sampler_type;
+   uint8_t interface_packing = type->interface_packing;
+
+   blob.write_uint32(&base_type);
+   blob.write_uint32(&length);
+   blob.write_uint8(&vector_elms);
+   blob.write_uint8(&matrix_cols);
+   blob.write_uint8(&sampler_dimensionality);
+   blob.write_uint8(&sampler_shadow);
+   blob.write_uint8(&sampler_array);
+   blob.write_uint8(&sampler_type);
+   blob.write_uint8(&interface_packing);
+
+   if (type->base_type == GLSL_TYPE_ARRAY)
+      save_glsl_type(blob, type->element_type());
+   else if (type->base_type == GLSL_TYPE_STRUCT ||
+      type->base_type == GLSL_TYPE_INTERFACE) {
+      glsl_struct_field *field = type->fields.structure;
+      for (unsigned k = 0; k < length; k++, field++) {
+         blob.write_string(field->name);
+         save_glsl_type(blob, field->type);
+         uint8_t row_major = field->row_major;
+         uint8_t interpolation = field->interpolation;
+         uint8_t centroid = field->centroid;
+         blob.write_uint8(&row_major);
+         blob.write_int32(&field->location);
+         blob.write_uint8(&interpolation);
+         blob.write_uint8(&centroid);
+      }
+   }
+
+   ir_len = blob.position() - start_pos - sizeof(ir_len);
+   blob.overwrite(&ir_len, sizeof(ir_len), start_pos);
+   return 0;
+}
+
+
+/**
+ * Function to create an unique string for a ir_variable. This is
+ * used by variable dereferences to indicate the exact ir_variable
+ * when deserialization happens.
+ */
+static char *_unique_name(ir_variable *var)
+{
+   return ralloc_asprintf(NULL,
+      "%s_%ld", var->name ? var->name : "parameter", (intptr_t) var);
+}
+
+
+int
+ir_serializer::save_ir(ir_variable *ir)
+{
+   /* name can be NULL, see ir_print_visitor for explanation */
+   const char *non_null_name = ir->name ? ir->name : "parameter";
+   char *uniq = _unique_name(ir);
+
+   save_glsl_type(blob, ir->type);
+
+   blob.write_string(non_null_name);
+   blob.write_string(uniq);
+
+   uint8_t mode = ir->mode;
+   uint8_t read_only = ir->read_only;
+   uint8_t centroid = ir->centroid;
+   uint8_t invariant = ir->invariant;
+   uint8_t interpolation = ir->interpolation;
+   uint8_t origin_upper_left = ir->origin_upper_left;
+   uint8_t pixel_center_integer = ir->pixel_center_integer;
+   uint8_t explicit_location = ir->explicit_location;
+   uint8_t explicit_index = ir->explicit_index;
+   uint8_t explicit_binding = ir->explicit_binding;
+   uint8_t has_initializer = ir->has_initializer;
+   int32_t depth_layout = ir->depth_layout;
+   uint8_t location_frac = ir->location_frac;
+   uint8_t has_constant_value = ir->constant_value ? 1 : 0;
+   uint8_t has_constant_initializer = ir->constant_initializer ? 1 : 0;
+
+   blob.write_uint8(&mode);
+   blob.write_uint32(&ir->max_array_access);
+   blob.write_int32(&ir->location);
+   blob.write_uint8(&read_only);
+   blob.write_uint8(&centroid);
+   blob.write_uint8(&invariant);
+   blob.write_uint8(&interpolation);
+   blob.write_uint8(&origin_upper_left);
+   blob.write_uint8(&pixel_center_integer);
+   blob.write_uint8(&explicit_location);
+   blob.write_uint8(&explicit_index);
+   blob.write_uint8(&explicit_binding);
+   blob.write_uint8(&has_initializer);
+   blob.write_int32(&depth_layout);
+   blob.write_uint8(&location_frac);
+   blob.write_uint32(&ir->num_state_slots);
+   blob.write_uint8(&has_constant_value);
+   blob.write_uint8(&has_constant_initializer);
+
+   for (unsigned i = 0; i < ir->num_state_slots; i++) {
+      blob.write_int32(&ir->state_slots[i].swizzle);
+      for (unsigned j = 0; j < 5; j++) {
+         blob.write_int32(&ir->state_slots[i].tokens[j]);
+      }
+   }
+
+   CACHE_DEBUG("save ir_variable [%s] [%s]\n", non_null_name, uniq);
+
+   ralloc_free(uniq);
+
+   if (ir->constant_value)
+      if (save(ir->constant_value))
+         return -1;
+
+   if (ir->constant_initializer)
+      if (save(ir->constant_initializer))
+         return -1;
+
+   uint8_t has_interface_type =
+      ir->is_interface_instance() ? 1 : 0;
+
+   blob.write_uint8(&has_interface_type);
+
+   if (has_interface_type)
+      save_glsl_type(blob, ir->get_interface_type());
+
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_dereference_array *ir)
+{
+   uint32_t array_type = ir->array->ir_type;
+   uint32_t array_index_type = ir->array_index->ir_type;
+   blob.write_uint32(&array_type);
+   save(ir->array);
+   blob.write_uint32(&array_index_type);
+   return save(ir->array_index);
+}
+
+
+int
+ir_serializer::save_ir(ir_dereference_record *ir)
+{
+   uint32_t ir_record_type = ir->record->ir_type;
+   blob.write_string(ir->field);
+   blob.write_uint32(&ir_record_type);
+   return save(ir->record);
+}
+
+
+int
+ir_serializer::save_ir(ir_dereference_variable *ir)
+{
+   char *uniq = _unique_name(ir->var);
+   blob.write_string(uniq);
+
+   CACHE_DEBUG("save ir_dereference_variable [%s]\n", uniq);
+
+   ralloc_free(uniq);
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_constant *ir)
+{
+   save_glsl_type(blob, ir->type);
+
+   blob.write(&ir->value, sizeof(ir_constant_data));
+
+   if (ir->array_elements) {
+      for (unsigned i = 0; i < ir->type->length; i++)
+         if (save(ir->array_elements[i]))
+            return -1;
+   }
+
+   uint32_t components = 0;
+
+   /* struct constant, dump components exec_list */
+   if (!ir->components.is_empty()) {
+      foreach_iter(exec_list_iterator, iter, ir->components)
+         components++;
+      blob.write_uint32(&components);
+
+      foreach_iter(exec_list_iterator, iter, ir->components) {
+         ir_instruction *const inst = (ir_instruction *) iter.get();
+         if (save(inst))
+            return -1;
+      }
+   }
+
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_expression *ir)
+{
+   int32_t num_operands = ir->get_num_operands();
+   uint32_t exp_operation = ir->operation;
+
+   save_glsl_type(blob, ir->type);
+
+   blob.write_uint32(&exp_operation);
+   blob.write_int32(&num_operands);
+
+   /* operand ir_type below is written to make parsing easier */
+   for (unsigned i = 0; i < ir->get_num_operands(); i++) {
+      uint32_t ir_type = ir->operands[i]->ir_type;
+      blob.write_uint32(&ir_type);
+      if (save(ir->operands[i]))
+         return -1;
+   }
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_function *ir)
+{
+   uint32_t sig_amount = 0;
+
+   foreach_iter(exec_list_iterator, iter, *ir)
+      sig_amount++;
+
+   blob.write_string(ir->name);
+   blob.write_uint32(&sig_amount);
+
+   CACHE_DEBUG("save ir_function [%s], %d sigs\n", ir->name, sig_amount);
+
+   foreach_iter(exec_list_iterator, iter, *ir) {
+      ir_function_signature *const sig = (ir_function_signature *) iter.get();
+      if (save(sig))
+         return -1;
+   }
+
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_function_signature *ir)
+{
+   int32_t par_count = 0;
+   int32_t body_size = 0;
+   uint8_t is_builtin = ir->is_builtin();
+
+   foreach_iter(exec_list_iterator, iter, ir->parameters)
+      par_count++;
+
+   foreach_iter(exec_list_iterator, iter, ir->body)
+      body_size++;
+
+   CACHE_DEBUG("signature (%s), returns %d, params %d size %d (builtin %d)\n",
+               ir->function_name(), ir->return_type->base_type, par_count,
+               body_size, is_builtin);
+
+   blob.write_int32(&par_count);
+   blob.write_int32(&body_size);
+   blob.write_uint8(&is_builtin);
+
+   /* dump the return type of function */
+   save_glsl_type(blob, ir->return_type);
+
+   /* function parameters */
+   foreach_iter(exec_list_iterator, iter, ir->parameters) {
+      ir_variable *const inst = (ir_variable *) iter.get();
+      CACHE_DEBUG("   parameter %s\n", inst->name);
+      if (save(inst))
+         return -1;
+   }
+
+   if (prototypes_only)
+      return 0;
+
+   /* function body */
+   foreach_iter(exec_list_iterator, iter, ir->body) {
+      ir_instruction *const inst = (ir_instruction *) iter.get();
+      CACHE_DEBUG("   body instruction node type %d\n", inst->ir_type);
+      if (save(inst))
+         return -1;
+   }
+
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_assignment *ir)
+{
+   uint32_t write_mask = ir->write_mask;
+
+   blob.write_uint32(&write_mask);
+
+   /* lhs (ir_deference_*) */
+   uint32_t lhs_type = ir->lhs->ir_type;
+   blob.write_uint32(&lhs_type);
+
+   if (save(ir->lhs))
+      return -1;
+
+   if (ir->condition) {
+      CACHE_DEBUG("%s: assignment has condition, not supported", __func__);
+   }
+
+    /* rhs (constant, expression ...) */
+   uint32_t rhs_type = ir->rhs->ir_type;
+   blob.write_uint32(&rhs_type);
+
+   if (save(ir->rhs))
+      return -1;
+
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_return *ir)
+{
+   ir_rvalue *const value = ir->get_value();
+   uint8_t has_rvalue = value ? 1 : 0;
+
+   blob.write_uint8(&has_rvalue);
+
+   if (has_rvalue) {
+      uint32_t ir_type = value->ir_type;
+      blob.write_uint32(&ir_type);
+      return save(value);
+   }
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_swizzle *ir)
+{
+   uint32_t components = ir->mask.num_components;
+   const uint32_t mask[4] = {
+      ir->mask.x,
+      ir->mask.y,
+      ir->mask.z,
+      ir->mask.w
+   };
+   uint32_t val_type = ir->val->ir_type;
+
+   blob.write_uint32(&components);
+   blob.write(&mask, 4 * sizeof(mask[0]));
+   blob.write_uint32(&val_type);
+
+   return save(ir->val);
+}
+
+
+int
+ir_serializer::save_ir(ir_texture *ir)
+{
+   int32_t op = ir->op;
+   uint8_t has_coordinate = ir->coordinate ? 1 : 0;
+   uint8_t has_projector = ir->projector ? 1 : 0;
+   uint8_t has_shadow_comp = ir->shadow_comparitor ? 1 : 0;
+   uint8_t has_offset = ir->offset ? 1 : 0;
+   uint32_t ir_type;
+
+   CACHE_DEBUG("save_ir_texture: op %d, coord %d proj %d shadow %d\n",
+               op, has_coordinate, has_projector, has_shadow_comp);
+
+   blob.write_int32(&op);
+   blob.write_uint8(&has_coordinate);
+   blob.write_uint8(&has_projector);
+   blob.write_uint8(&has_shadow_comp);
+   blob.write_uint8(&has_offset);
+
+   save_glsl_type(blob, ir->type);
+
+   /* sampler */
+   ir_type = ir->sampler->ir_type;
+   blob.write_uint32(&ir_type);
+   if (save(ir->sampler))
+      return -1;
+
+   if (has_coordinate) {
+      ir_type = ir->coordinate->ir_type;
+      blob.write_uint32(&ir_type);
+      if (save(ir->coordinate))
+         return -1;
+   }
+
+   if (has_projector) {
+      ir_type = ir->projector->ir_type;
+      blob.write_uint32(&ir_type);
+      if (save(ir->projector))
+         return -1;
+   }
+
+   if (has_shadow_comp) {
+      ir_type = ir->shadow_comparitor->ir_type;
+      blob.write_uint32(&ir_type);
+      if (save(ir->shadow_comparitor))
+         return -1;
+   }
+
+   if (has_offset) {
+      ir_type = ir->offset->ir_type;
+      blob.write_uint32(&ir_type);
+      if (save(ir->offset))
+         return -1;
+   }
+
+   /* lod_info structure */
+   uint8_t has_lod = ir->lod_info.lod ? 1 : 0;
+   uint8_t has_bias = ir->lod_info.bias ? 1 : 0;
+   uint8_t has_sample_index = ir->lod_info.sample_index ? 1 : 0;
+   uint8_t has_component = ir->lod_info.component ? 1 : 0;
+   uint8_t has_dpdx = ir->lod_info.grad.dPdx ? 1 : 0;
+   uint8_t has_dpdy = ir->lod_info.grad.dPdy ? 1 : 0;
+
+   blob.write_uint8(&has_lod);
+   blob.write_uint8(&has_bias);
+   blob.write_uint8(&has_sample_index);
+   blob.write_uint8(&has_component);
+   blob.write_uint8(&has_dpdx);
+   blob.write_uint8(&has_dpdy);
+
+   if (has_lod)
+      if (save(ir->lod_info.lod))
+         return -1;
+   if (has_bias)
+      if (save(ir->lod_info.bias))
+         return -1;
+   if (has_sample_index)
+      if (save(ir->lod_info.sample_index))
+         return -1;
+   if (has_component)
+      if (save(ir->lod_info.component))
+         return -1;
+   if (has_dpdx)
+      if (save(ir->lod_info.grad.dPdx))
+         return -1;
+   if (has_dpdy)
+      if (save(ir->lod_info.grad.dPdy))
+         return -1;
+
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_discard *ir)
+{
+   uint8_t has_condition = ir->condition ? 1 : 0;
+   blob.write_uint8(&has_condition);
+
+   if (ir->condition != NULL) {
+      CACHE_DEBUG("%s: error, there is no cond support here yet...\n",
+                  __func__);
+      if (save(ir->condition))
+         return -1;
+   }
+
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_call *ir)
+{
+   blob.write_string(ir->callee_name());
+
+   uint8_t has_return_deref = ir->return_deref ? 1 : 0;
+   uint8_t list_len = 0;
+   uint8_t use_builtin = ir->use_builtin;
+
+   blob.write_uint8(&has_return_deref);
+
+   if (ir->return_deref)
+      if (save(ir->return_deref))
+         return -1;
+
+   /* call parameter list */
+   foreach_iter(exec_list_iterator, iter, *ir)
+      list_len++;
+
+   blob.write_uint8(&list_len);
+
+   foreach_iter(exec_list_iterator, iter, *ir) {
+      ir_instruction *const inst = (ir_instruction *) iter.get();
+
+      int32_t ir_type = inst->ir_type;
+      blob.write_int32(&ir_type);
+
+      if (save(inst))
+         return -1;
+   }
+
+   blob.write_uint8(&use_builtin);
+
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_if *ir)
+{
+   uint32_t then_len = 0, else_len = 0;
+   uint32_t cond_type = ir->condition->ir_type;
+
+   /* then and else branch lengths */
+   foreach_iter(exec_list_iterator, iter, ir->then_instructions)
+      then_len++;
+   foreach_iter(exec_list_iterator, iter, ir->else_instructions)
+      else_len++;
+
+   blob.write_uint32(&then_len);
+   blob.write_uint32(&else_len);
+   blob.write_uint32(&cond_type);
+
+   CACHE_DEBUG("dump ir_if (then %d else %d), condition ir_type %d\n",
+               then_len, else_len, ir->condition->ir_type);
+
+   save(ir->condition);
+
+   /* dump branch instruction lists */
+   foreach_iter(exec_list_iterator, iter, ir->then_instructions) {
+      ir_instruction *const inst = (ir_instruction *) iter.get();
+      CACHE_DEBUG("   ir_if then instruction node type %d\n", inst->ir_type);
+      if (save(inst))
+         return -1;
+   }
+
+   foreach_iter(exec_list_iterator, iter, ir->else_instructions) {
+      ir_instruction *const inst = (ir_instruction *) iter.get();
+      CACHE_DEBUG("   ir_if else instruction node type %d\n", inst->ir_type);
+      if (save(inst))
+         return -1;
+   }
+
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_loop *ir)
+{
+   uint8_t has_counter = ir->counter ? 1 : 0;
+   uint8_t has_from = ir->from ? 1 : 0;
+   uint8_t has_to = ir->to ? 1 : 0;
+   uint8_t has_incr = ir->increment ? 1 : 0;
+   uint32_t body_size = 0;
+   uint32_t ir_type;
+
+   foreach_iter(exec_list_iterator, iter, ir->body_instructions)
+      body_size++;
+
+   blob.write_uint8(&has_from);
+   blob.write_uint8(&has_to);
+   blob.write_uint8(&has_incr);
+   blob.write_uint8(&has_counter);
+   blob.write_int32(&ir->cmp);
+   blob.write_uint32(&body_size);
+
+   if (has_from) {
+      ir_type = ir->from->ir_type;
+      blob.write_uint32(&ir_type);
+      if (save(ir->from))
+         return -1;
+   }
+
+   if (has_to) {
+      ir_type = ir->to->ir_type;
+      blob.write_uint32(&ir_type);
+      if (save(ir->to))
+         return -1;
+   }
+
+   if (has_incr) {
+      ir_type = ir->increment->ir_type;
+      blob.write_uint32(&ir_type);
+      if (save(ir->increment))
+         return -1;
+   }
+
+   if (has_counter) {
+     blob.write_string(ir->counter->name);
+     if (save(ir->counter))
+        return -1;
+   }
+
+   foreach_iter(exec_list_iterator, iter, ir->body_instructions) {
+      ir_instruction *const inst = (ir_instruction *) iter.get();
+      CACHE_DEBUG("save loop instruction type %d\n", inst->ir_type);
+      if (save(inst))
+         return -1;
+   }
+
+   return 0;
+}
+
+
+int ir_serializer::save_ir(ir_loop_jump *ir)
+{
+   uint32_t mode = ir->mode;
+   return blob.write_uint32(&mode);
+}
+
+
+int
+ir_serializer::save_ir(ir_emit_vertex *ir)
+{
+   return 0;
+}
+
+
+int
+ir_serializer::save_ir(ir_end_primitive *ir)
+{
+   return 0;
+}
+
+
+/**
+ * writes instruction type, packet size and calls
+ * save function for the instruction to save the data
+ */
+int
+ir_serializer::save(ir_instruction *ir)
+{
+   uint32_t ir_len = 666;
+   uint32_t ir_type = ir->ir_type;
+
+   blob.write_uint32(&ir_type);
+
+   int32_t start_pos = blob.position();
+
+   blob.write_uint32(&ir_len);
+
+#define SAVE_IR(type)\
+   if (save_ir(static_cast<type *>(ir))) goto write_errors;
+
+   switch(ir->ir_type) {
+
+   case ir_type_variable:
+      SAVE_IR(ir_variable);
+      break;
+   case ir_type_call:
+      SAVE_IR(ir_call);
+      break;
+   case ir_type_constant:
+      SAVE_IR(ir_constant);
+      break;
+   case ir_type_discard:
+      SAVE_IR(ir_discard);
+      break;
+   case ir_type_expression:
+      SAVE_IR(ir_expression);
+      break;
+   case ir_type_dereference_array:
+      SAVE_IR(ir_dereference_array);
+      break;
+   case ir_type_dereference_record:
+      SAVE_IR(ir_dereference_record);
+      break;
+   case ir_type_dereference_variable:
+      SAVE_IR(ir_dereference_variable);
+      break;
+   case ir_type_function:
+      SAVE_IR(ir_function);
+      break;
+   case ir_type_function_signature:
+      SAVE_IR(ir_function_signature);
+      break;
+   case ir_type_swizzle:
+      SAVE_IR(ir_swizzle);
+      break;
+   case ir_type_texture:
+      SAVE_IR(ir_texture);
+      break;
+   case ir_type_assignment:
+      SAVE_IR(ir_assignment);
+      break;
+   case ir_type_if:
+      SAVE_IR(ir_if);
+      break;
+   case ir_type_loop:
+      SAVE_IR(ir_loop);
+      break;
+   case ir_type_loop_jump:
+      SAVE_IR(ir_loop_jump);
+      break;
+   case ir_type_return:
+      SAVE_IR(ir_return);
+      break;
+   case ir_type_emit_vertex:
+      SAVE_IR(ir_emit_vertex);
+      break;
+   case ir_type_end_primitive:
+      SAVE_IR(ir_end_primitive);
+      break;
+
+   default:
+      CACHE_DEBUG("%s: error, type %d not implemented\n",
+                  __func__, ir->ir_type);
+      return -1;
+   }
+
+   ir_len = blob.position() - start_pos - sizeof(ir_len);
+
+   blob.overwrite(&ir_len, sizeof(ir_len), start_pos);
+
+   return 0;
+
+write_errors:
+   CACHE_DEBUG("%s: write errors (ir type %d)\n", __func__, ir->ir_type);
+   return -1;
+}
+
+
+static void
+_write_header(gl_shader *shader, const char *mesa_sha, memory_writer &blob)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   blob.write_string(mesa_sha);
+   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(&shader->Version);
+   blob.write_uint32(&shader->Type);
+   blob.write_uint8(&shader->IsES);
+
+   /* post-link data */
+   blob.write_uint32(&shader->num_samplers);
+   blob.write_uint32(&shader->active_samplers);
+   blob.write_uint32(&shader->shadow_samplers);
+   blob.write_uint32(&shader->num_uniform_components);
+   blob.write_uint32(&shader->num_combined_uniform_components);
+
+   for (unsigned i = 0; i < MAX_SAMPLERS; i++)
+      blob.write_uint8(&shader->SamplerUnits[i]);
+
+   for (unsigned i = 0; i < MAX_SAMPLERS; i++) {
+      int32_t target = shader->SamplerTargets[i];
+      blob.write_int32(&target);
+   }
+}
+
+
+static void
+_dump_bool(bool value, memory_writer &blob)
+{
+   uint8_t val = value;
+   blob.write_uint8(&val);
+}
+
+
+/**
+ * some of the state such as extension bits is required from
+ * the preprocessing stage, this is when caching unlinked shaders
+ */
+static void
+_write_state(struct _mesa_glsl_parse_state *state, memory_writer &blob)
+{
+   blob.write_uint32(&state->language_version);
+
+   _dump_bool(state->ARB_draw_buffers_enable, blob);
+   _dump_bool(state->ARB_draw_buffers_warn, blob);
+   _dump_bool(state->ARB_draw_instanced_enable, blob);
+   _dump_bool(state->ARB_draw_instanced_warn, blob);
+   _dump_bool(state->ARB_explicit_attrib_location_enable, blob);
+   _dump_bool(state->ARB_explicit_attrib_location_warn, blob);
+   _dump_bool(state->ARB_fragment_coord_conventions_enable, blob);
+   _dump_bool(state->ARB_fragment_coord_conventions_warn, blob);
+   _dump_bool(state->ARB_texture_rectangle_enable, blob);
+   _dump_bool(state->ARB_texture_rectangle_warn, blob);
+   _dump_bool(state->EXT_texture_array_enable, blob);
+   _dump_bool(state->EXT_texture_array_warn, blob);
+   _dump_bool(state->ARB_shader_texture_lod_enable, blob);
+   _dump_bool(state->ARB_shader_texture_lod_warn, blob);
+   _dump_bool(state->ARB_shader_stencil_export_enable, blob);
+   _dump_bool(state->ARB_shader_stencil_export_warn, blob);
+   _dump_bool(state->AMD_conservative_depth_enable, blob);
+   _dump_bool(state->AMD_conservative_depth_warn, blob);
+   _dump_bool(state->ARB_conservative_depth_enable, blob);
+   _dump_bool(state->ARB_conservative_depth_warn, blob);
+   _dump_bool(state->AMD_shader_stencil_export_enable, blob);
+   _dump_bool(state->AMD_shader_stencil_export_warn, blob);
+   _dump_bool(state->OES_texture_3D_enable, blob);
+   _dump_bool(state->OES_texture_3D_warn, blob);
+   _dump_bool(state->OES_EGL_image_external_enable, blob);
+   _dump_bool(state->OES_EGL_image_external_warn, blob);
+   _dump_bool(state->ARB_shader_bit_encoding_enable, blob);
+   _dump_bool(state->ARB_shader_bit_encoding_warn, blob);
+   _dump_bool(state->ARB_uniform_buffer_object_enable, blob);
+   _dump_bool(state->ARB_uniform_buffer_object_warn, blob);
+   _dump_bool(state->OES_standard_derivatives_enable, blob);
+   _dump_bool(state->OES_standard_derivatives_warn, blob);
+   _dump_bool(state->ARB_texture_cube_map_array_enable, blob);
+   _dump_bool(state->ARB_texture_cube_map_array_warn, blob);
+   _dump_bool(state->ARB_shading_language_packing_enable, blob);
+   _dump_bool(state->ARB_shading_language_packing_warn, blob);
+   _dump_bool(state->ARB_texture_multisample_enable, blob);
+   _dump_bool(state->ARB_texture_multisample_warn, blob);
+   _dump_bool(state->ARB_texture_query_lod_enable, blob);
+   _dump_bool(state->ARB_texture_query_lod_warn, blob);
+   _dump_bool(state->ARB_gpu_shader5_enable, blob);
+   _dump_bool(state->ARB_gpu_shader5_warn, blob);
+   _dump_bool(state->AMD_vertex_shader_layer_enable, blob);
+   _dump_bool(state->AMD_vertex_shader_layer_warn, blob);
+   _dump_bool(state->ARB_shading_language_420pack_enable, blob);
+   _dump_bool(state->ARB_shading_language_420pack_warn, blob);
+   _dump_bool(state->EXT_shader_integer_mix_enable, blob);
+   _dump_bool(state->EXT_shader_integer_mix_warn, blob);
+}
+
+
+/**
+ * serializes a single gl_shader, writes shader header
+ * information and exec_list of instructions
+ */
+char *
+ir_serializer::serialize(struct gl_shader *shader,
+   struct _mesa_glsl_parse_state *state,
+   const char *mesa_sha, size_t *size)
+{
+   uint32_t total = 0;
+
+   prototypes_only = true;
+
+   *size = 0;
+
+   int32_t start_pos = blob.position();
+   uint32_t shader_data_len = 666;
+   uint32_t shader_type = shader->Type;
+
+   blob.write_uint32(&shader_data_len);
+   blob.write_uint32(&shader_type);
+
+   _write_header(shader, mesa_sha, blob);
+
+   if (state)
+      _write_state(state, blob);
+
+   /* count variables + functions and dump prototypes */
+   foreach_list_const(node, shader->ir) {
+      if (((ir_instruction *) node)->as_variable())
+         total++;
+      if (((ir_instruction *) node)->as_function())
+         total++;
+   }
+
+   blob.write_uint32(&total);
+
+   CACHE_DEBUG("write %d prototypes\n", total);
+
+   foreach_list_const(node, shader->ir) {
+      ir_instruction *const inst = (ir_instruction *) node;
+      if (inst->as_variable())
+         if (save(inst))
+            goto write_errors;
+   }
+
+   foreach_list_const(node, shader->ir) {
+      ir_instruction *const inst = (ir_instruction *) node;
+      if (inst->as_function())
+         if (save(inst))
+            goto write_errors;
+   }
+
+   /* all shader instructions */
+   prototypes_only = false;
+   foreach_list_const(node, shader->ir) {
+      ir_instruction *instruction = (ir_instruction *) node;
+      if (save(instruction))
+         goto write_errors;
+   }
+
+   CACHE_DEBUG("cached a shader\n");
+
+   /* how much has been written */
+   *size = blob.position();
+
+   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);
+
+write_errors:
+
+   return NULL;
+}
diff --git a/src/glsl/ir_cache_serializer.h b/src/glsl/ir_cache_serializer.h
new file mode 100644
index 0000000..6e33ca9
--- /dev/null
+++ b/src/glsl/ir_cache_serializer.h
@@ -0,0 +1,207 @@
+/* -*- 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_SERIALIZER_H
+#define IR_CACHE_SERIALIZER_H
+
+#include "ir.h"
+#include "glsl_parser_extras.h"
+
+#ifdef SHADER_CACHE_DEBUG
+#define CACHE_DEBUG(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define CACHE_DEBUG(fmt, ...) do {} while (0)
+#endif
+
+#ifdef __cplusplus
+/**
+ * Helper class for writing data to memory
+ *
+ * This class maintains a dynamically-sized memory buffer and allows
+ * for data to be efficiently appended to it with automatic resizing.
+ */
+class memory_writer
+{
+public:
+   memory_writer() :
+      memory(NULL),
+      curr_size(0),
+      pos(0) {}
+
+   ~memory_writer()
+   {
+      free(memory);
+   }
+
+   /* user wants to claim the memory */
+   char *release_memory(size_t *size)
+   {
+      /* final realloc to free allocated but unused memory */
+      char *result = (char *) realloc(memory, pos);
+      memory = NULL;
+      curr_size = 0;
+      pos = 0;
+      return result;
+   }
+
+   /* write functions for different data types */
+   int write_uint8(uint8_t *data)
+   {
+      return write(data, sizeof(uint8_t));
+   }
+   int write_int32(int32_t *data)
+   {
+      return write(data, sizeof(int32_t));
+   }
+   int write_uint32(uint32_t *data)
+   {
+      return write(data, sizeof(uint32_t));
+   }
+
+   /* write function that reallocates more memory if required */
+   int write(const void *data, int32_t size)
+   {
+      if (!memory || pos > (int32_t)(curr_size - size))
+         if (grow(size))
+            return -1;
+
+      memcpy(memory + pos, data, size);
+
+      pos += size;
+      return 0;
+   }
+
+   int overwrite(const void *data, int32_t size, int32_t offset)
+   {
+      if (offset < 0 || offset + size > pos)
+         return -1;
+      memcpy(memory + offset, data, size);
+      return 0;
+   }
+
+   int write_string(const char *str)
+   {
+      if (!str)
+         return -1;
+      char terminator = '\0';
+      write(str, strlen(str));
+      write(&terminator, 1);
+      return 0;
+   }
+
+   inline int32_t position() { return pos; }
+
+private:
+
+   /* reallocate more memory */
+   int grow(int32_t size)
+   {
+      int32_t new_size = 2 * (curr_size + size);
+      char *more_mem = (char *) realloc(memory, new_size);
+      if (more_mem == NULL) {
+         free(memory);
+         memory = NULL;
+         return -1;
+      } else {
+         memory = more_mem;
+         curr_size = new_size;
+         return 0;
+      }
+   }
+
+   /* allocated memory */
+   char *memory;
+
+   /* current size of the whole allocation */
+   int32_t curr_size;
+
+   /* write position / size of the data written */
+   int32_t pos;
+};
+
+
+/**
+ * Utility function used both by ir_serializer and
+ * gl_shader_program structure serialization code
+ */
+int save_glsl_type(memory_writer &blob, const glsl_type *type);
+
+/**
+ * Class to serialize gl_shader as a binary data blob
+ *
+ * Serialization is done by writing small header data section, parser
+ * state data and all IR instructions of the shader including any relevant
+ * data to be able to deserialize them back.
+ */
+class ir_serializer
+{
+public:
+   ir_serializer() :
+      prototypes_only(false)
+   {
+   }
+
+   /* serialize gl_shader to memory */
+   char *serialize(struct gl_shader *shader,
+               struct _mesa_glsl_parse_state *state,
+               const char *mesa_sha, size_t *size);
+
+private:
+
+   memory_writer blob;
+
+   bool prototypes_only;
+
+   /**
+    * writes ir_type and instruction dump size as a 'header'
+    * for each instruction before calling save_ir with it
+    */
+   int save(ir_instruction *ir);
+
+   /* methods for each ir type */
+   int save_ir(ir_variable *ir);
+   int save_ir(ir_assignment *ir);
+   int save_ir(ir_call *ir);
+   int save_ir(ir_constant *ir);
+   int save_ir(ir_dereference_array *ir);
+   int save_ir(ir_dereference_record *ir);
+   int save_ir(ir_dereference_variable *ir);
+   int save_ir(ir_discard *ir);
+   int save_ir(ir_expression *ir);
+   int save_ir(ir_function *ir);
+   int save_ir(ir_function_signature *ir);
+   int save_ir(ir_if *ir);
+   int save_ir(ir_loop *ir);
+   int save_ir(ir_loop_jump *ir);
+   int save_ir(ir_return *ir);
+   int save_ir(ir_swizzle *ir);
+   int save_ir(ir_texture *ir);
+   int save_ir(ir_emit_vertex *ir);
+   int save_ir(ir_end_primitive *ir);
+
+};
+#endif /* ifdef __cplusplus */
+
+#endif /* IR_CACHE_SERIALIZER_H */
-- 
1.8.1.4



More information about the mesa-dev mailing list