From cc6661bfc87f6a8a46455ddaf2e0fb1c1fd332ed Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Fri, 10 Apr 2020 16:02:09 -0400 Subject: [PATCH] glsl: add NV_viewport_array2 support MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This enables gl_Layer/gl_ViewportIndex when the ext is enabled, as well as adding the new gl_ViewportMask[] array and viewport_relative layout qualifier for gl_Layer. Signed-off-by: Ilia Mirkin Acked-by: Marek Olšák Part-of: --- src/compiler/glsl/ast.h | 6 ++++ src/compiler/glsl/ast_to_hir.cpp | 30 ++++++++++++++++ src/compiler/glsl/builtin_variables.cpp | 45 ++++++++++++++++++++++-- src/compiler/glsl/glsl_parser.yy | 19 ++++++++++ src/compiler/glsl/glsl_parser_extras.cpp | 2 ++ src/compiler/glsl/glsl_parser_extras.h | 6 ++++ src/compiler/glsl/linker.cpp | 36 +++++++++++++++++++ src/compiler/shader_info.h | 3 ++ src/mesa/main/mtypes.h | 6 ++++ 9 files changed, 150 insertions(+), 3 deletions(-) diff --git a/src/compiler/glsl/ast.h b/src/compiler/glsl/ast.h index f6487643d42..3a960c2ff32 100644 --- a/src/compiler/glsl/ast.h +++ b/src/compiler/glsl/ast.h @@ -663,6 +663,12 @@ struct ast_type_qualifier { /** \{ */ unsigned derivative_group:1; /** \} */ + + /** + * Flag set if GL_NV_viewport_array2 viewport_relative layout + * qualifier is used. + */ + unsigned viewport_relative:1; } /** \brief Set of flags, accessed by name. */ q; diff --git a/src/compiler/glsl/ast_to_hir.cpp b/src/compiler/glsl/ast_to_hir.cpp index b5b0a509ea1..1201c11b778 100644 --- a/src/compiler/glsl/ast_to_hir.cpp +++ b/src/compiler/glsl/ast_to_hir.cpp @@ -3548,6 +3548,16 @@ is_conflicting_fragcoord_redeclaration(struct _mesa_glsl_parse_state *state, return false; } +static inline bool +is_conflicting_layer_redeclaration(struct _mesa_glsl_parse_state *state, + const struct ast_type_qualifier *qual) +{ + if (state->redeclares_gl_layer) { + return state->layer_viewport_relative != qual->flags.q.viewport_relative; + } + return false; +} + static inline void validate_array_dimensions(const glsl_type *t, struct _mesa_glsl_parse_state *state, @@ -3937,6 +3947,21 @@ apply_layout_qualifier_to_variable(const struct ast_type_qualifier *qual, "sample_interlock_ordered and sample_interlock_unordered, " "only valid in fragment shader input layout declaration."); } + + if (var->name != NULL && strcmp(var->name, "gl_Layer") == 0) { + if (is_conflicting_layer_redeclaration(state, qual)) { + _mesa_glsl_error(loc, state, "gl_Layer redeclaration with " + "different viewport_relative setting than earlier"); + } + state->redeclares_gl_layer = 1; + if (qual->flags.q.viewport_relative) { + state->layer_viewport_relative = 1; + } + } else if (qual->flags.q.viewport_relative) { + _mesa_glsl_error(loc, state, + "viewport_relative qualifier " + "can only be applied to gl_Layer."); + } } static void @@ -4378,6 +4403,11 @@ get_variable_being_redeclared(ir_variable **var_ptr, YYLTYPE loc, earlier->data.precision = var->data.precision; earlier->data.memory_coherent = var->data.memory_coherent; + } else if (state->NV_viewport_array2_enable && + strcmp(var->name, "gl_Layer") == 0 && + earlier->data.how_declared == ir_var_declared_implicitly) { + /* No need to do anything, just allow it. Qualifier is stored in state */ + } else if ((earlier->data.how_declared == ir_var_declared_implicitly && state->allow_builtin_variable_redeclaration) || allow_all_redeclarations) { diff --git a/src/compiler/glsl/builtin_variables.cpp b/src/compiler/glsl/builtin_variables.cpp index 6f960837321..e305ab9b9b8 100644 --- a/src/compiler/glsl/builtin_variables.cpp +++ b/src/compiler/glsl/builtin_variables.cpp @@ -1097,15 +1097,32 @@ builtin_variable_generator::generate_vs_special_vars() add_system_value(SYSTEM_VALUE_DRAW_ID, int_t, "gl_DrawIDARB"); } if (state->AMD_vertex_shader_layer_enable || - state->ARB_shader_viewport_layer_array_enable) { + state->ARB_shader_viewport_layer_array_enable || + state->NV_viewport_array2_enable) { var = add_output(VARYING_SLOT_LAYER, int_t, "gl_Layer"); var->data.interpolation = INTERP_MODE_FLAT; } if (state->AMD_vertex_shader_viewport_index_enable || - state->ARB_shader_viewport_layer_array_enable) { + state->ARB_shader_viewport_layer_array_enable || + state->NV_viewport_array2_enable) { var = add_output(VARYING_SLOT_VIEWPORT, int_t, "gl_ViewportIndex"); var->data.interpolation = INTERP_MODE_FLAT; } + if (state->NV_viewport_array2_enable) { + /* From the NV_viewport_array2 specification: + * + * "The variable gl_ViewportMask[] is available as an output variable + * in the VTG languages. The array has ceil(v/32) elements where v is + * the maximum number of viewports supported by the implementation." + * + * Since no drivers expose more than 16 viewports, we can simply set the + * array size to 1 rather than computing it and dealing with varying + * slot complication. + */ + var = add_output(VARYING_SLOT_VIEWPORT_MASK, array(int_t, 1), + "gl_ViewportMask"); + var->data.interpolation = INTERP_MODE_FLAT; + } if (compatibility) { add_input(VERT_ATTRIB_POS, vec4_t, "gl_Vertex"); add_input(VERT_ATTRIB_NORMAL, vec3_t, "gl_Normal"); @@ -1155,6 +1172,17 @@ builtin_variable_generator::generate_tcs_special_vars() add_output(bbox_slot, array(vec4_t, 2), GLSL_PRECISION_HIGH, "gl_BoundingBox")->data.patch = 1; } + + /* NOTE: These are completely pointless. Writing these will never go + * anywhere. But the specs demands it. So we add them with a slot of -1, + * which makes the data go nowhere. + */ + if (state->NV_viewport_array2_enable) { + add_output(-1, int_t, "gl_Layer"); + add_output(-1, int_t, "gl_ViewportIndex"); + add_output(-1, array(int_t, 1), "gl_ViewportMask"); + } + } @@ -1183,12 +1211,18 @@ builtin_variable_generator::generate_tes_special_vars() add_system_value(SYSTEM_VALUE_TESS_LEVEL_INNER, array(float_t, 2), GLSL_PRECISION_HIGH, "gl_TessLevelInner"); } - if (state->ARB_shader_viewport_layer_array_enable) { + if (state->ARB_shader_viewport_layer_array_enable || + state->NV_viewport_array2_enable) { var = add_output(VARYING_SLOT_LAYER, int_t, "gl_Layer"); var->data.interpolation = INTERP_MODE_FLAT; var = add_output(VARYING_SLOT_VIEWPORT, int_t, "gl_ViewportIndex"); var->data.interpolation = INTERP_MODE_FLAT; } + if (state->NV_viewport_array2_enable) { + var = add_output(VARYING_SLOT_VIEWPORT_MASK, array(int_t, 1), + "gl_ViewportMask"); + var->data.interpolation = INTERP_MODE_FLAT; + } } @@ -1208,6 +1242,11 @@ builtin_variable_generator::generate_gs_special_vars() "gl_ViewportIndex"); var->data.interpolation = INTERP_MODE_FLAT; } + if (state->NV_viewport_array2_enable) { + var = add_output(VARYING_SLOT_VIEWPORT_MASK, array(int_t, 1), + "gl_ViewportMask"); + var->data.interpolation = INTERP_MODE_FLAT; + } if (state->is_version(400, 320) || state->ARB_gpu_shader5_enable || state->OES_geometry_shader_enable || state->EXT_geometry_shader_enable) { add_system_value(SYSTEM_VALUE_INVOCATION_ID, int_t, GLSL_PRECISION_HIGH, diff --git a/src/compiler/glsl/glsl_parser.yy b/src/compiler/glsl/glsl_parser.yy index dc8a8b3db01..944329a92d8 100644 --- a/src/compiler/glsl/glsl_parser.yy +++ b/src/compiler/glsl/glsl_parser.yy @@ -1709,6 +1709,25 @@ layout_qualifier_id: } } + /* Layout qualifier for NV_viewport_array2. */ + if (!$$.flags.i && state->stage != MESA_SHADER_FRAGMENT) { + if (match_layout_qualifier($1, "viewport_relative", state) == 0) { + $$.flags.q.viewport_relative = 1; + } + + if ($$.flags.i && !state->NV_viewport_array2_enable) { + _mesa_glsl_error(& @1, state, + "qualifier `%s' requires " + "GL_NV_viewport_array2", $1); + } + + if ($$.flags.i && state->NV_viewport_array2_warn) { + _mesa_glsl_warning(& @1, state, + "GL_NV_viewport_array2 layout " + "identifier `%s' used", $1); + } + } + if (!$$.flags.i) { _mesa_glsl_error(& @1, state, "unrecognized layout identifier " "`%s'", $1); diff --git a/src/compiler/glsl/glsl_parser_extras.cpp b/src/compiler/glsl/glsl_parser_extras.cpp index c6e3999caf5..4f6a493f71a 100644 --- a/src/compiler/glsl/glsl_parser_extras.cpp +++ b/src/compiler/glsl/glsl_parser_extras.cpp @@ -1929,6 +1929,8 @@ set_shader_inout_layout(struct gl_shader *shader, shader->bindless_image = state->bindless_image_specified; shader->bound_sampler = state->bound_sampler_specified; shader->bound_image = state->bound_image_specified; + shader->redeclares_gl_layer = state->redeclares_gl_layer; + shader->layer_viewport_relative = state->layer_viewport_relative; } /* src can be NULL if only the symbols found in the exec_list should be diff --git a/src/compiler/glsl/glsl_parser_extras.h b/src/compiler/glsl/glsl_parser_extras.h index dc94a5b94c1..b5e687d6038 100644 --- a/src/compiler/glsl/glsl_parser_extras.h +++ b/src/compiler/glsl/glsl_parser_extras.h @@ -884,6 +884,8 @@ struct _mesa_glsl_parse_state { bool NV_image_formats_warn; bool NV_shader_atomic_float_enable; bool NV_shader_atomic_float_warn; + bool NV_viewport_array2_enable; + bool NV_viewport_array2_warn; /*@}*/ /** Extensions supported by the OpenGL implementation. */ @@ -926,6 +928,10 @@ struct _mesa_glsl_parse_state { /** Atomic counter offsets by binding */ unsigned atomic_counter_offsets[MAX_COMBINED_ATOMIC_BUFFERS]; + /** Whether gl_Layer output is viewport-relative. */ + bool redeclares_gl_layer; + bool layer_viewport_relative; + bool allow_extension_directive_midshader; bool allow_builtin_variable_redeclaration; bool allow_layout_qualifier_on_function_parameter; diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp index e0f9c3d06de..292da60b9d9 100644 --- a/src/compiler/glsl/linker.cpp +++ b/src/compiler/glsl/linker.cpp @@ -1816,6 +1816,40 @@ link_bindless_layout_qualifiers(struct gl_shader_program *prog, } } +/** + * Check for conflicting viewport_relative settings across shaders, and sets + * the value for the linked shader. + */ +static void +link_layer_viewport_relative_qualifier(struct gl_shader_program *prog, + struct gl_program *gl_prog, + struct gl_shader **shader_list, + unsigned num_shaders) +{ + unsigned i; + + /* Find first shader with explicit layer declaration */ + for (i = 0; i < num_shaders; i++) { + if (shader_list[i]->redeclares_gl_layer) { + gl_prog->info.layer_viewport_relative = + shader_list[i]->layer_viewport_relative; + break; + } + } + + /* Now make sure that each subsequent shader's explicit layer declaration + * matches the first one's. + */ + for (; i < num_shaders; i++) { + if (shader_list[i]->redeclares_gl_layer && + shader_list[i]->layer_viewport_relative != + gl_prog->info.layer_viewport_relative) { + linker_error(prog, "all gl_Layer redeclarations must have identical " + "viewport_relative settings"); + } + } +} + /** * Performs the cross-validation of tessellation control shader vertices and * layout qualifiers for the attached tessellation control shaders, @@ -2461,6 +2495,8 @@ link_intrastage_shaders(void *mem_ctx, link_bindless_layout_qualifiers(prog, shader_list, num_shaders); + link_layer_viewport_relative_qualifier(prog, gl_prog, shader_list, num_shaders); + populate_symbol_table(linked, shader_list[0]->symbols); /* The pointer to the main function in the final linked shader (i.e., the diff --git a/src/compiler/shader_info.h b/src/compiler/shader_info.h index 13da17fa264..2e22614b75b 100644 --- a/src/compiler/shader_info.h +++ b/src/compiler/shader_info.h @@ -191,6 +191,9 @@ typedef struct shader_info { /* Whether the shader writes memory, including transform feedback. */ bool writes_memory:1; + /* Whether gl_Layer is viewport-relative */ + bool layer_viewport_relative:1; + union { struct { /* Which inputs are doubles */ diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 487e7e6f326..0f39041f73b 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2674,6 +2674,12 @@ struct gl_shader bool bound_sampler; bool bound_image; + /** + * Whether layer output is viewport-relative. + */ + bool redeclares_gl_layer; + bool layer_viewport_relative; + /** Global xfb_stride out qualifier if any */ GLuint TransformFeedbackBufferStride[MAX_FEEDBACK_BUFFERS]; -- 2.30.2