X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fglsl%2Flink_uniform_blocks.cpp;h=249a767636c27c8cf3f5a8235aac21d23d3e6875;hb=77ea2ada5ae4b72c43598f3faa518526cb36b822;hp=1fc0e2d5109f2d20e57a66982c54990d157b04eb;hpb=52d2b28f7f107fbaff023533a15058055fa73bf0;p=mesa.git diff --git a/src/compiler/glsl/link_uniform_blocks.cpp b/src/compiler/glsl/link_uniform_blocks.cpp index 1fc0e2d5109..249a767636c 100644 --- a/src/compiler/glsl/link_uniform_blocks.cpp +++ b/src/compiler/glsl/link_uniform_blocks.cpp @@ -36,8 +36,8 @@ public: ubo_visitor(void *mem_ctx, gl_uniform_buffer_variable *variables, unsigned num_variables, struct gl_shader_program *prog) : index(0), offset(0), buffer_size(0), variables(variables), - num_variables(num_variables), mem_ctx(mem_ctx), is_array_instance(false), - prog(prog) + num_variables(num_variables), mem_ctx(mem_ctx), + is_array_instance(false), prog(prog) { /* empty */ } @@ -60,17 +60,10 @@ public: struct gl_shader_program *prog; private: - virtual void visit_field(const glsl_type *type, const char *name, - bool row_major) - { - (void) type; - (void) name; - (void) row_major; - assert(!"Should not get here."); - } - virtual void enter_record(const glsl_type *type, const char *, - bool row_major, const enum glsl_interface_packing packing) { + bool row_major, + const enum glsl_interface_packing packing) + { assert(type->is_record()); if (packing == GLSL_INTERFACE_PACKING_STD430) this->offset = glsl_align( @@ -81,15 +74,17 @@ private: } virtual void leave_record(const glsl_type *type, const char *, - bool row_major, const enum glsl_interface_packing packing) { + bool row_major, + const enum glsl_interface_packing packing) + { assert(type->is_record()); /* If this is the last field of a structure, apply rule #9. The - * GL_ARB_uniform_buffer_object spec says: + * ARB_uniform_buffer_object spec says: * - * "The structure may have padding at the end; the base offset of - * the member following the sub-structure is rounded up to the next - * multiple of the base alignment of the structure." + * The structure may have padding at the end; the base offset of the + * member following the sub-structure is rounded up to the next + * multiple of the base alignment of the structure. */ if (packing == GLSL_INTERFACE_PACKING_STD430) this->offset = glsl_align( @@ -138,19 +133,26 @@ private: unsigned alignment = 0; unsigned size = 0; - /* From ARB_program_interface_query: + /* The ARB_program_interface_query spec says: * - * "If the final member of an active shader storage block is array - * with no declared size, the minimum buffer size is computed - * assuming the array was declared as an array with one element." + * If the final member of an active shader storage block is array + * with no declared size, the minimum buffer size is computed + * assuming the array was declared as an array with one element. * - * For that reason, we use the base type of the unsized array to calculate - * its size. We don't need to check if the unsized array is the last member - * of a shader storage block (that check was already done by the parser). + * For that reason, we use the base type of the unsized array to + * calculate its size. We don't need to check if the unsized array is + * the last member of a shader storage block (that check was already + * done by the parser). */ const glsl_type *type_for_size = type; if (type->is_unsized_array()) { - assert(last_field); + if (!last_field) { + linker_error(prog, "unsized array `%s' definition: " + "only last member of a shader storage block " + "can be defined as unsized array", + name); + } + type_for_size = type->without_array(); } @@ -167,15 +169,15 @@ private: this->offset += size; - /* From the GL_ARB_uniform_buffer_object spec: + /* The ARB_uniform_buffer_object spec says: * - * "For uniform blocks laid out according to [std140] rules, the - * minimum buffer object size returned by the - * UNIFORM_BLOCK_DATA_SIZE query is derived by taking the offset of - * the last basic machine unit consumed by the last uniform of the - * uniform block (including any end-of-array or end-of-structure - * padding), adding one, and rounding up to the next multiple of - * the base alignment required for a vec4." + * For uniform blocks laid out according to [std140] rules, the + * minimum buffer object size returned by the UNIFORM_BLOCK_DATA_SIZE + * query is derived by taking the offset of the last basic machine + * unit consumed by the last uniform of the uniform block (including + * any end-of-array or end-of-structure padding), adding one, and + * rounding up to the next multiple of the base alignment required + * for a vec4. */ this->buffer_size = glsl_align(this->offset, 16); } @@ -191,12 +193,13 @@ public: unsigned num_active_uniforms; private: - virtual void visit_field(const glsl_type *type, const char *name, - bool row_major) + virtual void visit_field(const glsl_type * /* type */, + const char * /* name */, + bool /* row_major */, + const glsl_type * /* record_type */, + const enum glsl_interface_packing, + bool /* last_field */) { - (void) type; - (void) name; - (void) row_major; this->num_active_uniforms++; } }; @@ -208,66 +211,97 @@ struct block { bool has_instance_name; }; +static void process_block_array_leaf(const char *name, gl_uniform_block *blocks, + ubo_visitor *parcel, + gl_uniform_buffer_variable *variables, + const struct link_uniform_block_active *const b, + unsigned *block_index, + unsigned *binding_offset, + unsigned linearized_index, + struct gl_context *ctx, + struct gl_shader_program *prog); + +/** + * + * \param first_index Value of \c block_index for the first element of the + * array. + */ static void process_block_array(struct uniform_block_array_elements *ub_array, char **name, size_t name_length, gl_uniform_block *blocks, ubo_visitor *parcel, gl_uniform_buffer_variable *variables, const struct link_uniform_block_active *const b, unsigned *block_index, unsigned *binding_offset, - struct gl_context *ctx, struct gl_shader_program *prog) + struct gl_context *ctx, struct gl_shader_program *prog, + unsigned first_index) { - if (ub_array) { - for (unsigned j = 0; j < ub_array->num_array_elements; j++) { - size_t new_length = name_length; + for (unsigned j = 0; j < ub_array->num_array_elements; j++) { + size_t new_length = name_length; - /* Append the subscript to the current variable name */ - ralloc_asprintf_rewrite_tail(name, &new_length, "[%u]", - ub_array->array_elements[j]); + /* Append the subscript to the current variable name */ + ralloc_asprintf_rewrite_tail(name, &new_length, "[%u]", + ub_array->array_elements[j]); + if (ub_array->array) { process_block_array(ub_array->array, name, new_length, blocks, parcel, variables, b, block_index, - binding_offset, ctx, prog); + binding_offset, ctx, prog, first_index); + } else { + process_block_array_leaf(*name, blocks, + parcel, variables, b, block_index, + binding_offset, *block_index - first_index, + ctx, prog); } - } else { - unsigned i = *block_index; - const glsl_type *type = b->type->without_array(); + } +} - blocks[i].Name = ralloc_strdup(blocks, *name); - blocks[i].Uniforms = &variables[(*parcel).index]; +static void +process_block_array_leaf(const char *name, + gl_uniform_block *blocks, + ubo_visitor *parcel, gl_uniform_buffer_variable *variables, + const struct link_uniform_block_active *const b, + unsigned *block_index, unsigned *binding_offset, + unsigned linearized_index, + struct gl_context *ctx, struct gl_shader_program *prog) +{ + unsigned i = *block_index; + const glsl_type *type = b->type->without_array(); - /* The GL_ARB_shading_language_420pack spec says: - * - * "If the binding identifier is used with a uniform block - * instanced as an array then the first element of the array - * takes the specified block binding and each subsequent - * element takes the next consecutive uniform block binding - * point." - */ - blocks[i].Binding = (b->has_binding) ? b->binding + *binding_offset : 0; + blocks[i].Name = ralloc_strdup(blocks, name); + blocks[i].Uniforms = &variables[(*parcel).index]; - blocks[i].UniformBufferSize = 0; - blocks[i]._Packing = gl_uniform_block_packing(type->interface_packing); - blocks[i]._RowMajor = type->get_interface_row_major(); + /* The ARB_shading_language_420pack spec says: + * + * If the binding identifier is used with a uniform block instanced as + * an array then the first element of the array takes the specified + * block binding and each subsequent element takes the next consecutive + * uniform block binding point. + */ + blocks[i].Binding = (b->has_binding) ? b->binding + *binding_offset : 0; - parcel->process(type, blocks[i].Name); + blocks[i].UniformBufferSize = 0; + blocks[i]._Packing = gl_uniform_block_packing(type->interface_packing); + blocks[i]._RowMajor = type->get_interface_row_major(); + blocks[i].linearized_array_index = linearized_index; - blocks[i].UniformBufferSize = parcel->buffer_size; + parcel->process(type, b->has_instance_name ? blocks[i].Name : ""); - /* 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)", - b->type->name, - parcel->buffer_size, - ctx->Const.MaxShaderStorageBlockSize); - } - blocks[i].NumUniforms = - (unsigned)(ptrdiff_t)(&variables[parcel->index] - blocks[i].Uniforms); + blocks[i].UniformBufferSize = parcel->buffer_size; - *block_index = *block_index + 1; - *binding_offset = *binding_offset + 1; + /* 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)", + b->type->name, + parcel->buffer_size, + ctx->Const.MaxShaderStorageBlockSize); } + blocks[i].NumUniforms = + (unsigned)(ptrdiff_t)(&variables[parcel->index] - blocks[i].Uniforms); + + *block_index = *block_index + 1; + *binding_offset = *binding_offset + 1; } /* This function resizes the array types of the block so that later we can use @@ -310,7 +344,8 @@ create_buffer_blocks(void *mem_ctx, struct gl_context *ctx, /* Allocate storage to hold all of the information related to uniform * blocks that can be queried through the API. */ - struct gl_uniform_block *blocks = rzalloc_array(mem_ctx, gl_uniform_block, num_blocks); + struct gl_uniform_block *blocks = + rzalloc_array(mem_ctx, gl_uniform_block, num_blocks); gl_uniform_buffer_variable *variables = ralloc_array(blocks, gl_uniform_buffer_variable, num_variables); @@ -338,42 +373,21 @@ create_buffer_blocks(void *mem_ctx, struct gl_context *ctx, if ((create_ubo_blocks && !b->is_shader_storage) || (!create_ubo_blocks && b->is_shader_storage)) { + unsigned binding_offset = 0; 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); + variables, b, &i, &binding_offset, ctx, prog, + i); 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); - blocks[i]._RowMajor = block_type->get_interface_row_major(); - - 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++; + process_block_array_leaf(block_type->name, blocks, &parcel, + variables, b, &i, &binding_offset, + 0, ctx, prog); } } } @@ -407,8 +421,7 @@ link_uniform_blocks(void *mem_ctx, return; } - /* Determine which uniform blocks are active. - */ + /* Determine which uniform blocks are active. */ link_uniform_block_active_visitor v(mem_ctx, block_hash, prog); visit_list_elements(&v, shader->ir); @@ -473,12 +486,12 @@ link_uniform_blocks_are_compatible(const gl_uniform_block *a, /* Page 35 (page 42 of the PDF) in section 4.3.7 of the GLSL 1.50 spec says: * - * "Matched block names within an interface (as defined above) must - * match in terms of having the same number of declarations with the - * same sequence of types and the same sequence of member names, as - * well as having the same member-wise layout qualification....if a - * matching block is declared as an array, then the array sizes must - * also match... Any mismatch will generate a link error." + * Matched block names within an interface (as defined above) must match + * in terms of having the same number of declarations with the same + * sequence of types and the same sequence of member names, as well as + * having the same member-wise layout qualification....if a matching + * block is declared as an array, then the array sizes must also + * match... Any mismatch will generate a link error. * * Arrays are not yet supported, so there is no check for that. */ @@ -491,6 +504,9 @@ link_uniform_blocks_are_compatible(const gl_uniform_block *a, if (a->_RowMajor != b->_RowMajor) return false; + if (a->Binding != b->Binding) + return false; + for (unsigned i = 0; i < a->NumUniforms; i++) { if (strcmp(a->Uniforms[i].Name, b->Uniforms[i].Name) != 0) return false;