[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(¢roid);
+ }
+ }
+
+ 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(¢roid);
+ 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