• 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_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