• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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