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 parseried.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/vkscript/parser.h"
16
17 #include <vector>
18
19 #include "gtest/gtest.h"
20 #include "src/format.h"
21
22 namespace amber {
23 namespace vkscript {
24
25 using VkScriptParserTest = testing::Test;
26
TEST_F(VkScriptParserTest,RequireBlockNoArgumentFeatures)27 TEST_F(VkScriptParserTest, RequireBlockNoArgumentFeatures) {
28 struct {
29 const char* name;
30 } features[] = {{"robustBufferAccess"},
31 {"fullDrawIndexUint32"},
32 {"imageCubeArray"},
33 {"independentBlend"},
34 {"geometryShader"},
35 {"tessellationShader"},
36 {"sampleRateShading"},
37 {"dualSrcBlend"},
38 {"logicOp"},
39 {"multiDrawIndirect"},
40 {"drawIndirectFirstInstance"},
41 {"depthClamp"},
42 {"depthBiasClamp"},
43 {"fillModeNonSolid"},
44 {"depthBounds"},
45 {"wideLines"},
46 {"largePoints"},
47 {"alphaToOne"},
48 {"multiViewport"},
49 {"samplerAnisotropy"},
50 {"textureCompressionETC2"},
51 {"textureCompressionASTC_LDR"},
52 {"textureCompressionBC"},
53 {"occlusionQueryPrecise"},
54 {"pipelineStatisticsQuery"},
55 {"vertexPipelineStoresAndAtomics"},
56 {"fragmentStoresAndAtomics"},
57 {"shaderTessellationAndGeometryPointSize"},
58 {"shaderImageGatherExtended"},
59 {"shaderStorageImageExtendedFormats"},
60 {"shaderStorageImageMultisample"},
61 {"shaderStorageImageReadWithoutFormat"},
62 {"shaderStorageImageWriteWithoutFormat"},
63 {"shaderUniformBufferArrayDynamicIndexing"},
64 {"shaderSampledImageArrayDynamicIndexing"},
65 {"shaderStorageBufferArrayDynamicIndexing"},
66 {"shaderStorageImageArrayDynamicIndexing"},
67 {"shaderClipDistance"},
68 {"shaderCullDistance"},
69 {"shaderFloat64"},
70 {"shaderInt64"},
71 {"shaderInt16"},
72 {"shaderResourceResidency"},
73 {"shaderResourceMinLod"},
74 {"sparseBinding"},
75 {"sparseResidencyBuffer"},
76 {"sparseResidencyImage2D"},
77 {"sparseResidencyImage3D"},
78 {"sparseResidency2Samples"},
79 {"sparseResidency4Samples"},
80 {"sparseResidency8Samples"},
81 {"sparseResidency16Samples"},
82 {"sparseResidencyAliased"},
83 {"variableMultisampleRate"},
84 {"inheritedQueries"},
85 {"VariablePointerFeatures.variablePointers"},
86 {"VariablePointerFeatures.variablePointersStorageBuffer"}};
87
88 for (const auto& feature : features) {
89 std::string in = std::string("[require]\n") + feature.name + "\n";
90
91 Parser parser;
92 parser.SkipValidationForTest();
93 Result r = parser.Parse(in);
94 ASSERT_TRUE(r.IsSuccess()) << r.Error();
95
96 auto script = parser.GetScript();
97 auto feats = script->GetRequiredFeatures();
98 ASSERT_EQ(1U, feats.size());
99 EXPECT_EQ(feature.name, feats[0]);
100 }
101 }
102
TEST_F(VkScriptParserTest,RequireBlockExtensions)103 TEST_F(VkScriptParserTest, RequireBlockExtensions) {
104 std::string block = R"([require]
105 VK_KHR_storage_buffer_storage_class
106 VK_KHR_variable_pointers
107 VK_KHR_get_physical_device_properties2)";
108
109 Parser parser;
110 parser.SkipValidationForTest();
111 Result r = parser.Parse(block);
112 ASSERT_TRUE(r.IsSuccess()) << r.Error();
113
114 auto script = parser.GetScript();
115 auto device_exts = script->GetRequiredDeviceExtensions();
116 ASSERT_EQ(2U, device_exts.size());
117 EXPECT_EQ("VK_KHR_storage_buffer_storage_class", device_exts[0]);
118 EXPECT_EQ("VK_KHR_variable_pointers", device_exts[1]);
119
120 auto inst_exts = script->GetRequiredInstanceExtensions();
121 ASSERT_EQ(1U, inst_exts.size());
122 EXPECT_EQ("VK_KHR_get_physical_device_properties2", inst_exts[0]);
123 }
124
TEST_F(VkScriptParserTest,RequireBlockFramebuffer)125 TEST_F(VkScriptParserTest, RequireBlockFramebuffer) {
126 std::string block = "[require]\nframebuffer R32G32B32A32_SFLOAT";
127
128 Parser parser;
129 parser.SkipValidationForTest();
130 Result r = parser.Parse(block);
131 ASSERT_TRUE(r.IsSuccess());
132
133 auto script = parser.GetScript();
134 const auto& bufs = script->GetBuffers();
135 ASSERT_EQ(1U, bufs.size());
136 EXPECT_EQ(FormatType::kR32G32B32A32_SFLOAT,
137 bufs[0]->GetFormat()->GetFormatType());
138 }
139
TEST_F(VkScriptParserTest,RequireBlockDepthStencil)140 TEST_F(VkScriptParserTest, RequireBlockDepthStencil) {
141 std::string block = "[require]\ndepthstencil D24_UNORM_S8_UINT";
142
143 Parser parser;
144 parser.SkipValidationForTest();
145 Result r = parser.Parse(block);
146 ASSERT_TRUE(r.IsSuccess()) << r.Error();
147
148 auto script = parser.GetScript();
149 const auto& bufs = script->GetBuffers();
150 ASSERT_EQ(2U, bufs.size());
151 EXPECT_EQ(FormatType::kD24_UNORM_S8_UINT,
152 bufs[1]->GetFormat()->GetFormatType());
153 }
154
TEST_F(VkScriptParserTest,RequireFbSize)155 TEST_F(VkScriptParserTest, RequireFbSize) {
156 std::string block = "[require]\nfbsize 300 400";
157
158 Parser parser;
159 parser.SkipValidationForTest();
160 Result r = parser.Parse(block);
161 ASSERT_TRUE(r.IsSuccess()) << r.Error();
162
163 auto script = parser.GetScript();
164 const auto& pipelines = script->GetPipelines();
165 ASSERT_EQ(1U, pipelines.size());
166 EXPECT_EQ(300u, pipelines[0]->GetFramebufferWidth());
167 EXPECT_EQ(400u, pipelines[0]->GetFramebufferHeight());
168 }
169
TEST_F(VkScriptParserTest,RequireFbSizeMissingSize)170 TEST_F(VkScriptParserTest, RequireFbSizeMissingSize) {
171 std::string block = "[require]\nfbsize";
172
173 Parser parser;
174 Result r = parser.Parse(block);
175 ASSERT_FALSE(r.IsSuccess());
176 EXPECT_EQ("2: Missing width and height for fbsize command", r.Error());
177 }
178
TEST_F(VkScriptParserTest,RequireFbSizeMissingValue)179 TEST_F(VkScriptParserTest, RequireFbSizeMissingValue) {
180 std::string block = "[require]\nfbsize 200";
181
182 Parser parser;
183 Result r = parser.Parse(block);
184 ASSERT_FALSE(r.IsSuccess());
185 EXPECT_EQ("2: Missing height for fbsize command", r.Error());
186 }
187
TEST_F(VkScriptParserTest,RequireFbSizeExtraParams)188 TEST_F(VkScriptParserTest, RequireFbSizeExtraParams) {
189 std::string block = "[require]\nfbsize 200 300 EXTRA";
190
191 Parser parser;
192 Result r = parser.Parse(block);
193 ASSERT_FALSE(r.IsSuccess());
194 EXPECT_EQ("2: Failed to parse requirements block: invalid token: EXTRA",
195 r.Error());
196 }
197
TEST_F(VkScriptParserTest,RequireFbSizeInvalidFirstParam)198 TEST_F(VkScriptParserTest, RequireFbSizeInvalidFirstParam) {
199 std::string block = "[require]\nfbsize INVALID 200";
200
201 Parser parser;
202 Result r = parser.Parse(block);
203 ASSERT_FALSE(r.IsSuccess());
204 EXPECT_EQ("2: Invalid width for fbsize command", r.Error());
205 }
206
TEST_F(VkScriptParserTest,RequireFbSizeInvalidSecondParam)207 TEST_F(VkScriptParserTest, RequireFbSizeInvalidSecondParam) {
208 std::string block = "[require]\nfbsize 200 INVALID";
209
210 Parser parser;
211 Result r = parser.Parse(block);
212 ASSERT_FALSE(r.IsSuccess());
213 EXPECT_EQ("2: Invalid height for fbsize command", r.Error());
214 }
215
TEST_F(VkScriptParserTest,RequireBlockMultipleLines)216 TEST_F(VkScriptParserTest, RequireBlockMultipleLines) {
217 std::string block = R"([require]
218 # Requirements block stuff.
219 depthstencil D24_UNORM_S8_UINT
220 sparseResidency4Samples
221 framebuffer R32G32B32A32_SFLOAT
222 # More comments
223 inheritedQueries # line comment
224 )";
225
226 Parser parser;
227 parser.SkipValidationForTest();
228 Result r = parser.Parse(block);
229 ASSERT_TRUE(r.IsSuccess()) << r.Error();
230
231 auto script = parser.GetScript();
232 const auto& bufs = script->GetBuffers();
233 ASSERT_EQ(2U, bufs.size());
234 EXPECT_EQ(FormatType::kR32G32B32A32_SFLOAT,
235 bufs[0]->GetFormat()->GetFormatType());
236
237 EXPECT_EQ(FormatType::kD24_UNORM_S8_UINT,
238 bufs[1]->GetFormat()->GetFormatType());
239
240 auto feats = script->GetRequiredFeatures();
241 EXPECT_EQ("sparseResidency4Samples", feats[0]);
242 EXPECT_EQ("inheritedQueries", feats[1]);
243 }
244
TEST_F(VkScriptParserTest,IndicesBlock)245 TEST_F(VkScriptParserTest, IndicesBlock) {
246 std::string block = "[indices]\n1 2 3";
247
248 Parser parser;
249 parser.SkipValidationForTest();
250 Result r = parser.Parse(block);
251 ASSERT_TRUE(r.IsSuccess()) << r.Error();
252
253 auto script = parser.GetScript();
254 const auto& bufs = script->GetBuffers();
255 ASSERT_EQ(2U, bufs.size());
256
257 EXPECT_TRUE(bufs[1]->GetFormat()->IsUint32());
258 EXPECT_EQ(3U, bufs[1]->ElementCount());
259 EXPECT_EQ(3U, bufs[1]->ValueCount());
260 EXPECT_EQ(3U * sizeof(uint32_t), bufs[1]->GetSizeInBytes());
261
262 const auto* data = bufs[1]->GetValues<uint32_t>();
263 EXPECT_EQ(1u, data[0]);
264 EXPECT_EQ(2u, data[1]);
265 EXPECT_EQ(3u, data[2]);
266 }
267
TEST_F(VkScriptParserTest,IndicesBlockMultipleLines)268 TEST_F(VkScriptParserTest, IndicesBlockMultipleLines) {
269 std::string block = R"([indices]
270 # comment line
271 1 2 3 4 5 6
272 # another comment
273 7 8 9 10 11 12
274 )";
275
276 Parser parser;
277 parser.SkipValidationForTest();
278 Result r = parser.Parse(block);
279 ASSERT_TRUE(r.IsSuccess()) << r.Error();
280
281 auto script = parser.GetScript();
282 const auto& bufs = script->GetBuffers();
283 ASSERT_EQ(2U, bufs.size());
284
285 const auto* data = bufs[1]->GetValues<uint32_t>();
286 std::vector<uint16_t> results = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
287 ASSERT_EQ(results.size(), bufs[1]->ValueCount());
288 for (size_t i = 0; i < results.size(); ++i) {
289 EXPECT_EQ(results[i], data[i]);
290 }
291 }
292
TEST_F(VkScriptParserTest,IndicesBlockBadValue)293 TEST_F(VkScriptParserTest, IndicesBlockBadValue) {
294 std::string block = "[indices]\n1 a 3";
295
296 Parser parser;
297 Result r = parser.Parse(block);
298 ASSERT_FALSE(r.IsSuccess());
299 EXPECT_EQ("1: Invalid value in indices block: a", r.Error());
300 }
301
TEST_F(VkScriptParserTest,IndicesBlockValueTooLarge)302 TEST_F(VkScriptParserTest, IndicesBlockValueTooLarge) {
303 std::string block = "[indices]\n100000000000 3";
304
305 Parser parser;
306 Result r = parser.Parse(block);
307 ASSERT_FALSE(r.IsSuccess());
308 EXPECT_EQ("1: Value too large in indices block: 100000000000", r.Error());
309 }
310
TEST_F(VkScriptParserTest,VertexDataEmpty)311 TEST_F(VkScriptParserTest, VertexDataEmpty) {
312 std::string block = "[vertex data]\n#comment\n";
313
314 Parser parser;
315 parser.SkipValidationForTest();
316 Result r = parser.Parse(block);
317 ASSERT_TRUE(r.IsSuccess());
318
319 auto script = parser.GetScript();
320 EXPECT_EQ(1U, script->GetBuffers().size());
321 }
322
TEST_F(VkScriptParserTest,VertexDataHeaderFormatString)323 TEST_F(VkScriptParserTest, VertexDataHeaderFormatString) {
324 std::string block = "[vertex data]\n0/R32G32_SFLOAT 1/A8B8G8R8_UNORM_PACK32";
325
326 Parser parser;
327 parser.SkipValidationForTest();
328 Result r = parser.Parse(block);
329 ASSERT_TRUE(r.IsSuccess()) << r.Error();
330
331 auto script = parser.GetScript();
332 const auto& bufs = script->GetBuffers();
333 ASSERT_EQ(3U, bufs.size());
334
335 ASSERT_EQ(1U, script->GetPipelines().size());
336 const auto* pipeline = script->GetPipelines()[0].get();
337
338 ASSERT_EQ(2U, pipeline->GetVertexBuffers().size());
339 const auto& pipeline_buffers = pipeline->GetVertexBuffers();
340
341 EXPECT_EQ(static_cast<uint8_t>(0U), pipeline_buffers[0].location);
342 EXPECT_EQ(FormatType::kR32G32_SFLOAT, bufs[1]->GetFormat()->GetFormatType());
343 EXPECT_EQ(static_cast<uint32_t>(0), bufs[1]->ElementCount());
344
345 EXPECT_EQ(1U, pipeline_buffers[1].location);
346 EXPECT_EQ(FormatType::kA8B8G8R8_UNORM_PACK32,
347 bufs[2]->GetFormat()->GetFormatType());
348 EXPECT_EQ(static_cast<uint32_t>(0), bufs[2]->ElementCount());
349 }
350
TEST_F(VkScriptParserTest,VertexDataHeaderGlslString)351 TEST_F(VkScriptParserTest, VertexDataHeaderGlslString) {
352 std::string block = "[vertex data]\n0/float/vec2 1/int/vec3";
353
354 Parser parser;
355 parser.SkipValidationForTest();
356 Result r = parser.Parse(block);
357 ASSERT_TRUE(r.IsSuccess()) << r.Error();
358
359 auto script = parser.GetScript();
360 const auto& bufs = script->GetBuffers();
361 ASSERT_EQ(3U, bufs.size());
362
363 ASSERT_EQ(1U, script->GetPipelines().size());
364 const auto* pipeline = script->GetPipelines()[0].get();
365
366 ASSERT_EQ(2U, pipeline->GetVertexBuffers().size());
367 const auto& pipeline_buffers = pipeline->GetVertexBuffers();
368
369 EXPECT_EQ(static_cast<uint8_t>(0U), pipeline_buffers[0].location);
370
371 EXPECT_EQ(FormatType::kR32G32_SFLOAT, bufs[1]->GetFormat()->GetFormatType());
372
373 auto& segs1 = bufs[1]->GetFormat()->GetSegments();
374 ASSERT_EQ(2U, segs1.size());
375 EXPECT_EQ(FormatMode::kSFloat, segs1[0].GetFormatMode());
376 EXPECT_EQ(FormatMode::kSFloat, segs1[1].GetFormatMode());
377 EXPECT_EQ(static_cast<uint32_t>(0), bufs[1]->ElementCount());
378
379 EXPECT_EQ(1U, pipeline_buffers[1].location);
380 EXPECT_EQ(FormatType::kR32G32B32_SINT, bufs[2]->GetFormat()->GetFormatType());
381
382 auto& segs2 = bufs[2]->GetFormat()->GetSegments();
383 ASSERT_EQ(4u, segs2.size());
384 EXPECT_EQ(FormatMode::kSInt, segs2[0].GetFormatMode());
385 EXPECT_EQ(FormatMode::kSInt, segs2[1].GetFormatMode());
386 EXPECT_EQ(FormatMode::kSInt, segs2[2].GetFormatMode());
387 EXPECT_TRUE(segs2[3].IsPadding());
388 EXPECT_EQ(static_cast<uint32_t>(0), bufs[2]->ElementCount());
389 }
390
TEST_F(VkScriptParserTest,TestBlock)391 TEST_F(VkScriptParserTest, TestBlock) {
392 std::string block = R"([test]
393 clear color 255 255 255 0
394 clear depth 10
395 clear stencil 2
396 clear)";
397
398 Parser parser;
399 parser.SkipValidationForTest();
400 Result r = parser.Parse(block);
401 ASSERT_TRUE(r.IsSuccess()) << r.Error();
402
403 auto script = parser.GetScript();
404 const auto& cmds = script->GetCommands();
405 ASSERT_EQ(4U, cmds.size());
406
407 ASSERT_TRUE(cmds[0]->IsClearColor());
408 auto* color_cmd = cmds[0]->AsClearColor();
409 EXPECT_FLOAT_EQ(255.f, color_cmd->GetR());
410 EXPECT_FLOAT_EQ(255.f, color_cmd->GetG());
411 EXPECT_FLOAT_EQ(255.f, color_cmd->GetB());
412 EXPECT_FLOAT_EQ(0.0f, color_cmd->GetA());
413
414 ASSERT_TRUE(cmds[1]->IsClearDepth());
415 EXPECT_EQ(10U, cmds[1]->AsClearDepth()->GetValue());
416
417 ASSERT_TRUE(cmds[2]->IsClearStencil());
418 EXPECT_EQ(2U, cmds[2]->AsClearStencil()->GetValue());
419
420 EXPECT_TRUE(cmds[3]->IsClear());
421 }
422
TEST_F(VkScriptParserTest,VertexDataRows)423 TEST_F(VkScriptParserTest, VertexDataRows) {
424 std::string block = R"([vertex data]
425 # Vertex data
426 0/R32G32B32_SFLOAT 1/R8G8B8_UNORM
427 -1 -1 0.25 255 128 1 # ending comment
428 # Another Row
429 0.25 -1 0.25 255 128 255
430 )";
431
432 Parser parser;
433 parser.SkipValidationForTest();
434 Result r = parser.Parse(block);
435 ASSERT_TRUE(r.IsSuccess()) << r.Error();
436
437 auto script = parser.GetScript();
438 const auto& bufs = script->GetBuffers();
439 ASSERT_EQ(3U, bufs.size());
440
441 std::vector<float> seg_0 = {-1.f, -1.f, 0.25f, 0, 0.25f, -1.f, 0.25f, 0};
442 const auto* values_0 = bufs[1]->GetValues<float>();
443 for (size_t i = 0; i < seg_0.size(); ++i) {
444 EXPECT_FLOAT_EQ(seg_0[i], values_0[i]);
445 }
446
447 std::vector<uint8_t> seg_1 = {255, 128, 1, 0, 255, 128, 255, 0};
448 const auto* values_1 = bufs[2]->GetValues<uint8_t>();
449 for (size_t i = 0; i < seg_1.size(); ++i) {
450 EXPECT_EQ(seg_1[i], values_1[i]);
451 }
452 }
453
TEST_F(VkScriptParserTest,VertexDataShortRow)454 TEST_F(VkScriptParserTest, VertexDataShortRow) {
455 std::string block = R"([vertex data]
456 0/R32G32B32_SFLOAT 1/R8G8B8_UNORM
457 -1 -1 0.25 255 0 0
458 0.25 -1 0.25 255 0
459 )";
460
461 Parser parser;
462 Result r = parser.Parse(block);
463 ASSERT_FALSE(r.IsSuccess());
464 EXPECT_EQ("3: Too few cells in given vertex data row", r.Error());
465 }
466
TEST_F(VkScriptParserTest,VertexDataIncorrectValue)467 TEST_F(VkScriptParserTest, VertexDataIncorrectValue) {
468 std::string block = R"([vertex data]
469 0/R32G32B32_SFLOAT 1/R8G8B8_UNORM
470 -1 -1 0.25 255 StringValue 0
471 0.25 -1 0.25 255 0 0
472 )";
473
474 Parser parser;
475 Result r = parser.Parse(block);
476 ASSERT_FALSE(r.IsSuccess());
477 EXPECT_EQ("2: Invalid vertex data value: StringValue", r.Error());
478 }
479
TEST_F(VkScriptParserTest,VertexDataRowsWithHex)480 TEST_F(VkScriptParserTest, VertexDataRowsWithHex) {
481 std::string block = R"([vertex data]
482 0/A8B8G8R8_UNORM_PACK32
483 0xff0000ff
484 0xffff0000
485 )";
486
487 Parser parser;
488 parser.SkipValidationForTest();
489 Result r = parser.Parse(block);
490 ASSERT_TRUE(r.IsSuccess()) << r.Error();
491
492 auto script = parser.GetScript();
493 const auto& bufs = script->GetBuffers();
494 ASSERT_EQ(2U, bufs.size());
495
496 std::vector<uint32_t> seg_0 = {0xff0000ff, 0xffff0000};
497 const auto* values_0 = bufs[1]->GetValues<uint32_t>();
498 ASSERT_EQ(seg_0.size(), bufs[1]->ValueCount());
499
500 for (size_t i = 0; i < seg_0.size(); ++i) {
501 EXPECT_EQ(seg_0[i], values_0[i]);
502 }
503 }
504
TEST_F(VkScriptParserTest,VertexDataRowsWithHexWrongColumn)505 TEST_F(VkScriptParserTest, VertexDataRowsWithHexWrongColumn) {
506 std::string block = R"([vertex data]
507 0/R32G32B32_SFLOAT 1/R8G8B8_UNORM
508 -1 -1 0.25 0xffff0000
509 0.25 -1 0.25 255 0
510 )";
511
512 Parser parser;
513 Result r = parser.Parse(block);
514 ASSERT_FALSE(r.IsSuccess());
515 EXPECT_EQ("2: Invalid vertex data value: 0xffff0000", r.Error());
516 }
517
TEST_F(VkScriptParserTest,ErrorLineNumberBug195)518 TEST_F(VkScriptParserTest, ErrorLineNumberBug195) {
519 std::string input = R"([compute shader]
520 #version 430
521
522 void main() {
523 }
524
525 [test]
526 # Error must report "9: Unknown command: unknown"
527 unknown
528 })";
529
530 Parser parser;
531 Result r = parser.Parse(input);
532 ASSERT_FALSE(r.IsSuccess());
533 EXPECT_EQ("9: Unknown command: unknown", r.Error());
534 }
535
536 } // namespace vkscript
537 } // namespace amber
538