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 for VK_EXT_mesh_shader
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktMeshShaderMiscTests.hpp"
26 #include "vktMeshShaderUtil.hpp"
27 #include "vktTestCase.hpp"
28
29 #include "vkBuilderUtil.hpp"
30 #include "vkImageWithMemory.hpp"
31 #include "vkBufferWithMemory.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkImageUtil.hpp"
36 #include "vkBarrierUtil.hpp"
37
38 #include "tcuDefs.hpp"
39 #include "tcuVectorType.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuTexture.hpp"
42 #include "tcuTextureUtil.hpp"
43 #include "tcuMaybe.hpp"
44 #include "tcuStringTemplate.hpp"
45 #include "tcuTestLog.hpp"
46
47 #include "deRandom.hpp"
48
49 #include <cstdint>
50 #include <memory>
51 #include <utility>
52 #include <vector>
53 #include <string>
54 #include <sstream>
55 #include <map>
56 #include <type_traits>
57 #include <limits>
58
59 namespace vkt
60 {
61 namespace MeshShader
62 {
63
64 namespace
65 {
66
67 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
68
69 using namespace vk;
70
71 // Output images will use this format.
getOutputFormat()72 VkFormat getOutputFormat ()
73 {
74 return VK_FORMAT_R8G8B8A8_UNORM;
75 }
76
77 // Threshold that's reasonable for the previous format.
getCompareThreshold()78 float getCompareThreshold ()
79 {
80 return 0.005f; // 1/256 < 0.005 < 2/256
81 }
82
83 // Check mesh shader support.
genericCheckSupport(Context & context,bool requireTaskShader,bool requireVertexStores)84 void genericCheckSupport (Context& context, bool requireTaskShader, bool requireVertexStores)
85 {
86 checkTaskMeshShaderSupportEXT(context, requireTaskShader, true);
87
88 if (requireVertexStores)
89 {
90 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
91 }
92 }
93
94 struct MiscTestParams
95 {
96 tcu::Maybe<tcu::UVec3> taskCount;
97 tcu::UVec3 meshCount;
98
99 uint32_t width;
100 uint32_t height;
101
MiscTestParamsvkt::MeshShader::__anond8548dd90111::MiscTestParams102 MiscTestParams (const tcu::Maybe<tcu::UVec3>& taskCount_, const tcu::UVec3& meshCount_, uint32_t width_, uint32_t height_)
103 : taskCount (taskCount_)
104 , meshCount (meshCount_)
105 , width (width_)
106 , height (height_)
107 {}
108
109 // Makes the class polymorphic and allows the right destructor to be used for subclasses.
~MiscTestParamsvkt::MeshShader::__anond8548dd90111::MiscTestParams110 virtual ~MiscTestParams () {}
111
needsTaskShadervkt::MeshShader::__anond8548dd90111::MiscTestParams112 bool needsTaskShader () const
113 {
114 return static_cast<bool>(taskCount);
115 }
116
drawCountvkt::MeshShader::__anond8548dd90111::MiscTestParams117 tcu::UVec3 drawCount () const
118 {
119 if (needsTaskShader())
120 return taskCount.get();
121 return meshCount;
122 }
123 };
124
125 using ParamsPtr = std::unique_ptr<MiscTestParams>;
126
127 class MeshShaderMiscCase : public vkt::TestCase
128 {
129 public:
130 MeshShaderMiscCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params);
~MeshShaderMiscCase(void)131 virtual ~MeshShaderMiscCase (void) {}
132
133 void checkSupport (Context& context) const override;
134 void initPrograms (vk::SourceCollections& programCollection) const override;
135
136 protected:
137 std::unique_ptr<MiscTestParams> m_params;
138 };
139
MeshShaderMiscCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)140 MeshShaderMiscCase::MeshShaderMiscCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
141 : vkt::TestCase (testCtx, name)
142 , m_params (params.release())
143 {}
144
checkSupport(Context & context) const145 void MeshShaderMiscCase::checkSupport (Context& context) const
146 {
147 genericCheckSupport(context, m_params->needsTaskShader(), /*requireVertexStores*/false);
148 }
149
150 // Adds the generic fragment shader. To be called by subclasses.
initPrograms(vk::SourceCollections & programCollection) const151 void MeshShaderMiscCase::initPrograms (vk::SourceCollections& programCollection) const
152 {
153 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
154
155 std::string frag =
156 "#version 450\n"
157 "#extension GL_EXT_mesh_shader : enable\n"
158 "\n"
159 "layout (location=0) in perprimitiveEXT vec4 primitiveColor;\n"
160 "layout (location=0) out vec4 outColor;\n"
161 "\n"
162 "void main ()\n"
163 "{\n"
164 " outColor = primitiveColor;\n"
165 "}\n"
166 ;
167 programCollection.glslSources.add("frag") << glu::FragmentSource(frag) << buildOptions;
168 }
169
170 class MeshShaderMiscInstance : public vkt::TestInstance
171 {
172 public:
MeshShaderMiscInstance(Context & context,const MiscTestParams * params)173 MeshShaderMiscInstance (Context& context, const MiscTestParams* params)
174 : vkt::TestInstance (context)
175 , m_params (params)
176 , m_referenceLevel ()
177 {
178 }
179
180 void generateSolidRefLevel (const tcu::Vec4& color, std::unique_ptr<tcu::TextureLevel>& output);
181 virtual void generateReferenceLevel () = 0;
182
183 virtual bool verifyResult (const tcu::ConstPixelBufferAccess& resultAccess, const tcu::TextureLevel& referenceLevel) const;
184 virtual bool verifyResult (const tcu::ConstPixelBufferAccess& resultAccess) const;
185 tcu::TestStatus iterate () override;
186
187 protected:
188 const MiscTestParams* m_params;
189 std::unique_ptr<tcu::TextureLevel> m_referenceLevel;
190 };
191
generateSolidRefLevel(const tcu::Vec4 & color,std::unique_ptr<tcu::TextureLevel> & output)192 void MeshShaderMiscInstance::generateSolidRefLevel (const tcu::Vec4& color, std::unique_ptr<tcu::TextureLevel>& output)
193 {
194 const auto format = getOutputFormat();
195 const auto tcuFormat = mapVkFormat(format);
196
197 const auto iWidth = static_cast<int>(m_params->width);
198 const auto iHeight = static_cast<int>(m_params->height);
199
200 output.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
201
202 const auto access = output->getAccess();
203
204 // Fill with solid color.
205 tcu::clear(access, color);
206 }
207
verifyResult(const tcu::ConstPixelBufferAccess & resultAccess) const208 bool MeshShaderMiscInstance::verifyResult (const tcu::ConstPixelBufferAccess& resultAccess) const
209 {
210 return verifyResult(resultAccess, *m_referenceLevel);
211 }
212
verifyResult(const tcu::ConstPixelBufferAccess & resultAccess,const tcu::TextureLevel & referenceLevel) const213 bool MeshShaderMiscInstance::verifyResult (const tcu::ConstPixelBufferAccess& resultAccess, const tcu::TextureLevel& referenceLevel) const
214 {
215 const auto referenceAccess = referenceLevel.getAccess();
216
217 const auto refWidth = referenceAccess.getWidth();
218 const auto refHeight = referenceAccess.getHeight();
219 const auto refDepth = referenceAccess.getDepth();
220
221 const auto resWidth = resultAccess.getWidth();
222 const auto resHeight = resultAccess.getHeight();
223 const auto resDepth = resultAccess.getDepth();
224
225 DE_ASSERT(resWidth == refWidth || resHeight == refHeight || resDepth == refDepth);
226
227 // For release builds.
228 DE_UNREF(refWidth);
229 DE_UNREF(refHeight);
230 DE_UNREF(refDepth);
231 DE_UNREF(resWidth);
232 DE_UNREF(resHeight);
233 DE_UNREF(resDepth);
234
235 const auto outputFormat = getOutputFormat();
236 const auto expectedFormat = mapVkFormat(outputFormat);
237 const auto resFormat = resultAccess.getFormat();
238 const auto refFormat = referenceAccess.getFormat();
239
240 DE_ASSERT(resFormat == expectedFormat && refFormat == expectedFormat);
241
242 // For release builds
243 DE_UNREF(expectedFormat);
244 DE_UNREF(resFormat);
245 DE_UNREF(refFormat);
246
247 auto& log = m_context.getTestContext().getLog();
248 const auto threshold = getCompareThreshold();
249 const tcu::Vec4 thresholdVec (threshold, threshold, threshold, threshold);
250
251 return tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, thresholdVec, tcu::COMPARE_LOG_ON_ERROR);
252 }
253
iterate()254 tcu::TestStatus MeshShaderMiscInstance::iterate ()
255 {
256 const auto& vkd = m_context.getDeviceInterface();
257 const auto device = m_context.getDevice();
258 auto& alloc = m_context.getDefaultAllocator();
259 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
260 const auto queue = m_context.getUniversalQueue();
261
262 const auto imageFormat = getOutputFormat();
263 const auto tcuFormat = mapVkFormat(imageFormat);
264 const auto imageExtent = makeExtent3D(m_params->width, m_params->height, 1u);
265 const auto imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
266
267 const VkImageCreateInfo colorBufferInfo =
268 {
269 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
270 nullptr, // const void* pNext;
271 0u, // VkImageCreateFlags flags;
272 VK_IMAGE_TYPE_2D, // VkImageType imageType;
273 imageFormat, // VkFormat format;
274 imageExtent, // VkExtent3D extent;
275 1u, // uint32_t mipLevels;
276 1u, // uint32_t arrayLayers;
277 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
278 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
279 imageUsage, // VkImageUsageFlags usage;
280 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
281 0u, // uint32_t queueFamilyIndexCount;
282 nullptr, // const uint32_t* pQueueFamilyIndices;
283 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
284 };
285
286 // Create color image and view.
287 ImageWithMemory colorImage (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
288 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
289 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
290 const auto colorView = makeImageView(vkd, device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
291
292 // Create a memory buffer for verification.
293 const auto verificationBufferSize = static_cast<VkDeviceSize>(imageExtent.width * imageExtent.height * tcu::getPixelSize(tcuFormat));
294 const auto verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
295 const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
296
297 BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
298 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
299 void* verificationBufferData = verificationBufferAlloc.getHostPtr();
300
301 // Pipeline layout.
302 const auto pipelineLayout = makePipelineLayout(vkd, device);
303
304 // Shader modules.
305 const auto& binaries = m_context.getBinaryCollection();
306 const auto hasTask = binaries.contains("task");
307
308 const auto meshShader = createShaderModule(vkd, device, binaries.get("mesh"));
309 const auto fragShader = createShaderModule(vkd, device, binaries.get("frag"));
310
311 Move<VkShaderModule> taskShader;
312 if (hasTask)
313 taskShader = createShaderModule(vkd, device, binaries.get("task"));
314
315 // Render pass.
316 const auto renderPass = makeRenderPass(vkd, device, imageFormat);
317
318 // Framebuffer.
319 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), imageExtent.width, imageExtent.height);
320
321 // Viewport and scissor.
322 const std::vector<VkViewport> viewports (1u, makeViewport(imageExtent));
323 const std::vector<VkRect2D> scissors (1u, makeRect2D(imageExtent));
324
325 // Color blending.
326 const auto colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
327 const VkPipelineColorBlendAttachmentState blendAttState =
328 {
329 VK_TRUE, // VkBool32 blendEnable;
330 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
331 VK_BLEND_FACTOR_ONE, // VkBlendFactor dstColorBlendFactor;
332 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
333 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
334 VK_BLEND_FACTOR_ONE, // VkBlendFactor dstAlphaBlendFactor;
335 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
336 colorWriteMask, // VkColorComponentFlags colorWriteMask;
337 };
338
339 const VkPipelineColorBlendStateCreateInfo colorBlendInfo =
340 {
341 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
342 nullptr, // const void* pNext;
343 0u, // VkPipelineColorBlendStateCreateFlags flags;
344 VK_FALSE, // VkBool32 logicOpEnable;
345 VK_LOGIC_OP_OR, // VkLogicOp logicOp;
346 1u, // uint32_t attachmentCount;
347 &blendAttState, // const VkPipelineColorBlendAttachmentState* pAttachments;
348 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
349 };
350
351 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
352 taskShader.get(), meshShader.get(), fragShader.get(),
353 renderPass.get(), viewports, scissors, 0u/*subpass*/,
354 nullptr, nullptr, nullptr, &colorBlendInfo);
355
356 // Command pool and buffer.
357 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
358 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
359 const auto cmdBuffer = cmdBufferPtr.get();
360
361 beginCommandBuffer(vkd, cmdBuffer);
362
363 // Run pipeline.
364 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
365 const auto drawCount = m_params->drawCount();
366 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
367 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
368 vkd.cmdDrawMeshTasksEXT(cmdBuffer, drawCount.x(), drawCount.y(), drawCount.z());
369 endRenderPass(vkd, cmdBuffer);
370
371 // Copy color buffer to verification buffer.
372 const auto colorAccess = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
373 const auto transferRead = VK_ACCESS_TRANSFER_READ_BIT;
374 const auto transferWrite = VK_ACCESS_TRANSFER_WRITE_BIT;
375 const auto hostRead = VK_ACCESS_HOST_READ_BIT;
376
377 const auto preCopyBarrier = makeImageMemoryBarrier(colorAccess, transferRead, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSRR);
378 const auto postCopyBarrier = makeMemoryBarrier(transferWrite, hostRead);
379 const auto copyRegion = makeBufferImageCopy(imageExtent, colorSRL);
380
381 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
382 vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
383 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
384
385 endCommandBuffer(vkd, cmdBuffer);
386 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
387
388 // Generate reference image and compare results.
389 const tcu::IVec3 iExtent (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), 1);
390 const tcu::ConstPixelBufferAccess verificationAccess (tcuFormat, iExtent, verificationBufferData);
391
392 generateReferenceLevel();
393 invalidateAlloc(vkd, device, verificationBufferAlloc);
394 if (!verifyResult(verificationAccess))
395 TCU_FAIL("Result does not match reference; check log for details");
396
397 return tcu::TestStatus::pass("Pass");
398 }
399
400 // Verify passing more complex data between the task and mesh shaders.
401 class ComplexTaskDataCase : public MeshShaderMiscCase
402 {
403 public:
ComplexTaskDataCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)404 ComplexTaskDataCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
405 : MeshShaderMiscCase (testCtx, name, std::move(params))
406 {}
407
408 void initPrograms (vk::SourceCollections& programCollection) const override;
409 TestInstance* createInstance (Context& context) const override;
410 };
411
412 class ComplexTaskDataInstance : public MeshShaderMiscInstance
413 {
414 public:
ComplexTaskDataInstance(Context & context,const MiscTestParams * params)415 ComplexTaskDataInstance (Context& context, const MiscTestParams* params)
416 : MeshShaderMiscInstance (context, params)
417 {}
418
419 void generateReferenceLevel () override;
420 };
421
generateReferenceLevel()422 void ComplexTaskDataInstance::generateReferenceLevel ()
423 {
424 const auto format = getOutputFormat();
425 const auto tcuFormat = mapVkFormat(format);
426
427 const auto iWidth = static_cast<int>(m_params->width);
428 const auto iHeight = static_cast<int>(m_params->height);
429
430 const auto halfWidth = iWidth / 2;
431 const auto halfHeight = iHeight / 2;
432
433 m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
434
435 const auto access = m_referenceLevel->getAccess();
436
437 // Each image quadrant gets a different color.
438 for (int y = 0; y < iHeight; ++y)
439 for (int x = 0; x < iWidth; ++x)
440 {
441 const float red = ((y < halfHeight) ? 0.0f : 1.0f);
442 const float green = ((x < halfWidth) ? 0.0f : 1.0f);
443 const auto refColor = tcu::Vec4(red, green, 1.0f, 1.0f);
444 access.setPixel(refColor, x, y);
445 }
446 }
447
initPrograms(vk::SourceCollections & programCollection) const448 void ComplexTaskDataCase::initPrograms (vk::SourceCollections& programCollection) const
449 {
450 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
451
452 // Add the generic fragment shader.
453 MeshShaderMiscCase::initPrograms(programCollection);
454
455 const std::string taskDataDecl =
456 "struct RowId {\n"
457 " uint id;\n"
458 "};\n"
459 "\n"
460 "struct WorkGroupData {\n"
461 " float WorkGroupIdPlusOnex1000Iota[10];\n"
462 " RowId rowId;\n"
463 " uvec3 WorkGroupIdPlusOnex2000Iota;\n"
464 " vec2 WorkGroupIdPlusOnex3000Iota;\n"
465 "};\n"
466 "\n"
467 "struct ExternalData {\n"
468 " float OneMillion;\n"
469 " uint TwoMillion;\n"
470 " WorkGroupData workGroupData;\n"
471 "};\n"
472 "\n"
473 "struct TaskData {\n"
474 " uint yes;\n"
475 " ExternalData externalData;\n"
476 "};\n"
477 "taskPayloadSharedEXT TaskData td;\n"
478 ;
479
480 {
481 std::ostringstream task;
482 task
483 << "#version 450\n"
484 << "#extension GL_EXT_mesh_shader : enable\n"
485 << "\n"
486 << "layout (local_size_x=1) in;\n"
487 << "\n"
488 << taskDataDecl
489 << "\n"
490 << "void main ()\n"
491 << "{\n"
492 << " td.yes = 1u;\n"
493 << " td.externalData.OneMillion = 1000000.0;\n"
494 << " td.externalData.TwoMillion = 2000000u;\n"
495 << " for (uint i = 0; i < 10; i++) {\n"
496 << " td.externalData.workGroupData.WorkGroupIdPlusOnex1000Iota[i] = float((gl_WorkGroupID.x + 1u) * 1000 + i);\n"
497 << " }\n"
498 << " {\n"
499 << " uint baseVal = (gl_WorkGroupID.x + 1u) * 2000;\n"
500 << " td.externalData.workGroupData.WorkGroupIdPlusOnex2000Iota = uvec3(baseVal, baseVal + 1, baseVal + 2);\n"
501 << " }\n"
502 << " {\n"
503 << " uint baseVal = (gl_WorkGroupID.x + 1u) * 3000;\n"
504 << " td.externalData.workGroupData.WorkGroupIdPlusOnex3000Iota = vec2(baseVal, baseVal + 1);\n"
505 << " }\n"
506 << " td.externalData.workGroupData.rowId.id = gl_WorkGroupID.x;\n"
507 << " EmitMeshTasksEXT(2u, 1u, 1u);\n"
508 << "}\n"
509 ;
510 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
511 }
512
513 {
514 std::ostringstream mesh;
515 mesh
516 << "#version 450\n"
517 << "#extension GL_EXT_mesh_shader : enable\n"
518 << "\n"
519 << "layout(local_size_x=2) in;\n"
520 << "layout(triangles) out;\n"
521 << "layout(max_vertices=4, max_primitives=2) out;\n"
522 << "\n"
523 << "layout (location=0) out perprimitiveEXT vec4 triangleColor[];\n"
524 << "\n"
525 << taskDataDecl
526 << "\n"
527 << "void main ()\n"
528 << "{\n"
529 << " bool dataOK = true;\n"
530 << " dataOK = (dataOK && (td.yes == 1u));\n"
531 << " dataOK = (dataOK && (td.externalData.OneMillion == 1000000.0 && td.externalData.TwoMillion == 2000000u));\n"
532 << " uint rowId = td.externalData.workGroupData.rowId.id;\n"
533 << " dataOK = (dataOK && (rowId == 0u || rowId == 1u));\n"
534 << "\n"
535 << " {\n"
536 << " uint baseVal = (rowId + 1u) * 1000u;\n"
537 << " for (uint i = 0; i < 10; i++) {\n"
538 << " if (td.externalData.workGroupData.WorkGroupIdPlusOnex1000Iota[i] != float(baseVal + i)) {\n"
539 << " dataOK = false;\n"
540 << " break;\n"
541 << " }\n"
542 << " }\n"
543 << " }\n"
544 << "\n"
545 << " {\n"
546 << " uint baseVal = (rowId + 1u) * 2000;\n"
547 << " uvec3 expected = uvec3(baseVal, baseVal + 1, baseVal + 2);\n"
548 << " if (td.externalData.workGroupData.WorkGroupIdPlusOnex2000Iota != expected) {\n"
549 << " dataOK = false;\n"
550 << " }\n"
551 << " }\n"
552 << "\n"
553 << " {\n"
554 << " uint baseVal = (rowId + 1u) * 3000;\n"
555 << " vec2 expected = vec2(baseVal, baseVal + 1);\n"
556 << " if (td.externalData.workGroupData.WorkGroupIdPlusOnex3000Iota != expected) {\n"
557 << " dataOK = false;\n"
558 << " }\n"
559 << " }\n"
560 << "\n"
561 << " uint columnId = gl_WorkGroupID.x;\n"
562 << "\n"
563 << " uvec2 vertPrim = uvec2(0u, 0u);\n"
564 << " if (dataOK) {\n"
565 << " vertPrim = uvec2(4u, 2u);\n"
566 << " }\n"
567 << " SetMeshOutputsEXT(vertPrim.x, vertPrim.y);\n"
568 << " if (vertPrim.y == 0u) {\n"
569 << " return;\n"
570 << " }\n"
571 << "\n"
572 << " const vec4 outColor = vec4(rowId, columnId, 1.0f, 1.0f);\n"
573 << " triangleColor[0] = outColor;\n"
574 << " triangleColor[1] = outColor;\n"
575 << "\n"
576 << " // Each local invocation will generate two points and one triangle from the quad.\n"
577 << " // The first local invocation will generate the top quad vertices.\n"
578 << " // The second invocation will generate the two bottom vertices.\n"
579 << " vec4 left = vec4(0.0, 0.0, 0.0, 1.0);\n"
580 << " vec4 right = vec4(1.0, 0.0, 0.0, 1.0);\n"
581 << "\n"
582 << " float localInvocationOffsetY = float(gl_LocalInvocationIndex);\n"
583 << " left.y += localInvocationOffsetY;\n"
584 << " right.y += localInvocationOffsetY;\n"
585 << "\n"
586 << " // The code above creates a quad from (0, 0) to (1, 1) but we need to offset it\n"
587 << " // in X and/or Y depending on the row and column, to place it in other quadrants.\n"
588 << " float quadrantOffsetX = float(int(columnId) - 1);\n"
589 << " float quadrantOffsetY = float(int(rowId) - 1);\n"
590 << "\n"
591 << " left.x += quadrantOffsetX;\n"
592 << " right.x += quadrantOffsetX;\n"
593 << "\n"
594 << " left.y += quadrantOffsetY;\n"
595 << " right.y += quadrantOffsetY;\n"
596 << "\n"
597 << " uint baseVertexId = 2*gl_LocalInvocationIndex;\n"
598 << " gl_MeshVerticesEXT[baseVertexId + 0].gl_Position = left;\n"
599 << " gl_MeshVerticesEXT[baseVertexId + 1].gl_Position = right;\n"
600 << "\n"
601 << " // 0,1,2 or 1,2,3 (note: triangles alternate front face this way)\n"
602 << " const uvec3 indices = uvec3(0 + gl_LocalInvocationIndex, 1 + gl_LocalInvocationIndex, 2 + gl_LocalInvocationIndex);\n"
603 << " gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = indices;\n"
604 << "}\n"
605 ;
606 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
607 }
608 }
609
createInstance(Context & context) const610 TestInstance* ComplexTaskDataCase::createInstance (Context& context) const
611 {
612 return new ComplexTaskDataInstance(context, m_params.get());
613 }
614
615 // Verify drawing a single point.
616 class SinglePointCase : public MeshShaderMiscCase
617 {
618 public:
SinglePointCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params,bool writePointSize=true)619 SinglePointCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params, bool writePointSize = true)
620 : MeshShaderMiscCase (testCtx, name, std::move(params))
621 , m_writePointSize(writePointSize)
622 {}
623
624 void checkSupport (Context& context) const override;
625 void initPrograms (vk::SourceCollections& programCollection) const override;
626 TestInstance* createInstance (Context& context) const override;
627
628 protected:
629 const bool m_writePointSize = true;
630 };
631
632 class SinglePointInstance : public MeshShaderMiscInstance
633 {
634 public:
SinglePointInstance(Context & context,const MiscTestParams * params)635 SinglePointInstance (Context& context, const MiscTestParams* params)
636 : MeshShaderMiscInstance (context, params)
637 {}
638
639 void generateReferenceLevel () override;
640 };
641
checkSupport(Context & context) const642 void SinglePointCase::checkSupport (Context& context) const
643 {
644 MeshShaderMiscCase::checkSupport(context);
645
646 if (!m_writePointSize)
647 context.requireDeviceFunctionality("VK_KHR_maintenance5");
648 }
649
createInstance(Context & context) const650 TestInstance* SinglePointCase::createInstance (Context& context) const
651 {
652 return new SinglePointInstance (context, m_params.get());
653 }
654
initPrograms(vk::SourceCollections & programCollection) const655 void SinglePointCase::initPrograms (vk::SourceCollections& programCollection) const
656 {
657 DE_ASSERT(!m_params->needsTaskShader());
658
659 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
660
661 MeshShaderMiscCase::initPrograms(programCollection);
662
663 std::ostringstream mesh;
664 mesh
665 << "#version 450\n"
666 << "#extension GL_EXT_mesh_shader : enable\n"
667 << "\n"
668 << "layout(local_size_x=1) in;\n"
669 << "layout(points) out;\n"
670 << "layout(max_vertices=256, max_primitives=256) out;\n"
671 << "\n"
672 << "layout (location=0) out perprimitiveEXT vec4 pointColor[];\n"
673 << "\n"
674 << "void main ()\n"
675 << "{\n"
676 << " SetMeshOutputsEXT(1u, 1u);\n"
677 << " pointColor[0] = vec4(0.0f, 1.0f, 1.0f, 1.0f);\n"
678 << " gl_MeshVerticesEXT[0].gl_Position = vec4(0.0f, 0.0f, 0.0f, 1.0f);\n";
679 if (m_writePointSize)
680 {
681 mesh
682 << " gl_MeshVerticesEXT[0].gl_PointSize = 1.0f;\n";
683 }
684 mesh
685 << " gl_PrimitivePointIndicesEXT[0] = 0;\n"
686 << "}\n"
687 ;
688 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
689 }
690
generateReferenceLevel()691 void SinglePointInstance::generateReferenceLevel ()
692 {
693 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), m_referenceLevel);
694
695 const auto halfWidth = static_cast<int>(m_params->width / 2u);
696 const auto halfHeight = static_cast<int>(m_params->height / 2u);
697 const auto access = m_referenceLevel->getAccess();
698
699 access.setPixel(tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f), halfWidth, halfHeight);
700 }
701
702 // Verify drawing a single line.
703 class SingleLineCase : public MeshShaderMiscCase
704 {
705 public:
SingleLineCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)706 SingleLineCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
707 : MeshShaderMiscCase (testCtx, name, std::move(params))
708 {}
709
710 void initPrograms (vk::SourceCollections& programCollection) const override;
711 TestInstance* createInstance (Context& context) const override;
712 };
713
714 class SingleLineInstance : public MeshShaderMiscInstance
715 {
716 public:
SingleLineInstance(Context & context,const MiscTestParams * params)717 SingleLineInstance (Context& context, const MiscTestParams* params)
718 : MeshShaderMiscInstance (context, params)
719 {}
720
721 void generateReferenceLevel () override;
722 };
723
createInstance(Context & context) const724 TestInstance* SingleLineCase::createInstance (Context& context) const
725 {
726 return new SingleLineInstance (context, m_params.get());
727 }
728
initPrograms(vk::SourceCollections & programCollection) const729 void SingleLineCase::initPrograms (vk::SourceCollections& programCollection) const
730 {
731 DE_ASSERT(!m_params->needsTaskShader());
732
733 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
734
735 MeshShaderMiscCase::initPrograms(programCollection);
736
737 std::ostringstream mesh;
738 mesh
739 << "#version 450\n"
740 << "#extension GL_EXT_mesh_shader : enable\n"
741 << "\n"
742 << "layout(local_size_x=1) in;\n"
743 << "layout(lines) out;\n"
744 << "layout(max_vertices=256, max_primitives=256) out;\n"
745 << "\n"
746 << "layout (location=0) out perprimitiveEXT vec4 lineColor[];\n"
747 << "\n"
748 << "void main ()\n"
749 << "{\n"
750 << " SetMeshOutputsEXT(2u, 1u);\n"
751 << " lineColor[0] = vec4(0.0f, 1.0f, 1.0f, 1.0f);\n"
752 << " gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0f, 0.0f, 0.0f, 1.0f);\n"
753 << " gl_MeshVerticesEXT[1].gl_Position = vec4( 1.0f, 0.0f, 0.0f, 1.0f);\n"
754 << " gl_PrimitiveLineIndicesEXT[gl_LocalInvocationIndex] = uvec2(0u, 1u);\n"
755 << "}\n"
756 ;
757 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
758 }
759
generateReferenceLevel()760 void SingleLineInstance::generateReferenceLevel ()
761 {
762 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), m_referenceLevel);
763
764 const auto iWidth = static_cast<int>(m_params->width);
765 const auto halfHeight = static_cast<int>(m_params->height / 2u);
766 const auto access = m_referenceLevel->getAccess();
767
768 // Center row.
769 for (int x = 0; x < iWidth; ++x)
770 access.setPixel(tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f), x, halfHeight);
771 }
772
773 // Verify drawing a single triangle.
774 class SingleTriangleCase : public MeshShaderMiscCase
775 {
776 public:
SingleTriangleCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)777 SingleTriangleCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
778 : MeshShaderMiscCase (testCtx, name, std::move(params))
779 {}
780
781 void initPrograms (vk::SourceCollections& programCollection) const override;
782 TestInstance* createInstance (Context& context) const override;
783 };
784
785 class SingleTriangleInstance : public MeshShaderMiscInstance
786 {
787 public:
SingleTriangleInstance(Context & context,const MiscTestParams * params)788 SingleTriangleInstance (Context& context, const MiscTestParams* params)
789 : MeshShaderMiscInstance (context, params)
790 {}
791
792 void generateReferenceLevel () override;
793 };
794
createInstance(Context & context) const795 TestInstance* SingleTriangleCase::createInstance (Context& context) const
796 {
797 return new SingleTriangleInstance (context, m_params.get());
798 }
799
initPrograms(vk::SourceCollections & programCollection) const800 void SingleTriangleCase::initPrograms (vk::SourceCollections& programCollection) const
801 {
802 DE_ASSERT(!m_params->needsTaskShader());
803
804 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
805
806 MeshShaderMiscCase::initPrograms(programCollection);
807
808 const float halfPixelX = 2.0f / static_cast<float>(m_params->width);
809 const float halfPixelY = 2.0f / static_cast<float>(m_params->height);
810
811 std::ostringstream mesh;
812 mesh
813 << "#version 450\n"
814 << "#extension GL_EXT_mesh_shader : enable\n"
815 << "\n"
816 << "layout(local_size_x=1) in;\n"
817 << "layout(triangles) out;\n"
818 << "layout(max_vertices=256, max_primitives=256) out;\n"
819 << "\n"
820 << "layout (location=0) out perprimitiveEXT vec4 triangleColor[];\n"
821 << "\n"
822 << "void main ()\n"
823 << "{\n"
824 << " SetMeshOutputsEXT(3u, 1u);\n"
825 << " triangleColor[0] = vec4(0.0f, 1.0f, 1.0f, 1.0f);\n"
826 << " gl_MeshVerticesEXT[0].gl_Position = vec4(" << halfPixelY << ", " << -halfPixelX << ", 0.0f, 1.0f);\n"
827 << " gl_MeshVerticesEXT[1].gl_Position = vec4(" << halfPixelY << ", " << halfPixelX << ", 0.0f, 1.0f);\n"
828 << " gl_MeshVerticesEXT[2].gl_Position = vec4(" << -halfPixelY << ", 0.0f, 0.0f, 1.0f);\n"
829 << " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0u, 1u, 2u);\n"
830 << "}\n"
831 ;
832 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
833 }
834
generateReferenceLevel()835 void SingleTriangleInstance::generateReferenceLevel ()
836 {
837 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), m_referenceLevel);
838
839 const auto halfWidth = static_cast<int>(m_params->width / 2u);
840 const auto halfHeight = static_cast<int>(m_params->height / 2u);
841 const auto access = m_referenceLevel->getAccess();
842
843 // Single pixel in the center.
844 access.setPixel(tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f), halfWidth, halfHeight);
845 }
846
847 // Verify drawing the maximum number of points.
848 class MaxPointsCase : public MeshShaderMiscCase
849 {
850 public:
MaxPointsCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)851 MaxPointsCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
852 : MeshShaderMiscCase (testCtx, name, std::move(params))
853 {}
854
855 void initPrograms (vk::SourceCollections& programCollection) const override;
856 TestInstance* createInstance (Context& context) const override;
857 };
858
859 class MaxPointsInstance : public MeshShaderMiscInstance
860 {
861 public:
MaxPointsInstance(Context & context,const MiscTestParams * params)862 MaxPointsInstance (Context& context, const MiscTestParams* params)
863 : MeshShaderMiscInstance (context, params)
864 {}
865
866 void generateReferenceLevel () override;
867 };
868
createInstance(Context & context) const869 TestInstance* MaxPointsCase::createInstance (Context& context) const
870 {
871 return new MaxPointsInstance (context, m_params.get());
872 }
873
initPrograms(vk::SourceCollections & programCollection) const874 void MaxPointsCase::initPrograms (vk::SourceCollections& programCollection) const
875 {
876 DE_ASSERT(!m_params->needsTaskShader());
877
878 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
879
880 MeshShaderMiscCase::initPrograms(programCollection);
881
882 // Fill a 16x16 image with 256 points. Each of the 64 local invocations will handle a segment of 4 pixels. 4 segments per row.
883 DE_ASSERT(m_params->width == 16u && m_params->height == 16u);
884
885 std::ostringstream mesh;
886 mesh
887 << "#version 450\n"
888 << "#extension GL_EXT_mesh_shader : enable\n"
889 << "\n"
890 << "layout(local_size_x=8, local_size_y=2, local_size_z=4) in;\n"
891 << "layout(points) out;\n"
892 << "layout(max_vertices=256, max_primitives=256) out;\n"
893 << "\n"
894 << "layout (location=0) out perprimitiveEXT vec4 pointColor[];\n"
895 << "\n"
896 << "void main ()\n"
897 << "{\n"
898 << " SetMeshOutputsEXT(256u, 256u);\n"
899 << " uint firstPixel = 4u * gl_LocalInvocationIndex;\n"
900 << " uint row = firstPixel / 16u;\n"
901 << " uint col = firstPixel % 16u;\n"
902 << " float pixSize = 2.0f / 16.0f;\n"
903 << " float yCoord = pixSize * (float(row) + 0.5f) - 1.0f;\n"
904 << " float baseXCoord = pixSize * (float(col) + 0.5f) - 1.0f;\n"
905 << " for (uint i = 0; i < 4u; i++) {\n"
906 << " float xCoord = baseXCoord + pixSize * float(i);\n"
907 << " uint pixId = firstPixel + i;\n"
908 << " gl_MeshVerticesEXT[pixId].gl_Position = vec4(xCoord, yCoord, 0.0f, 1.0f);\n"
909 << " gl_MeshVerticesEXT[pixId].gl_PointSize = 1.0f;\n"
910 << " gl_PrimitivePointIndicesEXT[pixId] = pixId;\n"
911 << " pointColor[pixId] = vec4(((xCoord + 1.0f) / 2.0f), ((yCoord + 1.0f) / 2.0f), 0.0f, 1.0f);\n"
912 << " }\n"
913 << "}\n"
914 ;
915 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
916 }
917
generateReferenceLevel()918 void MaxPointsInstance::generateReferenceLevel ()
919 {
920 const auto format = getOutputFormat();
921 const auto tcuFormat = mapVkFormat(format);
922
923 const auto iWidth = static_cast<int>(m_params->width);
924 const auto iHeight = static_cast<int>(m_params->height);
925 const auto fWidth = static_cast<float>(m_params->width);
926 const auto fHeight = static_cast<float>(m_params->height);
927
928 m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
929
930 const auto access = m_referenceLevel->getAccess();
931
932 // Fill with gradient like the shader does.
933 for (int y = 0; y < iHeight; ++y)
934 for (int x = 0; x < iWidth; ++x)
935 {
936 const tcu::Vec4 color (
937 ((static_cast<float>(x) + 0.5f) / fWidth),
938 ((static_cast<float>(y) + 0.5f) / fHeight),
939 0.0f, 1.0f);
940 access.setPixel(color, x, y);
941 }
942 }
943
944 // Verify drawing the maximum number of lines.
945 class MaxLinesCase : public MeshShaderMiscCase
946 {
947 public:
MaxLinesCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)948 MaxLinesCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
949 : MeshShaderMiscCase (testCtx, name, std::move(params))
950 {}
951
952 void initPrograms (vk::SourceCollections& programCollection) const override;
953 TestInstance* createInstance (Context& context) const override;
954 };
955
956 class MaxLinesInstance : public MeshShaderMiscInstance
957 {
958 public:
MaxLinesInstance(Context & context,const MiscTestParams * params)959 MaxLinesInstance (Context& context, const MiscTestParams* params)
960 : MeshShaderMiscInstance (context, params)
961 {}
962
963 void generateReferenceLevel () override;
964 };
965
createInstance(Context & context) const966 TestInstance* MaxLinesCase::createInstance (Context& context) const
967 {
968 return new MaxLinesInstance (context, m_params.get());
969 }
970
initPrograms(vk::SourceCollections & programCollection) const971 void MaxLinesCase::initPrograms (vk::SourceCollections& programCollection) const
972 {
973 DE_ASSERT(!m_params->needsTaskShader());
974
975 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
976
977 MeshShaderMiscCase::initPrograms(programCollection);
978
979 // Fill a 1x1020 image with 255 lines, each line being 4 pixels tall. Each invocation will generate ~4 lines.
980 DE_ASSERT(m_params->width == 1u && m_params->height == 1020u);
981
982 std::ostringstream mesh;
983 mesh
984 << "#version 450\n"
985 << "#extension GL_EXT_mesh_shader : enable\n"
986 << "\n"
987 << "layout(local_size_x=4, local_size_y=2, local_size_z=8) in;\n"
988 << "layout(lines) out;\n"
989 << "layout(max_vertices=256, max_primitives=255) out;\n"
990 << "\n"
991 << "layout (location=0) out perprimitiveEXT vec4 lineColor[];\n"
992 << "\n"
993 << "void main ()\n"
994 << "{\n"
995 << " SetMeshOutputsEXT(256u, 255u);\n"
996 << " uint firstLine = 4u * gl_LocalInvocationIndex;\n"
997 << " for (uint i = 0u; i < 4u; i++) {\n"
998 << " uint lineId = firstLine + i;\n"
999 << " uint topPixel = 4u * lineId;\n"
1000 << " uint bottomPixel = 3u + topPixel;\n"
1001 << " if (bottomPixel < 1020u) {\n"
1002 << " float bottomCoord = ((float(bottomPixel) + 1.0f) / 1020.0) * 2.0 - 1.0;\n"
1003 << " gl_MeshVerticesEXT[lineId + 1u].gl_Position = vec4(0.0, bottomCoord, 0.0f, 1.0f);\n"
1004 << " gl_PrimitiveLineIndicesEXT[lineId] = uvec2(lineId, lineId + 1u);\n"
1005 << " lineColor[lineId] = vec4(0.0f, 1.0f, float(lineId) / 255.0f, 1.0f);\n"
1006 << " } else {\n"
1007 << " // The last iteration of the last invocation emits the first point\n"
1008 << " gl_MeshVerticesEXT[0].gl_Position = vec4(0.0, -1.0, 0.0f, 1.0f);\n"
1009 << " }\n"
1010 << " }\n"
1011 << "}\n"
1012 ;
1013 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
1014 }
1015
generateReferenceLevel()1016 void MaxLinesInstance::generateReferenceLevel ()
1017 {
1018 const auto format = getOutputFormat();
1019 const auto tcuFormat = mapVkFormat(format);
1020
1021 const auto iWidth = static_cast<int>(m_params->width);
1022 const auto iHeight = static_cast<int>(m_params->height);
1023
1024 m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
1025
1026 const auto access = m_referenceLevel->getAccess();
1027
1028 // Fill lines, 4 pixels per line.
1029 const uint32_t kNumLines = 255u;
1030 const uint32_t kLineHeight = 4u;
1031
1032 for (uint32_t i = 0u; i < kNumLines; ++i)
1033 {
1034 const tcu::Vec4 color (0.0f, 1.0f, static_cast<float>(i) / static_cast<float>(kNumLines), 1.0f);
1035 for (uint32_t j = 0u; j < kLineHeight; ++j)
1036 access.setPixel(color, 0, i*kLineHeight + j);
1037 }
1038 }
1039
1040 // Verify drawing the maximum number of triangles.
1041 class MaxTrianglesCase : public MeshShaderMiscCase
1042 {
1043 public:
1044 struct Params : public MiscTestParams
1045 {
1046 tcu::UVec3 localSize;
1047
Paramsvkt::MeshShader::__anond8548dd90111::MaxTrianglesCase::Params1048 Params (const tcu::UVec3& meshCount_, uint32_t width_, uint32_t height_, const tcu::UVec3& localSize_)
1049 : MiscTestParams (tcu::Nothing, meshCount_, width_, height_)
1050 , localSize (localSize_)
1051 {}
1052 };
1053
MaxTrianglesCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)1054 MaxTrianglesCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
1055 : MeshShaderMiscCase (testCtx, name, std::move(params))
1056 {}
1057
1058 void initPrograms (vk::SourceCollections& programCollection) const override;
1059 TestInstance* createInstance (Context& context) const override;
1060
1061 static constexpr uint32_t kNumVertices = 256u;
1062 static constexpr uint32_t kNumTriangles = 254u;
1063 };
1064
1065 class MaxTrianglesInstance : public MeshShaderMiscInstance
1066 {
1067 public:
MaxTrianglesInstance(Context & context,const MiscTestParams * params)1068 MaxTrianglesInstance (Context& context, const MiscTestParams* params)
1069 : MeshShaderMiscInstance (context, params)
1070 {}
1071
1072 void generateReferenceLevel () override;
1073 };
1074
createInstance(Context & context) const1075 TestInstance* MaxTrianglesCase::createInstance (Context& context) const
1076 {
1077 return new MaxTrianglesInstance (context, m_params.get());
1078 }
1079
initPrograms(vk::SourceCollections & programCollection) const1080 void MaxTrianglesCase::initPrograms (vk::SourceCollections& programCollection) const
1081 {
1082 // Default frag shader.
1083 MeshShaderMiscCase::initPrograms(programCollection);
1084
1085 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
1086 const auto params = dynamic_cast<const MaxTrianglesCase::Params*>(m_params.get());
1087
1088 DE_ASSERT(params);
1089 DE_ASSERT(!params->needsTaskShader());
1090
1091 const auto& localSize = params->localSize;
1092 const auto workGroupSize = (localSize.x() * localSize.y() * localSize.z());
1093
1094 DE_ASSERT(kNumVertices % workGroupSize == 0u);
1095 const auto trianglesPerInvocation = kNumVertices / workGroupSize;
1096
1097 // Fill a sufficiently large image with solid color. Generate a quarter of a circle with the center in the top left corner,
1098 // using a triangle fan that advances from top to bottom. Each invocation will generate ~trianglesPerInvocation triangles.
1099 std::ostringstream mesh;
1100 mesh
1101 << "#version 450\n"
1102 << "#extension GL_EXT_mesh_shader : enable\n"
1103 << "\n"
1104 << "layout(local_size_x=" << localSize.x() << ", local_size_y=" << localSize.y() << ", local_size_z=" << localSize.z() << ") in;\n"
1105 << "layout(triangles) out;\n"
1106 << "layout(max_vertices=" << kNumVertices << ", max_primitives=" << kNumTriangles << ") out;\n"
1107 << "\n"
1108 << "layout (location=0) out perprimitiveEXT vec4 triangleColor[];\n"
1109 << "\n"
1110 << "const float PI_2 = 1.57079632679489661923;\n"
1111 << "const float RADIUS = 4.5;\n"
1112 << "\n"
1113 << "void main ()\n"
1114 << "{\n"
1115 << " const uint trianglesPerInvocation = " << trianglesPerInvocation << "u;\n"
1116 << " const uint numVertices = " << kNumVertices << "u;\n"
1117 << " const uint numTriangles = " << kNumTriangles << "u;\n"
1118 << " const float fNumTriangles = float(numTriangles);\n"
1119 << " SetMeshOutputsEXT(numVertices, numTriangles);\n"
1120 << " uint firstTriangle = trianglesPerInvocation * gl_LocalInvocationIndex;\n"
1121 << " for (uint i = 0u; i < trianglesPerInvocation; i++) {\n"
1122 << " uint triangleId = firstTriangle + i;\n"
1123 << " if (triangleId < numTriangles) {\n"
1124 << " uint vertexId = triangleId + 2u;\n"
1125 << " float angleProportion = float(vertexId - 1u) / fNumTriangles;\n"
1126 << " float angle = PI_2 * angleProportion;\n"
1127 << " float xCoord = cos(angle) * RADIUS - 1.0;\n"
1128 << " float yCoord = sin(angle) * RADIUS - 1.0;\n"
1129 << " gl_MeshVerticesEXT[vertexId].gl_Position = vec4(xCoord, yCoord, 0.0, 1.0);\n"
1130 << " gl_PrimitiveTriangleIndicesEXT[triangleId] = uvec3(0u, triangleId + 1u, triangleId + 2u);\n"
1131 << " triangleColor[triangleId] = vec4(0.0f, 0.0f, 1.0f, 1.0f);\n"
1132 << " } else {\n"
1133 << " // The last iterations of the last invocation emit the first two vertices\n"
1134 << " uint vertexId = triangleId - numTriangles;\n"
1135 << " if (vertexId == 0u) {\n"
1136 << " gl_MeshVerticesEXT[0u].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
1137 << " } else {\n"
1138 << " gl_MeshVerticesEXT[1u].gl_Position = vec4(RADIUS, -1.0, 0.0, 1.0);\n"
1139 << " }\n"
1140 << " }\n"
1141 << " }\n"
1142 << "}\n"
1143 ;
1144 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
1145 }
1146
generateReferenceLevel()1147 void MaxTrianglesInstance::generateReferenceLevel ()
1148 {
1149 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
1150 }
1151
1152 struct LargeWorkGroupParams : public MiscTestParams
1153 {
LargeWorkGroupParamsvkt::MeshShader::__anond8548dd90111::LargeWorkGroupParams1154 LargeWorkGroupParams (const tcu::Maybe<tcu::UVec3>& taskCount_, const tcu::UVec3& meshCount_, uint32_t width_, uint32_t height_, const tcu::UVec3& localInvocations_)
1155 : MiscTestParams (taskCount_, meshCount_, width_, height_)
1156 , localInvocations (localInvocations_)
1157 {}
1158
1159 tcu::UVec3 localInvocations;
1160 };
1161
1162 // Large work groups with many threads.
1163 class LargeWorkGroupCase : public MeshShaderMiscCase
1164 {
1165 public:
LargeWorkGroupCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)1166 LargeWorkGroupCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
1167 : MeshShaderMiscCase (testCtx, name, std::move(params))
1168 {}
1169
1170 void initPrograms (vk::SourceCollections& programCollection) const override;
1171 TestInstance* createInstance (Context& context) const override;
1172 };
1173
1174 class LargeWorkGroupInstance : public MeshShaderMiscInstance
1175 {
1176 public:
LargeWorkGroupInstance(Context & context,const MiscTestParams * params)1177 LargeWorkGroupInstance (Context& context, const MiscTestParams* params)
1178 : MeshShaderMiscInstance (context, params)
1179 {}
1180
1181 void generateReferenceLevel () override;
1182 };
1183
createInstance(Context & context) const1184 TestInstance* LargeWorkGroupCase::createInstance (Context& context) const
1185 {
1186 return new LargeWorkGroupInstance(context, m_params.get());
1187 }
1188
generateReferenceLevel()1189 void LargeWorkGroupInstance::generateReferenceLevel ()
1190 {
1191 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
1192 }
1193
1194 // 'x', 'y' or 'z' depending on if dim is 0, 1 or 2, respectively.
dimSuffix(int dim)1195 char dimSuffix (int dim)
1196 {
1197 const std::string suffixes = "xyz";
1198 DE_ASSERT(dim >= 0 && dim < static_cast<int>(suffixes.size()));
1199 return suffixes[dim];
1200 }
1201
initPrograms(vk::SourceCollections & programCollection) const1202 void LargeWorkGroupCase::initPrograms (vk::SourceCollections& programCollection) const
1203 {
1204 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
1205 const auto params = dynamic_cast<LargeWorkGroupParams*>(m_params.get());
1206 DE_ASSERT(params);
1207
1208 const auto totalInvocations = params->localInvocations.x() * params->localInvocations.y() * params->localInvocations.z();
1209 const auto useTaskShader = params->needsTaskShader();
1210 uint32_t taskMultiplier = 1u;
1211 const auto& meshCount = params->meshCount;
1212 const auto meshMultiplier = meshCount.x() * meshCount.y() * meshCount.z();
1213
1214 if (useTaskShader)
1215 {
1216 const auto dim = params->taskCount.get();
1217 taskMultiplier = dim.x() * dim.y() * dim.z();
1218 }
1219
1220 // Add the frag shader.
1221 MeshShaderMiscCase::initPrograms(programCollection);
1222
1223 std::ostringstream taskData;
1224 taskData
1225 << "struct TaskData {\n"
1226 << " uint parentTask[" << totalInvocations << "];\n"
1227 << "};\n"
1228 << "taskPayloadSharedEXT TaskData td;\n"
1229 ;
1230 const auto taskDataStr = taskData.str();
1231
1232 const std::string localSizeStr = "layout ("
1233 "local_size_x=" + std::to_string(params->localInvocations.x()) + ", "
1234 "local_size_y=" + std::to_string(params->localInvocations.y()) + ", "
1235 "local_size_z=" + std::to_string(params->localInvocations.z())
1236 + ") in;\n"
1237 ;
1238
1239 if (useTaskShader)
1240 {
1241 std::ostringstream task;
1242 task
1243 << "#version 450\n"
1244 << "#extension GL_EXT_mesh_shader : enable\n"
1245 << "\n"
1246 << localSizeStr
1247 << "\n"
1248 << taskDataStr
1249 << "\n"
1250 << "void main () {\n"
1251 << " const uint workGroupIndex = gl_NumWorkGroups.x * gl_NumWorkGroups.y * gl_WorkGroupID.z + gl_NumWorkGroups.x * gl_WorkGroupID.y + gl_WorkGroupID.x;\n"
1252 << " td.parentTask[gl_LocalInvocationIndex] = workGroupIndex;\n"
1253 << " EmitMeshTasksEXT(" << meshCount.x() << ", " << meshCount.y() << ", " << meshCount.z() << ");\n"
1254 << "}\n"
1255 ;
1256 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
1257 }
1258
1259 // Needed for the code below to work.
1260 DE_ASSERT(params->width * params->height == taskMultiplier * meshMultiplier * totalInvocations);
1261 DE_UNREF(taskMultiplier); // For release builds.
1262
1263 // Emit one point per framebuffer pixel. The number of jobs (params->localInvocations in each mesh shader work group, multiplied
1264 // by the number of mesh work groups emitted by each task work group) must be the same as the total framebuffer size. Calculate
1265 // a job ID corresponding to the current mesh shader invocation, and assign a pixel position to it. Draw a point at that
1266 // position.
1267 std::ostringstream mesh;
1268 mesh
1269 << "#version 450\n"
1270 << "#extension GL_EXT_mesh_shader : enable\n"
1271 << "\n"
1272 << localSizeStr
1273 << "layout (points) out;\n"
1274 << "layout (max_vertices=" << totalInvocations << ", max_primitives=" << totalInvocations << ") out;\n"
1275 << "\n"
1276 << (useTaskShader ? taskDataStr : "")
1277 << "\n"
1278 << "layout (location=0) out perprimitiveEXT vec4 pointColor[];\n"
1279 << "\n"
1280 << "void main () {\n"
1281 << " uint parentTask = " << (useTaskShader ? "td.parentTask[0]" : "0") << ";\n";
1282 ;
1283
1284 if (useTaskShader)
1285 {
1286 mesh
1287 << " if (td.parentTask[gl_LocalInvocationIndex] != parentTask || parentTask >= " << taskMultiplier << ") {\n"
1288 << " return;\n"
1289 << " }\n"
1290 ;
1291 }
1292
1293 mesh
1294 << " SetMeshOutputsEXT(" << totalInvocations << ", " << totalInvocations << ");\n"
1295 << " const uint workGroupIndex = gl_NumWorkGroups.x * gl_NumWorkGroups.y * gl_WorkGroupID.z + gl_NumWorkGroups.x * gl_WorkGroupID.y + gl_WorkGroupID.x;\n"
1296 << " uint jobId = ((parentTask * " << meshMultiplier << ") + workGroupIndex) * " << totalInvocations << " + gl_LocalInvocationIndex;\n"
1297 << " uint row = jobId / " << params->width << ";\n"
1298 << " uint col = jobId % " << params->width << ";\n"
1299 << " float yCoord = (float(row + 0.5) / " << params->height << ".0) * 2.0 - 1.0;\n"
1300 << " float xCoord = (float(col + 0.5) / " << params->width << ".0) * 2.0 - 1.0;\n"
1301 << " gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = vec4(xCoord, yCoord, 0.0, 1.0);\n"
1302 << " gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_PointSize = 1.0;\n"
1303 << " gl_PrimitivePointIndicesEXT[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;\n"
1304 << " vec4 resultColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
1305 ;
1306
1307 mesh
1308 << " pointColor[gl_LocalInvocationIndex] = resultColor;\n"
1309 << "}\n"
1310 ;
1311 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
1312 }
1313
1314 // Tests that generate no primitives of a given type.
1315 enum class PrimitiveType { POINTS=0, LINES, TRIANGLES };
1316
primitiveTypeName(PrimitiveType primitiveType)1317 std::string primitiveTypeName (PrimitiveType primitiveType)
1318 {
1319 std::string primitiveName;
1320
1321 switch (primitiveType)
1322 {
1323 case PrimitiveType::POINTS: primitiveName = "points"; break;
1324 case PrimitiveType::LINES: primitiveName = "lines"; break;
1325 case PrimitiveType::TRIANGLES: primitiveName = "triangles"; break;
1326 default: DE_ASSERT(false); break;
1327 }
1328
1329 return primitiveName;
1330 }
1331
1332 struct NoPrimitivesParams : public MiscTestParams
1333 {
NoPrimitivesParamsvkt::MeshShader::__anond8548dd90111::NoPrimitivesParams1334 NoPrimitivesParams (const tcu::Maybe<tcu::UVec3>& taskCount_, const tcu::UVec3& meshCount_, uint32_t width_, uint32_t height_, PrimitiveType primitiveType_)
1335 : MiscTestParams (taskCount_, meshCount_, width_, height_)
1336 , primitiveType (primitiveType_)
1337 {}
1338
1339 PrimitiveType primitiveType;
1340 };
1341
1342 class NoPrimitivesCase : public MeshShaderMiscCase
1343 {
1344 public:
NoPrimitivesCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)1345 NoPrimitivesCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
1346 : MeshShaderMiscCase (testCtx, name, std::move(params))
1347 {}
1348
1349 void initPrograms (vk::SourceCollections& programCollection) const override;
1350 TestInstance* createInstance (Context& context) const override;
1351 };
1352
1353 class NoPrimitivesInstance : public MeshShaderMiscInstance
1354 {
1355 public:
NoPrimitivesInstance(Context & context,const MiscTestParams * params)1356 NoPrimitivesInstance (Context& context, const MiscTestParams* params)
1357 : MeshShaderMiscInstance (context, params)
1358 {}
1359
1360 void generateReferenceLevel () override;
1361 };
1362
generateReferenceLevel()1363 void NoPrimitivesInstance::generateReferenceLevel ()
1364 {
1365 // No primitives: clear color.
1366 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), m_referenceLevel);
1367 }
1368
createInstance(Context & context) const1369 TestInstance* NoPrimitivesCase::createInstance (Context& context) const
1370 {
1371 return new NoPrimitivesInstance(context, m_params.get());
1372 }
1373
initPrograms(vk::SourceCollections & programCollection) const1374 void NoPrimitivesCase::initPrograms (vk::SourceCollections& programCollection) const
1375 {
1376 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
1377 const auto params = dynamic_cast<NoPrimitivesParams*>(m_params.get());
1378
1379 DE_ASSERT(params);
1380 DE_ASSERT(!params->needsTaskShader());
1381
1382 const auto primitiveName = primitiveTypeName(params->primitiveType);
1383
1384 std::ostringstream mesh;
1385 mesh
1386 << "#version 450\n"
1387 << "#extension GL_EXT_mesh_shader : enable\n"
1388 << "\n"
1389 << "layout (local_size_x=128) in;\n"
1390 << "layout (" << primitiveName << ") out;\n"
1391 << "layout (max_vertices=256, max_primitives=256) out;\n"
1392 << "\n"
1393 << "layout (location=0) out perprimitiveEXT vec4 primitiveColor[];\n"
1394 << "\n"
1395 << "void main () {\n"
1396 << " SetMeshOutputsEXT(0u, 0u);\n"
1397 << "}\n"
1398 ;
1399
1400 MeshShaderMiscCase::initPrograms(programCollection);
1401 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
1402 }
1403
1404 class NoPrimitivesExtraWritesCase : public NoPrimitivesCase
1405 {
1406 public:
NoPrimitivesExtraWritesCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)1407 NoPrimitivesExtraWritesCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
1408 : NoPrimitivesCase (testCtx, name, std::move(params))
1409 {}
1410
1411 void initPrograms (vk::SourceCollections& programCollection) const override;
1412
1413 static constexpr uint32_t kLocalInvocations = 128u;
1414 };
1415
initPrograms(vk::SourceCollections & programCollection) const1416 void NoPrimitivesExtraWritesCase::initPrograms (vk::SourceCollections& programCollection) const
1417 {
1418 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
1419 const auto params = dynamic_cast<NoPrimitivesParams*>(m_params.get());
1420
1421 DE_ASSERT(params);
1422 DE_ASSERT(m_params->needsTaskShader());
1423
1424 std::ostringstream taskData;
1425 taskData
1426 << "struct TaskData {\n"
1427 << " uint localInvocations[" << kLocalInvocations << "];\n"
1428 << "};\n"
1429 << "taskPayloadSharedEXT TaskData td;\n"
1430 ;
1431 const auto taskDataStr = taskData.str();
1432
1433 std::ostringstream task;
1434 task
1435 << "#version 450\n"
1436 << "#extension GL_EXT_mesh_shader : enable\n"
1437 << "\n"
1438 << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
1439 << "\n"
1440 << taskDataStr
1441 << "\n"
1442 << "void main () {\n"
1443 << " td.localInvocations[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;\n"
1444 << " EmitMeshTasksEXT(" << params->meshCount.x() << ", " << params->meshCount.y() << ", " << params->meshCount.z() << ");\n"
1445 << "}\n"
1446 ;
1447 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
1448
1449 const auto primitiveName = primitiveTypeName(params->primitiveType);
1450
1451 // Otherwise the shader would be illegal.
1452 DE_ASSERT(kLocalInvocations > 2u);
1453
1454 uint32_t maxPrimitives = 0u;
1455 switch (params->primitiveType)
1456 {
1457 case PrimitiveType::POINTS: maxPrimitives = kLocalInvocations - 0u; break;
1458 case PrimitiveType::LINES: maxPrimitives = kLocalInvocations - 1u; break;
1459 case PrimitiveType::TRIANGLES: maxPrimitives = kLocalInvocations - 2u; break;
1460 default: DE_ASSERT(false); break;
1461 }
1462
1463 const std::string pointSizeDecl = ((params->primitiveType == PrimitiveType::POINTS)
1464 ? " gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_PointSize = 1.0;\n"
1465 : "");
1466
1467 std::ostringstream mesh;
1468 mesh
1469 << "#version 450\n"
1470 << "#extension GL_EXT_mesh_shader : enable\n"
1471 << "\n"
1472 << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
1473 << "layout (" << primitiveName << ") out;\n"
1474 << "layout (max_vertices=" << kLocalInvocations << ", max_primitives=" << maxPrimitives << ") out;\n"
1475 << "\n"
1476 << taskDataStr
1477 << "\n"
1478 << "layout (location=0) out perprimitiveEXT vec4 primitiveColor[];\n"
1479 << "\n"
1480 << "shared uint sumOfIds;\n"
1481 << "\n"
1482 << "const float PI_2 = 1.57079632679489661923;\n"
1483 << "const float RADIUS = 1.0f;\n"
1484 << "\n"
1485 << "void main ()\n"
1486 << "{\n"
1487 << " sumOfIds = 0u;\n"
1488 << " memoryBarrierShared();\n"
1489 << " barrier();\n"
1490 << " atomicAdd(sumOfIds, td.localInvocations[gl_LocalInvocationIndex]);\n"
1491 << " memoryBarrierShared();\n"
1492 << " barrier();\n"
1493 << " // This should dynamically give 0\n"
1494 << " uint primitiveCount = sumOfIds - (" << kLocalInvocations * (kLocalInvocations - 1u) / 2u << ");\n"
1495 << " SetMeshOutputsEXT(primitiveCount, primitiveCount);\n"
1496 << "\n"
1497 << " // Emit points and primitives to the arrays in any case\n"
1498 << " if (gl_LocalInvocationIndex > 0u) {\n"
1499 << " float proportion = (float(gl_LocalInvocationIndex - 1u) + 0.5f) / float(" << kLocalInvocations << " - 1u);\n"
1500 << " float angle = PI_2 * proportion;\n"
1501 << " float xCoord = cos(angle) * RADIUS - 1.0;\n"
1502 << " float yCoord = sin(angle) * RADIUS - 1.0;\n"
1503 << " gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = vec4(xCoord, yCoord, 0.0, 1.0);\n"
1504 << pointSizeDecl
1505 << " } else {\n"
1506 << " gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
1507 << pointSizeDecl
1508 << " }\n"
1509 << " uint primitiveId = max(gl_LocalInvocationIndex, " << (maxPrimitives - 1u) << ");\n"
1510 << " primitiveColor[primitiveId] = vec4(0.0, 0.0, 1.0, 1.0);\n"
1511 ;
1512
1513 if (params->primitiveType == PrimitiveType::POINTS)
1514 mesh << " gl_PrimitivePointIndicesEXT[primitiveId] = primitiveId;\n";
1515 else if (params->primitiveType == PrimitiveType::LINES)
1516 mesh << " gl_PrimitiveLineIndicesEXT[primitiveId] = uvec2(primitiveId + 0u, primitiveId + 1u);\n";
1517 else if (params->primitiveType == PrimitiveType::TRIANGLES)
1518 mesh << " gl_PrimitiveTriangleIndicesEXT[primitiveId] = uvec3(0u, primitiveId + 1u, primitiveId + 3u);\n";
1519 else
1520 DE_ASSERT(false);
1521
1522 mesh << "}\n";
1523
1524 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
1525
1526 MeshShaderMiscCase::initPrograms(programCollection);
1527 }
1528
1529 // Case testing barrier().
1530 class SimpleBarrierCase : public MeshShaderMiscCase
1531 {
1532 public:
SimpleBarrierCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)1533 SimpleBarrierCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
1534 : MeshShaderMiscCase (testCtx, name, std::move(params))
1535 {}
1536
1537 void initPrograms (vk::SourceCollections& programCollection) const override;
1538 TestInstance* createInstance (Context& context) const override;
1539
1540 static constexpr uint32_t kLocalInvocations = 32u;
1541 };
1542
1543 class SimpleBarrierInstance : public MeshShaderMiscInstance
1544 {
1545 public:
SimpleBarrierInstance(Context & context,const MiscTestParams * params)1546 SimpleBarrierInstance (Context& context, const MiscTestParams* params)
1547 : MeshShaderMiscInstance (context, params)
1548 {}
1549
1550 void generateReferenceLevel () override;
1551 };
1552
createInstance(Context & context) const1553 TestInstance* SimpleBarrierCase::createInstance (Context& context) const
1554 {
1555 return new SimpleBarrierInstance(context, m_params.get());
1556 }
1557
generateReferenceLevel()1558 void SimpleBarrierInstance::generateReferenceLevel ()
1559 {
1560 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
1561 }
1562
initPrograms(vk::SourceCollections & programCollection) const1563 void SimpleBarrierCase::initPrograms (vk::SourceCollections& programCollection) const
1564 {
1565 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
1566
1567 // Generate frag shader.
1568 MeshShaderMiscCase::initPrograms(programCollection);
1569
1570 DE_ASSERT(m_params->meshCount == tcu::UVec3(1u, 1u, 1u));
1571 DE_ASSERT(m_params->width == 1u && m_params->height == 1u);
1572
1573 const std::string taskOK = "workGroupSize = uvec3(1u, 1u, 1u);\n";
1574 const std::string taskFAIL = "workGroupSize = uvec3(0u, 0u, 0u);\n";
1575
1576 const std::string meshOK = "vertPrim = uvec2(1u, 1u);\n";
1577 const std::string meshFAIL = "vertPrim = uvec2(0u, 0u);\n";
1578
1579 const std::string okStatement = (m_params->needsTaskShader() ? taskOK : meshOK);
1580 const std::string failStatement = (m_params->needsTaskShader() ? taskFAIL : meshFAIL);
1581
1582 const std::string sharedDecl = "shared uint counter;\n\n";
1583 std::ostringstream verification;
1584 verification
1585 << "counter = 0;\n"
1586 << "memoryBarrierShared();\n"
1587 << "barrier();\n"
1588 << "atomicAdd(counter, 1u);\n"
1589 << "memoryBarrierShared();\n"
1590 << "barrier();\n"
1591 << "if (gl_LocalInvocationIndex == 0u) {\n"
1592 << " if (counter == " << kLocalInvocations << ") {\n"
1593 << "\n"
1594 << okStatement
1595 << "\n"
1596 << " } else {\n"
1597 << "\n"
1598 << failStatement
1599 << "\n"
1600 << " }\n"
1601 << "}\n"
1602 ;
1603
1604 // The mesh shader is very similar in both cases, so we use a template.
1605 std::ostringstream meshTemplateStr;
1606 meshTemplateStr
1607 << "#version 450\n"
1608 << "#extension GL_EXT_mesh_shader : enable\n"
1609 << "\n"
1610 << "layout (local_size_x=${LOCAL_SIZE}) in;\n"
1611 << "layout (points) out;\n"
1612 << "layout (max_vertices=1, max_primitives=1) out;\n"
1613 << "\n"
1614 << "layout (location=0) out perprimitiveEXT vec4 primitiveColor[];\n"
1615 << "\n"
1616 << "${GLOBALS:opt}"
1617 << "void main ()\n"
1618 << "{\n"
1619 << " uvec2 vertPrim = uvec2(0u, 0u);\n"
1620 << "${BODY}"
1621 << " SetMeshOutputsEXT(vertPrim.x, vertPrim.y);\n"
1622 << " if (gl_LocalInvocationIndex == 0u && vertPrim.x > 0u) {\n"
1623 << " gl_MeshVerticesEXT[0].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
1624 << " gl_MeshVerticesEXT[0].gl_PointSize = 1.0;\n"
1625 << " primitiveColor[0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
1626 << " gl_PrimitivePointIndicesEXT[0] = 0;\n"
1627 << " }\n"
1628 << "}\n"
1629 ;
1630 const tcu::StringTemplate meshTemplate = meshTemplateStr.str();
1631
1632 if (m_params->needsTaskShader())
1633 {
1634 std::ostringstream task;
1635 task
1636 << "#version 450\n"
1637 << "#extension GL_EXT_mesh_shader : enable\n"
1638 << "\n"
1639 << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
1640 << "\n"
1641 << sharedDecl
1642 << "void main ()\n"
1643 << "{\n"
1644 << " uvec3 workGroupSize = uvec3(0u, 0u, 0u);\n"
1645 << verification.str()
1646 << " EmitMeshTasksEXT(workGroupSize.x, workGroupSize.y, workGroupSize.z);\n"
1647 << "}\n"
1648 ;
1649
1650 std::map<std::string, std::string> replacements;
1651 replacements["LOCAL_SIZE"] = "1";
1652 replacements["BODY"] = meshOK;
1653
1654 const auto meshStr = meshTemplate.specialize(replacements);
1655
1656 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
1657 programCollection.glslSources.add("mesh") << glu::MeshSource(meshStr) << buildOptions;
1658 }
1659 else
1660 {
1661 std::map<std::string, std::string> replacements;
1662 replacements["LOCAL_SIZE"] = std::to_string(kLocalInvocations);
1663 replacements["BODY"] = verification.str();
1664 replacements["GLOBALS"] = sharedDecl;
1665
1666 const auto meshStr = meshTemplate.specialize(replacements);
1667
1668 programCollection.glslSources.add("mesh") << glu::MeshSource(meshStr) << buildOptions;
1669 }
1670 }
1671
1672 // Case testing memoryBarrierShared() and groupMemoryBarrier().
1673 enum class MemoryBarrierType { SHARED = 0, GROUP };
1674
1675 struct MemoryBarrierParams : public MiscTestParams
1676 {
MemoryBarrierParamsvkt::MeshShader::__anond8548dd90111::MemoryBarrierParams1677 MemoryBarrierParams (const tcu::Maybe<tcu::UVec3>& taskCount_, const tcu::UVec3& meshCount_, uint32_t width_, uint32_t height_, MemoryBarrierType memBarrierType_)
1678 : MiscTestParams (taskCount_, meshCount_, width_, height_)
1679 , memBarrierType (memBarrierType_)
1680 {}
1681
1682 MemoryBarrierType memBarrierType;
1683
glslFuncvkt::MeshShader::__anond8548dd90111::MemoryBarrierParams1684 std::string glslFunc () const
1685 {
1686 std::string funcName;
1687
1688 switch (memBarrierType)
1689 {
1690 case MemoryBarrierType::SHARED: funcName = "memoryBarrierShared"; break;
1691 case MemoryBarrierType::GROUP: funcName = "groupMemoryBarrier"; break;
1692 default: DE_ASSERT(false); break;
1693 }
1694
1695 return funcName;
1696 }
1697
1698 };
1699
1700 class MemoryBarrierCase : public MeshShaderMiscCase
1701 {
1702 public:
MemoryBarrierCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)1703 MemoryBarrierCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
1704 : MeshShaderMiscCase (testCtx, name, std::move(params))
1705 {}
1706
1707 void initPrograms (vk::SourceCollections& programCollection) const override;
1708 TestInstance* createInstance (Context& context) const override;
1709
1710 static constexpr uint32_t kLocalInvocations = 2u;
1711 };
1712
1713 class MemoryBarrierInstance : public MeshShaderMiscInstance
1714 {
1715 public:
MemoryBarrierInstance(Context & context,const MiscTestParams * params)1716 MemoryBarrierInstance (Context& context, const MiscTestParams* params)
1717 : MeshShaderMiscInstance (context, params)
1718 {}
1719
1720 void generateReferenceLevel () override;
1721 bool verifyResult (const tcu::ConstPixelBufferAccess& resultAccess) const override;
1722
1723 protected:
1724 // Allow two possible outcomes.
1725 std::unique_ptr<tcu::TextureLevel> m_referenceLevel2;
1726 };
1727
createInstance(Context & context) const1728 TestInstance* MemoryBarrierCase::createInstance (Context& context) const
1729 {
1730 return new MemoryBarrierInstance(context, m_params.get());
1731 }
1732
generateReferenceLevel()1733 void MemoryBarrierInstance::generateReferenceLevel ()
1734 {
1735 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
1736 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), m_referenceLevel2);
1737 }
1738
verifyResult(const tcu::ConstPixelBufferAccess & resultAccess) const1739 bool MemoryBarrierInstance::verifyResult (const tcu::ConstPixelBufferAccess& resultAccess) const
1740 {
1741 // Any of the two results is considered valid.
1742 constexpr auto Message = tcu::TestLog::Message;
1743 constexpr auto EndMessage = tcu::TestLog::EndMessage;
1744
1745 // Clarify what we are checking in the logs; otherwise, they could be confusing.
1746 auto& log = m_context.getTestContext().getLog();
1747 const std::vector<tcu::TextureLevel*> levels = { m_referenceLevel.get(), m_referenceLevel2.get() };
1748
1749 bool good = false;
1750 for (size_t i = 0; i < levels.size(); ++i)
1751 {
1752 log << Message << "Comparing result with reference " << i << "..." << EndMessage;
1753 const auto success = MeshShaderMiscInstance::verifyResult(resultAccess, *levels[i]);
1754 if (success)
1755 {
1756 log << Message << "Match! The test has passed" << EndMessage;
1757 good = true;
1758 break;
1759 }
1760 }
1761
1762 return good;
1763 }
1764
initPrograms(vk::SourceCollections & programCollection) const1765 void MemoryBarrierCase::initPrograms (vk::SourceCollections& programCollection) const
1766 {
1767 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
1768 const auto params = dynamic_cast<MemoryBarrierParams*>(m_params.get());
1769 DE_ASSERT(params);
1770
1771 // Generate frag shader.
1772 MeshShaderMiscCase::initPrograms(programCollection);
1773
1774 DE_ASSERT(params->meshCount == tcu::UVec3(1u, 1u, 1u));
1775 DE_ASSERT(params->width == 1u && params->height == 1u);
1776
1777 const bool taskShader = params->needsTaskShader();
1778
1779 const std::string taskDataDecl = "struct TaskData { float blue; }; taskPayloadSharedEXT TaskData td;\n\n";
1780 const auto barrierFunc = params->glslFunc();
1781
1782 const std::string taskAction = "td.blue = float(iterations % 2u);\nworkGroupSize = uvec3(1u, 1u, 1u);\n";
1783 const std::string meshAction = "vertPrim = uvec2(1u, 1u);\n";
1784 const std::string action = (taskShader ? taskAction : meshAction);
1785
1786 const std::string sharedDecl = "shared uint flags[2];\n\n";
1787 std::ostringstream verification;
1788 verification
1789 << "flags[gl_LocalInvocationIndex] = 0u;\n"
1790 << "barrier();\n"
1791 << "flags[gl_LocalInvocationIndex] = 1u;\n"
1792 << barrierFunc << "();\n"
1793 << "uint otherInvocation = 1u - gl_LocalInvocationIndex;\n"
1794 << "uint iterations = 0u;\n"
1795 << "while (flags[otherInvocation] != 1u) {\n"
1796 << " iterations++;\n"
1797 << "}\n"
1798 << "if (gl_LocalInvocationIndex == 0u) {\n"
1799 << "\n"
1800 << action
1801 << "\n"
1802 << "}\n"
1803 ;
1804
1805 // The mesh shader is very similar in both cases, so we use a template.
1806 std::ostringstream meshTemplateStr;
1807 meshTemplateStr
1808 << "#version 450\n"
1809 << "#extension GL_EXT_mesh_shader : enable\n"
1810 << "\n"
1811 << "layout (local_size_x=${LOCAL_SIZE}) in;\n"
1812 << "layout (points) out;\n"
1813 << "layout (max_vertices=1, max_primitives=1) out;\n"
1814 << "\n"
1815 << "layout (location=0) out perprimitiveEXT vec4 primitiveColor[];\n"
1816 << "\n"
1817 << "${GLOBALS}"
1818 << "void main ()\n"
1819 << "{\n"
1820 << " uvec2 vertPrim = uvec2(0u, 0u);\n"
1821 << "${BODY}"
1822 << " SetMeshOutputsEXT(vertPrim.x, vertPrim.y);\n"
1823 << " if (gl_LocalInvocationIndex == 0u && vertPrim.x > 0u) {\n"
1824 << " gl_MeshVerticesEXT[0].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
1825 << " gl_MeshVerticesEXT[0].gl_PointSize = 1.0;\n"
1826 << " primitiveColor[0] = vec4(0.0, 0.0, ${BLUE}, 1.0);\n"
1827 << " gl_PrimitivePointIndicesEXT[0] = 0;\n"
1828 << " }\n"
1829 << "}\n"
1830 ;
1831 const tcu::StringTemplate meshTemplate = meshTemplateStr.str();
1832
1833 if (params->needsTaskShader())
1834 {
1835 std::ostringstream task;
1836 task
1837 << "#version 450\n"
1838 << "#extension GL_EXT_mesh_shader : enable\n"
1839 << "\n"
1840 << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
1841 << "\n"
1842 << sharedDecl
1843 << taskDataDecl
1844 << "void main ()\n"
1845 << "{\n"
1846 << " uvec3 workGroupSize = uvec3(0u, 0u, 0u);\n"
1847 << verification.str()
1848 << " EmitMeshTasksEXT(workGroupSize.x, workGroupSize.y, workGroupSize.z);\n"
1849 << "}\n"
1850 ;
1851
1852 std::map<std::string, std::string> replacements;
1853 replacements["LOCAL_SIZE"] = "1";
1854 replacements["BODY"] = meshAction;
1855 replacements["GLOBALS"] = taskDataDecl;
1856 replacements["BLUE"] = "td.blue";
1857
1858 const auto meshStr = meshTemplate.specialize(replacements);
1859
1860 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
1861 programCollection.glslSources.add("mesh") << glu::MeshSource(meshStr) << buildOptions;
1862 }
1863 else
1864 {
1865 std::map<std::string, std::string> replacements;
1866 replacements["LOCAL_SIZE"] = std::to_string(kLocalInvocations);
1867 replacements["BODY"] = verification.str();
1868 replacements["GLOBALS"] = sharedDecl;
1869 replacements["BLUE"] = "float(iterations % 2u)";
1870
1871 const auto meshStr = meshTemplate.specialize(replacements);
1872
1873 programCollection.glslSources.add("mesh") << glu::MeshSource(meshStr) << buildOptions;
1874 }
1875 }
1876
1877 // Test the task payload can be read by all invocations in the work group.
1878 class PayloadReadCase : public MeshShaderMiscCase
1879 {
1880 public:
PayloadReadCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)1881 PayloadReadCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
1882 : MeshShaderMiscCase (testCtx, name, std::move(params))
1883 {}
1884
1885 void initPrograms (vk::SourceCollections& programCollection) const override;
1886 TestInstance* createInstance (Context& context) const override;
1887
1888 static constexpr uint32_t kLocalInvocations = 128u;
1889 };
1890
1891 class PayloadReadInstance : public MeshShaderMiscInstance
1892 {
1893 public:
PayloadReadInstance(Context & context,const MiscTestParams * params)1894 PayloadReadInstance (Context& context, const MiscTestParams* params)
1895 : MeshShaderMiscInstance (context, params)
1896 {}
1897
1898 void generateReferenceLevel () override;
1899 };
1900
createInstance(Context & context) const1901 TestInstance* PayloadReadCase::createInstance (Context &context) const
1902 {
1903 return new PayloadReadInstance(context, m_params.get());
1904 }
1905
initPrograms(vk::SourceCollections & programCollection) const1906 void PayloadReadCase::initPrograms (vk::SourceCollections &programCollection) const
1907 {
1908 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
1909
1910 // Add default fragment shader.
1911 MeshShaderMiscCase::initPrograms(programCollection);
1912
1913 std::ostringstream taskPayload;
1914 taskPayload
1915 << "struct TaskData {\n"
1916 << " uint verificationCodes[" << kLocalInvocations << "];\n"
1917 << " vec4 color;\n"
1918 << "};\n"
1919 << "taskPayloadSharedEXT TaskData td;\n"
1920 ;
1921 const std::string taskPayloadDecl = taskPayload.str();
1922
1923 DE_ASSERT(m_params->needsTaskShader());
1924
1925 const auto& meshCount = m_params->meshCount;
1926 DE_ASSERT(meshCount.x() == 1u && meshCount.y() == 1u && meshCount.z() == 1u);
1927
1928 const auto kLocalInvocations2 = kLocalInvocations * 2u;
1929
1930 std::ostringstream task;
1931 task
1932 << "#version 450\n"
1933 << "#extension GL_EXT_mesh_shader : enable\n"
1934 << "\n"
1935 << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
1936 << "\n"
1937 << taskPayloadDecl
1938 << "shared uint verificationOK[" << kLocalInvocations << "];\n"
1939 << "\n"
1940 << "void main ()\n"
1941 << "{\n"
1942 << " td.verificationCodes[gl_LocalInvocationIndex] = (" << kLocalInvocations2 << " - gl_LocalInvocationIndex);\n"
1943 << " memoryBarrierShared();\n"
1944 << " barrier();\n"
1945 // Verify all codes from all invocations.
1946 << " uint verificationResult = 1u;\n"
1947 << " for (uint i = 0u; i < " << kLocalInvocations << "; ++i) {\n"
1948 << " if (td.verificationCodes[i] != (" << kLocalInvocations2 << " - i)) {\n"
1949 << " verificationResult = 0u;\n"
1950 << " break;\n"
1951 << " }\n"
1952 << " }\n"
1953 << " verificationOK[gl_LocalInvocationIndex] = verificationResult;\n"
1954 << " memoryBarrierShared();\n"
1955 << " barrier();\n"
1956 // Check all verifications were OK (from the first invocation).
1957 << " if (gl_LocalInvocationIndex == 0u) {\n"
1958 << " vec4 color = vec4(0.0, 0.0, 1.0, 1.0);\n"
1959 << " for (uint i = 0u; i < " << kLocalInvocations << "; ++i) {\n"
1960 << " if (verificationOK[i] == 0u) {\n"
1961 << " color = vec4(0.0, 0.0, 0.0, 1.0);\n"
1962 << " }\n"
1963 << " }\n"
1964 << " td.color = color;\n"
1965 << " }\n"
1966 << " EmitMeshTasksEXT(" << meshCount.x() << ", " << meshCount.y() << ", " << meshCount.z() << ");\n"
1967 << "}\n"
1968 ;
1969 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
1970
1971 std::ostringstream mesh;
1972 mesh
1973 << "#version 450\n"
1974 << "#extension GL_EXT_mesh_shader : enable\n"
1975 << "\n"
1976 << "layout (local_size_x=1) in;\n"
1977 << "layout (triangles) out;\n"
1978 << "layout (max_vertices=3, max_primitives=1) out;\n"
1979 << "\n"
1980 << "layout (location=0) out perprimitiveEXT vec4 primitiveColor[];\n"
1981 << taskPayloadDecl
1982 << "\n"
1983 << "void main ()\n"
1984 << "{\n"
1985 // Verify data one more time from the mesh shader invocation.
1986 << " uint verificationResult = 1u;\n"
1987 << " for (uint i = 0u; i < " << kLocalInvocations << "; ++i) {\n"
1988 << " if (td.verificationCodes[i] != (" << kLocalInvocations2 << " - i)) {\n"
1989 << " verificationResult = 0u;\n"
1990 << " break;\n"
1991 << " }\n"
1992 << " }\n"
1993 << " const vec4 finalColor = ((verificationResult == 0u) ? vec4(0.0, 0.0, 0.0, 1.0) : td.color);\n"
1994 << "\n"
1995 << " SetMeshOutputsEXT(3u, 1u);\n"
1996 << "\n"
1997 << " gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
1998 << " gl_MeshVerticesEXT[1].gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
1999 << " gl_MeshVerticesEXT[2].gl_Position = vec4(-1.0, 3.0, 0.0, 1.0);\n"
2000 << "\n"
2001 << " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2);\n"
2002 << " primitiveColor[0] = finalColor;\n"
2003 << "}\n"
2004 ;
2005 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
2006 }
2007
generateReferenceLevel()2008 void PayloadReadInstance::generateReferenceLevel ()
2009 {
2010 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
2011 }
2012
2013 // Test with custom per-vertex and per-primitive attributes of different types.
2014 class CustomAttributesCase : public MeshShaderMiscCase
2015 {
2016 public:
CustomAttributesCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)2017 CustomAttributesCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
2018 : MeshShaderMiscCase(testCtx, name, std::move(params)) {}
~CustomAttributesCase(void)2019 virtual ~CustomAttributesCase (void) {}
2020
2021 TestInstance* createInstance (Context& context) const override;
2022 void checkSupport (Context& context) const override;
2023 void initPrograms (vk::SourceCollections& programCollection) const override;
2024 };
2025
2026 class CustomAttributesInstance : public MeshShaderMiscInstance
2027 {
2028 public:
CustomAttributesInstance(Context & context,const MiscTestParams * params)2029 CustomAttributesInstance (Context& context, const MiscTestParams* params)
2030 : MeshShaderMiscInstance(context, params) {}
~CustomAttributesInstance(void)2031 virtual ~CustomAttributesInstance (void) {}
2032
2033 void generateReferenceLevel () override;
2034 tcu::TestStatus iterate (void) override;
2035 };
2036
createInstance(Context & context) const2037 TestInstance* CustomAttributesCase::createInstance (Context& context) const
2038 {
2039 return new CustomAttributesInstance(context, m_params.get());
2040 }
2041
checkSupport(Context & context) const2042 void CustomAttributesCase::checkSupport (Context& context) const
2043 {
2044 MeshShaderMiscCase::checkSupport(context);
2045
2046 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
2047 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_CLIP_DISTANCE);
2048 }
2049
initPrograms(vk::SourceCollections & programCollection) const2050 void CustomAttributesCase::initPrograms (vk::SourceCollections& programCollection) const
2051 {
2052 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
2053
2054 std::ostringstream frag;
2055 frag
2056 << "#version 450\n"
2057 << "#extension GL_EXT_mesh_shader : enable\n"
2058 << "\n"
2059 << "layout (location=0) in vec4 customAttribute1;\n"
2060 << "layout (location=1) in flat float customAttribute2;\n"
2061 << "layout (location=2) in flat int customAttribute3;\n"
2062 << "\n"
2063 << "layout (location=3) in perprimitiveEXT flat uvec4 customAttribute4;\n"
2064 << "layout (location=4) in perprimitiveEXT float customAttribute5;\n"
2065 << "\n"
2066 << "layout (location=0) out vec4 outColor;\n"
2067 << "\n"
2068 << "void main ()\n"
2069 << "{\n"
2070 << " bool goodPrimitiveID = (gl_PrimitiveID == 1000 || gl_PrimitiveID == 1001);\n"
2071 << " bool goodViewportIndex = (gl_ViewportIndex == 1);\n"
2072 << " bool goodCustom1 = (customAttribute1.x >= 0.25 && customAttribute1.x <= 0.5 &&\n"
2073 << " customAttribute1.y >= 0.5 && customAttribute1.y <= 1.0 &&\n"
2074 << " customAttribute1.z >= 10.0 && customAttribute1.z <= 20.0 &&\n"
2075 << " customAttribute1.w == 3.0);\n"
2076 << " bool goodCustom2 = (customAttribute2 == 1.0 || customAttribute2 == 2.0);\n"
2077 << " bool goodCustom3 = (customAttribute3 == 3 || customAttribute3 == 4);\n"
2078 << " bool goodCustom4 = ((gl_PrimitiveID == 1000 && customAttribute4 == uvec4(100, 101, 102, 103)) ||\n"
2079 << " (gl_PrimitiveID == 1001 && customAttribute4 == uvec4(200, 201, 202, 203)));\n"
2080 << " bool goodCustom5 = ((gl_PrimitiveID == 1000 && customAttribute5 == 6.0) ||\n"
2081 << " (gl_PrimitiveID == 1001 && customAttribute5 == 7.0));\n"
2082 << " \n"
2083 << " if (goodPrimitiveID && goodViewportIndex && goodCustom1 && goodCustom2 && goodCustom3 && goodCustom4 && goodCustom5) {\n"
2084 << " outColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
2085 << " } else {\n"
2086 << " outColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
2087 << " }\n"
2088 << "}\n"
2089 ;
2090 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str()) << buildOptions;
2091
2092 std::ostringstream pvdDataDeclStream;
2093 pvdDataDeclStream
2094 << " vec4 positions[4];\n"
2095 << " float pointSizes[4];\n"
2096 << " float clipDistances[4];\n"
2097 << " vec4 custom1[4];\n"
2098 << " float custom2[4];\n"
2099 << " int custom3[4];\n"
2100 ;
2101 const auto pvdDataDecl = pvdDataDeclStream.str();
2102
2103 std::ostringstream ppdDataDeclStream;
2104 ppdDataDeclStream
2105 << " int primitiveIds[2];\n"
2106 << " int viewportIndices[2];\n"
2107 << " uvec4 custom4[2];\n"
2108 << " float custom5[2];\n"
2109 ;
2110 const auto ppdDataDecl = ppdDataDeclStream.str();
2111
2112 std::ostringstream bindingsDeclStream;
2113 bindingsDeclStream
2114 << "layout (set=0, binding=0, std430) buffer PerVertexData {\n"
2115 << pvdDataDecl
2116 << "} pvd;\n"
2117 << "layout (set=0, binding=1) uniform PerPrimitiveData {\n"
2118 << ppdDataDecl
2119 << "} ppd;\n"
2120 << "\n"
2121 ;
2122 const auto bindingsDecl = bindingsDeclStream.str();
2123
2124 std::ostringstream taskDataStream;
2125 taskDataStream
2126 << "struct TaskData {\n"
2127 << pvdDataDecl
2128 << ppdDataDecl
2129 << "};\n"
2130 << "taskPayloadSharedEXT TaskData td;\n"
2131 << "\n"
2132 ;
2133 const auto taskDataDecl = taskDataStream.str();
2134
2135 const auto taskShader = m_params->needsTaskShader();
2136
2137 const auto meshPvdPrefix = (taskShader ? "td" : "pvd");
2138 const auto meshPpdPrefix = (taskShader ? "td" : "ppd");
2139
2140 std::ostringstream mesh;
2141 mesh
2142 << "#version 450\n"
2143 << "#extension GL_EXT_mesh_shader : enable\n"
2144 << "\n"
2145 << "layout (local_size_x=1) in;\n"
2146 << "layout (max_primitives=2, max_vertices=4) out;\n"
2147 << "layout (triangles) out;\n"
2148 << "\n"
2149 << "out gl_MeshPerVertexEXT {\n"
2150 << " vec4 gl_Position;\n"
2151 << " float gl_PointSize;\n"
2152 << " float gl_ClipDistance[1];\n"
2153 << "} gl_MeshVerticesEXT[];\n"
2154 << "\n"
2155 << "layout (location=0) out vec4 customAttribute1[];\n"
2156 << "layout (location=1) out flat float customAttribute2[];\n"
2157 << "layout (location=2) out int customAttribute3[];\n"
2158 << "\n"
2159 << "layout (location=3) out perprimitiveEXT uvec4 customAttribute4[];\n"
2160 << "layout (location=4) out perprimitiveEXT float customAttribute5[];\n"
2161 << "\n"
2162 << "out perprimitiveEXT gl_MeshPerPrimitiveEXT {\n"
2163 << " int gl_PrimitiveID;\n"
2164 << " int gl_ViewportIndex;\n"
2165 << "} gl_MeshPrimitivesEXT[];\n"
2166 << "\n"
2167 << (taskShader ? taskDataDecl : bindingsDecl)
2168 << "void main ()\n"
2169 << "{\n"
2170 << " SetMeshOutputsEXT(4u, 2u);\n"
2171 << "\n"
2172 << " gl_MeshVerticesEXT[0].gl_Position = " << meshPvdPrefix << ".positions[0]; //vec4(-1.0, -1.0, 0.0, 1.0)\n"
2173 << " gl_MeshVerticesEXT[1].gl_Position = " << meshPvdPrefix << ".positions[1]; //vec4( 1.0, -1.0, 0.0, 1.0)\n"
2174 << " gl_MeshVerticesEXT[2].gl_Position = " << meshPvdPrefix << ".positions[2]; //vec4(-1.0, 1.0, 0.0, 1.0)\n"
2175 << " gl_MeshVerticesEXT[3].gl_Position = " << meshPvdPrefix << ".positions[3]; //vec4( 1.0, 1.0, 0.0, 1.0)\n"
2176 << "\n"
2177 << " gl_MeshVerticesEXT[0].gl_PointSize = " << meshPvdPrefix << ".pointSizes[0]; //1.0\n"
2178 << " gl_MeshVerticesEXT[1].gl_PointSize = " << meshPvdPrefix << ".pointSizes[1]; //1.0\n"
2179 << " gl_MeshVerticesEXT[2].gl_PointSize = " << meshPvdPrefix << ".pointSizes[2]; //1.0\n"
2180 << " gl_MeshVerticesEXT[3].gl_PointSize = " << meshPvdPrefix << ".pointSizes[3]; //1.0\n"
2181 << "\n"
2182 << " // Remove geometry on the right side.\n"
2183 << " gl_MeshVerticesEXT[0].gl_ClipDistance[0] = " << meshPvdPrefix << ".clipDistances[0]; // 1.0\n"
2184 << " gl_MeshVerticesEXT[1].gl_ClipDistance[0] = " << meshPvdPrefix << ".clipDistances[1]; //-1.0\n"
2185 << " gl_MeshVerticesEXT[2].gl_ClipDistance[0] = " << meshPvdPrefix << ".clipDistances[2]; // 1.0\n"
2186 << " gl_MeshVerticesEXT[3].gl_ClipDistance[0] = " << meshPvdPrefix << ".clipDistances[3]; //-1.0\n"
2187 << " \n"
2188 << " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2);\n"
2189 << " gl_PrimitiveTriangleIndicesEXT[1] = uvec3(2, 3, 1);\n"
2190 << "\n"
2191 << " gl_MeshPrimitivesEXT[0].gl_PrimitiveID = " << meshPpdPrefix << ".primitiveIds[0]; //1000\n"
2192 << " gl_MeshPrimitivesEXT[1].gl_PrimitiveID = " << meshPpdPrefix << ".primitiveIds[1]; //1001\n"
2193 << "\n"
2194 << " gl_MeshPrimitivesEXT[0].gl_ViewportIndex = " << meshPpdPrefix << ".viewportIndices[0]; //1\n"
2195 << " gl_MeshPrimitivesEXT[1].gl_ViewportIndex = " << meshPpdPrefix << ".viewportIndices[1]; //1\n"
2196 << "\n"
2197 << " // Custom per-vertex attributes\n"
2198 << " customAttribute1[0] = " << meshPvdPrefix << ".custom1[0]; //vec4(0.25, 0.5, 10.0, 3.0)\n"
2199 << " customAttribute1[1] = " << meshPvdPrefix << ".custom1[1]; //vec4(0.25, 1.0, 20.0, 3.0)\n"
2200 << " customAttribute1[2] = " << meshPvdPrefix << ".custom1[2]; //vec4( 0.5, 0.5, 20.0, 3.0)\n"
2201 << " customAttribute1[3] = " << meshPvdPrefix << ".custom1[3]; //vec4( 0.5, 1.0, 10.0, 3.0)\n"
2202 << "\n"
2203 << " customAttribute2[0] = " << meshPvdPrefix << ".custom2[0]; //1.0f\n"
2204 << " customAttribute2[1] = " << meshPvdPrefix << ".custom2[1]; //1.0f\n"
2205 << " customAttribute2[2] = " << meshPvdPrefix << ".custom2[2]; //2.0f\n"
2206 << " customAttribute2[3] = " << meshPvdPrefix << ".custom2[3]; //2.0f\n"
2207 << "\n"
2208 << " customAttribute3[0] = " << meshPvdPrefix << ".custom3[0]; //3\n"
2209 << " customAttribute3[1] = " << meshPvdPrefix << ".custom3[1]; //3\n"
2210 << " customAttribute3[2] = " << meshPvdPrefix << ".custom3[2]; //4\n"
2211 << " customAttribute3[3] = " << meshPvdPrefix << ".custom3[3]; //4\n"
2212 << "\n"
2213 << " // Custom per-primitive attributes.\n"
2214 << " customAttribute4[0] = " << meshPpdPrefix << ".custom4[0]; //uvec4(100, 101, 102, 103)\n"
2215 << " customAttribute4[1] = " << meshPpdPrefix << ".custom4[1]; //uvec4(200, 201, 202, 203)\n"
2216 << "\n"
2217 << " customAttribute5[0] = " << meshPpdPrefix << ".custom5[0]; //6.0\n"
2218 << " customAttribute5[1] = " << meshPpdPrefix << ".custom5[1]; //7.0\n"
2219 << "}\n"
2220 ;
2221 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
2222
2223 if (taskShader)
2224 {
2225 const auto& meshCount = m_params->meshCount;
2226 std::ostringstream task;
2227 task
2228 << "#version 450\n"
2229 << "#extension GL_EXT_mesh_shader : enable\n"
2230 << "\n"
2231 << taskDataDecl
2232 << bindingsDecl
2233 << "void main ()\n"
2234 << "{\n"
2235 << " td.positions[0] = pvd.positions[0];\n"
2236 << " td.positions[1] = pvd.positions[1];\n"
2237 << " td.positions[2] = pvd.positions[2];\n"
2238 << " td.positions[3] = pvd.positions[3];\n"
2239 << "\n"
2240 << " td.pointSizes[0] = pvd.pointSizes[0];\n"
2241 << " td.pointSizes[1] = pvd.pointSizes[1];\n"
2242 << " td.pointSizes[2] = pvd.pointSizes[2];\n"
2243 << " td.pointSizes[3] = pvd.pointSizes[3];\n"
2244 << "\n"
2245 << " td.clipDistances[0] = pvd.clipDistances[0];\n"
2246 << " td.clipDistances[1] = pvd.clipDistances[1];\n"
2247 << " td.clipDistances[2] = pvd.clipDistances[2];\n"
2248 << " td.clipDistances[3] = pvd.clipDistances[3];\n"
2249 << "\n"
2250 << " td.custom1[0] = pvd.custom1[0];\n"
2251 << " td.custom1[1] = pvd.custom1[1];\n"
2252 << " td.custom1[2] = pvd.custom1[2];\n"
2253 << " td.custom1[3] = pvd.custom1[3];\n"
2254 << "\n"
2255 << " td.custom2[0] = pvd.custom2[0];\n"
2256 << " td.custom2[1] = pvd.custom2[1];\n"
2257 << " td.custom2[2] = pvd.custom2[2];\n"
2258 << " td.custom2[3] = pvd.custom2[3];\n"
2259 << "\n"
2260 << " td.custom3[0] = pvd.custom3[0];\n"
2261 << " td.custom3[1] = pvd.custom3[1];\n"
2262 << " td.custom3[2] = pvd.custom3[2];\n"
2263 << " td.custom3[3] = pvd.custom3[3];\n"
2264 << "\n"
2265 << " td.primitiveIds[0] = ppd.primitiveIds[0];\n"
2266 << " td.primitiveIds[1] = ppd.primitiveIds[1];\n"
2267 << "\n"
2268 << " td.viewportIndices[0] = ppd.viewportIndices[0];\n"
2269 << " td.viewportIndices[1] = ppd.viewportIndices[1];\n"
2270 << "\n"
2271 << " td.custom4[0] = ppd.custom4[0];\n"
2272 << " td.custom4[1] = ppd.custom4[1];\n"
2273 << "\n"
2274 << " td.custom5[0] = ppd.custom5[0];\n"
2275 << " td.custom5[1] = ppd.custom5[1];\n"
2276 << "\n"
2277 << " EmitMeshTasksEXT(" << meshCount.x() << ", " << meshCount.y() << ", " << meshCount.z() << ");\n"
2278 << "}\n"
2279 ;
2280 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
2281 }
2282 }
2283
generateReferenceLevel()2284 void CustomAttributesInstance::generateReferenceLevel ()
2285 {
2286 const auto format = getOutputFormat();
2287 const auto tcuFormat = mapVkFormat(format);
2288
2289 const auto iWidth = static_cast<int>(m_params->width);
2290 const auto iHeight = static_cast<int>(m_params->height);
2291
2292 const auto halfWidth = iWidth / 2;
2293 const auto halfHeight = iHeight / 2;
2294
2295 m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
2296
2297 const auto access = m_referenceLevel->getAccess();
2298 const auto clearColor = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
2299 const auto blueColor = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
2300
2301 tcu::clear(access, clearColor);
2302
2303 // Fill the top left quarter.
2304 for (int y = 0; y < halfWidth; ++y)
2305 for (int x = 0; x < halfHeight; ++x)
2306 {
2307 access.setPixel(blueColor, x, y);
2308 }
2309 }
2310
iterate()2311 tcu::TestStatus CustomAttributesInstance::iterate ()
2312 {
2313 struct PerVertexData
2314 {
2315 tcu::Vec4 positions[4];
2316 float pointSizes[4];
2317 float clipDistances[4];
2318 tcu::Vec4 custom1[4];
2319 float custom2[4];
2320 int32_t custom3[4];
2321 };
2322
2323 struct PerPrimitiveData
2324 {
2325 // Note some of these are declared as vectors to match the std140 layout.
2326 tcu::IVec4 primitiveIds[2];
2327 tcu::IVec4 viewportIndices[2];
2328 tcu::UVec4 custom4[2];
2329 tcu::Vec4 custom5[2];
2330 };
2331
2332 const auto& vkd = m_context.getDeviceInterface();
2333 const auto device = m_context.getDevice();
2334 auto& alloc = m_context.getDefaultAllocator();
2335 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
2336 const auto queue = m_context.getUniversalQueue();
2337
2338 const auto imageFormat = getOutputFormat();
2339 const auto tcuFormat = mapVkFormat(imageFormat);
2340 const auto imageExtent = makeExtent3D(m_params->width, m_params->height, 1u);
2341 const auto imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2342
2343 const auto& binaries = m_context.getBinaryCollection();
2344 const auto hasTask = binaries.contains("task");
2345 const auto bufStages = (hasTask ? VK_SHADER_STAGE_TASK_BIT_EXT : VK_SHADER_STAGE_MESH_BIT_EXT);
2346
2347 const VkImageCreateInfo colorBufferInfo =
2348 {
2349 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
2350 nullptr, // const void* pNext;
2351 0u, // VkImageCreateFlags flags;
2352 VK_IMAGE_TYPE_2D, // VkImageType imageType;
2353 imageFormat, // VkFormat format;
2354 imageExtent, // VkExtent3D extent;
2355 1u, // uint32_t mipLevels;
2356 1u, // uint32_t arrayLayers;
2357 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
2358 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
2359 imageUsage, // VkImageUsageFlags usage;
2360 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
2361 0u, // uint32_t queueFamilyIndexCount;
2362 nullptr, // const uint32_t* pQueueFamilyIndices;
2363 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
2364 };
2365
2366 // Create color image and view.
2367 ImageWithMemory colorImage (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
2368 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
2369 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
2370 const auto colorView = makeImageView(vkd, device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
2371
2372 // Create a memory buffer for verification.
2373 const auto verificationBufferSize = static_cast<VkDeviceSize>(imageExtent.width * imageExtent.height * tcu::getPixelSize(tcuFormat));
2374 const auto verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
2375 const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
2376
2377 BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
2378 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
2379 void* verificationBufferData = verificationBufferAlloc.getHostPtr();
2380
2381 // This needs to match what the fragment shader will expect.
2382 const PerVertexData perVertexData =
2383 {
2384 // tcu::Vec4 positions[4];
2385 {
2386 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
2387 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
2388 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
2389 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
2390 },
2391 // float pointSizes[4];
2392 { 1.0f, 1.0f, 1.0f, 1.0f, },
2393 // float clipDistances[4];
2394 {
2395 1.0f,
2396 -1.0f,
2397 1.0f,
2398 -1.0f,
2399 },
2400 // tcu::Vec4 custom1[4];
2401 {
2402 tcu::Vec4(0.25, 0.5, 10.0, 3.0),
2403 tcu::Vec4(0.25, 1.0, 20.0, 3.0),
2404 tcu::Vec4( 0.5, 0.5, 20.0, 3.0),
2405 tcu::Vec4( 0.5, 1.0, 10.0, 3.0),
2406 },
2407 // float custom2[4];
2408 { 1.0f, 1.0f, 2.0f, 2.0f, },
2409 // int32_t custom3[4];
2410 { 3, 3, 4, 4 },
2411 };
2412
2413 // This needs to match what the fragment shader will expect. Reminder: some of these are declared as gvec4 to match the std140
2414 // layout, but only the first component is actually used.
2415 const PerPrimitiveData perPrimitiveData =
2416 {
2417 // int primitiveIds[2];
2418 {
2419 tcu::IVec4(1000, 0, 0, 0),
2420 tcu::IVec4(1001, 0, 0, 0),
2421 },
2422 // int viewportIndices[2];
2423 {
2424 tcu::IVec4(1, 0, 0, 0),
2425 tcu::IVec4(1, 0, 0, 0),
2426 },
2427 // uvec4 custom4[2];
2428 {
2429 tcu::UVec4(100u, 101u, 102u, 103u),
2430 tcu::UVec4(200u, 201u, 202u, 203u),
2431 },
2432 // float custom5[2];
2433 {
2434 tcu::Vec4(6.0f, 0.0f, 0.0f, 0.0f),
2435 tcu::Vec4(7.0f, 0.0f, 0.0f, 0.0f),
2436 },
2437 };
2438
2439 // Create and fill buffers with this data.
2440 const auto pvdSize = static_cast<VkDeviceSize>(sizeof(perVertexData));
2441 const auto pvdInfo = makeBufferCreateInfo(pvdSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
2442 BufferWithMemory pvdData (vkd, device, alloc, pvdInfo, MemoryRequirement::HostVisible);
2443 auto& pvdAlloc = pvdData.getAllocation();
2444 void* pvdPtr = pvdAlloc.getHostPtr();
2445
2446 const auto ppdSize = static_cast<VkDeviceSize>(sizeof(perPrimitiveData));
2447 const auto ppdInfo = makeBufferCreateInfo(ppdSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
2448 BufferWithMemory ppdData (vkd, device, alloc, ppdInfo, MemoryRequirement::HostVisible);
2449 auto& ppdAlloc = ppdData.getAllocation();
2450 void* ppdPtr = ppdAlloc.getHostPtr();
2451
2452 deMemcpy(pvdPtr, &perVertexData, sizeof(perVertexData));
2453 deMemcpy(ppdPtr, &perPrimitiveData, sizeof(perPrimitiveData));
2454
2455 flushAlloc(vkd, device, pvdAlloc);
2456 flushAlloc(vkd, device, ppdAlloc);
2457
2458 // Descriptor set layout.
2459 DescriptorSetLayoutBuilder setLayoutBuilder;
2460 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, bufStages);
2461 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bufStages);
2462 const auto setLayout = setLayoutBuilder.build(vkd, device);
2463
2464 // Create and update descriptor set.
2465 DescriptorPoolBuilder descriptorPoolBuilder;
2466 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
2467 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
2468 const auto descriptorPool = descriptorPoolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
2469 const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
2470
2471 DescriptorSetUpdateBuilder updateBuilder;
2472 const auto storageBufferInfo = makeDescriptorBufferInfo(pvdData.get(), 0ull, pvdSize);
2473 const auto uniformBufferInfo = makeDescriptorBufferInfo(ppdData.get(), 0ull, ppdSize);
2474 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &storageBufferInfo);
2475 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uniformBufferInfo);
2476 updateBuilder.update(vkd, device);
2477
2478 // Pipeline layout.
2479 const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
2480
2481 // Shader modules.
2482 const auto meshShader = createShaderModule(vkd, device, binaries.get("mesh"));
2483 const auto fragShader = createShaderModule(vkd, device, binaries.get("frag"));
2484
2485 Move<VkShaderModule> taskShader;
2486 if (hasTask)
2487 taskShader = createShaderModule(vkd, device, binaries.get("task"));
2488
2489 // Render pass.
2490 const auto renderPass = makeRenderPass(vkd, device, imageFormat);
2491
2492 // Framebuffer.
2493 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), imageExtent.width, imageExtent.height);
2494
2495 // Viewport and scissor.
2496 const auto topHalf = makeViewport(imageExtent.width, imageExtent.height / 2u);
2497 const std::vector<VkViewport> viewports { makeViewport(imageExtent), topHalf };
2498 const std::vector<VkRect2D> scissors (2u, makeRect2D(imageExtent));
2499
2500 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
2501 taskShader.get(), meshShader.get(), fragShader.get(),
2502 renderPass.get(), viewports, scissors);
2503
2504 // Command pool and buffer.
2505 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
2506 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2507 const auto cmdBuffer = cmdBufferPtr.get();
2508
2509 beginCommandBuffer(vkd, cmdBuffer);
2510
2511 // Run pipeline.
2512 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
2513 const auto drawCount = m_params->drawCount();
2514 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
2515 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
2516 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
2517 vkd.cmdDrawMeshTasksEXT(cmdBuffer, drawCount.x(), drawCount.y(), drawCount.z());
2518 endRenderPass(vkd, cmdBuffer);
2519
2520 // Copy color buffer to verification buffer.
2521 const auto colorAccess = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
2522 const auto transferRead = VK_ACCESS_TRANSFER_READ_BIT;
2523 const auto transferWrite = VK_ACCESS_TRANSFER_WRITE_BIT;
2524 const auto hostRead = VK_ACCESS_HOST_READ_BIT;
2525
2526 const auto preCopyBarrier = makeImageMemoryBarrier(colorAccess, transferRead, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSRR);
2527 const auto postCopyBarrier = makeMemoryBarrier(transferWrite, hostRead);
2528 const auto copyRegion = makeBufferImageCopy(imageExtent, colorSRL);
2529
2530 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
2531 vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
2532 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
2533
2534 endCommandBuffer(vkd, cmdBuffer);
2535 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
2536
2537 // Generate reference image and compare results.
2538 const tcu::IVec3 iExtent (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), 1);
2539 const tcu::ConstPixelBufferAccess verificationAccess (tcuFormat, iExtent, verificationBufferData);
2540
2541 generateReferenceLevel();
2542 invalidateAlloc(vkd, device, verificationBufferAlloc);
2543 if (!verifyResult(verificationAccess))
2544 TCU_FAIL("Result does not match reference; check log for details");
2545
2546 return tcu::TestStatus::pass("Pass");
2547 }
2548
2549 // Tests that use push constants in the new stages.
2550 class PushConstantCase : public MeshShaderMiscCase
2551 {
2552 public:
PushConstantCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)2553 PushConstantCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
2554 : MeshShaderMiscCase (testCtx, name, std::move(params))
2555 {}
2556
2557 void initPrograms (vk::SourceCollections& programCollection) const override;
2558 TestInstance* createInstance (Context& context) const override;
2559 };
2560
2561 class PushConstantInstance : public MeshShaderMiscInstance
2562 {
2563 public:
PushConstantInstance(Context & context,const MiscTestParams * params)2564 PushConstantInstance (Context& context, const MiscTestParams* params)
2565 : MeshShaderMiscInstance (context, params)
2566 {}
2567
2568 void generateReferenceLevel () override;
2569 tcu::TestStatus iterate () override;
2570 };
2571
createInstance(Context & context) const2572 TestInstance* PushConstantCase::createInstance (Context& context) const
2573 {
2574 return new PushConstantInstance(context, m_params.get());
2575 }
2576
generateReferenceLevel()2577 void PushConstantInstance::generateReferenceLevel ()
2578 {
2579 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
2580 }
2581
initPrograms(vk::SourceCollections & programCollection) const2582 void PushConstantCase::initPrograms (vk::SourceCollections& programCollection) const
2583 {
2584 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
2585 const auto useTaskShader = m_params->needsTaskShader();
2586 const auto pcNumFloats = (useTaskShader ? 2u : 4u);
2587
2588 std::ostringstream pushConstantStream;
2589 pushConstantStream
2590 << "layout (push_constant, std430) uniform PushConstantBlock {\n"
2591 << " layout (offset=${PCOFFSET}) float values[" << pcNumFloats << "];\n"
2592 << "} pc;\n"
2593 << "\n"
2594 ;
2595 const tcu::StringTemplate pushConstantsTemplate (pushConstantStream.str());
2596 using TemplateMap = std::map<std::string, std::string>;
2597
2598 std::ostringstream taskDataStream;
2599 taskDataStream
2600 << "struct TaskData {\n"
2601 << " float values[2];\n"
2602 << "};\n"
2603 << "taskPayloadSharedEXT TaskData td;\n"
2604 << "\n"
2605 ;
2606 const auto taskDataDecl = taskDataStream.str();
2607
2608 if (useTaskShader)
2609 {
2610 TemplateMap taskMap;
2611 taskMap["PCOFFSET"] = std::to_string(2u * sizeof(float));
2612
2613 const auto& meshCount = m_params->meshCount;
2614 std::ostringstream task;
2615 task
2616 << "#version 450\n"
2617 << "#extension GL_EXT_mesh_shader : enable\n"
2618 << "\n"
2619 << "layout(local_size_x=1) in;\n"
2620 << "\n"
2621 << taskDataDecl
2622 << pushConstantsTemplate.specialize(taskMap)
2623 << "void main ()\n"
2624 << "{\n"
2625 << " td.values[0] = pc.values[0];\n"
2626 << " td.values[1] = pc.values[1];\n"
2627 << "\n"
2628 << " EmitMeshTasksEXT(" << meshCount.x() << ", " << meshCount.y() << ", " << meshCount.z() << ");\n"
2629 << "}\n"
2630 ;
2631 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
2632 }
2633
2634 {
2635 const std::string blue = (useTaskShader ? "td.values[0] + pc.values[0]" : "pc.values[0] + pc.values[2]");
2636 const std::string alpha = (useTaskShader ? "td.values[1] + pc.values[1]" : "pc.values[1] + pc.values[3]");
2637
2638 TemplateMap meshMap;
2639 meshMap["PCOFFSET"] = "0";
2640
2641 std::ostringstream mesh;
2642 mesh
2643 << "#version 450\n"
2644 << "#extension GL_EXT_mesh_shader : enable\n"
2645 << "\n"
2646 << "layout(local_size_x=1) in;\n"
2647 << "layout(triangles) out;\n"
2648 << "layout(max_vertices=3, max_primitives=1) out;\n"
2649 << "\n"
2650 << "layout (location=0) out perprimitiveEXT vec4 triangleColor[];\n"
2651 << "\n"
2652 << pushConstantsTemplate.specialize(meshMap)
2653 << (useTaskShader ? taskDataDecl : "")
2654 << "void main ()\n"
2655 << "{\n"
2656 << " SetMeshOutputsEXT(3u, 1u);\n"
2657 << "\n"
2658 << " gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
2659 << " gl_MeshVerticesEXT[1].gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
2660 << " gl_MeshVerticesEXT[2].gl_Position = vec4(-1.0, 3.0, 0.0, 1.0);\n"
2661 << "\n"
2662 << " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2);\n"
2663 << " triangleColor[0] = vec4(0.0, 0.0, " << blue << ", " << alpha << ");\n"
2664 << "}\n"
2665 ;
2666 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
2667 }
2668
2669 // Add default fragment shader.
2670 MeshShaderMiscCase::initPrograms(programCollection);
2671 }
2672
iterate()2673 tcu::TestStatus PushConstantInstance::iterate ()
2674 {
2675 const auto& vkd = m_context.getDeviceInterface();
2676 const auto device = m_context.getDevice();
2677 auto& alloc = m_context.getDefaultAllocator();
2678 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
2679 const auto queue = m_context.getUniversalQueue();
2680
2681 const auto imageFormat = getOutputFormat();
2682 const auto tcuFormat = mapVkFormat(imageFormat);
2683 const auto imageExtent = makeExtent3D(m_params->width, m_params->height, 1u);
2684 const auto imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2685
2686 const auto& binaries = m_context.getBinaryCollection();
2687 const auto hasTask = binaries.contains("task");
2688
2689 const VkImageCreateInfo colorBufferInfo =
2690 {
2691 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
2692 nullptr, // const void* pNext;
2693 0u, // VkImageCreateFlags flags;
2694 VK_IMAGE_TYPE_2D, // VkImageType imageType;
2695 imageFormat, // VkFormat format;
2696 imageExtent, // VkExtent3D extent;
2697 1u, // uint32_t mipLevels;
2698 1u, // uint32_t arrayLayers;
2699 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
2700 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
2701 imageUsage, // VkImageUsageFlags usage;
2702 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
2703 0u, // uint32_t queueFamilyIndexCount;
2704 nullptr, // const uint32_t* pQueueFamilyIndices;
2705 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
2706 };
2707
2708 // Create color image and view.
2709 ImageWithMemory colorImage (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
2710 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
2711 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
2712 const auto colorView = makeImageView(vkd, device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
2713
2714 // Create a memory buffer for verification.
2715 const auto verificationBufferSize = static_cast<VkDeviceSize>(imageExtent.width * imageExtent.height * tcu::getPixelSize(tcuFormat));
2716 const auto verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
2717 const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
2718
2719 BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
2720 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
2721 void* verificationBufferData = verificationBufferAlloc.getHostPtr();
2722
2723 // Push constant ranges.
2724 std::vector<float> pcData { 0.25f, 0.25f, 0.75f, 0.75f };
2725 const auto pcSize = static_cast<uint32_t>(de::dataSize(pcData));
2726 const auto pcHalfSize = pcSize / 2u;
2727
2728 std::vector<VkPushConstantRange> pcRanges;
2729 if (hasTask)
2730 {
2731 pcRanges.push_back(makePushConstantRange(VK_SHADER_STAGE_MESH_BIT_EXT, 0u, pcHalfSize));
2732 pcRanges.push_back(makePushConstantRange(VK_SHADER_STAGE_TASK_BIT_EXT, pcHalfSize, pcHalfSize));
2733 }
2734 else
2735 {
2736 pcRanges.push_back(makePushConstantRange(VK_SHADER_STAGE_MESH_BIT_EXT, 0u, pcSize));
2737 }
2738
2739 // Pipeline layout.
2740 const auto pipelineLayout = makePipelineLayout(vkd, device, 0u, nullptr, static_cast<uint32_t>(pcRanges.size()), de::dataOrNull(pcRanges));
2741
2742 // Shader modules.
2743 const auto meshShader = createShaderModule(vkd, device, binaries.get("mesh"));
2744 const auto fragShader = createShaderModule(vkd, device, binaries.get("frag"));
2745
2746 Move<VkShaderModule> taskShader;
2747 if (hasTask)
2748 taskShader = createShaderModule(vkd, device, binaries.get("task"));
2749
2750 // Render pass.
2751 const auto renderPass = makeRenderPass(vkd, device, imageFormat);
2752
2753 // Framebuffer.
2754 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), imageExtent.width, imageExtent.height);
2755
2756 // Viewport and scissor.
2757 const std::vector<VkViewport> viewports (1u, makeViewport(imageExtent));
2758 const std::vector<VkRect2D> scissors (1u, makeRect2D(imageExtent));
2759
2760 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
2761 taskShader.get(), meshShader.get(), fragShader.get(),
2762 renderPass.get(), viewports, scissors);
2763
2764 // Command pool and buffer.
2765 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
2766 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2767 const auto cmdBuffer = cmdBufferPtr.get();
2768
2769 beginCommandBuffer(vkd, cmdBuffer);
2770
2771 // Run pipeline.
2772 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
2773 const auto drawCount = m_params->drawCount();
2774 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
2775 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
2776 for (const auto& range : pcRanges)
2777 vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), range.stageFlags, range.offset, range.size, reinterpret_cast<const char*>(pcData.data()) + range.offset);
2778 vkd.cmdDrawMeshTasksEXT(cmdBuffer, drawCount.x(), drawCount.y(), drawCount.z());
2779 endRenderPass(vkd, cmdBuffer);
2780
2781 // Copy color buffer to verification buffer.
2782 const auto colorAccess = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
2783 const auto transferRead = VK_ACCESS_TRANSFER_READ_BIT;
2784 const auto transferWrite = VK_ACCESS_TRANSFER_WRITE_BIT;
2785 const auto hostRead = VK_ACCESS_HOST_READ_BIT;
2786
2787 const auto preCopyBarrier = makeImageMemoryBarrier(colorAccess, transferRead, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSRR);
2788 const auto postCopyBarrier = makeMemoryBarrier(transferWrite, hostRead);
2789 const auto copyRegion = makeBufferImageCopy(imageExtent, colorSRL);
2790
2791 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
2792 vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
2793 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
2794
2795 endCommandBuffer(vkd, cmdBuffer);
2796 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
2797
2798 // Generate reference image and compare results.
2799 const tcu::IVec3 iExtent (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), 1);
2800 const tcu::ConstPixelBufferAccess verificationAccess (tcuFormat, iExtent, verificationBufferData);
2801
2802 generateReferenceLevel();
2803 invalidateAlloc(vkd, device, verificationBufferAlloc);
2804 if (!verifyResult(verificationAccess))
2805 TCU_FAIL("Result does not match reference; check log for details");
2806
2807 return tcu::TestStatus::pass("Pass");
2808 }
2809
2810 // Use large work group size, large number of vertices and large number of primitives.
2811 struct MaximizeThreadsParams : public MiscTestParams
2812 {
MaximizeThreadsParamsvkt::MeshShader::__anond8548dd90111::MaximizeThreadsParams2813 MaximizeThreadsParams (const tcu::Maybe<tcu::UVec3>& taskCount_, const tcu::UVec3& meshCount_, uint32_t width_, uint32_t height_,
2814 uint32_t localSize_, uint32_t numVertices_, uint32_t numPrimitives_)
2815 : MiscTestParams (taskCount_, meshCount_, width_, height_)
2816 , localSize (localSize_)
2817 , numVertices (numVertices_)
2818 , numPrimitives (numPrimitives_)
2819 {}
2820
2821 uint32_t localSize;
2822 uint32_t numVertices;
2823 uint32_t numPrimitives;
2824
checkSupportvkt::MeshShader::__anond8548dd90111::MaximizeThreadsParams2825 void checkSupport (Context& context) const
2826 {
2827 const auto& properties = context.getMeshShaderPropertiesEXT();
2828
2829 if (localSize > properties.maxMeshWorkGroupSize[0])
2830 TCU_THROW(NotSupportedError, "Required local size not supported");
2831
2832 if (numVertices > properties.maxMeshOutputVertices)
2833 TCU_THROW(NotSupportedError, "Required number of output vertices not supported");
2834
2835 if (numPrimitives > properties.maxMeshOutputPrimitives)
2836 TCU_THROW(NotSupportedError, "Required number of output primitives not supported");
2837 }
2838 };
2839
2840 // Focus on the number of primitives.
2841 class MaximizePrimitivesCase : public MeshShaderMiscCase
2842 {
2843 public:
MaximizePrimitivesCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)2844 MaximizePrimitivesCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
2845 : MeshShaderMiscCase (testCtx, name, std::move(params))
2846 {
2847 const auto mtParams = dynamic_cast<MaximizeThreadsParams*>(m_params.get());
2848 DE_ASSERT(mtParams);
2849 DE_UNREF(mtParams); // For release builds.
2850 }
2851
2852 void initPrograms (vk::SourceCollections& programCollection) const override;
2853 void checkSupport (Context& context) const override;
2854 TestInstance* createInstance (Context& context) const override;
2855 };
2856
2857 class MaximizePrimitivesInstance : public MeshShaderMiscInstance
2858 {
2859 public:
MaximizePrimitivesInstance(Context & context,const MiscTestParams * params)2860 MaximizePrimitivesInstance (Context& context, const MiscTestParams* params)
2861 : MeshShaderMiscInstance (context, params)
2862 {}
2863
2864 void generateReferenceLevel () override;
2865 };
2866
createInstance(Context & context) const2867 TestInstance* MaximizePrimitivesCase::createInstance (Context& context) const
2868 {
2869 return new MaximizePrimitivesInstance (context, m_params.get());
2870 }
2871
checkSupport(Context & context) const2872 void MaximizePrimitivesCase::checkSupport (Context& context) const
2873 {
2874 MeshShaderMiscCase::checkSupport(context);
2875
2876 const auto params = dynamic_cast<MaximizeThreadsParams*>(m_params.get());
2877 params->checkSupport(context);
2878 }
2879
initPrograms(vk::SourceCollections & programCollection) const2880 void MaximizePrimitivesCase::initPrograms (vk::SourceCollections& programCollection) const
2881 {
2882 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
2883 const auto params = dynamic_cast<MaximizeThreadsParams*>(m_params.get());
2884
2885 DE_ASSERT(!params->needsTaskShader());
2886 MeshShaderMiscCase::initPrograms(programCollection);
2887
2888 // Idea behind the test: generate 128 vertices, 1 per each pixel in a 128x1 image. Then, use each vertex to generate two points,
2889 // adding the colors of each point using color blending to make sure every point is properly generated.
2890
2891 DE_ASSERT(params->numPrimitives == params->numVertices * 2u);
2892 DE_ASSERT(params->numVertices == params->width);
2893
2894 const auto verticesPerInvocation = params->numVertices / params->localSize;
2895 const auto primitivesPerVertex = params->numPrimitives / params->numVertices;
2896
2897 std::ostringstream mesh;
2898 mesh
2899 << "#version 450\n"
2900 << "#extension GL_EXT_mesh_shader : enable\n"
2901 << "\n"
2902 << "layout(local_size_x=" << params->localSize << ") in;\n"
2903 << "layout(points) out;\n"
2904 << "layout(max_vertices=" << params->numVertices << ", max_primitives=" << params->numPrimitives << ") out;\n"
2905 << "\n"
2906 << "layout (location=0) out perprimitiveEXT vec4 pointColor[];\n"
2907 << "\n"
2908 << "const uint verticesPerInvocation = " << verticesPerInvocation << ";\n"
2909 << "const uint primitivesPerVertex = " << primitivesPerVertex << ";\n"
2910 << "\n"
2911 << "vec4 colors[primitivesPerVertex] = vec4[](\n"
2912 << " vec4(0.0, 0.0, 1.0, 1.0),\n"
2913 << " vec4(1.0, 0.0, 0.0, 1.0)\n"
2914 << ");\n"
2915 << "void main ()\n"
2916 << "{\n"
2917 << " SetMeshOutputsEXT(" << params->numVertices << ", " << params->numPrimitives << ");\n"
2918 << " const uint firstVertex = gl_LocalInvocationIndex * verticesPerInvocation;\n"
2919 << " for (uint i = 0u; i < verticesPerInvocation; ++i)\n"
2920 << " {\n"
2921 << " const uint vertexNumber = firstVertex + i;\n"
2922 << " const float xCoord = ((float(vertexNumber) + 0.5) / " << params->width << ".0) * 2.0 - 1.0;\n"
2923 << " const float yCoord = 0.0;\n"
2924 << " gl_MeshVerticesEXT[vertexNumber].gl_Position = vec4(xCoord, yCoord, 0.0f, 1.0f);\n"
2925 << " gl_MeshVerticesEXT[vertexNumber].gl_PointSize = 1.0f;\n"
2926 << " for (uint j = 0u; j < primitivesPerVertex; ++j)\n"
2927 << " {\n"
2928 << " const uint primitiveNumber = vertexNumber * primitivesPerVertex + j;\n"
2929 << " gl_PrimitivePointIndicesEXT[primitiveNumber] = vertexNumber;\n"
2930 << " pointColor[primitiveNumber] = colors[j];\n"
2931 << " }\n"
2932 << " }\n"
2933 << "}\n"
2934 ;
2935 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
2936 }
2937
generateReferenceLevel()2938 void MaximizePrimitivesInstance::generateReferenceLevel ()
2939 {
2940 generateSolidRefLevel(tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
2941 }
2942
2943 // Focus on the number of vertices.
2944 class MaximizeVerticesCase : public MeshShaderMiscCase
2945 {
2946 public:
MaximizeVerticesCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)2947 MaximizeVerticesCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
2948 : MeshShaderMiscCase (testCtx, name, std::move(params))
2949 {
2950 const auto mtParams = dynamic_cast<MaximizeThreadsParams*>(m_params.get());
2951 DE_ASSERT(mtParams);
2952 DE_UNREF(mtParams); // For release builds.
2953 }
2954
2955 void initPrograms (vk::SourceCollections& programCollection) const override;
2956 void checkSupport (Context& context) const override;
2957 TestInstance* createInstance (Context& context) const override;
2958 };
2959
2960 class MaximizeVerticesInstance : public MeshShaderMiscInstance
2961 {
2962 public:
MaximizeVerticesInstance(Context & context,const MiscTestParams * params)2963 MaximizeVerticesInstance (Context& context, const MiscTestParams* params)
2964 : MeshShaderMiscInstance (context, params)
2965 {}
2966
2967 void generateReferenceLevel () override;
2968 };
2969
createInstance(Context & context) const2970 TestInstance* MaximizeVerticesCase::createInstance (Context& context) const
2971 {
2972 return new MaximizeVerticesInstance (context, m_params.get());
2973 }
2974
checkSupport(Context & context) const2975 void MaximizeVerticesCase::checkSupport (Context& context) const
2976 {
2977 MeshShaderMiscCase::checkSupport(context);
2978
2979 const auto params = dynamic_cast<MaximizeThreadsParams*>(m_params.get());
2980 params->checkSupport(context);
2981 }
2982
initPrograms(vk::SourceCollections & programCollection) const2983 void MaximizeVerticesCase::initPrograms (vk::SourceCollections& programCollection) const
2984 {
2985 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
2986 const auto params = dynamic_cast<MaximizeThreadsParams*>(m_params.get());
2987
2988 DE_ASSERT(!params->needsTaskShader());
2989 MeshShaderMiscCase::initPrograms(programCollection);
2990
2991 // Idea behind the test: cover a framebuffer using a triangle quad per pixel (4 vertices, 2 triangles).
2992 DE_ASSERT(params->numVertices == params->numPrimitives * 2u);
2993 DE_ASSERT(params->numPrimitives == params->width * 2u);
2994
2995 const auto pixelsPerInvocation = params->width / params->localSize;
2996 const auto verticesPerPixel = 4u;
2997 const auto primitivesPerPixel = 2u;
2998 const auto verticesPerInvocation = pixelsPerInvocation * verticesPerPixel;
2999 const auto primitivesPerInvocation = pixelsPerInvocation * primitivesPerPixel;
3000
3001 std::ostringstream mesh;
3002 mesh
3003 << "#version 450\n"
3004 << "#extension GL_EXT_mesh_shader : enable\n"
3005 << "\n"
3006 << "layout(local_size_x=" << params->localSize << ") in;\n"
3007 << "layout(triangles) out;\n"
3008 << "layout(max_vertices=" << params->numVertices << ", max_primitives=" << params->numPrimitives << ") out;\n"
3009 << "\n"
3010 << "layout (location=0) out perprimitiveEXT vec4 triangleColor[];\n"
3011 << "\n"
3012 << "const uint pixelsPerInvocation = " << pixelsPerInvocation << ";\n"
3013 << "const uint verticesPerInvocation = " << verticesPerInvocation << ";\n"
3014 << "const uint primitivesPerInvocation = " << primitivesPerInvocation << ";\n"
3015 << "const uint indicesPerInvocation = primitivesPerInvocation * 3u;\n"
3016 << "const uint verticesPerPixel = " << verticesPerPixel << ";\n"
3017 << "const uint primitivesPerPixel = " << primitivesPerPixel << ";\n"
3018 << "const uint indicesPerPixel = primitivesPerPixel * 3u;\n"
3019 << "\n"
3020 << "void main ()\n"
3021 << "{\n"
3022 << " SetMeshOutputsEXT(" << params->numVertices << ", " << params->numPrimitives << ");\n"
3023 << "\n"
3024 << " const uint firstPixel = gl_LocalInvocationIndex * pixelsPerInvocation;\n"
3025 << " const float pixelWidth = 2.0 / float(" << params->width << ");\n"
3026 << " const float quarterWidth = pixelWidth / 4.0;\n"
3027 << "\n"
3028 << " for (uint pixelIdx = 0u; pixelIdx < pixelsPerInvocation; ++pixelIdx)\n"
3029 << " {\n"
3030 << " const uint pixelId = firstPixel + pixelIdx;\n"
3031 << " const float pixelCenter = (float(pixelId) + 0.5) / float(" << params->width << ") * 2.0 - 1.0;\n"
3032 << " const float left = pixelCenter - quarterWidth;\n"
3033 << " const float right = pixelCenter + quarterWidth;\n"
3034 << "\n"
3035 << " const uint firstVertex = gl_LocalInvocationIndex * verticesPerInvocation + pixelIdx * verticesPerPixel;\n"
3036 << " gl_MeshVerticesEXT[firstVertex + 0].gl_Position = vec4(left, -1.0, 0.0f, 1.0f);\n"
3037 << " gl_MeshVerticesEXT[firstVertex + 1].gl_Position = vec4(left, 1.0, 0.0f, 1.0f);\n"
3038 << " gl_MeshVerticesEXT[firstVertex + 2].gl_Position = vec4(right, -1.0, 0.0f, 1.0f);\n"
3039 << " gl_MeshVerticesEXT[firstVertex + 3].gl_Position = vec4(right, 1.0, 0.0f, 1.0f);\n"
3040 << "\n"
3041 << " const uint firstPrimitive = gl_LocalInvocationIndex * primitivesPerInvocation + pixelIdx * primitivesPerPixel;\n"
3042 << " triangleColor[firstPrimitive + 0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
3043 << " triangleColor[firstPrimitive + 1] = vec4(0.0, 0.0, 1.0, 1.0);\n"
3044 << "\n"
3045 << " const uint firstIndex = gl_LocalInvocationIndex * indicesPerInvocation + pixelIdx * indicesPerPixel;\n"
3046 << " gl_PrimitiveTriangleIndicesEXT[firstPrimitive + 0] = uvec3(firstVertex + 0, firstVertex + 1, firstVertex + 2);\n"
3047 << " gl_PrimitiveTriangleIndicesEXT[firstPrimitive + 1] = uvec3(firstVertex + 1, firstVertex + 3, firstVertex + 2);\n"
3048 << " }\n"
3049 << "}\n"
3050 ;
3051 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
3052 }
3053
generateReferenceLevel()3054 void MaximizeVerticesInstance::generateReferenceLevel ()
3055 {
3056 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
3057 }
3058
3059 // Focus on the number of invocations.
3060 class MaximizeInvocationsCase : public MeshShaderMiscCase
3061 {
3062 public:
MaximizeInvocationsCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)3063 MaximizeInvocationsCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
3064 : MeshShaderMiscCase (testCtx, name, std::move(params))
3065 {
3066 const auto mtParams = dynamic_cast<MaximizeThreadsParams*>(m_params.get());
3067 DE_ASSERT(mtParams);
3068 DE_UNREF(mtParams); // For release builds.
3069 }
3070
3071 void initPrograms (vk::SourceCollections& programCollection) const override;
3072 void checkSupport (Context& context) const override;
3073 TestInstance* createInstance (Context& context) const override;
3074 };
3075
3076 class MaximizeInvocationsInstance : public MeshShaderMiscInstance
3077 {
3078 public:
MaximizeInvocationsInstance(Context & context,const MiscTestParams * params)3079 MaximizeInvocationsInstance (Context& context, const MiscTestParams* params)
3080 : MeshShaderMiscInstance (context, params)
3081 {}
3082
3083 void generateReferenceLevel () override;
3084 };
3085
createInstance(Context & context) const3086 TestInstance* MaximizeInvocationsCase::createInstance (Context& context) const
3087 {
3088 return new MaximizeInvocationsInstance (context, m_params.get());
3089 }
3090
checkSupport(Context & context) const3091 void MaximizeInvocationsCase::checkSupport (Context& context) const
3092 {
3093 MeshShaderMiscCase::checkSupport(context);
3094
3095 const auto params = dynamic_cast<MaximizeThreadsParams*>(m_params.get());
3096 params->checkSupport(context);
3097 }
3098
initPrograms(vk::SourceCollections & programCollection) const3099 void MaximizeInvocationsCase::initPrograms (vk::SourceCollections& programCollection) const
3100 {
3101 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
3102 const auto params = dynamic_cast<MaximizeThreadsParams*>(m_params.get());
3103
3104 DE_ASSERT(!params->needsTaskShader());
3105 MeshShaderMiscCase::initPrograms(programCollection);
3106
3107 // Idea behind the test: use two invocations to generate one point per framebuffer pixel.
3108 DE_ASSERT(params->localSize == params->width * 2u);
3109 DE_ASSERT(params->localSize == params->numPrimitives * 2u);
3110 DE_ASSERT(params->localSize == params->numVertices * 2u);
3111
3112 std::ostringstream mesh;
3113 mesh
3114 << "#version 450\n"
3115 << "#extension GL_EXT_mesh_shader : enable\n"
3116 << "\n"
3117 << "layout(local_size_x=" << params->localSize << ") in;\n"
3118 << "layout(points) out;\n"
3119 << "layout(max_vertices=" << params->numVertices << ", max_primitives=" << params->numPrimitives << ") out;\n"
3120 << "\n"
3121 << "layout (location=0) out perprimitiveEXT vec4 pointColor[];\n"
3122 << "\n"
3123 << "void main ()\n"
3124 << "{\n"
3125 << " SetMeshOutputsEXT(" << params->numVertices << ", " << params->numPrimitives << ");\n"
3126 << " const uint pixelId = gl_LocalInvocationIndex / 2u;\n"
3127 << " if (gl_LocalInvocationIndex % 2u == 0u)\n"
3128 << " {\n"
3129 << " const float xCoord = (float(pixelId) + 0.5) / float(" << params->width << ") * 2.0 - 1.0;\n"
3130 << " gl_MeshVerticesEXT[pixelId].gl_Position = vec4(xCoord, 0.0, 0.0f, 1.0f);\n"
3131 << " gl_MeshVerticesEXT[pixelId].gl_PointSize = 1.0f;\n"
3132 << " }\n"
3133 << " else\n"
3134 << " {\n"
3135 << " gl_PrimitivePointIndicesEXT[pixelId] = pixelId;\n"
3136 << " pointColor[pixelId] = vec4(0.0, 0.0, 1.0, 1.0);\n"
3137 << " }\n"
3138 << "}\n"
3139 ;
3140 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
3141 }
3142
generateReferenceLevel()3143 void MaximizeInvocationsInstance::generateReferenceLevel ()
3144 {
3145 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
3146 }
3147
3148 // Verify mixing classic and mesh shading pipelines in the same render pass.
3149 struct MixedPipelinesParams : public MiscTestParams
3150 {
3151 public:
3152 bool dynamicTopology;
3153
MixedPipelinesParamsvkt::MeshShader::__anond8548dd90111::MixedPipelinesParams3154 MixedPipelinesParams (const tcu::Maybe<tcu::UVec3>& taskCount_, const tcu::UVec3& meshCount_, uint32_t width_, uint32_t height_, bool dynamicTopology_)
3155 : MiscTestParams (taskCount_, meshCount_, width_, height_)
3156 , dynamicTopology (dynamicTopology_)
3157 {}
3158 };
3159
3160 // Global idea behind this case: draw 4 times with classic, mesh, classic and mesh pipelines. Each draw will use a full screen quad
3161 // and a dynamic scissor to restrict drawing in the framebuffer to one specific quadrant of the color attachment. The color of each
3162 // quadrant will be taken from a push constant that changes between steps, so each quadrant ends up with a different color.
3163 class MixedPipelinesCase : public MeshShaderMiscCase
3164 {
3165 public:
MixedPipelinesCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)3166 MixedPipelinesCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
3167 : MeshShaderMiscCase (testCtx, name, std::move(params))
3168 {}
3169
3170 void checkSupport (Context& context) const override;
3171 void initPrograms (vk::SourceCollections& programCollection) const override;
3172 TestInstance* createInstance (Context& context) const override;
3173 };
3174
3175 class MixedPipelinesInstance : public MeshShaderMiscInstance
3176 {
3177 public:
MixedPipelinesInstance(Context & context,const MiscTestParams * params)3178 MixedPipelinesInstance (Context& context, const MiscTestParams* params)
3179 : MeshShaderMiscInstance (context, params)
3180 {}
3181
3182 typedef std::pair<VkRect2D, tcu::Vec4> RectColor;
3183 typedef std::vector<RectColor> RectColorVec;
3184 RectColorVec getQuadrantColors ();
3185 tcu::Vec4 getClearColor ();
3186
3187 void generateReferenceLevel () override;
3188 tcu::TestStatus iterate () override;
3189
3190 };
3191
createInstance(Context & context) const3192 TestInstance* MixedPipelinesCase::createInstance (Context& context) const
3193 {
3194 return new MixedPipelinesInstance (context, m_params.get());
3195 }
3196
checkSupport(Context & context) const3197 void MixedPipelinesCase::checkSupport (Context& context) const
3198 {
3199 const auto params = dynamic_cast<MixedPipelinesParams*>(m_params.get());
3200 DE_ASSERT(params);
3201
3202 MeshShaderMiscCase::checkSupport(context);
3203
3204 if (params->dynamicTopology)
3205 context.requireDeviceFunctionality("VK_EXT_extended_dynamic_state");
3206 }
3207
initPrograms(vk::SourceCollections & programCollection) const3208 void MixedPipelinesCase::initPrograms (vk::SourceCollections& programCollection) const
3209 {
3210 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
3211
3212 DE_ASSERT(!m_params->needsTaskShader());
3213
3214 // The fragment shader will draw using the color indicated by the push constant.
3215 const std::string frag =
3216 "#version 450\n"
3217 "\n"
3218 "layout (location=0) out vec4 outColor;\n"
3219 "layout (push_constant, std430) uniform PushConstantBlock {\n"
3220 " vec4 color;\n"
3221 "} pc;\n"
3222 "\n"
3223 "void main ()\n"
3224 "{\n"
3225 " outColor = pc.color;\n"
3226 "}\n"
3227 ;
3228 programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
3229
3230 const std::string vert =
3231 "#version 450\n"
3232 "\n"
3233 "void main()\n"
3234 "{\n"
3235 // Full-screen clockwise triangle strip with 4 vertices.
3236 " const float x = (-1.0+2.0*((gl_VertexIndex & 2)>>1));\n"
3237 " const float y = ( 1.0-2.0* (gl_VertexIndex % 2));\n"
3238 " gl_Position = vec4(x, y, 0.0, 1.0);\n"
3239 "}\n"
3240 ;
3241 programCollection.glslSources.add("vert") << glu::VertexSource(vert);
3242
3243 const std::string mesh =
3244 "#version 450\n"
3245 "#extension GL_EXT_mesh_shader : enable\n"
3246 "\n"
3247 "layout(local_size_x=4) in;\n"
3248 "layout(triangles) out;\n"
3249 "layout(max_vertices=4, max_primitives=2) out;\n"
3250 "\n"
3251 "void main ()\n"
3252 "{\n"
3253 " SetMeshOutputsEXT(4u, 2u);\n"
3254 // Full-screen clockwise triangle strip with 4 vertices.
3255 " const float x = (-1.0+2.0*((gl_LocalInvocationIndex & 2)>>1));\n"
3256 " const float y = ( 1.0-2.0*((gl_LocalInvocationIndex & 1) ));\n"
3257 " gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = vec4(x, y, 0.0, 1.0);\n"
3258 " if (gl_LocalInvocationIndex == 0u) {\n"
3259 " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0u, 1u, 2u);\n"
3260 " gl_PrimitiveTriangleIndicesEXT[1] = uvec3(2u, 1u, 3u);\n"
3261 " }\n"
3262 "}\n"
3263 ;
3264 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh) << buildOptions;
3265 }
3266
getQuadrantColors()3267 MixedPipelinesInstance::RectColorVec MixedPipelinesInstance::getQuadrantColors ()
3268 {
3269 const auto width = m_params->width;
3270 const auto height = m_params->height;
3271 const auto halfWidth = width / 2u;
3272 const auto halfHeight = height / 2u;
3273 const auto iHalfWidth = static_cast<int>(halfWidth);
3274 const auto iHalfHeight = static_cast<int>(halfHeight);
3275
3276 DE_ASSERT(width % 2u == 0u);
3277 DE_ASSERT(height % 2u == 0u);
3278
3279 // Associate a different color to each rectangle.
3280 const RectColorVec quadrantColors {
3281 std::make_pair(makeRect2D(0, 0, halfWidth, halfHeight), tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f)),
3282 std::make_pair(makeRect2D(0, iHalfHeight, halfWidth, halfHeight), tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f)),
3283 std::make_pair(makeRect2D(iHalfWidth, 0, halfWidth, halfHeight), tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f)),
3284 std::make_pair(makeRect2D(iHalfWidth, iHalfHeight, halfWidth, halfHeight), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)),
3285 };
3286 return quadrantColors;
3287 }
3288
getClearColor()3289 tcu::Vec4 MixedPipelinesInstance::getClearColor ()
3290 {
3291 return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
3292 }
3293
generateReferenceLevel()3294 void MixedPipelinesInstance::generateReferenceLevel ()
3295 {
3296 const auto format = getOutputFormat();
3297 const auto tcuFormat = mapVkFormat(format);
3298
3299 const auto iWidth = static_cast<int>(m_params->width);
3300 const auto iHeight = static_cast<int>(m_params->height);
3301
3302 m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
3303
3304 const auto access = m_referenceLevel->getAccess();
3305 const auto quadColors = getQuadrantColors();
3306 const auto clearColor = getClearColor();
3307
3308 // Each image quadrant gets a different color.
3309 tcu::clear(access, clearColor);
3310
3311 for (int y = 0; y < iHeight; ++y)
3312 for (int x = 0; x < iWidth; ++x)
3313 {
3314 for (const auto& quadrant : quadColors)
3315 {
3316 const auto minX = quadrant.first.offset.x;
3317 const auto minY = quadrant.first.offset.y;
3318 const auto maxX = quadrant.first.offset.x + static_cast<int32_t>(quadrant.first.extent.width);
3319 const auto maxY = quadrant.first.offset.y + static_cast<int32_t>(quadrant.first.extent.height);
3320
3321 if (x >= minX && x < maxX && y >= minY && y < maxY)
3322 access.setPixel(quadrant.second, x, y);
3323 }
3324 }
3325 }
3326
iterate()3327 tcu::TestStatus MixedPipelinesInstance::iterate ()
3328 {
3329 const auto params = dynamic_cast<const MixedPipelinesParams*>(m_params);
3330 DE_ASSERT(params);
3331
3332 const auto& vkd = m_context.getDeviceInterface();
3333 const auto device = m_context.getDevice();
3334 auto& alloc = m_context.getDefaultAllocator();
3335 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
3336 const auto queue = m_context.getUniversalQueue();
3337
3338 const auto dynTopo = params->dynamicTopology;
3339 const auto imageFormat = getOutputFormat();
3340 const auto tcuFormat = mapVkFormat(imageFormat);
3341 const auto imageExtent = makeExtent3D(m_params->width, m_params->height, 1u);
3342 const auto imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
3343
3344 const VkImageCreateInfo colorBufferInfo =
3345 {
3346 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
3347 nullptr, // const void* pNext;
3348 0u, // VkImageCreateFlags flags;
3349 VK_IMAGE_TYPE_2D, // VkImageType imageType;
3350 imageFormat, // VkFormat format;
3351 imageExtent, // VkExtent3D extent;
3352 1u, // uint32_t mipLevels;
3353 1u, // uint32_t arrayLayers;
3354 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
3355 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
3356 imageUsage, // VkImageUsageFlags usage;
3357 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
3358 0u, // uint32_t queueFamilyIndexCount;
3359 nullptr, // const uint32_t* pQueueFamilyIndices;
3360 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
3361 };
3362
3363 // Create color image and view.
3364 ImageWithMemory colorImage (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
3365 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
3366 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
3367 const auto colorView = makeImageView(vkd, device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
3368
3369 // Create a memory buffer for verification.
3370 const auto verificationBufferSize = static_cast<VkDeviceSize>(imageExtent.width * imageExtent.height * tcu::getPixelSize(tcuFormat));
3371 const auto verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
3372 const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
3373
3374 BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
3375 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
3376 void* verificationBufferData = verificationBufferAlloc.getHostPtr();
3377
3378 // Pipeline layouts for the mesh and classic pipelines.
3379 const auto pcSize = static_cast<uint32_t>(sizeof(tcu::Vec4));
3380 const auto pcRange = makePushConstantRange(VK_SHADER_STAGE_FRAGMENT_BIT, 0u, pcSize);
3381 const auto classicPipelineLayout = makePipelineLayout(vkd, device, DE_NULL, &pcRange);
3382 const auto meshPipelineLayout = makePipelineLayout(vkd, device, DE_NULL, &pcRange);
3383
3384 // Shader modules.
3385 const auto& binaries = m_context.getBinaryCollection();
3386 const auto vertShader = createShaderModule(vkd, device, binaries.get("vert"));
3387 const auto meshShader = createShaderModule(vkd, device, binaries.get("mesh"));
3388 const auto fragShader = createShaderModule(vkd, device, binaries.get("frag"));
3389
3390 // Render pass.
3391 const auto renderPass = makeRenderPass(vkd, device, imageFormat);
3392
3393 // Framebuffer.
3394 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), imageExtent.width, imageExtent.height);
3395
3396 // Viewport and scissor.
3397 const std::vector<VkViewport> viewports (1u, makeViewport(imageExtent));
3398 const std::vector<VkRect2D> scissors (1u, makeRect2D(imageExtent));
3399
3400 // Color blending.
3401 const auto colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
3402 const VkPipelineColorBlendAttachmentState blendAttState =
3403 {
3404 VK_TRUE, // VkBool32 blendEnable;
3405 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
3406 VK_BLEND_FACTOR_ONE, // VkBlendFactor dstColorBlendFactor;
3407 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
3408 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
3409 VK_BLEND_FACTOR_ONE, // VkBlendFactor dstAlphaBlendFactor;
3410 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
3411 colorWriteMask, // VkColorComponentFlags colorWriteMask;
3412 };
3413
3414 const VkPipelineColorBlendStateCreateInfo colorBlendInfo =
3415 {
3416 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
3417 nullptr, // const void* pNext;
3418 0u, // VkPipelineColorBlendStateCreateFlags flags;
3419 VK_FALSE, // VkBool32 logicOpEnable;
3420 VK_LOGIC_OP_OR, // VkLogicOp logicOp;
3421 1u, // uint32_t attachmentCount;
3422 &blendAttState, // const VkPipelineColorBlendAttachmentState* pAttachments;
3423 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
3424 };
3425
3426 const std::vector<VkDynamicState> meshDynamicStates { VK_DYNAMIC_STATE_SCISSOR };
3427 std::vector<VkDynamicState> classicDynamicStates (meshDynamicStates);
3428 if (dynTopo)
3429 classicDynamicStates.push_back(VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT);
3430
3431 const VkPipelineDynamicStateCreateInfo meshDynamicStateInfo =
3432 {
3433 VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
3434 nullptr, // const void* pNext;
3435 0u, // VkPipelineDynamicStateCreateFlags flags;
3436 static_cast<uint32_t>(meshDynamicStates.size()), // uint32_t dynamicStateCount;
3437 de::dataOrNull(meshDynamicStates), // const VkDynamicState* pDynamicStates;
3438 };
3439 const VkPipelineDynamicStateCreateInfo classicDynamicStateInfo =
3440 {
3441 VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
3442 nullptr, // const void* pNext;
3443 0u, // VkPipelineDynamicStateCreateFlags flags;
3444 static_cast<uint32_t>(classicDynamicStates.size()), // uint32_t dynamicStateCount;
3445 de::dataOrNull(classicDynamicStates), // const VkDynamicState* pDynamicStates;
3446 };
3447
3448 const auto meshPipeline = makeGraphicsPipeline(vkd, device, meshPipelineLayout.get(),
3449 DE_NULL, meshShader.get(), fragShader.get(),
3450 renderPass.get(), viewports, scissors, 0u/*subpass*/,
3451 nullptr, nullptr, nullptr, &colorBlendInfo, &meshDynamicStateInfo);
3452
3453 const VkPipelineVertexInputStateCreateInfo vertexInputInfo = initVulkanStructure();
3454
3455 const auto staticTopo = (dynTopo ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
3456 const auto classicPipeline = makeGraphicsPipeline(vkd, device, classicPipelineLayout.get(),
3457 vertShader.get(), DE_NULL, DE_NULL, DE_NULL, fragShader.get(),
3458 renderPass.get(), viewports, scissors, staticTopo, 0u/*subpass*/, 0u/*patchControlPoints*/,
3459 &vertexInputInfo, nullptr, nullptr, nullptr, nullptr, &classicDynamicStateInfo);
3460
3461 // Command pool and buffer.
3462 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
3463 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
3464 const auto cmdBuffer = cmdBufferPtr.get();
3465
3466 // Pipeline list.
3467 beginCommandBuffer(vkd, cmdBuffer);
3468
3469 // Run pipeline.
3470 const auto clearColor = getClearColor();
3471 const auto drawCount = m_params->drawCount();
3472 const auto quadColors = getQuadrantColors();
3473 DE_ASSERT(drawCount.x() == 1u && drawCount.y() == 1u && drawCount.z() == 1u);
3474
3475 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
3476 for (size_t idx = 0u; idx < quadColors.size(); ++idx)
3477 {
3478 const auto& rectColor = quadColors.at(idx);
3479 vkd.cmdSetScissor(cmdBuffer, 0u, 1u, &rectColor.first);
3480
3481 if (idx % 2u == 0u)
3482 {
3483 vkd.cmdPushConstants(cmdBuffer, classicPipelineLayout.get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0u, pcSize, &rectColor.second);
3484 if (dynTopo)
3485 vkd.cmdSetPrimitiveTopology(cmdBuffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
3486 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, classicPipeline.get());
3487 vkd.cmdDraw(cmdBuffer, 4u, 1u, 0u, 0u);
3488 }
3489 else
3490 {
3491 vkd.cmdPushConstants(cmdBuffer, meshPipelineLayout.get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0u, pcSize, &rectColor.second);
3492 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, meshPipeline.get());
3493 vkd.cmdDrawMeshTasksEXT(cmdBuffer, drawCount.x(), drawCount.y(), drawCount.z());
3494 }
3495 }
3496 endRenderPass(vkd, cmdBuffer);
3497
3498 // Copy color buffer to verification buffer.
3499 const auto colorAccess = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
3500 const auto transferRead = VK_ACCESS_TRANSFER_READ_BIT;
3501 const auto transferWrite = VK_ACCESS_TRANSFER_WRITE_BIT;
3502 const auto hostRead = VK_ACCESS_HOST_READ_BIT;
3503
3504 const auto preCopyBarrier = makeImageMemoryBarrier(colorAccess, transferRead, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSRR);
3505 const auto postCopyBarrier = makeMemoryBarrier(transferWrite, hostRead);
3506 const auto copyRegion = makeBufferImageCopy(imageExtent, colorSRL);
3507
3508 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
3509 vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
3510 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
3511
3512 endCommandBuffer(vkd, cmdBuffer);
3513 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
3514
3515 // Generate reference image and compare results.
3516 const tcu::IVec3 iExtent (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), 1);
3517 const tcu::ConstPixelBufferAccess verificationAccess (tcuFormat, iExtent, verificationBufferData);
3518
3519 generateReferenceLevel();
3520 invalidateAlloc(vkd, device, verificationBufferAlloc);
3521 if (!verifyResult(verificationAccess))
3522 TCU_FAIL("Result does not match reference; check log for details");
3523
3524 return tcu::TestStatus::pass("Pass");
3525 }
3526
3527 // Tests to check SetMeshOutputsEXT() and EmitMeshTasksEXT() take values from the first invocation.
3528 class FirstInvocationCase : public MeshShaderMiscCase
3529 {
3530 public:
FirstInvocationCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)3531 FirstInvocationCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
3532 : MeshShaderMiscCase (testCtx, name, std::move(params))
3533 {}
3534
3535 void checkSupport (Context& context) const override;
3536 void initPrograms (vk::SourceCollections& programCollection) const override;
3537 TestInstance* createInstance (Context& context) const override;
3538
3539 static constexpr uint32_t kColoredPixels = 120u;
3540 };
3541
3542 class FirstInvocationInstance : public MeshShaderMiscInstance
3543 {
3544 public:
FirstInvocationInstance(Context & context,const MiscTestParams * params)3545 FirstInvocationInstance (Context& context, const MiscTestParams* params)
3546 : MeshShaderMiscInstance (context, params)
3547 {}
3548
3549 void generateReferenceLevel () override;
3550 };
3551
generateReferenceLevel()3552 void FirstInvocationInstance::generateReferenceLevel ()
3553 {
3554 DE_ASSERT(m_params->height == 1u && m_params->width == 128u);
3555 DE_ASSERT(FirstInvocationCase::kColoredPixels < m_params->width);
3556
3557 const auto format = getOutputFormat();
3558 const auto tcuFormat = mapVkFormat(format);
3559
3560 const auto iWidth = static_cast<int>(m_params->width);
3561 const auto iHeight = static_cast<int>(m_params->height);
3562
3563 m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
3564
3565 const auto clearColor = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
3566 const auto geomColor = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
3567 const auto access = m_referenceLevel->getAccess();
3568
3569 // Fill the expected amount of colored pixels with solid color.
3570 for (int i = 0; i < iWidth; ++i)
3571 {
3572 const auto& color = ((static_cast<uint32_t>(i) < FirstInvocationCase::kColoredPixels) ? geomColor : clearColor);
3573 access.setPixel(color, i, 0);
3574 }
3575 }
3576
createInstance(Context & context) const3577 TestInstance* FirstInvocationCase::createInstance (Context& context) const
3578 {
3579 return new FirstInvocationInstance(context, m_params.get());
3580 }
3581
checkSupport(Context & context) const3582 void FirstInvocationCase::checkSupport (Context &context) const
3583 {
3584 MeshShaderMiscCase::checkSupport(context);
3585
3586 if (context.getUsedApiVersion() < VK_MAKE_VERSION(1, 1, 0))
3587 TCU_THROW(NotSupportedError, "Vulkan API version >= 1.1 required");
3588
3589 const auto &subgroupProperties = context.getSubgroupProperties();
3590 if (!(subgroupProperties.supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT))
3591 TCU_THROW(NotSupportedError, "Subgroup basic features not supported");
3592 }
3593
initPrograms(vk::SourceCollections & programCollection) const3594 void FirstInvocationCase::initPrograms (vk::SourceCollections& programCollection) const
3595 {
3596 DE_ASSERT(m_params->height == 1u && m_params->width == 128u);
3597 DE_ASSERT(kColoredPixels < m_params->width);
3598
3599 // Add generic fragment shader.
3600 MeshShaderMiscCase::initPrograms(programCollection);
3601
3602 const bool useTask = m_params->needsTaskShader();
3603 const auto fbWidth = m_params->width;
3604 const auto meshLocalSize = (useTask ? 1u : fbWidth);
3605 const auto taskLocalSize = fbWidth;
3606 const auto pointsPerMeshWG = (useTask ? 1u : kColoredPixels);
3607 const auto jobID = (useTask ? "gl_WorkGroupID.x" : "gl_LocalInvocationIndex");
3608 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
3609
3610 std::string taskDataDecl;
3611 if (useTask)
3612 {
3613 std::ostringstream aux;
3614 aux
3615 << "struct TaskData {\n"
3616 << " uint values[" << taskLocalSize << "];\n"
3617 << "};\n"
3618 << "taskPayloadSharedEXT TaskData td;\n"
3619 ;
3620 taskDataDecl = aux.str();
3621 }
3622
3623 if (useTask)
3624 {
3625 std::ostringstream task;
3626 task
3627 << "#version 450\n"
3628 << "#extension GL_EXT_mesh_shader : enable\n"
3629 << "#extension GL_KHR_shader_subgroup_basic : enable\n"
3630 << "\n"
3631 << "layout(local_size_x=" << taskLocalSize << ", local_size_y=1, local_size_z=1) in;\n"
3632 << "\n"
3633 << taskDataDecl
3634 << "\n"
3635 << "void main ()\n"
3636 << "{\n"
3637 << " td.values[gl_LocalInvocationIndex] = gl_LocalInvocationIndex * 2u;\n"
3638 << "\n"
3639 << " uint total_jobs = max(" << kColoredPixels << " / 2u, 1u);\n"
3640 << " if (gl_LocalInvocationIndex == 0u) {\n"
3641 << " total_jobs = " << kColoredPixels << ";\n"
3642 << " } else if (gl_SubgroupID > 0u) {\n"
3643 << " total_jobs = max(" << kColoredPixels << " / 4u, 1u);\n"
3644 << " }\n"
3645 << "\n"
3646 << " EmitMeshTasksEXT(total_jobs, 1u, 1u);\n"
3647 << "}\n"
3648 ;
3649
3650 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
3651 }
3652
3653 {
3654 std::ostringstream mesh;
3655 mesh
3656 << "#version 450\n"
3657 << "#extension GL_EXT_mesh_shader : enable\n"
3658 << "#extension GL_KHR_shader_subgroup_basic : enable\n"
3659 << "\n"
3660 << "layout(local_size_x=" << meshLocalSize << ", local_size_y=1, local_size_z=1) in;\n"
3661 << "layout(points) out;\n"
3662 << "layout(max_primitives=" << meshLocalSize << ", max_vertices=" << meshLocalSize << ") out;\n"
3663 << "\n"
3664 << "layout (location=0) out perprimitiveEXT vec4 pointColor[];\n"
3665 << taskDataDecl
3666 << "\n"
3667 << "void main ()\n"
3668 << "{\n"
3669 << " uint total_points = max(" << pointsPerMeshWG << " / 2u, 1u);\n"
3670 << " \n"
3671 ;
3672
3673 if (!useTask)
3674 {
3675 mesh
3676 << " if (gl_LocalInvocationIndex == 0u) {\n"
3677 << " total_points = " << pointsPerMeshWG << ";\n"
3678 << " } else if (gl_SubgroupID > 0u) {\n"
3679 << " total_points = max(" << pointsPerMeshWG << " / 4u, 1u);\n"
3680 << " }\n"
3681 << " \n"
3682 ;
3683 }
3684
3685 mesh
3686 << " SetMeshOutputsEXT(total_points, total_points);\n"
3687 << " if (gl_LocalInvocationIndex < " << pointsPerMeshWG << ") {\n"
3688 << " gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_PointSize = 1.0;\n"
3689 << " gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = vec4(((float(" << jobID << ") + 0.5) / " << fbWidth << ") * 2.0 - 1.0, 0.0, 0.0, 1.0);\n"
3690 << " gl_PrimitivePointIndicesEXT[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;\n"
3691 << " pointColor[gl_LocalInvocationIndex] = vec4(0.0, 0.0, 1.0, 1.0);\n"
3692 << " }\n"
3693 << "}\n"
3694 ;
3695
3696 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
3697 }
3698 }
3699
3700 // Tests that check LocalSizeId works as expected.
3701 class LocalSizeIdCase : public MeshShaderMiscCase
3702 {
3703 public:
LocalSizeIdCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)3704 LocalSizeIdCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
3705 : MeshShaderMiscCase (testCtx, name, std::move(params))
3706 {}
3707
3708 void checkSupport (Context& context) const override;
3709 void initPrograms (vk::SourceCollections& programCollection) const override;
3710 TestInstance* createInstance (Context& context) const override;
3711 };
3712
3713 class LocalSizeIdInstance : public MeshShaderMiscInstance
3714 {
3715 public:
LocalSizeIdInstance(Context & context,const MiscTestParams * params)3716 LocalSizeIdInstance (Context& context, const MiscTestParams* params)
3717 : MeshShaderMiscInstance (context, params)
3718 {}
3719
3720 void generateReferenceLevel () override;
3721 tcu::TestStatus iterate () override;
3722 };
3723
createInstance(Context & context) const3724 TestInstance* LocalSizeIdCase::createInstance (Context& context) const
3725 {
3726 return new LocalSizeIdInstance(context, m_params.get());
3727 }
3728
generateReferenceLevel()3729 void LocalSizeIdInstance::generateReferenceLevel ()
3730 {
3731 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
3732 }
3733
checkSupport(Context & context) const3734 void LocalSizeIdCase::checkSupport (Context &context) const
3735 {
3736 // Generic checks.
3737 MeshShaderMiscCase::checkSupport(context);
3738
3739 // Needed for LocalSizeId.
3740 context.requireDeviceFunctionality("VK_KHR_maintenance4");
3741 }
3742
initPrograms(vk::SourceCollections & programCollection) const3743 void LocalSizeIdCase::initPrograms (vk::SourceCollections& programCollection) const
3744 {
3745 const SpirVAsmBuildOptions spvOptions (programCollection.usedVulkanVersion, SPIRV_VERSION_1_5, false/*allowSpirv14*/, true/*allowMaintenance4*/);
3746 const auto useTask = m_params->needsTaskShader();
3747
3748 DE_ASSERT(m_params->height == 1u && m_params->width == 32u);
3749
3750 // Add generic fragment shader.
3751 MeshShaderMiscCase::initPrograms(programCollection);
3752
3753 if (useTask)
3754 {
3755 // Roughly equivalent to the following shader.
3756 // #version 450
3757 // #extension GL_EXT_mesh_shader : enable
3758 //
3759 // layout(local_size_x_id=10, local_size_y_id=11, local_size_z_id=12) in;
3760 // struct TaskData {
3761 // uint pixelID[32];
3762 // };
3763 // taskPayloadSharedEXT TaskData td;
3764 //
3765 // void main ()
3766 // {
3767 // td.pixelID[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;
3768 // EmitMeshTasksEXT(1u, 1u, 1u);
3769 // }
3770
3771 std::ostringstream taskSPV;
3772 taskSPV
3773 << " ; SPIR-V\n"
3774 << " ; Version: 1.0\n"
3775 << " ; Generator: Khronos Glslang Reference Front End; 10\n"
3776 << " ; Bound: 26\n"
3777 << " ; Schema: 0\n"
3778 << " OpCapability MeshShadingEXT\n"
3779 << " OpExtension \"SPV_EXT_mesh_shader\"\n"
3780 << " %1 = OpExtInstImport \"GLSL.std.450\"\n"
3781 << " OpMemoryModel Logical GLSL450\n"
3782 << " OpEntryPoint TaskEXT %4 \"main\" %11 %15\n"
3783 << " OpExecutionModeId %4 LocalSizeId %21 %22 %23\n"
3784 << " OpDecorate %15 BuiltIn LocalInvocationIndex\n"
3785 << " OpDecorate %21 SpecId 10\n"
3786 << " OpDecorate %22 SpecId 11\n"
3787 << " OpDecorate %23 SpecId 12\n"
3788 << " %2 = OpTypeVoid\n"
3789 << " %3 = OpTypeFunction %2\n"
3790 << " %6 = OpTypeInt 32 0\n"
3791 << " %7 = OpConstant %6 32\n"
3792 << " %8 = OpTypeArray %6 %7\n"
3793 << " %9 = OpTypeStruct %8\n"
3794 << "%10 = OpTypePointer TaskPayloadWorkgroupEXT %9\n"
3795 << "%11 = OpVariable %10 TaskPayloadWorkgroupEXT\n"
3796 << "%12 = OpTypeInt 32 1\n"
3797 << "%13 = OpConstant %12 0\n"
3798 << "%14 = OpTypePointer Input %6\n"
3799 << "%15 = OpVariable %14 Input\n"
3800 << "%18 = OpTypePointer TaskPayloadWorkgroupEXT %6\n"
3801 << "%20 = OpConstant %6 1\n"
3802 << "%21 = OpSpecConstant %6 1\n"
3803 << "%22 = OpSpecConstant %6 1\n"
3804 << "%23 = OpSpecConstant %6 1\n"
3805 << " %4 = OpFunction %2 None %3\n"
3806 << " %5 = OpLabel\n"
3807 << "%16 = OpLoad %6 %15\n"
3808 << "%17 = OpLoad %6 %15\n"
3809 << "%19 = OpAccessChain %18 %11 %13 %16\n"
3810 << " OpStore %19 %17\n"
3811 << " OpEmitMeshTasksEXT %20 %20 %20 %11\n"
3812 << " OpFunctionEnd\n"
3813 ;
3814
3815 programCollection.spirvAsmSources.add("task") << taskSPV.str() << spvOptions;
3816 }
3817
3818 {
3819 // Roughly equivalent to the following shader.
3820 // #version 450
3821 // #extension GL_EXT_mesh_shader : enable
3822 //
3823 // layout(local_size_x_id=20, local_size_y_id=21, local_size_z_id=22) in;
3824 // layout(points) out;
3825 // layout(max_primitives=32, max_vertices=32) out;
3826 //
3827 // layout (location=0) out perprimitiveEXT vec4 pointColor[];
3828 //#if useTask
3829 // struct TaskData {
3830 // uint pixelID[32];
3831 // };
3832 // taskPayloadSharedEXT TaskData td;
3833 //#endif
3834 //
3835 // void main ()
3836 // {
3837 //#if useTask
3838 // const uint pixelId = td.pixelID[gl_LocalInvocationIndex];
3839 //#else
3840 // const uint pixelId = gl_LocalInvocationIndex;
3841 //#endif
3842 // SetMeshOutputsEXT(32u, 32u);
3843 // gl_MeshVerticesEXT[pixelId].gl_PointSize = 1.0;
3844 // gl_MeshVerticesEXT[pixelId].gl_Position = vec4(((float(pixelId) + 0.5) / 32.0) * 2.0 - 1.0, 0.0, 0.0, 1.0);
3845 // gl_PrimitivePointIndicesEXT[pixelId] = pixelId;
3846 // pointColor[pixelId] = vec4(0.0, 0.0, 1.0, 1.0);
3847 // }
3848 std::ostringstream meshSPV;
3849 meshSPV
3850 << " OpCapability MeshShadingEXT\n"
3851 << " OpExtension \"SPV_EXT_mesh_shader\"\n"
3852 << " %1 = OpExtInstImport \"GLSL.std.450\"\n"
3853 << " OpMemoryModel Logical GLSL450\n"
3854 << " OpEntryPoint MeshEXT %main \"main\" %local_invocation_index %mesh_vertices %primitive_point_indices %primitive_colors" << (useTask ? " %task_data" : "") << "\n"
3855 << " OpExecutionModeId %main LocalSizeId %constand_id_20 %constant_id_21 %constant_id_22\n"
3856 << " OpExecutionMode %main OutputVertices 32\n"
3857 << " OpExecutionMode %main OutputPrimitivesNV 32\n"
3858 << " OpExecutionMode %main OutputPoints\n"
3859 << " OpDecorate %local_invocation_index BuiltIn LocalInvocationIndex\n"
3860 << " OpMemberDecorate %mesh_vertices_struct 0 BuiltIn Position\n"
3861 << " OpMemberDecorate %mesh_vertices_struct 1 BuiltIn PointSize\n"
3862 << " OpMemberDecorate %mesh_vertices_struct 2 BuiltIn ClipDistance\n"
3863 << " OpMemberDecorate %mesh_vertices_struct 3 BuiltIn CullDistance\n"
3864 << " OpDecorate %mesh_vertices_struct Block\n"
3865 << " OpDecorate %primitive_point_indices BuiltIn PrimitivePointIndicesEXT\n"
3866 << " OpDecorate %primitive_colors PerPrimitiveEXT\n"
3867 << " OpDecorate %primitive_colors Location 0\n"
3868 << " OpDecorate %constand_id_20 SpecId 20\n"
3869 << " OpDecorate %constant_id_21 SpecId 21\n"
3870 << " OpDecorate %constant_id_22 SpecId 22\n"
3871 << " %type_void = OpTypeVoid\n"
3872 << " %void_func = OpTypeFunction %type_void\n"
3873 << " %int = OpTypeInt 32 1\n"
3874 << " %uint = OpTypeInt 32 0\n"
3875 << " %float = OpTypeFloat 32\n"
3876 << " %vec4 = OpTypeVector %float 4\n"
3877 << " %uvec3 = OpTypeVector %uint 3\n"
3878 << " %int_0 = OpConstant %int 0\n"
3879 << " %int_1 = OpConstant %int 1\n"
3880 << " %uint_1 = OpConstant %uint 1\n"
3881 << " %uint_32 = OpConstant %uint 32\n"
3882 << " %float_0 = OpConstant %float 0\n"
3883 << " %float_1 = OpConstant %float 1\n"
3884 << " %float_0_5 = OpConstant %float 0.5\n"
3885 << " %float_32 = OpConstant %float 32\n"
3886 << " %float_2 = OpConstant %float 2\n"
3887 << " %float_array_1 = OpTypeArray %float %uint_1\n"
3888 << " %func_uint_ptr = OpTypePointer Function %uint\n"
3889 << " %input_uint_ptr = OpTypePointer Input %uint\n"
3890 << " %local_invocation_index = OpVariable %input_uint_ptr Input\n"
3891 << " %mesh_vertices_struct = OpTypeStruct %vec4 %float %float_array_1 %float_array_1\n"
3892 << " %mesh_vertices_array = OpTypeArray %mesh_vertices_struct %uint_32\n"
3893 << " %mesh_vertices_out_ptr = OpTypePointer Output %mesh_vertices_array\n"
3894 << " %mesh_vertices = OpVariable %mesh_vertices_out_ptr Output\n"
3895 << " %output_float_ptr = OpTypePointer Output %float\n"
3896 << " %output_vec4_ptr = OpTypePointer Output %vec4\n"
3897 << " %uint_array_32 = OpTypeArray %uint %uint_32\n"
3898 << "\n"
3899 ;
3900
3901 if (useTask)
3902 {
3903 meshSPV
3904 << "\n"
3905 << "%uint_array_32_struct = OpTypeStruct %uint_array_32\n"
3906 << "%task_payload_uint_array_32_struct_ptr = OpTypePointer TaskPayloadWorkgroupEXT %uint_array_32_struct\n"
3907 << "%task_data = OpVariable %task_payload_uint_array_32_struct_ptr TaskPayloadWorkgroupEXT\n"
3908 << "%task_payload_uint_ptr = OpTypePointer TaskPayloadWorkgroupEXT %uint\n"
3909 << "\n"
3910 ;
3911 }
3912
3913 meshSPV
3914 << " %output_uint_array_32_ptr = OpTypePointer Output %uint_array_32\n"
3915 << " %primitive_point_indices = OpVariable %output_uint_array_32_ptr Output\n"
3916 << " %output_uint_ptr = OpTypePointer Output %uint\n"
3917 << " %vec4_array_32 = OpTypeArray %vec4 %uint_32\n"
3918 << " %output_vec4_array_32_ptr = OpTypePointer Output %vec4_array_32\n"
3919 << " %primitive_colors = OpVariable %output_vec4_array_32_ptr Output\n"
3920 << " %blue = OpConstantComposite %vec4 %float_0 %float_0 %float_1 %float_1\n"
3921 << " %constand_id_20 = OpSpecConstant %uint 1\n"
3922 << " %constant_id_21 = OpSpecConstant %uint 1\n"
3923 << " %constant_id_22 = OpSpecConstant %uint 1\n"
3924 << " %main = OpFunction %type_void None %void_func\n"
3925 << " %main_label = OpLabel\n"
3926 << " %pixel_id = OpVariable %func_uint_ptr Function\n"
3927 << "%local_invocation_index_val = OpLoad %uint %local_invocation_index\n"
3928 ;
3929
3930 if (useTask)
3931 {
3932 meshSPV
3933 << " %td_pixel_id_ptr = OpAccessChain %task_payload_uint_ptr %task_data %int_0 %local_invocation_index_val\n"
3934 << " %td_pixel_id_val = OpLoad %uint %td_pixel_id_ptr\n"
3935 << " OpStore %pixel_id %td_pixel_id_val\n"
3936 ;
3937 }
3938 else
3939 {
3940 meshSPV << " OpStore %pixel_id %local_invocation_index_val\n";
3941 }
3942
3943 meshSPV
3944 << " OpSetMeshOutputsEXT %uint_32 %uint_32\n"
3945 << " %pixel_id_val = OpLoad %uint %pixel_id\n"
3946 << " %point_size = OpAccessChain %output_float_ptr %mesh_vertices %pixel_id_val %int_1\n"
3947 << " OpStore %point_size %float_1\n"
3948 << " %pixel_id_val_float = OpConvertUToF %float %pixel_id_val\n"
3949 << " %pixel_id_val_center = OpFAdd %float %pixel_id_val_float %float_0_5\n"
3950 << " %x_unorm = OpFDiv %float %pixel_id_val_center %float_32\n"
3951 << " %x_unorm_2 = OpFMul %float %x_unorm %float_2\n"
3952 << " %x_norm = OpFSub %float %x_unorm_2 %float_1\n"
3953 << " %point_pos = OpCompositeConstruct %vec4 %x_norm %float_0 %float_0 %float_1\n"
3954 << " %gl_position_ptr = OpAccessChain %output_vec4_ptr %mesh_vertices %pixel_id_val %int_0\n"
3955 << " OpStore %gl_position_ptr %point_pos\n"
3956 << " %point_index_ptr = OpAccessChain %output_uint_ptr %primitive_point_indices %pixel_id_val\n"
3957 << " OpStore %point_index_ptr %pixel_id_val\n"
3958 << " %point_color_ptr = OpAccessChain %output_vec4_ptr %primitive_colors %pixel_id_val\n"
3959 << " OpStore %point_color_ptr %blue\n"
3960 << " OpReturn\n"
3961 << " OpFunctionEnd\n"
3962 ;
3963
3964 programCollection.spirvAsmSources.add("mesh") << meshSPV.str() << spvOptions;
3965 }
3966 }
3967
iterate()3968 tcu::TestStatus LocalSizeIdInstance::iterate ()
3969 {
3970 const auto& vkd = m_context.getDeviceInterface();
3971 const auto device = m_context.getDevice();
3972 auto& alloc = m_context.getDefaultAllocator();
3973 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
3974 const auto queue = m_context.getUniversalQueue();
3975
3976 const auto imageFormat = getOutputFormat();
3977 const auto tcuFormat = mapVkFormat(imageFormat);
3978 const auto imageExtent = makeExtent3D(m_params->width, m_params->height, 1u);
3979 const auto imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
3980
3981 const auto& binaries = m_context.getBinaryCollection();
3982 const auto hasTask = binaries.contains("task");
3983
3984 const VkImageCreateInfo colorBufferInfo =
3985 {
3986 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
3987 nullptr, // const void* pNext;
3988 0u, // VkImageCreateFlags flags;
3989 VK_IMAGE_TYPE_2D, // VkImageType imageType;
3990 imageFormat, // VkFormat format;
3991 imageExtent, // VkExtent3D extent;
3992 1u, // uint32_t mipLevels;
3993 1u, // uint32_t arrayLayers;
3994 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
3995 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
3996 imageUsage, // VkImageUsageFlags usage;
3997 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
3998 0u, // uint32_t queueFamilyIndexCount;
3999 nullptr, // const uint32_t* pQueueFamilyIndices;
4000 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
4001 };
4002
4003 // Create color image and view.
4004 ImageWithMemory colorImage (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
4005 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
4006 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
4007 const auto colorView = makeImageView(vkd, device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
4008
4009 // Create a memory buffer for verification.
4010 const auto verificationBufferSize = static_cast<VkDeviceSize>(imageExtent.width * imageExtent.height * tcu::getPixelSize(tcuFormat));
4011 const auto verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
4012 const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
4013
4014 BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
4015 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
4016 void* verificationBufferData = verificationBufferAlloc.getHostPtr();
4017
4018 // Pipeline layout.
4019 const auto pipelineLayout = makePipelineLayout(vkd, device, 0u, nullptr, 0u, nullptr);
4020
4021 // Shader modules.
4022 const auto meshShader = createShaderModule(vkd, device, binaries.get("mesh"));
4023 const auto fragShader = createShaderModule(vkd, device, binaries.get("frag"));
4024
4025 Move<VkShaderModule> taskShader;
4026 if (hasTask)
4027 taskShader = createShaderModule(vkd, device, binaries.get("task"));
4028
4029 // Spec constant data (must match shaders).
4030 const std::vector<uint32_t> scData {
4031 // 10 11 12 20 21 22
4032 32u, 1u, 1u, 32u, 1u, 1u
4033 };
4034 const auto scSize = static_cast<uint32_t>(sizeof(uint32_t));
4035 const std::vector<VkSpecializationMapEntry> scMapEntries {
4036 makeSpecializationMapEntry(10u, 0u * scSize, scSize),
4037 makeSpecializationMapEntry(11u, 1u * scSize, scSize),
4038 makeSpecializationMapEntry(12u, 2u * scSize, scSize),
4039 makeSpecializationMapEntry(20u, 3u * scSize, scSize),
4040 makeSpecializationMapEntry(21u, 4u * scSize, scSize),
4041 makeSpecializationMapEntry(22u, 5u * scSize, scSize),
4042 };
4043
4044 const auto scMapInfo = makeSpecializationInfo(
4045 static_cast<uint32_t>(scMapEntries.size()), de::dataOrNull(scMapEntries),
4046 static_cast<uint32_t>(de::dataSize(scData)), de::dataOrNull(scData));
4047
4048 std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
4049 shaderStages.push_back(makePipelineShaderStageCreateInfo(VK_SHADER_STAGE_MESH_BIT_EXT, meshShader.get(), &scMapInfo));
4050 shaderStages.push_back(makePipelineShaderStageCreateInfo(VK_SHADER_STAGE_FRAGMENT_BIT, fragShader.get()));
4051 if (hasTask)
4052 shaderStages.push_back(makePipelineShaderStageCreateInfo(VK_SHADER_STAGE_TASK_BIT_EXT, taskShader.get(), &scMapInfo));
4053
4054 // Render pass.
4055 const auto renderPass = makeRenderPass(vkd, device, imageFormat);
4056
4057 // Framebuffer.
4058 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), imageExtent.width, imageExtent.height);
4059
4060 // Viewport and scissor.
4061 const std::vector<VkViewport> viewports (1u, makeViewport(imageExtent));
4062 const std::vector<VkRect2D> scissors (1u, makeRect2D(imageExtent));
4063
4064 // Pipeline with specialization constants.
4065 const auto pipeline = makeGraphicsPipeline(vkd, device, DE_NULL, pipelineLayout.get(), 0u, shaderStages, renderPass.get(), viewports, scissors);
4066
4067 // Command pool and buffer.
4068 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
4069 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
4070 const auto cmdBuffer = cmdBufferPtr.get();
4071
4072 beginCommandBuffer(vkd, cmdBuffer);
4073
4074 // Run pipeline.
4075 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
4076 const auto drawCount = m_params->drawCount();
4077 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
4078 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
4079 vkd.cmdDrawMeshTasksEXT(cmdBuffer, drawCount.x(), drawCount.y(), drawCount.z());
4080 endRenderPass(vkd, cmdBuffer);
4081
4082 // Copy color buffer to verification buffer.
4083 const auto colorAccess = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
4084 const auto transferRead = VK_ACCESS_TRANSFER_READ_BIT;
4085 const auto transferWrite = VK_ACCESS_TRANSFER_WRITE_BIT;
4086 const auto hostRead = VK_ACCESS_HOST_READ_BIT;
4087
4088 const auto preCopyBarrier = makeImageMemoryBarrier(colorAccess, transferRead, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSRR);
4089 const auto postCopyBarrier = makeMemoryBarrier(transferWrite, hostRead);
4090 const auto copyRegion = makeBufferImageCopy(imageExtent, colorSRL);
4091
4092 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
4093 vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
4094 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
4095
4096 endCommandBuffer(vkd, cmdBuffer);
4097 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
4098
4099 // Generate reference image and compare results.
4100 const tcu::IVec3 iExtent (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), 1);
4101 const tcu::ConstPixelBufferAccess verificationAccess (tcuFormat, iExtent, verificationBufferData);
4102
4103 generateReferenceLevel();
4104 invalidateAlloc(vkd, device, verificationBufferAlloc);
4105 if (!verifyResult(verificationAccess))
4106 TCU_FAIL("Result does not match reference; check log for details");
4107
4108 return tcu::TestStatus::pass("Pass");
4109 }
4110
4111 // Test multiple task payloads.
4112 class MultipleTaskPayloadsCase : public MeshShaderMiscCase
4113 {
4114 public:
MultipleTaskPayloadsCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)4115 MultipleTaskPayloadsCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
4116 : MeshShaderMiscCase (testCtx, name, std::move(params))
4117 {
4118 }
4119
4120 void initPrograms (vk::SourceCollections& programCollection) const override;
4121 TestInstance* createInstance (Context& context) const override;
4122
4123 static constexpr uint32_t kGoodKeyIdx = 1u;
4124 };
4125
4126 class MultipleTaskPayloadsInstance : public MeshShaderMiscInstance
4127 {
4128 public:
MultipleTaskPayloadsInstance(Context & context,const MiscTestParams * params)4129 MultipleTaskPayloadsInstance (Context& context, const MiscTestParams* params)
4130 : MeshShaderMiscInstance (context, params)
4131 {}
4132
4133 void generateReferenceLevel () override;
4134 tcu::TestStatus iterate () override;
4135 };
4136
createInstance(Context & context) const4137 TestInstance* MultipleTaskPayloadsCase::createInstance (Context& context) const
4138 {
4139 return new MultipleTaskPayloadsInstance (context, m_params.get());
4140 }
4141
initPrograms(vk::SourceCollections & programCollection) const4142 void MultipleTaskPayloadsCase::initPrograms (vk::SourceCollections& programCollection) const
4143 {
4144 DE_ASSERT(m_params->needsTaskShader());
4145
4146 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
4147 const auto spvBuildOptions = getMinMeshEXTSpvBuildOptions(programCollection.usedVulkanVersion);
4148 const std::vector<uint32_t> keys { 3717945376u, 2325956828u, 433982700u };
4149 //const std::vector<uint32_t> keys { 85u, 170u, 255u };
4150
4151 // Generic fragment shader.
4152 MeshShaderMiscCase::initPrograms(programCollection);
4153
4154 const std::string taskDataDecl =
4155 "struct TaskData {\n"
4156 " uint key;\n"
4157 "};\n"
4158 "taskPayloadSharedEXT TaskData td;\n"
4159 ;
4160
4161 // Idea behind this test: verify that the right payload was passed to the mesh shader and set the geometry color based on that.
4162 std::ostringstream mesh;
4163 mesh
4164 << "#version 450\n"
4165 << "#extension GL_EXT_mesh_shader : enable\n"
4166 << "\n"
4167 << "layout(local_size_x=1) in;\n"
4168 << "layout(triangles) out;\n"
4169 << "layout(max_vertices=3, max_primitives=1) out;\n"
4170 << "\n"
4171 << "layout(location=0) out perprimitiveEXT vec4 triangleColor[];\n"
4172 << taskDataDecl
4173 << "\n"
4174 << "void main ()\n"
4175 << "{\n"
4176 << " SetMeshOutputsEXT(3, 1);\n"
4177 << " gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0, -1.0, 0.0f, 1.0f);\n"
4178 << " gl_MeshVerticesEXT[1].gl_Position = vec4( 3.0, -1.0, 0.0f, 1.0f);\n"
4179 << " gl_MeshVerticesEXT[2].gl_Position = vec4(-1.0, 3.0, 0.0f, 1.0f);\n"
4180 << " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2);\n"
4181 << " const vec4 color = ((td.key == " << keys[kGoodKeyIdx] << "u) ? vec4(0.0, 0.0, 1.0, 1.0) : vec4(0.0, 0.0, 0.0, 1.0));\n"
4182 //<< " const vec4 color = vec4(0.0, 0.0, (float(td.key) / 255.0), 1.0);\n"
4183 << " triangleColor[0] = color;\n"
4184 << "}\n"
4185 ;
4186 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
4187
4188 const auto& meshCount = m_params->meshCount;
4189 DE_ASSERT(meshCount.x() == 1u && meshCount.y() == 1u && meshCount.z() == 1u);
4190 DE_UNREF(meshCount); // For release builds.
4191
4192 #if 0
4193 #if 0
4194 // Note: pseudocode, this actually does not compile with glslang.
4195 std::ostringstream task;
4196 task
4197 << "#version 450\n"
4198 << "#extension GL_EXT_mesh_shader : enable\n"
4199 << "\n"
4200 << "layout(local_size_x=1) in;\n"
4201 << "layout(push_constant, std430) uniform PCBlock {\n"
4202 << " uint index;\n"
4203 << "} pc;\n"
4204 << "struct TaskData {\n"
4205 << " uint key;\n"
4206 << "};\n"
4207 << "taskPayloadSharedEXT TaskData td0;\n"
4208 << "taskPayloadSharedEXT TaskData td1;\n"
4209 << "taskPayloadSharedEXT TaskData td2;\n"
4210 << "\n"
4211 << "void main ()\n"
4212 << "{\n"
4213 << " td0.key = " << keys.at(0) << "u;\n"
4214 << " td1.key = " << keys.at(1) << "u;\n"
4215 << " td2.key = " << keys.at(2) << "u;\n"
4216 << " if (pc.index == 0u) EmitMeshTasksEXT(1u, 1u, 1u, td0);\n"
4217 << " else if (pc.index == 1u) EmitMeshTasksEXT(1u, 1u, 1u, td1);\n"
4218 << " else EmitMeshTasksEXT(1u, 1u, 1u, td2);\n"
4219 << "}\n"
4220 ;
4221 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
4222 #else
4223 // Similar shader to check the setup works.
4224 std::ostringstream task;
4225 task
4226 << "#version 450\n"
4227 << "#extension GL_EXT_mesh_shader : enable\n"
4228 << "\n"
4229 << "layout(local_size_x=1) in;\n"
4230 << "layout(push_constant, std430) uniform PCBlock {\n"
4231 << " uint index;\n"
4232 << "} pc;\n"
4233 << "struct TaskData {\n"
4234 << " uint key;\n"
4235 << "};\n"
4236 << "taskPayloadSharedEXT TaskData td;\n"
4237 << "\n"
4238 << "void main ()\n"
4239 << "{\n"
4240 << " if (pc.index == 0u) td.key = " << keys.at(0) << "u;\n"
4241 << " else if (pc.index == 1u) td.key = " << keys.at(1) << "u;\n"
4242 << " else td.key = " << keys.at(2) << "u;\n"
4243 << " EmitMeshTasksEXT(1u, 1u, 1u);\n"
4244 << "}\n"
4245 ;
4246 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
4247 #endif
4248 #else
4249 std::ostringstream taskSPV;
4250 taskSPV
4251 << " OpCapability MeshShadingEXT\n"
4252 << " OpExtension \"SPV_EXT_mesh_shader\"\n"
4253 << " %1 = OpExtInstImport \"GLSL.std.450\"\n"
4254 << " OpMemoryModel Logical GLSL450\n"
4255 << " OpEntryPoint TaskEXT %main \"main\"\n"
4256 << " OpExecutionMode %main LocalSize 1 1 1\n"
4257 << " OpMemberDecorate %PCBlock 0 Offset 0\n"
4258 << " OpDecorate %PCBlock Block\n"
4259 << " OpDecorate %work_group_size BuiltIn WorkgroupSize\n"
4260 << " %2 = OpTypeVoid\n"
4261 << " %3 = OpTypeFunction %2\n"
4262 << " %uint = OpTypeInt 32 0\n"
4263 << " %TaskData = OpTypeStruct %uint\n"
4264 << " %TaskData_ptr = OpTypePointer TaskPayloadWorkgroupEXT %TaskData\n"
4265 << " %payload_0 = OpVariable %TaskData_ptr TaskPayloadWorkgroupEXT\n"
4266 << " %payload_1 = OpVariable %TaskData_ptr TaskPayloadWorkgroupEXT\n"
4267 << " %payload_2 = OpVariable %TaskData_ptr TaskPayloadWorkgroupEXT\n"
4268 << " %int = OpTypeInt 32 1\n"
4269 << " %int_0 = OpConstant %int 0\n"
4270 << " %key_0 = OpConstant %uint " << keys.at(0) << "\n"
4271 << " %key_1 = OpConstant %uint " << keys.at(1) << "\n"
4272 << " %key_2 = OpConstant %uint " << keys.at(2) << "\n"
4273 << "%payload_uint_ptr = OpTypePointer TaskPayloadWorkgroupEXT %uint\n"
4274 << " %PCBlock = OpTypeStruct %uint\n"
4275 << " %PCBlock_ptr = OpTypePointer PushConstant %PCBlock\n"
4276 << " %pc = OpVariable %PCBlock_ptr PushConstant\n"
4277 << " %pc_uint_ptr = OpTypePointer PushConstant %uint\n"
4278 << " %uint_0 = OpConstant %uint 0\n"
4279 << " %uint_1 = OpConstant %uint 1\n"
4280 << " %bool = OpTypeBool\n"
4281 << " %uvec3 = OpTypeVector %uint 3\n"
4282 << " %work_group_size = OpConstantComposite %uvec3 %uint_1 %uint_1 %uint_1\n"
4283 << " %main = OpFunction %2 None %3\n"
4284 << " %5 = OpLabel\n"
4285 << " %payload_0_key = OpAccessChain %payload_uint_ptr %payload_0 %int_0\n"
4286 << " %payload_1_key = OpAccessChain %payload_uint_ptr %payload_1 %int_0\n"
4287 << " %payload_2_key = OpAccessChain %payload_uint_ptr %payload_2 %int_0\n"
4288 << " OpStore %payload_0_key %key_0\n"
4289 << " OpStore %payload_1_key %key_1\n"
4290 << " OpStore %payload_2_key %key_2\n"
4291 << " %pc_index_ptr = OpAccessChain %pc_uint_ptr %pc %int_0\n"
4292 << " %pc_index = OpLoad %uint %pc_index_ptr\n"
4293 << " %23 = OpIEqual %bool %pc_index %uint_0\n"
4294 << " OpSelectionMerge %25 None\n"
4295 << " OpBranchConditional %23 %24 %27\n"
4296 << " %24 = OpLabel\n"
4297 << " OpEmitMeshTasksEXT %uint_1 %uint_1 %uint_1 %payload_0\n"
4298 << " OpBranch %25\n"
4299 << " %27 = OpLabel\n"
4300 << " %30 = OpIEqual %bool %pc_index %uint_1\n"
4301 << " OpSelectionMerge %32 None\n"
4302 << " OpBranchConditional %30 %31 %33\n"
4303 << " %31 = OpLabel\n"
4304 << " OpEmitMeshTasksEXT %uint_1 %uint_1 %uint_1 %payload_1\n"
4305 << " OpBranch %32\n"
4306 << " %33 = OpLabel\n"
4307 << " OpEmitMeshTasksEXT %uint_1 %uint_1 %uint_1 %payload_2\n"
4308 << " OpBranch %32\n"
4309 << " %32 = OpLabel\n"
4310 << " OpBranch %25\n"
4311 << " %25 = OpLabel\n"
4312 << " OpReturn\n"
4313 << " OpFunctionEnd\n"
4314 ;
4315 programCollection.spirvAsmSources.add("task") << taskSPV.str() << spvBuildOptions;
4316 #endif
4317 }
4318
generateReferenceLevel()4319 void MultipleTaskPayloadsInstance::generateReferenceLevel ()
4320 {
4321 generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
4322 }
4323
iterate()4324 tcu::TestStatus MultipleTaskPayloadsInstance::iterate ()
4325 {
4326 const auto& vkd = m_context.getDeviceInterface();
4327 const auto device = m_context.getDevice();
4328 auto& alloc = m_context.getDefaultAllocator();
4329 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
4330 const auto queue = m_context.getUniversalQueue();
4331
4332 const auto imageFormat = getOutputFormat();
4333 const auto tcuFormat = mapVkFormat(imageFormat);
4334 const auto imageExtent = makeExtent3D(m_params->width, m_params->height, 1u);
4335 const auto imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
4336
4337 const VkImageCreateInfo colorBufferInfo =
4338 {
4339 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
4340 nullptr, // const void* pNext;
4341 0u, // VkImageCreateFlags flags;
4342 VK_IMAGE_TYPE_2D, // VkImageType imageType;
4343 imageFormat, // VkFormat format;
4344 imageExtent, // VkExtent3D extent;
4345 1u, // uint32_t mipLevels;
4346 1u, // uint32_t arrayLayers;
4347 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
4348 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
4349 imageUsage, // VkImageUsageFlags usage;
4350 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
4351 0u, // uint32_t queueFamilyIndexCount;
4352 nullptr, // const uint32_t* pQueueFamilyIndices;
4353 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
4354 };
4355
4356 // Create color image and view.
4357 ImageWithMemory colorImage (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
4358 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
4359 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
4360 const auto colorView = makeImageView(vkd, device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
4361
4362 // Create a memory buffer for verification.
4363 const auto verificationBufferSize = static_cast<VkDeviceSize>(imageExtent.width * imageExtent.height * tcu::getPixelSize(tcuFormat));
4364 const auto verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
4365 const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
4366
4367 BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
4368 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
4369 void* verificationBufferData = verificationBufferAlloc.getHostPtr();
4370
4371 // Pipeline layout.
4372 const auto pcSize = static_cast<uint32_t>(sizeof(uint32_t));
4373 const auto pcRange = makePushConstantRange(VK_SHADER_STAGE_TASK_BIT_EXT, 0u, pcSize);
4374 const auto pipelineLayout = makePipelineLayout(vkd, device, DE_NULL, &pcRange);
4375
4376 // Shader modules.
4377 const auto& binaries = m_context.getBinaryCollection();
4378 const auto hasTask = binaries.contains("task");
4379
4380 const auto meshShader = createShaderModule(vkd, device, binaries.get("mesh"));
4381 const auto fragShader = createShaderModule(vkd, device, binaries.get("frag"));
4382
4383 Move<VkShaderModule> taskShader;
4384 if (hasTask)
4385 taskShader = createShaderModule(vkd, device, binaries.get("task"));
4386
4387 // Render pass.
4388 const auto renderPass = makeRenderPass(vkd, device, imageFormat);
4389
4390 // Framebuffer.
4391 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), imageExtent.width, imageExtent.height);
4392
4393 // Viewport and scissor.
4394 const std::vector<VkViewport> viewports (1u, makeViewport(imageExtent));
4395 const std::vector<VkRect2D> scissors (1u, makeRect2D(imageExtent));
4396
4397 // Color blending.
4398 const auto colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
4399 const VkPipelineColorBlendAttachmentState blendAttState =
4400 {
4401 VK_TRUE, // VkBool32 blendEnable;
4402 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
4403 VK_BLEND_FACTOR_ONE, // VkBlendFactor dstColorBlendFactor;
4404 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
4405 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
4406 VK_BLEND_FACTOR_ONE, // VkBlendFactor dstAlphaBlendFactor;
4407 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
4408 colorWriteMask, // VkColorComponentFlags colorWriteMask;
4409 };
4410
4411 const VkPipelineColorBlendStateCreateInfo colorBlendInfo =
4412 {
4413 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
4414 nullptr, // const void* pNext;
4415 0u, // VkPipelineColorBlendStateCreateFlags flags;
4416 VK_FALSE, // VkBool32 logicOpEnable;
4417 VK_LOGIC_OP_OR, // VkLogicOp logicOp;
4418 1u, // uint32_t attachmentCount;
4419 &blendAttState, // const VkPipelineColorBlendAttachmentState* pAttachments;
4420 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
4421 };
4422
4423 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
4424 taskShader.get(), meshShader.get(), fragShader.get(),
4425 renderPass.get(), viewports, scissors, 0u/*subpass*/,
4426 nullptr, nullptr, nullptr, &colorBlendInfo);
4427
4428 // Command pool and buffer.
4429 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
4430 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
4431 const auto cmdBuffer = cmdBufferPtr.get();
4432
4433 beginCommandBuffer(vkd, cmdBuffer);
4434
4435 // Run pipeline.
4436 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
4437 const auto drawCount = m_params->drawCount();
4438 const uint32_t pcData = MultipleTaskPayloadsCase::kGoodKeyIdx;
4439 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
4440 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
4441 vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), VK_SHADER_STAGE_TASK_BIT_EXT, 0u, pcSize, &pcData);
4442 vkd.cmdDrawMeshTasksEXT(cmdBuffer, drawCount.x(), drawCount.y(), drawCount.z());
4443 endRenderPass(vkd, cmdBuffer);
4444
4445 // Copy color buffer to verification buffer.
4446 const auto colorAccess = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
4447 const auto transferRead = VK_ACCESS_TRANSFER_READ_BIT;
4448 const auto transferWrite = VK_ACCESS_TRANSFER_WRITE_BIT;
4449 const auto hostRead = VK_ACCESS_HOST_READ_BIT;
4450
4451 const auto preCopyBarrier = makeImageMemoryBarrier(colorAccess, transferRead, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSRR);
4452 const auto postCopyBarrier = makeMemoryBarrier(transferWrite, hostRead);
4453 const auto copyRegion = makeBufferImageCopy(imageExtent, colorSRL);
4454
4455 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
4456 vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
4457 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
4458
4459 endCommandBuffer(vkd, cmdBuffer);
4460 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
4461
4462 // Generate reference image and compare results.
4463 const tcu::IVec3 iExtent (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), 1);
4464 const tcu::ConstPixelBufferAccess verificationAccess (tcuFormat, iExtent, verificationBufferData);
4465
4466 generateReferenceLevel();
4467 invalidateAlloc(vkd, device, verificationBufferAlloc);
4468 if (!verifyResult(verificationAccess))
4469 TCU_FAIL("Result does not match reference; check log for details");
4470
4471 return tcu::TestStatus::pass("Pass");
4472 }
4473
4474 // Test multiple task/mesh draw calls and updating push constants and descriptors in between. We will divide the output image in 4
4475 // quadrants, and use each task/mesh draw call to draw on a particular quadrant. The output color in each quadrant will be composed
4476 // of data from different sources: storage buffer, sampled image or push constant value, and those will change before each draw
4477 // call. We'll prepare different descriptors for each quadrant.
4478 class RebindSetsCase : public MeshShaderMiscCase
4479 {
4480 public:
RebindSetsCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr params)4481 RebindSetsCase (tcu::TestContext& testCtx, const std::string& name, ParamsPtr params)
4482 : MeshShaderMiscCase(testCtx, name, std::move(params))
4483 {
4484 const auto drawCount = m_params->drawCount();
4485 DE_ASSERT(drawCount.x() == 1u && drawCount.y() == 1u && drawCount.z() == 1u);
4486 DE_UNREF(drawCount); // For release builds.
4487 }
~RebindSetsCase(void)4488 virtual ~RebindSetsCase (void) {}
4489
4490 TestInstance* createInstance (Context& context) const override;
4491 void checkSupport (Context& context) const override;
4492 void initPrograms (vk::SourceCollections& programCollection) const override;
4493 };
4494
4495 class RebindSetsInstance : public MeshShaderMiscInstance
4496 {
4497 public:
RebindSetsInstance(Context & context,const MiscTestParams * params)4498 RebindSetsInstance (Context& context, const MiscTestParams* params)
4499 : MeshShaderMiscInstance(context, params) {}
~RebindSetsInstance(void)4500 virtual ~RebindSetsInstance (void) {}
4501
4502 void generateReferenceLevel () override;
4503 tcu::TestStatus iterate (void) override;
4504
4505 protected:
4506 struct QuadrantInfo
4507 {
4508 // Offsets in framebuffer coordinates (0 to 2, final coordinates in range -1 to 1)
4509 float offsetX;
4510 float offsetY;
4511 tcu::Vec4 color;
4512
QuadrantInfovkt::MeshShader::__anond8548dd90111::RebindSetsInstance::QuadrantInfo4513 QuadrantInfo (float offsetX_, float offsetY_, float red, float green, float blue)
4514 : offsetX (offsetX_)
4515 , offsetY (offsetY_)
4516 , color (red, green, blue, 1.0f)
4517 {}
4518 };
4519
getQuadrantInfos()4520 static std::vector<QuadrantInfo> getQuadrantInfos ()
4521 {
4522 std::vector<QuadrantInfo> infos;
4523 infos.reserve(4u);
4524
4525 // offsets rgb
4526 infos.emplace_back(0.0f, 0.0f, 1.0f, 0.0f, 1.0f);
4527 infos.emplace_back(1.0f, 0.0f, 1.0f, 1.0f, 0.0f);
4528 infos.emplace_back(0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
4529 infos.emplace_back(1.0f, 1.0f, 0.0f, 1.0f, 1.0f);
4530
4531 return infos;
4532 }
4533
4534 struct PushConstants
4535 {
4536 float offsetX;
4537 float offsetY;
4538 float blueComponent;
4539 };
4540 };
4541
createInstance(Context & context) const4542 TestInstance* RebindSetsCase::createInstance (Context &context) const
4543 {
4544 return new RebindSetsInstance(context, m_params.get());
4545 }
4546
checkSupport(Context & context) const4547 void RebindSetsCase::checkSupport (Context& context) const
4548 {
4549 genericCheckSupport(context, true, false);
4550 }
4551
initPrograms(vk::SourceCollections & programCollection) const4552 void RebindSetsCase::initPrograms (vk::SourceCollections& programCollection) const
4553 {
4554 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
4555
4556 // Generic fragment shader.
4557 MeshShaderMiscCase::initPrograms(programCollection);
4558
4559 const std::string ssbo = "layout (set=0, binding=0, std430) readonly buffer SSBOBlock { float redComponent; } ssbo;\n";
4560 const std::string combined = "layout (set=0, binding=1) uniform sampler2D greenComponent;\n";
4561 const std::string pc = "layout (push_constant, std430) uniform PCBlock { float offsetX; float offsetY; float blueComponent; } pc;\n";
4562 const std::string payload = "struct TaskData { float redComponent; }; taskPayloadSharedEXT TaskData td;\n";
4563
4564 std::ostringstream task;
4565 task
4566 << "#version 450\n"
4567 << "#extension GL_EXT_mesh_shader : enable\n"
4568 << "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
4569 << "\n"
4570 << ssbo
4571 << payload
4572 << "\n"
4573 << "void main (void)\n"
4574 << "{\n"
4575 << " td.redComponent = ssbo.redComponent;\n"
4576 << " EmitMeshTasksEXT(1u, 1u, 1u);\n"
4577 << "}\n"
4578 ;
4579 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
4580
4581 std::ostringstream mesh;
4582 mesh
4583 << "#version 450\n"
4584 << "#extension GL_EXT_mesh_shader : enable\n"
4585 << "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
4586 << "layout (triangles) out;\n"
4587 << "layout (max_vertices=4, max_primitives=2) out;\n"
4588 << "\n"
4589 << combined
4590 << pc
4591 << payload
4592 << "layout (location=0) out perprimitiveEXT vec4 primitiveColor[];\n"
4593 << "\n"
4594 << "void main (void)\n"
4595 << "{\n"
4596 << " SetMeshOutputsEXT(4u, 2u);\n"
4597 << "\n"
4598 << " gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0 + pc.offsetX, -1.0 + pc.offsetY, 0.0, 1.0);\n"
4599 << " gl_MeshVerticesEXT[1].gl_Position = vec4( 0.0 + pc.offsetX, -1.0 + pc.offsetY, 0.0, 1.0);\n"
4600 << " gl_MeshVerticesEXT[2].gl_Position = vec4(-1.0 + pc.offsetX, 0.0 + pc.offsetY, 0.0, 1.0);\n"
4601 << " gl_MeshVerticesEXT[3].gl_Position = vec4( 0.0 + pc.offsetX, 0.0 + pc.offsetY, 0.0, 1.0);\n"
4602 << "\n"
4603 << " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(2u, 1u, 0u);\n"
4604 << " gl_PrimitiveTriangleIndicesEXT[1] = uvec3(2u, 3u, 1u);\n"
4605 << "\n"
4606 << " const vec4 primColor = vec4(td.redComponent, texture(greenComponent, vec2(0.5, 0.5)).x, pc.blueComponent, 1.0);\n"
4607 << " primitiveColor[0] = primColor;\n"
4608 << " primitiveColor[1] = primColor;\n"
4609 << "}\n"
4610 ;
4611 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
4612 }
4613
generateReferenceLevel()4614 void RebindSetsInstance::generateReferenceLevel ()
4615 {
4616 const auto iWidth = static_cast<int>(m_params->width);
4617 const auto iHeight = static_cast<int>(m_params->height);
4618 const auto fWidth = static_cast<float>(iWidth);
4619 const auto fHeight = static_cast<float>(iHeight);
4620
4621 DE_ASSERT(iWidth % 2 == 0);
4622 DE_ASSERT(iHeight % 2 == 0);
4623
4624 const auto halfWidth = iWidth / 2;
4625 const auto halfHeight = iHeight / 2;
4626
4627 const auto format = getOutputFormat();
4628 const auto tcuFormat = mapVkFormat(format);
4629
4630 m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
4631 const auto access = m_referenceLevel->getAccess();
4632
4633 const auto quadrantInfos = getQuadrantInfos();
4634 DE_ASSERT(quadrantInfos.size() == 4u);
4635
4636 for (const auto& quadrantInfo : quadrantInfos)
4637 {
4638 const auto xCorner = static_cast<int>(quadrantInfo.offsetX / 2.0f * fWidth);
4639 const auto yCorner = static_cast<int>(quadrantInfo.offsetY / 2.0f * fHeight);
4640 const auto subregion = tcu::getSubregion(access, xCorner, yCorner, halfWidth, halfHeight);
4641
4642 tcu::clear(subregion, quadrantInfo.color);
4643 }
4644 }
4645
iterate(void)4646 tcu::TestStatus RebindSetsInstance::iterate (void)
4647 {
4648 const auto& vkd = m_context.getDeviceInterface();
4649 const auto device = m_context.getDevice();
4650 auto& alloc = m_context.getDefaultAllocator();
4651 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
4652 const auto queue = m_context.getUniversalQueue();
4653 const auto quadrantInfos = getQuadrantInfos();
4654 const auto setCount = static_cast<uint32_t>(quadrantInfos.size());
4655 const auto textureExtent = makeExtent3D(1u, 1u, 1u);
4656 const tcu::IVec3 iTexExtent (static_cast<int>(textureExtent.width), static_cast<int>(textureExtent.height), static_cast<int>(textureExtent.depth));
4657 const auto textureFormat = VK_FORMAT_R8G8B8A8_UNORM;
4658 const auto tcuTexFormat = mapVkFormat(textureFormat);
4659 const auto textureUsage = (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
4660 const auto colorExtent = makeExtent3D(m_params->width, m_params->height, 1u);
4661 const auto colorFormat = getOutputFormat();
4662 const auto tcuColorFormat = mapVkFormat(colorFormat);
4663 const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
4664
4665 DE_ASSERT(quadrantInfos.size() == 4u);
4666
4667 // We need 4 descriptor sets: 4 buffers, 4 images and 1 sampler.
4668 const VkSamplerCreateInfo samplerCreateInfo = initVulkanStructure();
4669 const auto sampler = createSampler(vkd, device, &samplerCreateInfo);
4670
4671 // Buffers.
4672 const auto ssboSize = static_cast<VkDeviceSize>(sizeof(float));
4673 const auto ssboCreateInfo = makeBufferCreateInfo(ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
4674
4675 std::vector<std::unique_ptr<BufferWithMemory>> ssbos;
4676 ssbos.reserve(quadrantInfos.size());
4677 for (const auto& quadrantInfo : quadrantInfos)
4678 {
4679 ssbos.emplace_back(new BufferWithMemory(vkd, device, alloc, ssboCreateInfo, MemoryRequirement::HostVisible));
4680 void* data = ssbos.back()->getAllocation().getHostPtr();
4681 const auto redComponent = quadrantInfo.color.x();
4682 deMemcpy(data, &redComponent, sizeof(redComponent));
4683 }
4684
4685 // Textures.
4686 const VkImageCreateInfo textureCreateInfo =
4687 {
4688 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
4689 nullptr, // const void* pNext;
4690 0u, // VkImageCreateFlags flags;
4691 VK_IMAGE_TYPE_2D, // VkImageType imageType;
4692 textureFormat, // VkFormat format;
4693 textureExtent, // VkExtent3D extent;
4694 1u, // uint32_t mipLevels;
4695 1u, // uint32_t arrayLayers;
4696 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
4697 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
4698 textureUsage, // VkImageUsageFlags usage;
4699 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
4700 0u, // uint32_t queueFamilyIndexCount;
4701 nullptr, // const uint32_t* pQueueFamilyIndices;
4702 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
4703 };
4704 const auto textureSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
4705 const auto textureSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
4706 const auto textureCopyRegion = makeBufferImageCopy(textureExtent, textureSRL);
4707
4708 std::vector<std::unique_ptr<ImageWithMemory>> textures;
4709 for (size_t i = 0u; i < quadrantInfos.size(); ++i)
4710 textures.emplace_back(new ImageWithMemory(vkd, device, alloc, textureCreateInfo, MemoryRequirement::Any));
4711
4712 std::vector<Move<VkImageView>> textureViews;
4713 textureViews.reserve(quadrantInfos.size());
4714 for (const auto& texture : textures)
4715 textureViews.push_back(makeImageView(vkd, device, texture->get(), VK_IMAGE_VIEW_TYPE_2D, textureFormat, textureSRR));
4716
4717 // Auxiliar buffers to fill the images with the right colors.
4718 const auto pixelSize = tcu::getPixelSize(tcuTexFormat);
4719 const auto pixelCount = textureExtent.width * textureExtent.height * textureExtent.depth;
4720 const auto auxiliarBufferSize = static_cast<VkDeviceSize>(static_cast<VkDeviceSize>(pixelSize) * static_cast<VkDeviceSize>(pixelCount));
4721 const auto auxiliarBufferCreateInfo = makeBufferCreateInfo(auxiliarBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
4722
4723 std::vector<std::unique_ptr<BufferWithMemory>> auxiliarBuffers;
4724 auxiliarBuffers.reserve(quadrantInfos.size());
4725 for (const auto& quadrantInfo : quadrantInfos)
4726 {
4727 auxiliarBuffers.emplace_back(new BufferWithMemory(vkd, device, alloc, auxiliarBufferCreateInfo, MemoryRequirement::HostVisible));
4728
4729 void* data = auxiliarBuffers.back()->getAllocation().getHostPtr();
4730 tcu::PixelBufferAccess access (tcuTexFormat, iTexExtent, data);
4731 const tcu::Vec4 quadrantColor (quadrantInfo.color.y(), 0.0f, 0.0f, 1.0f);
4732
4733 tcu::clear(access, quadrantColor);
4734 }
4735
4736 // Descriptor set layout.
4737 DescriptorSetLayoutBuilder layoutBuilder;
4738 layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TASK_BIT_EXT);
4739 layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_MESH_BIT_EXT);
4740 const auto setLayout = layoutBuilder.build(vkd, device);
4741
4742 // Pipeline layout.
4743 const auto pcSize = static_cast<uint32_t>(sizeof(PushConstants));
4744 const auto pcRange = makePushConstantRange(VK_SHADER_STAGE_MESH_BIT_EXT, 0u, pcSize);
4745 const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get(), &pcRange);
4746
4747 // Descriptor pool and sets.
4748 DescriptorPoolBuilder poolBuilder;
4749 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, setCount);
4750 poolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, setCount);
4751 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, setCount);
4752
4753 std::vector<Move<VkDescriptorSet>> descriptorSets;
4754 for (size_t i = 0; i < quadrantInfos.size(); ++i)
4755 descriptorSets.push_back(makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get()));
4756
4757 // Update descriptor sets.
4758 DescriptorSetUpdateBuilder updateBuilder;
4759 for (size_t i = 0; i < descriptorSets.size(); ++i)
4760 {
4761 const auto& descriptorSet = descriptorSets.at(i);
4762 const auto& ssbo = ssbos.at(i);
4763 const auto& textureView = textureViews.at(i);
4764 const auto descBufferInfo = makeDescriptorBufferInfo(ssbo->get(), 0ull, ssboSize);
4765 const auto descImageInfo = makeDescriptorImageInfo(sampler.get(), textureView.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
4766
4767 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descBufferInfo);
4768 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &descImageInfo);
4769 }
4770 updateBuilder.update(vkd, device);
4771
4772 // Color attachment.
4773 const VkImageCreateInfo colorCreateInfo =
4774 {
4775 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
4776 nullptr, // const void* pNext;
4777 0u, // VkImageCreateFlags flags;
4778 VK_IMAGE_TYPE_2D, // VkImageType imageType;
4779 colorFormat, // VkFormat format;
4780 colorExtent, // VkExtent3D extent;
4781 1u, // uint32_t mipLevels;
4782 1u, // uint32_t arrayLayers;
4783 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
4784 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
4785 colorUsage, // VkImageUsageFlags usage;
4786 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
4787 0u, // uint32_t queueFamilyIndexCount;
4788 nullptr, // const uint32_t* pQueueFamilyIndices;
4789 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
4790 };
4791 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
4792 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
4793
4794 ImageWithMemory colorAttachment (vkd, device, alloc, colorCreateInfo, MemoryRequirement::Any);
4795 const auto colorView = makeImageView(vkd, device, colorAttachment.get(), VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSRR);
4796
4797 // Create a memory buffer for verification.
4798 const auto verificationBufferSize = static_cast<VkDeviceSize>(colorExtent.width * colorExtent.height * tcu::getPixelSize(tcuColorFormat));
4799 const auto verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
4800 const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
4801
4802 BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
4803 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
4804 void* verificationBufferData = verificationBufferAlloc.getHostPtr();
4805
4806 // Render pass and framebuffer.
4807 const auto renderPass = makeRenderPass(vkd, device, colorFormat);
4808 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), colorExtent.width, colorExtent.height);
4809
4810 const std::vector<VkViewport> viewports (1u, makeViewport(colorExtent));
4811 const std::vector<VkRect2D> scissors (1u, makeRect2D(colorExtent));
4812
4813 // Shader modules and pipeline.
4814 const auto& binaries = m_context.getBinaryCollection();
4815 const auto taskShader = createShaderModule(vkd, device, binaries.get("task"));
4816 const auto meshShader = createShaderModule(vkd, device, binaries.get("mesh"));
4817 const auto fragShader = createShaderModule(vkd, device, binaries.get("frag"));
4818 const auto pipeline = makeGraphicsPipeline(
4819 vkd, device, pipelineLayout.get(),
4820 taskShader.get(), meshShader.get(), fragShader.get(),
4821 renderPass.get(), viewports, scissors);
4822
4823 // Command pool and buffer.
4824 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
4825 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
4826 const auto cmdBuffer = cmdBufferPtr.get();
4827
4828 beginCommandBuffer(vkd, cmdBuffer);
4829
4830 // Copy data from auxiliar buffers to textures.
4831 for (const auto& texture : textures)
4832 {
4833 const auto prepareTextureForCopy = makeImageMemoryBarrier(
4834 0u, VK_ACCESS_TRANSFER_WRITE_BIT,
4835 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4836 texture->get(), textureSRR);
4837 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &prepareTextureForCopy);
4838 }
4839
4840 for (size_t i = 0; i < auxiliarBuffers.size(); ++i)
4841 {
4842 const auto& auxBuffer = auxiliarBuffers.at(i);
4843 const auto& texture = textures.at(i);
4844 vkd.cmdCopyBufferToImage(cmdBuffer, auxBuffer->get(), texture->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &textureCopyRegion);
4845 }
4846
4847 // Prepare textures for sampling.
4848 for (const auto& texture : textures)
4849 {
4850 const auto prepareTextureForSampling = makeImageMemoryBarrier(
4851 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
4852 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
4853 texture->get(), textureSRR);
4854 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT, &prepareTextureForSampling);
4855 }
4856
4857 // Render stuff.
4858 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
4859 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
4860
4861 const auto drawCount = m_params->drawCount();
4862 for (size_t i = 0; i < quadrantInfos.size(); ++i)
4863 {
4864 const auto& quadrantInfo = quadrantInfos.at(i);
4865 const auto& descriptorSet = descriptorSets.at(i);
4866
4867 PushConstants pcData;
4868 pcData.blueComponent = quadrantInfo.color.z();
4869 pcData.offsetX = quadrantInfo.offsetX;
4870 pcData.offsetY = quadrantInfo.offsetY;
4871
4872 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
4873 vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), VK_SHADER_STAGE_MESH_BIT_EXT, 0u, pcSize, &pcData);
4874 vkd.cmdDrawMeshTasksEXT(cmdBuffer, drawCount.x(), drawCount.y(), drawCount.z());
4875 }
4876
4877 endRenderPass(vkd, cmdBuffer);
4878
4879 // Copy color attachment to verification buffer.
4880 const auto preCopyBarrier = makeImageMemoryBarrier(
4881 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4882 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4883 colorAttachment.get(), colorSRR);
4884 const auto postCopyBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
4885 const auto copyRegion = makeBufferImageCopy(colorExtent, colorSRL);
4886
4887 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
4888 vkd.cmdCopyImageToBuffer(cmdBuffer, colorAttachment.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
4889 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
4890
4891 endCommandBuffer(vkd, cmdBuffer);
4892 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
4893
4894 // Generate reference image and compare results.
4895 const tcu::IVec3 iColorExtent (static_cast<int>(colorExtent.width), static_cast<int>(colorExtent.height), 1);
4896 const tcu::ConstPixelBufferAccess verificationAccess (tcuColorFormat, iColorExtent, verificationBufferData);
4897
4898 generateReferenceLevel();
4899 invalidateAlloc(vkd, device, verificationBufferAlloc);
4900 if (!verifyResult(verificationAccess))
4901 TCU_FAIL("Result does not match reference; check log for details");
4902
4903 return tcu::TestStatus::pass("Pass");
4904 }
4905
4906 } // anonymous namespace
4907
createMeshShaderMiscTestsEXT(tcu::TestContext & testCtx)4908 tcu::TestCaseGroup* createMeshShaderMiscTestsEXT (tcu::TestContext& testCtx)
4909 {
4910 GroupPtr miscTests (new tcu::TestCaseGroup(testCtx, "misc"));
4911
4912 {
4913 ParamsPtr paramsPtr (new MiscTestParams(
4914 /*taskCount*/ tcu::just(tcu::UVec3(2u, 1u, 1u)),
4915 /*meshCount*/ tcu::UVec3(2u, 1u, 1u),
4916 /*width*/ 8u,
4917 /*height*/ 8u));
4918
4919 // Pass a complex structure from the task to the mesh shader
4920 miscTests->addChild(new ComplexTaskDataCase(testCtx, "complex_task_data", std::move(paramsPtr)));
4921 }
4922
4923 {
4924 ParamsPtr paramsPtr (new MiscTestParams(
4925 /*taskCount*/ tcu::Nothing,
4926 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
4927 /*width*/ 5u, // Use an odd value so there's a pixel in the exact center.
4928 /*height*/ 7u)); // Idem.
4929
4930 // Draw a single point
4931 miscTests->addChild(new SinglePointCase(testCtx, "single_point", std::move(paramsPtr)));
4932 }
4933
4934 {
4935 ParamsPtr paramsPtr (new MiscTestParams(
4936 /*taskCount*/ tcu::Nothing,
4937 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
4938 /*width*/ 5u, // Use an odd value so there's a pixel in the exact center.
4939 /*height*/ 7u)); // Idem.
4940
4941 // VK_KHR_maintenance5: Test default point size is 1.0f
4942 // Draw a single point without writing to PointSize
4943 miscTests->addChild(new SinglePointCase(testCtx, "single_point_default_size", std::move(paramsPtr), false));
4944 }
4945
4946 {
4947 ParamsPtr paramsPtr (new MiscTestParams(
4948 /*taskCount*/ tcu::Nothing,
4949 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
4950 /*width*/ 8u,
4951 /*height*/ 5u)); // Use an odd value so there's a center line.
4952
4953 // Draw a single line
4954 miscTests->addChild(new SingleLineCase(testCtx, "single_line", std::move(paramsPtr)));
4955 }
4956
4957 {
4958 ParamsPtr paramsPtr (new MiscTestParams(
4959 /*taskCount*/ tcu::Nothing,
4960 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
4961 /*width*/ 5u, // Use an odd value so there's a pixel in the exact center.
4962 /*height*/ 7u)); // Idem.
4963
4964 // Draw a single triangle
4965 miscTests->addChild(new SingleTriangleCase(testCtx, "single_triangle", std::move(paramsPtr)));
4966 }
4967
4968 {
4969 ParamsPtr paramsPtr (new MiscTestParams(
4970 /*taskCount*/ tcu::Nothing,
4971 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
4972 /*width*/ 16u,
4973 /*height*/ 16u));
4974
4975 // Draw the maximum number of points
4976 miscTests->addChild(new MaxPointsCase(testCtx, "max_points", std::move(paramsPtr)));
4977 }
4978
4979 {
4980 ParamsPtr paramsPtr (new MiscTestParams(
4981 /*taskCount*/ tcu::Nothing,
4982 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
4983 /*width*/ 1u,
4984 /*height*/ 1020u));
4985
4986 // Draw the maximum number of lines
4987 miscTests->addChild(new MaxLinesCase(testCtx, "max_lines", std::move(paramsPtr)));
4988 }
4989
4990 {
4991 const tcu::UVec3 localSizes[] =
4992 {
4993 tcu::UVec3(2u, 4u, 8u),
4994 tcu::UVec3(4u, 2u, 4u),
4995 tcu::UVec3(2u, 2u, 4u),
4996 };
4997
4998 // Draw the maximum number of triangles using a work group size of...
4999 for (const auto& localSize : localSizes)
5000 {
5001 const auto workGroupSize = (localSize.x() * localSize.y() * localSize.z());
5002 const auto wgsStr = std::to_string(workGroupSize);
5003 const auto testName = "max_triangles_workgroupsize_" + wgsStr;
5004
5005 ParamsPtr paramsPtr (new MaxTrianglesCase::Params(
5006 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5007 /*width*/ 512u,
5008 /*height*/ 512u,
5009 /*localSize*/ localSize));
5010
5011 miscTests->addChild(new MaxTrianglesCase(testCtx, testName, std::move(paramsPtr)));
5012 }
5013 }
5014
5015 using LargeWorkGroupParamsPtr = std::unique_ptr<LargeWorkGroupParams>;
5016 const int dimensionCases[] = { 0, 1, 2 };
5017
5018 for (const auto& dim : dimensionCases)
5019 {
5020 const auto dimChar = dimSuffix(dim);
5021
5022 {
5023 tcu::UVec3 taskCount (8u, 8u, 8u);
5024 taskCount[dim] = 65535u;
5025
5026 LargeWorkGroupParamsPtr lwgParamsPtr (new LargeWorkGroupParams(
5027 /*taskCount*/ tcu::just(taskCount),
5028 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5029 /*width*/ 2040u,
5030 /*height*/ 2056u,
5031 /*localInvocations*/ tcu::UVec3(1u, 1u, 1u)));
5032
5033 ParamsPtr paramsPtr (lwgParamsPtr.release());
5034
5035 const auto name = std::string("many_task_work_groups_") + dimChar;
5036
5037 miscTests->addChild(new LargeWorkGroupCase(testCtx, name, std::move(paramsPtr)));
5038 }
5039
5040 {
5041 tcu::UVec3 meshCount (8u, 8u, 8u);
5042 meshCount[dim] = 65535u;
5043
5044 LargeWorkGroupParamsPtr lwgParamsPtr (new LargeWorkGroupParams(
5045 /*taskCount*/ tcu::Nothing,
5046 /*meshCount*/ meshCount,
5047 /*width*/ 2040u,
5048 /*height*/ 2056u,
5049 /*localInvocations*/ tcu::UVec3(1u, 1u, 1u)));
5050
5051 ParamsPtr paramsPtr (lwgParamsPtr.release());
5052
5053 const auto name = std::string("many_mesh_work_groups_") + dimChar;
5054
5055 miscTests->addChild(new LargeWorkGroupCase(testCtx, name, std::move(paramsPtr)));
5056 }
5057
5058 {
5059 tcu::UVec3 meshCount (1u, 1u, 1u);
5060 tcu::UVec3 taskCount (1u, 1u, 1u);
5061 tcu::UVec3 localInvs (1u, 1u, 1u);
5062
5063 meshCount[dim] = 256u;
5064 taskCount[dim] = 128u;
5065 localInvs[dim] = 128u;
5066
5067 LargeWorkGroupParamsPtr lwgParamsPtr (new LargeWorkGroupParams(
5068 /*taskCount*/ tcu::just(taskCount),
5069 /*meshCount*/ meshCount,
5070 /*width*/ 2048u,
5071 /*height*/ 2048u,
5072 /*localInvocations*/ localInvs));
5073
5074 ParamsPtr paramsPtr (lwgParamsPtr.release());
5075
5076 const auto name = std::string("many_task_mesh_work_groups_") + dimChar;
5077
5078 miscTests->addChild(new LargeWorkGroupCase(testCtx, name, std::move(paramsPtr)));
5079 }
5080 }
5081
5082 {
5083 const PrimitiveType types[] = {
5084 PrimitiveType::POINTS,
5085 PrimitiveType::LINES,
5086 PrimitiveType::TRIANGLES,
5087 };
5088
5089 for (int i = 0; i < 2; ++i)
5090 {
5091 const bool extraWrites = (i > 0);
5092
5093 // XXX Is this test legal? [https://gitlab.khronos.org/GLSL/GLSL/-/merge_requests/77#note_348252]
5094 if (extraWrites)
5095 continue;
5096
5097 for (const auto primType : types)
5098 {
5099 std::unique_ptr<NoPrimitivesParams> params (new NoPrimitivesParams(
5100 /*taskCount*/ (extraWrites ? tcu::just(tcu::UVec3(1u, 1u, 1u)) : tcu::Nothing),
5101 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5102 /*width*/ 16u,
5103 /*height*/ 16u,
5104 /*primitiveType*/ primType));
5105
5106 ParamsPtr paramsPtr (params.release());
5107 const auto primName = primitiveTypeName(primType);
5108 const std::string name = "no_" + primName + (extraWrites ? "_extra_writes" : "");
5109
5110 miscTests->addChild(extraWrites
5111 ? (new NoPrimitivesExtraWritesCase(testCtx, name, std::move(paramsPtr)))
5112 : (new NoPrimitivesCase(testCtx, name, std::move(paramsPtr))));
5113 }
5114 }
5115 }
5116
5117 {
5118 for (int i = 0; i < 2; ++i)
5119 {
5120 const bool useTaskShader = (i == 0);
5121
5122 ParamsPtr paramsPtr (new MiscTestParams(
5123 /*taskCount*/ (useTaskShader ? tcu::just(tcu::UVec3(1u, 1u, 1u)) : tcu::Nothing),
5124 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5125 /*width*/ 1u,
5126 /*height*/ 1u));
5127
5128 const std::string shader = (useTaskShader ? "task" : "mesh");
5129 const std::string name = "barrier_in_" + shader;
5130
5131 miscTests->addChild(new SimpleBarrierCase(testCtx, name, std::move(paramsPtr)));
5132 }
5133 }
5134
5135 {
5136 const struct
5137 {
5138 MemoryBarrierType memBarrierType;
5139 std::string caseName;
5140 } barrierTypes[] =
5141 {
5142 { MemoryBarrierType::SHARED, "memory_barrier_shared" },
5143 { MemoryBarrierType::GROUP, "group_memory_barrier" },
5144 };
5145
5146 for (const auto& barrierCase : barrierTypes)
5147 {
5148 for (int i = 0; i < 2; ++i)
5149 {
5150 const bool useTaskShader = (i == 0);
5151
5152 std::unique_ptr<MemoryBarrierParams> paramsPtr (new MemoryBarrierParams(
5153 /*taskCount*/ (useTaskShader ? tcu::just(tcu::UVec3(1u, 1u, 1u)) : tcu::Nothing),
5154 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5155 /*width*/ 1u,
5156 /*height*/ 1u,
5157 /*memBarrierType*/ barrierCase.memBarrierType));
5158
5159 const std::string shader = (useTaskShader ? "task" : "mesh");
5160 const std::string name = barrierCase.caseName + "_in_" + shader;
5161
5162 miscTests->addChild(new MemoryBarrierCase(testCtx, name, std::move(paramsPtr)));
5163 }
5164 }
5165 }
5166
5167 {
5168 for (int i = 0; i < 2; ++i)
5169 {
5170 const bool useTaskShader = (i > 0);
5171 const auto name = std::string("custom_attributes") + (useTaskShader ? "_and_task_shader" : "");
5172
5173 ParamsPtr paramsPtr (new MiscTestParams(
5174 /*taskCount*/ (useTaskShader ? tcu::just(tcu::UVec3(1u, 1u, 1u)) : tcu::Nothing),
5175 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5176 /*width*/ 32u,
5177 /*height*/ 32u));
5178
5179 miscTests->addChild(new CustomAttributesCase(testCtx, name, std::move(paramsPtr)));
5180 }
5181 }
5182
5183 {
5184 for (int i = 0; i < 2; ++i)
5185 {
5186 const bool useTaskShader = (i > 0);
5187 const auto name = std::string("push_constant") + (useTaskShader ? "_and_task_shader" : "");
5188
5189 ParamsPtr paramsPtr (new MiscTestParams(
5190 /*taskCount*/ (useTaskShader ? tcu::just(tcu::UVec3(1u, 1u, 1u)) : tcu::Nothing),
5191 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5192 /*width*/ 16u,
5193 /*height*/ 16u));
5194
5195 miscTests->addChild(new PushConstantCase(testCtx, name, std::move(paramsPtr)));
5196 }
5197 }
5198
5199 {
5200 ParamsPtr paramsPtr (new MaximizeThreadsParams(
5201 /*taskCount*/ tcu::Nothing,
5202 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5203 /*width*/ 128u,
5204 /*height*/ 1u,
5205 /*localSize*/ 32u,
5206 /*numVertices*/ 128u,
5207 /*numPrimitives*/ 256u));
5208
5209 miscTests->addChild(new MaximizePrimitivesCase(testCtx, "maximize_primitives", std::move(paramsPtr)));
5210 }
5211
5212 {
5213 ParamsPtr paramsPtr (new MaximizeThreadsParams(
5214 /*taskCount*/ tcu::Nothing,
5215 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5216 /*width*/ 64u,
5217 /*height*/ 1u,
5218 /*localSize*/ 32u,
5219 /*numVertices*/ 256u,
5220 /*numPrimitives*/ 128u));
5221
5222 miscTests->addChild(new MaximizeVerticesCase(testCtx, "maximize_vertices", std::move(paramsPtr)));
5223 }
5224
5225 {
5226 const uint32_t kInvocationCases[] = { 32u, 64u, 128u, 256u };
5227
5228 for (const auto& invocationCase : kInvocationCases)
5229 {
5230 const auto invsStr = std::to_string(invocationCase);
5231 const auto numPixels = invocationCase / 2u;
5232
5233 ParamsPtr paramsPtr (new MaximizeThreadsParams(
5234 /*taskCount*/ tcu::Nothing,
5235 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5236 /*width*/ numPixels,
5237 /*height*/ 1u,
5238 /*localSize*/ invocationCase,
5239 /*numVertices*/ numPixels,
5240 /*numPrimitives*/ numPixels));
5241
5242 miscTests->addChild(new MaximizeInvocationsCase(testCtx, "maximize_invocations_" + invsStr, std::move(paramsPtr)));
5243 }
5244 }
5245
5246 {
5247 for (int i = 0; i < 2; ++i)
5248 {
5249 const bool useDynamicTopology = (i > 0);
5250
5251 ParamsPtr paramsPtr (new MixedPipelinesParams(
5252 /*taskCount*/ tcu::Nothing,
5253 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5254 /*width*/ 8u,
5255 /*height*/ 8u,
5256 /*dynamicTopology*/ useDynamicTopology));
5257
5258 const std::string nameSuffix = (useDynamicTopology ? "_dynamic_topology" : "");
5259 const std::string descSuffix = (useDynamicTopology ? " and use dynamic topology" : "");
5260
5261 miscTests->addChild(new MixedPipelinesCase(testCtx, "mixed_pipelines" + nameSuffix, std::move(paramsPtr)));
5262 }
5263 }
5264
5265 for (int i = 0; i < 2; ++i)
5266 {
5267 const bool useTask = (i > 0);
5268 const tcu::Maybe<tcu::UVec3> taskCount = (useTask ? tcu::just(tcu::UVec3(1u, 1u, 1u)) : tcu::nothing<tcu::UVec3>());
5269 const std::string testName = std::string("first_invocation_") + (useTask ? "task" : "mesh");
5270
5271 ParamsPtr paramsPtr (new MiscTestParams(
5272 /*taskCount*/ taskCount,
5273 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5274 /*width*/ 128u,
5275 /*height*/ 1u));
5276
5277 miscTests->addChild(new FirstInvocationCase(testCtx, testName, std::move(paramsPtr)));
5278 }
5279
5280 for (int i = 0; i < 2; ++i)
5281 {
5282 const bool useTask = (i > 0);
5283 const tcu::Maybe<tcu::UVec3> taskCount = (useTask ? tcu::just(tcu::UVec3(1u, 1u, 1u)) : tcu::nothing<tcu::UVec3>());
5284 const std::string testName = std::string("local_size_id_") + (useTask ? "task" : "mesh");
5285
5286 ParamsPtr paramsPtr (new MiscTestParams(
5287 /*taskCount*/ taskCount,
5288 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5289 /*width*/ 32u,
5290 /*height*/ 1u));
5291
5292 miscTests->addChild(new LocalSizeIdCase(testCtx, testName, std::move(paramsPtr)));
5293 }
5294
5295 if (false) // Disabled. This may be illegal.
5296 {
5297 ParamsPtr paramsPtr (new MiscTestParams(
5298 /*taskCount*/ tcu::UVec3(1u, 1u, 1u),
5299 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5300 /*width*/ 8u,
5301 /*height*/ 8u));
5302
5303 miscTests->addChild(new MultipleTaskPayloadsCase(testCtx, "multiple_task_payloads", std::move(paramsPtr)));
5304 }
5305
5306 {
5307 ParamsPtr paramsPtr (new MiscTestParams(
5308 /*taskCount*/ tcu::UVec3(1u, 1u, 1u),
5309 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5310 /*width*/ 8u,
5311 /*height*/ 8u));
5312
5313 miscTests->addChild(new PayloadReadCase(testCtx, "payload_read", std::move(paramsPtr)));
5314 }
5315
5316 {
5317 ParamsPtr paramsPtr (new MiscTestParams(
5318 /*taskCount*/ tcu::UVec3(1u, 1u, 1u),
5319 /*meshCount*/ tcu::UVec3(1u, 1u, 1u),
5320 /*width*/ 8u,
5321 /*height*/ 8u));
5322
5323 miscTests->addChild(new RebindSetsCase(testCtx, "rebind_sets", std::move(paramsPtr)));
5324 }
5325
5326 return miscTests.release();
5327 }
5328
5329 } // MeshShader
5330 } // vkt
5331