[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 00:51:00 PDT 2015
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;
+ } 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
More information about the mesa-dev
mailing list