aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r--mesalib/src/glsl/builtin_compiler/Makefile.am43
-rw-r--r--mesalib/src/glsl/ir_set_program_inouts.cpp38
-rw-r--r--mesalib/src/glsl/link_uniform_blocks.cpp6
-rw-r--r--mesalib/src/glsl/link_uniforms.cpp24
-rw-r--r--mesalib/src/glsl/link_varyings.cpp227
-rw-r--r--mesalib/src/glsl/link_varyings.h59
-rw-r--r--mesalib/src/glsl/linker.cpp59
-rw-r--r--mesalib/src/glsl/linker.h33
-rw-r--r--mesalib/src/glsl/program.h4
9 files changed, 341 insertions, 152 deletions
diff --git a/mesalib/src/glsl/builtin_compiler/Makefile.am b/mesalib/src/glsl/builtin_compiler/Makefile.am
index 976640822..e11a17fbe 100644
--- a/mesalib/src/glsl/builtin_compiler/Makefile.am
+++ b/mesalib/src/glsl/builtin_compiler/Makefile.am
@@ -20,23 +20,44 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
-CC = @CC_FOR_BUILD@
-CFLAGS = @CFLAGS_FOR_BUILD@
-CPP = @CPP_FOR_BUILD@
-CPPFLAGS = @CPPFLAGS_FOR_BUILD@
-CXX = @CXX_FOR_BUILD@
-CXXFLAGS = @CXXFLAGS_FOR_BUILD@
-LD = @LD_FOR_BUILD@
-LDFLAGS = @LDFLAGS_FOR_BUILD@
-
AM_CFLAGS = \
-I $(top_srcdir)/include \
-I $(top_srcdir)/src/mapi \
-I $(top_srcdir)/src/mesa \
-I $(GLSL_SRCDIR) \
-I $(GLSL_SRCDIR)/glcpp \
- -I $(GLSL_BUILDDIR) \
- $(DEFINES_FOR_BUILD)
+ -I $(GLSL_BUILDDIR)
+
+if CROSS_COMPILING
+proxyCC = @CC_FOR_BUILD@
+proxyCFLAGS = @CFLAGS_FOR_BUILD@
+proxyCPP = @CPP_FOR_BUILD@
+proxyCPPFLAGS = @CPPFLAGS_FOR_BUILD@
+proxyCXX = @CXX_FOR_BUILD@
+proxyCXXFLAGS = @CXXFLAGS_FOR_BUILD@
+proxyLD = @LD_FOR_BUILD@
+proxyLDFLAGS = @LDFLAGS_FOR_BUILD@
+AM_CFLAGS += $(DEFINES_FOR_BUILD)
+else
+proxyCC = @CC@
+proxyCFLAGS = @CFLAGS@
+proxyCPP = @CPP@
+proxyCPPFLAGS = @CPPFLAGS@
+proxyCXX = @CXX@
+proxyCXXFLAGS = @CXXFLAGS@
+proxyLD = @LD@
+proxyLDFLAGS = @LDFLAGS@
+AM_CFLAGS += $(DEFINES)
+endif
+
+CC = $(proxyCC)
+CFLAGS = $(proxyCFLAGS)
+CPP = $(proxyCPP)
+CPPFLAGS = $(proxyCPPFLAGS)
+CXX = $(proxyCXX)
+CXXFLAGS = $(proxyCXXFLAGS)
+LD = $(proxyLD)
+LDFLAGS = $(proxyLDFLAGS)
AM_CXXFLAGS = $(AM_CFLAGS)
diff --git a/mesalib/src/glsl/ir_set_program_inouts.cpp b/mesalib/src/glsl/ir_set_program_inouts.cpp
index 1e102bfbb..91a8b4526 100644
--- a/mesalib/src/glsl/ir_set_program_inouts.cpp
+++ b/mesalib/src/glsl/ir_set_program_inouts.cpp
@@ -38,7 +38,6 @@
*/
#include "main/core.h" /* for struct gl_program */
-#include "program/hash_table.h"
#include "ir.h"
#include "ir_visitor.h"
#include "glsl_types.h"
@@ -50,13 +49,9 @@ public:
{
this->prog = prog;
this->is_fragment_shader = is_fragment_shader;
- this->ht = hash_table_ctor(0,
- hash_table_pointer_hash,
- hash_table_pointer_compare);
}
~ir_set_program_inouts_visitor()
{
- hash_table_dtor(this->ht);
}
virtual ir_visitor_status visit_enter(ir_dereference_array *);
@@ -64,13 +59,19 @@ public:
virtual ir_visitor_status visit_enter(ir_expression *);
virtual ir_visitor_status visit_enter(ir_discard *);
virtual ir_visitor_status visit(ir_dereference_variable *);
- virtual ir_visitor_status visit(ir_variable *);
struct gl_program *prog;
- struct hash_table *ht;
bool is_fragment_shader;
};
+static inline bool
+is_shader_inout(ir_variable *var)
+{
+ return var->mode == ir_var_shader_in ||
+ var->mode == ir_var_shader_out ||
+ var->mode == ir_var_system_value;
+}
+
static void
mark(struct gl_program *prog, ir_variable *var, int offset, int len,
bool is_fragment_shader)
@@ -97,6 +98,7 @@ mark(struct gl_program *prog, ir_variable *var, int offset, int len,
} else if (var->mode == ir_var_system_value) {
prog->SystemValuesRead |= bitfield;
} else {
+ assert(var->mode == ir_var_shader_out);
prog->OutputsWritten |= bitfield;
}
}
@@ -106,7 +108,7 @@ mark(struct gl_program *prog, ir_variable *var, int offset, int len,
ir_visitor_status
ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir)
{
- if (hash_table_find(this->ht, ir->var) == NULL)
+ if (!is_shader_inout(ir->var))
return visit_continue;
if (ir->type->is_array()) {
@@ -127,13 +129,13 @@ ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
ir_dereference_variable *deref_var;
ir_constant *index = ir->array_index->as_constant();
deref_var = ir->array->as_dereference_variable();
- ir_variable *var = NULL;
+ ir_variable *var = deref_var ? deref_var->var : NULL;
/* Check that we're dereferencing a shader in or out */
- if (deref_var)
- var = (ir_variable *)hash_table_find(this->ht, deref_var->var);
+ if (!var || !is_shader_inout(var))
+ return visit_continue;
- if (index && var) {
+ if (index) {
int width = 1;
if (deref_var->type->is_array() &&
@@ -150,18 +152,6 @@ ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
}
ir_visitor_status
-ir_set_program_inouts_visitor::visit(ir_variable *ir)
-{
- if (ir->mode == ir_var_shader_in ||
- ir->mode == ir_var_shader_out ||
- ir->mode == ir_var_system_value) {
- hash_table_insert(this->ht, ir, ir);
- }
-
- return visit_continue;
-}
-
-ir_visitor_status
ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir)
{
/* We don't want to descend into the function parameters and
diff --git a/mesalib/src/glsl/link_uniform_blocks.cpp b/mesalib/src/glsl/link_uniform_blocks.cpp
index 74fe1e29f..c72d1d8f1 100644
--- a/mesalib/src/glsl/link_uniform_blocks.cpp
+++ b/mesalib/src/glsl/link_uniform_blocks.cpp
@@ -29,7 +29,7 @@
#include "main/hash_table.h"
#include "program.h"
-class ubo_visitor : public uniform_field_visitor {
+class ubo_visitor : public program_resource_visitor {
public:
ubo_visitor(void *mem_ctx, gl_uniform_buffer_variable *variables,
unsigned num_variables)
@@ -44,7 +44,7 @@ public:
this->offset = 0;
this->buffer_size = 0;
this->is_array_instance = strchr(name, ']') != NULL;
- this->uniform_field_visitor::process(type, name);
+ this->program_resource_visitor::process(type, name);
}
unsigned index;
@@ -112,7 +112,7 @@ private:
}
};
-class count_block_size : public uniform_field_visitor {
+class count_block_size : public program_resource_visitor {
public:
count_block_size() : num_active_uniforms(0)
{
diff --git a/mesalib/src/glsl/link_uniforms.cpp b/mesalib/src/glsl/link_uniforms.cpp
index f1284adb2..d457e4d0c 100644
--- a/mesalib/src/glsl/link_uniforms.cpp
+++ b/mesalib/src/glsl/link_uniforms.cpp
@@ -52,7 +52,7 @@ values_for_type(const glsl_type *type)
}
void
-uniform_field_visitor::process(const glsl_type *type, const char *name)
+program_resource_visitor::process(const glsl_type *type, const char *name)
{
assert(type->is_record()
|| (type->is_array() && type->fields.array->is_record())
@@ -65,7 +65,7 @@ uniform_field_visitor::process(const glsl_type *type, const char *name)
}
void
-uniform_field_visitor::process(ir_variable *var)
+program_resource_visitor::process(ir_variable *var)
{
const glsl_type *t = var->type;
@@ -93,8 +93,8 @@ uniform_field_visitor::process(ir_variable *var)
}
void
-uniform_field_visitor::recursion(const glsl_type *t, char **name,
- size_t name_length, bool row_major)
+program_resource_visitor::recursion(const glsl_type *t, char **name,
+ size_t name_length, bool row_major)
{
/* Records need to have each field processed individually.
*
@@ -110,7 +110,7 @@ uniform_field_visitor::recursion(const glsl_type *t, char **name,
if (t->fields.structure[i].type->is_record())
this->visit_field(&t->fields.structure[i]);
- /* Append '.field' to the current uniform name. */
+ /* Append '.field' to the current variable name. */
if (name_length == 0) {
ralloc_asprintf_rewrite_tail(name, &new_length, "%s", field);
} else {
@@ -125,7 +125,7 @@ uniform_field_visitor::recursion(const glsl_type *t, char **name,
for (unsigned i = 0; i < t->length; i++) {
size_t new_length = name_length;
- /* Append the subscript to the current uniform name */
+ /* Append the subscript to the current variable name */
ralloc_asprintf_rewrite_tail(name, &new_length, "[%u]", i);
recursion(t->fields.array, name, new_length,
@@ -137,7 +137,7 @@ uniform_field_visitor::recursion(const glsl_type *t, char **name,
}
void
-uniform_field_visitor::visit_field(const glsl_struct_field *field)
+program_resource_visitor::visit_field(const glsl_struct_field *field)
{
(void) field;
/* empty */
@@ -153,7 +153,7 @@ uniform_field_visitor::visit_field(const glsl_struct_field *field)
* If the same uniform is added multiple times (i.e., once for each shader
* target), it will only be accounted once.
*/
-class count_uniform_size : public uniform_field_visitor {
+class count_uniform_size : public program_resource_visitor {
public:
count_uniform_size(struct string_to_uint_map *map)
: num_active_uniforms(0), num_values(0), num_shader_samplers(0),
@@ -171,10 +171,10 @@ public:
void process(ir_variable *var)
{
if (var->is_interface_instance())
- uniform_field_visitor::process(var->interface_type,
- var->interface_type->name);
+ program_resource_visitor::process(var->interface_type,
+ var->interface_type->name);
else
- uniform_field_visitor::process(var);
+ program_resource_visitor::process(var);
}
/**
@@ -258,7 +258,7 @@ private:
* the \c gl_uniform_storage and \c gl_constant_value arrays are "big
* enough."
*/
-class parcel_out_uniform_storage : public uniform_field_visitor {
+class parcel_out_uniform_storage : public program_resource_visitor {
public:
parcel_out_uniform_storage(struct string_to_uint_map *map,
struct gl_uniform_storage *uniforms,
diff --git a/mesalib/src/glsl/link_varyings.cpp b/mesalib/src/glsl/link_varyings.cpp
index 25681d618..e2cb46e8c 100644
--- a/mesalib/src/glsl/link_varyings.cpp
+++ b/mesalib/src/glsl/link_varyings.cpp
@@ -35,6 +35,8 @@
#include "linker.h"
#include "link_varyings.h"
#include "main/macros.h"
+#include "program/hash_table.h"
+#include "program.h"
/**
@@ -154,10 +156,13 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
/**
* Initialize this object based on a string that was passed to
- * glTransformFeedbackVaryings. If there is a parse error, the error is
- * reported using linker_error(), and false is returned.
+ * glTransformFeedbackVaryings.
+ *
+ * If the input is mal-formed, this call still succeeds, but it sets
+ * this->var_name to a mal-formed input, so tfeedback_decl::find_output_var()
+ * will fail to find any matching variable.
*/
-bool
+void
tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog,
const void *mem_ctx, const char *input)
{
@@ -170,12 +175,13 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog,
this->is_clip_distance_mesa = false;
this->skip_components = 0;
this->next_buffer_separator = false;
+ this->matched_candidate = NULL;
if (ctx->Extensions.ARB_transform_feedback3) {
/* Parse gl_NextBuffer. */
if (strcmp(input, "gl_NextBuffer") == 0) {
this->next_buffer_separator = true;
- return true;
+ return;
}
/* Parse gl_SkipComponents. */
@@ -189,21 +195,17 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog,
this->skip_components = 4;
if (this->skip_components)
- return true;
+ return;
}
/* Parse a declaration. */
- const char *bracket = strrchr(input, '[');
-
- if (bracket) {
- this->var_name = ralloc_strndup(mem_ctx, input, bracket - input);
- if (sscanf(bracket, "[%u]", &this->array_subscript) != 1) {
- linker_error(prog, "Cannot parse transform feedback varying %s", input);
- return false;
- }
+ const char *base_name_end;
+ long subscript = parse_program_resource_name(input, &base_name_end);
+ this->var_name = ralloc_strndup(mem_ctx, input, base_name_end - input);
+ if (subscript >= 0) {
+ this->array_subscript = subscript;
this->is_subscripted = true;
} else {
- this->var_name = ralloc_strdup(mem_ctx, input);
this->is_subscripted = false;
}
@@ -215,8 +217,6 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog,
strcmp(this->var_name, "gl_ClipDistance") == 0) {
this->is_clip_distance_mesa = true;
}
-
- return true;
}
@@ -240,27 +240,32 @@ tfeedback_decl::is_same(const tfeedback_decl &x, const tfeedback_decl &y)
/**
- * Assign a location for this tfeedback_decl object based on the location
- * assignment in output_var.
+ * Assign a location for this tfeedback_decl object based on the transform
+ * feedback candidate found by find_candidate.
*
* If an error occurs, the error is reported through linker_error() and false
* is returned.
*/
bool
tfeedback_decl::assign_location(struct gl_context *ctx,
- struct gl_shader_program *prog,
- ir_variable *output_var)
+ struct gl_shader_program *prog)
{
assert(this->is_varying());
- if (output_var->type->is_array()) {
+ unsigned fine_location
+ = this->matched_candidate->toplevel_var->location * 4
+ + this->matched_candidate->toplevel_var->location_frac
+ + this->matched_candidate->offset;
+
+ if (this->matched_candidate->type->is_array()) {
/* Array variable */
const unsigned matrix_cols =
- output_var->type->fields.array->matrix_columns;
+ this->matched_candidate->type->fields.array->matrix_columns;
const unsigned vector_elements =
- output_var->type->fields.array->vector_elements;
+ this->matched_candidate->type->fields.array->vector_elements;
unsigned actual_array_size = this->is_clip_distance_mesa ?
- prog->Vert.ClipDistanceArraySize : output_var->type->array_size();
+ prog->Vert.ClipDistanceArraySize :
+ this->matched_candidate->type->array_size();
if (this->is_subscripted) {
/* Check array bounds. */
@@ -271,22 +276,11 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
actual_array_size);
return false;
}
- if (this->is_clip_distance_mesa) {
- this->location =
- output_var->location + this->array_subscript / 4;
- this->location_frac = this->array_subscript % 4;
- } else {
- unsigned fine_location
- = output_var->location * 4 + output_var->location_frac;
- unsigned array_elem_size = vector_elements * matrix_cols;
- fine_location += array_elem_size * this->array_subscript;
- this->location = fine_location / 4;
- this->location_frac = fine_location % 4;
- }
+ unsigned array_elem_size = this->is_clip_distance_mesa ?
+ 1 : vector_elements * matrix_cols;
+ fine_location += array_elem_size * this->array_subscript;
this->size = 1;
} else {
- this->location = output_var->location;
- this->location_frac = output_var->location_frac;
this->size = actual_array_size;
}
this->vector_elements = vector_elements;
@@ -294,7 +288,7 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
if (this->is_clip_distance_mesa)
this->type = GL_FLOAT;
else
- this->type = output_var->type->fields.array->gl_type;
+ this->type = this->matched_candidate->type->fields.array->gl_type;
} else {
/* Regular variable (scalar, vector, or matrix) */
if (this->is_subscripted) {
@@ -303,13 +297,13 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
this->orig_name, this->var_name);
return false;
}
- this->location = output_var->location;
- this->location_frac = output_var->location_frac;
this->size = 1;
- this->vector_elements = output_var->type->vector_elements;
- this->matrix_columns = output_var->type->matrix_columns;
- this->type = output_var->type->gl_type;
+ this->vector_elements = this->matched_candidate->type->vector_elements;
+ this->matrix_columns = this->matched_candidate->type->matrix_columns;
+ this->type = this->matched_candidate->type->gl_type;
}
+ this->location = fine_location / 4;
+ this->location_frac = fine_location % 4;
/* From GL_EXT_transform_feedback:
* A program will fail to link if:
@@ -404,35 +398,26 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
}
-ir_variable *
-tfeedback_decl::find_output_var(gl_shader_program *prog,
- gl_shader *producer) const
+const tfeedback_candidate *
+tfeedback_decl::find_candidate(gl_shader_program *prog,
+ hash_table *tfeedback_candidates)
{
const char *name = this->is_clip_distance_mesa
? "gl_ClipDistanceMESA" : this->var_name;
- ir_variable *var = producer->symbols->get_variable(name);
- if (var && var->mode == ir_var_shader_out) {
- const glsl_type *type = var->type;
- while (type->base_type == GLSL_TYPE_ARRAY)
- type = type->fields.array;
- if (type->base_type == GLSL_TYPE_STRUCT) {
- linker_error(prog, "Transform feedback of varying structs not "
- "implemented yet.");
- return NULL;
- }
- return var;
+ this->matched_candidate = (const tfeedback_candidate *)
+ hash_table_find(tfeedback_candidates, name);
+ if (!this->matched_candidate) {
+ /* From GL_EXT_transform_feedback:
+ * A program will fail to link if:
+ *
+ * * any variable name specified in the <varyings> array is not
+ * declared as an output in the geometry shader (if present) or
+ * the vertex shader (if no geometry shader is present);
+ */
+ linker_error(prog, "Transform feedback varying %s undeclared.",
+ this->orig_name);
}
-
- /* From GL_EXT_transform_feedback:
- * A program will fail to link if:
- *
- * * any variable name specified in the <varyings> array is not
- * declared as an output in the geometry shader (if present) or
- * the vertex shader (if no geometry shader is present);
- */
- linker_error(prog, "Transform feedback varying %s undeclared.",
- this->orig_name);
- return NULL;
+ return this->matched_candidate;
}
@@ -449,8 +434,7 @@ parse_tfeedback_decls(struct gl_context *ctx, struct gl_shader_program *prog,
char **varying_names, tfeedback_decl *decls)
{
for (unsigned i = 0; i < num_names; ++i) {
- if (!decls[i].init(ctx, prog, mem_ctx, varying_names[i]))
- return false;
+ decls[i].init(ctx, prog, mem_ctx, varying_names[i]);
if (!decls[i].is_varying())
continue;
@@ -871,6 +855,80 @@ is_varying_var(GLenum shaderType, const ir_variable *var)
/**
+ * Visitor class that generates tfeedback_candidate structs describing all
+ * possible targets of transform feedback.
+ *
+ * tfeedback_candidate structs are stored in the hash table
+ * tfeedback_candidates, which is passed to the constructor. This hash table
+ * maps varying names to instances of the tfeedback_candidate struct.
+ */
+class tfeedback_candidate_generator : public program_resource_visitor
+{
+public:
+ tfeedback_candidate_generator(void *mem_ctx,
+ hash_table *tfeedback_candidates)
+ : mem_ctx(mem_ctx),
+ tfeedback_candidates(tfeedback_candidates)
+ {
+ }
+
+ void process(ir_variable *var)
+ {
+ this->toplevel_var = var;
+ this->varying_floats = 0;
+ if (var->is_interface_instance())
+ program_resource_visitor::process(var->interface_type,
+ var->interface_type->name);
+ else
+ program_resource_visitor::process(var);
+ }
+
+private:
+ virtual void visit_field(const glsl_type *type, const char *name,
+ bool row_major)
+ {
+ assert(!type->is_record());
+ assert(!(type->is_array() && type->fields.array->is_record()));
+ assert(!type->is_interface());
+ assert(!(type->is_array() && type->fields.array->is_interface()));
+
+ (void) row_major;
+
+ tfeedback_candidate *candidate
+ = rzalloc(this->mem_ctx, tfeedback_candidate);
+ candidate->toplevel_var = this->toplevel_var;
+ candidate->type = type;
+ candidate->offset = this->varying_floats;
+ hash_table_insert(this->tfeedback_candidates, candidate,
+ ralloc_strdup(this->mem_ctx, name));
+ this->varying_floats += type->component_slots();
+ }
+
+ /**
+ * Memory context used to allocate hash table keys and values.
+ */
+ void * const mem_ctx;
+
+ /**
+ * Hash table in which tfeedback_candidate objects should be stored.
+ */
+ hash_table * const tfeedback_candidates;
+
+ /**
+ * Pointer to the toplevel variable that is being traversed.
+ */
+ ir_variable *toplevel_var;
+
+ /**
+ * Total number of varying floats that have been visited so far. This is
+ * used to determine the offset to each varying within the toplevel
+ * variable.
+ */
+ unsigned varying_floats;
+};
+
+
+/**
* Assign locations for all variables that are produced in one pipeline stage
* (the "producer") and consumed in the next stage (the "consumer").
*
@@ -902,6 +960,8 @@ assign_varying_locations(struct gl_context *ctx,
const unsigned producer_base = VERT_RESULT_VAR0;
const unsigned consumer_base = FRAG_ATTRIB_VAR0;
varying_matches matches(ctx->Const.DisableVaryingPacking);
+ hash_table *tfeedback_candidates
+ = hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare);
/* Operate in a total of three passes.
*
@@ -920,6 +980,9 @@ assign_varying_locations(struct gl_context *ctx,
if ((output_var == NULL) || (output_var->mode != ir_var_shader_out))
continue;
+ tfeedback_candidate_generator g(mem_ctx, tfeedback_candidates);
+ g.process(output_var);
+
ir_variable *input_var =
consumer ? consumer->symbols->get_variable(output_var->name) : NULL;
@@ -935,15 +998,16 @@ assign_varying_locations(struct gl_context *ctx,
if (!tfeedback_decls[i].is_varying())
continue;
- ir_variable *output_var
- = tfeedback_decls[i].find_output_var(prog, producer);
+ const tfeedback_candidate *matched_candidate
+ = tfeedback_decls[i].find_candidate(prog, tfeedback_candidates);
- if (output_var == NULL)
+ if (matched_candidate == NULL) {
+ hash_table_dtor(tfeedback_candidates);
return false;
-
- if (output_var->is_unmatched_generic_inout) {
- matches.record(output_var, NULL);
}
+
+ if (matched_candidate->toplevel_var->is_unmatched_generic_inout)
+ matches.record(matched_candidate->toplevel_var, NULL);
}
const unsigned slots_used = matches.assign_locations();
@@ -953,13 +1017,14 @@ assign_varying_locations(struct gl_context *ctx,
if (!tfeedback_decls[i].is_varying())
continue;
- ir_variable *output_var
- = tfeedback_decls[i].find_output_var(prog, producer);
-
- if (!tfeedback_decls[i].assign_location(ctx, prog, output_var))
+ if (!tfeedback_decls[i].assign_location(ctx, prog)) {
+ hash_table_dtor(tfeedback_candidates);
return false;
+ }
}
+ hash_table_dtor(tfeedback_candidates);
+
if (ctx->Const.DisableVaryingPacking) {
/* Transform feedback code assumes varyings are packed, so if the driver
* has disabled varying packing, make sure it does not support transform
diff --git a/mesalib/src/glsl/link_varyings.h b/mesalib/src/glsl/link_varyings.h
index 057e4b219..ee1010a7b 100644
--- a/mesalib/src/glsl/link_varyings.h
+++ b/mesalib/src/glsl/link_varyings.h
@@ -42,23 +42,66 @@ class ir_variable;
/**
+ * Data structure describing a varying which is available for use in transform
+ * feedback.
+ *
+ * For example, if the vertex shader contains:
+ *
+ * struct S {
+ * vec4 foo;
+ * float[3] bar;
+ * };
+ *
+ * varying S[2] v;
+ *
+ * Then there would be tfeedback_candidate objects corresponding to the
+ * following varyings:
+ *
+ * v[0].foo
+ * v[0].bar
+ * v[1].foo
+ * v[1].bar
+ */
+struct tfeedback_candidate
+{
+ /**
+ * Toplevel variable containing this varying. In the above example, this
+ * would point to the declaration of the varying v.
+ */
+ ir_variable *toplevel_var;
+
+ /**
+ * Type of this varying. In the above example, this would point to the
+ * glsl_type for "vec4" or "float[3]".
+ */
+ const glsl_type *type;
+
+ /**
+ * Offset within the toplevel variable where this varying occurs (counted
+ * in multiples of the size of a float).
+ */
+ unsigned offset;
+};
+
+
+/**
* Data structure tracking information about a transform feedback declaration
* during linking.
*/
class tfeedback_decl
{
public:
- bool init(struct gl_context *ctx, struct gl_shader_program *prog,
+ void init(struct gl_context *ctx, struct gl_shader_program *prog,
const void *mem_ctx, const char *input);
static bool is_same(const tfeedback_decl &x, const tfeedback_decl &y);
- bool assign_location(struct gl_context *ctx, struct gl_shader_program *prog,
- ir_variable *output_var);
+ bool assign_location(struct gl_context *ctx,
+ struct gl_shader_program *prog);
unsigned get_num_outputs() const;
bool store(struct gl_context *ctx, struct gl_shader_program *prog,
struct gl_transform_feedback_info *info, unsigned buffer,
const unsigned max_outputs) const;
- ir_variable *find_output_var(gl_shader_program *prog,
- gl_shader *producer) const;
+ const tfeedback_candidate *find_candidate(gl_shader_program *prog,
+ hash_table *tfeedback_candidates);
bool is_next_buffer_separator() const
{
@@ -158,6 +201,12 @@ private:
* Whether this is gl_NextBuffer from ARB_transform_feedback3.
*/
bool next_buffer_separator;
+
+ /**
+ * If find_candidate() has been called, pointer to the tfeedback_candidate
+ * data structure that was found. Otherwise NULL.
+ */
+ const tfeedback_candidate *matched_candidate;
};
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp
index 63ce178f4..57e7a9ad3 100644
--- a/mesalib/src/glsl/linker.cpp
+++ b/mesalib/src/glsl/linker.cpp
@@ -200,6 +200,65 @@ linker_warning(gl_shader_program *prog, const char *fmt, ...)
}
+/**
+ * Given a string identifying a program resource, break it into a base name
+ * and an optional array index in square brackets.
+ *
+ * If an array index is present, \c out_base_name_end is set to point to the
+ * "[" that precedes the array index, and the array index itself is returned
+ * as a long.
+ *
+ * If no array index is present (or if the array index is negative or
+ * mal-formed), \c out_base_name_end, is set to point to the null terminator
+ * at the end of the input string, and -1 is returned.
+ *
+ * Only the final array index is parsed; if the string contains other array
+ * indices (or structure field accesses), they are left in the base name.
+ *
+ * No attempt is made to check that the base name is properly formed;
+ * typically the caller will look up the base name in a hash table, so
+ * ill-formed base names simply turn into hash table lookup failures.
+ */
+long
+parse_program_resource_name(const GLchar *name,
+ const GLchar **out_base_name_end)
+{
+ /* Section 7.3.1 ("Program Interfaces") of the OpenGL 4.3 spec says:
+ *
+ * "When an integer array element or block instance number is part of
+ * the name string, it will be specified in decimal form without a "+"
+ * or "-" sign or any extra leading zeroes. Additionally, the name
+ * string will not include white space anywhere in the string."
+ */
+
+ const size_t len = strlen(name);
+ *out_base_name_end = name + len;
+
+ if (len == 0 || name[len-1] != ']')
+ return -1;
+
+ /* Walk backwards over the string looking for a non-digit character. This
+ * had better be the opening bracket for an array index.
+ *
+ * Initially, i specifies the location of the ']'. Since the string may
+ * contain only the ']' charcater, walk backwards very carefully.
+ */
+ unsigned i;
+ for (i = len - 1; (i > 0) && isdigit(name[i-1]); --i)
+ /* empty */ ;
+
+ if ((i == 0) || name[i-1] != '[')
+ return -1;
+
+ long array_index = strtol(&name[i], NULL, 10);
+ if (array_index < 0)
+ return -1;
+
+ *out_base_name_end = name + (i - 1);
+ return array_index;
+}
+
+
void
link_invalidate_variable_locations(gl_shader *sh, int input_base,
int output_base)
diff --git a/mesalib/src/glsl/linker.h b/mesalib/src/glsl/linker.h
index 14eb9c1cd..f1ce50ace 100644
--- a/mesalib/src/glsl/linker.h
+++ b/mesalib/src/glsl/linker.h
@@ -61,38 +61,39 @@ link_uniform_blocks(void *mem_ctx,
struct gl_uniform_block **blocks_ret);
/**
- * Class for processing all of the leaf fields of an uniform
+ * Class for processing all of the leaf fields of a variable that corresponds
+ * to a program resource.
*
- * Leaves are, roughly speaking, the parts of the uniform that the application
- * could query with \c glGetUniformLocation (or that could be returned by
- * \c glGetActiveUniforms).
+ * The leaf fields are all the parts of the variable that the application
+ * could query using \c glGetProgramResourceIndex (or that could be returned
+ * by \c glGetProgramResourceName).
*
* Classes my derive from this class to implement specific functionality.
* This class only provides the mechanism to iterate over the leaves. Derived
* classes must implement \c ::visit_field and may override \c ::process.
*/
-class uniform_field_visitor {
+class program_resource_visitor {
public:
/**
- * Begin processing a uniform
+ * Begin processing a variable
*
* Classes that overload this function should call \c ::process from the
- * base class to start the recursive processing of the uniform.
+ * base class to start the recursive processing of the variable.
*
- * \param var The uniform variable that is to be processed
+ * \param var The variable that is to be processed
*
- * Calls \c ::visit_field for each leaf of the uniform.
+ * Calls \c ::visit_field for each leaf of the variable.
*
* \warning
- * This entry should only be used with uniform blocks in cases where the
- * row / column ordering of matrices in the block does not matter. For
- * example, enumerating the names of members of the block, but not for
- * determining the offsets of members.
+ * When processing a uniform block, this entry should only be used in cases
+ * where the row / column ordering of matrices in the block does not
+ * matter. For example, enumerating the names of members of the block, but
+ * not for determining the offsets of members.
*/
void process(ir_variable *var);
/**
- * Begin processing a uniform of a structured type.
+ * Begin processing a variable of a structured type.
*
* This flavor of \c process should be used to handle structured types
* (i.e., structures, interfaces, or arrays there of) that need special
@@ -100,7 +101,7 @@ public:
* (instead of the instance name) is used for an interface block.
*
* \param type Type that is to be processed, associated with \c name
- * \param name Base name of the structured uniform being processed
+ * \param name Base name of the structured variable being processed
*
* \note
* \c type must be \c GLSL_TYPE_RECORD, \c GLSL_TYPE_INTERFACE, or an array
@@ -110,7 +111,7 @@ public:
protected:
/**
- * Method invoked for each leaf of the uniform
+ * Method invoked for each leaf of the variable
*
* \param type Type of the field.
* \param name Fully qualified name of the field.
diff --git a/mesalib/src/glsl/program.h b/mesalib/src/glsl/program.h
index 437ca1462..46ce9dccc 100644
--- a/mesalib/src/glsl/program.h
+++ b/mesalib/src/glsl/program.h
@@ -33,3 +33,7 @@ linker_error(gl_shader_program *prog, const char *fmt, ...)
extern void
linker_warning(gl_shader_program *prog, const char *fmt, ...)
PRINTFLIKE(2, 3);
+
+extern long
+parse_program_resource_name(const GLchar *name,
+ const GLchar **out_base_name_end);