glsl: Parse and propagate derivative_group to shader_info
authorCaio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Tue, 26 Mar 2019 07:04:57 +0000 (00:04 -0700)
committerCaio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Tue, 9 Apr 2019 02:29:32 +0000 (19:29 -0700)
NV_compute_shader_derivatives allow selecting between two possible
arrangements (quads and linear) when calculating derivatives and
certain subgroup operations in case of Vulkan.  So parse and propagate
those up to shader_info.h.

v2: Do not fail when ARB_compute_variable_group_size is being used,
    since we are still clarifying what is the right thing to do here.

Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
src/compiler/glsl/ast.h
src/compiler/glsl/ast_type.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_enums.h
src/compiler/shader_info.h
src/mesa/main/mtypes.h

index 94bcf644a26953291239104cdbbe710ec2e580cc..90a35654aeb158a810456ce8f02b38f27f2f6945 100644 (file)
@@ -654,6 +654,11 @@ struct ast_type_qualifier {
          /** \{ */
          unsigned non_coherent:1;
          /** \} */
+
+         /** \name Layout qualifiers for NV_compute_shader_derivatives */
+         /** \{ */
+         unsigned derivative_group:1;
+         /** \} */
       }
       /** \brief Set of flags, accessed by name. */
       q;
@@ -766,6 +771,12 @@ struct ast_type_qualifier {
     */
    GLenum image_format;
 
+   /**
+    * Arrangement of invocations used to calculate derivatives in a compute
+    * shader.  From NV_compute_shader_derivatives.
+    */
+   enum gl_derivative_group derivative_group;
+
    /**
     * Base type of the data read from or written to this image.  Only
     * the following enumerants are allowed: GLSL_TYPE_UINT,
index c2b6e6b3c2b4559b5dbb5757adc06c7acfa02634..b499ee913e7d914caba4c9efffd7becd5e945d67 100644 (file)
@@ -444,6 +444,11 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    if (q.flags.q.bound_image)
       this->flags.q.bound_image = true;
 
+   if (q.flags.q.derivative_group) {
+      this->flags.q.derivative_group = true;
+      this->derivative_group = q.derivative_group;
+   }
+
    this->flags.i |= q.flags.i;
 
    if (this->flags.q.in &&
@@ -645,6 +650,7 @@ ast_type_qualifier::validate_in_qualifier(YYLTYPE *loc,
    case MESA_SHADER_COMPUTE:
       valid_in_mask.flags.q.local_size = 7;
       valid_in_mask.flags.q.local_size_variable = 1;
+      valid_in_mask.flags.q.derivative_group = 1;
       break;
    default:
       r = false;
@@ -741,6 +747,19 @@ ast_type_qualifier::merge_into_in_qualifier(YYLTYPE *loc,
       r = false;
    }
 
+   if (state->in_qualifier->flags.q.derivative_group) {
+      if (state->cs_derivative_group != DERIVATIVE_GROUP_NONE) {
+         if (state->in_qualifier->derivative_group != DERIVATIVE_GROUP_NONE &&
+             state->cs_derivative_group != state->in_qualifier->derivative_group) {
+            _mesa_glsl_error(loc, state,
+                             "conflicting derivative groups.");
+            r = false;
+         }
+      } else {
+         state->cs_derivative_group = state->in_qualifier->derivative_group;
+      }
+   }
+
    /* We allow the creation of multiple cs_input_layout nodes. Coherence among
     * all existing nodes is checked later, when the AST node is transformed
     * into HIR.
index ddb54f4a4d6e9d718816aa3656ba481a6e78d83f..8d6c47fb6a3ac29516c9df9fe7fe084168e0683c 100644 (file)
@@ -1655,6 +1655,37 @@ layout_qualifier_id:
             $$.flags.q.non_coherent = 1;
       }
 
+      // Layout qualifiers for NV_compute_shader_derivatives.
+      if (!$$.flags.i) {
+         if (match_layout_qualifier($1, "derivative_group_quadsNV", state) == 0) {
+            $$.flags.q.derivative_group = 1;
+            $$.derivative_group = DERIVATIVE_GROUP_QUADS;
+         } else if (match_layout_qualifier($1, "derivative_group_linearNV", state) == 0) {
+            $$.flags.q.derivative_group = 1;
+            $$.derivative_group = DERIVATIVE_GROUP_LINEAR;
+         }
+
+         if ($$.flags.i) {
+            if (!state->has_compute_shader()) {
+               _mesa_glsl_error(& @1, state,
+                                "qualifier `%s' requires "
+                                "a compute shader", $1);
+            }
+
+            if (!state->NV_compute_shader_derivatives_enable) {
+               _mesa_glsl_error(& @1, state,
+                                "qualifier `%s' requires "
+                                "NV_compute_shader_derivatives", $1);
+            }
+
+            if (state->NV_compute_shader_derivatives_warn) {
+               _mesa_glsl_warning(& @1, state,
+                                  "NV_compute_shader_derivatives layout "
+                                  "qualifier `%s' used", $1);
+            }
+         }
+      }
+
       if (!$$.flags.i) {
          _mesa_glsl_error(& @1, state, "unrecognized layout identifier "
                           "`%s'", $1);
index ec196299b6a6c60bfb47afabbf33d388b949c218..c1c3c9649fe363f5d2e2f110a273d7c068d3362d 100644 (file)
@@ -1717,7 +1717,8 @@ set_shader_inout_layout(struct gl_shader *shader,
 {
    /* Should have been prevented by the parser. */
    if (shader->Stage != MESA_SHADER_GEOMETRY &&
-       shader->Stage != MESA_SHADER_TESS_EVAL) {
+       shader->Stage != MESA_SHADER_TESS_EVAL &&
+       shader->Stage != MESA_SHADER_COMPUTE) {
       assert(!state->in_qualifier->flags.i);
    }
 
@@ -1725,6 +1726,7 @@ set_shader_inout_layout(struct gl_shader *shader,
       /* Should have been prevented by the parser. */
       assert(!state->cs_input_local_size_specified);
       assert(!state->cs_input_local_size_variable_specified);
+      assert(state->cs_derivative_group == DERIVATIVE_GROUP_NONE);
    }
 
    if (shader->Stage != MESA_SHADER_FRAGMENT) {
@@ -1849,6 +1851,36 @@ set_shader_inout_layout(struct gl_shader *shader,
 
       shader->info.Comp.LocalSizeVariable =
          state->cs_input_local_size_variable_specified;
+
+      shader->info.Comp.DerivativeGroup = state->cs_derivative_group;
+
+      if (state->NV_compute_shader_derivatives_enable) {
+         /* We allow multiple cs_input_layout nodes, but do not store them in
+          * a convenient place, so for now live with an empty location error.
+          */
+         YYLTYPE loc = {0};
+         if (shader->info.Comp.DerivativeGroup == DERIVATIVE_GROUP_QUADS) {
+            if (shader->info.Comp.LocalSize[0] % 2 != 0) {
+               _mesa_glsl_error(&loc, state, "derivative_group_quadsNV must be used with a "
+                                "local group size whose first dimension "
+                                "is a multiple of 2\n");
+            }
+            if (shader->info.Comp.LocalSize[1] % 2 != 0) {
+               _mesa_glsl_error(&loc, state, "derivative_group_quadsNV must be used with a "
+                                "local group size whose second dimension "
+                                "is a multiple of 2\n");
+            }
+         } else if (shader->info.Comp.DerivativeGroup == DERIVATIVE_GROUP_LINEAR) {
+            if ((shader->info.Comp.LocalSize[0] *
+                 shader->info.Comp.LocalSize[1] *
+                 shader->info.Comp.LocalSize[2]) % 4 != 0) {
+               _mesa_glsl_error(&loc, state, "derivative_group_linearNV must be used with a "
+                            "local group size whose total number of invocations "
+                            "is a multiple of 4\n");
+            }
+         }
+      }
+
       break;
 
    case MESA_SHADER_FRAGMENT:
index 295612e9aed299da4523fc547908f153024f0405..82a2ce3424be2a171db07981b9f2b4bbbdd66ba3 100644 (file)
@@ -445,6 +445,12 @@ struct _mesa_glsl_parse_state {
     */
    bool cs_input_local_size_variable_specified;
 
+   /**
+    * Arrangement of invocations used to calculate derivatives in a compute
+    * shader.  From NV_compute_shader_derivatives.
+    */
+   enum gl_derivative_group cs_derivative_group;
+
    /**
     * True if a shader declare bindless_sampler/bindless_image, and
     * respectively bound_sampler/bound_image at global scope as specified by
index c6664e98ce3754267b7eace0c7ebdea165f50dc1..5667fb73f1e60414caefbb3840c3a8049d88f1b9 100644 (file)
@@ -2170,9 +2170,9 @@ link_gs_inout_layout_qualifiers(struct gl_shader_program *prog,
 
 
 /**
- * Perform cross-validation of compute shader local_size_{x,y,z} layout
- * qualifiers for the attached compute shaders, and propagate them to the
- * linked CS and linked shader program.
+ * Perform cross-validation of compute shader local_size_{x,y,z} layout and
+ * derivative arrangement qualifiers for the attached compute shaders, and
+ * propagate them to the linked CS and linked shader program.
  */
 static void
 link_cs_input_layout_qualifiers(struct gl_shader_program *prog,
@@ -2191,6 +2191,8 @@ link_cs_input_layout_qualifiers(struct gl_shader_program *prog,
 
    gl_prog->info.cs.local_size_variable = false;
 
+   gl_prog->info.cs.derivative_group = DERIVATIVE_GROUP_NONE;
+
    /* From the ARB_compute_shader spec, in the section describing local size
     * declarations:
     *
@@ -2234,6 +2236,17 @@ link_cs_input_layout_qualifiers(struct gl_shader_program *prog,
          }
          gl_prog->info.cs.local_size_variable = true;
       }
+
+      enum gl_derivative_group group = shader->info.Comp.DerivativeGroup;
+      if (group != DERIVATIVE_GROUP_NONE) {
+         if (gl_prog->info.cs.derivative_group != DERIVATIVE_GROUP_NONE &&
+             gl_prog->info.cs.derivative_group != group) {
+            linker_error(prog, "compute shader defined with conflicting "
+                         "derivative groups\n");
+            return;
+         }
+         gl_prog->info.cs.derivative_group = group;
+      }
    }
 
    /* Just do the intrastage -> interstage propagation right now,
@@ -2246,6 +2259,30 @@ link_cs_input_layout_qualifiers(struct gl_shader_program *prog,
                          "local group size\n");
       return;
    }
+
+   if (gl_prog->info.cs.derivative_group == DERIVATIVE_GROUP_QUADS) {
+      if (gl_prog->info.cs.local_size[0] % 2 != 0) {
+         linker_error(prog, "derivative_group_quadsNV must be used with a "
+                      "local group size whose first dimension "
+                      "is a multiple of 2\n");
+         return;
+      }
+      if (gl_prog->info.cs.local_size[1] % 2 != 0) {
+         linker_error(prog, "derivative_group_quadsNV must be used with a local"
+                      "group size whose second dimension "
+                      "is a multiple of 2\n");
+         return;
+      }
+   } else if (gl_prog->info.cs.derivative_group == DERIVATIVE_GROUP_LINEAR) {
+      if ((gl_prog->info.cs.local_size[0] *
+           gl_prog->info.cs.local_size[1] *
+           gl_prog->info.cs.local_size[2]) % 4 != 0) {
+         linker_error(prog, "derivative_group_linearNV must be used with a "
+                      "local group size whose total number of invocations "
+                      "is a multiple of 4\n");
+         return;
+      }
+   }
 }
 
 /**
index 883b282514673fee65bb8342037d43d143349564..f9a4006f0728c7f754c48e689936344ad8050ceb 100644 (file)
@@ -772,6 +772,47 @@ enum compare_func
    COMPARE_FUNC_ALWAYS,
 };
 
+/**
+ * Arrangements for grouping invocations from NV_compute_shader_derivatives.
+ *
+ *   The extension provides new layout qualifiers that support two different
+ *   arrangements of compute shader invocations for the purpose of derivative
+ *   computation.  When specifying
+ *
+ *     layout(derivative_group_quadsNV) in;
+ *
+ *   compute shader invocations are grouped into 2x2x1 arrays whose four local
+ *   invocation ID values follow the pattern:
+ *
+ *       +-----------------+------------------+
+ *       | (2x+0, 2y+0, z) |  (2x+1, 2y+0, z) |
+ *       +-----------------+------------------+
+ *       | (2x+0, 2y+1, z) |  (2x+1, 2y+1, z) |
+ *       +-----------------+------------------+
+ *
+ *   where Y increases from bottom to top.  When specifying
+ *
+ *     layout(derivative_group_linearNV) in;
+ *
+ *   compute shader invocations are grouped into 2x2x1 arrays whose four local
+ *   invocation index values follow the pattern:
+ *
+ *       +------+------+
+ *       | 4n+0 | 4n+1 |
+ *       +------+------+
+ *       | 4n+2 | 4n+3 |
+ *       +------+------+
+ *
+ *   If neither layout qualifier is specified, derivatives in compute shaders
+ *   return zero, which is consistent with the handling of built-in texture
+ *   functions like texture() in GLSL 4.50 compute shaders.
+ */
+enum gl_derivative_group {
+   DERIVATIVE_GROUP_NONE = 0,
+   DERIVATIVE_GROUP_QUADS,
+   DERIVATIVE_GROUP_LINEAR,
+};
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
index ef195760acbbdd4083adad5ca2f0b64bfc59c221..78f4032362a51cf39c90969397d735dfa8362cfb 100644 (file)
@@ -252,6 +252,12 @@ typedef struct shader_info {
           *   AddressingModelPhysical64: 64
           */
          unsigned ptr_size;
+
+         /*
+          * Arrangement of invocations used to calculate derivatives in a compute
+          * shader.  From NV_compute_shader_derivatives.
+          */
+         enum gl_derivative_group derivative_group;
       } cs;
 
       /* Applies to both TCS and TES. */
index d024d2a39fecc443786b8ae61e8df64bcdbc6c83..6f9c74bdfb03038263f44e156cefb8646d328bd3 100644 (file)
@@ -2516,6 +2516,12 @@ struct gl_shader_info
        * ARB_compute_variable_group_size.
        */
       bool LocalSizeVariable;
+
+      /*
+       * Arrangement of invocations used to calculate derivatives in a compute
+       * shader.  From NV_compute_shader_derivatives.
+       */
+      enum gl_derivative_group DerivativeGroup;
    } Comp;
 };