X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Flinker.cpp;h=b39c7f5d3ab7d7b6cdb84a4005b8ab3867520fad;hb=d97b060e6f305ce4ad050881944404b920c86edf;hp=9dcc2a76c9adc6612ffb6e1d869840c555483448;hpb=4bc16ad2176efda5f8c59e222b4735ee35c434b5;p=mesa.git diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 9dcc2a76c9a..b39c7f5d3ab 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -631,20 +631,12 @@ link_invalidate_variable_locations(exec_list *ir) /* ir_variable::is_unmatched_generic_inout is used by the linker while * connecting outputs from one stage to inputs of the next stage. - * - * There are two implicit assumptions here. First, we assume that any - * built-in variable (i.e., non-generic in or out) will have - * explicit_location set. Second, we assume that any generic in or out - * will not have explicit_location set. - * - * This second assumption will only be valid until - * GL_ARB_separate_shader_objects is supported. When that extension is - * implemented, this function will need some modifications. */ - if (!var->data.explicit_location) { - var->data.is_unmatched_generic_inout = 1; - } else { + if (var->data.explicit_location && + var->data.location < VARYING_SLOT_VAR0) { var->data.is_unmatched_generic_inout = 0; + } else { + var->data.is_unmatched_generic_inout = 1; } } } @@ -2421,6 +2413,7 @@ assign_attribute_or_color_locations(gl_shader_program *prog, continue; if (var->data.explicit_location) { + var->data.is_unmatched_generic_inout = 0; if ((var->data.location >= (int)(max_index + generic_base)) || (var->data.location < 0)) { linker_error(prog, @@ -2690,6 +2683,53 @@ assign_attribute_or_color_locations(gl_shader_program *prog, return true; } +/** + * Match explicit locations of outputs to inputs and deactivate the + * unmatch flag if found so we don't optimise them away. + */ +static void +match_explicit_outputs_to_inputs(struct gl_shader_program *prog, + gl_shader *producer, + gl_shader *consumer) +{ + glsl_symbol_table parameters; + ir_variable *explicit_locations[MAX_VARYING] = { NULL }; + + /* Find all shader outputs in the "producer" stage. + */ + foreach_in_list(ir_instruction, node, producer->ir) { + ir_variable *const var = node->as_variable(); + + if ((var == NULL) || (var->data.mode != ir_var_shader_out)) + continue; + + if (var->data.explicit_location && + var->data.location >= VARYING_SLOT_VAR0) { + const unsigned idx = var->data.location - VARYING_SLOT_VAR0; + if (explicit_locations[idx] == NULL) + explicit_locations[idx] = var; + } + } + + /* Match inputs to outputs */ + foreach_in_list(ir_instruction, node, consumer->ir) { + ir_variable *const input = node->as_variable(); + + if ((input == NULL) || (input->data.mode != ir_var_shader_in)) + continue; + + ir_variable *output = NULL; + if (input->data.explicit_location + && input->data.location >= VARYING_SLOT_VAR0) { + output = explicit_locations[input->data.location - VARYING_SLOT_VAR0]; + + if (output != NULL){ + input->data.is_unmatched_generic_inout = 0; + output->data.is_unmatched_generic_inout = 0; + } + } + } +} /** * Demote shader inputs and outputs that are not used in other stages @@ -3776,7 +3816,8 @@ build_program_resource_list(struct gl_shader_program *shProg) continue; for (int j = MESA_SHADER_VERTEX; j < MESA_SHADER_STAGES; j++) { - if (!shProg->UniformStorage[i].opaque[j].active) + if (!shProg->UniformStorage[i].opaque[j].active || + !shProg->UniformStorage[i].type->is_subroutine()) continue; type = _mesa_shader_stage_to_subroutine_uniform((gl_shader_stage)j); @@ -3799,11 +3840,6 @@ build_program_resource_list(struct gl_shader_program *shProg) return; } } - - /* TODO - following extensions will require more resource types: - * - * GL_ARB_shader_storage_buffer_object - */ } /** @@ -3868,10 +3904,43 @@ link_assign_subroutine_types(struct gl_shader_program *prog) sh->SubroutineFunctions[sh->NumSubroutineFunctions].types = ralloc_array(sh, const struct glsl_type *, fn->num_subroutine_types); + + /* From Section 4.4.4(Subroutine Function Layout Qualifiers) of the + * GLSL 4.5 spec: + * + * "Each subroutine with an index qualifier in the shader must be + * given a unique index, otherwise a compile or link error will be + * generated." + */ + for (unsigned j = 0; j < sh->NumSubroutineFunctions; j++) { + if (sh->SubroutineFunctions[j].index != -1 && + sh->SubroutineFunctions[j].index == fn->subroutine_index) { + linker_error(prog, "each subroutine index qualifier in the " + "shader must be unique\n"); + return; + } + } + sh->SubroutineFunctions[sh->NumSubroutineFunctions].index = + fn->subroutine_index; + for (int j = 0; j < fn->num_subroutine_types; j++) sh->SubroutineFunctions[sh->NumSubroutineFunctions].types[j] = fn->subroutine_types[j]; sh->NumSubroutineFunctions++; } + + /* Assign index for subroutines without an explicit index*/ + int index = 0; + for (unsigned j = 0; j < sh->NumSubroutineFunctions; j++) { + while (sh->SubroutineFunctions[j].index == -1) { + for (unsigned k = 0; k < sh->NumSubroutineFunctions; k++) { + if (sh->SubroutineFunctions[k].index == index) + break; + else if (k == sh->NumSubroutineFunctions - 1) + sh->SubroutineFunctions[j].index = index; + } + index++; + } + } } } @@ -3911,6 +3980,77 @@ split_ubos_and_ssbos(void *mem_ctx, assert(*num_ubos + *num_ssbos == num_blocks); } +static void +set_always_active_io(exec_list *ir, ir_variable_mode io_mode) +{ + assert(io_mode == ir_var_shader_in || io_mode == ir_var_shader_out); + + foreach_in_list(ir_instruction, node, ir) { + ir_variable *const var = node->as_variable(); + + if (var == NULL || var->data.mode != io_mode) + continue; + + /* Don't set always active on builtins that haven't been redeclared */ + if (var->data.how_declared == ir_var_declared_implicitly) + continue; + + var->data.always_active_io = true; + } +} + +/** + * When separate shader programs are enabled, only input/outputs between + * the stages of a multi-stage separate program can be safely removed + * from the shader interface. Other inputs/outputs must remain active. + */ +static void +disable_varying_optimizations_for_sso(struct gl_shader_program *prog) +{ + unsigned first, last; + assert(prog->SeparateShader); + + first = MESA_SHADER_STAGES; + last = 0; + + /* Determine first and last stage. Excluding the compute stage */ + for (unsigned i = 0; i < MESA_SHADER_COMPUTE; i++) { + if (!prog->_LinkedShaders[i]) + continue; + if (first == MESA_SHADER_STAGES) + first = i; + last = i; + } + + if (first == MESA_SHADER_STAGES) + return; + + for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) { + gl_shader *sh = prog->_LinkedShaders[stage]; + if (!sh) + continue; + + if (first == last) { + /* For a single shader program only allow inputs to the vertex shader + * and outputs from the fragment shader to be removed. + */ + if (stage != MESA_SHADER_VERTEX) + set_always_active_io(sh->ir, ir_var_shader_in); + if (stage != MESA_SHADER_FRAGMENT) + set_always_active_io(sh->ir, ir_var_shader_out); + } else { + /* For multi-stage separate shader programs only allow inputs and + * outputs between the shader stages to be removed as well as inputs + * to the vertex shader and outputs from the fragment shader. + */ + if (stage == first && stage != MESA_SHADER_VERTEX) + set_always_active_io(sh->ir, ir_var_shader_in); + else if (stage == last && stage != MESA_SHADER_FRAGMENT) + set_always_active_io(sh->ir, ir_var_shader_out); + } + } +} + void link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) { @@ -4110,11 +4250,18 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) if (!prog->LinkStatus) goto done; - unsigned prev; + unsigned first, last, prev; - for (prev = 0; prev <= MESA_SHADER_FRAGMENT; prev++) { - if (prog->_LinkedShaders[prev] != NULL) - break; + first = MESA_SHADER_STAGES; + last = 0; + + /* Determine first and last stage. */ + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + if (!prog->_LinkedShaders[i]) + continue; + if (first == MESA_SHADER_STAGES) + first = i; + last = i; } check_explicit_uniform_locations(ctx, prog); @@ -4128,6 +4275,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) /* Validate the inputs of each stage with the output of the preceding * stage. */ + prev = first; for (unsigned i = prev + 1; i <= MESA_SHADER_FRAGMENT; i++) { if (prog->_LinkedShaders[i] == NULL) continue; @@ -4170,6 +4318,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) } } + if (prog->SeparateShader) + disable_varying_optimizations_for_sso(prog); + if (!interstage_cross_validate_uniform_blocks(prog)) goto done; @@ -4221,6 +4372,16 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) } } + prev = first; + for (unsigned i = prev + 1; i <= MESA_SHADER_FRAGMENT; i++) { + if (prog->_LinkedShaders[i] == NULL) + continue; + + match_explicit_outputs_to_inputs(prog, prog->_LinkedShaders[prev], + prog->_LinkedShaders[i]); + prev = i; + } + if (!assign_attribute_or_color_locations(prog, &ctx->Const, MESA_SHADER_VERTEX)) { goto done; @@ -4231,20 +4392,6 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) goto done; } - unsigned first, last; - - first = MESA_SHADER_STAGES; - last = 0; - - /* Determine first and last stage. */ - for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { - if (!prog->_LinkedShaders[i]) - continue; - if (first == MESA_SHADER_STAGES) - first = i; - last = i; - } - if (num_tfeedback_decls != 0) { /* From GL_EXT_transform_feedback: * A program will fail to link if: @@ -4276,13 +4423,13 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) if (first < MESA_SHADER_FRAGMENT) { gl_shader *const sh = prog->_LinkedShaders[last]; - if (first == MESA_SHADER_GEOMETRY) { + if (first != MESA_SHADER_VERTEX) { /* There was no vertex shader, but we still have to assign varying - * locations for use by geometry shader inputs in SSO. + * locations for use by tessellation/geometry shader inputs in SSO. * * If the shader is not separable (i.e., prog->SeparateShader is - * false), linking will have already failed when first is - * MESA_SHADER_GEOMETRY. + * false), linking will have already failed when first is not + * MESA_SHADER_VERTEX. */ if (!assign_varying_locations(ctx, mem_ctx, prog, NULL, prog->_LinkedShaders[first], @@ -4304,13 +4451,14 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) do_dead_builtin_varyings(ctx, sh, NULL, num_tfeedback_decls, tfeedback_decls); - if (!prog->SeparateShader) + if (!prog->SeparateShader) { demote_shader_inputs_and_outputs(sh, ir_var_shader_out); - - /* Eliminate code that is now dead due to unused outputs being demoted. - */ - while (do_dead_code(sh->ir, false)) - ; + /* Eliminate code that is now dead due to unused outputs being + * demoted. + */ + while (do_dead_code(sh->ir, false)) + ; + } } else if (first == MESA_SHADER_FRAGMENT) { /* If the program only contains a fragment shader... @@ -4327,11 +4475,14 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) 0 /* num_tfeedback_decls */, NULL /* tfeedback_decls */)) goto done; - } else + } else { demote_shader_inputs_and_outputs(sh, ir_var_shader_in); - - while (do_dead_code(sh->ir, false)) - ; + /* Eliminate code that is now dead due to unused inputs being + * demoted. + */ + while (do_dead_code(sh->ir, false)) + ; + } } next = last; @@ -4449,6 +4600,20 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) /* FINISHME: Assign fragment shader output locations. */ + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + if (prog->_LinkedShaders[i] == NULL) + continue; + + if (ctx->Const.ShaderCompilerOptions[i].LowerBufferInterfaceBlocks) + lower_ubo_reference(prog->_LinkedShaders[i]); + + if (ctx->Const.ShaderCompilerOptions[i].LowerShaderSharedVariables) + lower_shared_reference(prog->_LinkedShaders[i], + &prog->Comp.SharedSize); + + lower_vector_derefs(prog->_LinkedShaders[i]); + } + done: for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { free(shader_list[i]);