1 // Copyright 2018 The Amber 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/pipeline.h"
16
17 #include "gtest/gtest.h"
18 #include "src/make_unique.h"
19 #include "src/type_parser.h"
20
21 namespace amber {
22 namespace {
23
24 struct ShaderTypeData {
25 ShaderType type;
26 };
27
28 } // namespace
29
30 class PipelineTest : public testing::Test {
31 public:
TearDown()32 void TearDown() override {
33 color_buffer_ = nullptr;
34 depth_stencil_buffer_ = nullptr;
35 }
36
SetupColorAttachment(Pipeline * p,uint32_t location)37 void SetupColorAttachment(Pipeline* p, uint32_t location) {
38 if (!color_buffer_)
39 color_buffer_ = p->GenerateDefaultColorAttachmentBuffer();
40
41 p->AddColorAttachment(color_buffer_.get(), location, 0);
42 }
43
SetupDepthStencilAttachment(Pipeline * p)44 void SetupDepthStencilAttachment(Pipeline* p) {
45 if (!depth_stencil_buffer_)
46 depth_stencil_buffer_ = p->GenerateDefaultDepthStencilAttachmentBuffer();
47
48 p->SetDepthStencilBuffer(depth_stencil_buffer_.get());
49 }
50
51 private:
52 std::unique_ptr<Buffer> color_buffer_;
53 std::unique_ptr<Buffer> depth_stencil_buffer_;
54 };
55
TEST_F(PipelineTest,AddShader)56 TEST_F(PipelineTest, AddShader) {
57 Shader v(kShaderTypeVertex);
58 Shader f(kShaderTypeFragment);
59
60 Pipeline p(PipelineType::kGraphics);
61 Result r = p.AddShader(&v, kShaderTypeVertex);
62 ASSERT_TRUE(r.IsSuccess()) << r.Error();
63
64 r = p.AddShader(&f, kShaderTypeFragment);
65 ASSERT_TRUE(r.IsSuccess()) << r.Error();
66
67 const auto& shaders = p.GetShaders();
68 EXPECT_EQ(2U, shaders.size());
69
70 EXPECT_EQ(&v, shaders[0].GetShader());
71 EXPECT_EQ(&f, shaders[1].GetShader());
72 }
73
TEST_F(PipelineTest,MissingShader)74 TEST_F(PipelineTest, MissingShader) {
75 Pipeline p(PipelineType::kGraphics);
76 Result r = p.AddShader(nullptr, kShaderTypeVertex);
77 ASSERT_FALSE(r.IsSuccess());
78 EXPECT_EQ("shader can not be null when attached to pipeline", r.Error());
79 }
80
TEST_F(PipelineTest,DuplicateShaders)81 TEST_F(PipelineTest, DuplicateShaders) {
82 Shader v(kShaderTypeVertex);
83 Shader f(kShaderTypeFragment);
84
85 Pipeline p(PipelineType::kGraphics);
86 Result r = p.AddShader(&v, kShaderTypeVertex);
87 ASSERT_TRUE(r.IsSuccess()) << r.Error();
88
89 r = p.AddShader(&f, kShaderTypeFragment);
90 ASSERT_TRUE(r.IsSuccess()) << r.Error();
91
92 r = p.AddShader(&v, kShaderTypeVertex);
93 ASSERT_FALSE(r.IsSuccess());
94 EXPECT_EQ("can not add duplicate shader to pipeline", r.Error());
95 }
96
97 using AmberScriptPipelineComputePipelineTest =
98 testing::TestWithParam<ShaderTypeData>;
TEST_P(AmberScriptPipelineComputePipelineTest,SettingGraphicsShaderToComputePipeline)99 TEST_P(AmberScriptPipelineComputePipelineTest,
100 SettingGraphicsShaderToComputePipeline) {
101 const auto test_data = GetParam();
102
103 Shader s(test_data.type);
104
105 Pipeline p(PipelineType::kCompute);
106 Result r = p.AddShader(&s, test_data.type);
107 ASSERT_FALSE(r.IsSuccess());
108 EXPECT_EQ("only compute shaders allowed in a compute pipeline", r.Error());
109 }
110 INSTANTIATE_TEST_SUITE_P(
111 AmberScriptPipelineComputePipelineTests,
112 AmberScriptPipelineComputePipelineTest,
113 testing::Values(
114 ShaderTypeData{kShaderTypeVertex},
115 ShaderTypeData{kShaderTypeFragment},
116 ShaderTypeData{kShaderTypeGeometry},
117 ShaderTypeData{kShaderTypeTessellationEvaluation},
118 ShaderTypeData{
119 kShaderTypeTessellationControl})); // NOLINT(whitespace/parens)
120
TEST_F(PipelineTest,SettingComputeShaderToGraphicsPipeline)121 TEST_F(PipelineTest, SettingComputeShaderToGraphicsPipeline) {
122 Shader c(kShaderTypeCompute);
123
124 Pipeline p(PipelineType::kGraphics);
125 Result r = p.AddShader(&c, kShaderTypeCompute);
126 ASSERT_FALSE(r.IsSuccess());
127 EXPECT_EQ("can not add a compute shader to a graphics pipeline", r.Error());
128 }
129
TEST_F(PipelineTest,SetShaderOptimizations)130 TEST_F(PipelineTest, SetShaderOptimizations) {
131 Shader v(kShaderTypeVertex);
132 Shader f(kShaderTypeFragment);
133
134 Pipeline p(PipelineType::kGraphics);
135 Result r = p.AddShader(&v, kShaderTypeVertex);
136 ASSERT_TRUE(r.IsSuccess()) << r.Error();
137
138 r = p.AddShader(&f, kShaderTypeFragment);
139 ASSERT_TRUE(r.IsSuccess()) << r.Error();
140
141 std::vector<std::string> first = {"First", "Second"};
142 std::vector<std::string> second = {"Third", "Forth"};
143
144 r = p.SetShaderOptimizations(&f, first);
145 ASSERT_TRUE(r.IsSuccess()) << r.Error();
146
147 r = p.SetShaderOptimizations(&v, second);
148 ASSERT_TRUE(r.IsSuccess()) << r.Error();
149
150 const auto& shaders = p.GetShaders();
151 EXPECT_EQ(2U, shaders.size());
152 EXPECT_EQ(second, shaders[0].GetShaderOptimizations());
153 EXPECT_EQ(first, shaders[1].GetShaderOptimizations());
154 }
155
TEST_F(PipelineTest,DuplicateShaderOptimizations)156 TEST_F(PipelineTest, DuplicateShaderOptimizations) {
157 Shader v(kShaderTypeVertex);
158
159 Pipeline p(PipelineType::kGraphics);
160 Result r = p.AddShader(&v, kShaderTypeVertex);
161 ASSERT_TRUE(r.IsSuccess()) << r.Error();
162
163 std::vector<std::string> data = {"One", "One"};
164 r = p.SetShaderOptimizations(&v, data);
165 ASSERT_FALSE(r.IsSuccess());
166 EXPECT_EQ("duplicate optimization flag (One) set on shader", r.Error());
167 }
168
TEST_F(PipelineTest,SetOptimizationForMissingShader)169 TEST_F(PipelineTest, SetOptimizationForMissingShader) {
170 Pipeline p(PipelineType::kGraphics);
171 Result r = p.SetShaderOptimizations(nullptr, {"One", "Two"});
172 ASSERT_FALSE(r.IsSuccess());
173 EXPECT_EQ("invalid shader specified for optimizations", r.Error());
174 }
175
TEST_F(PipelineTest,SetOptimizationForInvalidShader)176 TEST_F(PipelineTest, SetOptimizationForInvalidShader) {
177 Shader v(kShaderTypeVertex);
178 v.SetName("my_shader");
179
180 Pipeline p(PipelineType::kGraphics);
181 Result r = p.SetShaderOptimizations(&v, {"One", "Two"});
182 ASSERT_FALSE(r.IsSuccess());
183 EXPECT_EQ("unknown shader specified for optimizations: my_shader", r.Error());
184 }
185
TEST_F(PipelineTest,GraphicsPipelineRequiresColorAttachment)186 TEST_F(PipelineTest, GraphicsPipelineRequiresColorAttachment) {
187 Pipeline p(PipelineType::kGraphics);
188 SetupDepthStencilAttachment(&p);
189
190 Result r = p.Validate();
191 ASSERT_FALSE(r.IsSuccess());
192 EXPECT_EQ("PIPELINE missing color attachment", r.Error());
193 }
194
TEST_F(PipelineTest,GraphicsPipelineRequiresVertexAndFragmentShader)195 TEST_F(PipelineTest, GraphicsPipelineRequiresVertexAndFragmentShader) {
196 Shader v(kShaderTypeVertex);
197 Shader f(kShaderTypeFragment);
198 Shader g(kShaderTypeGeometry);
199
200 Pipeline p(PipelineType::kGraphics);
201 SetupColorAttachment(&p, 0);
202 SetupDepthStencilAttachment(&p);
203
204 Result r = p.AddShader(&v, kShaderTypeVertex);
205 EXPECT_TRUE(r.IsSuccess()) << r.Error();
206
207 r = p.AddShader(&g, kShaderTypeGeometry);
208 EXPECT_TRUE(r.IsSuccess()) << r.Error();
209
210 r = p.AddShader(&f, kShaderTypeFragment);
211 EXPECT_TRUE(r.IsSuccess()) << r.Error();
212
213 r = p.Validate();
214 EXPECT_TRUE(r.IsSuccess()) << r.Error();
215 }
216
TEST_F(PipelineTest,GraphicsPipelineMissingVertexShader)217 TEST_F(PipelineTest, GraphicsPipelineMissingVertexShader) {
218 Shader f(kShaderTypeFragment);
219 Shader g(kShaderTypeGeometry);
220
221 Pipeline p(PipelineType::kGraphics);
222 SetupColorAttachment(&p, 0);
223 SetupDepthStencilAttachment(&p);
224
225 Result r = p.AddShader(&g, kShaderTypeGeometry);
226 EXPECT_TRUE(r.IsSuccess()) << r.Error();
227
228 r = p.AddShader(&f, kShaderTypeFragment);
229 EXPECT_TRUE(r.IsSuccess()) << r.Error();
230
231 r = p.Validate();
232 EXPECT_FALSE(r.IsSuccess()) << r.Error();
233 EXPECT_EQ("graphics pipeline requires a vertex shader", r.Error());
234 }
235
TEST_F(PipelineTest,ComputePipelineRequiresComputeShader)236 TEST_F(PipelineTest, ComputePipelineRequiresComputeShader) {
237 Shader c(kShaderTypeCompute);
238
239 Pipeline p(PipelineType::kCompute);
240 SetupColorAttachment(&p, 0);
241 SetupDepthStencilAttachment(&p);
242
243 Result r = p.AddShader(&c, kShaderTypeCompute);
244 EXPECT_TRUE(r.IsSuccess()) << r.Error();
245
246 r = p.Validate();
247 EXPECT_TRUE(r.IsSuccess()) << r.Error();
248 }
249
TEST_F(PipelineTest,ComputePipelineWithoutShader)250 TEST_F(PipelineTest, ComputePipelineWithoutShader) {
251 Pipeline p(PipelineType::kCompute);
252 SetupColorAttachment(&p, 0);
253 SetupDepthStencilAttachment(&p);
254
255 Result r = p.Validate();
256 EXPECT_FALSE(r.IsSuccess()) << r.Error();
257 EXPECT_EQ("compute pipeline requires a compute shader", r.Error());
258 }
259
TEST_F(PipelineTest,PipelineBufferWithoutFormat)260 TEST_F(PipelineTest, PipelineBufferWithoutFormat) {
261 Pipeline p(PipelineType::kCompute);
262
263 auto buf = MakeUnique<Buffer>();
264 buf->SetName("MyBuffer");
265 p.AddBuffer(buf.get(), BufferType::kStorage, 0, 0, 0, 0);
266
267 Result r = p.Validate();
268 EXPECT_FALSE(r.IsSuccess()) << r.Error();
269 EXPECT_EQ("buffer (0:0) requires a format", r.Error());
270 }
271
TEST_F(PipelineTest,SetEntryPointForMissingShader)272 TEST_F(PipelineTest, SetEntryPointForMissingShader) {
273 Shader c(kShaderTypeCompute);
274 c.SetName("my_shader");
275
276 Pipeline p(PipelineType::kCompute);
277 Result r = p.SetShaderEntryPoint(&c, "test");
278 EXPECT_FALSE(r.IsSuccess());
279 EXPECT_EQ("unknown shader specified for entry point: my_shader", r.Error());
280 }
281
TEST_F(PipelineTest,SetEntryPointForNullShader)282 TEST_F(PipelineTest, SetEntryPointForNullShader) {
283 Pipeline p(PipelineType::kCompute);
284 Result r = p.SetShaderEntryPoint(nullptr, "test");
285 EXPECT_FALSE(r.IsSuccess());
286 EXPECT_EQ("invalid shader specified for entry point", r.Error());
287 }
288
TEST_F(PipelineTest,SetBlankEntryPoint)289 TEST_F(PipelineTest, SetBlankEntryPoint) {
290 Shader c(kShaderTypeCompute);
291 Pipeline p(PipelineType::kCompute);
292 Result r = p.AddShader(&c, kShaderTypeCompute);
293 ASSERT_TRUE(r.IsSuccess()) << r.Error();
294
295 r = p.SetShaderEntryPoint(&c, "");
296 EXPECT_FALSE(r.IsSuccess());
297 EXPECT_EQ("entry point should not be blank", r.Error());
298 }
299
TEST_F(PipelineTest,ShaderDefaultEntryPoint)300 TEST_F(PipelineTest, ShaderDefaultEntryPoint) {
301 Shader c(kShaderTypeCompute);
302 Pipeline p(PipelineType::kCompute);
303 Result r = p.AddShader(&c, kShaderTypeCompute);
304 ASSERT_TRUE(r.IsSuccess()) << r.Error();
305
306 const auto& shaders = p.GetShaders();
307 ASSERT_EQ(1U, shaders.size());
308 EXPECT_EQ("main", shaders[0].GetEntryPoint());
309 }
310
TEST_F(PipelineTest,SetShaderEntryPoint)311 TEST_F(PipelineTest, SetShaderEntryPoint) {
312 Shader c(kShaderTypeCompute);
313 Pipeline p(PipelineType::kCompute);
314 Result r = p.AddShader(&c, kShaderTypeCompute);
315 ASSERT_TRUE(r.IsSuccess()) << r.Error();
316
317 r = p.SetShaderEntryPoint(&c, "my_main");
318 ASSERT_TRUE(r.IsSuccess()) << r.Error();
319
320 const auto& shaders = p.GetShaders();
321 ASSERT_EQ(1U, shaders.size());
322 EXPECT_EQ("my_main", shaders[0].GetEntryPoint());
323 }
324
TEST_F(PipelineTest,SetEntryPointMulitpleTimes)325 TEST_F(PipelineTest, SetEntryPointMulitpleTimes) {
326 Shader c(kShaderTypeCompute);
327 Pipeline p(PipelineType::kCompute);
328 Result r = p.AddShader(&c, kShaderTypeCompute);
329 ASSERT_TRUE(r.IsSuccess()) << r.Error();
330
331 r = p.SetShaderEntryPoint(&c, "my_main");
332 ASSERT_TRUE(r.IsSuccess()) << r.Error();
333
334 r = p.SetShaderEntryPoint(&c, "another_main");
335 EXPECT_FALSE(r.IsSuccess());
336 EXPECT_EQ("multiple entry points given for the same shader", r.Error());
337 }
338
TEST_F(PipelineTest,Clone)339 TEST_F(PipelineTest, Clone) {
340 Pipeline p(PipelineType::kGraphics);
341 p.SetName("my_pipeline");
342 p.SetFramebufferWidth(800);
343 p.SetFramebufferHeight(600);
344
345 SetupColorAttachment(&p, 0);
346 SetupDepthStencilAttachment(&p);
347
348 Shader f(kShaderTypeFragment);
349 p.AddShader(&f, kShaderTypeFragment);
350 Shader v(kShaderTypeVertex);
351 p.AddShader(&v, kShaderTypeVertex);
352 p.SetShaderEntryPoint(&v, "my_main");
353
354 auto vtex_buf = MakeUnique<Buffer>();
355 vtex_buf->SetName("vertex_buffer");
356 TypeParser parser;
357 auto int_type = parser.Parse("R32_SINT");
358 auto int_fmt = MakeUnique<Format>(int_type.get());
359 p.AddVertexBuffer(vtex_buf.get(), 1, InputRate::kVertex, int_fmt.get(), 5,
360 10);
361
362 auto idx_buf = MakeUnique<Buffer>();
363 idx_buf->SetName("Index Buffer");
364 p.SetIndexBuffer(idx_buf.get());
365
366 auto buf1 = MakeUnique<Buffer>();
367 buf1->SetName("buf1");
368 p.AddBuffer(buf1.get(), BufferType::kStorage, 1, 1, 0, 0);
369
370 auto buf2 = MakeUnique<Buffer>();
371 buf2->SetName("buf2");
372 p.AddBuffer(buf2.get(), BufferType::kStorage, 1, 2, 0, 16);
373
374 auto clone = p.Clone();
375 EXPECT_EQ("", clone->GetName());
376 EXPECT_EQ(800U, clone->GetFramebufferWidth());
377 EXPECT_EQ(600U, clone->GetFramebufferHeight());
378
379 auto shaders = clone->GetShaders();
380 ASSERT_EQ(2U, shaders.size());
381 EXPECT_EQ(kShaderTypeFragment, shaders[0].GetShaderType());
382 EXPECT_EQ(kShaderTypeVertex, shaders[1].GetShaderType());
383 EXPECT_EQ("my_main", shaders[1].GetEntryPoint());
384
385 ASSERT_TRUE(clone->GetIndexBuffer() != nullptr);
386 EXPECT_EQ("Index Buffer", clone->GetIndexBuffer()->GetName());
387
388 auto vtex_buffers = clone->GetVertexBuffers();
389 ASSERT_EQ(1U, vtex_buffers.size());
390 EXPECT_EQ(1, vtex_buffers[0].location);
391 EXPECT_EQ("vertex_buffer", vtex_buffers[0].buffer->GetName());
392 EXPECT_EQ(InputRate::kVertex, vtex_buffers[0].input_rate);
393 EXPECT_EQ(FormatType::kR32_SINT, vtex_buffers[0].format->GetFormatType());
394 EXPECT_EQ(5, vtex_buffers[0].offset);
395 EXPECT_EQ(10, vtex_buffers[0].stride);
396
397 auto bufs = clone->GetBuffers();
398 ASSERT_EQ(2U, bufs.size());
399 EXPECT_EQ("buf1", bufs[0].buffer->GetName());
400 EXPECT_EQ(1U, bufs[0].descriptor_set);
401 EXPECT_EQ(1U, bufs[0].binding);
402 EXPECT_EQ(0U, bufs[0].dynamic_offset);
403
404 EXPECT_EQ("buf2", bufs[1].buffer->GetName());
405 EXPECT_EQ(1U, bufs[1].descriptor_set);
406 EXPECT_EQ(2U, bufs[1].binding);
407 EXPECT_EQ(16U, bufs[1].dynamic_offset);
408 }
409
TEST_F(PipelineTest,OpenCLUpdateBindings)410 TEST_F(PipelineTest, OpenCLUpdateBindings) {
411 Pipeline p(PipelineType::kCompute);
412 p.SetName("my_pipeline");
413
414 Shader cs(kShaderTypeCompute);
415 cs.SetFormat(kShaderFormatOpenCLC);
416 p.AddShader(&cs, kShaderTypeCompute);
417 p.SetShaderEntryPoint(&cs, "my_main");
418
419 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
420 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SSBO;
421 entry1.descriptor_set = 4;
422 entry1.binding = 5;
423 entry1.arg_name = "arg_a";
424 entry1.arg_ordinal = 0;
425 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
426
427 Pipeline::ShaderInfo::DescriptorMapEntry entry2;
428 entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SSBO;
429 entry2.descriptor_set = 3;
430 entry2.binding = 1;
431 entry2.arg_name = "arg_b";
432 entry2.arg_ordinal = 1;
433 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
434
435 auto a_buf = MakeUnique<Buffer>();
436 a_buf->SetName("buf1");
437 p.AddBuffer(a_buf.get(), BufferType::kStorage, "arg_a");
438
439 auto b_buf = MakeUnique<Buffer>();
440 b_buf->SetName("buf2");
441 p.AddBuffer(b_buf.get(), BufferType::kStorage, 1);
442
443 p.UpdateOpenCLBufferBindings();
444
445 auto& bufs = p.GetBuffers();
446 ASSERT_EQ(2U, bufs.size());
447 EXPECT_EQ("buf1", bufs[0].buffer->GetName());
448 EXPECT_EQ(4U, bufs[0].descriptor_set);
449 EXPECT_EQ(5U, bufs[0].binding);
450 EXPECT_EQ("buf2", bufs[1].buffer->GetName());
451 EXPECT_EQ(3U, bufs[1].descriptor_set);
452 EXPECT_EQ(1U, bufs[1].binding);
453 }
454
TEST_F(PipelineTest,OpenCLUpdateBindingTypeMismatch)455 TEST_F(PipelineTest, OpenCLUpdateBindingTypeMismatch) {
456 Pipeline p(PipelineType::kCompute);
457 p.SetName("my_pipeline");
458
459 Shader cs(kShaderTypeCompute);
460 cs.SetFormat(kShaderFormatOpenCLC);
461 p.AddShader(&cs, kShaderTypeCompute);
462 p.SetShaderEntryPoint(&cs, "my_main");
463
464 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
465 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SSBO;
466 entry1.descriptor_set = 4;
467 entry1.binding = 5;
468 entry1.arg_name = "arg_a";
469 entry1.arg_ordinal = 0;
470 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
471
472 Pipeline::ShaderInfo::DescriptorMapEntry entry2;
473 entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SSBO;
474 entry2.descriptor_set = 3;
475 entry2.binding = 1;
476 entry2.arg_name = "arg_b";
477 entry2.arg_ordinal = 1;
478 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
479
480 auto a_buf = MakeUnique<Buffer>();
481 a_buf->SetName("buf1");
482 p.AddBuffer(a_buf.get(), BufferType::kStorage, "arg_a");
483
484 auto b_buf = MakeUnique<Buffer>();
485 b_buf->SetName("buf2");
486 p.AddBuffer(b_buf.get(), BufferType::kUniform, 1);
487
488 auto r = p.UpdateOpenCLBufferBindings();
489
490 ASSERT_FALSE(r.IsSuccess());
491 EXPECT_EQ("Buffer buf2 must be a uniform binding", r.Error());
492 }
493
TEST_F(PipelineTest,OpenCLUpdateBindingImagesAndSamplers)494 TEST_F(PipelineTest, OpenCLUpdateBindingImagesAndSamplers) {
495 Pipeline p(PipelineType::kCompute);
496 p.SetName("my_pipeline");
497
498 Shader cs(kShaderTypeCompute);
499 cs.SetFormat(kShaderFormatOpenCLC);
500 p.AddShader(&cs, kShaderTypeCompute);
501 p.SetShaderEntryPoint(&cs, "my_main");
502
503 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
504 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::RO_IMAGE;
505 entry1.descriptor_set = 4;
506 entry1.binding = 5;
507 entry1.arg_name = "arg_a";
508 entry1.arg_ordinal = 0;
509 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
510
511 Pipeline::ShaderInfo::DescriptorMapEntry entry2;
512 entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::WO_IMAGE;
513 entry2.descriptor_set = 3;
514 entry2.binding = 1;
515 entry2.arg_name = "arg_b";
516 entry2.arg_ordinal = 1;
517 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
518
519 Pipeline::ShaderInfo::DescriptorMapEntry entry3;
520 entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SAMPLER;
521 entry2.descriptor_set = 3;
522 entry2.binding = 2;
523 entry2.arg_name = "arg_c";
524 entry2.arg_ordinal = 2;
525 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
526
527 auto a_buf = MakeUnique<Buffer>();
528 a_buf->SetName("buf1");
529 p.AddBuffer(a_buf.get(), BufferType::kSampledImage, "arg_a");
530
531 auto b_buf = MakeUnique<Buffer>();
532 b_buf->SetName("buf2");
533 p.AddBuffer(b_buf.get(), BufferType::kStorageImage, 1);
534
535 auto s = MakeUnique<Sampler>();
536 s->SetName("samp");
537 p.AddSampler(s.get(), "arg_c");
538
539 auto r = p.UpdateOpenCLBufferBindings();
540
541 ASSERT_TRUE(r.IsSuccess());
542 }
543
TEST_F(PipelineTest,OpenCLGeneratePodBuffers)544 TEST_F(PipelineTest, OpenCLGeneratePodBuffers) {
545 Pipeline p(PipelineType::kCompute);
546 p.SetName("my_pipeline");
547
548 Shader cs(kShaderTypeCompute);
549 cs.SetFormat(kShaderFormatOpenCLC);
550 p.AddShader(&cs, kShaderTypeCompute);
551 p.SetShaderEntryPoint(&cs, "my_main");
552
553 // Descriptor map.
554 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
555 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
556 entry1.descriptor_set = 4;
557 entry1.binding = 5;
558 entry1.arg_name = "arg_a";
559 entry1.arg_ordinal = 0;
560 entry1.pod_offset = 0;
561 entry1.pod_arg_size = 4;
562 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
563
564 Pipeline::ShaderInfo::DescriptorMapEntry entry2;
565 entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
566 entry2.descriptor_set = 4;
567 entry2.binding = 5;
568 entry2.arg_name = "arg_b";
569 entry2.arg_ordinal = 0;
570 entry2.pod_offset = 4;
571 entry2.pod_arg_size = 1;
572 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
573
574 Pipeline::ShaderInfo::DescriptorMapEntry entry3;
575 entry3.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
576 entry3.descriptor_set = 4;
577 entry3.binding = 4;
578 entry3.arg_name = "arg_c";
579 entry3.arg_ordinal = 0;
580 entry3.pod_offset = 0;
581 entry3.pod_arg_size = 4;
582 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry3));
583
584 // Set commands.
585 Value int_value;
586 int_value.SetIntValue(1);
587
588 TypeParser parser;
589 auto int_type = parser.Parse("R32_SINT");
590 auto int_fmt = MakeUnique<Format>(int_type.get());
591 auto char_type = parser.Parse("R8_SINT");
592 auto char_fmt = MakeUnique<Format>(char_type.get());
593
594 Pipeline::ArgSetInfo arg_info1;
595 arg_info1.name = "arg_a";
596 arg_info1.ordinal = 99;
597 arg_info1.fmt = int_fmt.get();
598 arg_info1.value = int_value;
599 p.SetArg(std::move(arg_info1));
600
601 Pipeline::ArgSetInfo arg_info2;
602 arg_info2.name = "arg_b";
603 arg_info2.ordinal = 99;
604 arg_info2.fmt = char_fmt.get();
605 arg_info2.value = int_value;
606 p.SetArg(std::move(arg_info2));
607
608 Pipeline::ArgSetInfo arg_info3;
609 arg_info3.name = "arg_c";
610 arg_info3.ordinal = 99;
611 arg_info3.fmt = int_fmt.get();
612 arg_info3.value = int_value;
613 p.SetArg(std::move(arg_info3));
614
615 auto r = p.GenerateOpenCLPodBuffers();
616 ASSERT_TRUE(r.IsSuccess());
617 EXPECT_EQ(2U, p.GetBuffers().size());
618
619 const auto& b1 = p.GetBuffers()[0];
620 EXPECT_EQ(4U, b1.descriptor_set);
621 EXPECT_EQ(5U, b1.binding);
622 EXPECT_EQ(5U, b1.buffer->ValueCount());
623
624 const auto& b2 = p.GetBuffers()[1];
625 EXPECT_EQ(4U, b2.descriptor_set);
626 EXPECT_EQ(4U, b2.binding);
627 EXPECT_EQ(4U, b2.buffer->ValueCount());
628 }
629
TEST_F(PipelineTest,OpenCLGeneratePodBuffersBadName)630 TEST_F(PipelineTest, OpenCLGeneratePodBuffersBadName) {
631 Pipeline p(PipelineType::kCompute);
632 p.SetName("my_pipeline");
633
634 Shader cs(kShaderTypeCompute);
635 cs.SetFormat(kShaderFormatOpenCLC);
636 p.AddShader(&cs, kShaderTypeCompute);
637 p.SetShaderEntryPoint(&cs, "my_main");
638
639 // Descriptor map.
640 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
641 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
642 entry1.descriptor_set = 4;
643 entry1.binding = 5;
644 entry1.arg_name = "arg_a";
645 entry1.arg_ordinal = 0;
646 entry1.pod_offset = 0;
647 entry1.pod_arg_size = 4;
648 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
649
650 // Set commands.
651 Value int_value;
652 int_value.SetIntValue(1);
653
654 TypeParser parser;
655 auto int_type = parser.Parse("R32_SINT");
656 auto int_fmt = MakeUnique<Format>(int_type.get());
657
658 Pipeline::ArgSetInfo arg_info1;
659 arg_info1.name = "arg_z";
660 arg_info1.ordinal = 99;
661 arg_info1.fmt = int_fmt.get();
662 arg_info1.value = int_value;
663 p.SetArg(std::move(arg_info1));
664
665 auto r = p.GenerateOpenCLPodBuffers();
666 ASSERT_FALSE(r.IsSuccess());
667 EXPECT_EQ(
668 "could not find descriptor map entry for SET command: kernel my_main, "
669 "name arg_z",
670 r.Error());
671 }
672
TEST_F(PipelineTest,OpenCLGeneratePodBuffersBadSize)673 TEST_F(PipelineTest, OpenCLGeneratePodBuffersBadSize) {
674 Pipeline p(PipelineType::kCompute);
675 p.SetName("my_pipeline");
676
677 Shader cs(kShaderTypeCompute);
678 cs.SetFormat(kShaderFormatOpenCLC);
679 p.AddShader(&cs, kShaderTypeCompute);
680 p.SetShaderEntryPoint(&cs, "my_main");
681
682 // Descriptor map.
683 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
684 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
685 entry1.descriptor_set = 4;
686 entry1.binding = 5;
687 entry1.arg_name = "arg_a";
688 entry1.arg_ordinal = 0;
689 entry1.pod_offset = 0;
690 entry1.pod_arg_size = 4;
691 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
692
693 // Set commands.
694 Value int_value;
695 int_value.SetIntValue(1);
696
697 TypeParser parser;
698 auto short_type = parser.Parse("R16_SINT");
699 auto short_fmt = MakeUnique<Format>(short_type.get());
700
701 Pipeline::ArgSetInfo arg_info1;
702 arg_info1.name = "";
703 arg_info1.ordinal = 0;
704 arg_info1.fmt = short_fmt.get();
705 arg_info1.value = int_value;
706 p.SetArg(std::move(arg_info1));
707
708 auto r = p.GenerateOpenCLPodBuffers();
709 ASSERT_FALSE(r.IsSuccess());
710 EXPECT_EQ("SET command uses incorrect data size: kernel my_main, number 0",
711 r.Error());
712 }
713
TEST_F(PipelineTest,OpenCLClone)714 TEST_F(PipelineTest, OpenCLClone) {
715 Pipeline p(PipelineType::kCompute);
716 p.SetName("my_pipeline");
717
718 Shader cs(kShaderTypeCompute);
719 cs.SetFormat(kShaderFormatOpenCLC);
720 p.AddShader(&cs, kShaderTypeCompute);
721 p.SetShaderEntryPoint(&cs, "my_main");
722
723 // Descriptor map.
724 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
725 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
726 entry1.descriptor_set = 4;
727 entry1.binding = 5;
728 entry1.arg_name = "arg_a";
729 entry1.arg_ordinal = 0;
730 entry1.pod_offset = 0;
731 entry1.pod_arg_size = 4;
732 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
733
734 Pipeline::ShaderInfo::DescriptorMapEntry entry2;
735 entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
736 entry2.descriptor_set = 4;
737 entry2.binding = 5;
738 entry2.arg_name = "arg_b";
739 entry2.arg_ordinal = 0;
740 entry2.pod_offset = 4;
741 entry2.pod_arg_size = 1;
742 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
743
744 Pipeline::ShaderInfo::DescriptorMapEntry entry3;
745 entry3.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
746 entry3.descriptor_set = 4;
747 entry3.binding = 4;
748 entry3.arg_name = "arg_c";
749 entry3.arg_ordinal = 0;
750 entry3.pod_offset = 0;
751 entry3.pod_arg_size = 4;
752 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry3));
753
754 // Set commands.
755 Value int_value;
756 int_value.SetIntValue(1);
757
758 TypeParser parser;
759 auto int_type = parser.Parse("R32_SINT");
760 auto int_fmt = MakeUnique<Format>(int_type.get());
761 auto char_type = parser.Parse("R8_SINT");
762 auto char_fmt = MakeUnique<Format>(char_type.get());
763
764 Pipeline::ArgSetInfo arg_info1;
765 arg_info1.name = "arg_a";
766 arg_info1.ordinal = 99;
767 arg_info1.fmt = int_fmt.get();
768 arg_info1.value = int_value;
769 p.SetArg(std::move(arg_info1));
770
771 Pipeline::ArgSetInfo arg_info2;
772 arg_info2.name = "arg_b";
773 arg_info2.ordinal = 99;
774 arg_info2.fmt = char_fmt.get();
775 arg_info2.value = int_value;
776 p.SetArg(std::move(arg_info2));
777
778 Pipeline::ArgSetInfo arg_info3;
779 arg_info3.name = "arg_c";
780 arg_info3.ordinal = 99;
781 arg_info3.fmt = int_fmt.get();
782 arg_info3.value = int_value;
783 p.SetArg(std::move(arg_info3));
784
785 auto clone = p.Clone();
786 auto r = clone->GenerateOpenCLPodBuffers();
787 ASSERT_TRUE(r.IsSuccess());
788 EXPECT_EQ(3U, clone->SetArgValues().size());
789 EXPECT_EQ(2U, clone->GetBuffers().size());
790
791 const auto& b1 = clone->GetBuffers()[0];
792 EXPECT_EQ(4U, b1.descriptor_set);
793 EXPECT_EQ(5U, b1.binding);
794 EXPECT_EQ(5U, b1.buffer->ValueCount());
795
796 const auto& b2 = clone->GetBuffers()[1];
797 EXPECT_EQ(4U, b2.descriptor_set);
798 EXPECT_EQ(4U, b2.binding);
799 EXPECT_EQ(4U, b2.buffer->ValueCount());
800 }
801
TEST_F(PipelineTest,OpenCLGenerateLiteralSamplers)802 TEST_F(PipelineTest, OpenCLGenerateLiteralSamplers) {
803 Pipeline p(PipelineType::kCompute);
804 p.SetName("my_pipeline");
805
806 p.AddSampler(16, 0, 0);
807 p.AddSampler(41, 0, 1);
808
809 auto r = p.GenerateOpenCLLiteralSamplers();
810 ASSERT_TRUE(r.IsSuccess());
811 for (auto& info : p.GetSamplers()) {
812 if (info.mask == 16) {
813 EXPECT_NE(nullptr, info.sampler);
814 EXPECT_EQ(FilterType::kNearest, info.sampler->GetMagFilter());
815 EXPECT_EQ(FilterType::kNearest, info.sampler->GetMinFilter());
816 EXPECT_EQ(AddressMode::kClampToEdge, info.sampler->GetAddressModeU());
817 EXPECT_EQ(AddressMode::kClampToEdge, info.sampler->GetAddressModeV());
818 EXPECT_EQ(AddressMode::kClampToEdge, info.sampler->GetAddressModeW());
819 EXPECT_EQ(0.0f, info.sampler->GetMinLOD());
820 EXPECT_EQ(0.0f, info.sampler->GetMaxLOD());
821 } else {
822 EXPECT_NE(nullptr, info.sampler);
823 EXPECT_EQ(FilterType::kLinear, info.sampler->GetMagFilter());
824 EXPECT_EQ(FilterType::kLinear, info.sampler->GetMinFilter());
825 EXPECT_EQ(AddressMode::kMirroredRepeat, info.sampler->GetAddressModeU());
826 EXPECT_EQ(AddressMode::kMirroredRepeat, info.sampler->GetAddressModeV());
827 EXPECT_EQ(AddressMode::kMirroredRepeat, info.sampler->GetAddressModeW());
828 EXPECT_EQ(0.0f, info.sampler->GetMinLOD());
829 EXPECT_EQ(0.0f, info.sampler->GetMaxLOD());
830 }
831 }
832 }
833
TEST_F(PipelineTest,OpenCLGeneratePushConstants)834 TEST_F(PipelineTest, OpenCLGeneratePushConstants) {
835 Pipeline p(PipelineType::kCompute);
836 p.SetName("my_pipeline");
837
838 Shader cs(kShaderTypeCompute);
839 cs.SetFormat(kShaderFormatOpenCLC);
840 p.AddShader(&cs, kShaderTypeCompute);
841 p.SetShaderEntryPoint(&cs, "my_main");
842
843 Pipeline::ShaderInfo::PushConstant pc1;
844 pc1.type = Pipeline::ShaderInfo::PushConstant::PushConstantType::kDimensions;
845 pc1.offset = 0;
846 pc1.size = 4;
847 p.GetShaders()[0].AddPushConstant(std::move(pc1));
848
849 Pipeline::ShaderInfo::PushConstant pc2;
850 pc2.type =
851 Pipeline::ShaderInfo::PushConstant::PushConstantType::kGlobalOffset;
852 pc2.offset = 16;
853 pc2.size = 12;
854 p.GetShaders()[0].AddPushConstant(std::move(pc2));
855
856 auto r = p.GenerateOpenCLPushConstants();
857 ASSERT_TRUE(r.IsSuccess());
858
859 const auto& buf = p.GetPushConstantBuffer();
860 EXPECT_EQ(28U, buf.buffer->GetSizeInBytes());
861
862 const uint32_t* bytes = buf.buffer->GetValues<uint32_t>();
863 EXPECT_EQ(3U, bytes[0]);
864 EXPECT_EQ(0U, bytes[4]);
865 EXPECT_EQ(0U, bytes[5]);
866 EXPECT_EQ(0U, bytes[6]);
867 }
868
TEST_F(PipelineTest,OpenCLPodPushConstants)869 TEST_F(PipelineTest, OpenCLPodPushConstants) {
870 Pipeline p(PipelineType::kCompute);
871 p.SetName("my_pipeline");
872
873 Shader cs(kShaderTypeCompute);
874 cs.SetFormat(kShaderFormatOpenCLC);
875 p.AddShader(&cs, kShaderTypeCompute);
876 p.SetShaderEntryPoint(&cs, "my_main");
877
878 // Descriptor map.
879 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
880 entry1.kind =
881 Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD_PUSHCONSTANT;
882 entry1.descriptor_set = static_cast<uint32_t>(-1);
883 entry1.binding = static_cast<uint32_t>(-1);
884 entry1.arg_name = "arg_a";
885 entry1.arg_ordinal = 0;
886 entry1.pod_offset = 0;
887 entry1.pod_arg_size = 4;
888 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
889
890 Pipeline::ShaderInfo::DescriptorMapEntry entry2;
891 entry2.kind =
892 Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD_PUSHCONSTANT;
893 entry2.descriptor_set = static_cast<uint32_t>(-1);
894 entry2.binding = static_cast<uint32_t>(-1);
895 entry2.arg_name = "arg_b";
896 entry2.arg_ordinal = 1;
897 entry2.pod_offset = 4;
898 entry2.pod_arg_size = 1;
899 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
900
901 Pipeline::ShaderInfo::DescriptorMapEntry entry3;
902 entry3.kind =
903 Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD_PUSHCONSTANT;
904 entry3.descriptor_set = static_cast<uint32_t>(-1);
905 entry3.binding = static_cast<uint32_t>(-1);
906 entry3.arg_name = "arg_c";
907 entry3.arg_ordinal = 2;
908 entry3.pod_offset = 8;
909 entry3.pod_arg_size = 4;
910 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry3));
911
912 // Set commands.
913 Value int_value;
914 int_value.SetIntValue(1);
915
916 TypeParser parser;
917 auto int_type = parser.Parse("R32_SINT");
918 auto int_fmt = MakeUnique<Format>(int_type.get());
919 auto char_type = parser.Parse("R8_SINT");
920 auto char_fmt = MakeUnique<Format>(char_type.get());
921
922 Pipeline::ArgSetInfo arg_info1;
923 arg_info1.name = "arg_a";
924 arg_info1.ordinal = 99;
925 arg_info1.fmt = int_fmt.get();
926 arg_info1.value = int_value;
927 p.SetArg(std::move(arg_info1));
928
929 Pipeline::ArgSetInfo arg_info2;
930 arg_info2.name = "arg_b";
931 arg_info2.ordinal = 99;
932 arg_info2.fmt = char_fmt.get();
933 arg_info2.value = int_value;
934 p.SetArg(std::move(arg_info2));
935
936 Pipeline::ArgSetInfo arg_info3;
937 arg_info3.name = "arg_c";
938 arg_info3.ordinal = 99;
939 arg_info3.fmt = int_fmt.get();
940 arg_info3.value = int_value;
941 p.SetArg(std::move(arg_info3));
942
943 auto r = p.GenerateOpenCLPodBuffers();
944 auto* buf = p.GetPushConstantBuffer().buffer;
945 EXPECT_NE(nullptr, buf);
946 EXPECT_EQ(12U, buf->GetSizeInBytes());
947
948 const uint32_t* ints = buf->GetValues<uint32_t>();
949 const uint8_t* bytes = buf->GetValues<uint8_t>();
950 EXPECT_EQ(1U, ints[0]);
951 EXPECT_EQ(1U, bytes[4]);
952 EXPECT_EQ(1U, ints[2]);
953 }
954
955 } // namespace amber
956