diff options
Diffstat (limited to 'src/compiler/glsl/linker.cpp')
-rw-r--r-- | src/compiler/glsl/linker.cpp | 341 |
1 files changed, 163 insertions, 178 deletions
diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp index 4776ffa6acd..bad1c1742b7 100644 --- a/src/compiler/glsl/linker.cpp +++ b/src/compiler/glsl/linker.cpp @@ -82,8 +82,6 @@ #include "main/enums.h" -void linker_error(gl_shader_program *, const char *, ...); - namespace { /** @@ -2125,6 +2123,7 @@ link_intrastage_shaders(void *mem_ctx, if (ok) { memcpy(linking_shaders, shader_list, num_shaders * sizeof(gl_shader *)); + _mesa_glsl_initialize_builtin_functions(); linking_shaders[num_shaders] = _mesa_glsl_get_builtin_function_shader(); ok = link_function_calls(prog, linked, linking_shaders, num_shaders + 1); @@ -4105,15 +4104,34 @@ disable_varying_optimizations_for_sso(struct gl_shader_program *prog) void link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) { + prog->LinkStatus = true; /* All error paths will set this to false */ + prog->Validated = false; + prog->_Used = false; + + /* Section 7.3 (Program Objects) of the OpenGL 4.5 Core Profile spec says: + * + * "Linking can fail for a variety of reasons as specified in the + * OpenGL Shading Language Specification, as well as any of the + * following reasons: + * + * - No shader objects are attached to program." + * + * The Compatibility Profile specification does not list the error. In + * Compatibility Profile missing shader stages are replaced by + * fixed-function. This applies to the case where all stages are + * missing. + */ + if (prog->NumShaders == 0) { + if (ctx->API != API_OPENGL_COMPAT) + linker_error(prog, "no shaders attached to the program\n"); + return; + } + tfeedback_decl *tfeedback_decls = NULL; unsigned num_tfeedback_decls = prog->TransformFeedback.NumVarying; void *mem_ctx = ralloc_context(NULL); // temporary linker context - prog->LinkStatus = true; /* All error paths will set this to false */ - prog->Validated = false; - prog->_Used = false; - prog->ARB_fragment_coord_conventions_enable = false; /* Separate the shaders into groups based on their type. @@ -4129,13 +4147,11 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) unsigned min_version = UINT_MAX; unsigned max_version = 0; - const bool is_es_prog = - (prog->NumShaders > 0 && prog->Shaders[0]->IsES) ? true : false; for (unsigned i = 0; i < prog->NumShaders; i++) { min_version = MIN2(min_version, prog->Shaders[i]->Version); max_version = MAX2(max_version, prog->Shaders[i]->Version); - if (prog->Shaders[i]->IsES != is_es_prog) { + if (prog->Shaders[i]->IsES != prog->Shaders[0]->IsES) { linker_error(prog, "all shaders must use same shading " "language version\n"); goto done; @@ -4153,80 +4169,59 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) /* In desktop GLSL, different shader versions may be linked together. In * GLSL ES, all shader versions must be the same. */ - if (is_es_prog && min_version != max_version) { + if (prog->Shaders[0]->IsES && min_version != max_version) { linker_error(prog, "all shaders must use same shading " "language version\n"); goto done; } prog->Version = max_version; - prog->IsES = is_es_prog; - - /* From OpenGL 4.5 Core specification (7.3 Program Objects): - * "Linking can fail for a variety of reasons as specified in the OpenGL - * Shading Language Specification, as well as any of the following - * reasons: - * - * * No shader objects are attached to program. - * - * ..." - * - * Same rule applies for OpenGL ES >= 3.1. - */ - - if (prog->NumShaders == 0 && - ((ctx->API == API_OPENGL_CORE && ctx->Version >= 45) || - (ctx->API == API_OPENGLES2 && ctx->Version >= 31))) { - linker_error(prog, "No shader objects are attached to program.\n"); - goto done; - } + prog->IsES = prog->Shaders[0]->IsES; /* Some shaders have to be linked with some other shaders present. */ - if (num_shaders[MESA_SHADER_GEOMETRY] > 0 && - num_shaders[MESA_SHADER_VERTEX] == 0 && - !prog->SeparateShader) { - linker_error(prog, "Geometry shader must be linked with " - "vertex shader\n"); - goto done; - } - if (num_shaders[MESA_SHADER_TESS_EVAL] > 0 && - num_shaders[MESA_SHADER_VERTEX] == 0 && - !prog->SeparateShader) { - linker_error(prog, "Tessellation evaluation shader must be linked with " - "vertex shader\n"); - goto done; - } - if (num_shaders[MESA_SHADER_TESS_CTRL] > 0 && - num_shaders[MESA_SHADER_VERTEX] == 0 && - !prog->SeparateShader) { - linker_error(prog, "Tessellation control shader must be linked with " - "vertex shader\n"); - goto done; - } + if (!prog->SeparateShader) { + if (num_shaders[MESA_SHADER_GEOMETRY] > 0 && + num_shaders[MESA_SHADER_VERTEX] == 0) { + linker_error(prog, "Geometry shader must be linked with " + "vertex shader\n"); + goto done; + } + if (num_shaders[MESA_SHADER_TESS_EVAL] > 0 && + num_shaders[MESA_SHADER_VERTEX] == 0) { + linker_error(prog, "Tessellation evaluation shader must be linked " + "with vertex shader\n"); + goto done; + } + if (num_shaders[MESA_SHADER_TESS_CTRL] > 0 && + num_shaders[MESA_SHADER_VERTEX] == 0) { + linker_error(prog, "Tessellation control shader must be linked with " + "vertex shader\n"); + goto done; + } - /* The spec is self-contradictory here. It allows linking without a tess - * eval shader, but that can only be used with transform feedback and - * rasterization disabled. However, transform feedback isn't allowed - * with GL_PATCHES, so it can't be used. - * - * More investigation showed that the idea of transform feedback after - * a tess control shader was dropped, because some hw vendors couldn't - * support tessellation without a tess eval shader, but the linker section - * wasn't updated to reflect that. - * - * All specifications (ARB_tessellation_shader, GL 4.0-4.5) have this - * spec bug. - * - * Do what's reasonable and always require a tess eval shader if a tess - * control shader is present. - */ - if (num_shaders[MESA_SHADER_TESS_CTRL] > 0 && - num_shaders[MESA_SHADER_TESS_EVAL] == 0 && - !prog->SeparateShader) { - linker_error(prog, "Tessellation control shader must be linked with " - "tessellation evaluation shader\n"); - goto done; + /* The spec is self-contradictory here. It allows linking without a tess + * eval shader, but that can only be used with transform feedback and + * rasterization disabled. However, transform feedback isn't allowed + * with GL_PATCHES, so it can't be used. + * + * More investigation showed that the idea of transform feedback after + * a tess control shader was dropped, because some hw vendors couldn't + * support tessellation without a tess eval shader, but the linker + * section wasn't updated to reflect that. + * + * All specifications (ARB_tessellation_shader, GL 4.0-4.5) have this + * spec bug. + * + * Do what's reasonable and always require a tess eval shader if a tess + * control shader is present. + */ + if (num_shaders[MESA_SHADER_TESS_CTRL] > 0 && + num_shaders[MESA_SHADER_TESS_EVAL] == 0) { + linker_error(prog, "Tessellation control shader must be linked with " + "tessellation evaluation shader\n"); + goto done; + } } /* Compute shaders have additional restrictions. */ @@ -4362,7 +4357,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) * * This rule also applies to GLSL ES 3.00. */ - if (max_version >= (is_es_prog ? 300 : 130)) { + if (max_version >= (prog->IsES ? 300 : 130)) { struct gl_shader *sh = prog->_LinkedShaders[MESA_SHADER_FRAGMENT]; if (sh) { lower_discard_flow(sh->ir); @@ -4451,9 +4446,10 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) * non-zero, but the program object has no vertex or geometry * shader; */ - if (first == MESA_SHADER_FRAGMENT) { + if (first >= MESA_SHADER_FRAGMENT) { linker_error(prog, "Transform feedback varyings specified, but " - "no vertex or geometry shader is present.\n"); + "no vertex, tessellation, or geometry shader is " + "present.\n"); goto done; } @@ -4465,91 +4461,80 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) goto done; } - /* Linking the stages in the opposite order (from fragment to vertex) - * ensures that inter-shader outputs written to in an earlier stage are - * eliminated if they are (transitively) not used in a later stage. + /* If there is no fragment shader we need to set transform feedback. + * + * For SSO we need also need to assign output locations, we assign them + * here because we need to do it for both single stage programs and multi + * stage programs. */ - int next; - - if (first < MESA_SHADER_FRAGMENT) { - gl_shader *const sh = prog->_LinkedShaders[last]; - - if (first != MESA_SHADER_VERTEX) { - /* There was no vertex shader, but we still have to assign varying - * 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 not - * MESA_SHADER_VERTEX. - */ - if (!assign_varying_locations(ctx, mem_ctx, prog, - NULL, prog->_LinkedShaders[first], - num_tfeedback_decls, tfeedback_decls)) - goto done; - } - - if (last != MESA_SHADER_FRAGMENT && - (num_tfeedback_decls != 0 || prog->SeparateShader)) { - /* There was no fragment shader, but we still have to assign varying - * locations for use by transform feedback. - */ - if (!assign_varying_locations(ctx, mem_ctx, prog, - sh, NULL, - num_tfeedback_decls, tfeedback_decls)) - goto done; - } - - do_dead_builtin_varyings(ctx, sh, NULL, - num_tfeedback_decls, tfeedback_decls); + if (last < MESA_SHADER_FRAGMENT && + (num_tfeedback_decls != 0 || prog->SeparateShader)) { + if (!assign_varying_locations(ctx, mem_ctx, prog, + prog->_LinkedShaders[last], NULL, + num_tfeedback_decls, tfeedback_decls)) + goto done; + } - remove_unused_shader_inputs_and_outputs(prog->SeparateShader, sh, + if (last <= MESA_SHADER_FRAGMENT) { + /* Remove unused varyings from the first/last stage unless SSO */ + remove_unused_shader_inputs_and_outputs(prog->SeparateShader, + prog->_LinkedShaders[first], + ir_var_shader_in); + remove_unused_shader_inputs_and_outputs(prog->SeparateShader, + prog->_LinkedShaders[last], ir_var_shader_out); - } - else if (first == MESA_SHADER_FRAGMENT) { - /* If the program only contains a fragment shader... - */ - gl_shader *const sh = prog->_LinkedShaders[first]; - do_dead_builtin_varyings(ctx, NULL, sh, - num_tfeedback_decls, tfeedback_decls); + /* If the program is made up of only a single stage */ + if (first == last) { - if (prog->SeparateShader) { - if (!assign_varying_locations(ctx, mem_ctx, prog, - NULL /* producer */, - sh /* consumer */, - 0 /* num_tfeedback_decls */, - NULL /* tfeedback_decls */)) - goto done; - } else { - remove_unused_shader_inputs_and_outputs(false, sh, - ir_var_shader_in); - } - } + gl_shader *const sh = prog->_LinkedShaders[last]; + if (prog->SeparateShader) { + /* Assign input locations for SSO, output locations are already + * assigned. + */ + if (!assign_varying_locations(ctx, mem_ctx, prog, + NULL /* producer */, + sh /* consumer */, + 0 /* num_tfeedback_decls */, + NULL /* tfeedback_decls */)) + goto done; + } - next = last; - for (int i = next - 1; i >= 0; i--) { - if (prog->_LinkedShaders[i] == NULL) - continue; + do_dead_builtin_varyings(ctx, NULL, sh, 0, NULL); + do_dead_builtin_varyings(ctx, sh, NULL, num_tfeedback_decls, + tfeedback_decls); + } else { + /* Linking the stages in the opposite order (from fragment to vertex) + * ensures that inter-shader outputs written to in an earlier stage + * are eliminated if they are (transitively) not used in a later + * stage. + */ + int next = last; + for (int i = next - 1; i >= 0; i--) { + if (prog->_LinkedShaders[i] == NULL) + continue; - gl_shader *const sh_i = prog->_LinkedShaders[i]; - gl_shader *const sh_next = prog->_LinkedShaders[next]; + gl_shader *const sh_i = prog->_LinkedShaders[i]; + gl_shader *const sh_next = prog->_LinkedShaders[next]; - if (!assign_varying_locations(ctx, mem_ctx, prog, sh_i, sh_next, - next == MESA_SHADER_FRAGMENT ? num_tfeedback_decls : 0, - tfeedback_decls)) - goto done; + if (!assign_varying_locations(ctx, mem_ctx, prog, sh_i, sh_next, + next == MESA_SHADER_FRAGMENT ? num_tfeedback_decls : 0, + tfeedback_decls)) + goto done; - do_dead_builtin_varyings(ctx, sh_i, sh_next, - next == MESA_SHADER_FRAGMENT ? num_tfeedback_decls : 0, - tfeedback_decls); + do_dead_builtin_varyings(ctx, sh_i, sh_next, + next == MESA_SHADER_FRAGMENT ? num_tfeedback_decls : 0, + tfeedback_decls); - /* This must be done after all dead varyings are eliminated. */ - if (!check_against_output_limit(ctx, prog, sh_i)) - goto done; - if (!check_against_input_limit(ctx, prog, sh_next)) - goto done; + /* This must be done after all dead varyings are eliminated. */ + if (!check_against_output_limit(ctx, prog, sh_i)) + goto done; + if (!check_against_input_limit(ctx, prog, sh_next)) + goto done; - next = i; + next = i; + } + } } if (!store_tfeedback_info(ctx, prog, num_tfeedback_decls, tfeedback_decls)) @@ -4569,38 +4554,38 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) if (!prog->LinkStatus) goto done; - /* OpenGL ES requires that a vertex shader and a fragment shader both be - * present in a linked program. GL_ARB_ES2_compatibility doesn't say + /* OpenGL ES < 3.1 requires that a vertex shader and a fragment shader both + * be present in a linked program. GL_ARB_ES2_compatibility doesn't say * anything about shader linking when one of the shaders (vertex or * fragment shader) is absent. So, the extension shouldn't change the * behavior specified in GLSL specification. + * + * From OpenGL ES 3.1 specification (7.3 Program Objects): + * "Linking can fail for a variety of reasons as specified in the + * OpenGL ES Shading Language Specification, as well as any of the + * following reasons: + * + * ... + * + * * program contains objects to form either a vertex shader or + * fragment shader, and program is not separable, and does not + * contain objects to form both a vertex shader and fragment + * shader." + * + * However, the only scenario in 3.1+ where we don't require them both is + * when we have a compute shader. For example: + * + * - No shaders is a link error. + * - Geom or Tess without a Vertex shader is a link error which means we + * always require a Vertex shader and hence a Fragment shader. + * - Finally a Compute shader linked with any other stage is a link error. */ - if (!prog->SeparateShader && ctx->API == API_OPENGLES2) { - /* With ES < 3.1 one needs to have always vertex + fragment shader. */ - if (ctx->Version < 31) { - if (prog->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) { - linker_error(prog, "program lacks a vertex shader\n"); - } else if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL) { - linker_error(prog, "program lacks a fragment shader\n"); - } - } else { - /* From OpenGL ES 3.1 specification (7.3 Program Objects): - * "Linking can fail for a variety of reasons as specified in the - * OpenGL ES Shading Language Specification, as well as any of the - * following reasons: - * - * ... - * - * * program contains objects to form either a vertex shader or - * fragment shader, and program is not separable, and does not - * contain objects to form both a vertex shader and fragment - * shader." - */ - if (!!prog->_LinkedShaders[MESA_SHADER_VERTEX] ^ - !!prog->_LinkedShaders[MESA_SHADER_FRAGMENT]) { - linker_error(prog, "Program needs to contain both vertex and " - "fragment shaders.\n"); - } + if (!prog->SeparateShader && ctx->API == API_OPENGLES2 && + num_shaders[MESA_SHADER_COMPUTE] == 0) { + if (prog->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) { + linker_error(prog, "program lacks a vertex shader\n"); + } else if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL) { + linker_error(prog, "program lacks a fragment shader\n"); } } |