X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fglsl%2Flink_uniforms.cpp;h=6518ec10f34f9b27ad0e8fecbd603a0be6fe0ee5;hb=HEAD;hp=ef1241119912513803aa27bb374f69c15f83f00e;hpb=4e1e8f684bf57df90afd60b460d65d9c09ab0d08;p=mesa.git diff --git a/src/compiler/glsl/link_uniforms.cpp b/src/compiler/glsl/link_uniforms.cpp index ef124111991..6518ec10f34 100644 --- a/src/compiler/glsl/link_uniforms.cpp +++ b/src/compiler/glsl/link_uniforms.cpp @@ -28,7 +28,9 @@ #include "program.h" #include "string_to_uint_map.h" #include "ir_array_refcount.h" + #include "main/mtypes.h" +#include "util/strndup.h" /** * \file link_uniforms.cpp @@ -42,6 +44,219 @@ */ #define UNMAPPED_UNIFORM_LOC ~0u +static char* +get_top_level_name(const char *name) +{ + const char *first_dot = strchr(name, '.'); + const char *first_square_bracket = strchr(name, '['); + int name_size = 0; + + /* The ARB_program_interface_query spec says: + * + * "For the property TOP_LEVEL_ARRAY_SIZE, a single integer identifying + * the number of active array elements of the top-level shader storage + * block member containing to the active variable is written to + * . If the top-level block member is not declared as an + * array, the value one is written to . If the top-level block + * member is an array with no declared size, the value zero is written + * to ." + */ + + /* The buffer variable is on top level.*/ + if (!first_square_bracket && !first_dot) + name_size = strlen(name); + else if ((!first_square_bracket || + (first_dot && first_dot < first_square_bracket))) + name_size = first_dot - name; + else + name_size = first_square_bracket - name; + + return strndup(name, name_size); +} + +static char* +get_var_name(const char *name) +{ + const char *first_dot = strchr(name, '.'); + + if (!first_dot) + return strdup(name); + + return strndup(first_dot+1, strlen(first_dot) - 1); +} + +static bool +is_top_level_shader_storage_block_member(const char* name, + const char* interface_name, + const char* field_name) +{ + bool result = false; + + /* If the given variable is already a top-level shader storage + * block member, then return array_size = 1. + * We could have two possibilities: if we have an instanced + * shader storage block or not instanced. + * + * For the first, we check create a name as it was in top level and + * compare it with the real name. If they are the same, then + * the variable is already at top-level. + * + * Full instanced name is: interface name + '.' + var name + + * NULL character + */ + int name_length = strlen(interface_name) + 1 + strlen(field_name) + 1; + char *full_instanced_name = (char *) calloc(name_length, sizeof(char)); + if (!full_instanced_name) { + fprintf(stderr, "%s: Cannot allocate space for name\n", __func__); + return false; + } + + snprintf(full_instanced_name, name_length, "%s.%s", + interface_name, field_name); + + /* Check if its top-level shader storage block member of an + * instanced interface block, or of a unnamed interface block. + */ + if (strcmp(name, full_instanced_name) == 0 || + strcmp(name, field_name) == 0) + result = true; + + free(full_instanced_name); + return result; +} + +static int +get_array_size(struct gl_uniform_storage *uni, const glsl_struct_field *field, + char *interface_name, char *var_name) +{ + /* The ARB_program_interface_query spec says: + * + * "For the property TOP_LEVEL_ARRAY_SIZE, a single integer identifying + * the number of active array elements of the top-level shader storage + * block member containing to the active variable is written to + * . If the top-level block member is not declared as an + * array, the value one is written to . If the top-level block + * member is an array with no declared size, the value zero is written + * to ." + */ + if (is_top_level_shader_storage_block_member(uni->name, + interface_name, + var_name)) + return 1; + else if (field->type->is_array()) + return field->type->length; + + return 1; +} + +static int +get_array_stride(struct gl_uniform_storage *uni, const glsl_type *iface, + const glsl_struct_field *field, char *interface_name, + char *var_name, bool use_std430_as_default) +{ + /* The ARB_program_interface_query spec says: + * + * "For the property TOP_LEVEL_ARRAY_STRIDE, a single integer + * identifying the stride between array elements of the top-level + * shader storage block member containing the active variable is + * written to . For top-level block members declared as + * arrays, the value written is the difference, in basic machine units, + * between the offsets of the active variable for consecutive elements + * in the top-level array. For top-level block members not declared as + * an array, zero is written to ." + */ + if (field->type->is_array()) { + const enum glsl_matrix_layout matrix_layout = + glsl_matrix_layout(field->matrix_layout); + bool row_major = matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR; + const glsl_type *array_type = field->type->fields.array; + + if (is_top_level_shader_storage_block_member(uni->name, + interface_name, + var_name)) + return 0; + + if (GLSL_INTERFACE_PACKING_STD140 == + iface->get_internal_ifc_packing(use_std430_as_default)) { + if (array_type->is_struct() || array_type->is_array()) + return glsl_align(array_type->std140_size(row_major), 16); + else + return MAX2(array_type->std140_base_alignment(row_major), 16); + } else { + return array_type->std430_array_stride(row_major); + } + } + return 0; +} + +static void +calculate_array_size_and_stride(struct gl_shader_program *shProg, + struct gl_uniform_storage *uni, + bool use_std430_as_default) +{ + if (!uni->is_shader_storage) + return; + + int block_index = uni->block_index; + int array_size = -1; + int array_stride = -1; + char *var_name = get_top_level_name(uni->name); + char *interface_name = + get_top_level_name(uni->is_shader_storage ? + shProg->data->ShaderStorageBlocks[block_index].Name : + shProg->data->UniformBlocks[block_index].Name); + + if (strcmp(var_name, interface_name) == 0) { + /* Deal with instanced array of SSBOs */ + char *temp_name = get_var_name(uni->name); + if (!temp_name) { + linker_error(shProg, "Out of memory during linking.\n"); + goto write_top_level_array_size_and_stride; + } + free(var_name); + var_name = get_top_level_name(temp_name); + free(temp_name); + if (!var_name) { + linker_error(shProg, "Out of memory during linking.\n"); + goto write_top_level_array_size_and_stride; + } + } + + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + const gl_linked_shader *sh = shProg->_LinkedShaders[i]; + if (sh == NULL) + continue; + + foreach_in_list(ir_instruction, node, sh->ir) { + ir_variable *var = node->as_variable(); + if (!var || !var->get_interface_type() || + var->data.mode != ir_var_shader_storage) + continue; + + const glsl_type *iface = var->get_interface_type(); + + if (strcmp(interface_name, iface->name) != 0) + continue; + + for (unsigned i = 0; i < iface->length; i++) { + const glsl_struct_field *field = &iface->fields.structure[i]; + if (strcmp(field->name, var_name) != 0) + continue; + + array_stride = get_array_stride(uni, iface, field, interface_name, + var_name, use_std430_as_default); + array_size = get_array_size(uni, field, interface_name, var_name); + goto write_top_level_array_size_and_stride; + } + } + } +write_top_level_array_size_and_stride: + free(interface_name); + free(var_name); + uni->top_level_array_stride = array_stride; + uni->top_level_array_size = array_size; +} + void program_resource_visitor::process(const glsl_type *type, const char *name, bool use_std430_as_default) @@ -472,7 +687,8 @@ public: bool use_std430_as_default) : prog(prog), map(map), uniforms(uniforms), use_std430_as_default(use_std430_as_default), values(values), - bindless_targets(NULL), bindless_access(NULL) + bindless_targets(NULL), bindless_access(NULL), + shader_storage_blocks_write_access(0) { } @@ -522,8 +738,10 @@ public: prog->data->ShaderStorageBlocks : prog->data->UniformBlocks; unsigned num_blks = var->is_in_shader_storage_block() ? prog->data->NumShaderStorageBlocks : prog->data->NumUniformBlocks; + bool is_interface_array = + var->is_interface_instance() && var->type->is_array(); - if (var->is_interface_instance() && var->type->is_array()) { + if (is_interface_array) { unsigned l = strlen(var->get_interface_type()->name); for (unsigned i = 0; i < num_blks; i++) { @@ -544,8 +762,22 @@ public: assert(buffer_block_index != -1); if (var->is_in_shader_storage_block() && - !var->data.memory_read_only) - shader_storage_blocks_write_access |= 1 << buffer_block_index; + !var->data.memory_read_only) { + unsigned array_size = is_interface_array ? + var->type->array_size() : 1; + + STATIC_ASSERT(MAX_SHADER_STORAGE_BUFFERS <= 32); + + /* Shaders that use too many SSBOs will fail to compile, which + * we don't care about. + * + * This is true for shaders that do not use too many SSBOs: + */ + if (buffer_block_index + array_size <= 32) { + shader_storage_blocks_write_access |= + u_bit_consecutive(buffer_block_index, array_size); + } + } /* Uniform blocks that were specified with an instance name must be * handled a little bit differently. The name of the variable is the @@ -827,7 +1059,8 @@ private: this->uniforms[id].opaque[shader_type].index = ~0; this->uniforms[id].opaque[shader_type].active = false; - this->uniforms[id].active_shader_mask |= 1 << shader_type; + if (current_var->data.used || base_type->is_subroutine()) + this->uniforms[id].active_shader_mask |= 1 << shader_type; /* This assigns uniform indices to sampler and image uniforms. */ handle_samplers(base_type, &this->uniforms[id], name); @@ -934,6 +1167,9 @@ private: !this->uniforms[id].is_shader_storage && this->buffer_block_index == -1) this->values += type->component_slots(); + + calculate_array_size_and_stride(prog, &this->uniforms[id], + use_std430_as_default); } /** @@ -1488,6 +1724,22 @@ link_assign_uniform_locations(struct gl_shader_program *prog, uniform_size.process(var); } + if (uniform_size.num_shader_samplers > + ctx->Const.Program[i].MaxTextureImageUnits) { + linker_error(prog, "Too many %s shader texture samplers\n", + _mesa_shader_stage_to_string(i)); + continue; + } + + if (uniform_size.num_shader_images > + ctx->Const.Program[i].MaxImageUniforms) { + linker_error(prog, "Too many %s shader image uniforms (%u > %u)\n", + _mesa_shader_stage_to_string(i), + sh->Program->info.num_images, + ctx->Const.Program[i].MaxImageUniforms); + continue; + } + sh->Program->info.num_textures = uniform_size.num_shader_samplers; sh->Program->info.num_images = uniform_size.num_shader_images; sh->num_uniform_components = uniform_size.num_shader_uniform_components; @@ -1499,6 +1751,11 @@ link_assign_uniform_locations(struct gl_shader_program *prog, } } + if (prog->data->LinkStatus == LINKING_FAILURE) { + delete hiddenUniforms; + return; + } + prog->data->NumUniformStorage = uniform_size.num_active_uniforms; prog->data->NumHiddenUniforms = uniform_size.num_hidden_uniforms;