[Mesa-dev] [PATCH V4 1/6] glsl: order indices for samplers inside a struct array
Timothy Arceri
t_arceri at yahoo.com.au
Tue Sep 15 17:20:33 PDT 2015
On Tue, 2015-09-15 at 11:23 -0700, Jason Ekstrand wrote:
> On Tue, Sep 15, 2015 at 12:51 AM, Timothy Arceri <
> t_arceri at yahoo.com.au> wrote:
> > This allows the correct offset to be easily calculated for indirect
> > indexing when a struct array contains multiple samplers, or any
> > crazy
> > nesting.
> >
> > The indices for the folling struct will now look like this:
> > Sampler index: 0 Name: s[0].tex
> > Sampler index: 1 Name: s[1].tex
> > Sampler index: 2 Name: s[0].si.tex
> > Sampler index: 3 Name: s[1].si.tex
> > Sampler index: 4 Name: s[0].si.tex2
> > Sampler index: 5 Name: s[1].si.tex2
> >
> > Before this change it looked like this:
> > Sampler index: 0 Name: s[0].tex
> > Sampler index: 3 Name: s[1].tex
> > Sampler index: 1 Name: s[0].si.tex
> > Sampler index: 4 Name: s[1].si.tex
> > Sampler index: 2 Name: s[0].si.tex2
> > Sampler index: 5 Name: s[1].si.tex2
> >
> > struct S_inner {
> > sampler2D tex;
> > sampler2D tex2;
> > };
> >
> > struct S {
> > sampler2D tex;
> > S_inner si;
> > };
> >
> > uniform S s[2];
> >
> > V3: Update comments with suggestions from Jason
> >
> > V2: rename struct array counter to have better name
> >
> > Reviewed-by: Jason Ekstrand <jason.ekstrand at intel.com>
> > ---
> > src/glsl/link_uniforms.cpp | 114
> > ++++++++++++++++++++++++++++++++++++++-------
> > src/glsl/linker.h | 4 +-
> > 2 files changed, 100 insertions(+), 18 deletions(-)
> >
> > diff --git a/src/glsl/link_uniforms.cpp
> > b/src/glsl/link_uniforms.cpp
> > index a0cb618..3a1296b 100644
> > --- a/src/glsl/link_uniforms.cpp
> > +++ b/src/glsl/link_uniforms.cpp
> > @@ -28,6 +28,7 @@
> > #include "glsl_symbol_table.h"
> > #include "program/hash_table.h"
> > #include "program.h"
> > +#include "util/hash_table.h"
> >
> > /**
> > * \file link_uniforms.cpp
> > @@ -62,14 +63,17 @@ program_resource_visitor::process(const
> > glsl_type *type, const char *name)
> > assert(type->without_array()->is_record()
> > || type->without_array()->is_interface());
> >
> > + unsigned record_array_count = 1;
> > char *name_copy = ralloc_strdup(NULL, name);
> > - recursion(type, &name_copy, strlen(name), false, NULL, false);
> > + recursion(type, &name_copy, strlen(name), false, NULL, false,
> > + record_array_count);
> > ralloc_free(name_copy);
> > }
> >
> > void
> > program_resource_visitor::process(ir_variable *var)
> > {
> > + unsigned record_array_count = 1;
> > const glsl_type *t = var->type;
> > const bool row_major =
> > var->data.matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR;
> > @@ -110,7 +114,8 @@ program_resource_visitor::process(ir_variable
> > *var)
> > * lowering is only applied to non-uniform interface
> > blocks, so we
> > * can safely pass false for row_major.
> > */
> > - recursion(var->type, &name, new_length, row_major, NULL,
> > false);
> > + recursion(var->type, &name, new_length, row_major, NULL,
> > false,
> > + record_array_count);
> > }
> > ralloc_free(name);
> > } else if (var->data.from_named_ifc_block_nonarray) {
> > @@ -134,19 +139,23 @@ program_resource_visitor::process(ir_variable
> > *var)
> > * is only applied to non-uniform interface blocks, so we
> > can safely
> > * pass false for row_major.
> > */
> > - recursion(var->type, &name, strlen(name), row_major, NULL,
> > false);
> > + recursion(var->type, &name, strlen(name), row_major, NULL,
> > false,
> > + record_array_count);
> > ralloc_free(name);
> > } else if (t->without_array()->is_record()) {
> > char *name = ralloc_strdup(NULL, var->name);
> > - recursion(var->type, &name, strlen(name), row_major, NULL,
> > false);
> > + recursion(var->type, &name, strlen(name), row_major, NULL,
> > false,
> > + record_array_count);
> > ralloc_free(name);
> > } else if (t->is_interface()) {
> > char *name = ralloc_strdup(NULL, var->type->name);
> > - recursion(var->type, &name, strlen(name), row_major, NULL,
> > false);
> > + recursion(var->type, &name, strlen(name), row_major, NULL,
> > false,
> > + record_array_count);
> > ralloc_free(name);
> > } else if (t->is_array() && t->fields.array->is_interface()) {
> > char *name = ralloc_strdup(NULL, var->type->fields.array
> > ->name);
> > - recursion(var->type, &name, strlen(name), row_major, NULL,
> > false);
> > + recursion(var->type, &name, strlen(name), row_major, NULL,
> > false,
> > + record_array_count);
> > ralloc_free(name);
> > } else {
> > this->visit_field(t, var->name, row_major, NULL, false);
> > @@ -157,7 +166,8 @@ void
> > program_resource_visitor::recursion(const glsl_type *t, char
> > **name,
> > size_t name_length, bool
> > row_major,
> > const glsl_type *record_type,
> > - bool last_field)
> > + bool last_field,
> > + unsigned record_array_count)
> > {
> > /* Records need to have each field processed individually.
> > *
> > @@ -204,7 +214,7 @@ program_resource_visitor::recursion(const
> > glsl_type *t, char **name,
> > recursion(t->fields.structure[i].type, name, new_length,
> > field_row_major,
> > record_type,
> > - (i + 1) == t->length);
> > + (i + 1) == t->length, record_array_count);
> >
> > /* Only the first leaf-field of the record gets called
> > with the
> > * record type pointer.
> > @@ -221,6 +231,8 @@ program_resource_visitor::recursion(const
> > glsl_type *t, char **name,
> > if (record_type == NULL && t->fields.array->is_record())
> > record_type = t->fields.array;
> >
> > + record_array_count *= t->length;
> > +
> > for (unsigned i = 0; i < t->length; i++) {
> > size_t new_length = name_length;
> >
> > @@ -229,7 +241,7 @@ program_resource_visitor::recursion(const
> > glsl_type *t, char **name,
> >
> > recursion(t->fields.array, name, new_length, row_major,
> > record_type,
> > - (i + 1) == t->length);
> > + (i + 1) == t->length, record_array_count);
> >
> > /* Only the first leaf-field of the record gets called
> > with the
> > * record type pointer.
> > @@ -237,6 +249,7 @@ program_resource_visitor::recursion(const
> > glsl_type *t, char **name,
> > record_type = NULL;
> > }
> > } else {
> > + this->set_record_array_count(record_array_count);
> > this->visit_field(t, *name, row_major, record_type,
> > last_field);
> > }
> > }
> > @@ -267,6 +280,11 @@ program_resource_visitor::leave_record(const
> > glsl_type *, const char *, bool)
> > {
> > }
> >
> > +void
> > +program_resource_visitor::set_record_array_count(unsigned)
> > +{
> > +}
> > +
> > namespace {
> >
> > /**
> > @@ -431,6 +449,7 @@ public:
> > this->next_sampler = 0;
> > this->next_image = 0;
> > this->next_subroutine = 0;
> > + this->record_array_count = 1;
> > memset(this->targets, 0, sizeof(this->targets));
> > }
> >
> > @@ -439,6 +458,7 @@ public:
> > {
> > current_var = var;
> > field_counter = 0;
> > + this->record_next_sampler = new string_to_uint_map;
> >
> > ubo_block_index = -1;
> > if (var->is_in_buffer_block()) {
> > @@ -492,6 +512,8 @@ public:
> > process(var);
> > } else
> > process(var);
> > + }
> > + delete this->record_next_sampler;
> > }
> >
> > int ubo_block_index;
> > @@ -500,17 +522,62 @@ public:
> >
> > private:
> > void handle_samplers(const glsl_type *base_type,
> > - struct gl_uniform_storage *uniform)
> > + struct gl_uniform_storage *uniform, const
> > char *name)
> > {
> > if (base_type->is_sampler()) {
> > - uniform->sampler[shader_type].index = this->next_sampler;
> > uniform->sampler[shader_type].active = true;
> >
> > - /* Increment the sampler by 1 for non-arrays and by the
> > number of
> > - * array elements for arrays.
> > - */
> > - this->next_sampler +=
> > - MAX2(1, uniform->array_elements);
> > + /* Handle multiple samplers inside struct arrays */
> > + if (this->record_array_count > 1) {
> > + unsigned inner_array_size = MAX2(1, uniform
> > ->array_elements);
> > + char *name_copy = ralloc_strdup(NULL, name);
> > +
> > + /* Remove all array subscripts from the sampler name
> > */
> > + char *str_start;
> > + const char *str_end;
> > + while((str_start = strchr(name_copy, '[')) &&
> > + (str_end = strchr(name_copy, ']'))) {
> > + memmove(str_start, str_end + 1, 1 +
> > strlen(str_end));
> > + }
> > +
> > + unsigned index = 0;
> > + if (this->record_next_sampler->get(index, name_copy))
> > {
> > + /* In this case, we've already seen this uniform so
> > we just use
> > + * the next sampler index recorded the last time we
> > visited.
> > + */
> > + uniform->sampler[shader_type].index = index;
> > + index = inner_array_size + uniform
> > ->sampler[shader_type].index;
> > + this->record_next_sampler->put(index, name_copy);
> > +
> > + ralloc_free(name_copy);
> > + return;
>
> Why is this an early return? Looking at things it seems to be
> because
> we don't want to assign targets and setup samplers_used more than
> once. However, it deserves a comment as well.
Correct. This was in the original comment that was replaced. I'll add
something back in above the return. Thanks.
>
> > + } else {
> > + /* We've never seen this uniform before so we need
> > to allocate
> > + * enough indices to store it.
> > + *
> > + * Nested struct arrays behave like arrays of
> > arrays so we need
> > + * to increase the index by the total number of
> > elements of the
> > + * sampler in case there is more than one sampler
> > inside the
> > + * structs. This allows the offset to be easily
> > calculated for
> > + * indirect indexing.
> > + */
> > + uniform->sampler[shader_type].index = this
> > ->next_sampler;
> > + this->next_sampler +=
> > + inner_array_size * this->record_array_count;
> > +
> > + /* Store the next index for future passes over the
> > struct array
> > + */
> > + index = uniform->sampler[shader_type].index +
> > inner_array_size;
> > + this->record_next_sampler->put(index, name_copy);
> > + ralloc_free(name_copy);
> > + }
> > + } else {
> > + /* Increment the sampler by 1 for non-arrays and by
> > the number of
> > + * array elements for arrays.
> > + */
> > + uniform->sampler[shader_type].index = this
> > ->next_sampler;
> > + this->next_sampler += MAX2(1, uniform
> > ->array_elements);
> > + }
> >
> > const gl_texture_index target = base_type
> > ->sampler_index();
> > const unsigned shadow = base_type->sampler_shadow;
> > @@ -563,6 +630,11 @@ private:
> > }
> > }
> >
> > + virtual void set_record_array_count(unsigned
> > record_array_count)
> > + {
> > + this->record_array_count = record_array_count;
> > + }
> > +
> > virtual void visit_field(const glsl_type *type, const char
> > *name,
> > bool row_major)
> > {
> > @@ -614,7 +686,7 @@ private:
> > }
> >
> > /* This assigns uniform indices to sampler and image
> > uniforms. */
> > - handle_samplers(base_type, &this->uniforms[id]);
> > + handle_samplers(base_type, &this->uniforms[id], name);
> > handle_images(base_type, &this->uniforms[id]);
> > handle_subroutines(base_type, &this->uniforms[id]);
> >
> > @@ -703,6 +775,14 @@ private:
> > unsigned next_image;
> > unsigned next_subroutine;
> >
> > + /* Stores total struct array elements including nested structs
> > */
> > + unsigned record_array_count;
> > +
> > + /* Map for temporarily storing next sampler index when handling
> > samplers in
> > + * struct arrays.
> > + */
> > + struct string_to_uint_map *record_next_sampler;
> > +
> > public:
> > union gl_constant_value *values;
> >
> > diff --git a/src/glsl/linker.h b/src/glsl/linker.h
> > index ce3dc32..40e6c73 100644
> > --- a/src/glsl/linker.h
> > +++ b/src/glsl/linker.h
> > @@ -181,6 +181,8 @@ protected:
> > virtual void leave_record(const glsl_type *type, const char
> > *name,
> > bool row_major);
> >
> > + virtual void set_record_array_count(unsigned
> > record_array_count);
> > +
> > private:
> > /**
> > * \param name_length Length of the current name \b not
> > including the
> > @@ -191,7 +193,7 @@ private:
> > */
> > void recursion(const glsl_type *t, char **name, size_t
> > name_length,
> > bool row_major, const glsl_type *record_type,
> > - bool last_field);
> > + bool last_field, unsigned record_array_count);
> > };
> >
> > void
> > --
> > 2.4.3
> >
> > _______________________________________________
> > mesa-dev mailing list
> > mesa-dev at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/mesa-dev
More information about the mesa-dev
mailing list