1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2021 The Khronos Group Inc.
6 * Copyright (c) 2021 Valve Corporation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Mesh Shader Property Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktMeshShaderPropertyTests.hpp"
26 #include "vktMeshShaderUtil.hpp"
27 #include "vktTestCase.hpp"
28
29 #include "vkBufferWithMemory.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkBuilderUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkBarrierUtil.hpp"
35
36 #include "tcuStringTemplate.hpp"
37
38 #include <vector>
39 #include <string>
40 #include <map>
41 #include <sstream>
42
43 namespace vkt
44 {
45 namespace MeshShader
46 {
47
48 namespace
49 {
50
51 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
52 using ReplacementsMap = std::map<std::string, std::string>;
53
54 using namespace vk;
55
getTaskShaderTemplate()56 tcu::StringTemplate getTaskShaderTemplate ()
57 {
58 return tcu::StringTemplate(
59 "#version 460\n"
60 "#extension GL_NV_mesh_shader : enable\n"
61 "\n"
62 "layout (local_size_x=${TASK_LOCAL_SIZE_X:default=1}) in;\n"
63 "\n"
64 "${TASK_GLOBAL_DECL:opt}"
65 "\n"
66 "${TASK_MESH_INTERFACE_OUT:opt}"
67 "\n"
68 "void main ()\n"
69 "{\n"
70 " gl_TaskCountNV = ${TASK_TASK_COUNT:default=0};\n"
71 "${TASK_BODY:opt}"
72 "}\n");
73 }
74
getMeshShaderTemplate()75 tcu::StringTemplate getMeshShaderTemplate ()
76 {
77 return tcu::StringTemplate(
78 "#version 460\n"
79 "#extension GL_NV_mesh_shader : enable\n"
80 "\n"
81 "layout (local_size_x=${MESH_LOCAL_SIZE_X:default=1}) in;\n"
82 "layout (triangles) out;\n"
83 "layout (max_vertices=3, max_primitives=1) out;\n"
84 "\n"
85 "${MESH_GLOBAL_DECL:opt}"
86 "\n"
87 "${TASK_MESH_INTERFACE_IN:opt}"
88 "\n"
89 "void main ()\n"
90 "{\n"
91 " gl_PrimitiveCountNV = 0u;\n"
92 "${MESH_BODY:opt}"
93 "}\n");
94 }
95
getCommonStorageBufferDecl()96 std::string getCommonStorageBufferDecl ()
97 {
98 return "layout (set=0, binding=0) buffer OutputBlock { uint values[]; } ov;\n";
99 }
100
genericCheckSupport(Context & context,bool taskShaderNeeded)101 void genericCheckSupport (Context& context, bool taskShaderNeeded)
102 {
103 checkTaskMeshShaderSupportNV(context, taskShaderNeeded, true);
104
105 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
106 }
107
108 struct InstanceParams
109 {
110 uint32_t bufferElements;
111 uint32_t taskCount;
112 };
113
114 class MeshShaderPropertyInstance : public vkt::TestInstance
115 {
116 public:
MeshShaderPropertyInstance(Context & context,const InstanceParams & params)117 MeshShaderPropertyInstance (Context& context, const InstanceParams& params)
118 : vkt::TestInstance (context)
119 , m_params (params)
120 {}
~MeshShaderPropertyInstance(void)121 virtual ~MeshShaderPropertyInstance (void) {}
122
123 tcu::TestStatus iterate () override;
124
125 protected:
126 InstanceParams m_params;
127 };
128
iterate()129 tcu::TestStatus MeshShaderPropertyInstance::iterate ()
130 {
131 const auto& vkd = m_context.getDeviceInterface();
132 const auto device = m_context.getDevice();
133 auto& alloc = m_context.getDefaultAllocator();
134 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
135 const auto queue = m_context.getUniversalQueue();
136 const auto& binaries = m_context.getBinaryCollection();
137 const auto extent = makeExtent3D(1u, 1u, 1u);
138 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
139 const auto useTask = binaries.contains("task");
140
141 const auto storageBufferSize = static_cast<VkDeviceSize>(m_params.bufferElements) * static_cast<VkDeviceSize>(sizeof(uint32_t));
142 const auto storageBufferUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
143 const auto storageBufferType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
144 const auto storageBufferStages = (VK_SHADER_STAGE_MESH_BIT_NV | (useTask ? VK_SHADER_STAGE_TASK_BIT_NV : 0));
145
146 // Create storage buffer with the required space.
147 const auto storageBufferInfo = makeBufferCreateInfo(storageBufferSize, storageBufferUsage);
148 BufferWithMemory storageBuffer (vkd, device, alloc, storageBufferInfo, MemoryRequirement::HostVisible);
149 auto& storageBufferAlloc = storageBuffer.getAllocation();
150 void* storageBufferDataPtr = storageBufferAlloc.getHostPtr();
151 const auto storageBufferDescInfo = makeDescriptorBufferInfo(storageBuffer.get(), 0ull, storageBufferSize);
152
153 deMemset(storageBufferDataPtr, 0xFF, static_cast<size_t>(storageBufferSize));
154 flushAlloc(vkd, device, storageBufferAlloc);
155
156 // Descriptor pool.
157 DescriptorPoolBuilder poolBuilder;
158 poolBuilder.addType(storageBufferType);
159 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
160
161 // Descriptor set layout and pipeline layout.
162 DescriptorSetLayoutBuilder layoutBuilder;
163 layoutBuilder.addSingleBinding(storageBufferType, storageBufferStages);
164 const auto setLayout = layoutBuilder.build(vkd, device);
165 const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
166
167 // Allocate and prepare descriptor set.
168 const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
169
170 DescriptorSetUpdateBuilder setUpdateBuilder;
171 setUpdateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), storageBufferType, &storageBufferDescInfo);
172 setUpdateBuilder.update(vkd, device);
173
174 // Create empty render pass and framebuffer.
175 const auto renderPass = makeRenderPass(vkd, device);
176 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), 0u, nullptr, extent.width, extent.height);
177
178 // Shader modules and pipeline.
179 Move<VkShaderModule> taskModule;
180 Move<VkShaderModule> meshModule;
181 const Move<VkShaderModule> fragModule; // No fragment shader.
182
183 if (useTask)
184 taskModule = createShaderModule(vkd, device, binaries.get("task"));
185 meshModule = createShaderModule(vkd, device, binaries.get("mesh"));
186
187 const std::vector<VkViewport> viewports (1u, makeViewport(extent));
188 const std::vector<VkRect2D> scissors (1u, makeRect2D(extent));
189
190 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
191 taskModule.get(), meshModule.get(), fragModule.get(),
192 renderPass.get(), viewports, scissors);
193
194 // Command pool and buffer.
195 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
196 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
197 const auto cmdBuffer = cmdBufferPtr.get();
198
199 // Run the pipeline.
200 beginCommandBuffer(vkd, cmdBuffer);
201
202 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0));
203 vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
204 vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get());
205 vkd.cmdDrawMeshTasksNV(cmdBuffer, m_params.taskCount, 0u);
206 endRenderPass(vkd, cmdBuffer);
207
208 const auto shaderToHostBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
209 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &shaderToHostBarrier, 0u, nullptr, 0u, nullptr);
210
211 endCommandBuffer(vkd, cmdBuffer);
212 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
213
214 // Verify the storage buffer has the expected results.
215 invalidateAlloc(vkd, device, storageBufferAlloc);
216
217 std::vector<uint32_t> bufferData (m_params.bufferElements);
218 deMemcpy(bufferData.data(), storageBufferDataPtr, de::dataSize(bufferData));
219
220 for (size_t idx = 0u; idx < bufferData.size(); ++idx)
221 {
222 const auto expected = static_cast<uint32_t>(idx);
223 const auto& bufferValue = bufferData[idx];
224
225 if (bufferValue != expected)
226 TCU_FAIL("Unexpected value found in buffer position " + de::toString(idx) + ": " + de::toString(bufferValue));
227 }
228
229 return tcu::TestStatus::pass("Pass");
230 }
231
232 class MaxDrawMeshTasksCountCase : public vkt::TestCase
233 {
234 public:
235 enum class TestType { TASK=0, MESH };
236
MaxDrawMeshTasksCountCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,TestType testType)237 MaxDrawMeshTasksCountCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, TestType testType)
238 : vkt::TestCase (testCtx, name, description)
239 , m_testType (testType)
240 {}
~MaxDrawMeshTasksCountCase(void)241 virtual ~MaxDrawMeshTasksCountCase (void) {}
242
243 void initPrograms (vk::SourceCollections& programCollection) const override;
244 TestInstance* createInstance (Context& context) const override;
245 void checkSupport (Context& context) const override;
246
247 static constexpr uint32_t minLimit = 65535u;
248
249 protected:
250 TestType m_testType;
251 };
252
checkSupport(Context & context) const253 void MaxDrawMeshTasksCountCase::checkSupport (Context& context) const
254 {
255 genericCheckSupport(context, (m_testType == TestType::TASK));
256
257 const auto& properties = context.getMeshShaderProperties();
258 if (properties.maxDrawMeshTasksCount < minLimit)
259 TCU_FAIL("maxDrawMeshTasksCount property below the minimum limit");
260 }
261
createInstance(Context & context) const262 TestInstance* MaxDrawMeshTasksCountCase::createInstance (Context& context) const
263 {
264 const InstanceParams params =
265 {
266 minLimit, // uint32_t bufferElements;
267 minLimit, // uint32_t taskCount;
268 };
269 return new MeshShaderPropertyInstance(context, params);
270 }
271
initPrograms(vk::SourceCollections & programCollection) const272 void MaxDrawMeshTasksCountCase::initPrograms (vk::SourceCollections& programCollection) const
273 {
274 ReplacementsMap meshReplacements;
275 ReplacementsMap taskReplacements;
276
277 const auto meshTemplate = getMeshShaderTemplate();
278
279 const std::string desc = getCommonStorageBufferDecl();
280 const std::string body = " ov.values[gl_WorkGroupID.x] = gl_WorkGroupID.x;\n";
281
282 if (m_testType == TestType::TASK)
283 {
284 const auto taskTemplate = getTaskShaderTemplate();
285 taskReplacements["TASK_GLOBAL_DECL"] = desc;
286 taskReplacements["TASK_BODY"] = body;
287
288 programCollection.glslSources.add("task") << glu::TaskSource(taskTemplate.specialize(taskReplacements));
289 }
290 else
291 {
292 meshReplacements["MESH_GLOBAL_DECL"] = desc;
293 meshReplacements["MESH_BODY"] = body;
294 }
295
296 programCollection.glslSources.add("mesh") << glu::MeshSource(meshTemplate.specialize(meshReplacements));
297 }
298
299 class MaxTaskWorkGroupInvocationsCase : public vkt::TestCase
300 {
301 public:
MaxTaskWorkGroupInvocationsCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)302 MaxTaskWorkGroupInvocationsCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description)
303 : vkt::TestCase (testCtx, name, description) {}
~MaxTaskWorkGroupInvocationsCase(void)304 virtual ~MaxTaskWorkGroupInvocationsCase (void) {}
305
306 void initPrograms (vk::SourceCollections& programCollection) const override;
307 TestInstance* createInstance (Context& context) const override;
308 void checkSupport (Context& context) const override;
309
310 static constexpr uint32_t minLimit = 32u;
311 };
312
checkSupport(Context & context) const313 void MaxTaskWorkGroupInvocationsCase::checkSupport (Context& context) const
314 {
315 genericCheckSupport(context, true/*taskShaderNeeded*/);
316
317 const auto& properties = context.getMeshShaderProperties();
318 if (properties.maxTaskWorkGroupInvocations < minLimit)
319 TCU_FAIL("maxTaskWorkGroupInvocations property below the minimum limit");
320 }
321
createInstance(Context & context) const322 TestInstance* MaxTaskWorkGroupInvocationsCase::createInstance (Context& context) const
323 {
324 const InstanceParams params =
325 {
326 minLimit, // uint32_t bufferElements;
327 1u, // uint32_t taskCount;
328 };
329 return new MeshShaderPropertyInstance(context, params);
330 }
331
initPrograms(vk::SourceCollections & programCollection) const332 void MaxTaskWorkGroupInvocationsCase::initPrograms (vk::SourceCollections& programCollection) const
333 {
334 const ReplacementsMap meshReplacements;
335 const auto meshTemplate = getMeshShaderTemplate();
336
337 programCollection.glslSources.add("mesh") << glu::MeshSource(meshTemplate.specialize(meshReplacements));
338
339 ReplacementsMap taskReplacements;
340 const auto taskTemplate = getTaskShaderTemplate();
341
342 taskReplacements["TASK_GLOBAL_DECL"] = getCommonStorageBufferDecl();
343 taskReplacements["TASK_BODY"] = " ov.values[gl_LocalInvocationID.x] = gl_LocalInvocationID.x;\n";
344 taskReplacements["TASK_LOCAL_SIZE_X"] = de::toString(uint32_t{minLimit});
345
346 programCollection.glslSources.add("task") << glu::TaskSource(taskTemplate.specialize(taskReplacements));
347 }
348
349 // In the case of the NV extension, this is very similar to the test above. Added for completion.
350 class MaxTaskWorkGroupSizeCase : public MaxTaskWorkGroupInvocationsCase
351 {
352 public:
MaxTaskWorkGroupSizeCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)353 MaxTaskWorkGroupSizeCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description)
354 : MaxTaskWorkGroupInvocationsCase (testCtx, name, description) {}
355
356 void checkSupport (Context& context) const override;
357
358 static constexpr uint32_t minSizeX = 32u;
359 static constexpr uint32_t minSizeY = 1u;
360 static constexpr uint32_t minSizeZ = 1u;
361 };
362
checkSupport(Context & context) const363 void MaxTaskWorkGroupSizeCase::checkSupport (Context& context) const
364 {
365 genericCheckSupport(context, true/*taskShaderNeeded*/);
366
367 const auto& properties = context.getMeshShaderProperties();
368 if (properties.maxTaskWorkGroupSize[0] < minSizeX ||
369 properties.maxTaskWorkGroupSize[1] < minSizeY ||
370 properties.maxTaskWorkGroupSize[2] < minSizeZ)
371 {
372 TCU_FAIL("maxTaskWorkGroupSize property below the minimum limit");
373 }
374 }
375
376 class MaxTaskOutputCountCase : public vkt::TestCase
377 {
378 public:
MaxTaskOutputCountCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)379 MaxTaskOutputCountCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description)
380 : vkt::TestCase (testCtx, name, description) {}
~MaxTaskOutputCountCase(void)381 virtual ~MaxTaskOutputCountCase (void) {}
382
383 void initPrograms (vk::SourceCollections& programCollection) const override;
384 TestInstance* createInstance (Context& context) const override;
385 void checkSupport (Context& context) const override;
386
387 static constexpr uint32_t minLimit = 65535u;
388 };
389
checkSupport(Context & context) const390 void MaxTaskOutputCountCase::checkSupport (Context& context) const
391 {
392 genericCheckSupport(context, true/*taskShaderNeeded*/);
393
394 const auto& properties = context.getMeshShaderProperties();
395 if (properties.maxTaskOutputCount < minLimit)
396 TCU_FAIL("maxTaskOutputCount property below the minimum limit");
397 }
398
createInstance(Context & context) const399 TestInstance* MaxTaskOutputCountCase::createInstance (Context& context) const
400 {
401 const InstanceParams params =
402 {
403 minLimit, // uint32_t bufferElements;
404 1u, // uint32_t taskCount;
405 };
406 return new MeshShaderPropertyInstance(context, params);
407 }
408
initPrograms(vk::SourceCollections & programCollection) const409 void MaxTaskOutputCountCase::initPrograms (vk::SourceCollections& programCollection) const
410 {
411 ReplacementsMap meshReplacements;
412 ReplacementsMap taskReplacements;
413 const auto meshTemplate = getMeshShaderTemplate();
414 const auto taskTemplate = getTaskShaderTemplate();
415
416 taskReplacements["TASK_TASK_COUNT"] = de::toString(uint32_t{minLimit});
417 meshReplacements["MESH_GLOBAL_DECL"] = getCommonStorageBufferDecl();
418 meshReplacements["MESH_BODY"] = " ov.values[gl_WorkGroupID.x] = gl_WorkGroupID.x;\n";
419
420 programCollection.glslSources.add("task") << glu::TaskSource(taskTemplate.specialize(taskReplacements));
421 programCollection.glslSources.add("mesh") << glu::MeshSource(meshTemplate.specialize(meshReplacements));
422 }
423
424 class MaxMeshWorkGroupInvocationsCase : public vkt::TestCase
425 {
426 public:
MaxMeshWorkGroupInvocationsCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)427 MaxMeshWorkGroupInvocationsCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description)
428 : vkt::TestCase (testCtx, name, description) {}
~MaxMeshWorkGroupInvocationsCase(void)429 virtual ~MaxMeshWorkGroupInvocationsCase (void) {}
430
431 void initPrograms (vk::SourceCollections& programCollection) const override;
432 TestInstance* createInstance (Context& context) const override;
433 void checkSupport (Context& context) const override;
434
435 static constexpr uint32_t minLimit = 32u;
436 };
437
checkSupport(Context & context) const438 void MaxMeshWorkGroupInvocationsCase::checkSupport (Context& context) const
439 {
440 genericCheckSupport(context, false/*taskShaderNeeded*/);
441
442 const auto& properties = context.getMeshShaderProperties();
443 if (properties.maxMeshWorkGroupInvocations < minLimit)
444 TCU_FAIL("maxMeshWorkGroupInvocations property below the minimum limit");
445 }
446
createInstance(Context & context) const447 TestInstance* MaxMeshWorkGroupInvocationsCase::createInstance (Context& context) const
448 {
449 const InstanceParams params =
450 {
451 minLimit, // uint32_t bufferElements;
452 1u, // uint32_t taskCount;
453 };
454 return new MeshShaderPropertyInstance(context, params);
455 }
456
initPrograms(vk::SourceCollections & programCollection) const457 void MaxMeshWorkGroupInvocationsCase::initPrograms (vk::SourceCollections& programCollection) const
458 {
459 ReplacementsMap meshReplacements;
460 const auto meshTemplate = getMeshShaderTemplate();
461
462 meshReplacements["MESH_LOCAL_SIZE_X"] = de::toString(uint32_t{minLimit});
463 meshReplacements["MESH_GLOBAL_DECL"] = getCommonStorageBufferDecl();
464 meshReplacements["MESH_BODY"] = " ov.values[gl_LocalInvocationID.x] = gl_LocalInvocationID.x;\n";
465
466 programCollection.glslSources.add("mesh") << glu::MeshSource(meshTemplate.specialize(meshReplacements));
467 }
468
469 // In the case of the NV extension, this is very similar to the test above. Added for completion.
470 class MaxMeshWorkGroupSizeCase : public MaxMeshWorkGroupInvocationsCase
471 {
472 public:
MaxMeshWorkGroupSizeCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)473 MaxMeshWorkGroupSizeCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description)
474 : MaxMeshWorkGroupInvocationsCase (testCtx, name, description) {}
475
476 void checkSupport (Context& context) const override;
477
478 static constexpr uint32_t minSizeX = 32u;
479 static constexpr uint32_t minSizeY = 1u;
480 static constexpr uint32_t minSizeZ = 1u;
481 };
482
checkSupport(Context & context) const483 void MaxMeshWorkGroupSizeCase::checkSupport (Context& context) const
484 {
485 genericCheckSupport(context, false/*taskShaderNeeded*/);
486
487 const auto& properties = context.getMeshShaderProperties();
488 if (properties.maxMeshWorkGroupSize[0] < minSizeX ||
489 properties.maxMeshWorkGroupSize[1] < minSizeY ||
490 properties.maxMeshWorkGroupSize[2] < minSizeZ)
491 {
492 TCU_FAIL("maxMeshWorkGroupSize property below the minimum limit");
493 }
494 }
495
getSharedArrayDecl(uint32_t numElements)496 std::string getSharedArrayDecl (uint32_t numElements)
497 {
498 std::ostringstream decl;
499 decl
500 << "const uint arrayElements = " << de::toString(numElements) << ";\n"
501 << "shared uint sharedArray[arrayElements];\n"
502 ;
503 return decl.str();
504 }
505
getSharedMemoryBody(uint32_t localSize)506 std::string getSharedMemoryBody (uint32_t localSize)
507 {
508 std::ostringstream body;
509 body
510 << "\n"
511 << " if (gl_LocalInvocationID.x == 0u)\n"
512 << " {\n"
513 << " for (uint i = 0; i < arrayElements; ++i)\n"
514 << " sharedArray[i] = 0u;\n"
515 << " }\n"
516 << "\n"
517 << " memoryBarrierShared();\n"
518 << " barrier();\n"
519 << "\n"
520 << " for (uint i = 0; i < arrayElements; ++i)\n"
521 << " atomicAdd(sharedArray[i], 1u);\n"
522 << "\n"
523 << " memoryBarrierShared();\n"
524 << " barrier();\n"
525 << "\n"
526 << " uint allGood = 1u;\n"
527 << " for (uint i = 0; i < arrayElements; ++i)\n"
528 << " {\n"
529 << " if (sharedArray[i] != " << localSize << ")\n"
530 << " {\n"
531 << " allGood = 0u;\n"
532 << " break;\n"
533 << " }\n"
534 << " }\n"
535 << "\n"
536 << " ov.values[gl_LocalInvocationID.x] = ((allGood == 1u) ? gl_LocalInvocationID.x : gl_WorkGroupSize.x);\n"
537 ;
538
539 return body.str();
540 }
541
542 class MaxTaskTotalMemorySizeCase : public vkt::TestCase
543 {
544 public:
MaxTaskTotalMemorySizeCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)545 MaxTaskTotalMemorySizeCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description)
546 : vkt::TestCase (testCtx, name, description) {}
~MaxTaskTotalMemorySizeCase(void)547 virtual ~MaxTaskTotalMemorySizeCase (void) {}
548
549 void initPrograms (vk::SourceCollections& programCollection) const override;
550 TestInstance* createInstance (Context& context) const override;
551 void checkSupport (Context& context) const override;
552
553 static constexpr uint32_t localSize = 32u;
554 static constexpr uint32_t minLimit = 16384u;
555 };
556
createInstance(Context & context) const557 TestInstance* MaxTaskTotalMemorySizeCase::createInstance (Context& context) const
558 {
559 const InstanceParams params =
560 {
561 localSize, // uint32_t bufferElements;
562 1u, // uint32_t taskCount;
563 };
564 return new MeshShaderPropertyInstance(context, params);
565 }
566
checkSupport(Context & context) const567 void MaxTaskTotalMemorySizeCase::checkSupport (Context& context) const
568 {
569 genericCheckSupport(context, true/*taskShaderNeeded*/);
570
571 const auto& properties = context.getMeshShaderProperties();
572 if (properties.maxTaskTotalMemorySize < minLimit)
573 TCU_FAIL("maxTaskTotalMemorySize property below the minimum limit");
574 }
575
initPrograms(vk::SourceCollections & programCollection) const576 void MaxTaskTotalMemorySizeCase::initPrograms (vk::SourceCollections& programCollection) const
577 {
578 const ReplacementsMap meshReplacements;
579 const auto meshTemplate = getMeshShaderTemplate();
580
581 programCollection.glslSources.add("mesh") << glu::MeshSource(meshTemplate.specialize(meshReplacements));
582
583 const auto taskTemplate = getTaskShaderTemplate();
584 const auto arrayElements = minLimit / static_cast<uint32_t>(sizeof(uint32_t));
585
586 const auto globalDecls = getCommonStorageBufferDecl() + getSharedArrayDecl(arrayElements);
587 const auto body = getSharedMemoryBody(localSize);
588
589 ReplacementsMap taskReplacements;
590 taskReplacements["TASK_LOCAL_SIZE_X"] = de::toString(uint32_t{localSize});
591 taskReplacements["TASK_GLOBAL_DECL"] = globalDecls;
592 taskReplacements["TASK_BODY"] = body;
593
594 programCollection.glslSources.add("task") << glu::TaskSource(taskTemplate.specialize(taskReplacements));
595 }
596
597 // Very similar to the previous one in NV.
598 class MaxMeshTotalMemorySizeCase : public vkt::TestCase
599 {
600 public:
MaxMeshTotalMemorySizeCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)601 MaxMeshTotalMemorySizeCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description)
602 : vkt::TestCase (testCtx, name, description) {}
~MaxMeshTotalMemorySizeCase(void)603 virtual ~MaxMeshTotalMemorySizeCase (void) {}
604
605 void initPrograms (vk::SourceCollections& programCollection) const override;
606 TestInstance* createInstance (Context& context) const override;
607 void checkSupport (Context& context) const override;
608
609 static constexpr uint32_t localSize = 32u;
610 static constexpr uint32_t minLimit = 16384u;
611 };
612
createInstance(Context & context) const613 TestInstance* MaxMeshTotalMemorySizeCase::createInstance (Context& context) const
614 {
615 const InstanceParams params =
616 {
617 localSize, // uint32_t bufferElements;
618 1u, // uint32_t taskCount;
619 };
620 return new MeshShaderPropertyInstance(context, params);
621 }
622
checkSupport(Context & context) const623 void MaxMeshTotalMemorySizeCase::checkSupport (Context& context) const
624 {
625 genericCheckSupport(context, false/*taskShaderNeeded*/);
626
627 const auto& properties = context.getMeshShaderProperties();
628 if (properties.maxMeshTotalMemorySize < minLimit)
629 TCU_FAIL("maxMeshTotalMemorySize property below the minimum limit");
630 }
631
initPrograms(vk::SourceCollections & programCollection) const632 void MaxMeshTotalMemorySizeCase::initPrograms (vk::SourceCollections& programCollection) const
633 {
634 const auto meshTemplate = getMeshShaderTemplate();
635 const auto arrayElements = minLimit / static_cast<uint32_t>(sizeof(uint32_t));
636
637 const auto globalDecls = getCommonStorageBufferDecl() + getSharedArrayDecl(arrayElements);
638 const auto body = getSharedMemoryBody(localSize);
639
640 ReplacementsMap meshReplacements;
641 meshReplacements["MESH_LOCAL_SIZE_X"] = de::toString(uint32_t{localSize});
642 meshReplacements["MESH_GLOBAL_DECL"] = globalDecls;
643 meshReplacements["MESH_BODY"] = body;
644
645 programCollection.glslSources.add("mesh") << glu::MeshSource(meshTemplate.specialize(meshReplacements));
646 }
647
648 }
649
createMeshShaderPropertyTests(tcu::TestContext & testCtx)650 tcu::TestCaseGroup* createMeshShaderPropertyTests (tcu::TestContext& testCtx)
651 {
652 GroupPtr mainGroup (new tcu::TestCaseGroup(testCtx, "property", "Mesh Shader Property Tests"));
653
654 mainGroup->addChild(new MaxDrawMeshTasksCountCase (testCtx, "max_draw_mesh_tasks_count_with_task", "", MaxDrawMeshTasksCountCase::TestType::TASK));
655 mainGroup->addChild(new MaxDrawMeshTasksCountCase (testCtx, "max_draw_mesh_tasks_count_with_mesh", "", MaxDrawMeshTasksCountCase::TestType::MESH));
656 mainGroup->addChild(new MaxTaskWorkGroupInvocationsCase (testCtx, "max_task_work_group_invocations", ""));
657 mainGroup->addChild(new MaxTaskWorkGroupSizeCase (testCtx, "max_task_work_group_size", ""));
658 mainGroup->addChild(new MaxTaskOutputCountCase (testCtx, "max_task_output_count", ""));
659 mainGroup->addChild(new MaxMeshWorkGroupInvocationsCase (testCtx, "max_mesh_work_group_invocations", ""));
660 mainGroup->addChild(new MaxMeshWorkGroupSizeCase (testCtx, "max_mesh_work_group_size", ""));
661 mainGroup->addChild(new MaxTaskTotalMemorySizeCase (testCtx, "max_task_total_memory_size", ""));
662 mainGroup->addChild(new MaxMeshTotalMemorySizeCase (testCtx, "max_mesh_total_memory_size", ""));
663
664 return mainGroup.release();
665 }
666
667 } // MeshShader
668 } // vkt
669