From d656736bbf926c219b6bcbc0ad59132fc82a7382 Mon Sep 17 00:00:00 2001 From: Tobias Klausmann Date: Sun, 8 May 2016 22:44:06 +0200 Subject: [PATCH] glsl: Add arb_cull_distance support (v3) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit v2: make too large array a compile error v3: squash mesa/prog patch to avoid static compiler errors in bisect Signed-off-by: Tobias Klausmann Signed-off-by: Dave Airlie Reviewed-by: Kristian Høgsberg --- src/compiler/glsl/ast_to_hir.cpp | 46 +++++--- src/compiler/glsl/builtin_variables.cpp | 11 +- src/compiler/glsl/glcpp/glcpp-parse.y | 3 + src/compiler/glsl/glsl_parser_extras.cpp | 1 + src/compiler/glsl/glsl_parser_extras.h | 8 ++ src/compiler/glsl/link_varyings.cpp | 10 ++ src/compiler/glsl/link_varyings.h | 1 + src/compiler/glsl/linker.cpp | 108 ++++++++++++++----- src/compiler/glsl/standalone_scaffolding.cpp | 1 + src/compiler/glsl/tests/varyings_test.cpp | 27 +++++ src/compiler/shader_enums.h | 4 + src/mesa/program/prog_print.c | 4 + 12 files changed, 185 insertions(+), 39 deletions(-) diff --git a/src/compiler/glsl/ast_to_hir.cpp b/src/compiler/glsl/ast_to_hir.cpp index 5a1fc9f68ac..338edc86676 100644 --- a/src/compiler/glsl/ast_to_hir.cpp +++ b/src/compiler/glsl/ast_to_hir.cpp @@ -1196,20 +1196,38 @@ check_builtin_array_max_size(const char *name, unsigned size, _mesa_glsl_error(&loc, state, "`gl_TexCoord' array size cannot " "be larger than gl_MaxTextureCoords (%u)", state->Const.MaxTextureCoords); - } else if (strcmp("gl_ClipDistance", name) == 0 - && size > state->Const.MaxClipPlanes) { - /* From section 7.1 (Vertex Shader Special Variables) of the - * GLSL 1.30 spec: - * - * "The gl_ClipDistance array is predeclared as unsized and - * must be sized by the shader either redeclaring it with a - * size or indexing it only with integral constant - * expressions. ... The size can be at most - * gl_MaxClipDistances." - */ - _mesa_glsl_error(&loc, state, "`gl_ClipDistance' array size cannot " - "be larger than gl_MaxClipDistances (%u)", - state->Const.MaxClipPlanes); + } else if (strcmp("gl_ClipDistance", name) == 0) { + state->clip_dist_size = size; + if (size + state->cull_dist_size > state->Const.MaxClipPlanes) { + /* From section 7.1 (Vertex Shader Special Variables) of the + * GLSL 1.30 spec: + * + * "The gl_ClipDistance array is predeclared as unsized and + * must be sized by the shader either redeclaring it with a + * size or indexing it only with integral constant + * expressions. ... The size can be at most + * gl_MaxClipDistances." + */ + _mesa_glsl_error(&loc, state, "`gl_ClipDistance' array size cannot " + "be larger than gl_MaxClipDistances (%u)", + state->Const.MaxClipPlanes); + } + } else if (strcmp("gl_CullDistance", name) == 0) { + state->cull_dist_size = size; + if (size + state->clip_dist_size > state->Const.MaxClipPlanes) { + /* From the ARB_cull_distance spec: + * + * "The gl_CullDistance array is predeclared as unsized and + * must be sized by the shader either redeclaring it with + * a size or indexing it only with integral constant + * expressions. The size determines the number and set of + * enabled cull distances and can be at most + * gl_MaxCullDistances." + */ + _mesa_glsl_error(&loc, state, "`gl_CullDistance' array size cannot " + "be larger than gl_MaxCullDistances (%u)", + state->Const.MaxClipPlanes); + } } } diff --git a/src/compiler/glsl/builtin_variables.cpp b/src/compiler/glsl/builtin_variables.cpp index cc32990fc2f..ff8a7e2db5e 100644 --- a/src/compiler/glsl/builtin_variables.cpp +++ b/src/compiler/glsl/builtin_variables.cpp @@ -302,7 +302,7 @@ public: const glsl_type *construct_interface_instance() const; private: - glsl_struct_field fields[10]; + glsl_struct_field fields[11]; unsigned num_fields; }; @@ -678,6 +678,11 @@ builtin_variable_generator::generate_constants() add_const("gl_MaxClipDistances", state->Const.MaxClipPlanes); add_const("gl_MaxVaryingComponents", state->ctx->Const.MaxVarying * 4); } + if (state->is_version(450, 0) || state->ARB_cull_distance_enable) { + add_const("gl_MaxCullDistances", state->Const.MaxClipPlanes); + add_const("gl_MaxCombinedClipAndCullDistances", + state->Const.MaxClipPlanes); + } if (state->has_geometry_shader()) { add_const("gl_MaxVertexOutputComponents", @@ -1249,6 +1254,10 @@ builtin_variable_generator::generate_varyings() add_varying(VARYING_SLOT_CLIP_DIST0, array(float_t, 0), "gl_ClipDistance"); } + if (state->is_version(450, 0) || state->ARB_cull_distance_enable) { + add_varying(VARYING_SLOT_CULL_DIST0, array(float_t, 0), + "gl_CullDistance"); + } if (compatibility) { add_varying(VARYING_SLOT_TEX0, array(vec4_t, 0), "gl_TexCoord"); diff --git a/src/compiler/glsl/glcpp/glcpp-parse.y b/src/compiler/glsl/glcpp/glcpp-parse.y index a48266cf1b2..e44f0749e85 100644 --- a/src/compiler/glsl/glcpp/glcpp-parse.y +++ b/src/compiler/glsl/glcpp/glcpp-parse.y @@ -2457,6 +2457,9 @@ _glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t versio if (extensions->ARB_shader_draw_parameters) add_builtin_define(parser, "GL_ARB_shader_draw_parameters", 1); + + if (extensions->ARB_cull_distance) + add_builtin_define(parser, "GL_ARB_cull_distance", 1); } } diff --git a/src/compiler/glsl/glsl_parser_extras.cpp b/src/compiler/glsl/glsl_parser_extras.cpp index 463cb9730ea..771fd197221 100644 --- a/src/compiler/glsl/glsl_parser_extras.cpp +++ b/src/compiler/glsl/glsl_parser_extras.cpp @@ -576,6 +576,7 @@ static const _mesa_glsl_extension _mesa_glsl_supported_extensions[] = { EXT(ARB_arrays_of_arrays, true, false, ARB_arrays_of_arrays), EXT(ARB_compute_shader, true, false, ARB_compute_shader), EXT(ARB_conservative_depth, true, false, ARB_conservative_depth), + EXT(ARB_cull_distance, true, false, ARB_cull_distance), EXT(ARB_derivative_control, true, false, ARB_derivative_control), EXT(ARB_draw_buffers, true, false, dummy_true), EXT(ARB_draw_instanced, true, false, ARB_draw_instanced), diff --git a/src/compiler/glsl/glsl_parser_extras.h b/src/compiler/glsl/glsl_parser_extras.h index 70183473b9e..aaf12dddff0 100644 --- a/src/compiler/glsl/glsl_parser_extras.h +++ b/src/compiler/glsl/glsl_parser_extras.h @@ -520,6 +520,8 @@ struct _mesa_glsl_parse_state { bool ARB_compute_shader_warn; bool ARB_conservative_depth_enable; bool ARB_conservative_depth_warn; + bool ARB_cull_distance_enable; + bool ARB_cull_distance_warn; bool ARB_derivative_control_enable; bool ARB_derivative_control_warn; bool ARB_draw_buffers_enable; @@ -702,6 +704,12 @@ struct _mesa_glsl_parse_state { * did the parser just parse a dot. */ bool is_field; + + /** + * seen values for clip/cull distance sizes + * so we can check totals aren't too large. + */ + unsigned clip_dist_size, cull_dist_size; }; # define YYLLOC_DEFAULT(Current, Rhs, N) \ diff --git a/src/compiler/glsl/link_varyings.cpp b/src/compiler/glsl/link_varyings.cpp index 2555cc94176..003b9d46abc 100644 --- a/src/compiler/glsl/link_varyings.cpp +++ b/src/compiler/glsl/link_varyings.cpp @@ -631,6 +631,10 @@ tfeedback_decl::init(struct gl_context *ctx, const void *mem_ctx, strcmp(this->var_name, "gl_ClipDistance") == 0) { this->lowered_builtin_array_variable = clip_distance; } + if (ctx->Const.ShaderCompilerOptions[MESA_SHADER_VERTEX].LowerCombinedClipCullDistance && + strcmp(this->var_name, "gl_CullDistance") == 0) { + this->lowered_builtin_array_variable = cull_distance; + } if (ctx->Const.LowerTessLevel && (strcmp(this->var_name, "gl_TessLevelOuter") == 0)) @@ -691,6 +695,9 @@ tfeedback_decl::assign_location(struct gl_context *ctx, case clip_distance: actual_array_size = prog->LastClipDistanceArraySize; break; + case cull_distance: + actual_array_size = prog->LastCullDistanceArraySize; + break; case tess_level_outer: actual_array_size = 4; break; @@ -911,6 +918,9 @@ tfeedback_decl::find_candidate(gl_shader_program *prog, case clip_distance: name = "gl_ClipDistanceMESA"; break; + case cull_distance: + name = "gl_CullDistanceMESA"; + break; case tess_level_outer: name = "gl_TessLevelOuterMESA"; break; diff --git a/src/compiler/glsl/link_varyings.h b/src/compiler/glsl/link_varyings.h index 543b80ff29b..0ad4f740502 100644 --- a/src/compiler/glsl/link_varyings.h +++ b/src/compiler/glsl/link_varyings.h @@ -210,6 +210,7 @@ private: enum { none, clip_distance, + cull_distance, tess_level_outer, tess_level_inner, } lowered_builtin_array_variable; diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp index a85072d7de5..eae1065572c 100644 --- a/src/compiler/glsl/linker.cpp +++ b/src/compiler/glsl/linker.cpp @@ -641,19 +641,25 @@ link_invalidate_variable_locations(exec_list *ir) /** - * Set clip_distance_array_size based on the given shader. + * Set clip_distance_array_size based and cull_distance_array_size on the given + * shader. * * Also check for errors based on incorrect usage of gl_ClipVertex and - * gl_ClipDistance. + * gl_ClipDistance and gl_CullDistance. + * Additionally test whether the arrays gl_ClipDistance and gl_CullDistance + * exceed the maximum size defined by gl_MaxCombinedClipAndCullDistances. * * Return false if an error was reported. */ static void -analyze_clip_usage(struct gl_shader_program *prog, - struct gl_shader *shader, - GLuint *clip_distance_array_size) +analyze_clip_cull_usage(struct gl_shader_program *prog, + struct gl_shader *shader, + struct gl_context *ctx, + GLuint *clip_distance_array_size, + GLuint *cull_distance_array_size) { *clip_distance_array_size = 0; + *cull_distance_array_size = 0; if (!prog->IsES && prog->Version >= 130) { /* From section 7.1 (Vertex Shader Special Variables) of the @@ -667,23 +673,62 @@ analyze_clip_usage(struct gl_shader_program *prog, */ find_assignment_visitor clip_vertex("gl_ClipVertex"); find_assignment_visitor clip_distance("gl_ClipDistance"); + find_assignment_visitor cull_distance("gl_CullDistance"); clip_vertex.run(shader->ir); clip_distance.run(shader->ir); + cull_distance.run(shader->ir); + + /* From the ARB_cull_distance spec: + * + * It is a compile-time or link-time error for the set of shaders forming + * a program to statically read or write both gl_ClipVertex and either + * gl_ClipDistance or gl_CullDistance. + * + * This does not apply to GLSL ES shaders, since GLSL ES defines neither + * gl_ClipVertex, gl_ClipDistance or gl_CullDistance. + */ if (clip_vertex.variable_found() && clip_distance.variable_found()) { linker_error(prog, "%s shader writes to both `gl_ClipVertex' " "and `gl_ClipDistance'\n", _mesa_shader_stage_to_string(shader->Stage)); return; } + if (clip_vertex.variable_found() && cull_distance.variable_found()) { + linker_error(prog, "%s shader writes to both `gl_ClipVertex' " + "and `gl_CullDistance'\n", + _mesa_shader_stage_to_string(shader->Stage)); + return; + } if (clip_distance.variable_found()) { ir_variable *clip_distance_var = - shader->symbols->get_variable("gl_ClipDistance"); - + shader->symbols->get_variable("gl_ClipDistance"); assert(clip_distance_var); *clip_distance_array_size = clip_distance_var->type->length; } + if (cull_distance.variable_found()) { + ir_variable *cull_distance_var = + shader->symbols->get_variable("gl_CullDistance"); + assert(cull_distance_var); + *cull_distance_array_size = cull_distance_var->type->length; + } + /* From the ARB_cull_distance spec: + * + * It is a compile-time or link-time error for the set of shaders forming + * a program to have the sum of the sizes of the gl_ClipDistance and + * gl_CullDistance arrays to be larger than + * gl_MaxCombinedClipAndCullDistances. + */ + if ((*clip_distance_array_size + *cull_distance_array_size) > + ctx->Const.MaxClipPlanes) { + linker_error(prog, "%s shader: the combined size of " + "'gl_ClipDistance' and 'gl_CullDistance' size cannot " + "be larger than " + "gl_MaxCombinedClipAndCullDistances (%u)", + _mesa_shader_stage_to_string(shader->Stage), + ctx->Const.MaxClipPlanes); + } } } @@ -691,13 +736,15 @@ analyze_clip_usage(struct gl_shader_program *prog, /** * Verify that a vertex shader executable meets all semantic requirements. * - * Also sets prog->Vert.ClipDistanceArraySize as a side effect. + * Also sets prog->Vert.ClipDistanceArraySize and + * prog->Vert.CullDistanceArraySize as a side effect. * * \param shader Vertex shader executable to be verified */ void validate_vertex_shader_executable(struct gl_shader_program *prog, - struct gl_shader *shader) + struct gl_shader *shader, + struct gl_context *ctx) { if (shader == NULL) return; @@ -744,17 +791,22 @@ validate_vertex_shader_executable(struct gl_shader_program *prog, } } - analyze_clip_usage(prog, shader, &prog->Vert.ClipDistanceArraySize); + analyze_clip_cull_usage(prog, shader, ctx, + &prog->Vert.ClipDistanceArraySize, + &prog->Vert.CullDistanceArraySize); } void validate_tess_eval_shader_executable(struct gl_shader_program *prog, - struct gl_shader *shader) + struct gl_shader *shader, + struct gl_context *ctx) { if (shader == NULL) return; - analyze_clip_usage(prog, shader, &prog->TessEval.ClipDistanceArraySize); + analyze_clip_cull_usage(prog, shader, ctx, + &prog->TessEval.ClipDistanceArraySize, + &prog->TessEval.CullDistanceArraySize); } @@ -765,7 +817,7 @@ validate_tess_eval_shader_executable(struct gl_shader_program *prog, */ void validate_fragment_shader_executable(struct gl_shader_program *prog, - struct gl_shader *shader) + struct gl_shader *shader) { if (shader == NULL) return; @@ -785,14 +837,15 @@ validate_fragment_shader_executable(struct gl_shader_program *prog, /** * Verify that a geometry shader executable meets all semantic requirements * - * Also sets prog->Geom.VerticesIn, and prog->Geom.ClipDistanceArraySize as - * a side effect. + * Also sets prog->Geom.VerticesIn, and prog->Geom.ClipDistanceArraySize and + * prog->Geom.CullDistanceArraySize as a side effect. * * \param shader Geometry shader executable to be verified */ void validate_geometry_shader_executable(struct gl_shader_program *prog, - struct gl_shader *shader) + struct gl_shader *shader, + struct gl_context *ctx) { if (shader == NULL) return; @@ -800,7 +853,9 @@ validate_geometry_shader_executable(struct gl_shader_program *prog, unsigned num_vertices = vertices_per_prim(prog->Geom.InputType); prog->Geom.VerticesIn = num_vertices; - analyze_clip_usage(prog, shader, &prog->Geom.ClipDistanceArraySize); + analyze_clip_cull_usage(prog, shader, ctx, + &prog->Geom.ClipDistanceArraySize, + &prog->Geom.CullDistanceArraySize); } /** @@ -4427,16 +4482,16 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) switch (stage) { case MESA_SHADER_VERTEX: - validate_vertex_shader_executable(prog, sh); + validate_vertex_shader_executable(prog, sh, ctx); break; case MESA_SHADER_TESS_CTRL: /* nothing to be done */ break; case MESA_SHADER_TESS_EVAL: - validate_tess_eval_shader_executable(prog, sh); + validate_tess_eval_shader_executable(prog, sh, ctx); break; case MESA_SHADER_GEOMETRY: - validate_geometry_shader_executable(prog, sh); + validate_geometry_shader_executable(prog, sh, ctx); break; case MESA_SHADER_FRAGMENT: validate_fragment_shader_executable(prog, sh); @@ -4452,14 +4507,19 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) } } - if (num_shaders[MESA_SHADER_GEOMETRY] > 0) + if (num_shaders[MESA_SHADER_GEOMETRY] > 0) { prog->LastClipDistanceArraySize = prog->Geom.ClipDistanceArraySize; - else if (num_shaders[MESA_SHADER_TESS_EVAL] > 0) + prog->LastCullDistanceArraySize = prog->Geom.CullDistanceArraySize; + } else if (num_shaders[MESA_SHADER_TESS_EVAL] > 0) { prog->LastClipDistanceArraySize = prog->TessEval.ClipDistanceArraySize; - else if (num_shaders[MESA_SHADER_VERTEX] > 0) + prog->LastCullDistanceArraySize = prog->TessEval.CullDistanceArraySize; + } else if (num_shaders[MESA_SHADER_VERTEX] > 0) { prog->LastClipDistanceArraySize = prog->Vert.ClipDistanceArraySize; - else + prog->LastCullDistanceArraySize = prog->Vert.CullDistanceArraySize; + } else { prog->LastClipDistanceArraySize = 0; /* Not used */ + prog->LastCullDistanceArraySize = 0; /* Not used */ + } /* Here begins the inter-stage linking phase. Some initial validation is * performed, then locations are assigned for uniforms, attributes, and diff --git a/src/compiler/glsl/standalone_scaffolding.cpp b/src/compiler/glsl/standalone_scaffolding.cpp index 09d7d6e8c26..4edb7672cd0 100644 --- a/src/compiler/glsl/standalone_scaffolding.cpp +++ b/src/compiler/glsl/standalone_scaffolding.cpp @@ -152,6 +152,7 @@ void initialize_context_to_defaults(struct gl_context *ctx, gl_api api) ctx->Extensions.ARB_texture_query_lod = true; ctx->Extensions.ARB_uniform_buffer_object = true; ctx->Extensions.ARB_viewport_array = true; + ctx->Extensions.ARB_cull_distance = true; ctx->Extensions.OES_EGL_image_external = true; ctx->Extensions.OES_standard_derivatives = true; diff --git a/src/compiler/glsl/tests/varyings_test.cpp b/src/compiler/glsl/tests/varyings_test.cpp index 9be5e8344b4..936f49581d7 100644 --- a/src/compiler/glsl/tests/varyings_test.cpp +++ b/src/compiler/glsl/tests/varyings_test.cpp @@ -194,6 +194,33 @@ TEST_F(link_varyings, gl_ClipDistance) EXPECT_TRUE(is_empty(consumer_interface_inputs)); } +TEST_F(link_varyings, gl_CullDistance) +{ + const glsl_type *const array_8_of_float = + glsl_type::get_array_instance(glsl_type::vec(1), 8); + + ir_variable *const culldistance = + new(mem_ctx) ir_variable(array_8_of_float, + "gl_CullDistance", + ir_var_shader_in); + + culldistance->data.explicit_location = true; + culldistance->data.location = VARYING_SLOT_CULL_DIST0; + culldistance->data.explicit_index = 0; + + ir.push_tail(culldistance); + + ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx, + &ir, + consumer_inputs, + consumer_interface_inputs, + junk)); + + EXPECT_EQ(culldistance, junk[VARYING_SLOT_CULL_DIST0]); + EXPECT_TRUE(is_empty(consumer_inputs)); + EXPECT_TRUE(is_empty(consumer_interface_inputs)); +} + TEST_F(link_varyings, single_interface_input) { ir_variable *const v = diff --git a/src/compiler/shader_enums.h b/src/compiler/shader_enums.h index 0c2740866fd..e93345d973d 100644 --- a/src/compiler/shader_enums.h +++ b/src/compiler/shader_enums.h @@ -205,6 +205,8 @@ typedef enum VARYING_SLOT_CLIP_VERTEX, /* Does not appear in FS */ VARYING_SLOT_CLIP_DIST0, VARYING_SLOT_CLIP_DIST1, + VARYING_SLOT_CULL_DIST0, + VARYING_SLOT_CULL_DIST1, VARYING_SLOT_PRIMITIVE_ID, /* Does not appear in VS */ VARYING_SLOT_LAYER, /* Appears as VS or GS output */ VARYING_SLOT_VIEWPORT, /* Appears as VS or GS output */ @@ -282,6 +284,8 @@ const char *gl_varying_slot_name(gl_varying_slot slot); #define VARYING_BIT_CLIP_VERTEX BITFIELD64_BIT(VARYING_SLOT_CLIP_VERTEX) #define VARYING_BIT_CLIP_DIST0 BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST0) #define VARYING_BIT_CLIP_DIST1 BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST1) +#define VARYING_BIT_CULL_DIST0 BITFIELD64_BIT(VARYING_SLOT_CULL_DIST0) +#define VARYING_BIT_CULL_DIST1 BITFIELD64_BIT(VARYING_SLOT_CULL_DIST1) #define VARYING_BIT_PRIMITIVE_ID BITFIELD64_BIT(VARYING_SLOT_PRIMITIVE_ID) #define VARYING_BIT_LAYER BITFIELD64_BIT(VARYING_SLOT_LAYER) #define VARYING_BIT_VIEWPORT BITFIELD64_BIT(VARYING_SLOT_VIEWPORT) diff --git a/src/mesa/program/prog_print.c b/src/mesa/program/prog_print.c index 08381b42523..755d6440e4a 100644 --- a/src/mesa/program/prog_print.c +++ b/src/mesa/program/prog_print.c @@ -149,6 +149,8 @@ arb_input_attrib_string(GLuint index, GLenum progType) "fragment.(twenty-three)", /* VARYING_SLOT_PNTC */ "fragment.(twenty-four)", /* VARYING_SLOT_TESS_LEVEL_OUTER */ "fragment.(twenty-five)", /* VARYING_SLOT_TESS_LEVEL_INNER */ + "fragment.(twenty-six)", /* VARYING_SLOT_CULL_DIST0 */ + "fragment.(twenty-seven)", /* VARYING_SLOT_CULL_DIST1 */ "fragment.varying[0]", "fragment.varying[1]", "fragment.varying[2]", @@ -276,6 +278,8 @@ arb_output_attrib_string(GLuint index, GLenum progType) "result.(twenty-three)", /* VARYING_SLOT_PNTC */ "result.(twenty-four)", /* VARYING_SLOT_TESS_LEVEL_OUTER */ "result.(twenty-five)", /* VARYING_SLOT_TESS_LEVEL_INNER */ + "result.(twenty-six)", /* VARYING_SLOT_CULL_DIST0 */ + "result.(twenty-seven)", /* VARYING_SLOT_CULL_DIST1 */ "result.varying[0]", "result.varying[1]", "result.varying[2]", -- 2.30.2