glsl: fully split apart buffer block arrays

With this change we create the UBO and SSBO arrays separately from the
beginning rather than putting them into a combined array and splitting
it apart later.

A bug is with UBO and SSBO stage reference querying is also fixed as
we now use the block index to lookup the references in the separate arrays
not the combined buffer block array.

Reviewed-by: Samuel Iglesias Gonsálvez <siglesias@igalia.com>
This commit is contained in:
Timothy Arceri
2016-04-03 12:44:33 +10:00
parent 506b561ba7
commit f1293b2f9b
11 changed files with 271 additions and 297 deletions

View File

@@ -291,13 +291,105 @@ resize_block_array(const glsl_type *type,
} }
} }
unsigned static void
create_buffer_blocks(void *mem_ctx, struct gl_context *ctx,
struct gl_shader_program *prog,
struct gl_uniform_block **out_blks, unsigned num_blocks,
struct hash_table *block_hash, unsigned num_variables,
bool create_ubo_blocks)
{
if (num_blocks == 0) {
assert(num_variables == 0);
return;
}
assert(num_variables != 0);
/* Allocate storage to hold all of the information related to uniform
* blocks that can be queried through the API.
*/
struct gl_uniform_block *blocks = ralloc_array(mem_ctx, gl_uniform_block, num_blocks);
gl_uniform_buffer_variable *variables =
ralloc_array(blocks, gl_uniform_buffer_variable, num_variables);
/* Add each variable from each uniform block to the API tracking
* structures.
*/
ubo_visitor parcel(blocks, variables, num_variables);
STATIC_ASSERT(unsigned(GLSL_INTERFACE_PACKING_STD140)
== unsigned(ubo_packing_std140));
STATIC_ASSERT(unsigned(GLSL_INTERFACE_PACKING_SHARED)
== unsigned(ubo_packing_shared));
STATIC_ASSERT(unsigned(GLSL_INTERFACE_PACKING_PACKED)
== unsigned(ubo_packing_packed));
STATIC_ASSERT(unsigned(GLSL_INTERFACE_PACKING_STD430)
== unsigned(ubo_packing_std430));
unsigned i = 0;
struct hash_entry *entry;
hash_table_foreach (block_hash, entry) {
const struct link_uniform_block_active *const b =
(const struct link_uniform_block_active *) entry->data;
const glsl_type *block_type = b->type;
if ((create_ubo_blocks && !b->is_shader_storage) ||
(!create_ubo_blocks && b->is_shader_storage)) {
if (b->array != NULL) {
unsigned binding_offset = 0;
char *name = ralloc_strdup(NULL,
block_type->without_array()->name);
size_t name_length = strlen(name);
assert(b->has_instance_name);
process_block_array(b->array, &name, name_length, blocks, &parcel,
variables, b, &i, &binding_offset, ctx, prog);
ralloc_free(name);
} else {
blocks[i].Name = ralloc_strdup(blocks, block_type->name);
blocks[i].Uniforms = &variables[parcel.index];
blocks[i].Binding = (b->has_binding) ? b->binding : 0;
blocks[i].UniformBufferSize = 0;
blocks[i]._Packing =
gl_uniform_block_packing(block_type->interface_packing);
parcel.process(block_type,
b->has_instance_name ? block_type->name : "");
blocks[i].UniformBufferSize = parcel.buffer_size;
/* Check SSBO size is lower than maximum supported size for SSBO
*/
if (b->is_shader_storage &&
parcel.buffer_size > ctx->Const.MaxShaderStorageBlockSize) {
linker_error(prog, "shader storage block `%s' has size %d, "
"which is larger than than the maximum allowed (%d)",
block_type->name, parcel.buffer_size,
ctx->Const.MaxShaderStorageBlockSize);
}
blocks[i].NumUniforms = (unsigned)(ptrdiff_t)
(&variables[parcel.index] - blocks[i].Uniforms);
i++;
}
}
}
*out_blks = blocks;
assert(parcel.index == num_variables);
}
void
link_uniform_blocks(void *mem_ctx, link_uniform_blocks(void *mem_ctx,
struct gl_context *ctx, struct gl_context *ctx,
struct gl_shader_program *prog, struct gl_shader_program *prog,
struct gl_shader **shader_list, struct gl_shader **shader_list,
unsigned num_shaders, unsigned num_shaders,
struct gl_uniform_block **blocks_ret) struct gl_uniform_block **ubo_blocks,
unsigned *num_ubo_blocks,
struct gl_uniform_block **ssbo_blocks,
unsigned *num_ssbo_blocks)
{ {
/* This hash table will track all of the uniform blocks that have been /* This hash table will track all of the uniform blocks that have been
* encountered. Since blocks with the same block-name must be the same, * encountered. Since blocks with the same block-name must be the same,
@@ -310,7 +402,7 @@ link_uniform_blocks(void *mem_ctx,
if (block_hash == NULL) { if (block_hash == NULL) {
_mesa_error_no_memory(__func__); _mesa_error_no_memory(__func__);
linker_error(prog, "out of memory\n"); linker_error(prog, "out of memory\n");
return 0; return;
} }
/* Determine which uniform blocks are active. /* Determine which uniform blocks are active.
@@ -323,8 +415,8 @@ link_uniform_blocks(void *mem_ctx,
/* Count the number of active uniform blocks. Count the total number of /* Count the number of active uniform blocks. Count the total number of
* active slots in those uniform blocks. * active slots in those uniform blocks.
*/ */
unsigned num_blocks = 0; unsigned num_ubo_variables = 0;
unsigned num_variables = 0; unsigned num_ssbo_variables = 0;
count_block_size block_size; count_block_size block_size;
struct hash_entry *entry; struct hash_entry *entry;
@@ -346,97 +438,31 @@ link_uniform_blocks(void *mem_ctx,
if (b->array != NULL) { if (b->array != NULL) {
unsigned aoa_size = b->type->arrays_of_arrays_size(); unsigned aoa_size = b->type->arrays_of_arrays_size();
num_blocks += aoa_size; if (b->is_shader_storage) {
num_variables += aoa_size * block_size.num_active_uniforms; *num_ssbo_blocks += aoa_size;
num_ssbo_variables += aoa_size * block_size.num_active_uniforms;
} else { } else {
num_blocks++; *num_ubo_blocks += aoa_size;
num_variables += block_size.num_active_uniforms; num_ubo_variables += aoa_size * block_size.num_active_uniforms;
} }
}
if (num_blocks == 0) {
assert(num_variables == 0);
_mesa_hash_table_destroy(block_hash, NULL);
return 0;
}
assert(num_variables != 0);
/* Allocate storage to hold all of the informatation related to uniform
* blocks that can be queried through the API.
*/
gl_uniform_block *blocks =
ralloc_array(mem_ctx, gl_uniform_block, num_blocks);
gl_uniform_buffer_variable *variables =
ralloc_array(blocks, gl_uniform_buffer_variable, num_variables);
/* Add each variable from each uniform block to the API tracking
* structures.
*/
unsigned i = 0;
ubo_visitor parcel(blocks, variables, num_variables);
STATIC_ASSERT(unsigned(GLSL_INTERFACE_PACKING_STD140)
== unsigned(ubo_packing_std140));
STATIC_ASSERT(unsigned(GLSL_INTERFACE_PACKING_SHARED)
== unsigned(ubo_packing_shared));
STATIC_ASSERT(unsigned(GLSL_INTERFACE_PACKING_PACKED)
== unsigned(ubo_packing_packed));
STATIC_ASSERT(unsigned(GLSL_INTERFACE_PACKING_STD430)
== unsigned(ubo_packing_std430));
hash_table_foreach (block_hash, entry) {
const struct link_uniform_block_active *const b =
(const struct link_uniform_block_active *) entry->data;
const glsl_type *block_type = b->type;
if (b->array != NULL) {
unsigned binding_offset = 0;
char *name = ralloc_strdup(NULL, block_type->without_array()->name);
size_t name_length = strlen(name);
assert(b->has_instance_name);
process_block_array(b->array, &name, name_length, blocks, &parcel,
variables, b, &i, &binding_offset, ctx, prog);
ralloc_free(name);
} else { } else {
blocks[i].Name = ralloc_strdup(blocks, block_type->name); if (b->is_shader_storage) {
blocks[i].Uniforms = &variables[parcel.index]; (*num_ssbo_blocks)++;
blocks[i].Binding = (b->has_binding) ? b->binding : 0; num_ssbo_variables += block_size.num_active_uniforms;
blocks[i].UniformBufferSize = 0; } else {
blocks[i]._Packing = (*num_ubo_blocks)++;
gl_uniform_block_packing(block_type->interface_packing); num_ubo_variables += block_size.num_active_uniforms;
parcel.process(block_type,
b->has_instance_name ? block_type->name : "");
blocks[i].UniformBufferSize = parcel.buffer_size;
/* Check SSBO size is lower than maximum supported size for SSBO */
if (b->is_shader_storage &&
parcel.buffer_size > ctx->Const.MaxShaderStorageBlockSize) {
linker_error(prog, "shader storage block `%s' has size %d, "
"which is larger than than the maximum allowed (%d)",
block_type->name,
parcel.buffer_size,
ctx->Const.MaxShaderStorageBlockSize);
}
blocks[i].NumUniforms =
(unsigned)(ptrdiff_t)(&variables[parcel.index] - blocks[i].Uniforms);
blocks[i].IsShaderStorage = b->is_shader_storage;
i++;
} }
} }
assert(parcel.index == num_variables); }
create_buffer_blocks(mem_ctx, ctx, prog, ubo_blocks, *num_ubo_blocks,
block_hash, num_ubo_variables, true);
create_buffer_blocks(mem_ctx, ctx, prog, ssbo_blocks, *num_ssbo_blocks,
block_hash, num_ssbo_variables, false);
_mesa_hash_table_destroy(block_hash, NULL); _mesa_hash_table_destroy(block_hash, NULL);
*blocks_ret = blocks;
return num_blocks;
} }
bool bool

