diff options
Diffstat (limited to 'src/glsl/linker.cpp')
-rw-r--r-- | src/glsl/linker.cpp | 268 |
1 files changed, 152 insertions, 116 deletions
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 07ea0e0c7e5..c35d87acea6 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -2282,6 +2282,22 @@ resize_tes_inputs(struct gl_context *ctx, foreach_in_list(ir_instruction, ir, tes->ir) { ir->accept(&input_resize_visitor); } + + if (tcs) { + /* Convert the gl_PatchVerticesIn system value into a constant, since + * the value is known at this point. + */ + foreach_in_list(ir_instruction, ir, tes->ir) { + ir_variable *var = ir->as_variable(); + if (var && var->data.mode == ir_var_system_value && + var->data.location == SYSTEM_VALUE_VERTICES_IN) { + void *mem_ctx = ralloc_parent(var); + var->data.mode = ir_var_auto; + var->data.location = 0; + var->constant_value = new(mem_ctx) ir_constant(num_vertices); + } + } + } } /** @@ -3137,7 +3153,8 @@ should_add_buffer_variable(struct gl_shader_program *shProg, GLenum type, const char *name) { bool found_interface = false; - const char *block_name = NULL; + unsigned block_name_len = 0; + const char *block_name_dot = strchr(name, '.'); /* These rules only apply to buffer variables. So we return * true for the rest of types. @@ -3146,8 +3163,28 @@ should_add_buffer_variable(struct gl_shader_program *shProg, return true; for (unsigned i = 0; i < shProg->NumBufferInterfaceBlocks; i++) { - block_name = shProg->BufferInterfaceBlocks[i].Name; - if (strncmp(block_name, name, strlen(block_name)) == 0) { + const char *block_name = shProg->BufferInterfaceBlocks[i].Name; + block_name_len = strlen(block_name); + + const char *block_square_bracket = strchr(block_name, '['); + if (block_square_bracket) { + /* The block is part of an array of named interfaces, + * for the name comparison we ignore the "[x]" part. + */ + block_name_len -= strlen(block_square_bracket); + } + + if (block_name_dot) { + /* Check if the variable name starts with the interface + * name. The interface name (if present) should have the + * length than the interface block name we are comparing to. + */ + unsigned len = strlen(name) - strlen(block_name_dot); + if (len != block_name_len) + continue; + } + + if (strncmp(block_name, name, block_name_len) == 0) { found_interface = true; break; } @@ -3157,7 +3194,7 @@ should_add_buffer_variable(struct gl_shader_program *shProg, * including the dot that follows it. */ if (found_interface) - name = name + strlen(block_name) + 1; + name = name + block_name_len + 1; /* From: ARB_program_interface_query extension: * @@ -3166,14 +3203,14 @@ should_add_buffer_variable(struct gl_shader_program *shProg, * of its type. For arrays of aggregate types, the enumeration rules are * applied recursively for the single enumerated array element. */ - const char *first_dot = strchr(name, '.'); + const char *struct_first_dot = strchr(name, '.'); const char *first_square_bracket = strchr(name, '['); /* The buffer variable is on top level and it is not an array */ if (!first_square_bracket) { return true; /* The shader storage block member is a struct, then generate the entry */ - } else if (first_dot && first_dot < first_square_bracket) { + } else if (struct_first_dot && struct_first_dot < first_square_bracket) { return true; } else { /* Shader storage block member is an array, only generate an entry for the @@ -3349,6 +3386,12 @@ add_interface_variables(struct gl_shader_program *shProg, if (strncmp(var->name, "packed:", 7) == 0) continue; + /* Skip fragdata arrays, these are handled separately + * by add_fragdata_arrays. + */ + if (strncmp(var->name, "gl_out_FragData", 15) == 0) + continue; + if (!add_program_resource(shProg, programInterface, var, build_stageref(shProg, var->name, var->data.mode) | mask)) @@ -3388,6 +3431,26 @@ add_packed_varyings(struct gl_shader_program *shProg, int stage) return true; } +static bool +add_fragdata_arrays(struct gl_shader_program *shProg) +{ + struct gl_shader *sh = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]; + + if (!sh || !sh->fragdata_arrays) + return true; + + foreach_in_list(ir_instruction, node, sh->fragdata_arrays) { + ir_variable *var = node->as_variable(); + if (var) { + assert(var->data.mode == ir_var_shader_out); + if (!add_program_resource(shProg, GL_PROGRAM_OUTPUT, var, + 1 << MESA_SHADER_FRAGMENT)) + return false; + } + } + return true; +} + static char* get_top_level_name(const char *name) { @@ -3467,80 +3530,78 @@ is_top_level_shader_storage_block_member(const char* name, return result; } -static void -calculate_array_size(struct gl_shader_program *shProg, - struct gl_uniform_storage *uni) +static int +get_array_size(struct gl_uniform_storage *uni, const glsl_struct_field *field, + char *interface_name, char *var_name) { - int block_index = uni->block_index; - int array_size = -1; - char *var_name = get_top_level_name(uni->name); - char *interface_name = - get_top_level_name(shProg->BufferInterfaceBlocks[block_index].Name); - - if (strcmp(var_name, interface_name) == 0) { - /* Deal with instanced array of SSBOs */ - char *temp_name = get_var_name(uni->name); - free(var_name); - var_name = get_top_level_name(temp_name); - free(temp_name); - } - - for (unsigned i = 0; i < shProg->NumShaders; i++) { - if (shProg->Shaders[i] == NULL) - continue; - - const gl_shader *stage = shProg->Shaders[i]; - foreach_in_list(ir_instruction, node, stage->ir) { - ir_variable *var = node->as_variable(); - if (!var || !var->get_interface_type() || - var->data.mode != ir_var_shader_storage) - continue; - - const glsl_type *interface = var->get_interface_type(); - - if (strcmp(interface_name, interface->name) != 0) - continue; - - for (unsigned i = 0; i < interface->length; i++) { - const glsl_struct_field *field = &interface->fields.structure[i]; - if (strcmp(field->name, var_name) != 0) - continue; - /* From GL_ARB_program_interface_query spec: - * - * "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 <params>. If the top-level block member is not - * declared as an array, the value one is written to <params>. If - * the top-level block member is an array with no declared size, - * the value zero is written to <params>. - */ - if (is_top_level_shader_storage_block_member(uni->name, - interface_name, - var_name)) - array_size = 1; - else if (field->type->is_unsized_array()) - array_size = 0; - else if (field->type->is_array()) - array_size = field->type->length; - else - array_size = 1; + /* From GL_ARB_program_interface_query spec: + * + * "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 <params>. If the top-level block member is not + * declared as an array, the value one is written to <params>. If + * the top-level block member is an array with no declared size, + * the value zero is written to <params>. + */ + if (is_top_level_shader_storage_block_member(uni->name, + interface_name, + var_name)) + return 1; + else if (field->type->is_unsized_array()) + return 0; + else if (field->type->is_array()) + return field->type->length; + + return 1; +} - goto found_top_level_array_size; - } +static int +get_array_stride(struct gl_uniform_storage *uni, const glsl_type *interface, + const glsl_struct_field *field, char *interface_name, + char *var_name) +{ + /* From GL_ARB_program_interface_query: + * + * "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 <params>. 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 + * <params>." + */ + 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 (interface->interface_packing != GLSL_INTERFACE_PACKING_STD430) { + if (array_type->is_record() || 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); } } -found_top_level_array_size: - free(interface_name); - free(var_name); - uni->top_level_array_size = array_size; + return 0; } static void -calculate_array_stride(struct gl_shader_program *shProg, - struct gl_uniform_storage *uni) +calculate_array_size_and_stride(struct gl_shader_program *shProg, + struct gl_uniform_storage *uni) { 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 = @@ -3549,9 +3610,17 @@ calculate_array_stride(struct gl_shader_program *shProg, 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 < shProg->NumShaders; i++) { @@ -3567,61 +3636,26 @@ calculate_array_stride(struct gl_shader_program *shProg, const glsl_type *interface = var->get_interface_type(); - if (strcmp(interface_name, interface->name) != 0) { + if (strcmp(interface_name, interface->name) != 0) continue; - } for (unsigned i = 0; i < interface->length; i++) { const glsl_struct_field *field = &interface->fields.structure[i]; if (strcmp(field->name, var_name) != 0) continue; - /* From GL_ARB_program_interface_query: - * - * "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 <params>. 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 - * <params>." - */ - 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)) { - array_stride = 0; - goto found_top_level_array_stride; - } - if (interface->interface_packing != GLSL_INTERFACE_PACKING_STD430) { - if (array_type->is_record() || array_type->is_array()) { - array_stride = array_type->std140_size(row_major); - array_stride = glsl_align(array_stride, 16); - } else { - unsigned element_base_align = 0; - element_base_align = array_type->std140_base_alignment(row_major); - array_stride = MAX2(element_base_align, 16); - } - } else { - array_stride = array_type->std430_array_stride(row_major); - } - } else { - array_stride = 0; - } - goto found_top_level_array_stride; + + array_stride = get_array_stride(uni, interface, field, + interface_name, var_name); + array_size = get_array_size(uni, field, interface_name, var_name); + goto write_top_level_array_size_and_stride; } } } -found_top_level_array_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; } /** @@ -3664,6 +3698,9 @@ build_program_resource_list(struct gl_shader_program *shProg) return; } + if (!add_fragdata_arrays(shProg)) + return; + /* Add inputs and outputs to the resource list. */ if (!add_interface_variables(shProg, shProg->_LinkedShaders[input_stage]->ir, GL_PROGRAM_INPUT)) @@ -3709,8 +3746,7 @@ build_program_resource_list(struct gl_shader_program *shProg) continue; if (is_shader_storage) { - calculate_array_size(shProg, &shProg->UniformStorage[i]); - calculate_array_stride(shProg, &shProg->UniformStorage[i]); + calculate_array_size_and_stride(shProg, &shProg->UniformStorage[i]); } if (!add_program_resource(shProg, type, |