nir/spirv: Handle execution modes as decorations
authorJason Ekstrand <jason.ekstrand@intel.com>
Thu, 31 Dec 2015 00:38:16 +0000 (16:38 -0800)
committerJason Ekstrand <jason.ekstrand@intel.com>
Thu, 31 Dec 2015 01:45:43 +0000 (17:45 -0800)
They're basically the same thing.

src/glsl/nir/spirv/spirv_to_nir.c
src/glsl/nir/spirv/vtn_private.h

index fd7e9e8dbc1bb4186fd3956f5dd4cfbacd9970f8..6a4cc182ff7a17816a02821199d04043f1e97c9b 100644 (file)
@@ -242,11 +242,14 @@ _foreach_decoration_helper(struct vtn_builder *b,
 {
    for (struct vtn_decoration *dec = value->decoration; dec; dec = dec->next) {
       int member;
-      if (dec->member < 0) {
+      if (dec->scope == VTN_DEC_DECORATION) {
          member = parent_member;
-      } else {
+      } else if (dec->scope >= VTN_DEC_STRUCT_MEMBER0) {
          assert(parent_member == -1);
-         member = dec->member;
+         member = dec->scope - VTN_DEC_STRUCT_MEMBER0;
+      } else {
+         /* Not a decoration */
+         continue;
       }
 
       if (dec->group) {
@@ -272,6 +275,19 @@ vtn_foreach_decoration(struct vtn_builder *b, struct vtn_value *value,
    _foreach_decoration_helper(b, value, -1, value, cb, data);
 }
 
+void
+vtn_foreach_execution_mode(struct vtn_builder *b, struct vtn_value *value,
+                           vtn_execution_mode_foreach_cb cb, void *data)
+{
+   for (struct vtn_decoration *dec = value->decoration; dec; dec = dec->next) {
+      if (dec->scope != VTN_DEC_EXECUTION_MODE)
+         continue;
+
+      assert(dec->group == NULL);
+      cb(b, value, dec, data);
+   }
+}
+
 static void
 vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
                       const uint32_t *w, unsigned count)
@@ -280,20 +296,30 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
    const uint32_t target = w[1];
    w += 2;
 
-   int member = -1;
    switch (opcode) {
    case SpvOpDecorationGroup:
       vtn_push_value(b, target, vtn_value_type_undef);
       break;
 
+   case SpvOpDecorate:
    case SpvOpMemberDecorate:
-      member = *(w++);
-      /* fallthrough */
-   case SpvOpDecorate: {
+   case SpvOpExecutionMode: {
       struct vtn_value *val = &b->values[target];
 
       struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration);
-      dec->member = member;
+      switch (opcode) {
+      case SpvOpDecorate:
+         dec->scope = VTN_DEC_DECORATION;
+         break;
+      case SpvOpMemberDecorate:
+         dec->scope = VTN_DEC_STRUCT_MEMBER0 + *(w++);
+         break;
+      case SpvOpExecutionMode:
+         dec->scope = VTN_DEC_EXECUTION_MODE;
+         break;
+      default:
+         unreachable("Invalid decoration opcode");
+      }
       dec->decoration = *(w++);
       dec->literals = w;
 
@@ -304,16 +330,21 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
    }
 
    case SpvOpGroupMemberDecorate:
-      member = *(w++);
-      /* fallthrough */
    case SpvOpGroupDecorate: {
       struct vtn_value *group = &b->values[target];
       assert(group->value_type == vtn_value_type_decoration_group);
 
+      int scope;
+      if (opcode == SpvOpGroupDecorate) {
+         scope = VTN_DEC_DECORATION;
+      } else {
+         scope = VTN_DEC_STRUCT_MEMBER0 + *(w++);
+      }
+
       for (; w < w_end; w++) {
          struct vtn_value *val = &b->values[*w];
          struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration);
-         dec->member = member;
+         dec->scope = scope;
          dec->group = group;
 
          /* Link into the list */
@@ -3201,100 +3232,6 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
       b->execution_model = w[1];
       break;
 
-   case SpvOpExecutionMode:
-      assert(b->entry_point == &b->values[w[1]]);
-
-      SpvExecutionMode mode = w[2];
-      switch(mode) {
-      case SpvExecutionModeOriginUpperLeft:
-      case SpvExecutionModeOriginLowerLeft:
-         b->origin_upper_left = (mode == SpvExecutionModeOriginUpperLeft);
-         break;
-
-      case SpvExecutionModeEarlyFragmentTests:
-         assert(b->shader->stage == MESA_SHADER_FRAGMENT);
-         b->shader->info.fs.early_fragment_tests = true;
-         break;
-
-      case SpvExecutionModeInvocations:
-         assert(b->shader->stage == MESA_SHADER_GEOMETRY);
-         b->shader->info.gs.invocations = MAX2(1, w[3]);
-         break;
-
-      case SpvExecutionModeDepthReplacing:
-         assert(b->shader->stage == MESA_SHADER_FRAGMENT);
-         b->shader->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_ANY;
-         break;
-      case SpvExecutionModeDepthGreater:
-         assert(b->shader->stage == MESA_SHADER_FRAGMENT);
-         b->shader->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_GREATER;
-         break;
-      case SpvExecutionModeDepthLess:
-         assert(b->shader->stage == MESA_SHADER_FRAGMENT);
-         b->shader->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_LESS;
-         break;
-      case SpvExecutionModeDepthUnchanged:
-         assert(b->shader->stage == MESA_SHADER_FRAGMENT);
-         b->shader->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_UNCHANGED;
-         break;
-
-      case SpvExecutionModeLocalSize:
-         assert(b->shader->stage == MESA_SHADER_COMPUTE);
-         b->shader->info.cs.local_size[0] = w[3];
-         b->shader->info.cs.local_size[1] = w[4];
-         b->shader->info.cs.local_size[2] = w[5];
-         break;
-      case SpvExecutionModeLocalSizeHint:
-         break; /* Nothing do do with this */
-
-      case SpvExecutionModeOutputVertices:
-         assert(b->shader->stage == MESA_SHADER_GEOMETRY);
-         b->shader->info.gs.vertices_out = w[3];
-         break;
-
-      case SpvExecutionModeInputPoints:
-      case SpvExecutionModeInputLines:
-      case SpvExecutionModeInputLinesAdjacency:
-      case SpvExecutionModeTriangles:
-      case SpvExecutionModeInputTrianglesAdjacency:
-      case SpvExecutionModeQuads:
-      case SpvExecutionModeIsolines:
-         if (b->shader->stage == MESA_SHADER_GEOMETRY) {
-            b->shader->info.gs.vertices_in =
-               vertices_in_from_spv_execution_mode(mode);
-         } else {
-            assert(!"Tesselation shaders not yet supported");
-         }
-         break;
-
-      case SpvExecutionModeOutputPoints:
-      case SpvExecutionModeOutputLineStrip:
-      case SpvExecutionModeOutputTriangleStrip:
-         assert(b->shader->stage == MESA_SHADER_GEOMETRY);
-         b->shader->info.gs.output_primitive =
-            gl_primitive_from_spv_execution_mode(mode);
-         break;
-
-      case SpvExecutionModeSpacingEqual:
-      case SpvExecutionModeSpacingFractionalEven:
-      case SpvExecutionModeSpacingFractionalOdd:
-      case SpvExecutionModeVertexOrderCw:
-      case SpvExecutionModeVertexOrderCcw:
-      case SpvExecutionModePointMode:
-         assert(!"TODO: Add tessellation metadata");
-         break;
-
-      case SpvExecutionModePixelCenterInteger:
-      case SpvExecutionModeXfb:
-         assert(!"Unhandled execution mode");
-         break;
-
-      case SpvExecutionModeVecTypeHint:
-      case SpvExecutionModeContractionOff:
-         break; /* OpenCL */
-      }
-      break;
-
    case SpvOpString:
       vtn_push_value(b, w[1], vtn_value_type_string)->str =
          vtn_string_literal(b, &w[2], count - 2);
@@ -3311,6 +3248,7 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
    case SpvOpLine:
       break; /* Ignored for now */
 
+   case SpvOpExecutionMode:
    case SpvOpDecorationGroup:
    case SpvOpDecorate:
    case SpvOpMemberDecorate:
@@ -3326,6 +3264,103 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
    return true;
 }
 
+static void
+vtn_handle_execution_mode(struct vtn_builder *b, struct vtn_value *entry_point,
+                          const struct vtn_decoration *mode, void *data)
+{
+   assert(b->entry_point == entry_point);
+
+   switch(mode->exec_mode) {
+   case SpvExecutionModeOriginUpperLeft:
+   case SpvExecutionModeOriginLowerLeft:
+      b->origin_upper_left =
+         (mode->exec_mode == SpvExecutionModeOriginUpperLeft);
+      break;
+
+   case SpvExecutionModeEarlyFragmentTests:
+      assert(b->shader->stage == MESA_SHADER_FRAGMENT);
+      b->shader->info.fs.early_fragment_tests = true;
+      break;
+
+   case SpvExecutionModeInvocations:
+      assert(b->shader->stage == MESA_SHADER_GEOMETRY);
+      b->shader->info.gs.invocations = MAX2(1, mode->literals[0]);
+      break;
+
+   case SpvExecutionModeDepthReplacing:
+      assert(b->shader->stage == MESA_SHADER_FRAGMENT);
+      b->shader->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_ANY;
+      break;
+   case SpvExecutionModeDepthGreater:
+      assert(b->shader->stage == MESA_SHADER_FRAGMENT);
+      b->shader->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_GREATER;
+      break;
+   case SpvExecutionModeDepthLess:
+      assert(b->shader->stage == MESA_SHADER_FRAGMENT);
+      b->shader->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_LESS;
+      break;
+   case SpvExecutionModeDepthUnchanged:
+      assert(b->shader->stage == MESA_SHADER_FRAGMENT);
+      b->shader->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_UNCHANGED;
+      break;
+
+   case SpvExecutionModeLocalSize:
+      assert(b->shader->stage == MESA_SHADER_COMPUTE);
+      b->shader->info.cs.local_size[0] = mode->literals[0];
+      b->shader->info.cs.local_size[1] = mode->literals[1];
+      b->shader->info.cs.local_size[2] = mode->literals[2];
+      break;
+   case SpvExecutionModeLocalSizeHint:
+      break; /* Nothing do do with this */
+
+   case SpvExecutionModeOutputVertices:
+      assert(b->shader->stage == MESA_SHADER_GEOMETRY);
+      b->shader->info.gs.vertices_out = mode->literals[0];
+      break;
+
+   case SpvExecutionModeInputPoints:
+   case SpvExecutionModeInputLines:
+   case SpvExecutionModeInputLinesAdjacency:
+   case SpvExecutionModeTriangles:
+   case SpvExecutionModeInputTrianglesAdjacency:
+   case SpvExecutionModeQuads:
+   case SpvExecutionModeIsolines:
+      if (b->shader->stage == MESA_SHADER_GEOMETRY) {
+         b->shader->info.gs.vertices_in =
+            vertices_in_from_spv_execution_mode(mode->exec_mode);
+      } else {
+         assert(!"Tesselation shaders not yet supported");
+      }
+      break;
+
+   case SpvExecutionModeOutputPoints:
+   case SpvExecutionModeOutputLineStrip:
+   case SpvExecutionModeOutputTriangleStrip:
+      assert(b->shader->stage == MESA_SHADER_GEOMETRY);
+      b->shader->info.gs.output_primitive =
+         gl_primitive_from_spv_execution_mode(mode->exec_mode);
+      break;
+
+   case SpvExecutionModeSpacingEqual:
+   case SpvExecutionModeSpacingFractionalEven:
+   case SpvExecutionModeSpacingFractionalOdd:
+   case SpvExecutionModeVertexOrderCw:
+   case SpvExecutionModeVertexOrderCcw:
+   case SpvExecutionModePointMode:
+      assert(!"TODO: Add tessellation metadata");
+      break;
+
+   case SpvExecutionModePixelCenterInteger:
+   case SpvExecutionModeXfb:
+      assert(!"Unhandled execution mode");
+      break;
+
+   case SpvExecutionModeVecTypeHint:
+   case SpvExecutionModeContractionOff:
+      break; /* OpenCL */
+   }
+}
+
 static bool
 vtn_handle_variable_or_type_instruction(struct vtn_builder *b, SpvOp opcode,
                                         const uint32_t *w, unsigned count)
@@ -3649,6 +3684,10 @@ spirv_to_nir(const uint32_t *words, size_t word_count,
    words = vtn_foreach_instruction(b, words, word_end,
                                    vtn_handle_preamble_instruction);
 
+   /* Parse execution modes */
+   vtn_foreach_execution_mode(b, b->entry_point,
+                              vtn_handle_execution_mode, NULL);
+
    /* Handle all variable, type, and constant instructions */
    words = vtn_foreach_instruction(b, words, word_end,
                                    vtn_handle_variable_or_type_instruction);
index 7ed62ee712b0a06536256755142525c7b57002f8..3498215ad5e3b666f845434ee872e7080f599fce 100644 (file)
@@ -263,12 +263,26 @@ struct vtn_value {
    };
 };
 
+#define VTN_DEC_DECORATION -1
+#define VTN_DEC_EXECUTION_MODE -2
+#define VTN_DEC_STRUCT_MEMBER0 0
+
 struct vtn_decoration {
    struct vtn_decoration *next;
-   int member; /* -1 if not a member decoration */
+
+   /* Specifies how to apply this decoration.  Negative values represent a
+    * decoration or execution mode. (See the VTN_DEC_ #defines above.)
+    * Non-negative values specify that it applies to a structure member.
+    */
+   int scope;
+
    const uint32_t *literals;
    struct vtn_value *group;
-   SpvDecoration decoration;
+
+   union {
+      SpvDecoration decoration;
+      SpvExecutionMode exec_mode;
+   };
 };
 
 struct vtn_builder {
@@ -357,5 +371,13 @@ typedef void (*vtn_decoration_foreach_cb)(struct vtn_builder *,
 void vtn_foreach_decoration(struct vtn_builder *b, struct vtn_value *value,
                             vtn_decoration_foreach_cb cb, void *data);
 
+typedef void (*vtn_execution_mode_foreach_cb)(struct vtn_builder *,
+                                              struct vtn_value *,
+                                              const struct vtn_decoration *,
+                                              void *);
+
+void vtn_foreach_execution_mode(struct vtn_builder *b, struct vtn_value *value,
+                                vtn_execution_mode_foreach_cb cb, void *data);
+
 bool vtn_handle_glsl450_instruction(struct vtn_builder *b, uint32_t ext_opcode,
                                     const uint32_t *words, unsigned count);