View File

@@ -154,11 +154,17 @@ set_opaque_binding(void *mem_ctx, gl_shader_program *prog,
} }
void void
set_block_binding(gl_shader_program *prog, const char *block_name, int binding) set_block_binding(gl_shader_program *prog, const char *block_name,
unsigned mode, int binding)
{ {
for (unsigned i = 0; i < prog->NumBufferInterfaceBlocks; i++) { unsigned num_blocks = mode == ir_var_uniform ? prog->NumUniformBlocks :
if (!strcmp(prog->BufferInterfaceBlocks[i].Name, block_name)) { prog->NumShaderStorageBlocks;
prog->BufferInterfaceBlocks[i].Binding = binding; struct gl_uniform_block *blks = mode == ir_var_uniform ?
prog->UniformBlocks : prog->ShaderStorageBlocks;
for (unsigned i = 0; i < num_blocks; i++) {
if (!strcmp(blks[i].Name, block_name)) {
blks[i].Binding = binding;
return; return;
} }
} }
@@ -308,11 +314,12 @@ link_set_uniform_initializers(struct gl_shader_program *prog,
* each subsequent element takes the next consecutive * each subsequent element takes the next consecutive
* uniform block binding point." * uniform block binding point."
*/ */
linker::set_block_binding(prog, name, linker::set_block_binding(prog, name, var->data.mode,
var->data.binding + i); var->data.binding + i);
} }
} else { } else {
linker::set_block_binding(prog, iface_type->name, linker::set_block_binding(prog, iface_type->name,
var->data.mode,
var->data.binding); var->data.binding);
} }
} else if (type->contains_atomic()) { } else if (type->contains_atomic()) {

View File

@@ -462,7 +462,7 @@ public:
buffer_block_index = -1; buffer_block_index = -1;
if (var->is_in_buffer_block()) { if (var->is_in_buffer_block()) {
struct gl_uniform_block **blks = var->is_in_shader_storage_block() ? struct gl_uniform_block *blks = var->is_in_shader_storage_block() ?
prog->ShaderStorageBlocks : prog->UniformBlocks; prog->ShaderStorageBlocks : prog->UniformBlocks;
unsigned num_blks = var->is_in_shader_storage_block() ? unsigned num_blks = var->is_in_shader_storage_block() ?
prog->NumShaderStorageBlocks : prog->NumUniformBlocks; prog->NumShaderStorageBlocks : prog->NumUniformBlocks;
@@ -471,15 +471,15 @@ public:
unsigned l = strlen(var->get_interface_type()->name); unsigned l = strlen(var->get_interface_type()->name);
for (unsigned i = 0; i < num_blks; i++) { for (unsigned i = 0; i < num_blks; i++) {
if (strncmp(var->get_interface_type()->name, blks[i]->Name, l) if (strncmp(var->get_interface_type()->name, blks[i].Name, l)
== 0 && blks[i]->Name[l] == '[') { == 0 && blks[i].Name[l] == '[') {
buffer_block_index = i; buffer_block_index = i;
break; break;
} }
} }
} else { } else {
for (unsigned i = 0; i < num_blks; i++) { for (unsigned i = 0; i < num_blks; i++) {
if (strcmp(var->get_interface_type()->name, blks[i]->Name) == if (strcmp(var->get_interface_type()->name, blks[i].Name) ==
0) { 0) {
buffer_block_index = i; buffer_block_index = i;
break; break;
@@ -500,7 +500,7 @@ public:
var->get_interface_type()->name); var->get_interface_type()->name);
} else { } else {
const struct gl_uniform_block *const block = const struct gl_uniform_block *const block =
blks[buffer_block_index]; &blks[buffer_block_index];
assert(var->data.location != -1); assert(var->data.location != -1);
@@ -960,11 +960,16 @@ link_update_uniform_buffer_variables(struct gl_shader *shader)
sentinel = '['; sentinel = '[';
} }
unsigned num_blocks = var->data.mode == ir_var_uniform ?
shader->NumUniformBlocks : shader->NumShaderStorageBlocks;
struct gl_uniform_block **blks = var->data.mode == ir_var_uniform ?
shader->UniformBlocks : shader->ShaderStorageBlocks;
const unsigned l = strlen(var->name); const unsigned l = strlen(var->name);
for (unsigned i = 0; i < shader->NumBufferInterfaceBlocks; i++) { for (unsigned i = 0; i < num_blocks; i++) {
for (unsigned j = 0; j < shader->BufferInterfaceBlocks[i]->NumUniforms; j++) { for (unsigned j = 0; j < blks[i]->NumUniforms; j++) {
if (sentinel) { if (sentinel) {
const char *begin = shader->BufferInterfaceBlocks[i]->Uniforms[j].Name; const char *begin = blks[i]->Uniforms[j].Name;
const char *end = strchr(begin, sentinel); const char *end = strchr(begin, sentinel);
if (end == NULL) if (end == NULL)
@@ -978,8 +983,7 @@ link_update_uniform_buffer_variables(struct gl_shader *shader)
var->data.location = j; var->data.location = j;
break; break;
} }
} else if (!strcmp(var->name, } else if (!strcmp(var->name, blks[i]->Uniforms[j].Name)) {
shader->BufferInterfaceBlocks[i]->Uniforms[j].Name)) {
found = true; found = true;
var->data.location = j; var->data.location = j;
break; break;
@@ -1104,11 +1108,9 @@ link_assign_uniform_locations(struct gl_shader_program *prog,
sh->num_uniform_components = uniform_size.num_shader_uniform_components; sh->num_uniform_components = uniform_size.num_shader_uniform_components;
sh->num_combined_uniform_components = sh->num_uniform_components; sh->num_combined_uniform_components = sh->num_uniform_components;
for (unsigned i = 0; i < sh->NumBufferInterfaceBlocks; i++) { for (unsigned i = 0; i < sh->NumUniformBlocks; i++) {
if (!sh->BufferInterfaceBlocks[i]->IsShaderStorage) {
sh->num_combined_uniform_components += sh->num_combined_uniform_components +=
sh->BufferInterfaceBlocks[i]->UniformBufferSize / 4; sh->UniformBlocks[i]->UniformBufferSize / 4;
}
} }
} }

View File

@@ -1165,39 +1165,58 @@ cross_validate_uniforms(struct gl_shader_program *prog)
} }
/** /**
* Accumulates the array of prog->BufferInterfaceBlocks and checks that all * Accumulates the array of buffer blocks and checks that all definitions of
* definitons of blocks agree on their contents. * blocks agree on their contents.
*/ */
static bool static bool
interstage_cross_validate_uniform_blocks(struct gl_shader_program *prog) interstage_cross_validate_uniform_blocks(struct gl_shader_program *prog,
bool validate_ssbo)
{ {
int *InterfaceBlockStageIndex[MESA_SHADER_STAGES]; int *InterfaceBlockStageIndex[MESA_SHADER_STAGES];
struct gl_uniform_block *blks = NULL;
unsigned *num_blks = validate_ssbo ? &prog->NumShaderStorageBlocks :
&prog->NumUniformBlocks;
unsigned max_num_uniform_blocks = 0; unsigned max_num_buffer_blocks = 0;
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
if (prog->_LinkedShaders[i]) if (prog->_LinkedShaders[i]) {
max_num_uniform_blocks += prog->_LinkedShaders[i]->NumBufferInterfaceBlocks; if (validate_ssbo) {
max_num_buffer_blocks +=
prog->_LinkedShaders[i]->NumShaderStorageBlocks;
} else {
max_num_buffer_blocks +=
prog->_LinkedShaders[i]->NumUniformBlocks;
}
}
} }
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
struct gl_shader *sh = prog->_LinkedShaders[i]; struct gl_shader *sh = prog->_LinkedShaders[i];
InterfaceBlockStageIndex[i] = new int[max_num_uniform_blocks]; InterfaceBlockStageIndex[i] = new int[max_num_buffer_blocks];
for (unsigned int j = 0; j < max_num_uniform_blocks; j++) for (unsigned int j = 0; j < max_num_buffer_blocks; j++)
InterfaceBlockStageIndex[i][j] = -1; InterfaceBlockStageIndex[i][j] = -1;
if (sh == NULL) if (sh == NULL)
continue; continue;
for (unsigned int j = 0; j < sh->NumBufferInterfaceBlocks; j++) { unsigned sh_num_blocks;
int index = link_cross_validate_uniform_block(prog, struct gl_uniform_block **sh_blks;
&prog->BufferInterfaceBlocks, if (validate_ssbo) {
&prog->NumBufferInterfaceBlocks, sh_num_blocks = prog->_LinkedShaders[i]->NumShaderStorageBlocks;
sh->BufferInterfaceBlocks[j]); sh_blks = sh->ShaderStorageBlocks;
} else {
sh_num_blocks = prog->_LinkedShaders[i]->NumUniformBlocks;
sh_blks = sh->UniformBlocks;
}
for (unsigned int j = 0; j < sh_num_blocks; j++) {
int index = link_cross_validate_uniform_block(prog, &blks, num_blks,
sh_blks[j]);
if (index == -1) { if (index == -1) {
linker_error(prog, "uniform block `%s' has mismatching definitions\n", linker_error(prog, "buffer block `%s' has mismatching "
sh->BufferInterfaceBlocks[j]->Name); "definitions\n", sh_blks[j]->Name);
for (unsigned k = 0; k <= i; k++) { for (unsigned k = 0; k <= i; k++) {
delete[] InterfaceBlockStageIndex[k]; delete[] InterfaceBlockStageIndex[k];
@@ -1213,16 +1232,18 @@ interstage_cross_validate_uniform_blocks(struct gl_shader_program *prog)
* FIXME: We should be able to free the per stage blocks here. * FIXME: We should be able to free the per stage blocks here.
*/ */
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
for (unsigned j = 0; j < prog->NumBufferInterfaceBlocks; j++) { for (unsigned j = 0; j < *num_blks; j++) {
int stage_index = InterfaceBlockStageIndex[i][j]; int stage_index = InterfaceBlockStageIndex[i][j];
if (stage_index != -1) { if (stage_index != -1) {
struct gl_shader *sh = prog->_LinkedShaders[i]; struct gl_shader *sh = prog->_LinkedShaders[i];
prog->BufferInterfaceBlocks[j].stageref |= (1 << i); blks[j].stageref |= (1 << i);
sh->BufferInterfaceBlocks[stage_index] = struct gl_uniform_block **sh_blks = validate_ssbo ?
&prog->BufferInterfaceBlocks[j]; sh->ShaderStorageBlocks : sh->UniformBlocks;
sh_blks[stage_index] = &blks[j];
} }
} }
} }
@@ -1231,6 +1252,11 @@ interstage_cross_validate_uniform_blocks(struct gl_shader_program *prog)
delete[] InterfaceBlockStageIndex[i]; delete[] InterfaceBlockStageIndex[i];
} }
if (validate_ssbo)
prog->ShaderStorageBlocks = blks;
else
prog->UniformBlocks = blks;
return true; return true;
} }
@@ -2074,7 +2100,10 @@ link_intrastage_shaders(void *mem_ctx,
struct gl_shader **shader_list, struct gl_shader **shader_list,
unsigned num_shaders) unsigned num_shaders)
{ {
struct gl_uniform_block *uniform_blocks = NULL; struct gl_uniform_block *ubo_blocks = NULL;
struct gl_uniform_block *ssbo_blocks = NULL;
unsigned num_ubo_blocks = 0;
unsigned num_ssbo_blocks = 0;
/* Check that global variables defined in multiple shaders are consistent. /* Check that global variables defined in multiple shaders are consistent.
*/ */
@@ -2090,9 +2119,10 @@ link_intrastage_shaders(void *mem_ctx,
return NULL; return NULL;
/* Link up uniform blocks defined within this stage. */ /* Link up uniform blocks defined within this stage. */
const unsigned num_uniform_blocks =
link_uniform_blocks(mem_ctx, ctx, prog, shader_list, num_shaders, link_uniform_blocks(mem_ctx, ctx, prog, shader_list, num_shaders,
&uniform_blocks); &ubo_blocks, &num_ubo_blocks, &ssbo_blocks,
&num_ssbo_blocks);
if (!prog->LinkStatus) if (!prog->LinkStatus)
return NULL; return NULL;
@@ -2159,15 +2189,23 @@ link_intrastage_shaders(void *mem_ctx,
linked->ir = new(linked) exec_list; linked->ir = new(linked) exec_list;
clone_ir_list(mem_ctx, linked->ir, main->ir); clone_ir_list(mem_ctx, linked->ir, main->ir);
linked->BufferInterfaceBlocks = /* Copy ubo blocks to linked shader list */
ralloc_array(linked, gl_uniform_block *, num_uniform_blocks); linked->UniformBlocks =
ralloc_array(linked, gl_uniform_block *, num_ubo_blocks);
ralloc_steal(linked, uniform_blocks); ralloc_steal(linked, ubo_blocks);
for (unsigned i = 0; i < num_uniform_blocks; i++) { for (unsigned i = 0; i < num_ubo_blocks; i++) {
linked->BufferInterfaceBlocks[i] = &uniform_blocks[i]; linked->UniformBlocks[i] = &ubo_blocks[i];
} }
linked->NumUniformBlocks = num_ubo_blocks;
linked->NumBufferInterfaceBlocks = num_uniform_blocks; /* Copy ssbo blocks to linked shader list */
linked->ShaderStorageBlocks =
ralloc_array(linked, gl_uniform_block *, num_ssbo_blocks);
ralloc_steal(linked, ssbo_blocks);
for (unsigned i = 0; i < num_ssbo_blocks; i++) {
linked->ShaderStorageBlocks[i] = &ssbo_blocks[i];
}
linked->NumShaderStorageBlocks = num_ssbo_blocks;
link_fs_input_layout_qualifiers(prog, linked, shader_list, num_shaders); link_fs_input_layout_qualifiers(prog, linked, shader_list, num_shaders);
link_tcs_out_layout_qualifiers(prog, linked, shader_list, num_shaders); link_tcs_out_layout_qualifiers(prog, linked, shader_list, num_shaders);
@@ -2973,21 +3011,22 @@ check_resources(struct gl_context *ctx, struct gl_shader_program *prog)
ctx->Const.MaxCombinedShaderStorageBlocks); ctx->Const.MaxCombinedShaderStorageBlocks);
} }
for (unsigned i = 0; i < prog->NumBufferInterfaceBlocks; i++) { for (unsigned i = 0; i < prog->NumUniformBlocks; i++) {
/* Don't check SSBOs for Uniform Block Size */ if (prog->UniformBlocks[i].UniformBufferSize >
if (!prog->BufferInterfaceBlocks[i].IsShaderStorage && ctx->Const.MaxUniformBlockSize) {
prog->BufferInterfaceBlocks[i].UniformBufferSize > ctx->Const.MaxUniformBlockSize) {
linker_error(prog, "Uniform block %s too big (%d/%d)\n", linker_error(prog, "Uniform block %s too big (%d/%d)\n",
prog->BufferInterfaceBlocks[i].Name, prog->UniformBlocks[i].Name,
prog->BufferInterfaceBlocks[i].UniformBufferSize, prog->UniformBlocks[i].UniformBufferSize,
ctx->Const.MaxUniformBlockSize); ctx->Const.MaxUniformBlockSize);
} }
}
if (prog->BufferInterfaceBlocks[i].IsShaderStorage && for (unsigned i = 0; i < prog->NumShaderStorageBlocks; i++) {
prog->BufferInterfaceBlocks[i].UniformBufferSize > ctx->Const.MaxShaderStorageBlockSize) { if (prog->ShaderStorageBlocks[i].UniformBufferSize >
ctx->Const.MaxShaderStorageBlockSize) {
linker_error(prog, "Shader storage block %s too big (%d/%d)\n", linker_error(prog, "Shader storage block %s too big (%d/%d)\n",
prog->BufferInterfaceBlocks[i].Name, prog->ShaderStorageBlocks[i].Name,
prog->BufferInterfaceBlocks[i].UniformBufferSize, prog->ShaderStorageBlocks[i].UniformBufferSize,
ctx->Const.MaxShaderStorageBlockSize); ctx->Const.MaxShaderStorageBlockSize);
} }
} }
@@ -3295,8 +3334,8 @@ should_add_buffer_variable(struct gl_shader_program *shProg,
if (type != GL_BUFFER_VARIABLE) if (type != GL_BUFFER_VARIABLE)
return true; return true;
for (unsigned i = 0; i < shProg->NumBufferInterfaceBlocks; i++) { for (unsigned i = 0; i < shProg->NumShaderStorageBlocks; i++) {
const char *block_name = shProg->BufferInterfaceBlocks[i].Name; const char *block_name = shProg->ShaderStorageBlocks[i].Name;
block_name_len = strlen(block_name); block_name_len = strlen(block_name);
const char *block_square_bracket = strchr(block_name, '['); const char *block_square_bracket = strchr(block_name, '[');
@@ -3805,8 +3844,8 @@ calculate_array_size_and_stride(struct gl_shader_program *shProg,
char *var_name = get_top_level_name(uni->name); char *var_name = get_top_level_name(uni->name);
char *interface_name = char *interface_name =
get_top_level_name(uni->is_shader_storage ? get_top_level_name(uni->is_shader_storage ?
shProg->ShaderStorageBlocks[block_index]->Name : shProg->ShaderStorageBlocks[block_index].Name :
shProg->UniformBlocks[block_index]->Name); shProg->UniformBlocks[block_index].Name);
if (strcmp(var_name, interface_name) == 0) { if (strcmp(var_name, interface_name) == 0) {
/* Deal with instanced array of SSBOs */ /* Deal with instanced array of SSBOs */
@@ -3947,8 +3986,8 @@ build_program_resource_list(struct gl_context *ctx,
int block_index = shProg->UniformStorage[i].block_index; int block_index = shProg->UniformStorage[i].block_index;
if (block_index != -1) { if (block_index != -1) {
stageref |= is_shader_storage ? stageref |= is_shader_storage ?
shProg->ShaderStorageBlocks[block_index]->stageref : shProg->ShaderStorageBlocks[block_index].stageref :
shProg->UniformBlocks[block_index]->stageref; shProg->UniformBlocks[block_index].stageref;
} }
GLenum type = is_shader_storage ? GL_BUFFER_VARIABLE : GL_UNIFORM; GLenum type = is_shader_storage ? GL_BUFFER_VARIABLE : GL_UNIFORM;
@@ -3965,12 +4004,17 @@ build_program_resource_list(struct gl_context *ctx,
return; return;
} }
/* Add program uniform blocks and shader storage blocks. */ /* Add program uniform blocks. */
for (unsigned i = 0; i < shProg->NumBufferInterfaceBlocks; i++) { for (unsigned i = 0; i < shProg->NumUniformBlocks; i++) {
bool is_shader_storage = shProg->BufferInterfaceBlocks[i].IsShaderStorage; if (!add_program_resource(shProg, GL_UNIFORM_BLOCK,
GLenum type = is_shader_storage ? GL_SHADER_STORAGE_BLOCK : GL_UNIFORM_BLOCK; &shProg->UniformBlocks[i], 0))
if (!add_program_resource(shProg, type, return;
&shProg->BufferInterfaceBlocks[i], 0)) }
/* Add program shader storage blocks. */
for (unsigned i = 0; i < shProg->NumShaderStorageBlocks; i++) {
if (!add_program_resource(shProg, GL_SHADER_STORAGE_BLOCK,
&shProg->ShaderStorageBlocks[i], 0))
return; return;
} }
@@ -4115,49 +4159,6 @@ link_assign_subroutine_types(struct gl_shader_program *prog)
} }
} }
static void
split_ubos_and_ssbos(void *mem_ctx,
struct gl_uniform_block **s_blks,
struct gl_uniform_block *p_blks,
unsigned num_blocks,
struct gl_uniform_block ***ubos,
unsigned *num_ubos,
struct gl_uniform_block ***ssbos,
unsigned *num_ssbos)
{
unsigned num_ubo_blocks = 0;
unsigned num_ssbo_blocks = 0;
/* Are we spliting the list of blocks for the shader or the program */
bool is_shader = p_blks == NULL;
for (unsigned i = 0; i < num_blocks; i++) {
if (is_shader ? s_blks[i]->IsShaderStorage : p_blks[i].IsShaderStorage)
num_ssbo_blocks++;
else
num_ubo_blocks++;
}
*ubos = ralloc_array(mem_ctx, gl_uniform_block *, num_ubo_blocks);
*num_ubos = 0;
*ssbos = ralloc_array(mem_ctx, gl_uniform_block *, num_ssbo_blocks);
*num_ssbos = 0;
for (unsigned i = 0; i < num_blocks; i++) {
struct gl_uniform_block *blk = is_shader ? s_blks[i] : &p_blks[i];
if (blk->IsShaderStorage) {
(*ssbos)[*num_ssbos] = blk;
(*num_ssbos)++;
} else {
(*ubos)[*num_ubos] = blk;
(*num_ubos)++;
}
}
assert(*num_ubos + *num_ssbos == num_blocks);
}
static void static void
set_always_active_io(exec_list *ir, ir_variable_mode io_mode) set_always_active_io(exec_list *ir, ir_variable_mode io_mode)
{ {
@@ -4498,7 +4499,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
if (prog->SeparateShader) if (prog->SeparateShader)
disable_varying_optimizations_for_sso(prog); disable_varying_optimizations_for_sso(prog);
if (!interstage_cross_validate_uniform_blocks(prog)) /* Process UBOs */
if (!interstage_cross_validate_uniform_blocks(prog, false))
goto done;
/* Process SSBOs */
if (!interstage_cross_validate_uniform_blocks(prog, true))
goto done; goto done;
/* Do common optimization before assigning storage for attributes, /* Do common optimization before assigning storage for attributes,
@@ -4695,33 +4701,6 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
has_xfb_qualifiers)) has_xfb_qualifiers))
goto done; goto done;
/* Split BufferInterfaceBlocks into UniformBlocks and ShaderStorageBlocks
* for gl_shader_program and gl_shader, so that drivers that need separate
* index spaces for each set can have that.
*/
for (unsigned i = MESA_SHADER_VERTEX; i < MESA_SHADER_STAGES; i++) {
if (prog->_LinkedShaders[i] != NULL) {
gl_shader *sh = prog->_LinkedShaders[i];
split_ubos_and_ssbos(sh,
sh->BufferInterfaceBlocks,
NULL,
sh->NumBufferInterfaceBlocks,
&sh->UniformBlocks,
&sh->NumUniformBlocks,
&sh->ShaderStorageBlocks,
&sh->NumShaderStorageBlocks);
}
}
split_ubos_and_ssbos(prog,
NULL,
prog->BufferInterfaceBlocks,
prog->NumBufferInterfaceBlocks,
&prog->UniformBlocks,
&prog->NumUniformBlocks,
&prog->ShaderStorageBlocks,
&prog->NumShaderStorageBlocks);
update_array_sizes(prog); update_array_sizes(prog);
link_assign_uniform_locations(prog, ctx->Const.UniformBooleanTrue, link_assign_uniform_locations(prog, ctx->Const.UniformBooleanTrue,
num_explicit_uniform_locs, num_explicit_uniform_locs,

View File

@@ -53,13 +53,16 @@ extern bool
link_uniform_blocks_are_compatible(const gl_uniform_block *a, link_uniform_blocks_are_compatible(const gl_uniform_block *a,
const gl_uniform_block *b); const gl_uniform_block *b);
extern unsigned extern void
link_uniform_blocks(void *mem_ctx, link_uniform_blocks(void *mem_ctx,
struct gl_context *ctx, struct gl_context *ctx,
struct gl_shader_program *prog, struct gl_shader_program *prog,
struct gl_shader **shader_list, struct gl_shader **shader_list,
unsigned num_shaders, unsigned num_shaders,
struct gl_uniform_block **blocks_ret); struct gl_uniform_block **ubo_blocks,
unsigned *num_ubo_blocks,
struct gl_uniform_block **ssbo_blocks,
unsigned *num_ssbo_blocks);
bool bool
validate_intrastage_arrays(struct gl_shader_program *prog, validate_intrastage_arrays(struct gl_shader_program *prog,

View File

@@ -105,10 +105,6 @@ _mesa_clear_shader_program_data(struct gl_shader_program *shProg)
ralloc_free(shProg->InfoLog); ralloc_free(shProg->InfoLog);
shProg->InfoLog = ralloc_strdup(shProg, ""); shProg->InfoLog = ralloc_strdup(shProg, "");
ralloc_free(shProg->BufferInterfaceBlocks);
shProg->BufferInterfaceBlocks = NULL;
shProg->NumBufferInterfaceBlocks = 0;
ralloc_free(shProg->UniformBlocks); ralloc_free(shProg->UniformBlocks);
shProg->UniformBlocks = NULL; shProg->UniformBlocks = NULL;
shProg->NumUniformBlocks = 0; shProg->NumUniformBlocks = 0;

View File

@@ -2295,30 +2295,6 @@ struct gl_shader
*/ */
unsigned num_combined_uniform_components; unsigned num_combined_uniform_components;
/**
* This shader's uniform/ssbo block information.
*
* These fields are only set post-linking.
*
* BufferInterfaceBlocks is a list containing both UBOs and SSBOs. This is
* useful during the linking process so that we don't have to handle SSBOs
* specifically.
*
* UniformBlocks is a list of UBOs. This is useful for backends that need
* or prefer to see separate index spaces for UBOS and SSBOs like the GL
* API specifies.
*
* ShaderStorageBlocks is a list of SSBOs. This is useful for backends that
* need or prefer to see separate index spaces for UBOS and SSBOs like the
* GL API specifies.
*
* UniformBlocks and ShaderStorageBlocks only have pointers into
* BufferInterfaceBlocks so the actual resource information is not
* duplicated.
*/
unsigned NumBufferInterfaceBlocks;
struct gl_uniform_block **BufferInterfaceBlocks;
unsigned NumUniformBlocks; unsigned NumUniformBlocks;
struct gl_uniform_block **UniformBlocks; struct gl_uniform_block **UniformBlocks;
@@ -2804,33 +2780,11 @@ struct gl_shader_program
*/ */
unsigned LastClipDistanceArraySize; unsigned LastClipDistanceArraySize;
/**
* This shader's uniform/ssbo block information.
*
* BufferInterfaceBlocks is a list containing both UBOs and SSBOs. This is
* useful during the linking process so that we don't have to handle SSBOs
* specifically.
*
* UniformBlocks is a list of UBOs. This is useful for backends that need
* or prefer to see separate index spaces for UBOS and SSBOs like the GL
* API specifies.
*
* ShaderStorageBlocks is a list of SSBOs. This is useful for backends that
* need or prefer to see separate index spaces for UBOS and SSBOs like the
* GL API specifies.
*
* UniformBlocks and ShaderStorageBlocks only have pointers into
* BufferInterfaceBlocks so the actual resource information is not
* duplicated and are only set after linking.
*/
unsigned NumBufferInterfaceBlocks;
struct gl_uniform_block *BufferInterfaceBlocks;
unsigned NumUniformBlocks; unsigned NumUniformBlocks;
struct gl_uniform_block **UniformBlocks; struct gl_uniform_block *UniformBlocks;
unsigned NumShaderStorageBlocks; unsigned NumShaderStorageBlocks;
struct gl_uniform_block **ShaderStorageBlocks; struct gl_uniform_block *ShaderStorageBlocks;
/** /**
* Map of active uniform names to locations * Map of active uniform names to locations

View File

@@ -925,8 +925,11 @@ is_resource_referenced(struct gl_shader_program *shProg,
if (res->Type == GL_ATOMIC_COUNTER_BUFFER) if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
return RESOURCE_ATC(res)->StageReferences[stage]; return RESOURCE_ATC(res)->StageReferences[stage];
if (res->Type == GL_UNIFORM_BLOCK || res->Type == GL_SHADER_STORAGE_BLOCK) if (res->Type == GL_UNIFORM_BLOCK)
return shProg->BufferInterfaceBlocks[index].stageref & (1 << stage); return shProg->UniformBlocks[index].stageref & (1 << stage);
if (res->Type == GL_SHADER_STORAGE_BLOCK)
return shProg->ShaderStorageBlocks[index].stageref & (1 << stage);
return res->StageReferences & (1 << stage); return res->StageReferences & (1 << stage);
} }

View File

@@ -727,7 +727,7 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname,
for (i = 0; i < shProg->NumUniformBlocks; i++) { for (i = 0; i < shProg->NumUniformBlocks; i++) {
/* Add one for the terminating NUL character. /* Add one for the terminating NUL character.
*/ */
const GLint len = strlen(shProg->UniformBlocks[i]->Name) + 1; const GLint len = strlen(shProg->UniformBlocks[i].Name) + 1;
if (len > max_len) if (len > max_len)
max_len = len; max_len = len;

View File

@@ -292,9 +292,13 @@ _mesa_clear_shader_program_data(struct gl_shader_program *shProg)
ralloc_free(shProg->InfoLog); ralloc_free(shProg->InfoLog);
shProg->InfoLog = ralloc_strdup(shProg, ""); shProg->InfoLog = ralloc_strdup(shProg, "");
ralloc_free(shProg->BufferInterfaceBlocks); ralloc_free(shProg->UniformBlocks);
shProg->BufferInterfaceBlocks = NULL; shProg->UniformBlocks = NULL;
shProg->NumBufferInterfaceBlocks = 0; shProg->NumUniformBlocks = 0;
ralloc_free(shProg->ShaderStorageBlocks);
shProg->ShaderStorageBlocks = NULL;
shProg->NumShaderStorageBlocks = 0;
ralloc_free(shProg->AtomicBuffers); ralloc_free(shProg->AtomicBuffers);
shProg->AtomicBuffers = NULL; shProg->AtomicBuffers = NULL;

View File

@@ -1016,13 +1016,13 @@ _mesa_UniformBlockBinding(GLuint program,
return; return;
} }
if (shProg->UniformBlocks[uniformBlockIndex]->Binding != if (shProg->UniformBlocks[uniformBlockIndex].Binding !=
uniformBlockBinding) { uniformBlockBinding) {
FLUSH_VERTICES(ctx, 0); FLUSH_VERTICES(ctx, 0);
ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer; ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer;
shProg->UniformBlocks[uniformBlockIndex]->Binding = uniformBlockBinding; shProg->UniformBlocks[uniformBlockIndex].Binding = uniformBlockBinding;
} }
} }
@@ -1059,13 +1059,13 @@ _mesa_ShaderStorageBlockBinding(GLuint program,
return; return;
} }
if (shProg->ShaderStorageBlocks[shaderStorageBlockIndex]->Binding != if (shProg->ShaderStorageBlocks[shaderStorageBlockIndex].Binding !=
shaderStorageBlockBinding) { shaderStorageBlockBinding) {
FLUSH_VERTICES(ctx, 0); FLUSH_VERTICES(ctx, 0);
ctx->NewDriverState |= ctx->DriverFlags.NewShaderStorageBuffer; ctx->NewDriverState |= ctx->DriverFlags.NewShaderStorageBuffer;
shProg->ShaderStorageBlocks[shaderStorageBlockIndex]->Binding = shProg->ShaderStorageBlocks[shaderStorageBlockIndex].Binding =
shaderStorageBlockBinding; shaderStorageBlockBinding;
} }
} }