[Mesa-dev] [PATCH v2] glsl: add ir_cache class for IR serialization (WIP)
Tapani Pälli
tapani.palli at intel.com
Fri Sep 20 04:48:54 PDT 2013
Patch introduces ir_cache class that can serialize a gl_shader
to a given file and also unserialize it back from a memory map.
This can be used by the shader compiler to cache individual
shaders and skip lexing, parsing, type checking, AST->IR
generation and optimization rounds that happen during compilation.
v2: fix builtin function handling in read_ir_function(), now
generated IR is identical with original
Known issues / bugs / missing implementation:
- constant structures not supported
- interfaces not supported
- no support for geometry shader emit_vertex, emit_primitive
- write/read file i/o likely not portable to some architectures
TODO
- try to use tpl or other library for serialization
- think of ways to reorganize ir_* structure contents for
faster data dumping/loading
- when writing, write to memory first, then data can be
either dumped to disk or given to further usage (for
shader cache extension)
- save also process name if possible, this would help when
filing bugs and debugging
Signed-off-by: Tapani Pälli <tapani.palli at intel.com>
---
src/glsl/Makefile.sources | 2 +
src/glsl/ir_cache.h | 536 +++++++++++++++++++++
src/glsl/ir_cache_serialize.cpp | 603 +++++++++++++++++++++++
src/glsl/ir_cache_unserialize.cpp | 973 ++++++++++++++++++++++++++++++++++++++
4 files changed, 2114 insertions(+)
create mode 100644 src/glsl/ir_cache.h
create mode 100644 src/glsl/ir_cache_serialize.cpp
create mode 100644 src/glsl/ir_cache_unserialize.cpp
diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources
index 2f7bfa1..1a3e72e 100644
--- a/src/glsl/Makefile.sources
+++ b/src/glsl/Makefile.sources
@@ -30,6 +30,8 @@ LIBGLSL_FILES = \
$(GLSL_SRCDIR)/hir_field_selection.cpp \
$(GLSL_SRCDIR)/ir_basic_block.cpp \
$(GLSL_SRCDIR)/ir_builder.cpp \
+ $(GLSL_SRCDIR)/ir_cache_serialize.cpp \
+ $(GLSL_SRCDIR)/ir_cache_unserialize.cpp \
$(GLSL_SRCDIR)/ir_clone.cpp \
$(GLSL_SRCDIR)/ir_constant_expression.cpp \
$(GLSL_SRCDIR)/ir.cpp \
diff --git a/src/glsl/ir_cache.h b/src/glsl/ir_cache.h
new file mode 100644
index 0000000..ad9c18a
--- /dev/null
+++ b/src/glsl/ir_cache.h
@@ -0,0 +1,536 @@
+/* -*- 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_H
+#define IR_CACHE_H
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "ir.h"
+#include "main/imports.h"
+#include "glsl_parser_extras.h"
+#include "program/hash_table.h"
+
+extern "C" {
+#include "program/symbol_table.h"
+}
+
+//#define SHADER_CACHE_DEBUG
+#ifdef SHADER_CACHE_DEBUG
+#define CACHE_DEBUG(fmt, args...) printf(fmt, ## args)
+#else
+#define CACHE_DEBUG(fmt, args...) do {} while (0)
+#endif
+
+
+/**
+ * helpers for writing to file
+ */
+#define _WRITE_VAL(_a, _file) fwrite(&_a, sizeof(_a), 1, _file)
+
+#define _WRITE_STRING_DATA(_s, _file) {\
+ _WRITE_VAL(_s->len, _file);\
+ fwrite(_s->data, _s->len, 1, _file);\
+}
+
+#define WRITE_STRING(_s, _file) {\
+ int32_t _len = strlen(_s);\
+ _WRITE_VAL(_len, _file);\
+ fwrite(_s, _len * sizeof(char), 1, _file);\
+}
+
+
+/**
+ * helper functions for dumping package size information
+ */
+static long PROLOGUE(FILE *out)
+{
+ long value = 666;
+ long offset = ftell(out);
+ _WRITE_VAL(value, out);
+ return offset;
+}
+
+static void EPILOGUE(FILE *out, long start)
+{
+ long end = ftell(out);
+ fseek(out, start, SEEK_SET);
+ long size = end - start - sizeof(long);
+ _WRITE_VAL(size, out);
+ fseek(out, end, SEEK_SET);
+}
+
+
+/**
+ * structures used for instruction serialization/creation
+ */
+struct string_data
+{
+public:
+ string_data() : data(NULL) {}
+ string_data(const char *cstr) :
+ data(NULL)
+ {
+ if (cstr) {
+ len = strlen(cstr);
+ data = _mesa_strdup(cstr);
+ }
+ }
+
+ ~string_data() {
+ if (data) {
+ free(data);
+ data = NULL;
+ }
+ }
+
+ void set(const char *cstr)
+ {
+ if (data)
+ free(data);
+ data = _mesa_strdup(cstr);
+ len = strlen(cstr);
+ }
+
+ int32_t len;
+ char *data;
+
+};
+
+
+/**
+ * data required to serialize glsl_type
+ */
+struct glsl_type_data
+{
+public:
+ glsl_type_data() :
+ name(NULL),
+ element_type(NULL),
+ field_names(NULL),
+ field_types(NULL) {}
+
+ glsl_type_data(const glsl_type *t) :
+ base_type(t->base_type),
+ length(t->length),
+ vector_elms(t->vector_elements),
+ matrix_cols(t->matrix_columns),
+ sampler_dimensionality(t->sampler_dimensionality),
+ sampler_shadow(t->sampler_shadow),
+ sampler_array(t->sampler_array),
+ sampler_type(t->sampler_type),
+ interface_packing(t->interface_packing),
+ element_type(NULL),
+ field_names(NULL),
+ field_types(NULL)
+ {
+ name = new string_data(t->name);
+
+ /* for array, save element type information */
+ if (t->base_type == GLSL_TYPE_ARRAY)
+ element_type =
+ new glsl_type_data(t->element_type());
+
+ /* with structs, copy each struct field name + type */
+ else if (t->base_type == GLSL_TYPE_STRUCT) {
+
+ field_names = new string_data[t->length];
+ field_types = new glsl_type_data*[t->length];
+
+ glsl_struct_field *field = t->fields.structure;
+ glsl_type_data **field_t = field_types;
+ for (unsigned k = 0; k < t->length; k++, field++, field_t++) {
+ field_names[k].set(field->name);
+ *field_t = new glsl_type_data(field->type);
+ }
+ }
+
+ else if (t->base_type == GLSL_TYPE_SAMPLER) {
+ /* TODO - figure out if we need to dump more data than right now */
+ }
+
+ }
+
+ ~glsl_type_data() {
+ delete name;
+ delete element_type;
+ delete [] field_names;
+ if (field_types) {
+ struct glsl_type_data **data = field_types;
+ for (int k = 0; k < length; k++, data++)
+ delete *data;
+ delete [] field_types;
+ }
+ }
+
+ int serialize(FILE *out)
+ {
+ _WRITE_STRING_DATA(name, out);
+
+ long start = PROLOGUE(out);
+
+ fwrite(this, sizeof(*this), 1, out);
+
+ if (base_type == GLSL_TYPE_ARRAY)
+ element_type->serialize(out);
+ else if (base_type == GLSL_TYPE_STRUCT) {
+ struct string_data *data = field_names;
+ glsl_type_data **field_t = field_types;
+ for (int k = 0; k < length; k++, data++, field_t++) {
+ _WRITE_STRING_DATA(data, out);
+ (*field_t)->serialize(out);
+ }
+ }
+
+ EPILOGUE(out, start);
+ return 0;
+ }
+
+ int32_t base_type;
+ int32_t length;
+ int32_t vector_elms;
+ int32_t matrix_cols;
+
+ uint32_t sampler_dimensionality;
+ uint32_t sampler_shadow;
+ uint32_t sampler_array;
+ uint32_t sampler_type;
+
+ uint32_t interface_packing;
+
+ struct string_data *name;
+
+ /* array element type */
+ struct glsl_type_data *element_type;
+
+ /* structure fields */
+ struct string_data *field_names;
+ struct glsl_type_data **field_types;
+};
+
+
+/* helper to create a unique id from a ir_variable address */
+static uint32_t _unique_id(ir_variable *var)
+{
+ char buffer[256];
+ _mesa_snprintf(buffer, 256, "%s_%p", var->name, var);
+ return _mesa_str_checksum(buffer);
+}
+
+
+struct ir_variable_data
+{
+public:
+ ir_variable_data() :
+ type(NULL),
+ name(NULL),
+ unique_name(NULL) {}
+
+ ir_variable_data(ir_variable *ir) :
+ unique_id(_unique_id(ir)),
+ max_array_access(ir->max_array_access),
+ ir_type(ir->ir_type),
+ mode(ir->mode),
+ location(ir->location),
+ centroid(ir->centroid),
+ invariant(ir->invariant),
+ interpolation(ir->interpolation),
+ explicit_location(ir->explicit_location),
+ explicit_index(ir->explicit_index),
+ explicit_binding(ir->explicit_binding),
+ has_constant_value(ir->constant_value ? 1 : 0),
+ has_constant_initializer(ir->constant_initializer ? 1 : 0)
+ {
+ char uniq[256];
+ _mesa_snprintf(uniq, 256, "%s_%d", ir->name, unique_id);
+ unique_name = new string_data(uniq);
+ name = new string_data(ir->name);
+ type = new glsl_type_data(ir->type);
+ }
+
+ ~ir_variable_data()
+ {
+ delete name;
+ delete unique_name;
+ delete type;
+ }
+
+ int serialize(FILE *out)
+ {
+ type->serialize(out);
+ _WRITE_STRING_DATA(name, out);
+ _WRITE_STRING_DATA(unique_name, out);
+ fwrite(this, sizeof(*this), 1, out);
+
+ return 0;
+ }
+
+ struct glsl_type_data *type;
+ struct string_data *name;
+ struct string_data *unique_name;
+
+ uint32_t unique_id;
+
+ uint32_t max_array_access;
+ int32_t ir_type;
+ int32_t mode;
+ int32_t location;
+ uint32_t centroid;
+ uint32_t invariant;
+ uint32_t interpolation;
+
+ uint32_t explicit_location;
+ uint32_t explicit_index;
+ uint32_t explicit_binding;
+
+ uint32_t has_constant_value;
+ uint32_t has_constant_initializer;
+};
+
+
+/**
+ * helper class to read instructions
+ */
+struct memory_map
+{
+public:
+ memory_map() :
+ fd(0),
+ cache_size(0),
+ cache_mmap(NULL),
+ cache_mmap_p(NULL) { }
+
+ int map(const char *path)
+ {
+ struct stat stat_info;
+ if (stat(path, &stat_info) != 0)
+ return -1;
+
+ cache_size = stat_info.st_size;
+
+ fd = open(path, O_RDONLY);
+ if (fd) {
+ cache_mmap_p = cache_mmap = (char *)
+ mmap(NULL, cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ return (cache_mmap == MAP_FAILED) ? -1 : 0;
+ }
+ return -1;
+ }
+
+ ~memory_map() {
+ if (cache_mmap) {
+ munmap(cache_mmap, cache_size);
+ close(fd);
+ }
+ }
+
+ /* move read pointer forward */
+ inline void ffwd(int len)
+ {
+ cache_mmap_p += len;
+ }
+
+ /* have we reached the end of mapping? */
+ inline bool end()
+ {
+ return (!((cache_mmap_p - cache_mmap) < cache_size));
+ }
+
+ /* template avoids use of typeof() cast */
+ template <typename T>
+ inline void read_value(T *val)
+ {
+ *val = *(T *)cache_mmap_p;
+ ffwd(sizeof(T));
+ }
+
+ template <typename T>
+ inline void read_nval(T *val, uint32_t amount)
+ {
+ memcpy(val, cache_mmap_p, amount * sizeof(val[0]));
+ ffwd(amount * sizeof(val[0]));
+ }
+
+ inline void read_string(char *str)
+ {
+ uint32_t len;
+ read_value(&len);
+ memcpy(str, cache_mmap_p, len);
+ str[len] = '\0';
+ ffwd(len);
+ }
+
+ template <typename T>
+ inline void read_struct(T *s)
+ {
+ memcpy(s, cache_mmap_p, sizeof(*s));
+ ffwd(sizeof(*s));
+ }
+
+private:
+
+ int32_t fd;
+ int32_t cache_size;
+ char *cache_mmap;
+ char *cache_mmap_p;
+};
+
+
+struct ir_cache
+{
+public:
+ ir_cache(bool prototypes = false) :
+ prototypes_only(prototypes)
+ {
+ var_ht = hash_table_ctor(0, hash_table_string_hash,
+ hash_table_string_compare);
+ }
+
+ ~ir_cache()
+ {
+ hash_table_call_foreach(this->var_ht, delete_key, NULL);
+ hash_table_dtor(this->var_ht);
+ }
+
+ /* serialize gl_shader to a FILE */
+ int serialize(struct gl_shader *shader,
+ struct _mesa_glsl_parse_state *state, FILE *out,
+ const char *mesa_sha);
+
+ /* unserialize gl_shader from mapped memory */
+ struct gl_shader *unserialize(void *mem_ctx, memory_map &map,
+ struct _mesa_glsl_parse_state *state,
+ const char *mesa_sha,
+ int *error_code);
+
+ enum cache_error {
+ GENERAL_READ_ERROR = -1,
+ DIFFERENT_MESA_SHA = -2,
+ };
+
+private:
+
+ /* variables and methods required for serialization */
+
+ bool prototypes_only;
+
+ /**
+ * writes ir_type and instruction dump size as a 'header'
+ * for each instruction before calling save_ir
+ */
+ int save(ir_instruction *ir, FILE *out);
+
+ int save_ir(ir_variable *ir, FILE *out);
+ int save_ir(ir_assignment *ir, FILE *out);
+ int save_ir(ir_call *ir, FILE *out);
+ int save_ir(ir_constant *ir, FILE *out);
+ int save_ir(ir_dereference_array *ir, FILE *out);
+ int save_ir(ir_dereference_record *ir, FILE *out);
+ int save_ir(ir_dereference_variable *ir, FILE *out);
+ int save_ir(ir_discard *ir, FILE *out);
+ int save_ir(ir_expression *ir, FILE *out);
+ int save_ir(ir_function *ir, FILE *out);
+ int save_ir(ir_function_signature *ir, FILE *out);
+ int save_ir(ir_if *ir, FILE *out);
+ int save_ir(ir_loop *ir, FILE *out);
+ int save_ir(ir_loop_jump *ir, FILE *out);
+ int save_ir(ir_return *ir, FILE *out);
+ int save_ir(ir_swizzle *ir, FILE *out);
+ int save_ir(ir_emit_vertex *ir, FILE *out);
+ int save_ir(ir_end_primitive *ir, FILE *out);
+
+ /* variables and methods required for unserialization */
+
+ struct _mesa_glsl_parse_state *state;
+ void *mem_ctx;
+
+ struct exec_list *top_level;
+ struct exec_list *prototypes;
+ struct exec_list *current_function;
+
+ /* reads saved parser state variables and initializes builtins */
+ int read_state(struct _mesa_glsl_parse_state *state, memory_map &map);
+
+ int read_header(struct gl_shader *shader, memory_map &map,
+ const char *mesa_sha);
+ int read_prototypes(memory_map &map);
+
+ int read_instruction(struct exec_list *list, memory_map &map,
+ bool ignore = false);
+
+ int read_ir_variable(struct exec_list *list, memory_map &map);
+ int read_ir_assignment(struct exec_list *list, memory_map &map);
+ int read_ir_function(struct exec_list *list, memory_map &map);
+ int read_ir_if(struct exec_list *list, memory_map &map);
+ int read_ir_return(struct exec_list *list, memory_map &map);
+ int read_ir_call(struct exec_list *list, memory_map &map);
+ int read_ir_discard(struct exec_list *list, memory_map &map);
+ int read_ir_loop(struct exec_list *list, memory_map &map);
+ int read_ir_loop_jump(struct exec_list *list, memory_map &map);
+
+ /* rvalue readers */
+ ir_rvalue *read_ir_rvalue(memory_map &map);
+ ir_constant *read_ir_constant(memory_map &map);
+ ir_swizzle *read_ir_swizzle(memory_map &map);
+ ir_expression *read_ir_expression(memory_map &map);
+ ir_dereference_array *read_ir_dereference_array(memory_map &map);
+ ir_dereference_record *read_ir_dereference_record(memory_map &map);
+ ir_dereference_variable *read_ir_dereference_variable(memory_map &map);
+
+ const glsl_type *read_glsl_type(memory_map &map);
+
+ /**
+ * var_ht is used to store created ir_variables with a unique_key for
+ * each so that ir_dereference_variable creation can find the variable
+ */
+ struct hash_table *var_ht;
+
+ /**
+ * these 2 functions are ~copy-pasta from string_to_uint_map,
+ * we need a hash here with a string key and pointer value
+ */
+ void hash_store(void * value, const char *key)
+ {
+ char *dup_key = strdup(key);
+ bool result = hash_table_replace(this->var_ht, value, dup_key);
+ if (result)
+ free(dup_key);
+ }
+
+ static void delete_key(const void *key, void *data, void *closure)
+ {
+ (void) data;
+ (void) closure;
+ free((char *)key);
+ }
+
+
+};
+
+#endif /* IR_CACHE_H */
diff --git a/src/glsl/ir_cache_serialize.cpp b/src/glsl/ir_cache_serialize.cpp
new file mode 100644
index 0000000..d7d3144
--- /dev/null
+++ b/src/glsl/ir_cache_serialize.cpp
@@ -0,0 +1,603 @@
+/* -*- 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.h"
+
+
+inline static int _write_string(const char *str, FILE *out)
+{
+ uint32_t len = strlen(str);
+
+ _WRITE_VAL(len, out);
+
+ if(fwrite(str, sizeof(char), len, out) == len)
+ return 0;
+
+ return -1;
+}
+
+
+int ir_cache::save_ir(ir_variable *ir, FILE *out)
+{
+ ir_variable_data *data = new ir_variable_data(ir);
+
+ data->serialize(out);
+
+ CACHE_DEBUG("save ir_variable [%s] id %d\n",
+ data->name->data, data->unique_id);
+
+ delete data;
+
+ if (ir->is_interface_instance()) {
+ CACHE_DEBUG("sorry, interfaces not supported\n");
+ return -1;
+ }
+
+ if (ir->constant_value)
+ save(ir->constant_value, out);
+
+ if (ir->constant_initializer)
+ save(ir->constant_initializer, out);
+
+ return 0;
+}
+
+
+int ir_cache::save_ir(ir_dereference_array *ir, FILE *out)
+{
+ _WRITE_VAL(ir->array->ir_type, out);
+
+ save(ir->array, out);
+
+ _WRITE_VAL(ir->array_index->ir_type, out);
+
+ return save(ir->array_index, out);
+}
+
+
+int ir_cache::save_ir(ir_dereference_record *ir, FILE *out)
+{
+ _write_string(ir->field, out);
+
+ _WRITE_VAL(ir->record->ir_type, out);
+
+ return save(ir->record, out);
+}
+
+
+int ir_cache::save_ir(ir_dereference_variable *ir, FILE *out)
+{
+ _write_string(ir->var->name, out);
+ uint32_t unique_id = _unique_id(ir->var);
+ _WRITE_VAL(unique_id, out);
+
+ CACHE_DEBUG("save ir_dereference_variable [%s] id %d\n",
+ ir->var->name, unique_id);
+
+ return 0;
+}
+
+
+int ir_cache::save_ir(ir_constant *ir, FILE *out)
+{
+ glsl_type_data *data = new glsl_type_data(ir->type);
+ data->serialize(out);
+
+ fwrite(&ir->value, sizeof(ir_constant_data), 1, out);
+
+ delete data;
+
+ if (ir->array_elements) {
+ for (unsigned i = 0; i < ir->type->length; i++)
+ if (save(ir->array_elements[i], out))
+ return -1;
+ }
+
+ /* FIXME, support missing for structs */
+ else if (!ir->components.is_empty()) {
+ CACHE_DEBUG("unsupported ir_constant type (struct)\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int ir_cache::save_ir(ir_expression *ir, FILE *out)
+{
+ glsl_type_data *data = new glsl_type_data(ir->type);
+ int32_t num_operands = ir->get_num_operands();
+
+ data->serialize(out);
+ delete data;
+
+ _WRITE_VAL(ir->operation, out);
+ _WRITE_VAL(num_operands, out);
+
+ /* operand ir_type below is written to make parsing easier */
+ for (unsigned i = 0; i < ir->get_num_operands(); i++) {
+ _WRITE_VAL(ir->operands[i]->ir_type, out);
+ if (save(ir->operands[i], out))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int ir_cache::save_ir(ir_function *ir, FILE *out)
+{
+ uint32_t sig_amount = 0;
+
+ foreach_iter(exec_list_iterator, iter, *ir)
+ sig_amount++;
+
+ _write_string(ir->name, out);
+ _WRITE_VAL(sig_amount, out);
+
+ 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, out))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int ir_cache::save_ir(ir_function_signature *ir, FILE *out)
+{
+ int32_t par_count = 0;
+ int32_t body_size = 0;
+ uint32_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);
+
+ _WRITE_VAL(par_count, out);
+ _WRITE_VAL(body_size, out);
+ _WRITE_VAL(is_builtin, out);
+
+ /* dump the return type of function */
+ glsl_type_data *data = new glsl_type_data(ir->return_type);
+ data->serialize(out);
+ delete data;
+
+ /* 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, out))
+ 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, out))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int ir_cache::save_ir(ir_assignment *ir, FILE *out)
+{
+ uint32_t write_mask = ir->write_mask;
+
+ _WRITE_VAL(write_mask, out);
+
+ /* lhs (ir_deference_*) */
+ _WRITE_VAL(ir->lhs->ir_type, out);
+
+ _write_string(ir->lhs->variable_referenced()->name, out);
+
+ if (save(ir->lhs, out))
+ return -1;
+
+ if (ir->condition) {
+ CACHE_DEBUG("%s: assignment has condition, not supported", __func__);
+ }
+
+ /* rhs (constant, expression ...) */
+ _WRITE_VAL(ir->rhs->ir_type, out);
+
+ if (save(ir->rhs, out))
+ return -1;
+
+ return 0;
+}
+
+
+int ir_cache::save_ir(ir_return *ir, FILE *out)
+{
+ ir_rvalue *const value = ir->get_value();
+ uint32_t has_rvalue = value ? 1 : 0;
+
+ _WRITE_VAL(has_rvalue, out);
+ _WRITE_VAL(value->ir_type, out);
+
+ return save(value, out);
+}
+
+
+int ir_cache::save_ir(ir_swizzle *ir, FILE *out)
+{
+ uint32_t components = ir->mask.num_components;
+ const uint32_t mask[4] = {
+ ir->mask.x,
+ ir->mask.y,
+ ir->mask.z,
+ ir->mask.w
+ };
+
+ _WRITE_VAL(components, out);
+ fwrite(&mask, sizeof(mask[0]), 4, out);
+
+ _WRITE_VAL(ir->val->ir_type, out);
+
+ return save(ir->val, out);
+}
+
+
+int ir_cache::save_ir(ir_discard *ir, FILE *out)
+{
+ unsigned has_condition = ir->condition ? 1 : 0;
+ _WRITE_VAL(has_condition, out);
+
+ /* TODO - figure out what condition on discard means */
+ if (ir->condition != NULL) {
+ CACHE_DEBUG("%s: error, there is no cond support here yet...\n",
+ __func__);
+ if (save(ir->condition, out))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int ir_cache::save_ir(ir_call *ir, FILE *out)
+{
+ _write_string(ir->callee_name(), out);
+
+ uint32_t has_return_deref = ir->return_deref ? 1 : 0;
+ uint32_t list_len = 0;
+ uint32_t use_builtin = ir->use_builtin;
+
+ _WRITE_VAL(has_return_deref, out);
+
+ if (ir->return_deref)
+ if (save(ir->return_deref, out))
+ return -1;
+
+ /* call parameter list */
+ foreach_iter(exec_list_iterator, iter, *ir)
+ list_len++;
+
+ _WRITE_VAL(list_len, out);
+
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_instruction *const inst = (ir_instruction *) iter.get();
+
+ int32_t ir_type = inst->ir_type;
+ _WRITE_VAL(ir_type, out);
+
+ if (save(inst, out))
+ return -1;
+ }
+
+ _WRITE_VAL(use_builtin, out);
+
+ return 0;
+}
+
+
+int ir_cache::save_ir(ir_if *ir, FILE *out)
+{
+ uint32_t then_len = 0, else_len = 0;
+
+ /* 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++;
+
+ _WRITE_VAL(then_len, out);
+ _WRITE_VAL(else_len, out);
+ _WRITE_VAL(ir->condition->ir_type, out);
+
+ 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, out);
+
+ /* 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, out))
+ 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, out))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int ir_cache::save_ir(ir_loop *ir, FILE *out)
+{
+ uint32_t has_counter = ir->counter ? 1 : 0;
+ uint32_t has_from = ir->from ? 1 : 0;
+ uint32_t has_to = ir->to ? 1 : 0;
+ uint32_t has_incr = ir->increment ? 1 : 0;
+ uint32_t body_size = 0;
+
+ foreach_iter(exec_list_iterator, iter, ir->body_instructions)
+ body_size++;
+
+ _WRITE_VAL(has_from, out);
+ _WRITE_VAL(has_to, out);
+ _WRITE_VAL(has_incr, out);
+ _WRITE_VAL(has_counter, out);
+ _WRITE_VAL(ir->cmp, out);
+ _WRITE_VAL(body_size, out);
+
+ if (has_from) {
+ _WRITE_VAL(ir->from->ir_type, out);
+ if (save(ir->from, out))
+ return -1;
+ }
+
+ if (has_to) {
+ _WRITE_VAL(ir->to->ir_type, out);
+ if (save(ir->to, out))
+ return -1;
+ }
+
+ if (has_incr) {
+ _WRITE_VAL(ir->increment->ir_type, out);
+ if (save(ir->increment, out))
+ return -1;
+ }
+
+ if (has_counter) {
+ _write_string(ir->counter->name, out);
+ if (save(ir->counter, out))
+ 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, out))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int ir_cache::save_ir(ir_loop_jump *ir, FILE *out)
+{
+ _WRITE_VAL(ir->mode, out);
+
+ return 0;
+}
+
+
+int ir_cache::save_ir(ir_emit_vertex *ir, FILE *out)
+{
+ return -1;
+}
+
+
+int ir_cache::save_ir(ir_end_primitive *ir, FILE *out)
+{
+ return -1;
+}
+
+
+/**
+ * writes instruction type, packet size and calls
+ * save function for the instruction to save the data
+ */
+int ir_cache::save(ir_instruction *ir, FILE *out)
+{
+ _WRITE_VAL(ir->ir_type, out);
+
+ long start = PROLOGUE(out);
+
+#define SAVE_IR(type)\
+ if (save_ir(static_cast<type *>(ir), out)) 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_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;
+ }
+
+ EPILOGUE(out, start);
+ return 0;
+
+write_errors:
+ CACHE_DEBUG("%s: write errors (ir type %d)\n", __func__, ir->ir_type);
+ return -1;
+}
+
+
+static void _write_state(struct _mesa_glsl_parse_state *state, FILE *out)
+{
+ uint32_t es = state->es_shader ? 1 : 0;
+
+ _WRITE_VAL(state->language_version, out);
+ _WRITE_VAL(state->target, out);
+ _WRITE_VAL(es, out);
+}
+
+
+static void _write_header(gl_shader *shader, FILE *out, const char *mesa_sha)
+{
+ _write_string(mesa_sha, out);
+ _WRITE_VAL(shader->Version, out);
+ _WRITE_VAL(shader->Type, out);
+ _WRITE_VAL(shader->IsES, out);
+
+}
+
+
+/**
+ * serializes a single gl_shader, writes state variables,
+ * shader header information and exec_list of instructions
+ */
+int ir_cache::serialize(struct gl_shader *shader,
+ struct _mesa_glsl_parse_state *state, FILE *out,
+ const char *mesa_sha)
+{
+ uint32_t total = 0;
+
+ prototypes_only = true;
+
+ _write_state(state, out);
+ _write_header(shader, out, mesa_sha);
+
+ /* 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++;
+ }
+
+ _WRITE_VAL(total, out);
+
+ 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, out))
+ goto write_errors;
+ }
+
+ foreach_list_const(node, shader->ir) {
+ ir_instruction *const inst = (ir_instruction *) node;
+ if (inst->as_function())
+ if (save(inst, out))
+ goto write_errors;
+ }
+
+ /* all shader instructions */
+ prototypes_only = false;
+ foreach_list_const(node, shader->ir) {
+ ir_instruction *instruction = (ir_instruction *) node;
+ if (save(instruction, out))
+ goto write_errors;
+ }
+
+ CACHE_DEBUG("cached a shader\n");
+
+ return 0;
+
+write_errors:
+ return -1;
+}
+
diff --git a/src/glsl/ir_cache_unserialize.cpp b/src/glsl/ir_cache_unserialize.cpp
new file mode 100644
index 0000000..40eeeea
--- /dev/null
+++ b/src/glsl/ir_cache_unserialize.cpp
@@ -0,0 +1,973 @@
+/* -*- 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.h"
+
+
+static ir_variable *search_var(struct exec_list *list,
+ const char *name, bool debug_print = false)
+{
+ foreach_list_safe(node, list) {
+ ir_variable *var = ((ir_instruction *) node)->as_variable();
+ if (var && debug_print) printf("[%s vs %s]\n", name, var->name);
+ if (var && strstr(name, var->name))
+ return var;
+ }
+ return NULL;
+}
+
+
+static ir_function *search_func(struct _mesa_glsl_parse_state *state,
+struct exec_list *list, const char *name, struct exec_list *parameters)
+{
+ foreach_list_safe(node, list) {
+ ir_function *func = ((ir_instruction *) node)->as_function();
+ if (func && strstr(name, func->name) &&
+ func->matching_signature(state, parameters))
+ return func;
+ }
+ return NULL;
+}
+
+
+int ir_cache::read_state(struct _mesa_glsl_parse_state *state, memory_map &map)
+{
+ uint32_t es;
+
+ CACHE_DEBUG("%s\n", __func__);
+
+ map.read_value(&state->language_version);
+ map.read_value(&state->target);
+ map.read_value(&es);
+
+ state->es_shader = es ? 1 : 0;
+
+ /* initialize builtins, types */
+ state->num_builtins_to_link = 0;
+
+ _mesa_glsl_initialize_builtin_functions();
+ _mesa_glsl_initialize_types(state);
+
+ return 0;
+}
+
+
+/**
+ * main purpose of the header is that it validates that cached
+ * shader was produced with the same Mesa drivers
+ */
+int ir_cache::read_header(struct gl_shader *shader, memory_map &map,
+ const char *mesa_sha)
+{
+ char cache_mesa_sha[256];
+
+ map.read_string(cache_mesa_sha);
+
+ map.read_value(&shader->Version);
+ map.read_value(&shader->Type);
+ map.read_value(&shader->IsES);
+
+ CACHE_DEBUG("%s: version %d, type 0x%x, %s (mesa %s)\n",
+ __func__, shader->Version, shader->Type,
+ (shader->IsES) ? "glsl es" : "desktop glsl",
+ cache_mesa_sha);
+
+ return memcmp(cache_mesa_sha, mesa_sha, strlen(mesa_sha));
+}
+
+
+const glsl_type *ir_cache::read_glsl_type(memory_map &map)
+{
+ char name[256];
+ long type_size;
+
+ map.read_string(name);
+ map.read_value(&type_size);
+
+ const glsl_type *type_exists = state->symbols->get_type(name);
+
+ /* if type exists, move read pointer forward and return type */
+ if (type_exists) {
+ map.ffwd(type_size);
+ return type_exists;
+ }
+
+ glsl_type_data data;
+
+ map.read_struct(&data);
+
+ data.name = NULL;
+ data.element_type = NULL;
+ data.field_names = NULL;
+ data.field_types = NULL;
+
+ if (data.base_type == GLSL_TYPE_SAMPLER) {
+
+ switch(data.sampler_dimensionality) {
+ case 0:
+ return glsl_type::sampler1D_type;
+ case 1:
+ return glsl_type::sampler2D_type;
+ case 2:
+ return glsl_type::sampler3D_type;
+ case 3:
+ return glsl_type::samplerCube_type;
+ default:
+ CACHE_DEBUG("%s: unknown sampler type (dim %d)\n",
+ __func__, data.sampler_dimensionality);
+ }
+ }
+
+ /* array type has additional element_type information */
+ if (data.base_type == GLSL_TYPE_ARRAY) {
+ const glsl_type *element_type = read_glsl_type(map);
+ if (!element_type) {
+ CACHE_DEBUG("error reading array element type\n");
+ return NULL;
+ }
+ return glsl_type::get_array_instance(element_type, data.length);
+ }
+
+ /* structures have fields containing of names and types */
+ else if (data.base_type == GLSL_TYPE_STRUCT) {
+ glsl_struct_field *fields = ralloc_array(mem_ctx,
+ glsl_struct_field, data.length);
+ for (int k = 0; k < data.length; k++) {
+ char field_name[256];
+ map.read_string(field_name);
+ fields[k].name = _mesa_strdup(field_name);
+ fields[k].type = read_glsl_type(map);
+ }
+ return glsl_type::get_record_instance(fields, data.length, name);
+ }
+
+ return glsl_type::get_instance(data.base_type,
+ data.vector_elms, data.matrix_cols);
+}
+
+
+int ir_cache::read_ir_variable(struct exec_list *list, memory_map &map)
+{
+ char name[256];
+ char unique_name[256];
+ glsl_type_data type_data;
+ ir_variable_data data;
+
+ const glsl_type *type = read_glsl_type(map);
+
+ map.read_string(name);
+ map.read_string(unique_name);
+ map.read_struct(&data);
+ data.name = NULL;
+ data.unique_name = NULL;
+ data.type = NULL;
+
+ ir_variable *var = new(mem_ctx)ir_variable(type,
+ name, (ir_variable_mode) data.mode);
+
+ if (!var)
+ return -1;
+
+ var->explicit_location = data.explicit_location;
+ var->explicit_index = data.explicit_index;
+ var->explicit_binding = data.explicit_binding;
+
+ var->max_array_access = data.max_array_access;
+ var->location = data.location;
+ var->centroid = data.centroid;
+ var->invariant = data.invariant;
+ var->interpolation = data.interpolation;
+
+ if (data.has_constant_value)
+ var->constant_value = read_ir_constant(map);
+
+ if (data.has_constant_initializer)
+ var->constant_initializer = read_ir_constant(map);
+
+ /* store address to this variable */
+ hash_store(var, unique_name);
+
+ list->push_tail(var);
+
+ return 0;
+}
+
+
+int ir_cache::read_ir_function(struct exec_list *list, memory_map &map)
+{
+ char name[256];
+ int32_t par_count = 0;
+ int32_t body_count = 0;
+ uint32_t is_builtin = 0;
+ int ir_type;
+ long len;
+ uint32_t sig_amount;
+
+ map.read_string(name);
+ map.read_value(&sig_amount);
+
+ ir_function *f = new(mem_ctx) ir_function(name);
+ ir_function_signature *sig = NULL;
+ const ir_function *builtin = NULL;
+
+ /* add all signatures to the function */
+ for (unsigned j = 0; j < sig_amount; j++) {
+
+ /* ir_function_signature */
+ map.read_value(&ir_type);
+ map.read_value(&len);
+
+ if (ir_type != ir_type_function_signature) {
+ CACHE_DEBUG("cache format error with function %s\n", name);
+ return -1;
+ }
+
+ map.read_value(&par_count);
+ map.read_value(&body_count);
+ map.read_value(&is_builtin);
+
+
+ CACHE_DEBUG("%s: [%s] %d parameters, body size %d (is_builtin %d)\n",
+ __func__, name, par_count, body_count, is_builtin);
+
+ const glsl_type *return_type = read_glsl_type(map);
+
+ if (!return_type) {
+ CACHE_DEBUG("no return type found for [%s]\n", name);
+ return -1;
+ }
+
+ sig = new(mem_ctx) ir_function_signature(return_type);
+
+ /* fill parameters for function signature */
+ for (int k = 0; k < par_count; k++)
+ if (read_instruction(&sig->parameters, map))
+ goto read_errors;
+
+ /* insert function parameter variables to prototypes list ... */
+ foreach_list_const(node, &sig->parameters) {
+ ir_variable *var = ((ir_instruction *) node)->as_variable();
+ if (var)
+ prototypes->push_tail(var->clone(mem_ctx, NULL));
+ }
+
+ current_function = &sig->body;
+
+ /* fill instructions for the function body */
+ if (!prototypes_only)
+ for (int k = 0; k < body_count; k++)
+ if (read_instruction(&sig->body, map, is_builtin ? true : false))
+ goto read_errors;
+
+ sig->is_defined = body_count ? 1 : 0;
+
+ if (!is_builtin) {
+ f->add_signature(sig);
+ } else {
+ ir_function_signature *builtin_sig =
+ _mesa_glsl_find_builtin_function(state, name, &sig->parameters);
+
+ if (builtin_sig) {
+ CACHE_DEBUG("found builtin signature for [%s]\n", name);
+ f->add_signature(sig);
+ } else {
+ CACHE_DEBUG("cannot find builtin, function [%s]\n", name);
+ return -1;
+ }
+ }
+
+ } /* for each function signature */
+
+ CACHE_DEBUG("added user function [%s]\n", name);
+
+ /* push ready function to the IR exec_list */
+ list->push_tail(f);
+
+ return 0;
+
+read_errors:
+ CACHE_DEBUG("%s: read errors with [%s]\n", __func__, name);
+ if (sig)
+ ralloc_free(sig);
+ return -1;
+
+}
+
+
+ir_dereference_array *ir_cache::read_ir_dereference_array(memory_map &map)
+{
+ int ir_type;
+ long len;
+
+ CACHE_DEBUG("%s\n", __func__);
+
+ map.read_value(&ir_type);
+ map.read_value(&len);
+
+ ir_rvalue *array_rval = read_ir_rvalue(map);
+ ir_rvalue *index_rval = read_ir_rvalue(map);
+
+ if (array_rval && index_rval)
+ return new(mem_ctx) ir_dereference_array(array_rval, index_rval);
+
+ CACHE_DEBUG("%s: could not get rvalues", __func__);
+ return NULL;
+}
+
+
+ir_dereference_record *ir_cache::read_ir_dereference_record(memory_map &map)
+{
+ int ir_type;
+ long len;
+ char name[256];
+
+ CACHE_DEBUG("%s\n", __func__);
+
+ map.read_value(&ir_type);
+ map.read_value(&len);
+ map.read_string(name);
+
+ ir_rvalue *rval = read_ir_rvalue(map);
+
+ if (rval)
+ return new(mem_ctx) ir_dereference_record(rval, name);
+
+ CACHE_DEBUG("%s: could not get rvalue", __func__);
+ return NULL;
+}
+
+
+/**
+ * Reads in a variable deref, seeks variable address
+ * from a map with it's unique_name
+ */
+ir_dereference_variable *ir_cache::read_ir_dereference_variable(memory_map &map)
+{
+ int ir_type;
+ long len;
+ char name[256];
+ char unique_name[256];
+ uint32_t unique_id;
+
+ map.read_value(&ir_type);
+ map.read_value(&len);
+ map.read_string(name);
+ map.read_value(&unique_id);
+
+ _mesa_snprintf(unique_name, 256, "%s_%d", name, unique_id);
+ const void *addr = hash_table_find(var_ht, (const void *) unique_name);
+
+ CACHE_DEBUG("found addr %p with name %s\n", addr, unique_name);
+
+ if (addr != 0) {
+ ir_variable *var = (ir_variable*) addr;
+ return new(mem_ctx) ir_dereference_variable(var);
+ }
+
+ CACHE_DEBUG("%s: could not find [%s]\n", __func__, name);
+ return NULL;
+}
+
+
+ir_constant *ir_cache::read_ir_constant(memory_map &map)
+{
+ ir_constant *con = NULL;
+ int ir_type;
+ long size;
+
+ map.read_value(&ir_type);
+ map.read_value(&size);
+
+ const glsl_type *constant_type = read_glsl_type(map);
+
+ /* data structure */
+ ir_constant_data data;
+ map.read_struct(&data);
+
+ con = new(mem_ctx) ir_constant(constant_type, &data);
+
+ /* constant with array of constants */
+ if (constant_type->base_type == GLSL_TYPE_ARRAY) {
+ con->array_elements = ralloc_array(mem_ctx, ir_constant *,
+ constant_type->length);
+
+ for (unsigned i = 0; i < constant_type->length; i++)
+ con->array_elements[i] = read_ir_constant(map);
+
+ return con;
+ }
+
+ /* FIXME, not supported yet */
+ else if (constant_type->base_type == GLSL_TYPE_STRUCT)
+ return NULL;
+
+ return con;
+}
+
+
+ir_swizzle *ir_cache::read_ir_swizzle(memory_map &map)
+{
+ unsigned swiz[4] = { 0 };
+ unsigned count;
+ int ir_type;
+ long size;
+
+ CACHE_DEBUG("%s\n", __func__);
+
+ map.read_value(&ir_type);
+ map.read_value(&size);
+
+ /* num of components + swizzle mask, rvalue */
+ map.read_value(&count);
+ map.read_nval(swiz, 4);
+
+ ir_rvalue *rval = read_ir_rvalue(map);
+
+ if (rval)
+ return new(mem_ctx) ir_swizzle(rval, swiz, count);
+
+ CACHE_DEBUG("error, could not handle rvalue for swizzle\n");
+ return NULL;
+}
+
+
+ir_expression *ir_cache::read_ir_expression(memory_map &map)
+{
+ ir_expression_operation operation;
+ ir_rvalue *ir_rvalue_table[4] = { NULL };
+ int operands;
+ int ir_type;
+ long r_size;
+
+ CACHE_DEBUG("%s\n", __func__);
+
+ map.read_value(&ir_type);
+ map.read_value(&r_size);
+
+ /* glsl_type resulted from operation */
+ const glsl_type *rval_type = read_glsl_type(map);
+
+ /* read operation type + all operands for creating ir_expression */
+ map.read_value(&operation);
+ map.read_value(&operands);
+
+ CACHE_DEBUG("%s : operation %d, operands %d\n",
+ __func__, operation, operands);
+
+ for (int k = 0; k < operands; k++) {
+ ir_rvalue *val = read_ir_rvalue(map);
+
+ if (!val)
+ return NULL;
+
+ ir_rvalue_table[k] = val;
+ }
+
+ return new(mem_ctx) ir_expression(operation,
+ rval_type,
+ ir_rvalue_table[0],
+ ir_rvalue_table[1],
+ ir_rvalue_table[2],
+ ir_rvalue_table[3]);
+}
+
+
+ir_rvalue *ir_cache::read_ir_rvalue(memory_map &map)
+{
+ int32_t ir_type = ir_type_unset;
+
+ map.read_value(&ir_type);
+
+ CACHE_DEBUG("%s: ir_value %d\n", __func__, ir_type);
+
+ switch(ir_type) {
+ case ir_type_constant:
+ return read_ir_constant(map);
+ case ir_type_dereference_variable:
+ return read_ir_dereference_variable(map);
+ case ir_type_dereference_record:
+ return read_ir_dereference_record(map);
+ case ir_type_dereference_array:
+ return read_ir_dereference_array(map);
+ case ir_type_expression:
+ return read_ir_expression(map);
+ case ir_type_swizzle:
+ return read_ir_swizzle(map);
+ default:
+ CACHE_DEBUG("%s: error, unhandled type %d\n",
+ __func__, ir_type);
+ break;
+ }
+ return NULL;
+}
+
+
+/**
+ * read assignment instruction, mask + rvalue
+ */
+int ir_cache::read_ir_assignment(struct exec_list *list, memory_map &map)
+{
+ unsigned write_mask = 0;
+ int lhs_type = 0;
+ char lhs_name[256];
+
+ ir_assignment *assign = NULL;
+ ir_dereference *lhs_deref = NULL;
+
+ map.read_value(&write_mask);
+ map.read_value(&lhs_type);
+
+ CACHE_DEBUG("%s: mask %d lhs_type %d\n", __func__, write_mask, lhs_type);
+
+ map.read_string(lhs_name);
+
+ CACHE_DEBUG("%s : lhs name [%s]\n", __func__, lhs_name);
+
+ switch (lhs_type) {
+ case ir_type_dereference_variable:
+ lhs_deref = read_ir_dereference_variable(map);
+ break;
+ case ir_type_dereference_record:
+ lhs_deref = read_ir_dereference_record(map);
+ break;
+ case ir_type_dereference_array:
+ lhs_deref = read_ir_dereference_array(map);
+ break;
+ default:
+ CACHE_DEBUG("%s: error, unhandled lhs_type %d\n",
+ __func__, lhs_type);
+ }
+
+ if (!lhs_deref) {
+ CACHE_DEBUG("could not find lhs variable, bailing out\n");
+ return -1;
+ }
+
+ /* rvalue for assignment */
+ ir_rvalue *rval = read_ir_rvalue(map);
+
+ /* if we managed to parse rvalue, then we can construct assignment */
+ if (rval) {
+
+ CACHE_DEBUG("%s: lhs type %d\n", __func__, lhs_type);
+
+ assign = new(mem_ctx) ir_assignment(lhs_deref, rval, NULL, write_mask);
+ list->push_tail(assign);
+ return 0;
+ }
+
+ CACHE_DEBUG("error reading assignment rhs\n");
+ return -1;
+}
+
+
+/**
+ * if with condition + then and else branches
+ */
+int ir_cache::read_ir_if(struct exec_list *list, memory_map &map)
+{
+ unsigned then_len, else_len;
+
+ CACHE_DEBUG("%s\n", __func__);
+
+ map.read_value(&then_len);
+ map.read_value(&else_len);
+
+ ir_rvalue *cond = read_ir_rvalue(map);
+
+ if (!cond) {
+ CACHE_DEBUG("%s: error reading condition\n", __func__);
+ return -1;
+ }
+
+ ir_if *irif = new(mem_ctx) ir_if(cond);
+
+ for (unsigned k = 0; k < then_len; k++)
+ if(read_instruction(&irif->then_instructions, map))
+ goto read_errors;
+
+ for (unsigned k = 0; k < else_len; k++)
+ if (read_instruction(&irif->else_instructions, map))
+ goto read_errors;
+
+ list->push_tail(irif);
+ return 0;
+
+read_errors:
+ CACHE_DEBUG("%s: read errors(then %d else %d)\n",
+ __func__, then_len, else_len);
+ ralloc_free(irif);
+ return -1;
+}
+
+
+int ir_cache::read_ir_return(struct exec_list *list, memory_map &map)
+{
+ uint32_t has_rvalue = 0;
+ map.read_value(&has_rvalue);
+
+ CACHE_DEBUG("%s\n", __func__);
+
+ ir_rvalue *rval = NULL;
+ if (has_rvalue)
+ rval = read_ir_rvalue(map);
+
+ ir_return *ret = new(mem_ctx) ir_return(rval);
+ list->push_tail(ret);
+
+ return 0;
+}
+
+
+/**
+ * read a call to a ir_function, finds the correct function
+ * signature from prototypes list and creates the call
+ */
+int ir_cache::read_ir_call(struct exec_list *list, memory_map &map)
+{
+ unsigned has_return_deref = 0;
+ unsigned list_len = 0;
+ unsigned use_builtin = 0;
+ struct exec_list parameters;
+ char name[256];
+ ir_dereference_variable *return_deref = NULL;
+
+ map.read_string(name);
+
+ map.read_value(&has_return_deref);
+
+ if (has_return_deref)
+ return_deref = read_ir_dereference_variable(map);
+
+ map.read_value(&list_len);
+
+ CACHE_DEBUG("call to function %s, %d parameters (ret deref %p)\n",
+ name, list_len, return_deref);
+
+ /* read call parameters */
+ for(unsigned k = 0; k < list_len; k++) {
+
+ ir_rvalue *rval = read_ir_rvalue(map);
+ if (rval) {
+ parameters.push_tail(rval);
+ } else {
+ CACHE_DEBUG("%s: error reading rvalue\n", __func__);
+ return -1;
+ }
+ }
+
+ map.read_value(&use_builtin);
+
+ if (use_builtin) {
+ ir_function_signature *builtin_sig =
+ _mesa_glsl_find_builtin_function(state, name, ¶meters);
+
+ if (builtin_sig) {
+ CACHE_DEBUG("%s: found function %s from builtins\n", __func__, name);
+
+ ir_function_signature *callee = builtin_sig;
+
+ CACHE_DEBUG("function signature for builtin %s : %p\n", name, callee);
+ if (!callee) {
+ CACHE_DEBUG("sorry, cannot find signature for builtin ..\n");
+ return -1;
+ }
+
+ ir_call *call = new(mem_ctx) ir_call(callee, return_deref,
+ ¶meters);
+
+ call->use_builtin = true;
+
+ list->push_tail(call);
+ return 0;
+ }
+ }
+
+ /* find the function from the prototypes */
+ ir_function *func = search_func(state, prototypes, name, ¶meters);
+
+ if (func) {
+ CACHE_DEBUG("found function with name %s (has user sig %d)\n",
+ name, func->has_user_signature());
+
+ ir_function_signature *callee = func->matching_signature(state,
+ ¶meters);
+
+ /**
+ * FIXME - this is a workaround for a call to empty user defined function
+ * (happens with glb2.7), linking would fail if we would create a call,
+ * empty functions get removed only afer linking .. this is not a safe
+ * thing todo here though :/
+ */
+ if (!callee->is_defined)
+ return 0;
+
+ ir_call *call = new(mem_ctx) ir_call(callee, return_deref, ¶meters);
+ list->push_tail(call);
+ return 0;
+ }
+
+ CACHE_DEBUG("%s:function %s not found for ir_call ...\n",
+ __func__, name);
+ return -1;
+}
+
+
+int ir_cache::read_ir_discard(struct exec_list *list, memory_map &map)
+{
+ uint32_t has_condition;
+ map.read_value(&has_condition);
+
+ CACHE_DEBUG("%s\n", __func__);
+
+ list->push_tail(new(mem_ctx) ir_discard);
+ return 0;
+}
+
+
+/**
+ * read in ir_loop
+ */
+int ir_cache::read_ir_loop(struct exec_list *list, memory_map &map)
+{
+ unsigned has_counter, has_from, has_to, has_increment, body_size;
+ int cmp;
+ char counter_name[256];
+ ir_loop *loop = NULL;
+
+ loop = new(mem_ctx) ir_loop;
+
+ map.read_value(&has_from);
+ map.read_value(&has_to);
+ map.read_value(&has_increment);
+ map.read_value(&has_counter);
+ map.read_value(&cmp);
+ map.read_value(&body_size);
+
+ /* comparison operation for loop termination */
+ loop->cmp = cmp;
+
+ /* ir_rvalues: from, to, increment + one ir_variable counter */
+ if (has_from) {
+ loop->from = read_ir_rvalue(map);
+ if (!loop->from)
+ return -1;
+ }
+
+ if (has_to) {
+ loop->to = read_ir_rvalue(map);
+ if (!loop->to)
+ return -1;
+ }
+
+ if (has_increment) {
+ loop->increment = read_ir_rvalue(map);
+ if (!loop->increment)
+ return -1;
+ }
+
+ /* read ir_variable to prototypes list and search from there */
+ if (has_counter) {
+ map.read_string(counter_name);
+ if (read_instruction(prototypes, map))
+ return -1;
+ loop->counter = search_var(prototypes, counter_name);
+ if (!loop->counter)
+ return -1;
+ }
+
+ CACHE_DEBUG("%s: from %p to %p increment %p counter %p size %d\n", __func__,
+ loop->from, loop->to, loop->increment, loop->counter, body_size);
+
+ for (unsigned k = 0; k < body_size; k++) {
+ if(read_instruction(&loop->body_instructions, map))
+ goto read_errors;
+ }
+
+ list->push_tail(loop);
+ return 0;
+
+read_errors:
+ CACHE_DEBUG("%s: read errors\n", __func__);
+ if (loop)
+ ralloc_free(loop);
+ return -1;
+}
+
+
+int ir_cache::read_ir_loop_jump(struct exec_list *list, memory_map &map)
+{
+ int32_t mode;
+ map.read_value(&mode);
+ list->push_tail(new(mem_ctx) ir_loop_jump((ir_loop_jump::jump_mode)mode));
+ return 0;
+}
+
+
+int ir_cache::read_instruction(struct exec_list *list, memory_map &map,
+ bool ignore)
+{
+ int ir_type = ir_type_unset;
+ long inst_dumpsize = 0;
+
+ map.read_value(&ir_type);
+ map.read_value(&inst_dumpsize);
+
+ /* reader wants to jump over this instruction */
+ if (ignore) {
+ map.ffwd(inst_dumpsize);
+ return 0;
+ }
+
+ switch(ir_type) {
+ case ir_type_variable:
+ return read_ir_variable(list, map);
+ case ir_type_assignment:
+ return read_ir_assignment(list, map);
+ case ir_type_function:
+ return read_ir_function(list, map);
+ case ir_type_if:
+ return read_ir_if(list, map);
+ case ir_type_return:
+ return read_ir_return(list, map);
+ case ir_type_call:
+ return read_ir_call(list, map);
+ case ir_type_discard:
+ return read_ir_discard(list, map);
+ case ir_type_loop:
+ return read_ir_loop(list, map);
+ case ir_type_loop_jump:
+ return read_ir_loop_jump(list, map);
+ default:
+ CACHE_DEBUG("%s cannot read type %d, todo...\n",
+ __func__, ir_type);
+ }
+
+ return -1;
+}
+
+
+/**
+ * reads prototypes section of the dump, consists
+ * of variables and functions
+ */
+int ir_cache::read_prototypes(memory_map &map)
+{
+ uint32_t total;
+ int ir_type;
+ long inst_dumpsize;
+
+ map.read_value(&total);
+
+ prototypes_only = true;
+
+ for (unsigned k = 0; k < total; k++) {
+
+ map.read_value(&ir_type);
+ map.read_value(&inst_dumpsize);
+
+ switch (ir_type) {
+ case ir_type_variable:
+ if (read_ir_variable(prototypes, map))
+ return -1;
+ break;
+ case ir_type_function:
+ if (read_ir_function(prototypes, map))
+ return -1;
+ break;
+ default:
+ CACHE_DEBUG("%s: error in cache data (ir %d)\n",
+ __func__, ir_type);
+ return -1;
+ }
+ }
+
+ prototypes_only = false;
+
+ CACHE_DEBUG("%s: done\n", __func__);
+ return 0;
+}
+
+
+struct gl_shader *ir_cache::unserialize(void *mem_ctx,
+ memory_map &map,
+ struct _mesa_glsl_parse_state *state,
+ const char *mesa_sha,
+ int *error_code)
+{
+ int error = 0;
+ *error_code = ir_cache::GENERAL_READ_ERROR;
+
+ struct gl_shader *shader =
+ (struct gl_shader *) ralloc (mem_ctx, struct gl_shader);
+
+ if (!shader)
+ return NULL;
+
+ shader->ir = new(shader) exec_list;
+
+ top_level = shader->ir;
+
+ if (read_state(state, map))
+ goto error_unserialize;
+
+ if (read_header(shader, map, mesa_sha)) {
+ *error_code = ir_cache::DIFFERENT_MESA_SHA;
+ goto error_unserialize;
+ }
+
+ /**
+ * parser state is used to find builtin functions and
+ * existing types during reading
+ */
+ this->state = state;
+
+ /* allocations during reading */
+ this->mem_ctx = mem_ctx;
+
+ prototypes = new(mem_ctx) exec_list;
+
+ error = read_prototypes(map);
+
+ /* top level exec_list read loop, constructs a new list */
+ while(!map.end() && error == 0)
+ error = read_instruction(shader->ir, map);
+
+ ralloc_free(prototypes);
+
+ if (error)
+ goto error_unserialize;
+
+ *error_code = 0;
+
+ CACHE_DEBUG("shader from cache\n");
+
+ return shader;
+
+error_unserialize:
+ ralloc_free(shader->ir);
+ ralloc_free(shader);
+ return NULL;
+}
+
--
1.8.1.4
More information about the mesa-dev
mailing list