diff options
author | Ian Romanick <ian.d.romanick@intel.com> | 2017-08-29 18:48:01 -0700 |
---|---|---|
committer | Ian Romanick <ian.d.romanick@intel.com> | 2018-03-29 14:16:12 -0700 |
commit | fb322ba998f6512d7f1f544f2d96b37e598472ce (patch) | |
tree | 649ec3495b8457f79d46f83acf917ce29b8264d0 | |
parent | 153a32579ee784ecbb8befd47bff0350f8644d1b (diff) |
glsl/spirv: Emit SPIR-V OpEntryPoint and OpExecutionMode for vertex shaders
-rw-r--r-- | src/compiler/Makefile.glsl.am | 1 | ||||
-rw-r--r-- | src/compiler/glsl/glsl_to_spirv.cpp | 37 | ||||
-rw-r--r-- | src/compiler/glsl/glsl_to_spirv.h | 5 | ||||
-rw-r--r-- | src/compiler/glsl/tests/emit_spirv_entry_point_test.cpp | 255 | ||||
-rw-r--r-- | src/compiler/glsl/tests/meson.build | 4 |
5 files changed, 300 insertions, 2 deletions
diff --git a/src/compiler/Makefile.glsl.am b/src/compiler/Makefile.glsl.am index d5e1b58dbe5..eba0ad45143 100644 --- a/src/compiler/Makefile.glsl.am +++ b/src/compiler/Makefile.glsl.am @@ -93,6 +93,7 @@ glsl_tests_general_ir_test_LDADD = \ glsl_tests_emit_spirv_test_SOURCES = \ glsl/tests/emit_spirv_test.h \ glsl/tests/emit_spirv_constants_test.cpp \ + glsl/tests/emit_spirv_entry_point_test.cpp \ glsl/tests/emit_spirv_functions_test.cpp \ glsl/tests/emit_spirv_types_test.cpp \ glsl/tests/emit_spirv_variables_test.cpp diff --git a/src/compiler/glsl/glsl_to_spirv.cpp b/src/compiler/glsl/glsl_to_spirv.cpp index 97b8d19cabe..d8c04b8e6de 100644 --- a/src/compiler/glsl/glsl_to_spirv.cpp +++ b/src/compiler/glsl/glsl_to_spirv.cpp @@ -1214,4 +1214,41 @@ _mesa_spirv_program::emit_constant(const ir_constant *constant) return known_items.insert_pre_hashed(constant, result_id, hash); } +void +_mesa_spirv_program::emit_entry_point(const struct shader_info *info, + const ir_function_signature *sig) +{ + /* Assign a SpvId for the entry point, and add the function signature for + * "main" to the set of known items. This same ID must be used later when + * the function is emitted. + */ + const SpvId id = known_items.insert(sig); + + STATIC_ASSERT(unsigned(SpvExecutionModelVertex) == + unsigned(MESA_SHADER_VERTEX)); + STATIC_ASSERT(unsigned(SpvExecutionModelTessellationControl) == + unsigned(MESA_SHADER_TESS_CTRL)); + STATIC_ASSERT(unsigned(SpvExecutionModelTessellationEvaluation) == + unsigned(MESA_SHADER_TESS_EVAL)); + STATIC_ASSERT(unsigned(SpvExecutionModelGeometry) == + unsigned(MESA_SHADER_GEOMETRY)); + STATIC_ASSERT(unsigned(SpvExecutionModelFragment) == + unsigned(MESA_SHADER_FRAGMENT)); + STATIC_ASSERT(unsigned(SpvExecutionModelGLCompute) == + unsigned(MESA_SHADER_COMPUTE)); + + /* DO NOT call end_SpvOpEntryPoint here. This must only be called after + * the entire shader stage has been emitted. + */ + begin_SpvOpEntryPoint(&entry_points, + SpvExecutionModel(info->stage), + id, + "main"); + + stage_entry_point_id = id; + + if (info->has_transform_feedback_varyings) + emit_SpvOpExecutionMode(&execution_modes, id, SpvExecutionModeXfb, NULL); +} + } diff --git a/src/compiler/glsl/glsl_to_spirv.h b/src/compiler/glsl/glsl_to_spirv.h index e9d34e7aa26..af6e594c9d4 100644 --- a/src/compiler/glsl/glsl_to_spirv.h +++ b/src/compiler/glsl/glsl_to_spirv.h @@ -64,6 +64,9 @@ public: unsigned emit_function_declaration(const ir_function_signature *sig); + void emit_entry_point(const struct shader_info *info, + const ir_function_signature *sig); + unsigned emit_constant(const ir_constant *constant); private: @@ -135,6 +138,8 @@ public: * SpvId of the entry-point of the shader stage being processed * * In the periods between processing of individual stages, this will be 0. + * + * \sa _mesa_spirv_program::emit_entry_point */ unsigned stage_entry_point_id; }; diff --git a/src/compiler/glsl/tests/emit_spirv_entry_point_test.cpp b/src/compiler/glsl/tests/emit_spirv_entry_point_test.cpp new file mode 100644 index 00000000000..99ef337e692 --- /dev/null +++ b/src/compiler/glsl/tests/emit_spirv_entry_point_test.cpp @@ -0,0 +1,255 @@ +/* + * Copyright © 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <gtest/gtest.h> +#include "main/compiler.h" +#include "main/mtypes.h" +#include "main/macros.h" +#include "ir.h" +#include "util/hash_table.h" +#include "spirv/spirv.h" +#include "spirv/GLSL.std.450.h" +#include "spirv/spirv_capabilities.h" +#include "spirv/spirv_builder.h" +#include "emit_spirv_test.h" + +/** + * \file emit_spirv_entry_point_test.cpp + */ + +class validate_emit_entry_points : public validate_emit_spirv { +public: + void SetUp(); + + struct shader_info *allocate_shader_info(); + + ir_function_signature *main_sig; + +protected: + validate_emit_entry_points(gl_shader_stage _stage) + : stage(_stage), exec_model(execution_model(_stage)) + { + /* empty */ + } + + gl_shader_stage stage; + SpvExecutionModel exec_model; +}; + +class validate_emit_vertex_entry_points : public validate_emit_entry_points { +public: + validate_emit_vertex_entry_points() + : validate_emit_entry_points(MESA_SHADER_VERTEX) + { + /* empty */ + } +}; + +void +validate_emit_entry_points::SetUp() +{ + validate_emit_spirv::SetUp(); + + main_sig = make_prototype(glsl_type::void_type, + "main", + NULL); +} + +struct shader_info * +validate_emit_entry_points::allocate_shader_info() +{ + struct shader_info *info = rzalloc(mem_ctx, struct shader_info); + + info->stage = stage; + + return info; +} + +TEST_F(validate_emit_vertex_entry_points, simple) +{ + struct shader_info *info = allocate_shader_info(); + + spv->emit_entry_point(info, main_sig); + + /* Must manually end the entry point. It was left "open" so that the input + * and output interfaces could be added as the rest of the shader is + * processed. + */ + end_SpvOpEntryPoint(&spv->entry_points); + + const unsigned entry_point_id = spv->known_items.get_id(main_sig); + + EXPECT_NE(0, entry_point_id); + EXPECT_EQ(entry_point_id, spv->stage_entry_point_id); + EXPECT_EQ(0, spv->execution_modes.size_in_bytes()); + + EXPECT_INSTRUCTIONS(spv->entry_points, + 0x0005000f, /* SpvOpEntryPoint */ + exec_model, /* ExecutionModel */ + entry_point_id, /* EntryPoint */ + chars_to_word("main"), /* Name = "main" */ + 0x00000000 + ); +} + +TEST_F(validate_emit_vertex_entry_points, transform_feedback) +{ + struct shader_info *info = allocate_shader_info(); + + info->has_transform_feedback_varyings = true; + + spv->emit_entry_point(info, main_sig); + + /* Must manually end the entry point. It was left "open" so that the input + * and output interfaces could be added as the rest of the shader is + * processed. + */ + end_SpvOpEntryPoint(&spv->entry_points); + + const unsigned entry_point_id = spv->known_items.get_id(main_sig); + + EXPECT_NE(0, entry_point_id); + EXPECT_EQ(entry_point_id, spv->stage_entry_point_id); + + EXPECT_INSTRUCTIONS(spv->execution_modes, + 0x00030010, /* SpvOpExecutionMode */ + entry_point_id, /* EntryPoint */ + 0x0000000b /* Mode = SpvExecutionModeXfb*/ + ); + + EXPECT_INSTRUCTIONS(spv->entry_points, + 0x0005000f, /* SpvOpEntryPoint */ + exec_model, /* ExecutionModel */ + entry_point_id, /* EntryPoint */ + chars_to_word("main"), /* Name = "main" */ + 0x00000000 + ); + + EXPECT_TRUE(spv->capabilities.is_enabled(SpvCapabilityTransformFeedback)); +} + +TEST_F(validate_emit_vertex_entry_points, invalid_from_tessellation) +{ + struct shader_info *info = allocate_shader_info(); + + /* Set a bunch of garbage in the shader_info structure that, for other + * shader stages, would indicate additional execution modes. + */ + info->tess.tcs_vertices_out = 64; + info->tess.primitive_mode = GL_QUADS; + info->tess.spacing = TESS_SPACING_EQUAL; + + spv->emit_entry_point(info, main_sig); + + /* Must manually end the entry point. It was left "open" so that the input + * and output interfaces could be added as the rest of the shader is + * processed. + */ + end_SpvOpEntryPoint(&spv->entry_points); + + const unsigned entry_point_id = spv->known_items.get_id(main_sig); + + EXPECT_NE(0, entry_point_id); + EXPECT_EQ(entry_point_id, spv->stage_entry_point_id); + EXPECT_EQ(0, spv->execution_modes.size_in_bytes()); + + EXPECT_INSTRUCTIONS(spv->entry_points, + 0x0005000f, /* SpvOpEntryPoint */ + exec_model, /* ExecutionModel */ + entry_point_id, /* EntryPoint */ + chars_to_word("main"), /* Name = "main" */ + 0x00000000 + ); + + EXPECT_FALSE(spv->capabilities.is_enabled(SpvCapabilityTessellation)); +} + +TEST_F(validate_emit_vertex_entry_points, invalid_from_geometry) +{ + struct shader_info *info = allocate_shader_info(); + + /* Set a bunch of garbage in the shader_info structure that, for other + * shader stages, would indicate additional execution modes. + */ + info->gs.vertices_in = 3; + info->gs.output_primitive = GL_POINTS; + info->gs.input_primitive = GL_POINTS; + info->gs.vertices_out = 16; + info->gs.invocations = 2; + + spv->emit_entry_point(info, main_sig); + + /* Must manually end the entry point. It was left "open" so that the input + * and output interfaces could be added as the rest of the shader is + * processed. + */ + end_SpvOpEntryPoint(&spv->entry_points); + + const unsigned entry_point_id = spv->known_items.get_id(main_sig); + + EXPECT_NE(0, entry_point_id); + EXPECT_EQ(entry_point_id, spv->stage_entry_point_id); + EXPECT_EQ(0, spv->execution_modes.size_in_bytes()); + + EXPECT_INSTRUCTIONS(spv->entry_points, + 0x0005000f, /* SpvOpEntryPoint */ + exec_model, /* ExecutionModel */ + entry_point_id, /* EntryPoint */ + chars_to_word("main"), /* Name = "main" */ + 0x00000000 + ); + + EXPECT_FALSE(spv->capabilities.is_enabled(SpvCapabilityGeometry)); +} + +TEST_F(validate_emit_vertex_entry_points, invalid_from_fragment) +{ + struct shader_info *info = allocate_shader_info(); + + /* Set a bunch of garbage in the shader_info structure that, for other + * shader stages, would indicate additional execution modes. + */ + info->fs.depth_layout = FRAG_DEPTH_LAYOUT_LESS; + info->fs.early_fragment_tests = true; + + spv->emit_entry_point(info, main_sig); + + /* Must manually end the entry point. It was left "open" so that the input + * and output interfaces could be added as the rest of the shader is + * processed. + */ + end_SpvOpEntryPoint(&spv->entry_points); + + const unsigned entry_point_id = spv->known_items.get_id(main_sig); + + EXPECT_NE(0, entry_point_id); + EXPECT_EQ(entry_point_id, spv->stage_entry_point_id); + EXPECT_EQ(0, spv->execution_modes.size_in_bytes()); + + EXPECT_INSTRUCTIONS(spv->entry_points, + 0x0005000f, /* SpvOpEntryPoint */ + exec_model, /* ExecutionModel */ + entry_point_id, /* EntryPoint */ + chars_to_word("main"), /* Name = "main" */ + 0x00000000 + ); +} diff --git a/src/compiler/glsl/tests/meson.build b/src/compiler/glsl/tests/meson.build index 2a4d1a19412..030fc513f21 100644 --- a/src/compiler/glsl/tests/meson.build +++ b/src/compiler/glsl/tests/meson.build @@ -46,8 +46,8 @@ test( executable( 'emit-spirv_test', ['emit_spirv_test.h', 'emit_spirv_constants_test.cpp', - 'emit_spirv_functions_test.cpp', 'emit_spirv_types_test.cpp', - 'emit_spirv_variables_test.cpp'], + 'emit_spirv_entry_point_test.cpp', 'emit_spirv_functions_test.cpp', + 'emit_spirv_types_test.cpp', 'emit_spirv_variables_test.cpp'], cpp_args : [cpp_vis_args, cpp_msvc_compat_args], include_directories : [inc_common, inc_compiler, inc_glsl, inc_spirv], link_with : [libglsl, libglsl_standalone, libglsl_util], |