• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/ast/stage_decoration.h"
16 #include "src/ast/workgroup_decoration.h"
17 #include "src/writer/spirv/spv_dump.h"
18 #include "src/writer/spirv/test_helper.h"
19 
20 namespace tint {
21 namespace writer {
22 namespace spirv {
23 namespace {
24 
25 using BuilderTest = TestHelper;
26 
TEST_F(BuilderTest,Decoration_Stage)27 TEST_F(BuilderTest, Decoration_Stage) {
28   auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
29                     ast::DecorationList{
30                         Stage(ast::PipelineStage::kFragment),
31                     });
32 
33   spirv::Builder& b = Build();
34 
35   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
36   EXPECT_EQ(DumpInstructions(b.entry_points()),
37             R"(OpEntryPoint Fragment %3 "main"
38 )");
39 }
40 
41 struct FunctionStageData {
42   ast::PipelineStage stage;
43   SpvExecutionModel model;
44 };
operator <<(std::ostream & out,FunctionStageData data)45 inline std::ostream& operator<<(std::ostream& out, FunctionStageData data) {
46   out << data.stage;
47   return out;
48 }
49 using Decoration_StageTest = TestParamHelper<FunctionStageData>;
TEST_P(Decoration_StageTest,Emit)50 TEST_P(Decoration_StageTest, Emit) {
51   auto params = GetParam();
52 
53   const ast::Variable* var = nullptr;
54   const ast::Type* ret_type = nullptr;
55   ast::DecorationList ret_type_decos;
56   ast::StatementList body;
57   if (params.stage == ast::PipelineStage::kVertex) {
58     ret_type = ty.vec4<f32>();
59     ret_type_decos.push_back(Builtin(ast::Builtin::kPosition));
60     body.push_back(Return(Construct(ty.vec4<f32>())));
61   } else {
62     ret_type = ty.void_();
63   }
64 
65   auto deco_list = ast::DecorationList{Stage(params.stage)};
66   if (params.stage == ast::PipelineStage::kCompute) {
67     deco_list.push_back(WorkgroupSize(1));
68   }
69 
70   auto* func = Func("main", {}, ret_type, body, deco_list, ret_type_decos);
71 
72   spirv::Builder& b = Build();
73 
74   if (var) {
75     ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
76   }
77   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
78 
79   auto preamble = b.entry_points();
80   ASSERT_GE(preamble.size(), 1u);
81   EXPECT_EQ(preamble[0].opcode(), spv::Op::OpEntryPoint);
82 
83   ASSERT_GE(preamble[0].operands().size(), 3u);
84   EXPECT_EQ(preamble[0].operands()[0].to_i(),
85             static_cast<uint32_t>(params.model));
86 }
87 INSTANTIATE_TEST_SUITE_P(
88     BuilderTest,
89     Decoration_StageTest,
90     testing::Values(FunctionStageData{ast::PipelineStage::kVertex,
91                                       SpvExecutionModelVertex},
92                     FunctionStageData{ast::PipelineStage::kFragment,
93                                       SpvExecutionModelFragment},
94                     FunctionStageData{ast::PipelineStage::kCompute,
95                                       SpvExecutionModelGLCompute}));
96 
TEST_F(BuilderTest,Decoration_ExecutionMode_Fragment_OriginUpperLeft)97 TEST_F(BuilderTest, Decoration_ExecutionMode_Fragment_OriginUpperLeft) {
98   auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
99                     ast::DecorationList{
100                         Stage(ast::PipelineStage::kFragment),
101                     });
102 
103   spirv::Builder& b = Build();
104 
105   ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
106   EXPECT_EQ(DumpInstructions(b.execution_modes()),
107             R"(OpExecutionMode %3 OriginUpperLeft
108 )");
109 }
110 
TEST_F(BuilderTest,Decoration_ExecutionMode_WorkgroupSize_Default)111 TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Default) {
112   auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
113                     ast::DecorationList{Stage(ast::PipelineStage::kCompute),
114                                         WorkgroupSize(1)});
115 
116   spirv::Builder& b = Build();
117 
118   ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
119   EXPECT_EQ(DumpInstructions(b.execution_modes()),
120             R"(OpExecutionMode %3 LocalSize 1 1 1
121 )");
122 }
123 
TEST_F(BuilderTest,Decoration_ExecutionMode_WorkgroupSize_Literals)124 TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Literals) {
125   auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
126                     ast::DecorationList{
127                         WorkgroupSize(2, 4, 6),
128                         Stage(ast::PipelineStage::kCompute),
129                     });
130 
131   spirv::Builder& b = Build();
132 
133   ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
134   EXPECT_EQ(DumpInstructions(b.execution_modes()),
135             R"(OpExecutionMode %3 LocalSize 2 4 6
136 )");
137 }
138 
TEST_F(BuilderTest,Decoration_ExecutionMode_WorkgroupSize_Const)139 TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Const) {
140   GlobalConst("width", ty.i32(), Construct(ty.i32(), 2));
141   GlobalConst("height", ty.i32(), Construct(ty.i32(), 3));
142   GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4));
143   auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
144                     ast::DecorationList{
145                         WorkgroupSize("width", "height", "depth"),
146                         Stage(ast::PipelineStage::kCompute),
147                     });
148 
149   spirv::Builder& b = Build();
150 
151   ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
152   EXPECT_EQ(DumpInstructions(b.execution_modes()),
153             R"(OpExecutionMode %3 LocalSize 2 3 4
154 )");
155 }
156 
TEST_F(BuilderTest,Decoration_ExecutionMode_WorkgroupSize_OverridableConst)157 TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_OverridableConst) {
158   GlobalConst("width", ty.i32(), Construct(ty.i32(), 2), {Override(7u)});
159   GlobalConst("height", ty.i32(), Construct(ty.i32(), 3), {Override(8u)});
160   GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4), {Override(9u)});
161   auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
162                     ast::DecorationList{
163                         WorkgroupSize("width", "height", "depth"),
164                         Stage(ast::PipelineStage::kCompute),
165                     });
166 
167   spirv::Builder& b = Build();
168 
169   ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
170   EXPECT_EQ(DumpInstructions(b.execution_modes()), "");
171   EXPECT_EQ(DumpInstructions(b.types()),
172             R"(%2 = OpTypeInt 32 0
173 %1 = OpTypeVector %2 3
174 %4 = OpSpecConstant %2 2
175 %5 = OpSpecConstant %2 3
176 %6 = OpSpecConstant %2 4
177 %3 = OpSpecConstantComposite %1 %4 %5 %6
178 )");
179   EXPECT_EQ(DumpInstructions(b.annots()),
180             R"(OpDecorate %4 SpecId 7
181 OpDecorate %5 SpecId 8
182 OpDecorate %6 SpecId 9
183 OpDecorate %3 BuiltIn WorkgroupSize
184 )");
185 }
186 
TEST_F(BuilderTest,Decoration_ExecutionMode_WorkgroupSize_LiteralAndConst)187 TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_LiteralAndConst) {
188   GlobalConst("height", ty.i32(), Construct(ty.i32(), 2), {Override(7u)});
189   GlobalConst("depth", ty.i32(), Construct(ty.i32(), 3));
190   auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
191                     ast::DecorationList{
192                         WorkgroupSize(4, "height", "depth"),
193                         Stage(ast::PipelineStage::kCompute),
194                     });
195 
196   spirv::Builder& b = Build();
197 
198   ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
199   EXPECT_EQ(DumpInstructions(b.execution_modes()), "");
200   EXPECT_EQ(DumpInstructions(b.types()),
201             R"(%2 = OpTypeInt 32 0
202 %1 = OpTypeVector %2 3
203 %4 = OpConstant %2 4
204 %5 = OpSpecConstant %2 2
205 %6 = OpConstant %2 3
206 %3 = OpSpecConstantComposite %1 %4 %5 %6
207 )");
208   EXPECT_EQ(DumpInstructions(b.annots()),
209             R"(OpDecorate %5 SpecId 7
210 OpDecorate %3 BuiltIn WorkgroupSize
211 )");
212 }
213 
TEST_F(BuilderTest,Decoration_ExecutionMode_MultipleFragment)214 TEST_F(BuilderTest, Decoration_ExecutionMode_MultipleFragment) {
215   auto* func1 = Func("main1", {}, ty.void_(), ast::StatementList{},
216                      ast::DecorationList{
217                          Stage(ast::PipelineStage::kFragment),
218                      });
219 
220   auto* func2 = Func("main2", {}, ty.void_(), ast::StatementList{},
221                      ast::DecorationList{
222                          Stage(ast::PipelineStage::kFragment),
223                      });
224 
225   spirv::Builder& b = Build();
226 
227   ASSERT_TRUE(b.GenerateFunction(func1)) << b.error();
228   ASSERT_TRUE(b.GenerateFunction(func2)) << b.error();
229   EXPECT_EQ(DumpBuilder(b),
230             R"(OpEntryPoint Fragment %3 "main1"
231 OpEntryPoint Fragment %5 "main2"
232 OpExecutionMode %3 OriginUpperLeft
233 OpExecutionMode %5 OriginUpperLeft
234 OpName %3 "main1"
235 OpName %5 "main2"
236 %2 = OpTypeVoid
237 %1 = OpTypeFunction %2
238 %3 = OpFunction %2 None %1
239 %4 = OpLabel
240 OpReturn
241 OpFunctionEnd
242 %5 = OpFunction %2 None %1
243 %6 = OpLabel
244 OpReturn
245 OpFunctionEnd
246 )");
247 }
248 
TEST_F(BuilderTest,Decoration_ExecutionMode_FragDepth)249 TEST_F(BuilderTest, Decoration_ExecutionMode_FragDepth) {
250   Func("main", ast::VariableList{}, ty.f32(),
251        ast::StatementList{
252            Return(Expr(1.f)),
253        },
254        ast::DecorationList{Stage(ast::PipelineStage::kFragment)},
255        ast::DecorationList{
256            Builtin(ast::Builtin::kFragDepth),
257        });
258 
259   spirv::Builder& b = SanitizeAndBuild();
260 
261   ASSERT_TRUE(b.Build());
262 
263   EXPECT_EQ(DumpInstructions(b.execution_modes()),
264             R"(OpExecutionMode %11 OriginUpperLeft
265 OpExecutionMode %11 DepthReplacing
266 )");
267 }
268 
269 }  // namespace
270 }  // namespace spirv
271 }  // namespace writer
272 }  // namespace tint
273