From d9c9a117dc7a4f8ca562926c811e4030d95d78f7 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 30 Dec 2015 16:38:16 -0800 Subject: [PATCH] nir/spirv: Handle execution modes as decorations They're basically the same thing. --- src/glsl/nir/spirv/spirv_to_nir.c | 249 +++++++++++++++++------------- src/glsl/nir/spirv/vtn_private.h | 26 +++- 2 files changed, 168 insertions(+), 107 deletions(-) diff --git a/src/glsl/nir/spirv/spirv_to_nir.c b/src/glsl/nir/spirv/spirv_to_nir.c index fd7e9e8dbc1..6a4cc182ff7 100644 --- a/src/glsl/nir/spirv/spirv_to_nir.c +++ b/src/glsl/nir/spirv/spirv_to_nir.c @@ -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); diff --git a/src/glsl/nir/spirv/vtn_private.h b/src/glsl/nir/spirv/vtn_private.h index 7ed62ee712b..3498215ad5e 100644 --- a/src/glsl/nir/spirv/vtn_private.h +++ b/src/glsl/nir/spirv/vtn_private.h @@ -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); -- 2.30.2