• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 parseried.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "gtest/gtest.h"
16 #include "src/amberscript/parser.h"
17 
18 namespace amber {
19 namespace amberscript {
20 
21 using AmberScriptParserTest = testing::Test;
22 
TEST_F(AmberScriptParserTest,Pipeline)23 TEST_F(AmberScriptParserTest, Pipeline) {
24   std::string in = R"(
25 SHADER vertex my_shader PASSTHROUGH
26 SHADER fragment my_fragment GLSL
27 # GLSL Shader
28 END
29 
30 PIPELINE graphics my_pipeline
31   ATTACH my_shader
32   ATTACH my_fragment
33 END
34 )";
35 
36   Parser parser;
37   Result r = parser.Parse(in);
38   ASSERT_TRUE(r.IsSuccess()) << r.Error();
39 
40   auto script = parser.GetScript();
41   EXPECT_EQ(2U, script->GetShaders().size());
42 
43   const auto& pipelines = script->GetPipelines();
44   ASSERT_EQ(1U, pipelines.size());
45 
46   const auto* pipeline = pipelines[0].get();
47   EXPECT_EQ("my_pipeline", pipeline->GetName());
48   EXPECT_EQ(PipelineType::kGraphics, pipeline->GetType());
49 
50   const auto& shaders = pipeline->GetShaders();
51   ASSERT_EQ(2U, shaders.size());
52 
53   ASSERT_TRUE(shaders[0].GetShader() != nullptr);
54   EXPECT_EQ("my_shader", shaders[0].GetShader()->GetName());
55   EXPECT_EQ(kShaderTypeVertex, shaders[0].GetShader()->GetType());
56   EXPECT_EQ(static_cast<uint32_t>(0),
57             shaders[0].GetShaderOptimizations().size());
58 
59   ASSERT_TRUE(shaders[1].GetShader() != nullptr);
60   EXPECT_EQ("my_fragment", shaders[1].GetShader()->GetName());
61   EXPECT_EQ(kShaderTypeFragment, shaders[1].GetShader()->GetType());
62   EXPECT_EQ(static_cast<uint32_t>(0),
63             shaders[1].GetShaderOptimizations().size());
64 }
65 
TEST_F(AmberScriptParserTest,PipelineMissingEnd)66 TEST_F(AmberScriptParserTest, PipelineMissingEnd) {
67   std::string in = R"(
68 SHADER vertex my_shader PASSTHROUGH
69 PIPELINE graphics my_pipeline
70   ATTACH my_shader
71 )";
72 
73   Parser parser;
74   Result r = parser.Parse(in);
75   ASSERT_FALSE(r.IsSuccess());
76   EXPECT_EQ("5: PIPELINE missing END command", r.Error());
77 }
78 
TEST_F(AmberScriptParserTest,PipelineWithExtraParams)79 TEST_F(AmberScriptParserTest, PipelineWithExtraParams) {
80   std::string in = R"(
81 PIPELINE graphics my_pipeline INVALID
82   ATTACH my_shader
83 END
84 )";
85 
86   Parser parser;
87   Result r = parser.Parse(in);
88   ASSERT_FALSE(r.IsSuccess());
89   EXPECT_EQ("2: extra parameters after PIPELINE command: INVALID", r.Error());
90 }
91 
TEST_F(AmberScriptParserTest,PipelineInvalidType)92 TEST_F(AmberScriptParserTest, PipelineInvalidType) {
93   std::string in = "PIPELINE my_name\nEND";
94 
95   Parser parser;
96   Result r = parser.Parse(in);
97   ASSERT_FALSE(r.IsSuccess());
98   EXPECT_EQ("1: unknown pipeline type: my_name", r.Error());
99 }
100 
TEST_F(AmberScriptParserTest,PipelineMissingName)101 TEST_F(AmberScriptParserTest, PipelineMissingName) {
102   std::string in = "PIPELINE compute\nEND";
103 
104   Parser parser;
105   Result r = parser.Parse(in);
106   ASSERT_FALSE(r.IsSuccess());
107   EXPECT_EQ("2: invalid token when looking for pipeline name", r.Error());
108 }
109 
TEST_F(AmberScriptParserTest,PipelineWithInvalidTokenType)110 TEST_F(AmberScriptParserTest, PipelineWithInvalidTokenType) {
111   std::string in = "PIPELINE 123 my_pipeline\nEND";
112 
113   Parser parser;
114   Result r = parser.Parse(in);
115   ASSERT_FALSE(r.IsSuccess());
116   EXPECT_EQ("1: invalid token when looking for pipeline type", r.Error());
117 }
118 
TEST_F(AmberScriptParserTest,PipelineWithInvalidTokenName)119 TEST_F(AmberScriptParserTest, PipelineWithInvalidTokenName) {
120   std::string in = "PIPELINE compute 123\nEND";
121 
122   Parser parser;
123   Result r = parser.Parse(in);
124   ASSERT_FALSE(r.IsSuccess());
125   EXPECT_EQ("1: invalid token when looking for pipeline name", r.Error());
126 }
127 
TEST_F(AmberScriptParserTest,PipelineEmpty)128 TEST_F(AmberScriptParserTest, PipelineEmpty) {
129   std::string in = "PIPELINE compute my_pipeline\nEND";
130 
131   Parser parser;
132   Result r = parser.Parse(in);
133   ASSERT_FALSE(r.IsSuccess());
134   EXPECT_EQ("compute pipeline requires a compute shader", r.Error());
135 }
136 
TEST_F(AmberScriptParserTest,PipelineWithUnknownCommand)137 TEST_F(AmberScriptParserTest, PipelineWithUnknownCommand) {
138   std::string in = R"(
139 PIPELINE compute my_pipeline
140   SHADER vertex my_shader PASSTHROUGH
141 END)";
142 
143   Parser parser;
144   Result r = parser.Parse(in);
145   ASSERT_FALSE(r.IsSuccess());
146   EXPECT_EQ("3: unknown token in pipeline block: SHADER", r.Error());
147 }
148 
TEST_F(AmberScriptParserTest,DuplicatePipelineName)149 TEST_F(AmberScriptParserTest, DuplicatePipelineName) {
150   std::string in = R"(
151 SHADER vertex my_shader PASSTHROUGH
152 SHADER fragment my_fragment GLSL
153 # Fragment shader
154 END
155 
156 PIPELINE graphics my_pipeline
157   ATTACH my_shader
158   ATTACH my_fragment
159 END
160 PIPELINE graphics my_pipeline
161   ATTACH my_shader
162   ATTACH my_fragment
163 END)";
164 
165   Parser parser;
166   Result r = parser.Parse(in);
167   ASSERT_FALSE(r.IsSuccess());
168   EXPECT_EQ("14: duplicate pipeline name provided", r.Error());
169 }
170 
TEST_F(AmberScriptParserTest,PipelineDefaultColorBuffer)171 TEST_F(AmberScriptParserTest, PipelineDefaultColorBuffer) {
172   std::string in = R"(
173 SHADER vertex my_shader PASSTHROUGH
174 SHADER fragment my_fragment GLSL
175 # GLSL Shader
176 END
177 
178 PIPELINE graphics my_pipeline
179   ATTACH my_shader
180   ATTACH my_fragment
181 END
182 PIPELINE graphics my_pipeline2
183   ATTACH my_shader
184   ATTACH my_fragment
185 END)";
186 
187   Parser parser;
188   Result r = parser.Parse(in);
189   ASSERT_TRUE(r.IsSuccess()) << r.Error();
190 
191   auto script = parser.GetScript();
192   const auto& pipelines = script->GetPipelines();
193   ASSERT_EQ(2U, pipelines.size());
194 
195   ASSERT_EQ(1U, pipelines[0]->GetColorAttachments().size());
196   const auto& buf1 = pipelines[0]->GetColorAttachments()[0];
197   ASSERT_TRUE(buf1.buffer != nullptr);
198 
199   Buffer* buffer1 = buf1.buffer;
200   EXPECT_EQ(FormatType::kB8G8R8A8_UNORM, buffer1->GetFormat()->GetFormatType());
201   EXPECT_EQ(0u, buf1.location);
202   EXPECT_EQ(250u * 250u, buffer1->ElementCount());
203   EXPECT_EQ(250u * 250u * 4u, buffer1->ValueCount());
204   EXPECT_EQ(250u * 250u * 4u * sizeof(uint8_t), buffer1->GetSizeInBytes());
205 
206   ASSERT_EQ(1U, pipelines[1]->GetColorAttachments().size());
207   const auto& buf2 = pipelines[1]->GetColorAttachments()[0];
208   ASSERT_TRUE(buf2.buffer != nullptr);
209   ASSERT_EQ(buffer1, buf2.buffer);
210   EXPECT_EQ(0u, buf2.location);
211   EXPECT_EQ(FormatType::kB8G8R8A8_UNORM,
212             buf2.buffer->GetFormat()->GetFormatType());
213   EXPECT_EQ(250u * 250u, buf2.buffer->ElementCount());
214   EXPECT_EQ(250u * 250u * 4u, buf2.buffer->ValueCount());
215   EXPECT_EQ(250u * 250u * 4u * sizeof(uint8_t), buf2.buffer->GetSizeInBytes());
216 }
217 
TEST_F(AmberScriptParserTest,PipelineDefaultColorBufferMismatchSize)218 TEST_F(AmberScriptParserTest, PipelineDefaultColorBufferMismatchSize) {
219   std::string in = R"(
220 SHADER vertex my_shader PASSTHROUGH
221 SHADER fragment my_fragment GLSL
222 # GLSL Shader
223 END
224 
225 PIPELINE graphics my_pipeline
226   ATTACH my_shader
227   ATTACH my_fragment
228 END
229 PIPELINE graphics my_pipeline2
230   ATTACH my_shader
231   ATTACH my_fragment
232   FRAMEBUFFER_SIZE 256 256
233 END)";
234 
235   Parser parser;
236   Result r = parser.Parse(in);
237   ASSERT_FALSE(r.IsSuccess());
238 
239   EXPECT_EQ("shared framebuffer must have same size over all PIPELINES",
240             r.Error());
241 }
242 
TEST_F(AmberScriptParserTest,PipelinePolygonMode)243 TEST_F(AmberScriptParserTest, PipelinePolygonMode) {
244   std::string in = R"(
245 SHADER vertex my_shader PASSTHROUGH
246 SHADER fragment my_fragment GLSL
247 # GLSL Shader
248 END
249 
250 PIPELINE graphics my_pipeline_default
251   ATTACH my_shader
252   ATTACH my_fragment
253   FRAMEBUFFER_SIZE 256 256
254 END
255 PIPELINE graphics my_pipeline_fill
256   ATTACH my_shader
257   ATTACH my_fragment
258   POLYGON_MODE fill
259   FRAMEBUFFER_SIZE 256 256
260 END
261 PIPELINE graphics my_pipeline_line
262   ATTACH my_shader
263   ATTACH my_fragment
264   POLYGON_MODE line
265   FRAMEBUFFER_SIZE 256 256
266 END
267 PIPELINE graphics my_pipeline_point
268   ATTACH my_shader
269   ATTACH my_fragment
270   POLYGON_MODE point
271   FRAMEBUFFER_SIZE 256 256
272 END)";
273 
274   Parser parser;
275   Result r = parser.Parse(in);
276   ASSERT_TRUE(r.IsSuccess());
277 
278   auto script = parser.GetScript();
279   const auto& pipelines = script->GetPipelines();
280   ASSERT_EQ(4U, pipelines.size());
281 
282   auto mode0 = pipelines[0]->GetPipelineData()->GetPolygonMode();
283   ASSERT_EQ(mode0, PolygonMode::kFill);
284   auto mode1 = pipelines[1]->GetPipelineData()->GetPolygonMode();
285   ASSERT_EQ(mode1, PolygonMode::kFill);
286   auto mode2 = pipelines[2]->GetPipelineData()->GetPolygonMode();
287   ASSERT_EQ(mode2, PolygonMode::kLine);
288   auto mode3 = pipelines[3]->GetPipelineData()->GetPolygonMode();
289   ASSERT_EQ(mode3, PolygonMode::kPoint);
290 }
291 
TEST_F(AmberScriptParserTest,PipelineMissingPolygonMode)292 TEST_F(AmberScriptParserTest, PipelineMissingPolygonMode) {
293   std::string in = R"(
294 SHADER vertex my_shader PASSTHROUGH
295 SHADER fragment my_fragment GLSL
296 # GLSL Shader
297 END
298 
299 PIPELINE graphics my_pipeline
300   ATTACH my_shader
301   ATTACH my_fragment
302   POLYGON_MODE
303   FRAMEBUFFER_SIZE 256 256
304 END)";
305 
306   Parser parser;
307   Result r = parser.Parse(in);
308   ASSERT_FALSE(r.IsSuccess());
309 
310   EXPECT_EQ("11: missing mode in POLYGON_MODE command", r.Error());
311 }
312 
TEST_F(AmberScriptParserTest,PipelineInvalidPolygonMode)313 TEST_F(AmberScriptParserTest, PipelineInvalidPolygonMode) {
314   std::string in = R"(
315 SHADER vertex my_shader PASSTHROUGH
316 SHADER fragment my_fragment GLSL
317 # GLSL Shader
318 END
319 
320 PIPELINE graphics my_pipeline
321   ATTACH my_shader
322   ATTACH my_fragment
323   POLYGON_MODE foo
324   FRAMEBUFFER_SIZE 256 256
325 END)";
326 
327   Parser parser;
328   Result r = parser.Parse(in);
329   ASSERT_FALSE(r.IsSuccess());
330 
331   EXPECT_EQ("10: invalid polygon mode: foo", r.Error());
332 }
333 
TEST_F(AmberScriptParserTest,DerivePipeline)334 TEST_F(AmberScriptParserTest, DerivePipeline) {
335   std::string in = R"(
336 SHADER vertex my_shader PASSTHROUGH
337 SHADER fragment my_fragment GLSL
338 # GLSL Shader
339 END
340 SHADER fragment other_fragment GLSL
341 # GLSL Shader
342 END
343 BUFFER buf1 DATA_TYPE int32 SIZE 20 FILL 5
344 BUFFER buf2 DATA_TYPE int32 SIZE 20 FILL 7
345 
346 PIPELINE graphics parent_pipeline
347   ATTACH my_shader
348   ATTACH my_fragment
349   BIND BUFFER buf1 AS storage DESCRIPTOR_SET 1 BINDING 3
350 END
351 
352 DERIVE_PIPELINE child_pipeline FROM parent_pipeline
353   ATTACH other_fragment
354   BIND BUFFER buf2 AS storage DESCRIPTOR_SET 1 BINDING 3
355 END
356 )";
357 
358   Parser parser;
359   Result r = parser.Parse(in);
360   ASSERT_TRUE(r.IsSuccess()) << r.Error();
361 
362   auto script = parser.GetScript();
363   const auto& pipelines = script->GetPipelines();
364   ASSERT_EQ(2U, pipelines.size());
365 
366   const auto* pipeline1 = pipelines[0].get();
367   auto buffers1 = pipeline1->GetBuffers();
368   ASSERT_EQ(1U, buffers1.size());
369   EXPECT_EQ("buf1", buffers1[0].buffer->GetName());
370   EXPECT_EQ(1u, buffers1[0].descriptor_set);
371   EXPECT_EQ(3u, buffers1[0].binding);
372 
373   auto shaders1 = pipeline1->GetShaders();
374   ASSERT_EQ(2U, shaders1.size());
375   EXPECT_EQ("my_shader", shaders1[0].GetShader()->GetName());
376   EXPECT_EQ("my_fragment", shaders1[1].GetShader()->GetName());
377 
378   const auto* pipeline2 = pipelines[1].get();
379   EXPECT_EQ("child_pipeline", pipeline2->GetName());
380 
381   auto buffers2 = pipeline2->GetBuffers();
382   ASSERT_EQ(1U, buffers2.size());
383   EXPECT_EQ("buf2", buffers2[0].buffer->GetName());
384   EXPECT_EQ(1u, buffers2[0].descriptor_set);
385   EXPECT_EQ(3u, buffers2[0].binding);
386 
387   auto shaders2 = pipeline2->GetShaders();
388   ASSERT_EQ(2U, shaders2.size());
389   EXPECT_EQ("my_shader", shaders2[0].GetShader()->GetName());
390   EXPECT_EQ("other_fragment", shaders2[1].GetShader()->GetName());
391 }
392 
TEST_F(AmberScriptParserTest,DerivePipelineMissingEnd)393 TEST_F(AmberScriptParserTest, DerivePipelineMissingEnd) {
394   std::string in = R"(
395 SHADER vertex my_shader PASSTHROUGH
396 SHADER fragment my_fragment GLSL
397 # GLSL Shader
398 END
399 
400 PIPELINE graphics parent_pipeline
401   ATTACH my_shader
402   ATTACH my_fragment
403 END
404 
405 DERIVE_PIPELINE derived_pipeline FROM parent_pipeline
406 )";
407 
408   Parser parser;
409   Result r = parser.Parse(in);
410   ASSERT_FALSE(r.IsSuccess());
411   EXPECT_EQ("13: DERIVE_PIPELINE missing END command", r.Error());
412 }
413 
TEST_F(AmberScriptParserTest,DerivePipelineMissingPipelineName)414 TEST_F(AmberScriptParserTest, DerivePipelineMissingPipelineName) {
415   std::string in = R"(
416 SHADER vertex my_shader PASSTHROUGH
417 SHADER fragment my_fragment GLSL
418 # GLSL Shader
419 END
420 
421 PIPELINE graphics parent_pipeline
422   ATTACH my_shader
423   ATTACH my_fragment
424 END
425 
426 DERIVE_PIPELINE FROM parent_pipeline
427 END
428 )";
429 
430   Parser parser;
431   Result r = parser.Parse(in);
432   ASSERT_FALSE(r.IsSuccess());
433   EXPECT_EQ("12: missing pipeline name for DERIVE_PIPELINE command", r.Error());
434 }
435 
TEST_F(AmberScriptParserTest,DerivePipelineMissingFrom)436 TEST_F(AmberScriptParserTest, DerivePipelineMissingFrom) {
437   std::string in = R"(
438 DERIVE_PIPELINE derived_pipeline parent_pipeline
439 END
440 )";
441 
442   Parser parser;
443   Result r = parser.Parse(in);
444   ASSERT_FALSE(r.IsSuccess());
445   EXPECT_EQ("2: missing FROM in DERIVE_PIPELINE command", r.Error());
446 }
447 
TEST_F(AmberScriptParserTest,DerivePipelineMissingParentPipelineName)448 TEST_F(AmberScriptParserTest, DerivePipelineMissingParentPipelineName) {
449   std::string in = R"(
450 DERIVE_PIPELINE derived_pipeline FROM
451 END
452 )";
453 
454   Parser parser;
455   Result r = parser.Parse(in);
456   ASSERT_FALSE(r.IsSuccess());
457   EXPECT_EQ("3: missing parent pipeline name in DERIVE_PIPELINE command",
458             r.Error());
459 }
460 
TEST_F(AmberScriptParserTest,DerivePipelineUnknownParentPipeline)461 TEST_F(AmberScriptParserTest, DerivePipelineUnknownParentPipeline) {
462   std::string in = R"(
463 DERIVE_PIPELINE derived_pipeline FROM parent_pipeline
464 END
465 )";
466 
467   Parser parser;
468   Result r = parser.Parse(in);
469   ASSERT_FALSE(r.IsSuccess());
470   EXPECT_EQ("2: unknown parent pipeline in DERIVE_PIPELINE command", r.Error());
471 }
472 
TEST_F(AmberScriptParserTest,DerivePipelineDuplicatePipelineName)473 TEST_F(AmberScriptParserTest, DerivePipelineDuplicatePipelineName) {
474   std::string in = R"(
475 SHADER vertex my_shader PASSTHROUGH
476 SHADER fragment my_fragment GLSL
477 # GLSL Shader
478 END
479 
480 PIPELINE graphics parent_pipeline
481   ATTACH my_shader
482   ATTACH my_fragment
483 END
484 
485 DERIVE_PIPELINE parent_pipeline FROM parent_pipeline
486 END
487 )";
488 
489   Parser parser;
490   Result r = parser.Parse(in);
491   ASSERT_FALSE(r.IsSuccess());
492   EXPECT_EQ("12: duplicate pipeline name for DERIVE_PIPELINE command",
493             r.Error());
494 }
495 
TEST_F(AmberScriptParserTest,DerivePipelineNoParams)496 TEST_F(AmberScriptParserTest, DerivePipelineNoParams) {
497   std::string in = R"(
498 DERIVE_PIPELINE
499 END
500 )";
501 
502   Parser parser;
503   Result r = parser.Parse(in);
504   ASSERT_FALSE(r.IsSuccess());
505   EXPECT_EQ("3: missing pipeline name for DERIVE_PIPELINE command", r.Error());
506 }
507 
TEST_F(AmberScriptParserTest,DerivePipelineSpecialized)508 TEST_F(AmberScriptParserTest, DerivePipelineSpecialized) {
509   std::string in = R"(
510 SHADER compute my_shader GLSL
511 #shaders
512 END
513 PIPELINE compute p1
514   ATTACH my_shader SPECIALIZE 3 AS uint32 4
515 END
516 DERIVE_PIPELINE p2 FROM p1
517 END
518 )";
519 
520   Parser parser;
521   Result r = parser.Parse(in);
522   EXPECT_EQ("", r.Error());
523   ASSERT_TRUE(r.IsSuccess());
524 
525   auto script = parser.GetScript();
526   const auto& pipelines = script->GetPipelines();
527   ASSERT_EQ(2U, pipelines.size());
528 
529   const auto* p1 = pipelines[0].get();
530   const auto& s1 = p1->GetShaders();
531   ASSERT_EQ(1U, s1.size());
532 
533   EXPECT_EQ(1u, s1[0].GetSpecialization().size());
534   EXPECT_EQ(4u, s1[0].GetSpecialization().at(3));
535 
536   const auto* p2 = pipelines[1].get();
537   const auto& s2 = p2->GetShaders();
538   ASSERT_EQ(1U, s2.size());
539 
540   EXPECT_EQ(1u, s2[0].GetSpecialization().size());
541   EXPECT_EQ(4u, s2[0].GetSpecialization().at(3));
542 }
543 
544 }  // namespace amberscript
545 }  // namespace amber
546