summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Romanick <ian.d.romanick@intel.com>2017-08-29 18:48:01 -0700
committerIan Romanick <ian.d.romanick@intel.com>2018-03-29 14:16:12 -0700
commitfb322ba998f6512d7f1f544f2d96b37e598472ce (patch)
tree649ec3495b8457f79d46f83acf917ce29b8264d0
parent153a32579ee784ecbb8befd47bff0350f8644d1b (diff)
glsl/spirv: Emit SPIR-V OpEntryPoint and OpExecutionMode for vertex shaders
-rw-r--r--src/compiler/Makefile.glsl.am1
-rw-r--r--src/compiler/glsl/glsl_to_spirv.cpp37
-rw-r--r--src/compiler/glsl/glsl_to_spirv.h5
-rw-r--r--src/compiler/glsl/tests/emit_spirv_entry_point_test.cpp255
-rw-r--r--src/compiler/glsl/tests/meson.build4
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],