glsl: add NV_viewport_array2 support
authorIlia Mirkin <imirkin@alum.mit.edu>
Fri, 10 Apr 2020 20:02:09 +0000 (16:02 -0400)
committerIlia Mirkin <imirkin@alum.mit.edu>
Thu, 16 Apr 2020 00:12:00 +0000 (20:12 -0400)
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 <imirkin@alum.mit.edu>
Acked-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4529>

src/compiler/glsl/ast.h
src/compiler/glsl/ast_to_hir.cpp
src/compiler/glsl/builtin_variables.cpp
src/compiler/glsl/glsl_parser.yy
src/compiler/glsl/glsl_parser_extras.cpp
src/compiler/glsl/glsl_parser_extras.h
src/compiler/glsl/linker.cpp
src/compiler/shader_info.h
src/mesa/main/mtypes.h

index f6487643d42ced7dc379a2af3f15dc9d6289bad6..3a960c2ff327306b924657ffdad22569fc07e5aa 100644 (file)
@@ -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;
index b5b0a509ea1c808f93c48de5631de48c4e569eb0..1201c11b77810660e2d24fac26c32b2bd817f280 100644 (file)
@@ -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) {
index 6f96083732100cf41afb029bfffb822e750ffec3..e305ab9b9b8e32ff8f639a75e0a6e4f6dd64d912 100644 (file)
@@ -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,
index dc8a8b3db0147134b5192a552e8c48bf255e510f..944329a92d88b2890e6e8f8d0a4ee13f201778fc 100644 (file)
@@ -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);
index c6e3999caf5c08bc252a6cad8dab5add3b2a4c1c..4f6a493f71ae393b1c043a4e26a31ea78fcaafec 100644 (file)
@@ -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
index dc94a5b94c1a68d25b2fe21a871d926551f43394..b5e687d603865d448bce19869451333265cfd1e8 100644 (file)
@@ -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;
index e0f9c3d06de89636e9094d5ce5ade72c60e11630..292da60b9d9a12963bf6ece9dc85c05c85f164ed 100644 (file)
@@ -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
index 13da17fa264c32bc70f211b8c812ee90d973cb07..2e22614b75bdc82ab1f5112ca7883c73a03f8ad0 100644 (file)
@@ -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 */
index 487e7e6f3262a264b158e05dadec0635338f326d..0f39041f73b26c3588285afaa1d117451afa5254 100644 (file)
@@ -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];