glsl: Merge the lists of uniform blocks into the linked shader program.
This attempts error-checking, but the layout isn't done yet. Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
This commit is contained in:
@@ -316,6 +316,67 @@ public:
|
||||
unsigned shader_shadow_samplers;
|
||||
};
|
||||
|
||||
/**
|
||||
* Merges a uniform block into an array of uniform blocks that may or
|
||||
* may not already contain a copy of it.
|
||||
*
|
||||
* Returns the index of the new block in the array.
|
||||
*/
|
||||
int
|
||||
link_cross_validate_uniform_block(void *mem_ctx,
|
||||
struct gl_uniform_block **linked_blocks,
|
||||
unsigned int *num_linked_blocks,
|
||||
struct gl_uniform_block *new_block)
|
||||
{
|
||||
for (unsigned int i = 0; i < *num_linked_blocks; i++) {
|
||||
struct gl_uniform_block *old_block = &(*linked_blocks)[i];
|
||||
if (strcmp(old_block->Name, new_block->Name) == 0) {
|
||||
if (old_block->NumUniforms != new_block->NumUniforms) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < old_block->NumUniforms; j++) {
|
||||
if (strcmp(old_block->Uniforms[j].Name,
|
||||
new_block->Uniforms[j].Name) != 0)
|
||||
return -1;
|
||||
|
||||
if (old_block->Uniforms[j].Offset !=
|
||||
new_block->Uniforms[j].Offset)
|
||||
return -1;
|
||||
|
||||
if (old_block->Uniforms[j].RowMajor !=
|
||||
new_block->Uniforms[j].RowMajor)
|
||||
return -1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
*linked_blocks = reralloc(mem_ctx, *linked_blocks,
|
||||
struct gl_uniform_block,
|
||||
*num_linked_blocks + 1);
|
||||
int linked_block_index = (*num_linked_blocks)++;
|
||||
struct gl_uniform_block *linked_block = &(*linked_blocks)[linked_block_index];
|
||||
|
||||
memcpy(linked_block, new_block, sizeof(*new_block));
|
||||
linked_block->Uniforms = ralloc_array(*linked_blocks,
|
||||
struct gl_uniform_buffer_variable,
|
||||
linked_block->NumUniforms);
|
||||
|
||||
memcpy(linked_block->Uniforms,
|
||||
new_block->Uniforms,
|
||||
sizeof(*linked_block->Uniforms) * linked_block->NumUniforms);
|
||||
|
||||
for (unsigned int i = 0; i < linked_block->NumUniforms; i++) {
|
||||
struct gl_uniform_buffer_variable *ubo_var =
|
||||
&linked_block->Uniforms[i];
|
||||
|
||||
ubo_var->Name = ralloc_strdup(*linked_blocks, ubo_var->Name);
|
||||
}
|
||||
|
||||
return linked_block_index;
|
||||
}
|
||||
|
||||
void
|
||||
link_assign_uniform_locations(struct gl_shader_program *prog)
|
||||
{
|
||||
|
@@ -581,6 +581,48 @@ cross_validate_uniforms(struct gl_shader_program *prog)
|
||||
MESA_SHADER_TYPES, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulates the array of prog->UniformBlocks and checks that all
|
||||
* definitons of blocks agree on their contents.
|
||||
*/
|
||||
static bool
|
||||
interstage_cross_validate_uniform_blocks(struct gl_shader_program *prog)
|
||||
{
|
||||
unsigned max_num_uniform_blocks = 0;
|
||||
for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
|
||||
if (prog->_LinkedShaders[i])
|
||||
max_num_uniform_blocks += prog->_LinkedShaders[i]->NumUniformBlocks;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
|
||||
struct gl_shader *sh = prog->_LinkedShaders[i];
|
||||
|
||||
prog->UniformBlockStageIndex[i] = ralloc_array(prog, int,
|
||||
max_num_uniform_blocks);
|
||||
for (unsigned int j = 0; j < max_num_uniform_blocks; j++)
|
||||
prog->UniformBlockStageIndex[i][j] = -1;
|
||||
|
||||
if (sh == NULL)
|
||||
continue;
|
||||
|
||||
for (unsigned int j = 0; j < sh->NumUniformBlocks; j++) {
|
||||
int index = link_cross_validate_uniform_block(prog,
|
||||
&prog->UniformBlocks,
|
||||
&prog->NumUniformBlocks,
|
||||
&sh->UniformBlocks[j]);
|
||||
|
||||
if (index == -1) {
|
||||
linker_error(prog, "uniform block `%s' has mismatching definitions",
|
||||
sh->UniformBlocks[j].Name);
|
||||
return false;
|
||||
}
|
||||
|
||||
prog->UniformBlockStageIndex[i][index] = j;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that outputs from one stage match inputs of another
|
||||
@@ -910,7 +952,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Combine a group of shaders for a single stage to generate a linked shader
|
||||
*
|
||||
@@ -925,11 +966,31 @@ link_intrastage_shaders(void *mem_ctx,
|
||||
struct gl_shader **shader_list,
|
||||
unsigned num_shaders)
|
||||
{
|
||||
struct gl_uniform_block *uniform_blocks = NULL;
|
||||
unsigned num_uniform_blocks = 0;
|
||||
|
||||
/* Check that global variables defined in multiple shaders are consistent.
|
||||
*/
|
||||
if (!cross_validate_globals(prog, shader_list, num_shaders, false))
|
||||
return NULL;
|
||||
|
||||
/* Check that uniform blocks between shaders for a stage agree. */
|
||||
for (unsigned i = 0; i < num_shaders; i++) {
|
||||
struct gl_shader *sh = shader_list[i];
|
||||
|
||||
for (unsigned j = 0; j < shader_list[i]->NumUniformBlocks; j++) {
|
||||
int index = link_cross_validate_uniform_block(mem_ctx,
|
||||
&uniform_blocks,
|
||||
&num_uniform_blocks,
|
||||
&sh->UniformBlocks[j]);
|
||||
if (index == -1) {
|
||||
linker_error(prog, "uniform block `%s' has mismatching definitions",
|
||||
sh->UniformBlocks[j].Name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that there is only a single definition of each function signature
|
||||
* across all shaders.
|
||||
*/
|
||||
@@ -997,6 +1058,10 @@ link_intrastage_shaders(void *mem_ctx,
|
||||
linked->ir = new(linked) exec_list;
|
||||
clone_ir_list(mem_ctx, linked->ir, main->ir);
|
||||
|
||||
linked->UniformBlocks = uniform_blocks;
|
||||
linked->NumUniformBlocks = num_uniform_blocks;
|
||||
ralloc_steal(linked, linked->UniformBlocks);
|
||||
|
||||
populate_symbol_table(linked);
|
||||
|
||||
/* The a pointer to the main function in the final linked shader (i.e., the
|
||||
@@ -2289,11 +2354,17 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
|
||||
prog->Validated = false;
|
||||
prog->_Used = false;
|
||||
|
||||
if (prog->InfoLog != NULL)
|
||||
ralloc_free(prog->InfoLog);
|
||||
|
||||
ralloc_free(prog->InfoLog);
|
||||
prog->InfoLog = ralloc_strdup(NULL, "");
|
||||
|
||||
ralloc_free(prog->UniformBlocks);
|
||||
prog->UniformBlocks = NULL;
|
||||
prog->NumUniformBlocks = 0;
|
||||
for (int i = 0; i < MESA_SHADER_TYPES; i++) {
|
||||
ralloc_free(prog->UniformBlockStageIndex[i]);
|
||||
prog->UniformBlockStageIndex[i] = NULL;
|
||||
}
|
||||
|
||||
/* Separate the shaders into groups based on their type.
|
||||
*/
|
||||
struct gl_shader **vert_shader_list;
|
||||
@@ -2422,6 +2493,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
|
||||
}
|
||||
}
|
||||
|
||||
if (!interstage_cross_validate_uniform_blocks(prog))
|
||||
goto done;
|
||||
|
||||
/* Do common optimization before assigning storage for attributes,
|
||||
* uniforms, and varyings. Later optimization could possibly make
|
||||
* some of that unused.
|
||||
|
@@ -40,6 +40,12 @@ link_assign_uniform_locations(struct gl_shader_program *prog);
|
||||
extern void
|
||||
link_set_uniform_initializers(struct gl_shader_program *prog);
|
||||
|
||||
extern int
|
||||
link_cross_validate_uniform_block(void *mem_ctx,
|
||||
struct gl_uniform_block **linked_blocks,
|
||||
unsigned int *num_linked_blocks,
|
||||
struct gl_uniform_block *new_block);
|
||||
|
||||
/**
|
||||
* Class for processing all of the leaf fields of an uniform
|
||||
*
|
||||
|
@@ -2216,6 +2216,15 @@ struct gl_shader
|
||||
*/
|
||||
unsigned num_uniform_components;
|
||||
|
||||
/**
|
||||
* This shader's uniform block information.
|
||||
*
|
||||
* The offsets of the variables are assigned only for shaders in a program's
|
||||
* _LinkedShaders[].
|
||||
*/
|
||||
struct gl_uniform_block *UniformBlocks;
|
||||
unsigned NumUniformBlocks;
|
||||
|
||||
struct exec_list *ir;
|
||||
struct glsl_symbol_table *symbols;
|
||||
|
||||
@@ -2254,6 +2263,19 @@ struct gl_uniform_block
|
||||
/** Array of supplemental information about UBO ir_variables. */
|
||||
struct gl_uniform_buffer_variable *Uniforms;
|
||||
GLuint NumUniforms;
|
||||
|
||||
/**
|
||||
* Index (GL_UNIFORM_BLOCK_BINDING) into ctx->UniformBufferBindings[] to use
|
||||
* with glBindBufferBase to bind a buffer object to this uniform block. When
|
||||
* updated in the program, _NEW_BUFFER_OBJECT will be set.
|
||||
*/
|
||||
GLuint Binding;
|
||||
|
||||
/**
|
||||
* Minimum size of a buffer object to back this uniform buffer
|
||||
* (GL_UNIFORM_BLOCK_DATA_SIZE).
|
||||
*/
|
||||
GLuint UniformBufferSize;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2338,6 +2360,18 @@ struct gl_shader_program
|
||||
unsigned NumUserUniformStorage;
|
||||
struct gl_uniform_storage *UniformStorage;
|
||||
|
||||
struct gl_uniform_block *UniformBlocks;
|
||||
unsigned NumUniformBlocks;
|
||||
|
||||
/**
|
||||
* Indices into the _LinkedShaders's UniformBlocks[] array for each stage
|
||||
* they're used in, or -1.
|
||||
*
|
||||
* This is used to maintain the Binding values of the stage's UniformBlocks[]
|
||||
* and to answer the GL_UNIFORM_BLOCK_REFERENCED_BY_*_SHADER queries.
|
||||
*/
|
||||
int *UniformBlockStageIndex[MESA_SHADER_TYPES];
|
||||
|
||||
/**
|
||||
* Map of active uniform names to locations
|
||||
*
|
||||
|
@@ -3115,6 +3115,12 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
|
||||
}
|
||||
}
|
||||
|
||||
if (shader->UniformBlocks)
|
||||
ralloc_free(shader->UniformBlocks);
|
||||
shader->NumUniformBlocks = state->num_uniform_blocks;
|
||||
shader->UniformBlocks = state->uniform_blocks;
|
||||
ralloc_steal(shader, shader->UniformBlocks);
|
||||
|
||||
/* Retain any live IR, but trash the rest. */
|
||||
reparent_ir(shader->ir, shader->ir);
|
||||
|
||||
|
Reference in New Issue
Block a user