* an atomic counter.
*/
int atomic_buffer_index;
+
+ /**
+ * The 'base location' for this uniform in the uniform remap table. For
+ * arrays this is the first element in the array.
+ */
+ unsigned remap_location;
};
#ifdef __cplusplus
prog->UniformStorage = NULL;
prog->NumUserUniformStorage = 0;
+ ralloc_free(prog->UniformRemapTable);
+ prog->UniformRemapTable = NULL;
+ prog->NumUniformRemapTable = 0;
+
if (prog->UniformHash != NULL) {
prog->UniformHash->clear();
} else {
sizeof(prog->_LinkedShaders[i]->SamplerTargets));
}
- /* Determine the size of the largest uniform array queryable via
- * glGetUniformLocation. Using this as the location scale guarantees that
- * there is enough "room" for the array index to be stored in the low order
- * part of the uniform location. It also makes the locations be more
- * tightly packed.
- */
- unsigned max_array_size = 1;
+ /* Build the uniform remap table that is used to set/get uniform locations */
for (unsigned i = 0; i < num_user_uniforms; i++) {
- if (uniforms[i].array_elements > max_array_size)
- max_array_size = uniforms[i].array_elements;
- }
- prog->UniformLocationBaseScale = max_array_size;
+ /* how many new entries for this uniform? */
+ const unsigned entries = MAX2(1, uniforms[i].array_elements);
+
+ /* resize remap table to fit new entries */
+ prog->UniformRemapTable =
+ reralloc(prog,
+ prog->UniformRemapTable,
+ gl_uniform_storage *,
+ prog->NumUniformRemapTable + entries);
+
+ /* set pointers for this uniform */
+ for (unsigned j = 0; j < entries; j++)
+ prog->UniformRemapTable[prog->NumUniformRemapTable+j] = &uniforms[i];
+
+ /* set the base location in remap table for the uniform */
+ uniforms[i].remap_location = prog->NumUniformRemapTable;
+
+ prog->NumUniformRemapTable += entries;
+ }
#ifndef NDEBUG
for (unsigned i = 0; i < num_user_uniforms; i++) {
unsigned NumUserUniformStorage;
struct gl_uniform_storage *UniformStorage;
+ /**
+ * Mapping from GL uniform locations returned by \c glUniformLocation to
+ * UniformStorage entries. Arrays will have multiple contiguous slots
+ * in the UniformRemapTable, all pointing to the same UniformStorage entry.
+ */
+ unsigned NumUniformRemapTable;
+ struct gl_uniform_storage **UniformRemapTable;
+
/**
* Size of the gl_ClipDistance array that is output from the last pipeline
* stage before the fragment shader.
struct gl_uniform_block *UniformBlocks;
unsigned NumUniformBlocks;
- /**
- * Scale factor for the uniform base location
- *
- * This is used to generate locations (returned by \c glGetUniformLocation)
- * of uniforms. The base location of the uniform is multiplied by this
- * value, and the array index is added.
- *
- * \note
- * Must be >= 1.
- *
- * \sa
- * _mesa_uniform_merge_location_offset, _mesa_uniform_split_location_offset
- */
- unsigned UniformLocationBaseScale;
-
/**
* Indices into the _LinkedShaders's UniformBlocks[] array for each stage
* they're used in, or -1.
ralloc_free(shProg->UniformStorage);
shProg->NumUserUniformStorage = 0;
shProg->UniformStorage = NULL;
- shProg->UniformLocationBaseScale = 0;
+ }
+
+ if (shProg->UniformRemapTable) {
+ ralloc_free(shProg->UniformRemapTable);
+ shProg->NumUniformRemapTable = 0;
+ shProg->UniformRemapTable = NULL;
}
if (shProg->UniformHash) {
return false;
}
- _mesa_uniform_split_location_offset(shProg, location, loc, array_index);
-
- if (*loc >= shProg->NumUserUniformStorage) {
+ /* Check that the given location is in bounds of uniform remap table. */
+ if (location >= (GLint) shProg->NumUniformRemapTable) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
caller, location);
return false;
}
+ _mesa_uniform_split_location_offset(shProg, location, loc, array_index);
+
if (shProg->UniformStorage[*loc].array_elements == 0 && count > 1) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(count > 1 for non-array, location=%d)",
* element. We could insert dummy entries in the list for each array
* element after [0] but that causes complications elsewhere.
*
- * We solve this problem by encoding two values in the location that's
- * returned by glGetUniformLocation():
- * a) index into gl_uniform_list::Uniforms[] for the uniform
- * b) an array/field offset (0 for simple types)
+ * We solve this problem by creating multiple entries for uniform arrays
+ * in the UniformRemapTable so that their elements get sequential locations.
+ *
+ * Utility functions below offer functionality to split UniformRemapTable
+ * location in to location of the uniform in UniformStorage + offset to the
+ * array element (0 if not an array) and also merge it back again as the
+ * UniformRemapTable location.
*
- * These two values are encoded in the high and low halves of a GLint.
- * By putting the uniform number in the high part and the offset in the
- * low part, we can support the unofficial ability to index into arrays
- * by adding offsets to the location value.
*/
/*@{*/
/**
- * Combine the uniform's base location and the offset
+ * Combine the uniform's storage index and the array index
*/
static inline GLint
_mesa_uniform_merge_location_offset(const struct gl_shader_program *prog,
- unsigned base_location, unsigned offset)
+ unsigned storage_index,
+ unsigned uniform_array_index)
{
- assert(prog->UniformLocationBaseScale >= 1);
- assert(offset < prog->UniformLocationBaseScale);
- return (base_location * prog->UniformLocationBaseScale) + offset;
+ /* location in remap table + array element offset */
+ return prog->UniformStorage[storage_index].remap_location +
+ uniform_array_index;
}
/**
- * Separate the uniform base location and parameter offset
+ * Separate the uniform storage index and array index
*/
static inline void
_mesa_uniform_split_location_offset(const struct gl_shader_program *prog,
- GLint location, unsigned *base_location,
- unsigned *offset)
+ GLint location, unsigned *storage_index,
+ unsigned *uniform_array_index)
{
- *offset = location % prog->UniformLocationBaseScale;
- *base_location = location / prog->UniformLocationBaseScale;
+ *storage_index = prog->UniformRemapTable[location] - prog->UniformStorage;
+ *uniform_array_index = location -
+ prog->UniformRemapTable[location]->remap_location;
+
+ /*gl_uniform_storage in UniformStorage with the calculated base_location
+ * must match with the entry in remap table
+ */
+ assert(&prog->UniformStorage[*storage_index] ==
+ prog->UniformRemapTable[location]);
}
/*@}*/