From c750029b37c64521267910af0ec2c89c58c82987 Mon Sep 17 00:00:00 2001 From: Andres Gomez Date: Thu, 24 Mar 2016 01:13:26 +0200 Subject: [PATCH] glsl: Checks for interpolation into its own function. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This generalizes the validation also to be done for variables inside interface blocks, which, for some cases, was missing. For a discussion about the additional validation cases included see https://lists.freedesktop.org/archives/mesa-dev/2016-March/109117.html and Khronos bug #15671. Reviewed-by: Samuel Iglesias Gonsálvez Signed-off-by: Andres Gomez --- src/compiler/glsl/ast_to_hir.cpp | 316 +++++++++++++++++-------------- 1 file changed, 171 insertions(+), 145 deletions(-) diff --git a/src/compiler/glsl/ast_to_hir.cpp b/src/compiler/glsl/ast_to_hir.cpp index 82eb22a82c6..dd8e4e0553d 100644 --- a/src/compiler/glsl/ast_to_hir.cpp +++ b/src/compiler/glsl/ast_to_hir.cpp @@ -2792,8 +2792,164 @@ apply_explicit_binding(struct _mesa_glsl_parse_state *state, } +static void +validate_interpolation_qualifier(struct _mesa_glsl_parse_state *state, + YYLTYPE *loc, + const glsl_interp_qualifier interpolation, + const struct ast_type_qualifier *qual, + const struct glsl_type *var_type, + ir_variable_mode mode) +{ + /* Interpolation qualifiers can only apply to shader inputs or outputs, but + * not to vertex shader inputs nor fragment shader outputs. + * + * From section 4.3 ("Storage Qualifiers") of the GLSL 1.30 spec: + * "Outputs from a vertex shader (out) and inputs to a fragment + * shader (in) can be further qualified with one or more of these + * interpolation qualifiers" + * ... + * "These interpolation qualifiers may only precede the qualifiers in, + * centroid in, out, or centroid out in a declaration. They do not apply + * to the deprecated storage qualifiers varying or centroid + * varying. They also do not apply to inputs into a vertex shader or + * outputs from a fragment shader." + * + * From section 4.3 ("Storage Qualifiers") of the GLSL ES 3.00 spec: + * "Outputs from a shader (out) and inputs to a shader (in) can be + * further qualified with one of these interpolation qualifiers." + * ... + * "These interpolation qualifiers may only precede the qualifiers + * in, centroid in, out, or centroid out in a declaration. They do + * not apply to inputs into a vertex shader or outputs from a + * fragment shader." + */ + if (state->is_version(130, 300) + && interpolation != INTERP_QUALIFIER_NONE) { + const char *i = interpolation_string(interpolation); + if (mode != ir_var_shader_in && mode != ir_var_shader_out) + _mesa_glsl_error(loc, state, + "interpolation qualifier `%s' can only be applied to " + "shader inputs or outputs.", i); + + switch (state->stage) { + case MESA_SHADER_VERTEX: + if (mode == ir_var_shader_in) { + _mesa_glsl_error(loc, state, + "interpolation qualifier '%s' cannot be applied to " + "vertex shader inputs", i); + } + break; + case MESA_SHADER_FRAGMENT: + if (mode == ir_var_shader_out) { + _mesa_glsl_error(loc, state, + "interpolation qualifier '%s' cannot be applied to " + "fragment shader outputs", i); + } + break; + default: + break; + } + } + + /* Interpolation qualifiers cannot be applied to 'centroid' and + * 'centroid varying'. + * + * From section 4.3 ("Storage Qualifiers") of the GLSL 1.30 spec: + * "interpolation qualifiers may only precede the qualifiers in, + * centroid in, out, or centroid out in a declaration. They do not apply + * to the deprecated storage qualifiers varying or centroid varying." + * + * These deprecated storage qualifiers do not exist in GLSL ES 3.00. + */ + if (state->is_version(130, 0) + && interpolation != INTERP_QUALIFIER_NONE + && qual->flags.q.varying) { + + const char *i = interpolation_string(interpolation); + const char *s; + if (qual->flags.q.centroid) + s = "centroid varying"; + else + s = "varying"; + + _mesa_glsl_error(loc, state, + "qualifier '%s' cannot be applied to the " + "deprecated storage qualifier '%s'", i, s); + } + + /* Integer fragment inputs must be qualified with 'flat'. In GLSL ES, + * so must integer vertex outputs. + * + * From section 4.3.4 ("Inputs") of the GLSL 1.50 spec: + * "Fragment shader inputs that are signed or unsigned integers or + * integer vectors must be qualified with the interpolation qualifier + * flat." + * + * From section 4.3.4 ("Input Variables") of the GLSL 3.00 ES spec: + * "Fragment shader inputs that are, or contain, signed or unsigned + * integers or integer vectors must be qualified with the + * interpolation qualifier flat." + * + * From section 4.3.6 ("Output Variables") of the GLSL 3.00 ES spec: + * "Vertex shader outputs that are, or contain, signed or unsigned + * integers or integer vectors must be qualified with the + * interpolation qualifier flat." + * + * Note that prior to GLSL 1.50, this requirement applied to vertex + * outputs rather than fragment inputs. That creates problems in the + * presence of geometry shaders, so we adopt the GLSL 1.50 rule for all + * desktop GL shaders. For GLSL ES shaders, we follow the spec and + * apply the restriction to both vertex outputs and fragment inputs. + * + * Note also that the desktop GLSL specs are missing the text "or + * contain"; this is presumably an oversight, since there is no + * reasonable way to interpolate a fragment shader input that contains + * an integer. See Khronos bug #15671. + */ + if (state->is_version(130, 300) + && var_type->contains_integer() + && interpolation != INTERP_QUALIFIER_FLAT + && ((state->stage == MESA_SHADER_FRAGMENT && mode == ir_var_shader_in) + || (state->stage == MESA_SHADER_VERTEX && mode == ir_var_shader_out + && state->es_shader))) { + const char *shader_var_type = (state->stage == MESA_SHADER_VERTEX) ? + "vertex output" : "fragment input"; + _mesa_glsl_error(loc, state, "if a %s is (or contains) " + "an integer, then it must be qualified with 'flat'", + shader_var_type); + } + + /* Double fragment inputs must be qualified with 'flat'. + * + * From the "Overview" of the ARB_gpu_shader_fp64 extension spec: + * "This extension does not support interpolation of double-precision + * values; doubles used as fragment shader inputs must be qualified as + * "flat"." + * + * From section 4.3.4 ("Inputs") of the GLSL 4.00 spec: + * "Fragment shader inputs that are signed or unsigned integers, integer + * vectors, or any double-precision floating-point type must be + * qualified with the interpolation qualifier flat." + * + * Note that the GLSL specs are missing the text "or contain"; this is + * presumably an oversight. See Khronos bug #15671. + * + * The 'double' type does not exist in GLSL ES so far. + */ + if ((state->ARB_gpu_shader_fp64_enable + || state->is_version(400, 0)) + && var_type->contains_double() + && interpolation != INTERP_QUALIFIER_FLAT + && state->stage == MESA_SHADER_FRAGMENT + && mode == ir_var_shader_in) { + _mesa_glsl_error(loc, state, "if a fragment input is (or contains) " + "a double, then it must be qualified with 'flat'"); + } +} + static glsl_interp_qualifier interpret_interpolation_qualifier(const struct ast_type_qualifier *qual, + const struct glsl_type *var_type, ir_variable_mode mode, struct _mesa_glsl_parse_state *state, YYLTYPE *loc) @@ -2805,37 +2961,23 @@ interpret_interpolation_qualifier(const struct ast_type_qualifier *qual, interpolation = INTERP_QUALIFIER_NOPERSPECTIVE; else if (qual->flags.q.smooth) interpolation = INTERP_QUALIFIER_SMOOTH; - else - interpolation = INTERP_QUALIFIER_NONE; - - if (interpolation != INTERP_QUALIFIER_NONE) { - if (mode != ir_var_shader_in && mode != ir_var_shader_out) { - _mesa_glsl_error(loc, state, - "interpolation qualifier `%s' can only be applied to " - "shader inputs or outputs.", - interpolation_string(interpolation)); - - } - - if ((state->stage == MESA_SHADER_VERTEX && mode == ir_var_shader_in) || - (state->stage == MESA_SHADER_FRAGMENT && mode == ir_var_shader_out)) { - _mesa_glsl_error(loc, state, - "interpolation qualifier `%s' cannot be applied to " - "vertex shader inputs or fragment shader outputs", - interpolation_string(interpolation)); - } - } else if (state->es_shader && - ((mode == ir_var_shader_in && - state->stage != MESA_SHADER_VERTEX) || - (mode == ir_var_shader_out && - state->stage != MESA_SHADER_FRAGMENT))) { + else if (state->es_shader && + ((mode == ir_var_shader_in && + state->stage != MESA_SHADER_VERTEX) || + (mode == ir_var_shader_out && + state->stage != MESA_SHADER_FRAGMENT))) /* Section 4.3.9 (Interpolation) of the GLSL ES 3.00 spec says: * * "When no interpolation qualifier is present, smooth interpolation * is used." */ interpolation = INTERP_QUALIFIER_SMOOTH; - } + else + interpolation = INTERP_QUALIFIER_NONE; + + validate_interpolation_qualifier(state, loc, + interpolation, + qual, var_type, mode); return interpolation; } @@ -3575,7 +3717,8 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, } var->data.interpolation = - interpret_interpolation_qualifier(qual, (ir_variable_mode) var->data.mode, + interpret_interpolation_qualifier(qual, var->type, + (ir_variable_mode) var->data.mode, state, loc); /* Does the declaration use the deprecated 'attribute' or 'varying' @@ -4756,124 +4899,6 @@ ast_declarator_list::hir(exec_list *instructions, var->data.how_declared = ir_var_hidden; } - /* Integer fragment inputs must be qualified with 'flat'. In GLSL ES, - * so must integer vertex outputs. - * - * From section 4.3.4 ("Inputs") of the GLSL 1.50 spec: - * "Fragment shader inputs that are signed or unsigned integers or - * integer vectors must be qualified with the interpolation qualifier - * flat." - * - * From section 4.3.4 ("Input Variables") of the GLSL 3.00 ES spec: - * "Fragment shader inputs that are, or contain, signed or unsigned - * integers or integer vectors must be qualified with the - * interpolation qualifier flat." - * - * From section 4.3.6 ("Output Variables") of the GLSL 3.00 ES spec: - * "Vertex shader outputs that are, or contain, signed or unsigned - * integers or integer vectors must be qualified with the - * interpolation qualifier flat." - * - * Note that prior to GLSL 1.50, this requirement applied to vertex - * outputs rather than fragment inputs. That creates problems in the - * presence of geometry shaders, so we adopt the GLSL 1.50 rule for all - * desktop GL shaders. For GLSL ES shaders, we follow the spec and - * apply the restriction to both vertex outputs and fragment inputs. - * - * Note also that the desktop GLSL specs are missing the text "or - * contain"; this is presumably an oversight, since there is no - * reasonable way to interpolate a fragment shader input that contains - * an integer. - */ - if (state->is_version(130, 300) && - var->type->contains_integer() && - var->data.interpolation != INTERP_QUALIFIER_FLAT && - ((state->stage == MESA_SHADER_FRAGMENT && var->data.mode == ir_var_shader_in) - || (state->stage == MESA_SHADER_VERTEX && var->data.mode == ir_var_shader_out - && state->es_shader))) { - const char *var_type = (state->stage == MESA_SHADER_VERTEX) ? - "vertex output" : "fragment input"; - _mesa_glsl_error(&loc, state, "if a %s is (or contains) " - "an integer, then it must be qualified with 'flat'", - var_type); - } - - /* Double fragment inputs must be qualified with 'flat'. */ - if (var->type->contains_double() && - var->data.interpolation != INTERP_QUALIFIER_FLAT && - state->stage == MESA_SHADER_FRAGMENT && - var->data.mode == ir_var_shader_in) { - _mesa_glsl_error(&loc, state, "if a fragment input is (or contains) " - "a double, then it must be qualified with 'flat'", - var_type); - } - - /* Interpolation qualifiers cannot be applied to 'centroid' and - * 'centroid varying'. - * - * From page 29 (page 35 of the PDF) of the GLSL 1.30 spec: - * "interpolation qualifiers may only precede the qualifiers in, - * centroid in, out, or centroid out in a declaration. They do not apply - * to the deprecated storage qualifiers varying or centroid varying." - * - * These deprecated storage qualifiers do not exist in GLSL ES 3.00. - */ - if (state->is_version(130, 0) - && this->type->qualifier.has_interpolation() - && this->type->qualifier.flags.q.varying) { - - const char *i = interpolation_string(var->data.interpolation); - const char *s; - if (this->type->qualifier.flags.q.centroid) - s = "centroid varying"; - else - s = "varying"; - - _mesa_glsl_error(&loc, state, - "qualifier '%s' cannot be applied to the " - "deprecated storage qualifier '%s'", i, s); - } - - - /* Interpolation qualifiers can only apply to vertex shader outputs and - * fragment shader inputs. - * - * From page 29 (page 35 of the PDF) of the GLSL 1.30 spec: - * "Outputs from a vertex shader (out) and inputs to a fragment - * shader (in) can be further qualified with one or more of these - * interpolation qualifiers" - * - * From page 31 (page 37 of the PDF) of the GLSL ES 3.00 spec: - * "These interpolation qualifiers may only precede the qualifiers - * in, centroid in, out, or centroid out in a declaration. They do - * not apply to inputs into a vertex shader or outputs from a - * fragment shader." - */ - if (state->is_version(130, 300) - && this->type->qualifier.has_interpolation()) { - - const char *i = interpolation_string(var->data.interpolation); - switch (state->stage) { - case MESA_SHADER_VERTEX: - if (this->type->qualifier.flags.q.in) { - _mesa_glsl_error(&loc, state, - "qualifier '%s' cannot be applied to vertex " - "shader inputs", i); - } - break; - case MESA_SHADER_FRAGMENT: - if (this->type->qualifier.flags.q.out) { - _mesa_glsl_error(&loc, state, - "qualifier '%s' cannot be applied to fragment " - "shader outputs", i); - } - break; - default: - break; - } - } - - /* From section 4.3.4 of the GLSL 4.00 spec: * "Input variables may not be declared using the patch in qualifier * in tessellation control or geometry shaders." @@ -6608,7 +6633,8 @@ ast_process_struct_or_iface_block_members(exec_list *instructions, fields[i].type = field_type; fields[i].name = decl->identifier; fields[i].interpolation = - interpret_interpolation_qualifier(qual, var_mode, state, &loc); + interpret_interpolation_qualifier(qual, field_type, + var_mode, state, &loc); fields[i].centroid = qual->flags.q.centroid ? 1 : 0; fields[i].sample = qual->flags.q.sample ? 1 : 0; fields[i].patch = qual->flags.q.patch ? 1 : 0; -- 2.30.2