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_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);
42 }
43
SetupDepthAttachment(Pipeline * p)44 void SetupDepthAttachment(Pipeline* p) {
45 if (!depth_buffer_)
46 depth_buffer_ = p->GenerateDefaultDepthAttachmentBuffer();
47
48 p->SetDepthBuffer(depth_buffer_.get());
49 }
50
51 private:
52 std::unique_ptr<Buffer> color_buffer_;
53 std::unique_ptr<Buffer> depth_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 SetupDepthAttachment(&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 SetupDepthAttachment(&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 SetupDepthAttachment(&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 SetupDepthAttachment(&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 SetupDepthAttachment(&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>(BufferType::kStorage);
264 buf->SetName("MyBuffer");
265 p.AddBuffer(buf.get(), 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 SetupDepthAttachment(&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>(BufferType::kVertex);
355 vtex_buf->SetName("vertex_buffer");
356 p.AddVertexBuffer(vtex_buf.get(), 1);
357
358 auto idx_buf = MakeUnique<Buffer>(BufferType::kIndex);
359 idx_buf->SetName("Index Buffer");
360 p.SetIndexBuffer(idx_buf.get());
361
362 auto buf1 = MakeUnique<Buffer>(BufferType::kStorage);
363 buf1->SetName("buf1");
364 p.AddBuffer(buf1.get(), 1, 1);
365
366 auto buf2 = MakeUnique<Buffer>(BufferType::kStorage);
367 buf2->SetName("buf2");
368 p.AddBuffer(buf2.get(), 1, 2);
369
370 auto clone = p.Clone();
371 EXPECT_EQ("", clone->GetName());
372 EXPECT_EQ(800U, clone->GetFramebufferWidth());
373 EXPECT_EQ(600U, clone->GetFramebufferHeight());
374
375 auto shaders = clone->GetShaders();
376 ASSERT_EQ(2U, shaders.size());
377 EXPECT_EQ(kShaderTypeFragment, shaders[0].GetShaderType());
378 EXPECT_EQ(kShaderTypeVertex, shaders[1].GetShaderType());
379 EXPECT_EQ("my_main", shaders[1].GetEntryPoint());
380
381 ASSERT_TRUE(clone->GetIndexBuffer() != nullptr);
382 EXPECT_EQ("Index Buffer", clone->GetIndexBuffer()->GetName());
383
384 auto vtex_buffers = clone->GetVertexBuffers();
385 ASSERT_EQ(1U, vtex_buffers.size());
386 EXPECT_EQ(1, vtex_buffers[0].location);
387 EXPECT_EQ("vertex_buffer", vtex_buffers[0].buffer->GetName());
388
389 auto bufs = clone->GetBuffers();
390 ASSERT_EQ(2U, bufs.size());
391 EXPECT_EQ("buf1", bufs[0].buffer->GetName());
392 EXPECT_EQ(1U, bufs[0].descriptor_set);
393 EXPECT_EQ(1U, bufs[0].binding);
394
395 EXPECT_EQ("buf2", bufs[1].buffer->GetName());
396 EXPECT_EQ(1U, bufs[1].descriptor_set);
397 EXPECT_EQ(2U, bufs[1].binding);
398 }
399
TEST_F(PipelineTest,OpenCLUpdateBindings)400 TEST_F(PipelineTest, OpenCLUpdateBindings) {
401 Pipeline p(PipelineType::kCompute);
402 p.SetName("my_pipeline");
403
404 Shader cs(kShaderTypeCompute);
405 cs.SetFormat(kShaderFormatOpenCLC);
406 p.AddShader(&cs, kShaderTypeCompute);
407 p.SetShaderEntryPoint(&cs, "my_main");
408
409 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
410 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SSBO;
411 entry1.descriptor_set = 4;
412 entry1.binding = 5;
413 entry1.arg_name = "arg_a";
414 entry1.arg_ordinal = 0;
415 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
416
417 Pipeline::ShaderInfo::DescriptorMapEntry entry2;
418 entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SSBO;
419 entry2.descriptor_set = 3;
420 entry2.binding = 1;
421 entry2.arg_name = "arg_b";
422 entry2.arg_ordinal = 1;
423 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
424
425 auto a_buf = MakeUnique<Buffer>(BufferType::kStorage);
426 a_buf->SetName("buf1");
427 p.AddBuffer(a_buf.get(), "arg_a");
428
429 auto b_buf = MakeUnique<Buffer>(BufferType::kStorage);
430 b_buf->SetName("buf2");
431 p.AddBuffer(b_buf.get(), 1);
432
433 p.UpdateOpenCLBufferBindings();
434
435 auto& bufs = p.GetBuffers();
436 ASSERT_EQ(2U, bufs.size());
437 EXPECT_EQ("buf1", bufs[0].buffer->GetName());
438 EXPECT_EQ(4U, bufs[0].descriptor_set);
439 EXPECT_EQ(5U, bufs[0].binding);
440 EXPECT_EQ("buf2", bufs[1].buffer->GetName());
441 EXPECT_EQ(3U, bufs[1].descriptor_set);
442 EXPECT_EQ(1U, bufs[1].binding);
443 }
444
TEST_F(PipelineTest,OpenCLUpdateBindingTypeMismatch)445 TEST_F(PipelineTest, OpenCLUpdateBindingTypeMismatch) {
446 Pipeline p(PipelineType::kCompute);
447 p.SetName("my_pipeline");
448
449 Shader cs(kShaderTypeCompute);
450 cs.SetFormat(kShaderFormatOpenCLC);
451 p.AddShader(&cs, kShaderTypeCompute);
452 p.SetShaderEntryPoint(&cs, "my_main");
453
454 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
455 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SSBO;
456 entry1.descriptor_set = 4;
457 entry1.binding = 5;
458 entry1.arg_name = "arg_a";
459 entry1.arg_ordinal = 0;
460 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
461
462 Pipeline::ShaderInfo::DescriptorMapEntry entry2;
463 entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SSBO;
464 entry2.descriptor_set = 3;
465 entry2.binding = 1;
466 entry2.arg_name = "arg_b";
467 entry2.arg_ordinal = 1;
468 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
469
470 auto a_buf = MakeUnique<Buffer>(BufferType::kStorage);
471 a_buf->SetName("buf1");
472 p.AddBuffer(a_buf.get(), "arg_a");
473
474 auto b_buf = MakeUnique<Buffer>(BufferType::kUniform);
475 b_buf->SetName("buf2");
476 p.AddBuffer(b_buf.get(), 1);
477
478 auto r = p.UpdateOpenCLBufferBindings();
479
480 ASSERT_FALSE(r.IsSuccess());
481 EXPECT_EQ("Buffer buf2 must be an uniform binding", r.Error());
482 }
483
TEST_F(PipelineTest,OpenCLGeneratePodBuffers)484 TEST_F(PipelineTest, OpenCLGeneratePodBuffers) {
485 Pipeline p(PipelineType::kCompute);
486 p.SetName("my_pipeline");
487
488 Shader cs(kShaderTypeCompute);
489 cs.SetFormat(kShaderFormatOpenCLC);
490 p.AddShader(&cs, kShaderTypeCompute);
491 p.SetShaderEntryPoint(&cs, "my_main");
492
493 // Descriptor map.
494 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
495 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
496 entry1.descriptor_set = 4;
497 entry1.binding = 5;
498 entry1.arg_name = "arg_a";
499 entry1.arg_ordinal = 0;
500 entry1.pod_offset = 0;
501 entry1.pod_arg_size = 4;
502 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
503
504 Pipeline::ShaderInfo::DescriptorMapEntry entry2;
505 entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
506 entry2.descriptor_set = 4;
507 entry2.binding = 5;
508 entry2.arg_name = "arg_b";
509 entry2.arg_ordinal = 0;
510 entry2.pod_offset = 4;
511 entry2.pod_arg_size = 1;
512 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
513
514 Pipeline::ShaderInfo::DescriptorMapEntry entry3;
515 entry3.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
516 entry3.descriptor_set = 4;
517 entry3.binding = 4;
518 entry3.arg_name = "arg_c";
519 entry3.arg_ordinal = 0;
520 entry3.pod_offset = 0;
521 entry3.pod_arg_size = 4;
522 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry3));
523
524 // Set commands.
525 Value int_value;
526 int_value.SetIntValue(1);
527
528 TypeParser parser;
529 auto int_type = parser.Parse("R32_SINT");
530 auto int_fmt = MakeUnique<Format>(int_type.get());
531 auto char_type = parser.Parse("R8_SINT");
532 auto char_fmt = MakeUnique<Format>(char_type.get());
533
534 Pipeline::ArgSetInfo arg_info1;
535 arg_info1.name = "arg_a";
536 arg_info1.ordinal = 99;
537 arg_info1.fmt = int_fmt.get();
538 arg_info1.value = int_value;
539 p.SetArg(std::move(arg_info1));
540
541 Pipeline::ArgSetInfo arg_info2;
542 arg_info2.name = "arg_b";
543 arg_info2.ordinal = 99;
544 arg_info2.fmt = char_fmt.get();
545 arg_info2.value = int_value;
546 p.SetArg(std::move(arg_info2));
547
548 Pipeline::ArgSetInfo arg_info3;
549 arg_info3.name = "arg_c";
550 arg_info3.ordinal = 99;
551 arg_info3.fmt = int_fmt.get();
552 arg_info3.value = int_value;
553 p.SetArg(std::move(arg_info3));
554
555 auto r = p.GenerateOpenCLPodBuffers();
556 ASSERT_TRUE(r.IsSuccess());
557 EXPECT_EQ(2U, p.GetBuffers().size());
558
559 const auto& b1 = p.GetBuffers()[0];
560 EXPECT_EQ(4U, b1.descriptor_set);
561 EXPECT_EQ(5U, b1.binding);
562 EXPECT_EQ(5U, b1.buffer->ValueCount());
563
564 const auto& b2 = p.GetBuffers()[1];
565 EXPECT_EQ(4U, b2.descriptor_set);
566 EXPECT_EQ(4U, b2.binding);
567 EXPECT_EQ(4U, b2.buffer->ValueCount());
568 }
569
TEST_F(PipelineTest,OpenCLGeneratePodBuffersBadName)570 TEST_F(PipelineTest, OpenCLGeneratePodBuffersBadName) {
571 Pipeline p(PipelineType::kCompute);
572 p.SetName("my_pipeline");
573
574 Shader cs(kShaderTypeCompute);
575 cs.SetFormat(kShaderFormatOpenCLC);
576 p.AddShader(&cs, kShaderTypeCompute);
577 p.SetShaderEntryPoint(&cs, "my_main");
578
579 // Descriptor map.
580 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
581 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
582 entry1.descriptor_set = 4;
583 entry1.binding = 5;
584 entry1.arg_name = "arg_a";
585 entry1.arg_ordinal = 0;
586 entry1.pod_offset = 0;
587 entry1.pod_arg_size = 4;
588 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
589
590 // Set commands.
591 Value int_value;
592 int_value.SetIntValue(1);
593
594 TypeParser parser;
595 auto int_type = parser.Parse("R32_SINT");
596 auto int_fmt = MakeUnique<Format>(int_type.get());
597
598 Pipeline::ArgSetInfo arg_info1;
599 arg_info1.name = "arg_z";
600 arg_info1.ordinal = 99;
601 arg_info1.fmt = int_fmt.get();
602 arg_info1.value = int_value;
603 p.SetArg(std::move(arg_info1));
604
605 auto r = p.GenerateOpenCLPodBuffers();
606 ASSERT_FALSE(r.IsSuccess());
607 EXPECT_EQ(
608 "could not find descriptor map entry for SET command: kernel my_main, "
609 "name arg_z",
610 r.Error());
611 }
612
TEST_F(PipelineTest,OpenCLGeneratePodBuffersBadSize)613 TEST_F(PipelineTest, OpenCLGeneratePodBuffersBadSize) {
614 Pipeline p(PipelineType::kCompute);
615 p.SetName("my_pipeline");
616
617 Shader cs(kShaderTypeCompute);
618 cs.SetFormat(kShaderFormatOpenCLC);
619 p.AddShader(&cs, kShaderTypeCompute);
620 p.SetShaderEntryPoint(&cs, "my_main");
621
622 // Descriptor map.
623 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
624 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
625 entry1.descriptor_set = 4;
626 entry1.binding = 5;
627 entry1.arg_name = "arg_a";
628 entry1.arg_ordinal = 0;
629 entry1.pod_offset = 0;
630 entry1.pod_arg_size = 4;
631 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
632
633 // Set commands.
634 Value int_value;
635 int_value.SetIntValue(1);
636
637 TypeParser parser;
638 auto short_type = parser.Parse("R16_SINT");
639 auto short_fmt = MakeUnique<Format>(short_type.get());
640
641 Pipeline::ArgSetInfo arg_info1;
642 arg_info1.name = "";
643 arg_info1.ordinal = 0;
644 arg_info1.fmt = short_fmt.get();
645 arg_info1.value = int_value;
646 p.SetArg(std::move(arg_info1));
647
648 auto r = p.GenerateOpenCLPodBuffers();
649 ASSERT_FALSE(r.IsSuccess());
650 EXPECT_EQ("SET command uses incorrect data size: kernel my_main, number 0",
651 r.Error());
652 }
653
TEST_F(PipelineTest,OpenCLClone)654 TEST_F(PipelineTest, OpenCLClone) {
655 Pipeline p(PipelineType::kCompute);
656 p.SetName("my_pipeline");
657
658 Shader cs(kShaderTypeCompute);
659 cs.SetFormat(kShaderFormatOpenCLC);
660 p.AddShader(&cs, kShaderTypeCompute);
661 p.SetShaderEntryPoint(&cs, "my_main");
662
663 // Descriptor map.
664 Pipeline::ShaderInfo::DescriptorMapEntry entry1;
665 entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
666 entry1.descriptor_set = 4;
667 entry1.binding = 5;
668 entry1.arg_name = "arg_a";
669 entry1.arg_ordinal = 0;
670 entry1.pod_offset = 0;
671 entry1.pod_arg_size = 4;
672 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
673
674 Pipeline::ShaderInfo::DescriptorMapEntry entry2;
675 entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
676 entry2.descriptor_set = 4;
677 entry2.binding = 5;
678 entry2.arg_name = "arg_b";
679 entry2.arg_ordinal = 0;
680 entry2.pod_offset = 4;
681 entry2.pod_arg_size = 1;
682 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
683
684 Pipeline::ShaderInfo::DescriptorMapEntry entry3;
685 entry3.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
686 entry3.descriptor_set = 4;
687 entry3.binding = 4;
688 entry3.arg_name = "arg_c";
689 entry3.arg_ordinal = 0;
690 entry3.pod_offset = 0;
691 entry3.pod_arg_size = 4;
692 p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry3));
693
694 // Set commands.
695 Value int_value;
696 int_value.SetIntValue(1);
697
698 TypeParser parser;
699 auto int_type = parser.Parse("R32_SINT");
700 auto int_fmt = MakeUnique<Format>(int_type.get());
701 auto char_type = parser.Parse("R8_SINT");
702 auto char_fmt = MakeUnique<Format>(char_type.get());
703
704 Pipeline::ArgSetInfo arg_info1;
705 arg_info1.name = "arg_a";
706 arg_info1.ordinal = 99;
707 arg_info1.fmt = int_fmt.get();
708 arg_info1.value = int_value;
709 p.SetArg(std::move(arg_info1));
710
711 Pipeline::ArgSetInfo arg_info2;
712 arg_info2.name = "arg_b";
713 arg_info2.ordinal = 99;
714 arg_info2.fmt = char_fmt.get();
715 arg_info2.value = int_value;
716 p.SetArg(std::move(arg_info2));
717
718 Pipeline::ArgSetInfo arg_info3;
719 arg_info3.name = "arg_c";
720 arg_info3.ordinal = 99;
721 arg_info3.fmt = int_fmt.get();
722 arg_info3.value = int_value;
723 p.SetArg(std::move(arg_info3));
724
725 auto clone = p.Clone();
726 auto r = clone->GenerateOpenCLPodBuffers();
727 ASSERT_TRUE(r.IsSuccess());
728 EXPECT_EQ(3U, clone->SetArgValues().size());
729 EXPECT_EQ(2U, clone->GetBuffers().size());
730
731 const auto& b1 = clone->GetBuffers()[0];
732 EXPECT_EQ(4U, b1.descriptor_set);
733 EXPECT_EQ(5U, b1.binding);
734 EXPECT_EQ(5U, b1.buffer->ValueCount());
735
736 const auto& b2 = clone->GetBuffers()[1];
737 EXPECT_EQ(4U, b2.descriptor_set);
738 EXPECT_EQ(4U, b2.binding);
739 EXPECT_EQ(4U, b2.buffer->ValueCount());
740 }
741
742 } // namespace amber
743