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 Misc Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktMeshShaderMiscTests.hpp"
26 #include "vktTestCase.hpp"
27
28 #include "vkBuilderUtil.hpp"
29 #include "vkImageWithMemory.hpp"
30 #include "vkBufferWithMemory.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkImageUtil.hpp"
35 #include "vkBarrierUtil.hpp"
36
37 #include "tcuImageCompare.hpp"
38 #include "tcuTexture.hpp"
39 #include "tcuTextureUtil.hpp"
40 #include "tcuMaybe.hpp"
41 #include "tcuStringTemplate.hpp"
42 #include "tcuTestLog.hpp"
43
44 #include <memory>
45 #include <utility>
46 #include <vector>
47 #include <string>
48 #include <sstream>
49 #include <map>
50
51 namespace vkt
52 {
53 namespace MeshShader
54 {
55
56 namespace
57 {
58
59 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
60
61 using namespace vk;
62
63 // Output images will use this format.
getOutputFormat()64 VkFormat getOutputFormat ()
65 {
66 return VK_FORMAT_R8G8B8A8_UNORM;
67 }
68
69 // Threshold that's reasonable for the previous format.
getCompareThreshold()70 float getCompareThreshold ()
71 {
72 return 0.005f; // 1/256 < 0.005 < 2/256
73 }
74
75 // Check mesh shader support.
genericCheckSupport(Context & context,bool requireTaskShader,bool requireVertexStores)76 void genericCheckSupport (Context& context, bool requireTaskShader, bool requireVertexStores)
77 {
78 context.requireDeviceFunctionality("VK_NV_mesh_shader");
79
80 const auto& meshFeatures = context.getMeshShaderFeatures();
81
82 if (!meshFeatures.meshShader)
83 TCU_THROW(NotSupportedError, "Mesh shader not supported");
84
85 if (requireTaskShader && !meshFeatures.taskShader)
86 TCU_THROW(NotSupportedError, "Task shader not supported");
87
88 if (requireVertexStores)
89 {
90 const auto& features = context.getDeviceFeatures();
91 if (!features.vertexPipelineStoresAndAtomics)
92 TCU_THROW(NotSupportedError, "Vertex pieline stores and atomics not supported");
93 }
94 }
95
96 struct MiscTestParams
97 {
98 tcu::Maybe<uint32_t> taskCount;
99 uint32_t meshCount;
100
101 uint32_t width;
102 uint32_t height;
103
104 // Makes the class polymorphic and allows the right destructor to be used for subclasses.
~MiscTestParamsvkt::MeshShader::__anona67b1ba90111::MiscTestParams105 virtual ~MiscTestParams () {}
106
needsTaskShadervkt::MeshShader::__anona67b1ba90111::MiscTestParams107 bool needsTaskShader () const
108 {
109 return static_cast<bool>(taskCount);
110 }
111
drawCountvkt::MeshShader::__anona67b1ba90111::MiscTestParams112 uint32_t drawCount () const
113 {
114 if (needsTaskShader())
115 return taskCount.get();
116 return meshCount;
117 }
118 };
119
120 using ParamsPtr = std::unique_ptr<MiscTestParams>;
121
122 class MeshShaderMiscCase : public vkt::TestCase
123 {
124 public:
125 MeshShaderMiscCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params);
~MeshShaderMiscCase(void)126 virtual ~MeshShaderMiscCase (void) {}
127
128 void checkSupport (Context& context) const override;
129 void initPrograms (vk::SourceCollections& programCollection) const override;
130
131 protected:
132 std::unique_ptr<MiscTestParams> m_params;
133 };
134
MeshShaderMiscCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)135 MeshShaderMiscCase::MeshShaderMiscCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
136 : vkt::TestCase (testCtx, name, description)
137 , m_params (params.release())
138 {}
139
checkSupport(Context & context) const140 void MeshShaderMiscCase::checkSupport (Context& context) const
141 {
142 genericCheckSupport(context, m_params->needsTaskShader(), /*requireVertexStores*/false);
143 }
144
145 // Adds the generic fragment shader. To be called by subclasses.
initPrograms(vk::SourceCollections & programCollection) const146 void MeshShaderMiscCase::initPrograms (vk::SourceCollections& programCollection) const
147 {
148 std::string frag =
149 "#version 450\n"
150 "#extension GL_NV_mesh_shader : enable\n"
151 "\n"
152 "layout (location=0) in perprimitiveNV vec4 primitiveColor;\n"
153 "layout (location=0) out vec4 outColor;\n"
154 "\n"
155 "void main ()\n"
156 "{\n"
157 " outColor = primitiveColor;\n"
158 "}\n"
159 ;
160 programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
161 }
162
163 class MeshShaderMiscInstance : public vkt::TestInstance
164 {
165 public:
MeshShaderMiscInstance(Context & context,const MiscTestParams * params)166 MeshShaderMiscInstance (Context& context, const MiscTestParams* params)
167 : vkt::TestInstance (context)
168 , m_params (params)
169 , m_referenceLevel ()
170 {
171 }
172
173 void generateSolidRefLevel (const tcu::Vec4& color, std::unique_ptr<tcu::TextureLevel>& output);
174 virtual void generateReferenceLevel () = 0;
175
176 virtual bool verifyResult (const tcu::ConstPixelBufferAccess& resultAccess, const tcu::TextureLevel& referenceLevel) const;
177 virtual bool verifyResult (const tcu::ConstPixelBufferAccess& resultAccess) const;
178 tcu::TestStatus iterate () override;
179
180 protected:
181 const MiscTestParams* m_params;
182 std::unique_ptr<tcu::TextureLevel> m_referenceLevel;
183 };
184
generateSolidRefLevel(const tcu::Vec4 & color,std::unique_ptr<tcu::TextureLevel> & output)185 void MeshShaderMiscInstance::generateSolidRefLevel (const tcu::Vec4& color, std::unique_ptr<tcu::TextureLevel>& output)
186 {
187 const auto format = getOutputFormat();
188 const auto tcuFormat = mapVkFormat(format);
189
190 const auto iWidth = static_cast<int>(m_params->width);
191 const auto iHeight = static_cast<int>(m_params->height);
192
193 output.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
194
195 const auto access = output->getAccess();
196
197 // Fill with solid color.
198 tcu::clear(access, color);
199 }
200
verifyResult(const tcu::ConstPixelBufferAccess & resultAccess) const201 bool MeshShaderMiscInstance::verifyResult (const tcu::ConstPixelBufferAccess& resultAccess) const
202 {
203 return verifyResult(resultAccess, *m_referenceLevel);
204 }
205
verifyResult(const tcu::ConstPixelBufferAccess & resultAccess,const tcu::TextureLevel & referenceLevel) const206 bool MeshShaderMiscInstance::verifyResult (const tcu::ConstPixelBufferAccess& resultAccess, const tcu::TextureLevel& referenceLevel) const
207 {
208 const auto referenceAccess = referenceLevel.getAccess();
209
210 const auto refWidth = referenceAccess.getWidth();
211 const auto refHeight = referenceAccess.getHeight();
212 const auto refDepth = referenceAccess.getDepth();
213
214 const auto resWidth = resultAccess.getWidth();
215 const auto resHeight = resultAccess.getHeight();
216 const auto resDepth = resultAccess.getDepth();
217
218 DE_ASSERT(resWidth == refWidth || resHeight == refHeight || resDepth == refDepth);
219
220 // For release builds.
221 DE_UNREF(refWidth);
222 DE_UNREF(refHeight);
223 DE_UNREF(refDepth);
224 DE_UNREF(resWidth);
225 DE_UNREF(resHeight);
226 DE_UNREF(resDepth);
227
228 const auto outputFormat = getOutputFormat();
229 const auto expectedFormat = mapVkFormat(outputFormat);
230 const auto resFormat = resultAccess.getFormat();
231 const auto refFormat = referenceAccess.getFormat();
232
233 DE_ASSERT(resFormat == expectedFormat && refFormat == expectedFormat);
234
235 // For release builds
236 DE_UNREF(expectedFormat);
237 DE_UNREF(resFormat);
238 DE_UNREF(refFormat);
239
240 auto& log = m_context.getTestContext().getLog();
241 const auto threshold = getCompareThreshold();
242 const tcu::Vec4 thresholdVec (threshold, threshold, threshold, threshold);
243
244 return tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, thresholdVec, tcu::COMPARE_LOG_ON_ERROR);
245 }
246
iterate()247 tcu::TestStatus MeshShaderMiscInstance::iterate ()
248 {
249 const auto& vkd = m_context.getDeviceInterface();
250 const auto device = m_context.getDevice();
251 auto& alloc = m_context.getDefaultAllocator();
252 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
253 const auto queue = m_context.getUniversalQueue();
254
255 const auto imageFormat = getOutputFormat();
256 const auto tcuFormat = mapVkFormat(imageFormat);
257 const auto imageExtent = makeExtent3D(m_params->width, m_params->height, 1u);
258 const auto imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
259
260 const VkImageCreateInfo colorBufferInfo =
261 {
262 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
263 nullptr, // const void* pNext;
264 0u, // VkImageCreateFlags flags;
265 VK_IMAGE_TYPE_2D, // VkImageType imageType;
266 imageFormat, // VkFormat format;
267 imageExtent, // VkExtent3D extent;
268 1u, // uint32_t mipLevels;
269 1u, // uint32_t arrayLayers;
270 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
271 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
272 imageUsage, // VkImageUsageFlags usage;
273 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
274 0u, // uint32_t queueFamilyIndexCount;
275 nullptr, // const uint32_t* pQueueFamilyIndices;
276 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
277 };
278
279 // Create color image and view.
280 ImageWithMemory colorImage (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
281 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
282 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
283 const auto colorView = makeImageView(vkd, device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
284
285 // Create a memory buffer for verification.
286 const auto verificationBufferSize = static_cast<VkDeviceSize>(imageExtent.width * imageExtent.height * tcu::getPixelSize(tcuFormat));
287 const auto verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
288 const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
289
290 BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
291 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
292 void* verificationBufferData = verificationBufferAlloc.getHostPtr();
293
294 // Pipeline layout.
295 const auto pipelineLayout = makePipelineLayout(vkd, device);
296
297 // Shader modules.
298 const auto& binaries = m_context.getBinaryCollection();
299 const auto hasTask = binaries.contains("task");
300
301 const auto meshShader = createShaderModule(vkd, device, binaries.get("mesh"));
302 const auto fragShader = createShaderModule(vkd, device, binaries.get("frag"));
303
304 Move<VkShaderModule> taskShader;
305 if (hasTask)
306 taskShader = createShaderModule(vkd, device, binaries.get("task"));
307
308 // Render pass.
309 const auto renderPass = makeRenderPass(vkd, device, imageFormat);
310
311 // Framebuffer.
312 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), imageExtent.width, imageExtent.height);
313
314 // Viewport and scissor.
315 const std::vector<VkViewport> viewports (1u, makeViewport(imageExtent));
316 const std::vector<VkRect2D> scissors (1u, makeRect2D(imageExtent));
317
318 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
319 taskShader.get(), meshShader.get(), fragShader.get(),
320 renderPass.get(), viewports, scissors);
321
322 // Command pool and buffer.
323 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
324 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
325 const auto cmdBuffer = cmdBufferPtr.get();
326
327 beginCommandBuffer(vkd, cmdBuffer);
328
329 // Run pipeline.
330 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
331 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
332 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
333 vkd.cmdDrawMeshTasksNV(cmdBuffer, m_params->drawCount(), 0u);
334 endRenderPass(vkd, cmdBuffer);
335
336 // Copy color buffer to verification buffer.
337 const auto colorAccess = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
338 const auto transferRead = VK_ACCESS_TRANSFER_READ_BIT;
339 const auto transferWrite = VK_ACCESS_TRANSFER_WRITE_BIT;
340 const auto hostRead = VK_ACCESS_HOST_READ_BIT;
341
342 const auto preCopyBarrier = makeImageMemoryBarrier(colorAccess, transferRead, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSRR);
343 const auto postCopyBarrier = makeMemoryBarrier(transferWrite, hostRead);
344 const auto copyRegion = makeBufferImageCopy(imageExtent, colorSRL);
345
346 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
347 vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
348 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
349
350 endCommandBuffer(vkd, cmdBuffer);
351 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
352
353 // Generate reference image and compare results.
354 const tcu::IVec3 iExtent (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), 1);
355 const tcu::ConstPixelBufferAccess verificationAccess (tcuFormat, iExtent, verificationBufferData);
356
357 generateReferenceLevel();
358 invalidateAlloc(vkd, device, verificationBufferAlloc);
359 if (!verifyResult(verificationAccess))
360 TCU_FAIL("Result does not match reference; check log for details");
361
362 return tcu::TestStatus::pass("Pass");
363 }
364
365 // Verify passing more complex data between the task and mesh shaders.
366 class ComplexTaskDataCase : public MeshShaderMiscCase
367 {
368 public:
ComplexTaskDataCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)369 ComplexTaskDataCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
370 : MeshShaderMiscCase (testCtx, name, description, std::move(params))
371 {}
372
373 void initPrograms (vk::SourceCollections& programCollection) const override;
374 TestInstance* createInstance (Context& context) const override;
375 };
376
377 class ComplexTaskDataInstance : public MeshShaderMiscInstance
378 {
379 public:
ComplexTaskDataInstance(Context & context,const MiscTestParams * params)380 ComplexTaskDataInstance (Context& context, const MiscTestParams* params)
381 : MeshShaderMiscInstance (context, params)
382 {}
383
384 void generateReferenceLevel () override;
385 };
386
generateReferenceLevel()387 void ComplexTaskDataInstance::generateReferenceLevel ()
388 {
389 const auto format = getOutputFormat();
390 const auto tcuFormat = mapVkFormat(format);
391
392 const auto iWidth = static_cast<int>(m_params->width);
393 const auto iHeight = static_cast<int>(m_params->height);
394
395 const auto halfWidth = iWidth / 2;
396 const auto halfHeight = iHeight / 2;
397
398 m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
399
400 const auto access = m_referenceLevel->getAccess();
401
402 // Each image quadrant gets a different color.
403 for (int y = 0; y < iHeight; ++y)
404 for (int x = 0; x < iWidth; ++x)
405 {
406 const float red = ((y < halfHeight) ? 0.0f : 1.0f);
407 const float green = ((x < halfWidth) ? 0.0f : 1.0f);
408 const auto refColor = tcu::Vec4(red, green, 1.0f, 1.0f);
409 access.setPixel(refColor, x, y);
410 }
411 }
412
initPrograms(vk::SourceCollections & programCollection) const413 void ComplexTaskDataCase::initPrograms (vk::SourceCollections& programCollection) const
414 {
415 // Add the generic fragment shader.
416 MeshShaderMiscCase::initPrograms(programCollection);
417
418 const std::string taskDataDeclTemplate =
419 "struct RowId {\n"
420 " uint id;\n"
421 "};\n"
422 "\n"
423 "struct WorkGroupData {\n"
424 " float WorkGroupIdPlusOnex1000Iota[10];\n"
425 " RowId rowId;\n"
426 " uvec3 WorkGroupIdPlusOnex2000Iota;\n"
427 " vec2 WorkGroupIdPlusOnex3000Iota;\n"
428 "};\n"
429 "\n"
430 "struct ExternalData {\n"
431 " float OneMillion;\n"
432 " uint TwoMillion;\n"
433 " WorkGroupData workGroupData;\n"
434 "};\n"
435 "\n"
436 "${INOUT} taskNV TaskData {\n"
437 " uint yes;\n"
438 " ExternalData externalData;\n"
439 "} td;\n"
440 ;
441 const tcu::StringTemplate taskDataDecl(taskDataDeclTemplate);
442
443 {
444 std::map<std::string, std::string> taskMap;
445 taskMap["INOUT"] = "out";
446 std::ostringstream task;
447 task
448 << "#version 450\n"
449 << "#extension GL_NV_mesh_shader : enable\n"
450 << "\n"
451 << "layout (local_size_x=1) in;\n"
452 << "\n"
453 << taskDataDecl.specialize(taskMap)
454 << "\n"
455 << "void main ()\n"
456 << "{\n"
457 << " gl_TaskCountNV = 2u;\n"
458 << " td.yes = 1u;\n"
459 << " td.externalData.OneMillion = 1000000.0;\n"
460 << " td.externalData.TwoMillion = 2000000u;\n"
461 << " for (uint i = 0; i < 10; i++) {\n"
462 << " td.externalData.workGroupData.WorkGroupIdPlusOnex1000Iota[i] = float((gl_WorkGroupID.x + 1u) * 1000 + i);\n"
463 << " }\n"
464 << " {\n"
465 << " uint baseVal = (gl_WorkGroupID.x + 1u) * 2000;\n"
466 << " td.externalData.workGroupData.WorkGroupIdPlusOnex2000Iota = uvec3(baseVal, baseVal + 1, baseVal + 2);\n"
467 << " }\n"
468 << " {\n"
469 << " uint baseVal = (gl_WorkGroupID.x + 1u) * 3000;\n"
470 << " td.externalData.workGroupData.WorkGroupIdPlusOnex3000Iota = vec2(baseVal, baseVal + 1);\n"
471 << " }\n"
472 << " td.externalData.workGroupData.rowId.id = gl_WorkGroupID.x;\n"
473 << "}\n"
474 ;
475 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
476 }
477
478 {
479 std::map<std::string, std::string> meshMap;
480 meshMap["INOUT"] = "in";
481 std::ostringstream mesh;
482 mesh
483 << "#version 450\n"
484 << "#extension GL_NV_mesh_shader : enable\n"
485 << "\n"
486 << "layout(local_size_x=2) in;\n"
487 << "layout(triangles) out;\n"
488 << "layout(max_vertices=4, max_primitives=2) out;\n"
489 << "\n"
490 << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
491 << "\n"
492 << taskDataDecl.specialize(meshMap)
493 << "\n"
494 << "void main ()\n"
495 << "{\n"
496 << " bool dataOK = true;\n"
497 << " dataOK = (dataOK && (td.yes == 1u));\n"
498 << " dataOK = (dataOK && (td.externalData.OneMillion == 1000000.0 && td.externalData.TwoMillion == 2000000u));\n"
499 << " uint rowId = td.externalData.workGroupData.rowId.id;\n"
500 << " dataOK = (dataOK && (rowId == 0u || rowId == 1u));\n"
501 << "\n"
502 << " {\n"
503 << " uint baseVal = (rowId + 1u) * 1000u;\n"
504 << " for (uint i = 0; i < 10; i++) {\n"
505 << " if (td.externalData.workGroupData.WorkGroupIdPlusOnex1000Iota[i] != float(baseVal + i)) {\n"
506 << " dataOK = false;\n"
507 << " break;\n"
508 << " }\n"
509 << " }\n"
510 << " }\n"
511 << "\n"
512 << " {\n"
513 << " uint baseVal = (rowId + 1u) * 2000;\n"
514 << " uvec3 expected = uvec3(baseVal, baseVal + 1, baseVal + 2);\n"
515 << " if (td.externalData.workGroupData.WorkGroupIdPlusOnex2000Iota != expected) {\n"
516 << " dataOK = false;\n"
517 << " }\n"
518 << " }\n"
519 << "\n"
520 << " {\n"
521 << " uint baseVal = (rowId + 1u) * 3000;\n"
522 << " vec2 expected = vec2(baseVal, baseVal + 1);\n"
523 << " if (td.externalData.workGroupData.WorkGroupIdPlusOnex3000Iota != expected) {\n"
524 << " dataOK = false;\n"
525 << " }\n"
526 << " }\n"
527 << "\n"
528 << " uint columnId = gl_WorkGroupID.x;\n"
529 << "\n"
530 << " if (dataOK) {\n"
531 << " gl_PrimitiveCountNV = 2u;\n"
532 << " }\n"
533 << " else {\n"
534 << " gl_PrimitiveCountNV = 0u;\n"
535 << " return;\n"
536 << " }\n"
537 << "\n"
538 << " const vec4 outColor = vec4(rowId, columnId, 1.0f, 1.0f);\n"
539 << " triangleColor[0] = outColor;\n"
540 << " triangleColor[1] = outColor;\n"
541 << "\n"
542 << " // Each local invocation will generate two points and one triangle from the quad.\n"
543 << " // The first local invocation will generate the top quad vertices.\n"
544 << " // The second invocation will generate the two bottom vertices.\n"
545 << " vec4 left = vec4(0.0, 0.0, 0.0, 1.0);\n"
546 << " vec4 right = vec4(1.0, 0.0, 0.0, 1.0);\n"
547 << "\n"
548 << " float localInvocationOffsetY = float(gl_LocalInvocationID.x);\n"
549 << " left.y += localInvocationOffsetY;\n"
550 << " right.y += localInvocationOffsetY;\n"
551 << "\n"
552 << " // The code above creates a quad from (0, 0) to (1, 1) but we need to offset it\n"
553 << " // in X and/or Y depending on the row and column, to place it in other quadrants.\n"
554 << " float quadrantOffsetX = float(int(columnId) - 1);\n"
555 << " float quadrantOffsetY = float(int(rowId) - 1);\n"
556 << "\n"
557 << " left.x += quadrantOffsetX;\n"
558 << " right.x += quadrantOffsetX;\n"
559 << "\n"
560 << " left.y += quadrantOffsetY;\n"
561 << " right.y += quadrantOffsetY;\n"
562 << "\n"
563 << " uint baseVertexId = 2*gl_LocalInvocationID.x;\n"
564 << " gl_MeshVerticesNV[baseVertexId + 0].gl_Position = left;\n"
565 << " gl_MeshVerticesNV[baseVertexId + 1].gl_Position = right;\n"
566 << "\n"
567 << " uint baseIndexId = 3*gl_LocalInvocationID.x;\n"
568 << " // 0,1,2 or 1,2,3 (note: triangles alternate front face this way)\n"
569 << " gl_PrimitiveIndicesNV[baseIndexId + 0] = 0 + gl_LocalInvocationID.x;\n"
570 << " gl_PrimitiveIndicesNV[baseIndexId + 1] = 1 + gl_LocalInvocationID.x;\n"
571 << " gl_PrimitiveIndicesNV[baseIndexId + 2] = 2 + gl_LocalInvocationID.x;\n"
572 << "}\n"
573 ;
574 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
575 }
576 }
577
createInstance(Context & context) const578 TestInstance* ComplexTaskDataCase::createInstance (Context& context) const
579 {
580 return new ComplexTaskDataInstance(context, m_params.get());
581 }
582
583 // Verify drawing a single point.
584 class SinglePointCase : public MeshShaderMiscCase
585 {
586 public:
SinglePointCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)587 SinglePointCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
588 : MeshShaderMiscCase (testCtx, name, description, std::move(params))
589 {}
590
591 void initPrograms (vk::SourceCollections& programCollection) const override;
592 TestInstance* createInstance (Context& context) const override;
593 };
594
595 class SinglePointInstance : public MeshShaderMiscInstance
596 {
597 public:
SinglePointInstance(Context & context,const MiscTestParams * params)598 SinglePointInstance (Context& context, const MiscTestParams* params)
599 : MeshShaderMiscInstance (context, params)
600 {}
601
602 void generateReferenceLevel () override;
603 };
604
createInstance(Context & context) const605 TestInstance* SinglePointCase::createInstance (Context& context) const
606 {
607 return new SinglePointInstance (context, m_params.get());
608 }
609
initPrograms(vk::SourceCollections & programCollection) const610 void SinglePointCase::initPrograms (vk::SourceCollections& programCollection) const
611 {
612 DE_ASSERT(!m_params->needsTaskShader());
613
614 MeshShaderMiscCase::initPrograms(programCollection);
615
616 std::ostringstream mesh;
617 mesh
618 << "#version 450\n"
619 << "#extension GL_NV_mesh_shader : enable\n"
620 << "\n"
621 << "layout(local_size_x=1) in;\n"
622 << "layout(points) out;\n"
623 << "layout(max_vertices=256, max_primitives=256) out;\n"
624 << "\n"
625 << "layout (location=0) out perprimitiveNV vec4 pointColor[];\n"
626 << "\n"
627 << "void main ()\n"
628 << "{\n"
629 << " gl_PrimitiveCountNV = 1u;\n"
630 << " pointColor[0] = vec4(0.0f, 1.0f, 1.0f, 1.0f);\n"
631 << " gl_MeshVerticesNV[0].gl_Position = vec4(0.0f, 0.0f, 0.0f, 1.0f);\n"
632 << " gl_MeshVerticesNV[0].gl_PointSize = 1.0f;\n"
633 << " gl_PrimitiveIndicesNV[0] = 0;\n"
634 << "}\n"
635 ;
636 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
637 }
638
generateReferenceLevel()639 void SinglePointInstance::generateReferenceLevel ()
640 {
641 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), m_referenceLevel);
642
643 const auto halfWidth = static_cast<int>(m_params->width / 2u);
644 const auto halfHeight = static_cast<int>(m_params->height / 2u);
645 const auto access = m_referenceLevel->getAccess();
646
647 access.setPixel(tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f), halfWidth, halfHeight);
648 }
649
650 // Verify drawing a single line.
651 class SingleLineCase : public MeshShaderMiscCase
652 {
653 public:
SingleLineCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)654 SingleLineCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
655 : MeshShaderMiscCase (testCtx, name, description, std::move(params))
656 {}
657
658 void initPrograms (vk::SourceCollections& programCollection) const override;
659 TestInstance* createInstance (Context& context) const override;
660 };
661
662 class SingleLineInstance : public MeshShaderMiscInstance
663 {
664 public:
SingleLineInstance(Context & context,const MiscTestParams * params)665 SingleLineInstance (Context& context, const MiscTestParams* params)
666 : MeshShaderMiscInstance (context, params)
667 {}
668
669 void generateReferenceLevel () override;
670 };
671
createInstance(Context & context) const672 TestInstance* SingleLineCase::createInstance (Context& context) const
673 {
674 return new SingleLineInstance (context, m_params.get());
675 }
676
initPrograms(vk::SourceCollections & programCollection) const677 void SingleLineCase::initPrograms (vk::SourceCollections& programCollection) const
678 {
679 DE_ASSERT(!m_params->needsTaskShader());
680
681 MeshShaderMiscCase::initPrograms(programCollection);
682
683 std::ostringstream mesh;
684 mesh
685 << "#version 450\n"
686 << "#extension GL_NV_mesh_shader : enable\n"
687 << "\n"
688 << "layout(local_size_x=1) in;\n"
689 << "layout(lines) out;\n"
690 << "layout(max_vertices=256, max_primitives=256) out;\n"
691 << "\n"
692 << "layout (location=0) out perprimitiveNV vec4 lineColor[];\n"
693 << "\n"
694 << "void main ()\n"
695 << "{\n"
696 << " gl_PrimitiveCountNV = 1u;\n"
697 << " lineColor[0] = vec4(0.0f, 1.0f, 1.0f, 1.0f);\n"
698 << " gl_MeshVerticesNV[0].gl_Position = vec4(-1.0f, 0.0f, 0.0f, 1.0f);\n"
699 << " gl_MeshVerticesNV[1].gl_Position = vec4( 1.0f, 0.0f, 0.0f, 1.0f);\n"
700 << " gl_PrimitiveIndicesNV[0] = 0;\n"
701 << " gl_PrimitiveIndicesNV[1] = 1;\n"
702 << "}\n"
703 ;
704 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
705 }
706
generateReferenceLevel()707 void SingleLineInstance::generateReferenceLevel ()
708 {
709 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), m_referenceLevel);
710
711 const auto iWidth = static_cast<int>(m_params->width);
712 const auto halfHeight = static_cast<int>(m_params->height / 2u);
713 const auto access = m_referenceLevel->getAccess();
714
715 // Center row.
716 for (int x = 0; x < iWidth; ++x)
717 access.setPixel(tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f), x, halfHeight);
718 }
719
720 // Verify drawing a single triangle.
721 class SingleTriangleCase : public MeshShaderMiscCase
722 {
723 public:
SingleTriangleCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)724 SingleTriangleCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
725 : MeshShaderMiscCase (testCtx, name, description, std::move(params))
726 {}
727
728 void initPrograms (vk::SourceCollections& programCollection) const override;
729 TestInstance* createInstance (Context& context) const override;
730 };
731
732 class SingleTriangleInstance : public MeshShaderMiscInstance
733 {
734 public:
SingleTriangleInstance(Context & context,const MiscTestParams * params)735 SingleTriangleInstance (Context& context, const MiscTestParams* params)
736 : MeshShaderMiscInstance (context, params)
737 {}
738
739 void generateReferenceLevel () override;
740 };
741
createInstance(Context & context) const742 TestInstance* SingleTriangleCase::createInstance (Context& context) const
743 {
744 return new SingleTriangleInstance (context, m_params.get());
745 }
746
initPrograms(vk::SourceCollections & programCollection) const747 void SingleTriangleCase::initPrograms (vk::SourceCollections& programCollection) const
748 {
749 DE_ASSERT(!m_params->needsTaskShader());
750
751 MeshShaderMiscCase::initPrograms(programCollection);
752
753 const float halfPixelX = 2.0f / static_cast<float>(m_params->width);
754 const float halfPixelY = 2.0f / static_cast<float>(m_params->height);
755
756 std::ostringstream mesh;
757 mesh
758 << "#version 450\n"
759 << "#extension GL_NV_mesh_shader : enable\n"
760 << "\n"
761 << "layout(local_size_x=1) in;\n"
762 << "layout(triangles) out;\n"
763 << "layout(max_vertices=256, max_primitives=256) out;\n"
764 << "\n"
765 << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
766 << "\n"
767 << "void main ()\n"
768 << "{\n"
769 << " gl_PrimitiveCountNV = 1u;\n"
770 << " triangleColor[0] = vec4(0.0f, 1.0f, 1.0f, 1.0f);\n"
771 << " gl_MeshVerticesNV[0].gl_Position = vec4(" << halfPixelY << ", " << -halfPixelX << ", 0.0f, 1.0f);\n"
772 << " gl_MeshVerticesNV[1].gl_Position = vec4(" << halfPixelY << ", " << halfPixelX << ", 0.0f, 1.0f);\n"
773 << " gl_MeshVerticesNV[2].gl_Position = vec4(" << -halfPixelY << ", 0.0f, 0.0f, 1.0f);\n"
774 << " gl_PrimitiveIndicesNV[0] = 0;\n"
775 << " gl_PrimitiveIndicesNV[1] = 1;\n"
776 << " gl_PrimitiveIndicesNV[2] = 2;\n"
777 << "}\n"
778 ;
779 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
780 }
781
generateReferenceLevel()782 void SingleTriangleInstance::generateReferenceLevel ()
783 {
784 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), m_referenceLevel);
785
786 const auto halfWidth = static_cast<int>(m_params->width / 2u);
787 const auto halfHeight = static_cast<int>(m_params->height / 2u);
788 const auto access = m_referenceLevel->getAccess();
789
790 // Single pixel in the center.
791 access.setPixel(tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f), halfWidth, halfHeight);
792 }
793
794 // Verify drawing the maximum number of points.
795 class MaxPointsCase : public MeshShaderMiscCase
796 {
797 public:
MaxPointsCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)798 MaxPointsCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
799 : MeshShaderMiscCase (testCtx, name, description, std::move(params))
800 {}
801
802 void initPrograms (vk::SourceCollections& programCollection) const override;
803 TestInstance* createInstance (Context& context) const override;
804 };
805
806 class MaxPointsInstance : public MeshShaderMiscInstance
807 {
808 public:
MaxPointsInstance(Context & context,const MiscTestParams * params)809 MaxPointsInstance (Context& context, const MiscTestParams* params)
810 : MeshShaderMiscInstance (context, params)
811 {}
812
813 void generateReferenceLevel () override;
814 };
815
createInstance(Context & context) const816 TestInstance* MaxPointsCase::createInstance (Context& context) const
817 {
818 return new MaxPointsInstance (context, m_params.get());
819 }
820
initPrograms(vk::SourceCollections & programCollection) const821 void MaxPointsCase::initPrograms (vk::SourceCollections& programCollection) const
822 {
823 DE_ASSERT(!m_params->needsTaskShader());
824
825 MeshShaderMiscCase::initPrograms(programCollection);
826
827 // Fill a 16x16 image with 256 points. Each of the 32 local invocations will handle a segment of 8 pixels. Two segments per row.
828 DE_ASSERT(m_params->width == 16u && m_params->height == 16u);
829
830 std::ostringstream mesh;
831 mesh
832 << "#version 450\n"
833 << "#extension GL_NV_mesh_shader : enable\n"
834 << "\n"
835 << "layout(local_size_x=32) in;\n"
836 << "layout(points) out;\n"
837 << "layout(max_vertices=256, max_primitives=256) out;\n"
838 << "\n"
839 << "layout (location=0) out perprimitiveNV vec4 pointColor[];\n"
840 << "\n"
841 << "void main ()\n"
842 << "{\n"
843 << " gl_PrimitiveCountNV = 256u;\n"
844 << " uint firstPixel = 8u * gl_LocalInvocationID.x;\n"
845 << " uint row = firstPixel / 16u;\n"
846 << " uint col = firstPixel % 16u;\n"
847 << " float pixSize = 2.0f / 16.0f;\n"
848 << " float yCoord = pixSize * (float(row) + 0.5f) - 1.0f;\n"
849 << " float baseXCoord = pixSize * (float(col) + 0.5f) - 1.0f;\n"
850 << " for (uint i = 0; i < 8u; i++) {\n"
851 << " float xCoord = baseXCoord + pixSize * float(i);\n"
852 << " uint pixId = firstPixel + i;\n"
853 << " gl_MeshVerticesNV[pixId].gl_Position = vec4(xCoord, yCoord, 0.0f, 1.0f);\n"
854 << " gl_MeshVerticesNV[pixId].gl_PointSize = 1.0f;\n"
855 << " gl_PrimitiveIndicesNV[pixId] = pixId;\n"
856 << " pointColor[pixId] = vec4(((xCoord + 1.0f) / 2.0f), ((yCoord + 1.0f) / 2.0f), 0.0f, 1.0f);\n"
857 << " }\n"
858 << "}\n"
859 ;
860 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
861 }
862
generateReferenceLevel()863 void MaxPointsInstance::generateReferenceLevel ()
864 {
865 const auto format = getOutputFormat();
866 const auto tcuFormat = mapVkFormat(format);
867
868 const auto iWidth = static_cast<int>(m_params->width);
869 const auto iHeight = static_cast<int>(m_params->height);
870 const auto fWidth = static_cast<float>(m_params->width);
871 const auto fHeight = static_cast<float>(m_params->height);
872
873 m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
874
875 const auto access = m_referenceLevel->getAccess();
876
877 // Fill with gradient like the shader does.
878 for (int y = 0; y < iHeight; ++y)
879 for (int x = 0; x < iWidth; ++x)
880 {
881 const tcu::Vec4 color (
882 ((static_cast<float>(x) + 0.5f) / fWidth),
883 ((static_cast<float>(y) + 0.5f) / fHeight),
884 0.0f, 1.0f);
885 access.setPixel(color, x, y);
886 }
887 }
888
889 // Verify drawing the maximum number of lines.
890 class MaxLinesCase : public MeshShaderMiscCase
891 {
892 public:
MaxLinesCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)893 MaxLinesCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
894 : MeshShaderMiscCase (testCtx, name, description, std::move(params))
895 {}
896
897 void initPrograms (vk::SourceCollections& programCollection) const override;
898 TestInstance* createInstance (Context& context) const override;
899 };
900
901 class MaxLinesInstance : public MeshShaderMiscInstance
902 {
903 public:
MaxLinesInstance(Context & context,const MiscTestParams * params)904 MaxLinesInstance (Context& context, const MiscTestParams* params)
905 : MeshShaderMiscInstance (context, params)
906 {}
907
908 void generateReferenceLevel () override;
909 };
910
createInstance(Context & context) const911 TestInstance* MaxLinesCase::createInstance (Context& context) const
912 {
913 return new MaxLinesInstance (context, m_params.get());
914 }
915
initPrograms(vk::SourceCollections & programCollection) const916 void MaxLinesCase::initPrograms (vk::SourceCollections& programCollection) const
917 {
918 DE_ASSERT(!m_params->needsTaskShader());
919
920 MeshShaderMiscCase::initPrograms(programCollection);
921
922 // Fill a 1x1020 image with 255 lines, each line being 4 pixels tall. Each invocation will generate ~8 lines.
923 DE_ASSERT(m_params->width == 1u && m_params->height == 1020u);
924
925 std::ostringstream mesh;
926 mesh
927 << "#version 450\n"
928 << "#extension GL_NV_mesh_shader : enable\n"
929 << "\n"
930 << "layout(local_size_x=32) in;\n"
931 << "layout(lines) out;\n"
932 << "layout(max_vertices=256, max_primitives=255) out;\n"
933 << "\n"
934 << "layout (location=0) out perprimitiveNV vec4 lineColor[];\n"
935 << "\n"
936 << "void main ()\n"
937 << "{\n"
938 << " gl_PrimitiveCountNV = 255u;\n"
939 << " uint firstLine = 8u * gl_LocalInvocationID.x;\n"
940 << " for (uint i = 0u; i < 8u; i++) {\n"
941 << " uint lineId = firstLine + i;\n"
942 << " uint topPixel = 4u * lineId;\n"
943 << " uint bottomPixel = 3u + topPixel;\n"
944 << " if (bottomPixel < 1020u) {\n"
945 << " float bottomCoord = ((float(bottomPixel) + 1.0f) / 1020.0) * 2.0 - 1.0;\n"
946 << " gl_MeshVerticesNV[lineId + 1u].gl_Position = vec4(0.0, bottomCoord, 0.0f, 1.0f);\n"
947 << " gl_PrimitiveIndicesNV[lineId * 2u] = lineId;\n"
948 << " gl_PrimitiveIndicesNV[lineId * 2u + 1u] = lineId + 1u;\n"
949 << " lineColor[lineId] = vec4(0.0f, 1.0f, float(lineId) / 255.0f, 1.0f);\n"
950 << " } else {\n"
951 << " // The last iteration of the last invocation emits the first point\n"
952 << " gl_MeshVerticesNV[0].gl_Position = vec4(0.0, -1.0, 0.0f, 1.0f);\n"
953 << " }\n"
954 << " }\n"
955 << "}\n"
956 ;
957 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
958 }
959
generateReferenceLevel()960 void MaxLinesInstance::generateReferenceLevel ()
961 {
962 const auto format = getOutputFormat();
963 const auto tcuFormat = mapVkFormat(format);
964
965 const auto iWidth = static_cast<int>(m_params->width);
966 const auto iHeight = static_cast<int>(m_params->height);
967
968 m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
969
970 const auto access = m_referenceLevel->getAccess();
971
972 // Fill lines, 4 pixels per line.
973 const uint32_t kNumLines = 255u;
974 const uint32_t kLineHeight = 4u;
975
976 for (uint32_t i = 0u; i < kNumLines; ++i)
977 {
978 const tcu::Vec4 color (0.0f, 1.0f, static_cast<float>(i) / static_cast<float>(kNumLines), 1.0f);
979 for (uint32_t j = 0u; j < kLineHeight; ++j)
980 access.setPixel(color, 0, i*kLineHeight + j);
981 }
982 }
983
984 // Verify drawing the maximum number of triangles.
985 class MaxTrianglesCase : public MeshShaderMiscCase
986 {
987 public:
MaxTrianglesCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)988 MaxTrianglesCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
989 : MeshShaderMiscCase (testCtx, name, description, std::move(params))
990 {}
991
992 void initPrograms (vk::SourceCollections& programCollection) const override;
993 TestInstance* createInstance (Context& context) const override;
994 };
995
996 class MaxTrianglesInstance : public MeshShaderMiscInstance
997 {
998 public:
MaxTrianglesInstance(Context & context,const MiscTestParams * params)999 MaxTrianglesInstance (Context& context, const MiscTestParams* params)
1000 : MeshShaderMiscInstance (context, params)
1001 {}
1002
1003 void generateReferenceLevel () override;
1004 };
1005
createInstance(Context & context) const1006 TestInstance* MaxTrianglesCase::createInstance (Context& context) const
1007 {
1008 return new MaxTrianglesInstance (context, m_params.get());
1009 }
1010
initPrograms(vk::SourceCollections & programCollection) const1011 void MaxTrianglesCase::initPrograms (vk::SourceCollections& programCollection) const
1012 {
1013 DE_ASSERT(!m_params->needsTaskShader());
1014
1015 MeshShaderMiscCase::initPrograms(programCollection);
1016
1017 // Fill a sufficiently large image with solid color. Generate a quarter of a circle with the center in the top left corner,
1018 // using a triangle fan that advances from top to bottom. Each invocation will generate ~8 triangles.
1019 std::ostringstream mesh;
1020 mesh
1021 << "#version 450\n"
1022 << "#extension GL_NV_mesh_shader : enable\n"
1023 << "\n"
1024 << "layout(local_size_x=32) in;\n"
1025 << "layout(triangles) out;\n"
1026 << "layout(max_vertices=256, max_primitives=254) out;\n"
1027 << "\n"
1028 << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
1029 << "\n"
1030 << "const float PI_2 = 1.57079632679489661923;\n"
1031 << "const float RADIUS = 4.5;\n"
1032 << "\n"
1033 << "void main ()\n"
1034 << "{\n"
1035 << " gl_PrimitiveCountNV = 254u;\n"
1036 << " uint firstTriangle = 8u * gl_LocalInvocationID.x;\n"
1037 << " for (uint i = 0u; i < 8u; i++) {\n"
1038 << " uint triangleId = firstTriangle + i;\n"
1039 << " if (triangleId < 254u) {\n"
1040 << " uint vertexId = triangleId + 2u;\n"
1041 << " float angleProportion = float(vertexId - 1u) / 254.0f;\n"
1042 << " float angle = PI_2 * angleProportion;\n"
1043 << " float xCoord = cos(angle) * RADIUS - 1.0;\n"
1044 << " float yCoord = sin(angle) * RADIUS - 1.0;\n"
1045 << " gl_MeshVerticesNV[vertexId].gl_Position = vec4(xCoord, yCoord, 0.0, 1.0);\n"
1046 << " gl_PrimitiveIndicesNV[triangleId * 3u + 0u] = 0u;\n"
1047 << " gl_PrimitiveIndicesNV[triangleId * 3u + 1u] = triangleId + 1u;\n"
1048 << " gl_PrimitiveIndicesNV[triangleId * 3u + 2u] = triangleId + 2u;\n"
1049 << " triangleColor[triangleId] = vec4(0.0f, 0.0f, 1.0f, 1.0f);\n"
1050 << " } else {\n"
1051 << " // The last iterations of the last invocation emit the first two vertices\n"
1052 << " uint vertexId = triangleId - 254u;\n"
1053 << " if (vertexId == 0u) {\n"
1054 << " gl_MeshVerticesNV[0u].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
1055 << " } else {\n"
1056 << " gl_MeshVerticesNV[1u].gl_Position = vec4(RADIUS, -1.0, 0.0, 1.0);\n"
1057 << " }\n"
1058 << " }\n"
1059 << " }\n"
1060 << "}\n"
1061 ;
1062 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1063 }
1064
generateReferenceLevel()1065 void MaxTrianglesInstance::generateReferenceLevel ()
1066 {
1067 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
1068 }
1069
1070 // Large work groups with many threads.
1071 class LargeWorkGroupCase : public MeshShaderMiscCase
1072 {
1073 public:
LargeWorkGroupCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)1074 LargeWorkGroupCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
1075 : MeshShaderMiscCase (testCtx, name, description, std::move(params))
1076 {}
1077
1078 void initPrograms (vk::SourceCollections& programCollection) const override;
1079 TestInstance* createInstance (Context& context) const override;
1080
1081 static constexpr uint32_t kLocalInvocations = 32u;
1082 };
1083
1084 class LargeWorkGroupInstance : public MeshShaderMiscInstance
1085 {
1086 public:
LargeWorkGroupInstance(Context & context,const MiscTestParams * params)1087 LargeWorkGroupInstance (Context& context, const MiscTestParams* params)
1088 : MeshShaderMiscInstance (context, params)
1089 {}
1090
1091 void generateReferenceLevel () override;
1092 };
1093
createInstance(Context & context) const1094 TestInstance* LargeWorkGroupCase::createInstance (Context& context) const
1095 {
1096 return new LargeWorkGroupInstance(context, m_params.get());
1097 }
1098
generateReferenceLevel()1099 void LargeWorkGroupInstance::generateReferenceLevel ()
1100 {
1101 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
1102 }
1103
initPrograms(vk::SourceCollections & programCollection) const1104 void LargeWorkGroupCase::initPrograms (vk::SourceCollections& programCollection) const
1105 {
1106 const auto useTaskShader = m_params->needsTaskShader();
1107 const auto taskMultiplier = (useTaskShader ? m_params->taskCount.get() : 1u);
1108
1109 // Add the frag shader.
1110 MeshShaderMiscCase::initPrograms(programCollection);
1111
1112 std::ostringstream taskData;
1113 taskData
1114 << "taskNV TaskData {\n"
1115 << " uint parentTask[" << kLocalInvocations << "];\n"
1116 << "} td;\n"
1117 ;
1118 const auto taskDataStr = taskData.str();
1119
1120 if (useTaskShader)
1121 {
1122 std::ostringstream task;
1123 task
1124 << "#version 450\n"
1125 << "#extension GL_NV_mesh_shader : enable\n"
1126 << "\n"
1127 << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
1128 << "\n"
1129 << "out " << taskDataStr
1130 << "\n"
1131 << "void main () {\n"
1132 << " gl_TaskCountNV = " << m_params->meshCount << ";\n"
1133 << " td.parentTask[gl_LocalInvocationID.x] = gl_WorkGroupID.x;\n"
1134 << "}\n"
1135 ;
1136 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
1137 }
1138
1139 // Needed for the code below to work.
1140 DE_ASSERT(m_params->width * m_params->height == taskMultiplier * m_params->meshCount * kLocalInvocations);
1141 DE_UNREF(taskMultiplier); // For release builds.
1142
1143 // Emit one point per framebuffer pixel. The number of jobs (kLocalInvocations in each mesh shader work group, multiplied by the
1144 // number of mesh work groups emitted by each task work group) must be the same as the total framebuffer size. Calculate a job
1145 // ID corresponding to the current mesh shader invocation, and assign a pixel position to it. Draw a point at that position.
1146 std::ostringstream mesh;
1147 mesh
1148 << "#version 450\n"
1149 << "#extension GL_NV_mesh_shader : enable\n"
1150 << "\n"
1151 << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
1152 << "layout (points) out;\n"
1153 << "layout (max_vertices=" << kLocalInvocations << ", max_primitives=" << kLocalInvocations << ") out;\n"
1154 << "\n"
1155 << (useTaskShader ? "in " + taskDataStr : "")
1156 << "\n"
1157 << "layout (location=0) out perprimitiveNV vec4 pointColor[];\n"
1158 << "\n"
1159 << "void main () {\n"
1160 ;
1161
1162 if (useTaskShader)
1163 {
1164 mesh
1165 << " uint parentTask = td.parentTask[0];\n"
1166 << " if (td.parentTask[gl_LocalInvocationID.x] != parentTask) {\n"
1167 << " return;\n"
1168 << " }\n"
1169 ;
1170 }
1171 else
1172 {
1173 mesh << " uint parentTask = 0;\n";
1174 }
1175
1176 mesh
1177 << " gl_PrimitiveCountNV = " << kLocalInvocations << ";\n"
1178 << " uint jobId = ((parentTask * " << m_params->meshCount << ") + gl_WorkGroupID.x) * " << kLocalInvocations << " + gl_LocalInvocationID.x;\n"
1179 << " uint row = jobId / " << m_params->width << ";\n"
1180 << " uint col = jobId % " << m_params->width << ";\n"
1181 << " float yCoord = (float(row + 0.5) / " << m_params->height << ".0) * 2.0 - 1.0;\n"
1182 << " float xCoord = (float(col + 0.5) / " << m_params->width << ".0) * 2.0 - 1.0;\n"
1183 << " gl_MeshVerticesNV[gl_LocalInvocationID.x].gl_Position = vec4(xCoord, yCoord, 0.0, 1.0);\n"
1184 << " gl_MeshVerticesNV[gl_LocalInvocationID.x].gl_PointSize = 1.0;\n"
1185 << " gl_PrimitiveIndicesNV[gl_LocalInvocationID.x] = gl_LocalInvocationID.x;\n"
1186 << " pointColor[gl_LocalInvocationID.x] = vec4(0.0, 0.0, 1.0, 1.0);\n"
1187 << "}\n"
1188 ;
1189 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1190 }
1191
1192 // Tests that generate no primitives of a given type.
1193 enum class PrimitiveType { POINTS=0, LINES, TRIANGLES };
1194
primitiveTypeName(PrimitiveType primitiveType)1195 std::string primitiveTypeName (PrimitiveType primitiveType)
1196 {
1197 std::string primitiveName;
1198
1199 switch (primitiveType)
1200 {
1201 case PrimitiveType::POINTS: primitiveName = "points"; break;
1202 case PrimitiveType::LINES: primitiveName = "lines"; break;
1203 case PrimitiveType::TRIANGLES: primitiveName = "triangles"; break;
1204 default: DE_ASSERT(false); break;
1205 }
1206
1207 return primitiveName;
1208 }
1209
1210 struct NoPrimitivesParams : public MiscTestParams
1211 {
1212 PrimitiveType primitiveType;
1213 };
1214
1215 class NoPrimitivesCase : public MeshShaderMiscCase
1216 {
1217 public:
NoPrimitivesCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)1218 NoPrimitivesCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
1219 : MeshShaderMiscCase (testCtx, name, description, std::move(params))
1220 {}
1221
1222 void initPrograms (vk::SourceCollections& programCollection) const override;
1223 TestInstance* createInstance (Context& context) const override;
1224 };
1225
1226 class NoPrimitivesInstance : public MeshShaderMiscInstance
1227 {
1228 public:
NoPrimitivesInstance(Context & context,const MiscTestParams * params)1229 NoPrimitivesInstance (Context& context, const MiscTestParams* params)
1230 : MeshShaderMiscInstance (context, params)
1231 {}
1232
1233 void generateReferenceLevel () override;
1234 };
1235
generateReferenceLevel()1236 void NoPrimitivesInstance::generateReferenceLevel ()
1237 {
1238 // No primitives: clear color.
1239 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), m_referenceLevel);
1240 }
1241
createInstance(Context & context) const1242 TestInstance* NoPrimitivesCase::createInstance (Context& context) const
1243 {
1244 return new NoPrimitivesInstance(context, m_params.get());
1245 }
1246
initPrograms(vk::SourceCollections & programCollection) const1247 void NoPrimitivesCase::initPrograms (vk::SourceCollections& programCollection) const
1248 {
1249 const auto params = dynamic_cast<NoPrimitivesParams*>(m_params.get());
1250
1251 DE_ASSERT(params);
1252 DE_ASSERT(!params->needsTaskShader());
1253
1254 const auto primitiveName = primitiveTypeName(params->primitiveType);
1255
1256 std::ostringstream mesh;
1257 mesh
1258 << "#version 450\n"
1259 << "#extension GL_NV_mesh_shader : enable\n"
1260 << "\n"
1261 << "layout (local_size_x=32) in;\n"
1262 << "layout (" << primitiveName << ") out;\n"
1263 << "layout (max_vertices=256, max_primitives=256) out;\n"
1264 << "\n"
1265 << "layout (location=0) out perprimitiveNV vec4 primitiveColor[];\n"
1266 << "\n"
1267 << "void main () {\n"
1268 << " gl_PrimitiveCountNV = 0u;\n"
1269 << "}\n"
1270 ;
1271
1272 MeshShaderMiscCase::initPrograms(programCollection);
1273 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1274 }
1275
1276 class NoPrimitivesExtraWritesCase : public NoPrimitivesCase
1277 {
1278 public:
NoPrimitivesExtraWritesCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)1279 NoPrimitivesExtraWritesCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
1280 : NoPrimitivesCase (testCtx, name, description, std::move(params))
1281 {}
1282
1283 void initPrograms (vk::SourceCollections& programCollection) const override;
1284
1285 static constexpr uint32_t kLocalInvocations = 32u;
1286 };
1287
initPrograms(vk::SourceCollections & programCollection) const1288 void NoPrimitivesExtraWritesCase::initPrograms (vk::SourceCollections& programCollection) const
1289 {
1290 const auto params = dynamic_cast<NoPrimitivesParams*>(m_params.get());
1291
1292 DE_ASSERT(params);
1293 DE_ASSERT(m_params->needsTaskShader());
1294
1295 std::ostringstream taskData;
1296 taskData
1297 << "taskNV TaskData {\n"
1298 << " uint localInvocations[" << kLocalInvocations << "];\n"
1299 << "} td;\n"
1300 ;
1301 const auto taskDataStr = taskData.str();
1302
1303 std::ostringstream task;
1304 task
1305 << "#version 450\n"
1306 << "#extension GL_NV_mesh_shader : enable\n"
1307 << "\n"
1308 << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
1309 << "\n"
1310 << "out " << taskDataStr
1311 << "\n"
1312 << "void main () {\n"
1313 << " gl_TaskCountNV = " << params->meshCount << ";\n"
1314 << " td.localInvocations[gl_LocalInvocationID.x] = gl_LocalInvocationID.x;\n"
1315 << "}\n"
1316 ;
1317 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
1318
1319 const auto primitiveName = primitiveTypeName(params->primitiveType);
1320
1321 // Otherwise the shader would be illegal.
1322 DE_ASSERT(kLocalInvocations > 2u);
1323
1324 uint32_t maxPrimitives = 0u;
1325 switch (params->primitiveType)
1326 {
1327 case PrimitiveType::POINTS: maxPrimitives = kLocalInvocations - 0u; break;
1328 case PrimitiveType::LINES: maxPrimitives = kLocalInvocations - 1u; break;
1329 case PrimitiveType::TRIANGLES: maxPrimitives = kLocalInvocations - 2u; break;
1330 default: DE_ASSERT(false); break;
1331 }
1332
1333 const std::string pointSizeDecl = ((params->primitiveType == PrimitiveType::POINTS)
1334 ? " gl_MeshVerticesNV[gl_LocalInvocationID.x].gl_PointSize = 1.0;\n"
1335 : "");
1336
1337 std::ostringstream mesh;
1338 mesh
1339 << "#version 450\n"
1340 << "#extension GL_NV_mesh_shader : enable\n"
1341 << "\n"
1342 << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
1343 << "layout (" << primitiveName << ") out;\n"
1344 << "layout (max_vertices=" << kLocalInvocations << ", max_primitives=" << maxPrimitives << ") out;\n"
1345 << "\n"
1346 << "in " << taskDataStr
1347 << "\n"
1348 << "layout (location=0) out perprimitiveNV vec4 primitiveColor[];\n"
1349 << "\n"
1350 << "shared uint sumOfIds;\n"
1351 << "\n"
1352 << "const float PI_2 = 1.57079632679489661923;\n"
1353 << "const float RADIUS = 1.0f;\n"
1354 << "\n"
1355 << "void main ()\n"
1356 << "{\n"
1357 << " sumOfIds = 0u;\n"
1358 << " barrier();\n"
1359 << " atomicAdd(sumOfIds, td.localInvocations[gl_LocalInvocationID.x]);\n"
1360 << " barrier();\n"
1361 << " // This should dynamically give 0\n"
1362 << " gl_PrimitiveCountNV = sumOfIds - (" << kLocalInvocations * (kLocalInvocations - 1u) / 2u << ");\n"
1363 << "\n"
1364 << " // Emit points and primitives to the arrays in any case\n"
1365 << " if (gl_LocalInvocationID.x > 0u) {\n"
1366 << " float proportion = (float(gl_LocalInvocationID.x - 1u) + 0.5f) / float(" << kLocalInvocations << " - 1u);\n"
1367 << " float angle = PI_2 * proportion;\n"
1368 << " float xCoord = cos(angle) * RADIUS - 1.0;\n"
1369 << " float yCoord = sin(angle) * RADIUS - 1.0;\n"
1370 << " gl_MeshVerticesNV[gl_LocalInvocationID.x].gl_Position = vec4(xCoord, yCoord, 0.0, 1.0);\n"
1371 << pointSizeDecl
1372 << " } else {\n"
1373 << " gl_MeshVerticesNV[gl_LocalInvocationID.x].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
1374 << pointSizeDecl
1375 << " }\n"
1376 << " uint primitiveId = max(gl_LocalInvocationID.x, " << (maxPrimitives - 1u) << ");\n"
1377 << " primitiveColor[primitiveId] = vec4(0.0, 0.0, 1.0, 1.0);\n"
1378 ;
1379
1380 if (params->primitiveType == PrimitiveType::POINTS)
1381 {
1382 mesh
1383 << " gl_PrimitiveIndicesNV[primitiveId] = primitiveId;\n"
1384 ;
1385 }
1386 else if (params->primitiveType == PrimitiveType::LINES)
1387 {
1388 mesh
1389 << " gl_PrimitiveIndicesNV[primitiveId * 2u + 0u] = primitiveId + 0u;\n"
1390 << " gl_PrimitiveIndicesNV[primitiveId * 2u + 1u] = primitiveId + 1u;\n"
1391 ;
1392 }
1393 else if (params->primitiveType == PrimitiveType::TRIANGLES)
1394 {
1395 mesh
1396 << " gl_PrimitiveIndicesNV[primitiveId * 3u + 0u] = 0u;\n"
1397 << " gl_PrimitiveIndicesNV[primitiveId * 3u + 1u] = primitiveId + 1u;\n"
1398 << " gl_PrimitiveIndicesNV[primitiveId * 3u + 2u] = primitiveId + 3u;\n"
1399 ;
1400 }
1401 else
1402 DE_ASSERT(false);
1403
1404 mesh
1405 << "}\n"
1406 ;
1407
1408 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1409
1410 MeshShaderMiscCase::initPrograms(programCollection);
1411 }
1412
1413 // Case testing barrier().
1414 class SimpleBarrierCase : public MeshShaderMiscCase
1415 {
1416 public:
SimpleBarrierCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)1417 SimpleBarrierCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
1418 : MeshShaderMiscCase (testCtx, name, description, std::move(params))
1419 {}
1420
1421 void initPrograms (vk::SourceCollections& programCollection) const override;
1422 TestInstance* createInstance (Context& context) const override;
1423
1424 static constexpr uint32_t kLocalInvocations = 32u;
1425 };
1426
1427 class SimpleBarrierInstance : public MeshShaderMiscInstance
1428 {
1429 public:
SimpleBarrierInstance(Context & context,const MiscTestParams * params)1430 SimpleBarrierInstance (Context& context, const MiscTestParams* params)
1431 : MeshShaderMiscInstance (context, params)
1432 {}
1433
1434 void generateReferenceLevel () override;
1435 };
1436
createInstance(Context & context) const1437 TestInstance* SimpleBarrierCase::createInstance (Context& context) const
1438 {
1439 return new SimpleBarrierInstance(context, m_params.get());
1440 }
1441
generateReferenceLevel()1442 void SimpleBarrierInstance::generateReferenceLevel ()
1443 {
1444 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
1445 }
1446
initPrograms(vk::SourceCollections & programCollection) const1447 void SimpleBarrierCase::initPrograms (vk::SourceCollections& programCollection) const
1448 {
1449 // Generate frag shader.
1450 MeshShaderMiscCase::initPrograms(programCollection);
1451
1452 DE_ASSERT(m_params->meshCount == 1u);
1453 DE_ASSERT(m_params->width == 1u && m_params->height == 1u);
1454
1455 std::ostringstream meshPrimData;
1456 meshPrimData
1457 << "gl_PrimitiveCountNV = 1u;\n"
1458 << "gl_MeshVerticesNV[0].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
1459 << "gl_MeshVerticesNV[0].gl_PointSize = 1.0;\n"
1460 << "primitiveColor[0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
1461 << "gl_PrimitiveIndicesNV[0] = 0;\n"
1462 ;
1463 const std::string meshPrimStr = meshPrimData.str();
1464
1465 const std::string taskOK = "gl_TaskCountNV = 1u;\n";
1466 const std::string taskFAIL = "gl_TaskCountNV = 0u;\n";
1467
1468 const std::string meshOK = meshPrimStr;
1469 const std::string meshFAIL = "gl_PrimitiveCountNV = 0u;\n";
1470
1471 const std::string okStatement = (m_params->needsTaskShader() ? taskOK : meshOK);
1472 const std::string failStatement = (m_params->needsTaskShader() ? taskFAIL : meshFAIL);
1473
1474 const std::string sharedDecl = "shared uint counter;\n\n";
1475 std::ostringstream verification;
1476 verification
1477 << "counter = 0;\n"
1478 << "barrier();\n"
1479 << "atomicAdd(counter, 1u);\n"
1480 << "barrier();\n"
1481 << "if (gl_LocalInvocationID.x == 0u) {\n"
1482 << " if (counter == " << kLocalInvocations << ") {\n"
1483 << "\n"
1484 << okStatement
1485 << "\n"
1486 << " } else {\n"
1487 << "\n"
1488 << failStatement
1489 << "\n"
1490 << " }\n"
1491 << "}\n"
1492 ;
1493
1494 // The mesh shader is very similar in both cases, so we use a template.
1495 std::ostringstream meshTemplateStr;
1496 meshTemplateStr
1497 << "#version 450\n"
1498 << "#extension GL_NV_mesh_shader : enable\n"
1499 << "\n"
1500 << "layout (local_size_x=${LOCAL_SIZE}) in;\n"
1501 << "layout (points) out;\n"
1502 << "layout (max_vertices=1, max_primitives=1) out;\n"
1503 << "\n"
1504 << "layout (location=0) out perprimitiveNV vec4 primitiveColor[];\n"
1505 << "\n"
1506 << "${GLOBALS:opt}"
1507 << "void main ()\n"
1508 << "{\n"
1509 << "${BODY}"
1510 << "}\n"
1511 ;
1512 const tcu::StringTemplate meshTemplate = meshTemplateStr.str();
1513
1514 if (m_params->needsTaskShader())
1515 {
1516 std::ostringstream task;
1517 task
1518 << "#version 450\n"
1519 << "#extension GL_NV_mesh_shader : enable\n"
1520 << "\n"
1521 << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
1522 << "\n"
1523 << sharedDecl
1524 << "void main ()\n"
1525 << "{\n"
1526 << verification.str()
1527 << "}\n"
1528 ;
1529
1530 std::map<std::string, std::string> replacements;
1531 replacements["LOCAL_SIZE"] = "1";
1532 replacements["BODY"] = meshPrimStr;
1533
1534 const auto meshStr = meshTemplate.specialize(replacements);
1535
1536 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
1537 programCollection.glslSources.add("mesh") << glu::MeshSource(meshStr);
1538 }
1539 else
1540 {
1541 std::map<std::string, std::string> replacements;
1542 replacements["LOCAL_SIZE"] = std::to_string(kLocalInvocations);
1543 replacements["BODY"] = verification.str();
1544 replacements["GLOBALS"] = sharedDecl;
1545
1546 const auto meshStr = meshTemplate.specialize(replacements);
1547
1548 programCollection.glslSources.add("mesh") << glu::MeshSource(meshStr);
1549 }
1550 }
1551
1552 // Case testing memoryBarrierShared() and groupMemoryBarrier().
1553 enum class MemoryBarrierType { SHARED = 0, GROUP };
1554
1555 struct MemoryBarrierParams : public MiscTestParams
1556 {
1557 MemoryBarrierType memBarrierType;
1558
glslFuncvkt::MeshShader::__anona67b1ba90111::MemoryBarrierParams1559 std::string glslFunc () const
1560 {
1561 std::string funcName;
1562
1563 switch (memBarrierType)
1564 {
1565 case MemoryBarrierType::SHARED: funcName = "memoryBarrierShared"; break;
1566 case MemoryBarrierType::GROUP: funcName = "groupMemoryBarrier"; break;
1567 default: DE_ASSERT(false); break;
1568 }
1569
1570 return funcName;
1571 }
1572
1573 };
1574
1575 class MemoryBarrierCase : public MeshShaderMiscCase
1576 {
1577 public:
MemoryBarrierCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)1578 MemoryBarrierCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
1579 : MeshShaderMiscCase (testCtx, name, description, std::move(params))
1580 {}
1581
1582 void initPrograms (vk::SourceCollections& programCollection) const override;
1583 TestInstance* createInstance (Context& context) const override;
1584
1585 static constexpr uint32_t kLocalInvocations = 2u;
1586 };
1587
1588 class MemoryBarrierInstance : public MeshShaderMiscInstance
1589 {
1590 public:
MemoryBarrierInstance(Context & context,const MiscTestParams * params)1591 MemoryBarrierInstance (Context& context, const MiscTestParams* params)
1592 : MeshShaderMiscInstance (context, params)
1593 {}
1594
1595 void generateReferenceLevel () override;
1596 bool verifyResult (const tcu::ConstPixelBufferAccess& resultAccess) const override;
1597
1598 protected:
1599 // Allow two possible outcomes.
1600 std::unique_ptr<tcu::TextureLevel> m_referenceLevel2;
1601 };
1602
createInstance(Context & context) const1603 TestInstance* MemoryBarrierCase::createInstance (Context& context) const
1604 {
1605 return new MemoryBarrierInstance(context, m_params.get());
1606 }
1607
generateReferenceLevel()1608 void MemoryBarrierInstance::generateReferenceLevel ()
1609 {
1610 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
1611 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), m_referenceLevel2);
1612 }
1613
verifyResult(const tcu::ConstPixelBufferAccess & resultAccess) const1614 bool MemoryBarrierInstance::verifyResult (const tcu::ConstPixelBufferAccess& resultAccess) const
1615 {
1616 // Any of the two results is considered valid.
1617 // Clarify what we are checking in the logs; otherwise, they could be confusing.
1618 auto& log = m_context.getTestContext().getLog();
1619 const std::vector<tcu::TextureLevel*> levels = { m_referenceLevel.get(), m_referenceLevel2.get() };
1620
1621 bool good = false;
1622 for (size_t i = 0; i < levels.size(); ++i)
1623 {
1624 log << tcu::TestLog::Message << "Comparing result with reference " << i << "..." << tcu::TestLog::EndMessage;
1625 const auto success = MeshShaderMiscInstance::verifyResult(resultAccess, *levels[i]);
1626 if (success)
1627 {
1628 log << tcu::TestLog::Message << "Match! The test has passed" << tcu::TestLog::EndMessage;
1629 good = true;
1630 break;
1631 }
1632 }
1633
1634 return good;
1635 }
1636
initPrograms(vk::SourceCollections & programCollection) const1637 void MemoryBarrierCase::initPrograms (vk::SourceCollections& programCollection) const
1638 {
1639 const auto params = dynamic_cast<MemoryBarrierParams*>(m_params.get());
1640 DE_ASSERT(params);
1641
1642 // Generate frag shader.
1643 MeshShaderMiscCase::initPrograms(programCollection);
1644
1645 DE_ASSERT(params->meshCount == 1u);
1646 DE_ASSERT(params->width == 1u && params->height == 1u);
1647
1648 const bool taskShader = params->needsTaskShader();
1649
1650 const std::string taskDataDecl = "taskNV TaskData { float blue; } td;\n\n";
1651 const std::string inTaskData = "in " + taskDataDecl;
1652 const std::string outTaskData = "out " + taskDataDecl;
1653 const auto barrierFunc = params->glslFunc();
1654
1655 std::ostringstream meshPrimData;
1656 meshPrimData
1657 << "gl_PrimitiveCountNV = 1u;\n"
1658 << "gl_MeshVerticesNV[0].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
1659 << "gl_MeshVerticesNV[0].gl_PointSize = 1.0;\n"
1660 << "primitiveColor[0] = vec4(0.0, 0.0, " << (taskShader ? "td.blue" : "float(iterations % 2u)") << ", 1.0);\n"
1661 << "gl_PrimitiveIndicesNV[0] = 0;\n"
1662 ;
1663 const std::string meshPrimStr = meshPrimData.str();
1664
1665 const std::string taskAction = "gl_TaskCountNV = 1u;\ntd.blue = float(iterations % 2u);\n";
1666 const std::string meshAction = meshPrimStr;
1667 const std::string action = (taskShader ? taskAction : meshAction);
1668
1669 const std::string sharedDecl = "shared uint flags[2];\n\n";
1670 std::ostringstream verification;
1671 verification
1672 << "flags[gl_LocalInvocationID.x] = 0u;\n"
1673 << "barrier();\n"
1674 << "flags[gl_LocalInvocationID.x] = 1u;\n"
1675 << barrierFunc << "();\n"
1676 << "uint otherInvocation = 1u - gl_LocalInvocationID.x;\n"
1677 << "uint iterations = 0u;\n"
1678 << "while (flags[otherInvocation] != 1u) {\n"
1679 << " iterations++;\n"
1680 << "}\n"
1681 << "if (gl_LocalInvocationID.x == 0u) {\n"
1682 << "\n"
1683 << action
1684 << "\n"
1685 << "}\n"
1686 ;
1687
1688 // The mesh shader is very similar in both cases, so we use a template.
1689 std::ostringstream meshTemplateStr;
1690 meshTemplateStr
1691 << "#version 450\n"
1692 << "#extension GL_NV_mesh_shader : enable\n"
1693 << "\n"
1694 << "layout (local_size_x=${LOCAL_SIZE}) in;\n"
1695 << "layout (points) out;\n"
1696 << "layout (max_vertices=1, max_primitives=1) out;\n"
1697 << "\n"
1698 << "layout (location=0) out perprimitiveNV vec4 primitiveColor[];\n"
1699 << "\n"
1700 << "${GLOBALS}"
1701 << "void main ()\n"
1702 << "{\n"
1703 << "${BODY}"
1704 << "}\n"
1705 ;
1706 const tcu::StringTemplate meshTemplate = meshTemplateStr.str();
1707
1708 if (params->needsTaskShader())
1709 {
1710 std::ostringstream task;
1711 task
1712 << "#version 450\n"
1713 << "#extension GL_NV_mesh_shader : enable\n"
1714 << "\n"
1715 << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
1716 << "\n"
1717 << sharedDecl
1718 << outTaskData
1719 << "void main ()\n"
1720 << "{\n"
1721 << verification.str()
1722 << "}\n"
1723 ;
1724
1725 std::map<std::string, std::string> replacements;
1726 replacements["LOCAL_SIZE"] = "1";
1727 replacements["BODY"] = meshPrimStr;
1728 replacements["GLOBALS"] = inTaskData;
1729
1730 const auto meshStr = meshTemplate.specialize(replacements);
1731
1732 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
1733 programCollection.glslSources.add("mesh") << glu::MeshSource(meshStr);
1734 }
1735 else
1736 {
1737 std::map<std::string, std::string> replacements;
1738 replacements["LOCAL_SIZE"] = std::to_string(kLocalInvocations);
1739 replacements["BODY"] = verification.str();
1740 replacements["GLOBALS"] = sharedDecl;
1741
1742 const auto meshStr = meshTemplate.specialize(replacements);
1743
1744 programCollection.glslSources.add("mesh") << glu::MeshSource(meshStr);
1745 }
1746 }
1747
1748 class CustomAttributesCase : public MeshShaderMiscCase
1749 {
1750 public:
CustomAttributesCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)1751 CustomAttributesCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
1752 : MeshShaderMiscCase(testCtx, name, description, std::move(params)) {}
~CustomAttributesCase(void)1753 virtual ~CustomAttributesCase (void) {}
1754
1755 TestInstance* createInstance (Context& context) const override;
1756 void checkSupport (Context& context) const override;
1757 void initPrograms (vk::SourceCollections& programCollection) const override;
1758 };
1759
1760 class CustomAttributesInstance : public MeshShaderMiscInstance
1761 {
1762 public:
CustomAttributesInstance(Context & context,const MiscTestParams * params)1763 CustomAttributesInstance (Context& context, const MiscTestParams* params)
1764 : MeshShaderMiscInstance(context, params) {}
~CustomAttributesInstance(void)1765 virtual ~CustomAttributesInstance (void) {}
1766
1767 void generateReferenceLevel () override;
1768 tcu::TestStatus iterate (void) override;
1769 };
1770
createInstance(Context & context) const1771 TestInstance* CustomAttributesCase::createInstance (Context& context) const
1772 {
1773 return new CustomAttributesInstance(context, m_params.get());
1774 }
1775
checkSupport(Context & context) const1776 void CustomAttributesCase::checkSupport (Context& context) const
1777 {
1778 MeshShaderMiscCase::checkSupport(context);
1779
1780 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
1781 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_CLIP_DISTANCE);
1782 }
1783
initPrograms(vk::SourceCollections & programCollection) const1784 void CustomAttributesCase::initPrograms (vk::SourceCollections& programCollection) const
1785 {
1786 std::ostringstream frag;
1787 frag
1788 << "#version 450\n"
1789 << "#extension GL_NV_mesh_shader : enable\n"
1790 << "\n"
1791 << "layout (location=0) in vec4 customAttribute1;\n"
1792 << "layout (location=1) in flat float customAttribute2;\n"
1793 << "layout (location=2) in flat int customAttribute3;\n"
1794 << "\n"
1795 << "layout (location=3) in perprimitiveNV flat uvec4 customAttribute4;\n"
1796 << "layout (location=4) in perprimitiveNV float customAttribute5;\n"
1797 << "\n"
1798 << "layout (location=0) out vec4 outColor;\n"
1799 << "\n"
1800 << "void main ()\n"
1801 << "{\n"
1802 << " bool goodPrimitiveID = (gl_PrimitiveID == 1000 || gl_PrimitiveID == 1001);\n"
1803 << " bool goodViewportIndex = (gl_ViewportIndex == 1);\n"
1804 << " bool goodCustom1 = (customAttribute1.x >= 0.25 && customAttribute1.x <= 0.5 &&\n"
1805 << " customAttribute1.y >= 0.5 && customAttribute1.y <= 1.0 &&\n"
1806 << " customAttribute1.z >= 10.0 && customAttribute1.z <= 20.0 &&\n"
1807 << " customAttribute1.w == 3.0);\n"
1808 << " bool goodCustom2 = (customAttribute2 == 1.0 || customAttribute2 == 2.0);\n"
1809 << " bool goodCustom3 = (customAttribute3 == 3 || customAttribute3 == 4);\n"
1810 << " bool goodCustom4 = ((gl_PrimitiveID == 1000 && customAttribute4 == uvec4(100, 101, 102, 103)) ||\n"
1811 << " (gl_PrimitiveID == 1001 && customAttribute4 == uvec4(200, 201, 202, 203)));\n"
1812 << " bool goodCustom5 = ((gl_PrimitiveID == 1000 && customAttribute5 == 6.0) ||\n"
1813 << " (gl_PrimitiveID == 1001 && customAttribute5 == 7.0));\n"
1814 << " \n"
1815 << " if (goodPrimitiveID && goodViewportIndex && goodCustom1 && goodCustom2 && goodCustom3 && goodCustom4 && goodCustom5) {\n"
1816 << " outColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
1817 << " } else {\n"
1818 << " outColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
1819 << " }\n"
1820 << "}\n"
1821 ;
1822 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
1823
1824 std::ostringstream pvdDataDeclStream;
1825 pvdDataDeclStream
1826 << " vec4 positions[4];\n"
1827 << " float pointSizes[4];\n"
1828 << " float clipDistances[4];\n"
1829 << " vec4 custom1[4];\n"
1830 << " float custom2[4];\n"
1831 << " int custom3[4];\n"
1832 ;
1833 const auto pvdDataDecl = pvdDataDeclStream.str();
1834
1835 std::ostringstream ppdDataDeclStream;
1836 ppdDataDeclStream
1837 << " int primitiveIds[2];\n"
1838 << " int viewportIndices[2];\n"
1839 << " uvec4 custom4[2];\n"
1840 << " float custom5[2];\n"
1841 ;
1842 const auto ppdDataDecl = ppdDataDeclStream.str();
1843
1844 std::ostringstream bindingsDeclStream;
1845 bindingsDeclStream
1846 << "layout (set=0, binding=0, std430) buffer PerVertexData {\n"
1847 << pvdDataDecl
1848 << "} pvd;\n"
1849 << "layout (set=0, binding=1) uniform PerPrimitiveData {\n"
1850 << ppdDataDecl
1851 << "} ppd;\n"
1852 << "\n"
1853 ;
1854 const auto bindingsDecl = bindingsDeclStream.str();
1855
1856 std::ostringstream taskDataStream;
1857 taskDataStream
1858 << "taskNV TaskData {\n"
1859 << pvdDataDecl
1860 << ppdDataDecl
1861 << "} td;\n"
1862 << "\n"
1863 ;
1864 const auto taskDataDecl = taskDataStream.str();
1865
1866 const auto taskShader = m_params->needsTaskShader();
1867
1868 const auto meshPvdPrefix = (taskShader ? "td" : "pvd");
1869 const auto meshPpdPrefix = (taskShader ? "td" : "ppd");
1870
1871 std::ostringstream mesh;
1872 mesh
1873 << "#version 450\n"
1874 << "#extension GL_NV_mesh_shader : enable\n"
1875 << "\n"
1876 << "layout (local_size_x=1) in;\n"
1877 << "layout (max_primitives=2, max_vertices=4) out;\n"
1878 << "layout (triangles) out;\n"
1879 << "\n"
1880 << "out gl_MeshPerVertexNV {\n"
1881 << " vec4 gl_Position;\n"
1882 << " float gl_PointSize;\n"
1883 << " float gl_ClipDistance[1];\n"
1884 << "} gl_MeshVerticesNV[];\n"
1885 << "\n"
1886 << "layout (location=0) out vec4 customAttribute1[];\n"
1887 << "layout (location=1) out flat float customAttribute2[];\n"
1888 << "layout (location=2) out int customAttribute3[];\n"
1889 << "\n"
1890 << "layout (location=3) out perprimitiveNV uvec4 customAttribute4[];\n"
1891 << "layout (location=4) out perprimitiveNV float customAttribute5[];\n"
1892 << "\n"
1893 << "out perprimitiveNV gl_MeshPerPrimitiveNV {\n"
1894 << " int gl_PrimitiveID;\n"
1895 << " int gl_ViewportIndex;\n"
1896 << "} gl_MeshPrimitivesNV[];\n"
1897 << "\n"
1898 << (taskShader ? "in " + taskDataDecl : bindingsDecl)
1899 << "void main ()\n"
1900 << "{\n"
1901 << " gl_PrimitiveCountNV = 2u;\n"
1902 << "\n"
1903 << " gl_MeshVerticesNV[0].gl_Position = " << meshPvdPrefix << ".positions[0]; //vec4(-1.0, -1.0, 0.0, 1.0)\n"
1904 << " gl_MeshVerticesNV[1].gl_Position = " << meshPvdPrefix << ".positions[1]; //vec4( 1.0, -1.0, 0.0, 1.0)\n"
1905 << " gl_MeshVerticesNV[2].gl_Position = " << meshPvdPrefix << ".positions[2]; //vec4(-1.0, 1.0, 0.0, 1.0)\n"
1906 << " gl_MeshVerticesNV[3].gl_Position = " << meshPvdPrefix << ".positions[3]; //vec4( 1.0, 1.0, 0.0, 1.0)\n"
1907 << "\n"
1908 << " gl_MeshVerticesNV[0].gl_PointSize = " << meshPvdPrefix << ".pointSizes[0]; //1.0\n"
1909 << " gl_MeshVerticesNV[1].gl_PointSize = " << meshPvdPrefix << ".pointSizes[1]; //1.0\n"
1910 << " gl_MeshVerticesNV[2].gl_PointSize = " << meshPvdPrefix << ".pointSizes[2]; //1.0\n"
1911 << " gl_MeshVerticesNV[3].gl_PointSize = " << meshPvdPrefix << ".pointSizes[3]; //1.0\n"
1912 << "\n"
1913 << " // Remove geometry on the right side.\n"
1914 << " gl_MeshVerticesNV[0].gl_ClipDistance[0] = " << meshPvdPrefix << ".clipDistances[0]; // 1.0\n"
1915 << " gl_MeshVerticesNV[1].gl_ClipDistance[0] = " << meshPvdPrefix << ".clipDistances[1]; //-1.0\n"
1916 << " gl_MeshVerticesNV[2].gl_ClipDistance[0] = " << meshPvdPrefix << ".clipDistances[2]; // 1.0\n"
1917 << " gl_MeshVerticesNV[3].gl_ClipDistance[0] = " << meshPvdPrefix << ".clipDistances[3]; //-1.0\n"
1918 << " \n"
1919 << " gl_PrimitiveIndicesNV[0] = 0;\n"
1920 << " gl_PrimitiveIndicesNV[1] = 2;\n"
1921 << " gl_PrimitiveIndicesNV[2] = 1;\n"
1922 << "\n"
1923 << " gl_PrimitiveIndicesNV[3] = 2;\n"
1924 << " gl_PrimitiveIndicesNV[4] = 3;\n"
1925 << " gl_PrimitiveIndicesNV[5] = 1;\n"
1926 << "\n"
1927 << " gl_MeshPrimitivesNV[0].gl_PrimitiveID = " << meshPpdPrefix << ".primitiveIds[0]; //1000\n"
1928 << " gl_MeshPrimitivesNV[1].gl_PrimitiveID = " << meshPpdPrefix << ".primitiveIds[1]; //1001\n"
1929 << "\n"
1930 << " gl_MeshPrimitivesNV[0].gl_ViewportIndex = " << meshPpdPrefix << ".viewportIndices[0]; //1\n"
1931 << " gl_MeshPrimitivesNV[1].gl_ViewportIndex = " << meshPpdPrefix << ".viewportIndices[1]; //1\n"
1932 << "\n"
1933 << " // Custom per-vertex attributes\n"
1934 << " customAttribute1[0] = " << meshPvdPrefix << ".custom1[0]; //vec4(0.25, 0.5, 10.0, 3.0)\n"
1935 << " customAttribute1[1] = " << meshPvdPrefix << ".custom1[1]; //vec4(0.25, 1.0, 20.0, 3.0)\n"
1936 << " customAttribute1[2] = " << meshPvdPrefix << ".custom1[2]; //vec4( 0.5, 0.5, 20.0, 3.0)\n"
1937 << " customAttribute1[3] = " << meshPvdPrefix << ".custom1[3]; //vec4( 0.5, 1.0, 10.0, 3.0)\n"
1938 << "\n"
1939 << " customAttribute2[0] = " << meshPvdPrefix << ".custom2[0]; //1.0f\n"
1940 << " customAttribute2[1] = " << meshPvdPrefix << ".custom2[1]; //1.0f\n"
1941 << " customAttribute2[2] = " << meshPvdPrefix << ".custom2[2]; //2.0f\n"
1942 << " customAttribute2[3] = " << meshPvdPrefix << ".custom2[3]; //2.0f\n"
1943 << "\n"
1944 << " customAttribute3[0] = " << meshPvdPrefix << ".custom3[0]; //3\n"
1945 << " customAttribute3[1] = " << meshPvdPrefix << ".custom3[1]; //3\n"
1946 << " customAttribute3[2] = " << meshPvdPrefix << ".custom3[2]; //4\n"
1947 << " customAttribute3[3] = " << meshPvdPrefix << ".custom3[3]; //4\n"
1948 << "\n"
1949 << " // Custom per-primitive attributes.\n"
1950 << " customAttribute4[0] = " << meshPpdPrefix << ".custom4[0]; //uvec4(100, 101, 102, 103)\n"
1951 << " customAttribute4[1] = " << meshPpdPrefix << ".custom4[1]; //uvec4(200, 201, 202, 203)\n"
1952 << "\n"
1953 << " customAttribute5[0] = " << meshPpdPrefix << ".custom5[0]; //6.0\n"
1954 << " customAttribute5[1] = " << meshPpdPrefix << ".custom5[1]; //7.0\n"
1955 << "}\n"
1956 ;
1957 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1958
1959 if (taskShader)
1960 {
1961 std::ostringstream task;
1962 task
1963 << "#version 450\n"
1964 << "#extension GL_NV_mesh_shader : enable\n"
1965 << "\n"
1966 << "out " << taskDataDecl
1967 << bindingsDecl
1968 << "void main ()\n"
1969 << "{\n"
1970 << " gl_TaskCountNV = " << m_params->meshCount << ";\n"
1971 << "\n"
1972 << " td.positions[0] = pvd.positions[0];\n"
1973 << " td.positions[1] = pvd.positions[1];\n"
1974 << " td.positions[2] = pvd.positions[2];\n"
1975 << " td.positions[3] = pvd.positions[3];\n"
1976 << "\n"
1977 << " td.pointSizes[0] = pvd.pointSizes[0];\n"
1978 << " td.pointSizes[1] = pvd.pointSizes[1];\n"
1979 << " td.pointSizes[2] = pvd.pointSizes[2];\n"
1980 << " td.pointSizes[3] = pvd.pointSizes[3];\n"
1981 << "\n"
1982 << " td.clipDistances[0] = pvd.clipDistances[0];\n"
1983 << " td.clipDistances[1] = pvd.clipDistances[1];\n"
1984 << " td.clipDistances[2] = pvd.clipDistances[2];\n"
1985 << " td.clipDistances[3] = pvd.clipDistances[3];\n"
1986 << "\n"
1987 << " td.custom1[0] = pvd.custom1[0];\n"
1988 << " td.custom1[1] = pvd.custom1[1];\n"
1989 << " td.custom1[2] = pvd.custom1[2];\n"
1990 << " td.custom1[3] = pvd.custom1[3];\n"
1991 << "\n"
1992 << " td.custom2[0] = pvd.custom2[0];\n"
1993 << " td.custom2[1] = pvd.custom2[1];\n"
1994 << " td.custom2[2] = pvd.custom2[2];\n"
1995 << " td.custom2[3] = pvd.custom2[3];\n"
1996 << "\n"
1997 << " td.custom3[0] = pvd.custom3[0];\n"
1998 << " td.custom3[1] = pvd.custom3[1];\n"
1999 << " td.custom3[2] = pvd.custom3[2];\n"
2000 << " td.custom3[3] = pvd.custom3[3];\n"
2001 << "\n"
2002 << " td.primitiveIds[0] = ppd.primitiveIds[0];\n"
2003 << " td.primitiveIds[1] = ppd.primitiveIds[1];\n"
2004 << "\n"
2005 << " td.viewportIndices[0] = ppd.viewportIndices[0];\n"
2006 << " td.viewportIndices[1] = ppd.viewportIndices[1];\n"
2007 << "\n"
2008 << " td.custom4[0] = ppd.custom4[0];\n"
2009 << " td.custom4[1] = ppd.custom4[1];\n"
2010 << "\n"
2011 << " td.custom5[0] = ppd.custom5[0];\n"
2012 << " td.custom5[1] = ppd.custom5[1];\n"
2013 << "}\n"
2014 ;
2015 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
2016 }
2017 }
2018
generateReferenceLevel()2019 void CustomAttributesInstance::generateReferenceLevel ()
2020 {
2021 const auto format = getOutputFormat();
2022 const auto tcuFormat = mapVkFormat(format);
2023
2024 const auto iWidth = static_cast<int>(m_params->width);
2025 const auto iHeight = static_cast<int>(m_params->height);
2026
2027 const auto halfWidth = iWidth / 2;
2028 const auto halfHeight = iHeight / 2;
2029
2030 m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
2031
2032 const auto access = m_referenceLevel->getAccess();
2033 const auto clearColor = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
2034 const auto blueColor = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
2035
2036 tcu::clear(access, clearColor);
2037
2038 // Fill the top left quarter.
2039 for (int y = 0; y < halfWidth; ++y)
2040 for (int x = 0; x < halfHeight; ++x)
2041 {
2042 access.setPixel(blueColor, x, y);
2043 }
2044 }
2045
iterate()2046 tcu::TestStatus CustomAttributesInstance::iterate ()
2047 {
2048 struct PerVertexData
2049 {
2050 tcu::Vec4 positions[4];
2051 float pointSizes[4];
2052 float clipDistances[4];
2053 tcu::Vec4 custom1[4];
2054 float custom2[4];
2055 int32_t custom3[4];
2056 };
2057
2058 struct PerPrimitiveData
2059 {
2060 // Note some of these are declared as vectors to match the std140 layout.
2061 tcu::IVec4 primitiveIds[2];
2062 tcu::IVec4 viewportIndices[2];
2063 tcu::UVec4 custom4[2];
2064 tcu::Vec4 custom5[2];
2065 };
2066
2067 const auto& vkd = m_context.getDeviceInterface();
2068 const auto device = m_context.getDevice();
2069 auto& alloc = m_context.getDefaultAllocator();
2070 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
2071 const auto queue = m_context.getUniversalQueue();
2072
2073 const auto imageFormat = getOutputFormat();
2074 const auto tcuFormat = mapVkFormat(imageFormat);
2075 const auto imageExtent = makeExtent3D(m_params->width, m_params->height, 1u);
2076 const auto imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2077
2078 const auto& binaries = m_context.getBinaryCollection();
2079 const auto hasTask = binaries.contains("task");
2080 const auto bufStages = (hasTask ? VK_SHADER_STAGE_TASK_BIT_NV : VK_SHADER_STAGE_MESH_BIT_NV);
2081
2082 const VkImageCreateInfo colorBufferInfo =
2083 {
2084 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
2085 nullptr, // const void* pNext;
2086 0u, // VkImageCreateFlags flags;
2087 VK_IMAGE_TYPE_2D, // VkImageType imageType;
2088 imageFormat, // VkFormat format;
2089 imageExtent, // VkExtent3D extent;
2090 1u, // uint32_t mipLevels;
2091 1u, // uint32_t arrayLayers;
2092 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
2093 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
2094 imageUsage, // VkImageUsageFlags usage;
2095 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
2096 0u, // uint32_t queueFamilyIndexCount;
2097 nullptr, // const uint32_t* pQueueFamilyIndices;
2098 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
2099 };
2100
2101 // Create color image and view.
2102 ImageWithMemory colorImage (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
2103 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
2104 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
2105 const auto colorView = makeImageView(vkd, device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
2106
2107 // Create a memory buffer for verification.
2108 const auto verificationBufferSize = static_cast<VkDeviceSize>(imageExtent.width * imageExtent.height * tcu::getPixelSize(tcuFormat));
2109 const auto verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
2110 const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
2111
2112 BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
2113 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
2114 void* verificationBufferData = verificationBufferAlloc.getHostPtr();
2115
2116 // This needs to match what the fragment shader will expect.
2117 const PerVertexData perVertexData =
2118 {
2119 // tcu::Vec4 positions[4];
2120 {
2121 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
2122 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
2123 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
2124 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
2125 },
2126 // float pointSizes[4];
2127 { 1.0f, 1.0f, 1.0f, 1.0f, },
2128 // float clipDistances[4];
2129 {
2130 1.0f,
2131 -1.0f,
2132 1.0f,
2133 -1.0f,
2134 },
2135 // tcu::Vec4 custom1[4];
2136 {
2137 tcu::Vec4(0.25, 0.5, 10.0, 3.0),
2138 tcu::Vec4(0.25, 1.0, 20.0, 3.0),
2139 tcu::Vec4( 0.5, 0.5, 20.0, 3.0),
2140 tcu::Vec4( 0.5, 1.0, 10.0, 3.0),
2141 },
2142 // float custom2[4];
2143 { 1.0f, 1.0f, 2.0f, 2.0f, },
2144 // int32_t custom3[4];
2145 { 3, 3, 4, 4 },
2146 };
2147
2148 // This needs to match what the fragment shader will expect. Reminder: some of these are declared as gvec4 to match the std140
2149 // layout, but only the first component is actually used.
2150 const PerPrimitiveData perPrimitiveData =
2151 {
2152 // int primitiveIds[2];
2153 {
2154 tcu::IVec4(1000, 0, 0, 0),
2155 tcu::IVec4(1001, 0, 0, 0),
2156 },
2157 // int viewportIndices[2];
2158 {
2159 tcu::IVec4(1, 0, 0, 0),
2160 tcu::IVec4(1, 0, 0, 0),
2161 },
2162 // uvec4 custom4[2];
2163 {
2164 tcu::UVec4(100u, 101u, 102u, 103u),
2165 tcu::UVec4(200u, 201u, 202u, 203u),
2166 },
2167 // float custom5[2];
2168 {
2169 tcu::Vec4(6.0f, 0.0f, 0.0f, 0.0f),
2170 tcu::Vec4(7.0f, 0.0f, 0.0f, 0.0f),
2171 },
2172 };
2173
2174 // Create and fill buffers with this data.
2175 const auto pvdSize = static_cast<VkDeviceSize>(sizeof(perVertexData));
2176 const auto pvdInfo = makeBufferCreateInfo(pvdSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
2177 BufferWithMemory pvdData (vkd, device, alloc, pvdInfo, MemoryRequirement::HostVisible);
2178 auto& pvdAlloc = pvdData.getAllocation();
2179 void* pvdPtr = pvdAlloc.getHostPtr();
2180
2181 const auto ppdSize = static_cast<VkDeviceSize>(sizeof(perPrimitiveData));
2182 const auto ppdInfo = makeBufferCreateInfo(ppdSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
2183 BufferWithMemory ppdData (vkd, device, alloc, ppdInfo, MemoryRequirement::HostVisible);
2184 auto& ppdAlloc = ppdData.getAllocation();
2185 void* ppdPtr = ppdAlloc.getHostPtr();
2186
2187 deMemcpy(pvdPtr, &perVertexData, sizeof(perVertexData));
2188 deMemcpy(ppdPtr, &perPrimitiveData, sizeof(perPrimitiveData));
2189
2190 flushAlloc(vkd, device, pvdAlloc);
2191 flushAlloc(vkd, device, ppdAlloc);
2192
2193 // Descriptor set layout.
2194 DescriptorSetLayoutBuilder setLayoutBuilder;
2195 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, bufStages);
2196 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bufStages);
2197 const auto setLayout = setLayoutBuilder.build(vkd, device);
2198
2199 // Create and update descriptor set.
2200 DescriptorPoolBuilder descriptorPoolBuilder;
2201 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
2202 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
2203 const auto descriptorPool = descriptorPoolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
2204 const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
2205
2206 DescriptorSetUpdateBuilder updateBuilder;
2207 const auto storageBufferInfo = makeDescriptorBufferInfo(pvdData.get(), 0ull, pvdSize);
2208 const auto uniformBufferInfo = makeDescriptorBufferInfo(ppdData.get(), 0ull, ppdSize);
2209 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &storageBufferInfo);
2210 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uniformBufferInfo);
2211 updateBuilder.update(vkd, device);
2212
2213 // Pipeline layout.
2214 const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
2215
2216 // Shader modules.
2217 const auto meshShader = createShaderModule(vkd, device, binaries.get("mesh"));
2218 const auto fragShader = createShaderModule(vkd, device, binaries.get("frag"));
2219
2220 Move<VkShaderModule> taskShader;
2221 if (hasTask)
2222 taskShader = createShaderModule(vkd, device, binaries.get("task"));
2223
2224 // Render pass.
2225 const auto renderPass = makeRenderPass(vkd, device, imageFormat);
2226
2227 // Framebuffer.
2228 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), imageExtent.width, imageExtent.height);
2229
2230 // Viewport and scissor.
2231 const auto topHalf = makeViewport(imageExtent.width, imageExtent.height / 2u);
2232 const std::vector<VkViewport> viewports { makeViewport(imageExtent), topHalf };
2233 const std::vector<VkRect2D> scissors (2u, makeRect2D(imageExtent));
2234
2235 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
2236 taskShader.get(), meshShader.get(), fragShader.get(),
2237 renderPass.get(), viewports, scissors);
2238
2239 // Command pool and buffer.
2240 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
2241 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2242 const auto cmdBuffer = cmdBufferPtr.get();
2243
2244 beginCommandBuffer(vkd, cmdBuffer);
2245
2246 // Run pipeline.
2247 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
2248 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
2249 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
2250 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
2251 vkd.cmdDrawMeshTasksNV(cmdBuffer, m_params->drawCount(), 0u);
2252 endRenderPass(vkd, cmdBuffer);
2253
2254 // Copy color buffer to verification buffer.
2255 const auto colorAccess = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
2256 const auto transferRead = VK_ACCESS_TRANSFER_READ_BIT;
2257 const auto transferWrite = VK_ACCESS_TRANSFER_WRITE_BIT;
2258 const auto hostRead = VK_ACCESS_HOST_READ_BIT;
2259
2260 const auto preCopyBarrier = makeImageMemoryBarrier(colorAccess, transferRead, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSRR);
2261 const auto postCopyBarrier = makeMemoryBarrier(transferWrite, hostRead);
2262 const auto copyRegion = makeBufferImageCopy(imageExtent, colorSRL);
2263
2264 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
2265 vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
2266 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
2267
2268 endCommandBuffer(vkd, cmdBuffer);
2269 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
2270
2271 // Generate reference image and compare results.
2272 const tcu::IVec3 iExtent (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), 1);
2273 const tcu::ConstPixelBufferAccess verificationAccess (tcuFormat, iExtent, verificationBufferData);
2274
2275 generateReferenceLevel();
2276 invalidateAlloc(vkd, device, verificationBufferAlloc);
2277 if (!verifyResult(verificationAccess))
2278 TCU_FAIL("Result does not match reference; check log for details");
2279
2280 return tcu::TestStatus::pass("Pass");
2281 }
2282
2283 // Tests that use push constants in the new stages.
2284 class PushConstantCase : public MeshShaderMiscCase
2285 {
2286 public:
PushConstantCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsPtr params)2287 PushConstantCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
2288 : MeshShaderMiscCase (testCtx, name, description, std::move(params))
2289 {}
2290
2291 void initPrograms (vk::SourceCollections& programCollection) const override;
2292 TestInstance* createInstance (Context& context) const override;
2293 };
2294
2295 class PushConstantInstance : public MeshShaderMiscInstance
2296 {
2297 public:
PushConstantInstance(Context & context,const MiscTestParams * params)2298 PushConstantInstance (Context& context, const MiscTestParams* params)
2299 : MeshShaderMiscInstance (context, params)
2300 {}
2301
2302 void generateReferenceLevel () override;
2303 tcu::TestStatus iterate () override;
2304 };
2305
createInstance(Context & context) const2306 TestInstance* PushConstantCase::createInstance (Context& context) const
2307 {
2308 return new PushConstantInstance(context, m_params.get());
2309 }
2310
generateReferenceLevel()2311 void PushConstantInstance::generateReferenceLevel ()
2312 {
2313 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
2314 }
2315
initPrograms(vk::SourceCollections & programCollection) const2316 void PushConstantCase::initPrograms (vk::SourceCollections& programCollection) const
2317 {
2318 const auto useTaskShader = m_params->needsTaskShader();
2319 const auto pcNumFloats = (useTaskShader ? 2u : 4u);
2320
2321 std::ostringstream pushConstantStream;
2322 pushConstantStream
2323 << "layout (push_constant, std430) uniform PushConstantBlock {\n"
2324 << " layout (offset=${PCOFFSET}) float values[" << pcNumFloats << "];\n"
2325 << "} pc;\n"
2326 << "\n"
2327 ;
2328 const tcu::StringTemplate pushConstantsTemplate (pushConstantStream.str());
2329 using TemplateMap = std::map<std::string, std::string>;
2330
2331 std::ostringstream taskDataStream;
2332 taskDataStream
2333 << "taskNV TaskData {\n"
2334 << " float values[2];\n"
2335 << "} td;\n"
2336 << "\n"
2337 ;
2338 const auto taskDataDecl = taskDataStream.str();
2339
2340 if (useTaskShader)
2341 {
2342 TemplateMap taskMap;
2343 taskMap["PCOFFSET"] = std::to_string(2u * sizeof(float));
2344
2345 std::ostringstream task;
2346 task
2347 << "#version 450\n"
2348 << "#extension GL_NV_mesh_shader : enable\n"
2349 << "\n"
2350 << "layout(local_size_x=1) in;\n"
2351 << "\n"
2352 << "out " << taskDataDecl
2353 << pushConstantsTemplate.specialize(taskMap)
2354 << "void main ()\n"
2355 << "{\n"
2356 << " gl_TaskCountNV = " << m_params->meshCount << ";\n"
2357 << "\n"
2358 << " td.values[0] = pc.values[0];\n"
2359 << " td.values[1] = pc.values[1];\n"
2360 << "}\n"
2361 ;
2362 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
2363 }
2364
2365 {
2366 const std::string blue = (useTaskShader ? "td.values[0] + pc.values[0]" : "pc.values[0] + pc.values[2]");
2367 const std::string alpha = (useTaskShader ? "td.values[1] + pc.values[1]" : "pc.values[1] + pc.values[3]");
2368
2369 TemplateMap meshMap;
2370 meshMap["PCOFFSET"] = "0";
2371
2372 std::ostringstream mesh;
2373 mesh
2374 << "#version 450\n"
2375 << "#extension GL_NV_mesh_shader : enable\n"
2376 << "\n"
2377 << "layout(local_size_x=1) in;\n"
2378 << "layout(triangles) out;\n"
2379 << "layout(max_vertices=3, max_primitives=1) out;\n"
2380 << "\n"
2381 << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
2382 << "\n"
2383 << pushConstantsTemplate.specialize(meshMap)
2384 << (useTaskShader ? "in " + taskDataDecl : "")
2385 << "void main ()\n"
2386 << "{\n"
2387 << " gl_PrimitiveCountNV = 1;\n"
2388 << "\n"
2389 << " gl_MeshVerticesNV[0].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
2390 << " gl_MeshVerticesNV[1].gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
2391 << " gl_MeshVerticesNV[2].gl_Position = vec4(-1.0, 3.0, 0.0, 1.0);\n"
2392 << "\n"
2393 << " gl_PrimitiveIndicesNV[0] = 0;\n"
2394 << " gl_PrimitiveIndicesNV[1] = 1;\n"
2395 << " gl_PrimitiveIndicesNV[2] = 2;\n"
2396 << "\n"
2397 << " triangleColor[0] = vec4(0.0, 0.0, " << blue << ", " << alpha << ");\n"
2398 << "}\n"
2399 ;
2400 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
2401 }
2402
2403 // Add default fragment shader.
2404 MeshShaderMiscCase::initPrograms(programCollection);
2405 }
2406
iterate()2407 tcu::TestStatus PushConstantInstance::iterate ()
2408 {
2409 const auto& vkd = m_context.getDeviceInterface();
2410 const auto device = m_context.getDevice();
2411 auto& alloc = m_context.getDefaultAllocator();
2412 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
2413 const auto queue = m_context.getUniversalQueue();
2414
2415 const auto imageFormat = getOutputFormat();
2416 const auto tcuFormat = mapVkFormat(imageFormat);
2417 const auto imageExtent = makeExtent3D(m_params->width, m_params->height, 1u);
2418 const auto imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2419
2420 const auto& binaries = m_context.getBinaryCollection();
2421 const auto hasTask = binaries.contains("task");
2422
2423 const VkImageCreateInfo colorBufferInfo =
2424 {
2425 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
2426 nullptr, // const void* pNext;
2427 0u, // VkImageCreateFlags flags;
2428 VK_IMAGE_TYPE_2D, // VkImageType imageType;
2429 imageFormat, // VkFormat format;
2430 imageExtent, // VkExtent3D extent;
2431 1u, // uint32_t mipLevels;
2432 1u, // uint32_t arrayLayers;
2433 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
2434 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
2435 imageUsage, // VkImageUsageFlags usage;
2436 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
2437 0u, // uint32_t queueFamilyIndexCount;
2438 nullptr, // const uint32_t* pQueueFamilyIndices;
2439 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
2440 };
2441
2442 // Create color image and view.
2443 ImageWithMemory colorImage (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
2444 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
2445 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
2446 const auto colorView = makeImageView(vkd, device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
2447
2448 // Create a memory buffer for verification.
2449 const auto verificationBufferSize = static_cast<VkDeviceSize>(imageExtent.width * imageExtent.height * tcu::getPixelSize(tcuFormat));
2450 const auto verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
2451 const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
2452
2453 BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
2454 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
2455 void* verificationBufferData = verificationBufferAlloc.getHostPtr();
2456
2457 // Push constant ranges.
2458 std::vector<float> pcData { 0.25f, 0.25f, 0.75f, 0.75f };
2459 const auto pcSize = static_cast<uint32_t>(de::dataSize(pcData));
2460 const auto pcHalfSize = pcSize / 2u;
2461
2462 std::vector<VkPushConstantRange> pcRanges;
2463 if (hasTask)
2464 {
2465 pcRanges.push_back(makePushConstantRange(VK_SHADER_STAGE_MESH_BIT_NV, 0u, pcHalfSize));
2466 pcRanges.push_back(makePushConstantRange(VK_SHADER_STAGE_TASK_BIT_NV, pcHalfSize, pcHalfSize));
2467 }
2468 else
2469 {
2470 pcRanges.push_back(makePushConstantRange(VK_SHADER_STAGE_MESH_BIT_NV, 0u, pcSize));
2471 }
2472
2473 // Pipeline layout.
2474 const auto pipelineLayout = makePipelineLayout(vkd, device, 0u, nullptr, static_cast<uint32_t>(pcRanges.size()), de::dataOrNull(pcRanges));
2475
2476 // Shader modules.
2477 const auto meshShader = createShaderModule(vkd, device, binaries.get("mesh"));
2478 const auto fragShader = createShaderModule(vkd, device, binaries.get("frag"));
2479
2480 Move<VkShaderModule> taskShader;
2481 if (hasTask)
2482 taskShader = createShaderModule(vkd, device, binaries.get("task"));
2483
2484 // Render pass.
2485 const auto renderPass = makeRenderPass(vkd, device, imageFormat);
2486
2487 // Framebuffer.
2488 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), imageExtent.width, imageExtent.height);
2489
2490 // Viewport and scissor.
2491 const std::vector<VkViewport> viewports (1u, makeViewport(imageExtent));
2492 const std::vector<VkRect2D> scissors (1u, makeRect2D(imageExtent));
2493
2494 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
2495 taskShader.get(), meshShader.get(), fragShader.get(),
2496 renderPass.get(), viewports, scissors);
2497
2498 // Command pool and buffer.
2499 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
2500 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2501 const auto cmdBuffer = cmdBufferPtr.get();
2502
2503 beginCommandBuffer(vkd, cmdBuffer);
2504
2505 // Run pipeline.
2506 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
2507 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
2508 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
2509 for (const auto& range : pcRanges)
2510 vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), range.stageFlags, range.offset, range.size, reinterpret_cast<const char*>(pcData.data()) + range.offset);
2511 vkd.cmdDrawMeshTasksNV(cmdBuffer, m_params->drawCount(), 0u);
2512 endRenderPass(vkd, cmdBuffer);
2513
2514 // Copy color buffer to verification buffer.
2515 const auto colorAccess = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
2516 const auto transferRead = VK_ACCESS_TRANSFER_READ_BIT;
2517 const auto transferWrite = VK_ACCESS_TRANSFER_WRITE_BIT;
2518 const auto hostRead = VK_ACCESS_HOST_READ_BIT;
2519
2520 const auto preCopyBarrier = makeImageMemoryBarrier(colorAccess, transferRead, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSRR);
2521 const auto postCopyBarrier = makeMemoryBarrier(transferWrite, hostRead);
2522 const auto copyRegion = makeBufferImageCopy(imageExtent, colorSRL);
2523
2524 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
2525 vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
2526 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
2527
2528 endCommandBuffer(vkd, cmdBuffer);
2529 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
2530
2531 // Generate reference image and compare results.
2532 const tcu::IVec3 iExtent (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), 1);
2533 const tcu::ConstPixelBufferAccess verificationAccess (tcuFormat, iExtent, verificationBufferData);
2534
2535 generateReferenceLevel();
2536 invalidateAlloc(vkd, device, verificationBufferAlloc);
2537 if (!verifyResult(verificationAccess))
2538 TCU_FAIL("Result does not match reference; check log for details");
2539
2540 return tcu::TestStatus::pass("Pass");
2541 }
2542
2543 }
2544
createMeshShaderMiscTests(tcu::TestContext & testCtx)2545 tcu::TestCaseGroup* createMeshShaderMiscTests (tcu::TestContext& testCtx)
2546 {
2547 GroupPtr miscTests (new tcu::TestCaseGroup(testCtx, "misc", "Mesh Shader Misc Tests"));
2548
2549 {
2550 ParamsPtr paramsPtr (new MiscTestParams);
2551
2552 paramsPtr->taskCount = tcu::just(2u);
2553 paramsPtr->meshCount = 2u;
2554 paramsPtr->width = 8u;
2555 paramsPtr->height = 8u;
2556
2557 miscTests->addChild(new ComplexTaskDataCase(testCtx, "complex_task_data", "Pass a complex structure from the task to the mesh shader", std::move(paramsPtr)));
2558 }
2559
2560 {
2561 ParamsPtr paramsPtr (new MiscTestParams);
2562
2563 paramsPtr->taskCount = tcu::nothing<uint32_t>();
2564 paramsPtr->meshCount = 1u;
2565 paramsPtr->width = 5u; // Use an odd value so there's a pixel in the exact center.
2566 paramsPtr->height = 7u; // Idem.
2567
2568 miscTests->addChild(new SinglePointCase(testCtx, "single_point", "Draw a single point", std::move(paramsPtr)));
2569 }
2570
2571 {
2572 ParamsPtr paramsPtr (new MiscTestParams);
2573
2574 paramsPtr->taskCount = tcu::nothing<uint32_t>();
2575 paramsPtr->meshCount = 1u;
2576 paramsPtr->width = 8u;
2577 paramsPtr->height = 5u; // Use an odd value so there's a center line.
2578
2579 miscTests->addChild(new SingleLineCase(testCtx, "single_line", "Draw a single line", std::move(paramsPtr)));
2580 }
2581
2582 {
2583 ParamsPtr paramsPtr (new MiscTestParams);
2584
2585 paramsPtr->taskCount = tcu::nothing<uint32_t>();
2586 paramsPtr->meshCount = 1u;
2587 paramsPtr->width = 5u; // Use an odd value so there's a pixel in the exact center.
2588 paramsPtr->height = 7u; // Idem.
2589
2590 miscTests->addChild(new SingleTriangleCase(testCtx, "single_triangle", "Draw a single triangle", std::move(paramsPtr)));
2591 }
2592
2593 {
2594 ParamsPtr paramsPtr (new MiscTestParams);
2595
2596 paramsPtr->taskCount = tcu::nothing<uint32_t>();
2597 paramsPtr->meshCount = 1u;
2598 paramsPtr->width = 16u;
2599 paramsPtr->height = 16u;
2600
2601 miscTests->addChild(new MaxPointsCase(testCtx, "max_points", "Draw the maximum number of points", std::move(paramsPtr)));
2602 }
2603
2604 {
2605 ParamsPtr paramsPtr (new MiscTestParams);
2606
2607 paramsPtr->taskCount = tcu::nothing<uint32_t>();
2608 paramsPtr->meshCount = 1u;
2609 paramsPtr->width = 1u;
2610 paramsPtr->height = 1020u;
2611
2612 miscTests->addChild(new MaxLinesCase(testCtx, "max_lines", "Draw the maximum number of lines", std::move(paramsPtr)));
2613 }
2614
2615 {
2616 ParamsPtr paramsPtr (new MiscTestParams);
2617
2618 paramsPtr->taskCount = tcu::nothing<uint32_t>();
2619 paramsPtr->meshCount = 1u;
2620 paramsPtr->width = 512u;
2621 paramsPtr->height = 512u;
2622
2623 miscTests->addChild(new MaxTrianglesCase(testCtx, "max_triangles", "Draw the maximum number of triangles", std::move(paramsPtr)));
2624 }
2625
2626 {
2627 ParamsPtr paramsPtr (new MiscTestParams);
2628
2629 paramsPtr->taskCount = tcu::just(65535u);
2630 paramsPtr->meshCount = 1u;
2631 paramsPtr->width = 1360u;
2632 paramsPtr->height = 1542u;
2633
2634 miscTests->addChild(new LargeWorkGroupCase(testCtx, "many_task_work_groups", "Generate a large number of task work groups", std::move(paramsPtr)));
2635 }
2636
2637 {
2638 ParamsPtr paramsPtr (new MiscTestParams);
2639
2640 paramsPtr->taskCount = tcu::nothing<uint32_t>();
2641 paramsPtr->meshCount = 65535u;
2642 paramsPtr->width = 1360u;
2643 paramsPtr->height = 1542u;
2644
2645 miscTests->addChild(new LargeWorkGroupCase(testCtx, "many_mesh_work_groups", "Generate a large number of mesh work groups", std::move(paramsPtr)));
2646 }
2647
2648 {
2649 ParamsPtr paramsPtr (new MiscTestParams);
2650
2651 paramsPtr->taskCount = tcu::just(512u);
2652 paramsPtr->meshCount = 512u;
2653 paramsPtr->width = 4096u;
2654 paramsPtr->height = 2048u;
2655
2656 miscTests->addChild(new LargeWorkGroupCase(testCtx, "many_task_mesh_work_groups", "Generate a large number of task and mesh work groups", std::move(paramsPtr)));
2657 }
2658
2659 {
2660 const PrimitiveType types[] = {
2661 PrimitiveType::POINTS,
2662 PrimitiveType::LINES,
2663 PrimitiveType::TRIANGLES,
2664 };
2665
2666 for (int i = 0; i < 2; ++i)
2667 {
2668 const bool extraWrites = (i > 0);
2669
2670 for (const auto primType : types)
2671 {
2672 std::unique_ptr<NoPrimitivesParams> params (new NoPrimitivesParams);
2673 params->taskCount = (extraWrites ? tcu::just(1u) : tcu::nothing<uint32_t>());
2674 params->meshCount = 1u;
2675 params->width = 16u;
2676 params->height = 16u;
2677 params->primitiveType = primType;
2678
2679 ParamsPtr paramsPtr (params.release());
2680 const auto primName = primitiveTypeName(primType);
2681 const std::string name = "no_" + primName + (extraWrites ? "_extra_writes" : "");
2682 const std::string desc = "Run a pipeline that generates no " + primName + (extraWrites ? " but generates primitive data" : "");
2683
2684 miscTests->addChild(extraWrites
2685 ? (new NoPrimitivesExtraWritesCase(testCtx, name, desc, std::move(paramsPtr)))
2686 : (new NoPrimitivesCase(testCtx, name, desc, std::move(paramsPtr))));
2687 }
2688 }
2689 }
2690
2691 {
2692 for (int i = 0; i < 2; ++i)
2693 {
2694 const bool useTaskShader = (i == 0);
2695
2696 ParamsPtr paramsPtr (new MiscTestParams);
2697
2698 paramsPtr->taskCount = (useTaskShader ? tcu::just(1u) : tcu::nothing<uint32_t>());
2699 paramsPtr->meshCount = 1u;
2700 paramsPtr->width = 1u;
2701 paramsPtr->height = 1u;
2702
2703 const std::string shader = (useTaskShader ? "task" : "mesh");
2704 const std::string name = "barrier_in_" + shader;
2705 const std::string desc = "Use a control barrier in the " + shader + " shader";
2706
2707 miscTests->addChild(new SimpleBarrierCase(testCtx, name, desc, std::move(paramsPtr)));
2708 }
2709 }
2710
2711 {
2712 const struct
2713 {
2714 MemoryBarrierType memBarrierType;
2715 std::string caseName;
2716 } barrierTypes[] =
2717 {
2718 { MemoryBarrierType::SHARED, "memory_barrier_shared" },
2719 { MemoryBarrierType::GROUP, "group_memory_barrier" },
2720 };
2721
2722 for (const auto& barrierCase : barrierTypes)
2723 {
2724 for (int i = 0; i < 2; ++i)
2725 {
2726 const bool useTaskShader = (i == 0);
2727
2728 std::unique_ptr<MemoryBarrierParams> paramsPtr (new MemoryBarrierParams);
2729
2730 paramsPtr->taskCount = (useTaskShader ? tcu::just(1u) : tcu::nothing<uint32_t>());
2731 paramsPtr->meshCount = 1u;
2732 paramsPtr->width = 1u;
2733 paramsPtr->height = 1u;
2734 paramsPtr->memBarrierType = barrierCase.memBarrierType;
2735
2736 const std::string shader = (useTaskShader ? "task" : "mesh");
2737 const std::string name = barrierCase.caseName + "_in_" + shader;
2738 const std::string desc = "Use " + paramsPtr->glslFunc() + "() in the " + shader + " shader";
2739
2740 miscTests->addChild(new MemoryBarrierCase(testCtx, name, desc, std::move(paramsPtr)));
2741 }
2742 }
2743 }
2744
2745 {
2746 for (int i = 0; i < 2; ++i)
2747 {
2748 const bool useTaskShader = (i > 0);
2749 const auto name = std::string("custom_attributes") + (useTaskShader ? "_and_task_shader" : "");
2750 const auto desc = std::string("Use several custom vertex and primitive attributes") + (useTaskShader ? " and also a task shader" : "");
2751
2752 ParamsPtr paramsPtr (new MiscTestParams);
2753
2754 paramsPtr->taskCount = (useTaskShader ? tcu::just(1u) : tcu::nothing<uint32_t>());
2755 paramsPtr->meshCount = 1u;
2756 paramsPtr->width = 32u;
2757 paramsPtr->height = 32u;
2758
2759 miscTests->addChild(new CustomAttributesCase(testCtx, name, desc, std::move(paramsPtr)));
2760 }
2761 }
2762
2763 {
2764 for (int i = 0; i < 2; ++i)
2765 {
2766 const bool useTaskShader = (i > 0);
2767 const auto name = std::string("push_constant") + (useTaskShader ? "_and_task_shader" : "");
2768 const auto desc = std::string("Use push constants in the mesh shader stage") + (useTaskShader ? " and also in the task shader stage" : "");
2769
2770 ParamsPtr paramsPtr (new MiscTestParams);
2771
2772 paramsPtr->taskCount = (useTaskShader ? tcu::just(1u) : tcu::nothing<uint32_t>());
2773 paramsPtr->meshCount = 1u;
2774 paramsPtr->width = 16u;
2775 paramsPtr->height = 16u;
2776
2777 miscTests->addChild(new PushConstantCase(testCtx, name, desc, std::move(paramsPtr)));
2778 }
2779 }
2780
2781 return miscTests.release();
2782 }
2783
2784 } // MeshShader
2785 } // vkt
2786