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("#version 460\n"
59 "#extension GL_NV_mesh_shader : enable\n"
60 "\n"
61 "layout (local_size_x=${TASK_LOCAL_SIZE_X:default=1}) in;\n"
62 "\n"
63 "${TASK_GLOBAL_DECL:opt}"
64 "\n"
65 "${TASK_MESH_INTERFACE_OUT:opt}"
66 "\n"
67 "void main ()\n"
68 "{\n"
69 " gl_TaskCountNV = ${TASK_TASK_COUNT:default=0};\n"
70 "${TASK_BODY:opt}"
71 "}\n");
72 }
73
getMeshShaderTemplate()74 tcu::StringTemplate getMeshShaderTemplate()
75 {
76 return tcu::StringTemplate("#version 460\n"
77 "#extension GL_NV_mesh_shader : enable\n"
78 "\n"
79 "layout (local_size_x=${MESH_LOCAL_SIZE_X:default=1}) in;\n"
80 "layout (triangles) out;\n"
81 "layout (max_vertices=3, max_primitives=1) out;\n"
82 "\n"
83 "${MESH_GLOBAL_DECL:opt}"
84 "\n"
85 "${TASK_MESH_INTERFACE_IN:opt}"
86 "\n"
87 "void main ()\n"
88 "{\n"
89 " gl_PrimitiveCountNV = 0u;\n"
90 "${MESH_BODY:opt}"
91 "}\n");
92 }
93
getCommonStorageBufferDecl()94 std::string getCommonStorageBufferDecl()
95 {
96 return "layout (set=0, binding=0) buffer OutputBlock { uint values[]; } ov;\n";
97 }
98
genericCheckSupport(Context & context,bool taskShaderNeeded)99 void genericCheckSupport(Context &context, bool taskShaderNeeded)
100 {
101 checkTaskMeshShaderSupportNV(context, taskShaderNeeded, true);
102
103 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
104 }
105
106 struct InstanceParams
107 {
108 uint32_t bufferElements;
109 uint32_t taskCount;
110 };
111
112 class MeshShaderPropertyInstance : public vkt::TestInstance
113 {
114 public:
MeshShaderPropertyInstance(Context & context,const InstanceParams & params)115 MeshShaderPropertyInstance(Context &context, const InstanceParams ¶ms)
116 : vkt::TestInstance(context)
117 , m_params(params)
118 {
119 }
~MeshShaderPropertyInstance(void)120 virtual ~MeshShaderPropertyInstance(void)
121 {
122 }
123
124 tcu::TestStatus iterate() override;
125
126 protected:
127 InstanceParams m_params;
128 };
129
iterate()130 tcu::TestStatus MeshShaderPropertyInstance::iterate()
131 {
132 const auto &vkd = m_context.getDeviceInterface();
133 const auto device = m_context.getDevice();
134 auto &alloc = m_context.getDefaultAllocator();
135 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
136 const auto queue = m_context.getUniversalQueue();
137 const auto &binaries = m_context.getBinaryCollection();
138 const auto extent = makeExtent3D(1u, 1u, 1u);
139 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
140 const auto useTask = binaries.contains("task");
141
142 const auto storageBufferSize =
143 static_cast<VkDeviceSize>(m_params.bufferElements) * static_cast<VkDeviceSize>(sizeof(uint32_t));
144 const auto storageBufferUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
145 const auto storageBufferType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
146 const auto storageBufferStages = (VK_SHADER_STAGE_MESH_BIT_NV | (useTask ? VK_SHADER_STAGE_TASK_BIT_NV : 0));
147
148 // Create storage buffer with the required space.
149 const auto storageBufferInfo = makeBufferCreateInfo(storageBufferSize, storageBufferUsage);
150 BufferWithMemory storageBuffer(vkd, device, alloc, storageBufferInfo, MemoryRequirement::HostVisible);
151 auto &storageBufferAlloc = storageBuffer.getAllocation();
152 void *storageBufferDataPtr = storageBufferAlloc.getHostPtr();
153 const auto storageBufferDescInfo = makeDescriptorBufferInfo(storageBuffer.get(), 0ull, storageBufferSize);
154
155 deMemset(storageBufferDataPtr, 0xFF, static_cast<size_t>(storageBufferSize));
156 flushAlloc(vkd, device, storageBufferAlloc);
157
158 // Descriptor pool.
159 DescriptorPoolBuilder poolBuilder;
160 poolBuilder.addType(storageBufferType);
161 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
162
163 // Descriptor set layout and pipeline layout.
164 DescriptorSetLayoutBuilder layoutBuilder;
165 layoutBuilder.addSingleBinding(storageBufferType, storageBufferStages);
166 const auto setLayout = layoutBuilder.build(vkd, device);
167 const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
168
169 // Allocate and prepare descriptor set.
170 const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
171
172 DescriptorSetUpdateBuilder setUpdateBuilder;
173 setUpdateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u),
174 storageBufferType, &storageBufferDescInfo);
175 setUpdateBuilder.update(vkd, device);
176
177 // Create empty render pass and framebuffer.
178 const auto renderPass = makeRenderPass(vkd, device);
179 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), 0u, nullptr, extent.width, extent.height);
180
181 // Shader modules and pipeline.
182 Move<VkShaderModule> taskModule;
183 Move<VkShaderModule> meshModule;
184 const Move<VkShaderModule> fragModule; // No fragment shader.
185
186 if (useTask)
187 taskModule = createShaderModule(vkd, device, binaries.get("task"));
188 meshModule = createShaderModule(vkd, device, binaries.get("mesh"));
189
190 const std::vector<VkViewport> viewports(1u, makeViewport(extent));
191 const std::vector<VkRect2D> scissors(1u, makeRect2D(extent));
192
193 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(), taskModule.get(), meshModule.get(),
194 fragModule.get(), renderPass.get(), viewports, scissors);
195
196 // Command pool and buffer.
197 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
198 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
199 const auto cmdBuffer = cmdBufferPtr.get();
200
201 // Run the pipeline.
202 beginCommandBuffer(vkd, cmdBuffer);
203
204 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0));
205 vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
206 vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get());
207 vkd.cmdDrawMeshTasksNV(cmdBuffer, m_params.taskCount, 0u);
208 endRenderPass(vkd, cmdBuffer);
209
210 const auto shaderToHostBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
211 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u,
212 &shaderToHostBarrier, 0u, nullptr, 0u, nullptr);
213
214 endCommandBuffer(vkd, cmdBuffer);
215 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
216
217 // Verify the storage buffer has the expected results.
218 invalidateAlloc(vkd, device, storageBufferAlloc);
219
220 std::vector<uint32_t> bufferData(m_params.bufferElements);
221 deMemcpy(bufferData.data(), storageBufferDataPtr, de::dataSize(bufferData));
222
223 for (size_t idx = 0u; idx < bufferData.size(); ++idx)
224 {
225 const auto expected = static_cast<uint32_t>(idx);
226 const auto &bufferValue = bufferData[idx];
227
228 if (bufferValue != expected)
229 TCU_FAIL("Unexpected value found in buffer position " + de::toString(idx) + ": " +
230 de::toString(bufferValue));
231 }
232
233 return tcu::TestStatus::pass("Pass");
234 }
235
236 class MaxDrawMeshTasksCountCase : public vkt::TestCase
237 {
238 public:
239 enum class TestType
240 {
241 TASK = 0,
242 MESH
243 };
244
MaxDrawMeshTasksCountCase(tcu::TestContext & testCtx,const std::string & name,TestType testType)245 MaxDrawMeshTasksCountCase(tcu::TestContext &testCtx, const std::string &name, TestType testType)
246 : vkt::TestCase(testCtx, name)
247 , m_testType(testType)
248 {
249 }
~MaxDrawMeshTasksCountCase(void)250 virtual ~MaxDrawMeshTasksCountCase(void)
251 {
252 }
253
254 void initPrograms(vk::SourceCollections &programCollection) const override;
255 TestInstance *createInstance(Context &context) const override;
256 void checkSupport(Context &context) const override;
257
258 static constexpr uint32_t minLimit = 65535u;
259
260 protected:
261 TestType m_testType;
262 };
263
checkSupport(Context & context) const264 void MaxDrawMeshTasksCountCase::checkSupport(Context &context) const
265 {
266 genericCheckSupport(context, (m_testType == TestType::TASK));
267
268 const auto &properties = context.getMeshShaderProperties();
269 if (properties.maxDrawMeshTasksCount < minLimit)
270 TCU_FAIL("maxDrawMeshTasksCount property below the minimum limit");
271 }
272
createInstance(Context & context) const273 TestInstance *MaxDrawMeshTasksCountCase::createInstance(Context &context) const
274 {
275 const InstanceParams params = {
276 minLimit, // uint32_t bufferElements;
277 minLimit, // uint32_t taskCount;
278 };
279 return new MeshShaderPropertyInstance(context, params);
280 }
281
initPrograms(vk::SourceCollections & programCollection) const282 void MaxDrawMeshTasksCountCase::initPrograms(vk::SourceCollections &programCollection) const
283 {
284 ReplacementsMap meshReplacements;
285 ReplacementsMap taskReplacements;
286
287 const auto meshTemplate = getMeshShaderTemplate();
288
289 const std::string desc = getCommonStorageBufferDecl();
290 const std::string body = " ov.values[gl_WorkGroupID.x] = gl_WorkGroupID.x;\n";
291
292 if (m_testType == TestType::TASK)
293 {
294 const auto taskTemplate = getTaskShaderTemplate();
295 taskReplacements["TASK_GLOBAL_DECL"] = desc;
296 taskReplacements["TASK_BODY"] = body;
297
298 programCollection.glslSources.add("task") << glu::TaskSource(taskTemplate.specialize(taskReplacements));
299 }
300 else
301 {
302 meshReplacements["MESH_GLOBAL_DECL"] = desc;
303 meshReplacements["MESH_BODY"] = body;
304 }
305
306 programCollection.glslSources.add("mesh") << glu::MeshSource(meshTemplate.specialize(meshReplacements));
307 }
308
309 class MaxTaskWorkGroupInvocationsCase : public vkt::TestCase
310 {
311 public:
MaxTaskWorkGroupInvocationsCase(tcu::TestContext & testCtx,const std::string & name)312 MaxTaskWorkGroupInvocationsCase(tcu::TestContext &testCtx, const std::string &name) : vkt::TestCase(testCtx, name)
313 {
314 }
~MaxTaskWorkGroupInvocationsCase(void)315 virtual ~MaxTaskWorkGroupInvocationsCase(void)
316 {
317 }
318
319 void initPrograms(vk::SourceCollections &programCollection) const override;
320 TestInstance *createInstance(Context &context) const override;
321 void checkSupport(Context &context) const override;
322
323 static constexpr uint32_t minLimit = 32u;
324 };
325
checkSupport(Context & context) const326 void MaxTaskWorkGroupInvocationsCase::checkSupport(Context &context) const
327 {
328 genericCheckSupport(context, true /*taskShaderNeeded*/);
329
330 const auto &properties = context.getMeshShaderProperties();
331 if (properties.maxTaskWorkGroupInvocations < minLimit)
332 TCU_FAIL("maxTaskWorkGroupInvocations property below the minimum limit");
333 }
334
createInstance(Context & context) const335 TestInstance *MaxTaskWorkGroupInvocationsCase::createInstance(Context &context) const
336 {
337 const InstanceParams params = {
338 minLimit, // uint32_t bufferElements;
339 1u, // uint32_t taskCount;
340 };
341 return new MeshShaderPropertyInstance(context, params);
342 }
343
initPrograms(vk::SourceCollections & programCollection) const344 void MaxTaskWorkGroupInvocationsCase::initPrograms(vk::SourceCollections &programCollection) const
345 {
346 const ReplacementsMap meshReplacements;
347 const auto meshTemplate = getMeshShaderTemplate();
348
349 programCollection.glslSources.add("mesh") << glu::MeshSource(meshTemplate.specialize(meshReplacements));
350
351 ReplacementsMap taskReplacements;
352 const auto taskTemplate = getTaskShaderTemplate();
353
354 taskReplacements["TASK_GLOBAL_DECL"] = getCommonStorageBufferDecl();
355 taskReplacements["TASK_BODY"] = " ov.values[gl_LocalInvocationID.x] = gl_LocalInvocationID.x;\n";
356 taskReplacements["TASK_LOCAL_SIZE_X"] = de::toString(uint32_t{minLimit});
357
358 programCollection.glslSources.add("task") << glu::TaskSource(taskTemplate.specialize(taskReplacements));
359 }
360
361 // In the case of the NV extension, this is very similar to the test above. Added for completion.
362 class MaxTaskWorkGroupSizeCase : public MaxTaskWorkGroupInvocationsCase
363 {
364 public:
MaxTaskWorkGroupSizeCase(tcu::TestContext & testCtx,const std::string & name)365 MaxTaskWorkGroupSizeCase(tcu::TestContext &testCtx, const std::string &name)
366 : MaxTaskWorkGroupInvocationsCase(testCtx, name)
367 {
368 }
369
370 void checkSupport(Context &context) const override;
371
372 static constexpr uint32_t minSizeX = 32u;
373 static constexpr uint32_t minSizeY = 1u;
374 static constexpr uint32_t minSizeZ = 1u;
375 };
376
checkSupport(Context & context) const377 void MaxTaskWorkGroupSizeCase::checkSupport(Context &context) const
378 {
379 genericCheckSupport(context, true /*taskShaderNeeded*/);
380
381 const auto &properties = context.getMeshShaderProperties();
382 if (properties.maxTaskWorkGroupSize[0] < minSizeX || properties.maxTaskWorkGroupSize[1] < minSizeY ||
383 properties.maxTaskWorkGroupSize[2] < minSizeZ)
384 {
385 TCU_FAIL("maxTaskWorkGroupSize property below the minimum limit");
386 }
387 }
388
389 class MaxTaskOutputCountCase : public vkt::TestCase
390 {
391 public:
MaxTaskOutputCountCase(tcu::TestContext & testCtx,const std::string & name)392 MaxTaskOutputCountCase(tcu::TestContext &testCtx, const std::string &name) : vkt::TestCase(testCtx, name)
393 {
394 }
~MaxTaskOutputCountCase(void)395 virtual ~MaxTaskOutputCountCase(void)
396 {
397 }
398
399 void initPrograms(vk::SourceCollections &programCollection) const override;
400 TestInstance *createInstance(Context &context) const override;
401 void checkSupport(Context &context) const override;
402
403 static constexpr uint32_t minLimit = 65535u;
404 };
405
checkSupport(Context & context) const406 void MaxTaskOutputCountCase::checkSupport(Context &context) const
407 {
408 genericCheckSupport(context, true /*taskShaderNeeded*/);
409
410 const auto &properties = context.getMeshShaderProperties();
411 if (properties.maxTaskOutputCount < minLimit)
412 TCU_FAIL("maxTaskOutputCount property below the minimum limit");
413 }
414
createInstance(Context & context) const415 TestInstance *MaxTaskOutputCountCase::createInstance(Context &context) const
416 {
417 const InstanceParams params = {
418 minLimit, // uint32_t bufferElements;
419 1u, // uint32_t taskCount;
420 };
421 return new MeshShaderPropertyInstance(context, params);
422 }
423
initPrograms(vk::SourceCollections & programCollection) const424 void MaxTaskOutputCountCase::initPrograms(vk::SourceCollections &programCollection) const
425 {
426 ReplacementsMap meshReplacements;
427 ReplacementsMap taskReplacements;
428 const auto meshTemplate = getMeshShaderTemplate();
429 const auto taskTemplate = getTaskShaderTemplate();
430
431 taskReplacements["TASK_TASK_COUNT"] = de::toString(uint32_t{minLimit});
432 meshReplacements["MESH_GLOBAL_DECL"] = getCommonStorageBufferDecl();
433 meshReplacements["MESH_BODY"] = " ov.values[gl_WorkGroupID.x] = gl_WorkGroupID.x;\n";
434
435 programCollection.glslSources.add("task") << glu::TaskSource(taskTemplate.specialize(taskReplacements));
436 programCollection.glslSources.add("mesh") << glu::MeshSource(meshTemplate.specialize(meshReplacements));
437 }
438
439 class MaxMeshWorkGroupInvocationsCase : public vkt::TestCase
440 {
441 public:
MaxMeshWorkGroupInvocationsCase(tcu::TestContext & testCtx,const std::string & name)442 MaxMeshWorkGroupInvocationsCase(tcu::TestContext &testCtx, const std::string &name) : vkt::TestCase(testCtx, name)
443 {
444 }
~MaxMeshWorkGroupInvocationsCase(void)445 virtual ~MaxMeshWorkGroupInvocationsCase(void)
446 {
447 }
448
449 void initPrograms(vk::SourceCollections &programCollection) const override;
450 TestInstance *createInstance(Context &context) const override;
451 void checkSupport(Context &context) const override;
452
453 static constexpr uint32_t minLimit = 32u;
454 };
455
checkSupport(Context & context) const456 void MaxMeshWorkGroupInvocationsCase::checkSupport(Context &context) const
457 {
458 genericCheckSupport(context, false /*taskShaderNeeded*/);
459
460 const auto &properties = context.getMeshShaderProperties();
461 if (properties.maxMeshWorkGroupInvocations < minLimit)
462 TCU_FAIL("maxMeshWorkGroupInvocations property below the minimum limit");
463 }
464
createInstance(Context & context) const465 TestInstance *MaxMeshWorkGroupInvocationsCase::createInstance(Context &context) const
466 {
467 const InstanceParams params = {
468 minLimit, // uint32_t bufferElements;
469 1u, // uint32_t taskCount;
470 };
471 return new MeshShaderPropertyInstance(context, params);
472 }
473
initPrograms(vk::SourceCollections & programCollection) const474 void MaxMeshWorkGroupInvocationsCase::initPrograms(vk::SourceCollections &programCollection) const
475 {
476 ReplacementsMap meshReplacements;
477 const auto meshTemplate = getMeshShaderTemplate();
478
479 meshReplacements["MESH_LOCAL_SIZE_X"] = de::toString(uint32_t{minLimit});
480 meshReplacements["MESH_GLOBAL_DECL"] = getCommonStorageBufferDecl();
481 meshReplacements["MESH_BODY"] = " ov.values[gl_LocalInvocationID.x] = gl_LocalInvocationID.x;\n";
482
483 programCollection.glslSources.add("mesh") << glu::MeshSource(meshTemplate.specialize(meshReplacements));
484 }
485
486 // In the case of the NV extension, this is very similar to the test above. Added for completion.
487 class MaxMeshWorkGroupSizeCase : public MaxMeshWorkGroupInvocationsCase
488 {
489 public:
MaxMeshWorkGroupSizeCase(tcu::TestContext & testCtx,const std::string & name)490 MaxMeshWorkGroupSizeCase(tcu::TestContext &testCtx, const std::string &name)
491 : MaxMeshWorkGroupInvocationsCase(testCtx, name)
492 {
493 }
494
495 void checkSupport(Context &context) const override;
496
497 static constexpr uint32_t minSizeX = 32u;
498 static constexpr uint32_t minSizeY = 1u;
499 static constexpr uint32_t minSizeZ = 1u;
500 };
501
checkSupport(Context & context) const502 void MaxMeshWorkGroupSizeCase::checkSupport(Context &context) const
503 {
504 genericCheckSupport(context, false /*taskShaderNeeded*/);
505
506 const auto &properties = context.getMeshShaderProperties();
507 if (properties.maxMeshWorkGroupSize[0] < minSizeX || properties.maxMeshWorkGroupSize[1] < minSizeY ||
508 properties.maxMeshWorkGroupSize[2] < minSizeZ)
509 {
510 TCU_FAIL("maxMeshWorkGroupSize property below the minimum limit");
511 }
512 }
513
getSharedArrayDecl(uint32_t numElements)514 std::string getSharedArrayDecl(uint32_t numElements)
515 {
516 std::ostringstream decl;
517 decl << "const uint arrayElements = " << de::toString(numElements) << ";\n"
518 << "shared uint sharedArray[arrayElements];\n";
519 return decl.str();
520 }
521
getSharedMemoryBody(uint32_t localSize)522 std::string getSharedMemoryBody(uint32_t localSize)
523 {
524 std::ostringstream body;
525 body
526 << "\n"
527 << " if (gl_LocalInvocationID.x == 0u)\n"
528 << " {\n"
529 << " for (uint i = 0; i < arrayElements; ++i)\n"
530 << " sharedArray[i] = 0u;\n"
531 << " }\n"
532 << "\n"
533 << " memoryBarrierShared();\n"
534 << " barrier();\n"
535 << "\n"
536 << " for (uint i = 0; i < arrayElements; ++i)\n"
537 << " atomicAdd(sharedArray[i], 1u);\n"
538 << "\n"
539 << " memoryBarrierShared();\n"
540 << " barrier();\n"
541 << "\n"
542 << " uint allGood = 1u;\n"
543 << " for (uint i = 0; i < arrayElements; ++i)\n"
544 << " {\n"
545 << " if (sharedArray[i] != " << localSize << ")\n"
546 << " {\n"
547 << " allGood = 0u;\n"
548 << " break;\n"
549 << " }\n"
550 << " }\n"
551 << "\n"
552 << " ov.values[gl_LocalInvocationID.x] = ((allGood == 1u) ? gl_LocalInvocationID.x : gl_WorkGroupSize.x);\n";
553
554 return body.str();
555 }
556
557 class MaxTaskTotalMemorySizeCase : public vkt::TestCase
558 {
559 public:
MaxTaskTotalMemorySizeCase(tcu::TestContext & testCtx,const std::string & name)560 MaxTaskTotalMemorySizeCase(tcu::TestContext &testCtx, const std::string &name) : vkt::TestCase(testCtx, name)
561 {
562 }
~MaxTaskTotalMemorySizeCase(void)563 virtual ~MaxTaskTotalMemorySizeCase(void)
564 {
565 }
566
567 void initPrograms(vk::SourceCollections &programCollection) const override;
568 TestInstance *createInstance(Context &context) const override;
569 void checkSupport(Context &context) const override;
570
571 static constexpr uint32_t localSize = 32u;
572 static constexpr uint32_t minLimit = 16384u;
573 };
574
createInstance(Context & context) const575 TestInstance *MaxTaskTotalMemorySizeCase::createInstance(Context &context) const
576 {
577 const InstanceParams params = {
578 localSize, // uint32_t bufferElements;
579 1u, // uint32_t taskCount;
580 };
581 return new MeshShaderPropertyInstance(context, params);
582 }
583
checkSupport(Context & context) const584 void MaxTaskTotalMemorySizeCase::checkSupport(Context &context) const
585 {
586 genericCheckSupport(context, true /*taskShaderNeeded*/);
587
588 const auto &properties = context.getMeshShaderProperties();
589 if (properties.maxTaskTotalMemorySize < minLimit)
590 TCU_FAIL("maxTaskTotalMemorySize property below the minimum limit");
591 }
592
initPrograms(vk::SourceCollections & programCollection) const593 void MaxTaskTotalMemorySizeCase::initPrograms(vk::SourceCollections &programCollection) const
594 {
595 const ReplacementsMap meshReplacements;
596 const auto meshTemplate = getMeshShaderTemplate();
597
598 programCollection.glslSources.add("mesh") << glu::MeshSource(meshTemplate.specialize(meshReplacements));
599
600 const auto taskTemplate = getTaskShaderTemplate();
601 const auto arrayElements = minLimit / static_cast<uint32_t>(sizeof(uint32_t));
602
603 const auto globalDecls = getCommonStorageBufferDecl() + getSharedArrayDecl(arrayElements);
604 const auto body = getSharedMemoryBody(localSize);
605
606 ReplacementsMap taskReplacements;
607 taskReplacements["TASK_LOCAL_SIZE_X"] = de::toString(uint32_t{localSize});
608 taskReplacements["TASK_GLOBAL_DECL"] = globalDecls;
609 taskReplacements["TASK_BODY"] = body;
610
611 programCollection.glslSources.add("task") << glu::TaskSource(taskTemplate.specialize(taskReplacements));
612 }
613
614 // Very similar to the previous one in NV.
615 class MaxMeshTotalMemorySizeCase : public vkt::TestCase
616 {
617 public:
MaxMeshTotalMemorySizeCase(tcu::TestContext & testCtx,const std::string & name)618 MaxMeshTotalMemorySizeCase(tcu::TestContext &testCtx, const std::string &name) : vkt::TestCase(testCtx, name)
619 {
620 }
~MaxMeshTotalMemorySizeCase(void)621 virtual ~MaxMeshTotalMemorySizeCase(void)
622 {
623 }
624
625 void initPrograms(vk::SourceCollections &programCollection) const override;
626 TestInstance *createInstance(Context &context) const override;
627 void checkSupport(Context &context) const override;
628
629 static constexpr uint32_t localSize = 32u;
630 static constexpr uint32_t minLimit = 16384u;
631 };
632
createInstance(Context & context) const633 TestInstance *MaxMeshTotalMemorySizeCase::createInstance(Context &context) const
634 {
635 const InstanceParams params = {
636 localSize, // uint32_t bufferElements;
637 1u, // uint32_t taskCount;
638 };
639 return new MeshShaderPropertyInstance(context, params);
640 }
641
checkSupport(Context & context) const642 void MaxMeshTotalMemorySizeCase::checkSupport(Context &context) const
643 {
644 genericCheckSupport(context, false /*taskShaderNeeded*/);
645
646 const auto &properties = context.getMeshShaderProperties();
647 if (properties.maxMeshTotalMemorySize < minLimit)
648 TCU_FAIL("maxMeshTotalMemorySize property below the minimum limit");
649 }
650
initPrograms(vk::SourceCollections & programCollection) const651 void MaxMeshTotalMemorySizeCase::initPrograms(vk::SourceCollections &programCollection) const
652 {
653 const auto meshTemplate = getMeshShaderTemplate();
654 const auto arrayElements = minLimit / static_cast<uint32_t>(sizeof(uint32_t));
655
656 const auto globalDecls = getCommonStorageBufferDecl() + getSharedArrayDecl(arrayElements);
657 const auto body = getSharedMemoryBody(localSize);
658
659 ReplacementsMap meshReplacements;
660 meshReplacements["MESH_LOCAL_SIZE_X"] = de::toString(uint32_t{localSize});
661 meshReplacements["MESH_GLOBAL_DECL"] = globalDecls;
662 meshReplacements["MESH_BODY"] = body;
663
664 programCollection.glslSources.add("mesh") << glu::MeshSource(meshTemplate.specialize(meshReplacements));
665 }
666
667 } // namespace
668
createMeshShaderPropertyTests(tcu::TestContext & testCtx)669 tcu::TestCaseGroup *createMeshShaderPropertyTests(tcu::TestContext &testCtx)
670 {
671 GroupPtr mainGroup(new tcu::TestCaseGroup(testCtx, "property"));
672
673 mainGroup->addChild(new MaxDrawMeshTasksCountCase(testCtx, "max_draw_mesh_tasks_count_with_task",
674 MaxDrawMeshTasksCountCase::TestType::TASK));
675 mainGroup->addChild(new MaxDrawMeshTasksCountCase(testCtx, "max_draw_mesh_tasks_count_with_mesh",
676 MaxDrawMeshTasksCountCase::TestType::MESH));
677 mainGroup->addChild(new MaxTaskWorkGroupInvocationsCase(testCtx, "max_task_work_group_invocations"));
678 mainGroup->addChild(new MaxTaskWorkGroupSizeCase(testCtx, "max_task_work_group_size"));
679 mainGroup->addChild(new MaxTaskOutputCountCase(testCtx, "max_task_output_count"));
680 mainGroup->addChild(new MaxMeshWorkGroupInvocationsCase(testCtx, "max_mesh_work_group_invocations"));
681 mainGroup->addChild(new MaxMeshWorkGroupSizeCase(testCtx, "max_mesh_work_group_size"));
682 mainGroup->addChild(new MaxTaskTotalMemorySizeCase(testCtx, "max_task_total_memory_size"));
683 mainGroup->addChild(new MaxMeshTotalMemorySizeCase(testCtx, "max_mesh_total_memory_size"));
684
685 return mainGroup.release();
686 }
687
688 } // namespace MeshShader
689 } // namespace vkt
690