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 Builtin Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktMeshShaderBuiltinTests.hpp"
26 #include "vktMeshShaderUtil.hpp"
27 #include "vktTestCase.hpp"
28
29 #include "vkTypeUtil.hpp"
30 #include "vkImageUtil.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkImageWithMemory.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vkCmdUtil.hpp"
36 #include "vkBarrierUtil.hpp"
37
38 #include "tcuTexture.hpp"
39 #include "tcuTestLog.hpp"
40
41 #include <vector>
42 #include <algorithm>
43 #include <sstream>
44 #include <map>
45 #include <utility>
46 #include <sstream>
47
48 namespace vkt
49 {
50 namespace MeshShader
51 {
52
53 namespace
54 {
55
56 // Wraps a tcu::IVec2 with a custom operator< that uses the X and Y components in component order so it can be used as a map key.
57 // Can be converted to and from a tcu::IVec2 automatically.
58 class CoordKey
59 {
60 public:
CoordKey(const tcu::IVec2 & coords)61 CoordKey(const tcu::IVec2 &coords) : m_coords(coords)
62 {
63 }
64
operator tcu::IVec2() const65 operator tcu::IVec2() const
66 {
67 return m_coords;
68 }
69
operator <(const CoordKey & other) const70 bool operator<(const CoordKey &other) const
71 {
72 const auto &a = this->m_coords;
73 const auto &b = other.m_coords;
74
75 for (int i = 0; i < tcu::IVec2::SIZE; ++i)
76 {
77 if (a[i] < b[i])
78 return true;
79 if (a[i] > b[i])
80 return false;
81 }
82
83 return false;
84 }
85
86 private:
87 const tcu::IVec2 m_coords;
88 };
89
90 using namespace vk;
91
92 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
93 using DrawCommandVec = std::vector<VkDrawMeshTasksIndirectCommandNV>;
94 using ImageWithMemoryPtr = de::MovePtr<ImageWithMemory>;
95 using BufferWithMemoryPtr = de::MovePtr<BufferWithMemory>;
96 using ViewportVec = std::vector<VkViewport>;
97 using ColorVec = std::vector<tcu::Vec4>;
98 using PixelMap = std::map<CoordKey, tcu::Vec4>; // Coordinates to color.
99
getDefaultExtent()100 VkExtent2D getDefaultExtent()
101 {
102 return makeExtent2D(8u, 8u);
103 }
104
getLinearExtent()105 VkExtent2D getLinearExtent()
106 {
107 return makeExtent2D(8u, 1u);
108 }
109
110 struct JobSize
111 {
112 uint32_t numTasks;
113 uint32_t localSize;
114 };
115
getLargeJobSize()116 JobSize getLargeJobSize()
117 {
118 return JobSize{8u, 8u};
119 }
120
121 // Single draw command with the given number of tasks, 1 by default.
getDefaultDrawCommands(uint32_t taskCount=1u)122 DrawCommandVec getDefaultDrawCommands(uint32_t taskCount = 1u)
123 {
124 return DrawCommandVec(1u, makeDrawMeshTasksIndirectCommandNV(taskCount, 0u));
125 }
126
127 // Basic fragment shader that draws fragments in blue.
getBasicFragShader()128 std::string getBasicFragShader()
129 {
130 return "#version 460\n"
131 "#extension GL_NV_mesh_shader : enable\n"
132 "\n"
133 "layout (location=0) out vec4 outColor;\n"
134 "\n"
135 "void main ()\n"
136 "{\n"
137 " outColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
138 "}\n";
139 }
140
141 struct IterationParams
142 {
143 VkExtent2D colorExtent;
144 uint32_t numLayers;
145 DrawCommandVec drawArgs;
146 bool indirect;
147 ViewportVec viewports; // If empty, a single default viewport is used.
148 tcu::Maybe<FragmentSize> fragmentSize;
149 };
150
151 class MeshShaderBuiltinInstance : public vkt::TestInstance
152 {
153 public:
MeshShaderBuiltinInstance(Context & context,const IterationParams & params)154 MeshShaderBuiltinInstance(Context &context, const IterationParams ¶ms)
155 : vkt::TestInstance(context)
156 , m_params(params)
157 {
158 }
~MeshShaderBuiltinInstance(void)159 virtual ~MeshShaderBuiltinInstance(void)
160 {
161 }
162
163 tcu::TestStatus iterate() override;
164 virtual void verifyResults(const tcu::ConstPixelBufferAccess &result) = 0;
165
166 protected:
167 IterationParams m_params;
168 };
169
iterate()170 tcu::TestStatus MeshShaderBuiltinInstance::iterate()
171 {
172 const auto &vkd = m_context.getDeviceInterface();
173 const auto device = m_context.getDevice();
174 auto &alloc = m_context.getDefaultAllocator();
175 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
176 const auto queue = m_context.getUniversalQueue();
177 const auto &binaries = m_context.getBinaryCollection();
178
179 const auto useTask = binaries.contains("task");
180 const auto useFrag = binaries.contains("frag");
181 const auto extent = makeExtent3D(m_params.colorExtent.width, m_params.colorExtent.height, 1u);
182 const auto iExtent3D = tcu::IVec3(static_cast<int>(extent.width), static_cast<int>(extent.height),
183 static_cast<int>(m_params.numLayers));
184 const auto format = VK_FORMAT_R8G8B8A8_UNORM;
185 const auto tcuFormat = mapVkFormat(format);
186 const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
187 const auto viewType = ((m_params.numLayers > 1u) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D);
188 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_params.numLayers);
189 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, m_params.numLayers);
190 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
191
192 ImageWithMemoryPtr colorBuffer;
193 Move<VkImageView> colorBufferView;
194 {
195 const VkImageCreateInfo colorBufferInfo = {
196 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
197 nullptr, // const void* pNext;
198 0u, // VkImageCreateFlags flags;
199 VK_IMAGE_TYPE_2D, // VkImageType imageType;
200 format, // VkFormat format;
201 extent, // VkExtent3D extent;
202 1u, // uint32_t mipLevels;
203 m_params.numLayers, // uint32_t arrayLayers;
204 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
205 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
206 colorUsage, // VkImageUsageFlags usage;
207 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
208 0u, // uint32_t queueFamilyIndexCount;
209 nullptr, // const uint32_t* pQueueFamilyIndices;
210 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
211 };
212 colorBuffer =
213 ImageWithMemoryPtr(new ImageWithMemory(vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any));
214 colorBufferView = makeImageView(vkd, device, colorBuffer->get(), viewType, format, colorSRR);
215 }
216
217 // Empty descriptor set layout.
218 DescriptorSetLayoutBuilder layoutBuilder;
219 const auto setLayout = layoutBuilder.build(vkd, device);
220
221 // Pipeline layout.
222 const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
223
224 // Render pass and framebuffer.
225 const auto renderPass = makeRenderPass(vkd, device, format);
226 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorBufferView.get(), extent.width,
227 extent.height, m_params.numLayers);
228
229 // Pipeline.
230 Move<VkShaderModule> taskModule;
231 Move<VkShaderModule> meshModule;
232 Move<VkShaderModule> fragModule;
233
234 if (useTask)
235 taskModule = createShaderModule(vkd, device, binaries.get("task"));
236 if (useFrag)
237 fragModule = createShaderModule(vkd, device, binaries.get("frag"));
238 meshModule = createShaderModule(vkd, device, binaries.get("mesh"));
239
240 std::vector<VkViewport> viewports;
241 std::vector<VkRect2D> scissors;
242 if (m_params.viewports.empty())
243 {
244 // Default ones.
245 viewports.push_back(makeViewport(extent));
246 scissors.push_back(makeRect2D(extent));
247 }
248 else
249 {
250 // The desired viewports and the same number of default scissors.
251 viewports.reserve(m_params.viewports.size());
252 std::copy(begin(m_params.viewports), end(m_params.viewports), std::back_inserter(viewports));
253 scissors.resize(viewports.size(), makeRect2D(extent));
254 }
255
256 using ShadingRateInfoPtr = de::MovePtr<VkPipelineFragmentShadingRateStateCreateInfoKHR>;
257 ShadingRateInfoPtr pNext;
258 if (static_cast<bool>(m_params.fragmentSize))
259 {
260 pNext = ShadingRateInfoPtr(new VkPipelineFragmentShadingRateStateCreateInfoKHR);
261 *pNext = initVulkanStructure();
262
263 pNext->fragmentSize = getShadingRateSize(m_params.fragmentSize.get());
264 pNext->combinerOps[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR;
265 pNext->combinerOps[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR;
266 }
267
268 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(), taskModule.get(), meshModule.get(),
269 fragModule.get(), renderPass.get(), viewports, scissors, 0u, nullptr,
270 nullptr, nullptr, nullptr, nullptr, 0u, pNext.get());
271
272 // Command pool and buffer.
273 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
274 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
275 const auto cmdBuffer = cmdBufferPtr.get();
276
277 // Indirect buffer if needed.
278 BufferWithMemoryPtr indirectBuffer;
279
280 DE_ASSERT(!m_params.drawArgs.empty());
281 if (m_params.indirect)
282 {
283 // Indirect draws.
284 const auto indirectBufferSize = static_cast<VkDeviceSize>(de::dataSize(m_params.drawArgs));
285 const auto indirectBufferUsage = (VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
286 const auto indirectBufferInfo = makeBufferCreateInfo(indirectBufferSize, indirectBufferUsage);
287 indirectBuffer = BufferWithMemoryPtr(
288 new BufferWithMemory(vkd, device, alloc, indirectBufferInfo, MemoryRequirement::HostVisible));
289 auto &indirectBufferAlloc = indirectBuffer->getAllocation();
290 void *indirectBufferData = indirectBufferAlloc.getHostPtr();
291
292 deMemcpy(indirectBufferData, m_params.drawArgs.data(), static_cast<size_t>(indirectBufferSize));
293 flushAlloc(vkd, device, indirectBufferAlloc);
294 }
295
296 // Submit commands.
297 beginCommandBuffer(vkd, cmdBuffer);
298 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), clearColor);
299 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
300
301 if (!m_params.indirect)
302 {
303 for (const auto &command : m_params.drawArgs)
304 vkd.cmdDrawMeshTasksNV(cmdBuffer, command.taskCount, command.firstTask);
305 }
306 else
307 {
308 const auto numDraws = static_cast<uint32_t>(m_params.drawArgs.size());
309 const auto stride = static_cast<uint32_t>(sizeof(decltype(m_params.drawArgs)::value_type));
310 vkd.cmdDrawMeshTasksIndirectNV(cmdBuffer, indirectBuffer->get(), 0ull, numDraws, stride);
311 }
312
313 endRenderPass(vkd, cmdBuffer);
314
315 // Output buffer to extract the color buffer contents.
316 BufferWithMemoryPtr outBuffer;
317 void *outBufferData = nullptr;
318 {
319 const auto layerSize = static_cast<VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) *
320 extent.width * extent.height);
321 const auto outBufferSize = layerSize * m_params.numLayers;
322 const auto outBufferUsage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
323 const auto outBufferInfo = makeBufferCreateInfo(outBufferSize, outBufferUsage);
324
325 outBuffer = BufferWithMemoryPtr(
326 new BufferWithMemory(vkd, device, alloc, outBufferInfo, MemoryRequirement::HostVisible));
327 outBufferData = outBuffer->getAllocation().getHostPtr();
328 }
329
330 // Transition image layout.
331 const auto preTransferBarrier = makeImageMemoryBarrier(
332 (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), VK_ACCESS_TRANSFER_READ_BIT,
333 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer->get(), colorSRR);
334
335 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
336 0u, nullptr, 0u, nullptr, 1u, &preTransferBarrier);
337
338 // Copy image to output buffer.
339 const std::vector<VkBufferImageCopy> regions(1u, makeBufferImageCopy(extent, colorSRL));
340 vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, outBuffer->get(),
341 static_cast<uint32_t>(regions.size()), de::dataOrNull(regions));
342
343 // Transfer to host barrier.
344 const auto postTransferBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
345 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u,
346 &postTransferBarrier, 0u, nullptr, 0u, nullptr);
347
348 endCommandBuffer(vkd, cmdBuffer);
349 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
350
351 // Invalidate alloc and verify result.
352 {
353 auto &outBufferAlloc = outBuffer->getAllocation();
354 invalidateAlloc(vkd, device, outBufferAlloc);
355
356 tcu::ConstPixelBufferAccess result(tcuFormat, iExtent3D, outBufferData);
357 verifyResults(result);
358 }
359
360 return tcu::TestStatus::pass("Pass");
361 }
362
363 // Abstract case that implements the generic checkSupport method.
364 class MeshShaderBuiltinCase : public vkt::TestCase
365 {
366 public:
MeshShaderBuiltinCase(tcu::TestContext & testCtx,const std::string & name,bool taskNeeded)367 MeshShaderBuiltinCase(tcu::TestContext &testCtx, const std::string &name, bool taskNeeded)
368 : vkt::TestCase(testCtx, name)
369 , m_taskNeeded(taskNeeded)
370 {
371 }
~MeshShaderBuiltinCase(void)372 virtual ~MeshShaderBuiltinCase(void)
373 {
374 }
375
376 void checkSupport(Context &context) const override;
377
378 protected:
379 const bool m_taskNeeded;
380 };
381
checkSupport(Context & context) const382 void MeshShaderBuiltinCase::checkSupport(Context &context) const
383 {
384 checkTaskMeshShaderSupportNV(context, m_taskNeeded, true);
385 }
386
387 // Instance that verifies color layers.
388 class FullScreenColorInstance : public MeshShaderBuiltinInstance
389 {
390 public:
FullScreenColorInstance(Context & context,const IterationParams & params,const ColorVec & expectedColors)391 FullScreenColorInstance(Context &context, const IterationParams ¶ms, const ColorVec &expectedColors)
392 : MeshShaderBuiltinInstance(context, params)
393 , m_expectedColors(expectedColors)
394 {
395 }
~FullScreenColorInstance(void)396 virtual ~FullScreenColorInstance(void)
397 {
398 }
399
400 void verifyResults(const tcu::ConstPixelBufferAccess &result) override;
401
402 protected:
403 const ColorVec m_expectedColors;
404 };
405
verifyResults(const tcu::ConstPixelBufferAccess & result)406 void FullScreenColorInstance::verifyResults(const tcu::ConstPixelBufferAccess &result)
407 {
408 auto &log = m_context.getTestContext().getLog();
409 bool fail = false;
410 const auto width = result.getWidth();
411 const auto height = result.getHeight();
412 const auto depth = result.getDepth();
413
414 for (int z = 0; z < depth; ++z)
415 {
416 const auto &expected = m_expectedColors.at(z);
417
418 for (int y = 0; y < height; ++y)
419 for (int x = 0; x < width; ++x)
420 {
421 const auto resultColor = result.getPixel(x, y, z);
422 if (resultColor != expected)
423 {
424 std::ostringstream msg;
425 msg << "Pixel (" << x << ", " << y << ", " << z << ") failed: expected " << expected
426 << " and found " << resultColor;
427 log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
428 fail = true;
429 }
430 }
431 }
432
433 if (fail)
434 {
435 log << tcu::TestLog::Image("Result", "", result);
436 TCU_FAIL("Check log for details");
437 }
438 }
439
440 // Instance that verifies single-layer framebuffers divided into 4 quadrants.
441 class QuadrantsInstance : public MeshShaderBuiltinInstance
442 {
443 public:
QuadrantsInstance(Context & context,const IterationParams & params,const tcu::Vec4 topLeft,const tcu::Vec4 topRight,const tcu::Vec4 bottomLeft,const tcu::Vec4 bottomRight)444 QuadrantsInstance(Context &context, const IterationParams ¶ms, const tcu::Vec4 topLeft,
445 const tcu::Vec4 topRight, const tcu::Vec4 bottomLeft, const tcu::Vec4 bottomRight)
446 : MeshShaderBuiltinInstance(context, params)
447 , m_topLeft(topLeft)
448 , m_topRight(topRight)
449 , m_bottomLeft(bottomLeft)
450 , m_bottomRight(bottomRight)
451 {
452 }
~QuadrantsInstance(void)453 virtual ~QuadrantsInstance(void)
454 {
455 }
456
457 void verifyResults(const tcu::ConstPixelBufferAccess &result) override;
458
459 protected:
460 const tcu::Vec4 m_topLeft;
461 const tcu::Vec4 m_topRight;
462 const tcu::Vec4 m_bottomLeft;
463 const tcu::Vec4 m_bottomRight;
464 };
465
verifyResults(const tcu::ConstPixelBufferAccess & result)466 void QuadrantsInstance::verifyResults(const tcu::ConstPixelBufferAccess &result)
467 {
468 const auto width = result.getWidth();
469 const auto height = result.getHeight();
470 const auto depth = result.getDepth();
471
472 DE_ASSERT(depth == 1);
473 DE_ASSERT(width > 0 && width % 2 == 0);
474 DE_ASSERT(height > 0 && height % 2 == 0);
475 DE_UNREF(depth); // For release builds.
476
477 const auto halfWidth = width / 2;
478 const auto halfHeight = height / 2;
479 tcu::Vec4 expected;
480
481 for (int y = 0; y < height; ++y)
482 for (int x = 0; x < width; ++x)
483 {
484 // Choose the right quadrant
485 if (y < halfHeight)
486 expected = ((x < halfWidth) ? m_topLeft : m_topRight);
487 else
488 expected = ((x < halfWidth) ? m_bottomLeft : m_bottomRight);
489
490 const auto resultColor = result.getPixel(x, y);
491 if (resultColor != expected)
492 {
493 std::ostringstream msg;
494 msg << "Pixel (" << x << ", " << y << ") failed: expected " << expected << " and found " << resultColor;
495 TCU_FAIL(msg.str());
496 }
497 }
498 }
499
500 // Instance that verifies single-layer framebuffers with specific pixels set to some color.
501 struct PixelVerifierParams
502 {
503 const tcu::Vec4 background;
504 const PixelMap pixelMap;
505 };
506
507 class PixelsInstance : public MeshShaderBuiltinInstance
508 {
509 public:
PixelsInstance(Context & context,const IterationParams & params,const PixelVerifierParams & pixelParams)510 PixelsInstance(Context &context, const IterationParams ¶ms, const PixelVerifierParams &pixelParams)
511 : MeshShaderBuiltinInstance(context, params)
512 , m_pixelParams(pixelParams)
513 {
514 }
~PixelsInstance(void)515 virtual ~PixelsInstance(void)
516 {
517 }
518
519 void verifyResults(const tcu::ConstPixelBufferAccess &result) override;
520
521 protected:
522 const PixelVerifierParams m_pixelParams;
523 };
524
verifyResults(const tcu::ConstPixelBufferAccess & result)525 void PixelsInstance::verifyResults(const tcu::ConstPixelBufferAccess &result)
526 {
527 const auto width = result.getWidth();
528 const auto height = result.getHeight();
529 const auto depth = result.getDepth();
530
531 DE_ASSERT(depth == 1);
532 DE_UNREF(depth); // For release builds.
533
534 for (int y = 0; y < height; ++y)
535 for (int x = 0; x < width; ++x)
536 {
537 const tcu::IVec2 coords(x, y);
538 const auto iter = m_pixelParams.pixelMap.find(coords);
539 const auto expected = ((iter == m_pixelParams.pixelMap.end()) ? m_pixelParams.background : iter->second);
540 const auto resultColor = result.getPixel(x, y);
541
542 if (resultColor != expected)
543 {
544 std::ostringstream msg;
545 msg << "Pixel (" << x << ", " << y << ") failed: expected " << expected << " and found " << resultColor;
546 TCU_FAIL(msg.str());
547 }
548 }
549 }
550
551 // Primitive ID cases.
552 class PrimitiveIdCase : public MeshShaderBuiltinCase
553 {
554 public:
PrimitiveIdCase(tcu::TestContext & testCtx,const std::string & name,bool glslFrag)555 PrimitiveIdCase(tcu::TestContext &testCtx, const std::string &name, bool glslFrag)
556 : MeshShaderBuiltinCase(testCtx, name, false /*taskNeeded*/)
557 , m_glslFrag(glslFrag)
558 {
559 }
~PrimitiveIdCase(void)560 virtual ~PrimitiveIdCase(void)
561 {
562 }
563
564 void initPrograms(vk::SourceCollections &programCollection) const override;
565 void checkSupport(Context &context) const override;
566 TestInstance *createInstance(Context &context) const override;
567
568 protected:
569 // Fragment shader in GLSL means glslang will use the Geometry capability due to gl_PrimitiveID.
570 const bool m_glslFrag;
571 };
572
initPrograms(vk::SourceCollections & programCollection) const573 void PrimitiveIdCase::initPrograms(vk::SourceCollections &programCollection) const
574 {
575 // Mesh shader.
576 {
577 std::ostringstream mesh;
578 mesh << "#version 460\n"
579 << "#extension GL_NV_mesh_shader : enable\n"
580 << "\n"
581 << "layout (local_size_x=1) in;\n"
582 << "layout (triangles) out;\n"
583 << "layout (max_vertices=3, max_primitives=1) out;\n"
584 << "\n"
585 << "perprimitiveNV out gl_MeshPerPrimitiveNV {\n"
586 << " int gl_PrimitiveID;\n"
587 << "} gl_MeshPrimitivesNV[];\n"
588 << "\n"
589 << "void main ()\n"
590 << "{\n"
591 << " gl_PrimitiveCountNV = 1u;\n"
592 << "\n"
593 << " gl_PrimitiveIndicesNV[0] = 0;\n"
594 << " gl_PrimitiveIndicesNV[1] = 1;\n"
595 << " gl_PrimitiveIndicesNV[2] = 2;\n"
596 << "\n"
597 << " gl_MeshVerticesNV[0].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
598 << " gl_MeshVerticesNV[1].gl_Position = vec4(-1.0, 3.0, 0.0, 1.0);\n"
599 << " gl_MeshVerticesNV[2].gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
600 << "\n"
601 // Sets an arbitrary primitive id.
602 << " gl_MeshPrimitivesNV[0].gl_PrimitiveID = 1629198956;\n"
603 << "}\n";
604 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
605 }
606
607 // Frag shader.
608 if (m_glslFrag)
609 {
610 std::ostringstream frag;
611 frag << "#version 460\n"
612 << "#extension GL_NV_mesh_shader : enable\n"
613 << "\n"
614 << "layout (location=0) out vec4 outColor;\n"
615 << "\n"
616 << "void main ()\n"
617 << "{\n"
618 // Checks the primitive id matches.
619 << " outColor = ((gl_PrimitiveID == 1629198956) ? vec4(0.0, 0.0, 1.0, 1.0) : vec4(0.0, 0.0, 0.0, "
620 "1.0));\n"
621 << "}\n";
622 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
623 }
624 else
625 {
626 // This is the same shader as above, but OpCapability Geometry has been replaced by OpCapability MeshShadingNV in order to
627 // access gl_PrimitiveID. This also needs the SPV_NV_mesh_shader extension.
628 std::ostringstream frag;
629 frag << "; Version: 1.0\n"
630 << "; Generator: Khronos Glslang Reference Front End; 10\n"
631 << "; Bound: 24\n"
632 << "; Schema: 0\n"
633 << " OpCapability Shader\n"
634
635 // Manual change in these lines.
636 //<< " OpCapability Geometry\n"
637 << " OpCapability MeshShadingNV\n"
638 << " OpExtension \"SPV_NV_mesh_shader\"\n"
639
640 << " %1 = OpExtInstImport \"GLSL.std.450\"\n"
641 << " OpMemoryModel Logical GLSL450\n"
642 << " OpEntryPoint Fragment %4 \"main\" %9 %12\n"
643 << " OpExecutionMode %4 OriginUpperLeft\n"
644 << " OpDecorate %9 Location 0\n"
645 << " OpDecorate %12 Flat\n"
646 << " OpDecorate %12 BuiltIn PrimitiveId\n"
647 << " %2 = OpTypeVoid\n"
648 << " %3 = OpTypeFunction %2\n"
649 << " %6 = OpTypeFloat 32\n"
650 << " %7 = OpTypeVector %6 4\n"
651 << " %8 = OpTypePointer Output %7\n"
652 << " %9 = OpVariable %8 Output\n"
653 << "%10 = OpTypeInt 32 1\n"
654 << "%11 = OpTypePointer Input %10\n"
655 << "%12 = OpVariable %11 Input\n"
656 << "%14 = OpConstant %10 1629198956\n"
657 << "%15 = OpTypeBool\n"
658 << "%17 = OpConstant %6 0\n"
659 << "%18 = OpConstant %6 1\n"
660 << "%19 = OpConstantComposite %7 %17 %17 %18 %18\n"
661 << "%20 = OpConstantComposite %7 %17 %17 %17 %18\n"
662 << "%21 = OpTypeVector %15 4\n"
663 << " %4 = OpFunction %2 None %3\n"
664 << " %5 = OpLabel\n"
665 << "%13 = OpLoad %10 %12\n"
666 << "%16 = OpIEqual %15 %13 %14\n"
667 << "%22 = OpCompositeConstruct %21 %16 %16 %16 %16\n"
668 << "%23 = OpSelect %7 %22 %19 %20\n"
669 << " OpStore %9 %23\n"
670 << " OpReturn\n"
671 << " OpFunctionEnd\n";
672 programCollection.spirvAsmSources.add("frag") << frag.str();
673 }
674 }
675
checkSupport(Context & context) const676 void PrimitiveIdCase::checkSupport(Context &context) const
677 {
678 MeshShaderBuiltinCase::checkSupport(context);
679
680 // Fragment shader in GLSL means glslang will use the Geometry capability due to gl_PrimitiveID.
681 if (m_glslFrag)
682 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
683 }
684
createInstance(Context & context) const685 TestInstance *PrimitiveIdCase::createInstance(Context &context) const
686 {
687 const ColorVec expectedColors(1u, tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
688 const IterationParams iterationParams = {
689 getDefaultExtent(), // VkExtent2D colorExtent;
690 1u, // uint32_t numLayers;
691 getDefaultDrawCommands(), // DrawCommandVec drawArgs;
692 false, // bool indirect;
693 {}, // ViewportVec viewports; // If empty, a single default viewport is used.
694 tcu::Nothing, // tcu::Maybe<FragmentSize> fragmentSize;
695 };
696 return new FullScreenColorInstance(context, iterationParams, expectedColors);
697 }
698
699 // Layer builtin case.
700 class LayerCase : public MeshShaderBuiltinCase
701 {
702 public:
LayerCase(tcu::TestContext & testCtx,const std::string & name,bool shareVertices)703 LayerCase(tcu::TestContext &testCtx, const std::string &name, bool shareVertices)
704 : MeshShaderBuiltinCase(testCtx, name, false /*taskNeeded*/)
705 , m_shareVertices(shareVertices)
706 {
707 }
~LayerCase(void)708 virtual ~LayerCase(void)
709 {
710 }
711
712 void initPrograms(vk::SourceCollections &programCollection) const override;
713 void checkSupport(Context &context) const override;
714 TestInstance *createInstance(Context &context) const override;
715
716 static constexpr uint32_t kNumLayers = 4u;
717
718 protected:
719 const bool m_shareVertices;
720 };
721
initPrograms(vk::SourceCollections & programCollection) const722 void LayerCase::initPrograms(vk::SourceCollections &programCollection) const
723 {
724 const auto localSize = (m_shareVertices ? kNumLayers : 1u);
725 const auto numPrimitives = (m_shareVertices ? kNumLayers : 1u);
726 const auto layerNumber = (m_shareVertices ? "gl_LocalInvocationIndex" : "gl_WorkGroupID.x");
727
728 // One layer per local invocation or work group (shared vertices or not, respectively).
729 {
730 std::ostringstream mesh;
731 mesh << "#version 460\n"
732 << "#extension GL_NV_mesh_shader : enable\n"
733 << "\n"
734 << "layout (local_size_x=" << localSize << ") in;\n"
735 << "layout (triangles) out;\n"
736 << "layout (max_vertices=3, max_primitives=" << numPrimitives << ") out;\n"
737 << "\n"
738 << "perprimitiveNV out gl_MeshPerPrimitiveNV {\n"
739 << " int gl_Layer;\n"
740 << "} gl_MeshPrimitivesNV[];\n"
741 << "\n"
742 << "void main ()\n"
743 << "{\n"
744 << " gl_PrimitiveCountNV = " << numPrimitives << ";\n"
745 << "\n"
746 << " if (gl_LocalInvocationIndex == 0u)\n"
747 << " {\n"
748 << " gl_MeshVerticesNV[0].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
749 << " gl_MeshVerticesNV[1].gl_Position = vec4(-1.0, 3.0, 0.0, 1.0);\n"
750 << " gl_MeshVerticesNV[2].gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
751 << " }\n"
752 << "\n"
753 << " const uint baseIndex = gl_LocalInvocationIndex * 3u;\n"
754 << " gl_PrimitiveIndicesNV[baseIndex + 0] = 0;\n"
755 << " gl_PrimitiveIndicesNV[baseIndex + 1] = 1;\n"
756 << " gl_PrimitiveIndicesNV[baseIndex + 2] = 2;\n"
757 << "\n"
758 << " gl_MeshPrimitivesNV[gl_LocalInvocationIndex].gl_Layer = int(" << layerNumber << ");\n"
759 << "}\n";
760 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
761 }
762
763 // Fragment shader chooses one color per layer.
764 {
765 std::ostringstream frag;
766 frag << "#version 460\n"
767 << "#extension GL_NV_mesh_shader : enable\n"
768 << "\n"
769 << "layout (location=0) out vec4 outColor;\n"
770 << "\n"
771 << "vec4 colors[" << kNumLayers << "] = vec4[](\n"
772 << " vec4(0.0, 0.0, 1.0, 1.0),\n"
773 << " vec4(1.0, 0.0, 1.0, 1.0),\n"
774 << " vec4(0.0, 1.0, 1.0, 1.0),\n"
775 << " vec4(1.0, 1.0, 0.0, 1.0)\n"
776 << ");\n"
777 << "\n"
778 << "void main ()\n"
779 << "{\n"
780 << " outColor = colors[gl_Layer];\n"
781 << "}\n";
782 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
783 }
784 }
785
checkSupport(Context & context) const786 void LayerCase::checkSupport(Context &context) const
787 {
788 MeshShaderBuiltinCase::checkSupport(context);
789
790 if (!context.contextSupports(vk::ApiVersion(0u, 1u, 2u, 0u)))
791 context.requireDeviceFunctionality("VK_EXT_shader_viewport_index_layer");
792 else
793 {
794 const auto &features = context.getDeviceVulkan12Features();
795 if (!features.shaderOutputLayer)
796 TCU_THROW(NotSupportedError, "shaderOutputLayer feature not supported");
797 }
798 }
799
createInstance(Context & context) const800 TestInstance *LayerCase::createInstance(Context &context) const
801 {
802 ColorVec expectedColors;
803
804 expectedColors.reserve(kNumLayers);
805 expectedColors.push_back(tcu::Vec4(0.0, 0.0, 1.0, 1.0));
806 expectedColors.push_back(tcu::Vec4(1.0, 0.0, 1.0, 1.0));
807 expectedColors.push_back(tcu::Vec4(0.0, 1.0, 1.0, 1.0));
808 expectedColors.push_back(tcu::Vec4(1.0, 1.0, 0.0, 1.0));
809
810 const auto numWorkGroups = (m_shareVertices ? 1u : kNumLayers);
811 const IterationParams iterationParams = {
812 getDefaultExtent(), // VkExtent2D colorExtent;
813 kNumLayers, // uint32_t numLayers;
814 getDefaultDrawCommands(numWorkGroups), // DrawCommandVec drawArgs;
815 false, // bool indirect;
816 {}, // ViewportVec viewports; // If empty, a single default viewport is used.
817 tcu::Nothing, // tcu::Maybe<FragmentSize> fragmentSize;
818 };
819 return new FullScreenColorInstance(context, iterationParams, expectedColors);
820 }
821
822 // ViewportIndex builtin case.
823 class ViewportIndexCase : public MeshShaderBuiltinCase
824 {
825 public:
ViewportIndexCase(tcu::TestContext & testCtx,const std::string & name,bool shareVertices)826 ViewportIndexCase(tcu::TestContext &testCtx, const std::string &name, bool shareVertices)
827 : MeshShaderBuiltinCase(testCtx, name, false /*taskNeeded*/)
828 , m_shareVertices(shareVertices)
829 {
830 }
~ViewportIndexCase(void)831 virtual ~ViewportIndexCase(void)
832 {
833 }
834
835 void initPrograms(vk::SourceCollections &programCollection) const override;
836 void checkSupport(Context &context) const override;
837 TestInstance *createInstance(Context &context) const override;
838
839 static constexpr uint32_t kQuadrants = 4u;
840
841 protected:
842 const bool m_shareVertices;
843 };
844
initPrograms(vk::SourceCollections & programCollection) const845 void ViewportIndexCase::initPrograms(vk::SourceCollections &programCollection) const
846 {
847 const auto localSize = (m_shareVertices ? kQuadrants : 1u);
848 const auto numPrimitives = (m_shareVertices ? kQuadrants : 1u);
849 const auto viewportIndex = (m_shareVertices ? "gl_LocalInvocationIndex" : "gl_WorkGroupID.x");
850
851 // One viewport per local invocation or work group (sharing vertices or not, respectively).
852 {
853 std::ostringstream mesh;
854 mesh << "#version 460\n"
855 << "#extension GL_NV_mesh_shader : enable\n"
856 << "\n"
857 << "layout (local_size_x=" << localSize << ") in;\n"
858 << "layout (triangles) out;\n"
859 << "layout (max_vertices=3, max_primitives=" << numPrimitives << ") out;\n"
860 << "\n"
861 << "perprimitiveNV out gl_MeshPerPrimitiveNV {\n"
862 << " int gl_ViewportIndex;\n"
863 << "} gl_MeshPrimitivesNV[];\n"
864 << "\n"
865 << "void main ()\n"
866 << "{\n"
867 << " gl_PrimitiveCountNV = " << numPrimitives << ";\n"
868 << "\n"
869 << " if (gl_LocalInvocationIndex == 0u)\n"
870 << " {\n"
871 << " gl_MeshVerticesNV[0].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
872 << " gl_MeshVerticesNV[1].gl_Position = vec4(-1.0, 3.0, 0.0, 1.0);\n"
873 << " gl_MeshVerticesNV[2].gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
874 << " }\n"
875 << "\n"
876 << " const uint baseIndex = gl_LocalInvocationIndex * 3u;\n"
877 << " gl_PrimitiveIndicesNV[baseIndex + 0] = 0;\n"
878 << " gl_PrimitiveIndicesNV[baseIndex + 1] = 1;\n"
879 << " gl_PrimitiveIndicesNV[baseIndex + 2] = 2;\n"
880 << "\n"
881 << " gl_MeshPrimitivesNV[gl_LocalInvocationIndex].gl_ViewportIndex = int(" << viewportIndex << ");\n"
882 << "}\n";
883 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
884 }
885
886 // Fragment shader chooses one color per viewport.
887 {
888 std::ostringstream frag;
889 frag << "#version 460\n"
890 << "#extension GL_NV_mesh_shader : enable\n"
891 << "\n"
892 << "layout (location=0) out vec4 outColor;\n"
893 << "\n"
894 << "vec4 colors[" << kQuadrants << "] = vec4[](\n"
895 << " vec4(0.0, 0.0, 1.0, 1.0),\n"
896 << " vec4(1.0, 0.0, 1.0, 1.0),\n"
897 << " vec4(0.0, 1.0, 1.0, 1.0),\n"
898 << " vec4(1.0, 1.0, 0.0, 1.0)\n"
899 << ");\n"
900 << "\n"
901 << "void main ()\n"
902 << "{\n"
903 << " outColor = colors[gl_ViewportIndex];\n"
904 << "}\n";
905 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
906 }
907 }
908
checkSupport(Context & context) const909 void ViewportIndexCase::checkSupport(Context &context) const
910 {
911 MeshShaderBuiltinCase::checkSupport(context);
912 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
913
914 if (!context.contextSupports(vk::ApiVersion(0u, 1u, 2u, 0u)))
915 context.requireDeviceFunctionality("VK_EXT_shader_viewport_index_layer");
916 else
917 {
918 const auto &features = context.getDeviceVulkan12Features();
919 if (!features.shaderOutputViewportIndex)
920 TCU_THROW(NotSupportedError, "shaderOutputViewportIndex feature not supported");
921 }
922 }
923
createInstance(Context & context) const924 TestInstance *ViewportIndexCase::createInstance(Context &context) const
925 {
926 const auto extent = getDefaultExtent();
927
928 DE_ASSERT(extent.width > 0u && extent.width % 2u == 0u);
929 DE_ASSERT(extent.height > 0u && extent.height % 2u == 0u);
930
931 const auto halfWidth = static_cast<float>(extent.width) / 2.0f;
932 const auto halfHeight = static_cast<float>(extent.height) / 2.0f;
933
934 const auto topLeft = tcu::Vec4(0.0, 0.0, 1.0, 1.0);
935 const auto topRight = tcu::Vec4(1.0, 0.0, 1.0, 1.0);
936 const auto bottomLeft = tcu::Vec4(0.0, 1.0, 1.0, 1.0);
937 const auto bottomRight = tcu::Vec4(1.0, 1.0, 0.0, 1.0);
938
939 ViewportVec viewports;
940 viewports.reserve(kQuadrants);
941 viewports.emplace_back(makeViewport(0.0f, 0.0f, halfWidth, halfHeight, 0.0f, 1.0f));
942 viewports.emplace_back(makeViewport(halfWidth, 0.0f, halfWidth, halfHeight, 0.0f, 1.0f));
943 viewports.emplace_back(makeViewport(0.0f, halfHeight, halfWidth, halfHeight, 0.0f, 1.0f));
944 viewports.emplace_back(makeViewport(halfWidth, halfHeight, halfWidth, halfHeight, 0.0f, 1.0f));
945
946 const auto numWorkGroups = (m_shareVertices ? 1u : kQuadrants);
947 const IterationParams iterationParams = {
948 getDefaultExtent(), // VkExtent2D colorExtent;
949 1u, // uint32_t numLayers;
950 getDefaultDrawCommands(numWorkGroups), // DrawCommandVec drawArgs;
951 false, // bool indirect;
952 std::move(viewports), // ViewportVec viewports;
953 tcu::Nothing, // tcu::Maybe<FragmentSize> fragmentSize;
954 };
955 return new QuadrantsInstance(context, iterationParams, topLeft, topRight, bottomLeft, bottomRight);
956 }
957
958 // Position builtin case.
959 class PositionCase : public MeshShaderBuiltinCase
960 {
961 public:
PositionCase(tcu::TestContext & testCtx,const std::string & name)962 PositionCase(tcu::TestContext &testCtx, const std::string &name)
963 : MeshShaderBuiltinCase(testCtx, name, false /*taskNeeded*/)
964 {
965 }
~PositionCase(void)966 virtual ~PositionCase(void)
967 {
968 }
969
970 void initPrograms(vk::SourceCollections &programCollection) const override;
971 TestInstance *createInstance(Context &context) const override;
972 };
973
initPrograms(vk::SourceCollections & programCollection) const974 void PositionCase::initPrograms(vk::SourceCollections &programCollection) const
975 {
976 // Mesh shader: emit single triangle around the center of the top left pixel.
977 {
978 const auto extent = getDefaultExtent();
979 const auto fWidth = static_cast<float>(extent.width);
980 const auto fHeight = static_cast<float>(extent.height);
981
982 const auto pxWidth = 2.0f / fWidth;
983 const auto pxHeight = 2.0f / fHeight;
984
985 const auto halfXPix = pxWidth / 2.0f;
986 const auto halfYPix = pxHeight / 2.0f;
987
988 // Center of top left pixel.
989 const auto x = -1.0f + halfXPix;
990 const auto y = -1.0f + halfYPix;
991
992 std::ostringstream mesh;
993 mesh << "#version 460\n"
994 << "#extension GL_NV_mesh_shader : enable\n"
995 << "\n"
996 << "layout (local_size_x=1) in;\n"
997 << "layout (triangles) out;\n"
998 << "layout (max_vertices=3, max_primitives=1) out;\n"
999 << "\n"
1000 << "void main ()\n"
1001 << "{\n"
1002 << " gl_PrimitiveCountNV = 1u;\n"
1003 << "\n"
1004 << " gl_PrimitiveIndicesNV[0] = 0;\n"
1005 << " gl_PrimitiveIndicesNV[1] = 1;\n"
1006 << " gl_PrimitiveIndicesNV[2] = 2;\n"
1007 << "\n"
1008 << " gl_MeshVerticesNV[0].gl_Position = vec4(" << (x - halfXPix) << ", " << (y + halfYPix)
1009 << ", 0.0, 1.0);\n"
1010 << " gl_MeshVerticesNV[1].gl_Position = vec4(" << (x + halfXPix) << ", " << (y + halfYPix)
1011 << ", 0.0, 1.0);\n"
1012 << " gl_MeshVerticesNV[2].gl_Position = vec4(" << x << ", " << (y - halfYPix) << ", 0.0, 1.0);\n"
1013 << "}\n";
1014 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1015 }
1016
1017 // Basic fragment shader.
1018 {
1019 const auto frag = getBasicFragShader();
1020 programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
1021 }
1022 }
1023
createInstance(Context & context) const1024 TestInstance *PositionCase::createInstance(Context &context) const
1025 {
1026 const IterationParams iterationParams = {
1027 getDefaultExtent(), // VkExtent2D colorExtent;
1028 1u, // uint32_t numLayers;
1029 getDefaultDrawCommands(), // DrawCommandVec drawArgs;
1030 false, // bool indirect;
1031 {}, // ViewportVec viewports; // If empty, a single default viewport is used.
1032 tcu::Nothing, // tcu::Maybe<FragmentSize> fragmentSize;
1033 };
1034
1035 // Must match the shader.
1036 PixelMap pixelMap;
1037 pixelMap[tcu::IVec2(0, 0)] = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
1038
1039 const PixelVerifierParams verifierParams = {
1040 tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), // const tcu::Vec4 background;
1041 std::move(pixelMap), // const PixelMap pixelMap;
1042 };
1043 return new PixelsInstance(context, iterationParams, verifierParams);
1044 }
1045
1046 // PointSize builtin case.
1047 class PointSizeCase : public MeshShaderBuiltinCase
1048 {
1049 public:
PointSizeCase(tcu::TestContext & testCtx,const std::string & name)1050 PointSizeCase(tcu::TestContext &testCtx, const std::string &name)
1051 : MeshShaderBuiltinCase(testCtx, name, false /*taskNeeded*/)
1052 {
1053 }
~PointSizeCase(void)1054 virtual ~PointSizeCase(void)
1055 {
1056 }
1057
1058 void initPrograms(vk::SourceCollections &programCollection) const override;
1059 TestInstance *createInstance(Context &context) const override;
1060 void checkSupport(Context &context) const override;
1061
1062 static constexpr float kPointSize = 4.0f;
1063 };
1064
initPrograms(vk::SourceCollections & programCollection) const1065 void PointSizeCase::initPrograms(vk::SourceCollections &programCollection) const
1066 {
1067 // Mesh shader: large point covering the top left quadrant.
1068 {
1069 std::ostringstream mesh;
1070 mesh << "#version 460\n"
1071 << "#extension GL_NV_mesh_shader : enable\n"
1072 << "\n"
1073 << "layout (local_size_x=1) in;\n"
1074 << "layout (points) out;\n"
1075 << "layout (max_vertices=1, max_primitives=1) out;\n"
1076 << "\n"
1077 << "void main ()\n"
1078 << "{\n"
1079 << " gl_PrimitiveCountNV = 1u;\n"
1080 << " gl_PrimitiveIndicesNV[0] = 0;\n"
1081 << " gl_MeshVerticesNV[0].gl_Position = vec4(-0.5, -0.5, 0.0, 1.0);\n"
1082 << " gl_MeshVerticesNV[0].gl_PointSize = " << kPointSize << ";\n"
1083 << "}\n";
1084 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1085 }
1086
1087 // Basic fragment shader.
1088 {
1089 const auto frag = getBasicFragShader();
1090 programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
1091 }
1092 }
1093
createInstance(Context & context) const1094 TestInstance *PointSizeCase::createInstance(Context &context) const
1095 {
1096 const IterationParams iterationParams = {
1097 getDefaultExtent(), // VkExtent2D colorExtent;
1098 1u, // uint32_t numLayers;
1099 getDefaultDrawCommands(), // DrawCommandVec drawArgs;
1100 false, // bool indirect;
1101 {}, // ViewportVec viewports; // If empty, a single default viewport is used.
1102 tcu::Nothing, // tcu::Maybe<FragmentSize> fragmentSize;
1103 };
1104
1105 // Must match the shader.
1106 const tcu::Vec4 black(0.0f, 0.0f, 0.0f, 1.0f);
1107 const tcu::Vec4 blue(0.0f, 0.0f, 1.0f, 1.0f);
1108
1109 return new QuadrantsInstance(context, iterationParams, blue, black, black, black);
1110 }
1111
checkSupport(Context & context) const1112 void PointSizeCase::checkSupport(Context &context) const
1113 {
1114 MeshShaderBuiltinCase::checkSupport(context);
1115 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
1116
1117 const auto &properties = context.getDeviceProperties();
1118 if (kPointSize < properties.limits.pointSizeRange[0] || kPointSize > properties.limits.pointSizeRange[1])
1119 TCU_THROW(NotSupportedError, "Required point size outside point size range");
1120 }
1121
1122 // ClipDistance builtin case.
1123 class ClipDistanceCase : public MeshShaderBuiltinCase
1124 {
1125 public:
ClipDistanceCase(tcu::TestContext & testCtx,const std::string & name)1126 ClipDistanceCase(tcu::TestContext &testCtx, const std::string &name)
1127 : MeshShaderBuiltinCase(testCtx, name, false /*taskNeeded*/)
1128 {
1129 }
~ClipDistanceCase(void)1130 virtual ~ClipDistanceCase(void)
1131 {
1132 }
1133
1134 void initPrograms(vk::SourceCollections &programCollection) const override;
1135 TestInstance *createInstance(Context &context) const override;
1136 void checkSupport(Context &context) const override;
1137 };
1138
initPrograms(vk::SourceCollections & programCollection) const1139 void ClipDistanceCase::initPrograms(vk::SourceCollections &programCollection) const
1140 {
1141 // Mesh shader: full-screen quad using different clip distances.
1142 {
1143 std::ostringstream mesh;
1144 mesh << "#version 460\n"
1145 << "#extension GL_NV_mesh_shader : enable\n"
1146 << "\n"
1147 << "layout (local_size_x=1) in;\n"
1148 << "layout (triangles) out;\n"
1149 << "layout (max_vertices=4, max_primitives=2) out;\n"
1150 << "\n"
1151 << "out gl_MeshPerVertexNV {\n"
1152 << " vec4 gl_Position;\n"
1153 << " float gl_ClipDistance[2];\n"
1154 << "} gl_MeshVerticesNV[];\n"
1155 << "\n"
1156 << "void main ()\n"
1157 << "{\n"
1158 << " gl_PrimitiveCountNV = 2u;\n"
1159 << "\n"
1160 << " gl_PrimitiveIndicesNV[0] = 0;\n"
1161 << " gl_PrimitiveIndicesNV[1] = 1;\n"
1162 << " gl_PrimitiveIndicesNV[2] = 2;\n"
1163 << " gl_PrimitiveIndicesNV[3] = 1;\n"
1164 << " gl_PrimitiveIndicesNV[4] = 3;\n"
1165 << " gl_PrimitiveIndicesNV[5] = 2;\n"
1166 << "\n"
1167 << " gl_MeshVerticesNV[0].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
1168 << " gl_MeshVerticesNV[1].gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
1169 << " gl_MeshVerticesNV[2].gl_Position = vec4( 1.0, -1.0, 0.0, 1.0);\n"
1170 << " gl_MeshVerticesNV[3].gl_Position = vec4( 1.0, 1.0, 0.0, 1.0);\n"
1171 << "\n"
1172 // The first clip plane keeps the left half of the frame buffer.
1173 << " gl_MeshVerticesNV[0].gl_ClipDistance[0] = 1.0;\n"
1174 << " gl_MeshVerticesNV[1].gl_ClipDistance[0] = 1.0;\n"
1175 << " gl_MeshVerticesNV[2].gl_ClipDistance[0] = -1.0;\n"
1176 << " gl_MeshVerticesNV[3].gl_ClipDistance[0] = -1.0;\n"
1177 << "\n"
1178 // The second clip plane keeps the top half of the frame buffer.
1179 << " gl_MeshVerticesNV[0].gl_ClipDistance[1] = 1.0;\n"
1180 << " gl_MeshVerticesNV[1].gl_ClipDistance[1] = -1.0;\n"
1181 << " gl_MeshVerticesNV[2].gl_ClipDistance[1] = 1.0;\n"
1182 << " gl_MeshVerticesNV[3].gl_ClipDistance[1] = -1.0;\n"
1183 << "}\n";
1184 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1185 }
1186
1187 // Fragment shader chooses a constant color.
1188 {
1189 std::ostringstream frag;
1190 frag << "#version 460\n"
1191 << "#extension GL_NV_mesh_shader : enable\n"
1192 << "\n"
1193 << "layout (location=0) out vec4 outColor;\n"
1194 << "\n"
1195 << "void main ()\n"
1196 << "{\n"
1197 // White color should not actually be used, as those fragments are supposed to be discarded.
1198 << " outColor = ((gl_ClipDistance[0] >= 0.0 && gl_ClipDistance[1] >= 0.0) ? vec4(0.0, 0.0, 1.0, 1.0) : "
1199 "vec4(1.0, 1.0, 1.0, 1.0));\n"
1200 << "}\n";
1201 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
1202 }
1203 }
1204
createInstance(Context & context) const1205 TestInstance *ClipDistanceCase::createInstance(Context &context) const
1206 {
1207 const IterationParams iterationParams = {
1208 getDefaultExtent(), // VkExtent2D colorExtent;
1209 1u, // uint32_t numLayers;
1210 getDefaultDrawCommands(), // DrawCommandVec drawArgs;
1211 false, // bool indirect;
1212 {}, // ViewportVec viewports; // If empty, a single default viewport is used.
1213 tcu::Nothing, // tcu::Maybe<FragmentSize> fragmentSize;
1214 };
1215
1216 // Must match the shader.
1217 const tcu::Vec4 black(0.0f, 0.0f, 0.0f, 1.0f);
1218 const tcu::Vec4 blue(0.0f, 0.0f, 1.0f, 1.0f);
1219
1220 return new QuadrantsInstance(context, iterationParams, blue, black, black, black);
1221 }
1222
checkSupport(Context & context) const1223 void ClipDistanceCase::checkSupport(Context &context) const
1224 {
1225 MeshShaderBuiltinCase::checkSupport(context);
1226 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_CLIP_DISTANCE);
1227 }
1228
1229 // CullDistance builtin case.
1230 class CullDistanceCase : public MeshShaderBuiltinCase
1231 {
1232 public:
CullDistanceCase(tcu::TestContext & testCtx,const std::string & name)1233 CullDistanceCase(tcu::TestContext &testCtx, const std::string &name)
1234 : MeshShaderBuiltinCase(testCtx, name, false /*taskNeeded*/)
1235 {
1236 }
~CullDistanceCase(void)1237 virtual ~CullDistanceCase(void)
1238 {
1239 }
1240
1241 void initPrograms(vk::SourceCollections &programCollection) const override;
1242 TestInstance *createInstance(Context &context) const override;
1243 void checkSupport(Context &context) const override;
1244 };
1245
initPrograms(vk::SourceCollections & programCollection) const1246 void CullDistanceCase::initPrograms(vk::SourceCollections &programCollection) const
1247 {
1248 // Mesh shader: two quads covering the whole screen, one on top of the other.
1249 // Use cull distances to discard the bottom quad.
1250 // Use cull distances to paint the top one in two colors: blue on the left, white on the right.
1251 {
1252 std::ostringstream mesh;
1253 mesh << "#version 460\n"
1254 << "#extension GL_NV_mesh_shader : enable\n"
1255 << "\n"
1256 << "layout (local_size_x=1) in;\n"
1257 << "layout (triangles) out;\n"
1258 << "layout (max_vertices=6, max_primitives=4) out;\n"
1259 << "\n"
1260 << "out gl_MeshPerVertexNV {\n"
1261 << " vec4 gl_Position;\n"
1262 << " float gl_CullDistance[2];\n"
1263 << "} gl_MeshVerticesNV[];\n"
1264 << "\n"
1265 << "void main ()\n"
1266 << "{\n"
1267 << " gl_PrimitiveCountNV = 4u;\n"
1268 << "\n"
1269 << " gl_PrimitiveIndicesNV[0] = 0;\n"
1270 << " gl_PrimitiveIndicesNV[1] = 1;\n"
1271 << " gl_PrimitiveIndicesNV[2] = 3;\n"
1272 << " gl_PrimitiveIndicesNV[3] = 1;\n"
1273 << " gl_PrimitiveIndicesNV[4] = 4;\n"
1274 << " gl_PrimitiveIndicesNV[5] = 3;\n"
1275 << " gl_PrimitiveIndicesNV[6] = 1;\n"
1276 << " gl_PrimitiveIndicesNV[7] = 2;\n"
1277 << " gl_PrimitiveIndicesNV[8] = 4;\n"
1278 << " gl_PrimitiveIndicesNV[9] = 2;\n"
1279 << " gl_PrimitiveIndicesNV[10] = 5;\n"
1280 << " gl_PrimitiveIndicesNV[11] = 4;\n"
1281 << "\n"
1282 << " gl_MeshVerticesNV[0].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
1283 << " gl_MeshVerticesNV[1].gl_Position = vec4(-1.0, 0.0, 0.0, 1.0);\n"
1284 << " gl_MeshVerticesNV[2].gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
1285 << " gl_MeshVerticesNV[3].gl_Position = vec4( 1.0, -1.0, 0.0, 1.0);\n"
1286 << " gl_MeshVerticesNV[4].gl_Position = vec4( 1.0, 0.0, 0.0, 1.0);\n"
1287 << " gl_MeshVerticesNV[5].gl_Position = vec4( 1.0, 1.0, 0.0, 1.0);\n"
1288 << "\n"
1289 // The first cull plane discards the bottom quad
1290 << " gl_MeshVerticesNV[0].gl_CullDistance[0] = 1.0;\n"
1291 << " gl_MeshVerticesNV[1].gl_CullDistance[0] = -1.0;\n"
1292 << " gl_MeshVerticesNV[2].gl_CullDistance[0] = -2.0;\n"
1293 << " gl_MeshVerticesNV[3].gl_CullDistance[0] = 1.0;\n"
1294 << " gl_MeshVerticesNV[4].gl_CullDistance[0] = -1.0;\n"
1295 << " gl_MeshVerticesNV[5].gl_CullDistance[0] = -2.0;\n"
1296 << "\n"
1297 // The second cull plane helps paint left and right different.
1298 << " gl_MeshVerticesNV[0].gl_CullDistance[1] = 1.0;\n"
1299 << " gl_MeshVerticesNV[1].gl_CullDistance[1] = 1.0;\n"
1300 << " gl_MeshVerticesNV[2].gl_CullDistance[1] = 1.0;\n"
1301 << " gl_MeshVerticesNV[3].gl_CullDistance[1] = -1.0;\n"
1302 << " gl_MeshVerticesNV[4].gl_CullDistance[1] = -1.0;\n"
1303 << " gl_MeshVerticesNV[5].gl_CullDistance[1] = -1.0;\n"
1304 << "}\n";
1305 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1306 }
1307
1308 // Fragment shader chooses color based on the second cull distance.
1309 {
1310 std::ostringstream frag;
1311 frag << "#version 460\n"
1312 << "#extension GL_NV_mesh_shader : enable\n"
1313 << "\n"
1314 << "layout (location=0) out vec4 outColor;\n"
1315 << "\n"
1316 << "void main ()\n"
1317 << "{\n"
1318 << " outColor = ((gl_CullDistance[1] >= 0.0) ? vec4(0.0, 0.0, 1.0, 1.0) : vec4(1.0, 1.0, 1.0, 1.0));\n"
1319 << "}\n";
1320 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
1321 }
1322 }
1323
createInstance(Context & context) const1324 TestInstance *CullDistanceCase::createInstance(Context &context) const
1325 {
1326 const IterationParams iterationParams = {
1327 getDefaultExtent(), // VkExtent2D colorExtent;
1328 1u, // uint32_t numLayers;
1329 getDefaultDrawCommands(), // DrawCommandVec drawArgs;
1330 false, // bool indirect;
1331 {}, // ViewportVec viewports; // If empty, a single default viewport is used.
1332 tcu::Nothing, // tcu::Maybe<FragmentSize> fragmentSize;
1333 };
1334
1335 // Must match the shader.
1336 const tcu::Vec4 black(0.0f, 0.0f, 0.0f, 1.0f);
1337 const tcu::Vec4 blue(0.0f, 0.0f, 1.0f, 1.0f);
1338 const tcu::Vec4 white(1.0f, 1.0f, 1.0f, 1.0f);
1339
1340 return new QuadrantsInstance(context, iterationParams, blue, white, black, black);
1341 }
1342
checkSupport(Context & context) const1343 void CullDistanceCase::checkSupport(Context &context) const
1344 {
1345 MeshShaderBuiltinCase::checkSupport(context);
1346 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_CULL_DISTANCE);
1347 }
1348
1349 // Generates statements to draw a triangle around the given pixel number, knowing the framebuffer width (len).
1350 // Supposes the height of the framebuffer is 1.
triangleForPixel(const std::string & pixel,const std::string & len,const std::string & baseIndex)1351 std::string triangleForPixel(const std::string &pixel, const std::string &len, const std::string &baseIndex)
1352 {
1353 std::ostringstream statements;
1354 statements << " const float imgWidth = float(" << len << ");\n"
1355 << " const float pixWidth = (2.0 / imgWidth);\n"
1356 << " const float halfPix = (pixWidth / 2.0);\n"
1357 << " const float xCenter = (((float(" << pixel << ") + 0.5) / imgWidth) * 2.0 - 1.0);\n"
1358 << " const float xLeft = (xCenter - halfPix);\n"
1359 << " const float xRight = (xCenter + halfPix);\n"
1360 << " const uvec3 indices = uvec3(" << baseIndex << " + 0, " << baseIndex << " + 1, " << baseIndex
1361 << " + 2);\n"
1362 << "\n"
1363 << " gl_PrimitiveIndicesNV[indices.x] = indices.x;\n"
1364 << " gl_PrimitiveIndicesNV[indices.y] = indices.y;\n"
1365 << " gl_PrimitiveIndicesNV[indices.z] = indices.z;\n"
1366 << "\n"
1367 << " gl_MeshVerticesNV[indices.x].gl_Position = vec4(xLeft, 0.5, 0.0, 1.0);\n"
1368 << " gl_MeshVerticesNV[indices.y].gl_Position = vec4(xRight, 0.5, 0.0, 1.0);\n"
1369 << " gl_MeshVerticesNV[indices.z].gl_Position = vec4(xCenter, -0.5, 0.0, 1.0);\n";
1370 return statements.str();
1371 }
1372
1373 // WorkGroupID builtin case.
1374 class WorkGroupIdCase : public MeshShaderBuiltinCase
1375 {
1376 public:
WorkGroupIdCase(tcu::TestContext & testCtx,const std::string & name,bool taskNeeded)1377 WorkGroupIdCase(tcu::TestContext &testCtx, const std::string &name, bool taskNeeded)
1378 : MeshShaderBuiltinCase(testCtx, name, taskNeeded)
1379 , m_extent(getLinearExtent())
1380 {
1381 }
~WorkGroupIdCase(void)1382 virtual ~WorkGroupIdCase(void)
1383 {
1384 }
1385
1386 void initPrograms(vk::SourceCollections &programCollection) const override;
1387 TestInstance *createInstance(Context &context) const override;
1388
1389 protected:
1390 const VkExtent2D m_extent;
1391 };
1392
initPrograms(vk::SourceCollections & programCollection) const1393 void WorkGroupIdCase::initPrograms(vk::SourceCollections &programCollection) const
1394 {
1395 const std::string taskDataDecl = "taskNV TaskData {\n"
1396 " uint id;\n"
1397 " uint size;\n"
1398 "} td;\n";
1399
1400 // Mesh shader: each work group fills one pixel.
1401 {
1402 const std::string pixel = (m_taskNeeded ? "td.id" : "gl_WorkGroupID.x");
1403 const std::string len = (m_taskNeeded ? "td.size" : de::toString(m_extent.width));
1404
1405 std::ostringstream mesh;
1406 mesh << "#version 460\n"
1407 << "#extension GL_NV_mesh_shader : enable\n"
1408 << "\n"
1409 << "layout (local_size_x=1) in;\n"
1410 << "layout (triangles) out;\n"
1411 << "layout (max_vertices=3, max_primitives=1) out;\n"
1412 << "\n"
1413 << (m_taskNeeded ? ("in " + taskDataDecl) : "") << "\n"
1414 << "void main ()\n"
1415 << "{\n"
1416 << " gl_PrimitiveCountNV = 1u;\n"
1417 << "\n"
1418 << triangleForPixel(pixel, len, "0") << "}\n";
1419 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1420 }
1421
1422 if (m_taskNeeded)
1423 {
1424 std::ostringstream task;
1425 task << "#version 460\n"
1426 << "#extension GL_NV_mesh_shader : enable\n"
1427 << "\n"
1428 << "layout (local_size_x=1) in;\n"
1429 << "\n"
1430 << "out " << taskDataDecl << "\n"
1431 << "void main ()\n"
1432 << "{\n"
1433 << " gl_TaskCountNV = 1u;\n"
1434 << " td.id = gl_WorkGroupID.x;\n"
1435 << " td.size = " << m_extent.width << ";\n"
1436 << "}\n";
1437 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
1438 }
1439
1440 // Basic fragment shader.
1441 {
1442 const auto frag = getBasicFragShader();
1443 programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
1444 }
1445 }
1446
createInstance(Context & context) const1447 TestInstance *WorkGroupIdCase::createInstance(Context &context) const
1448 {
1449 // Must match the shader.
1450 const ColorVec expectedColors(1u, tcu::Vec4(0.0, 0.0, 1.0, 1.0));
1451 const IterationParams iterationParams = {
1452 m_extent, // VkExtent2D colorExtent;
1453 1u, // uint32_t numLayers;
1454 getDefaultDrawCommands(m_extent.width), // DrawCommandVec drawArgs;
1455 false, // bool indirect;
1456 {}, // ViewportVec viewports; // If empty, a single default viewport is used.
1457 tcu::Nothing, // tcu::Maybe<FragmentSize> fragmentSize;
1458 };
1459 return new FullScreenColorInstance(context, iterationParams, expectedColors);
1460 }
1461
1462 // Variable to use.
1463 enum class LocalInvocation
1464 {
1465 ID = 0,
1466 INDEX
1467 };
1468
1469 // LocalInvocationId and LocalInvocationIndex builtin cases. These are also used to test WorkGroupSize.
1470 class LocalInvocationCase : public MeshShaderBuiltinCase
1471 {
1472 public:
LocalInvocationCase(tcu::TestContext & testCtx,const std::string & name,bool taskNeeded,LocalInvocation variable)1473 LocalInvocationCase(tcu::TestContext &testCtx, const std::string &name, bool taskNeeded, LocalInvocation variable)
1474 : MeshShaderBuiltinCase(testCtx, name, taskNeeded)
1475 , m_extent(getLinearExtent())
1476 , m_variable(variable)
1477 {
1478 }
~LocalInvocationCase(void)1479 virtual ~LocalInvocationCase(void)
1480 {
1481 }
1482
1483 void initPrograms(vk::SourceCollections &programCollection) const override;
1484 TestInstance *createInstance(Context &context) const override;
1485
1486 protected:
1487 const VkExtent2D m_extent;
1488 const LocalInvocation m_variable;
1489 };
1490
initPrograms(vk::SourceCollections & programCollection) const1491 void LocalInvocationCase::initPrograms(vk::SourceCollections &programCollection) const
1492 {
1493 // Invocation index to use.
1494 const std::string localIndex =
1495 ((m_variable == LocalInvocation::ID) ? "gl_LocalInvocationID.x" : "gl_LocalInvocationIndex");
1496
1497 // Task data.
1498 std::ostringstream taskDataDecl;
1499 taskDataDecl << "taskNV TaskData {\n"
1500 // indexNumber[x] == x
1501 << " uint indexNumber[" << m_extent.width << "];\n"
1502 << " uint size;\n"
1503 << "} td;\n";
1504 const auto taskDataDeclStr = taskDataDecl.str();
1505
1506 // Mesh shader: each work group fills one pixel.
1507 {
1508 const std::string pixel = (m_taskNeeded ? "td.indexNumber[gl_WorkGroupID.x]" : localIndex);
1509 const std::string len = (m_taskNeeded ? "td.size" : "gl_WorkGroupSize.x");
1510 const auto localSize = (m_taskNeeded ? 1u : m_extent.width);
1511 const auto maxVert = localSize * 3u;
1512 const std::string baseIndex = (m_taskNeeded ? "0" : "(" + localIndex + " * 3u)");
1513
1514 std::ostringstream mesh;
1515 mesh << "#version 460\n"
1516 << "#extension GL_NV_mesh_shader : enable\n"
1517 << "\n"
1518 << "layout (local_size_x=" << localSize << ") in;\n"
1519 << "layout (triangles) out;\n"
1520 << "layout (max_vertices=" << maxVert << ", max_primitives=" << localSize << ") out;\n"
1521 << "\n"
1522 << (m_taskNeeded ? ("in " + taskDataDeclStr) : "") << "\n"
1523 << "void main ()\n"
1524 << "{\n"
1525 << " gl_PrimitiveCountNV = " << localSize << ";\n"
1526 << "\n"
1527 << triangleForPixel(pixel, len, baseIndex) << "}\n";
1528 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1529 }
1530
1531 if (m_taskNeeded)
1532 {
1533 std::ostringstream task;
1534 task << "#version 460\n"
1535 << "#extension GL_NV_mesh_shader : enable\n"
1536 << "\n"
1537 << "layout (local_size_x=" << m_extent.width << ") in;\n"
1538 << "\n"
1539 << "out " << taskDataDeclStr << "\n"
1540 << "void main ()\n"
1541 << "{\n"
1542 << " gl_TaskCountNV = " << m_extent.width << ";\n"
1543 << " td.indexNumber[" << localIndex << "] = " << localIndex << ";\n"
1544 << " td.size = gl_WorkGroupSize.x;\n"
1545 << "}\n";
1546 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
1547 }
1548
1549 // Basic fragment shader.
1550 {
1551 const auto frag = getBasicFragShader();
1552 programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
1553 }
1554 }
1555
createInstance(Context & context) const1556 TestInstance *LocalInvocationCase::createInstance(Context &context) const
1557 {
1558 // Must match the shader.
1559 const ColorVec expectedColors(1u, tcu::Vec4(0.0, 0.0, 1.0, 1.0));
1560 const IterationParams iterationParams = {
1561 m_extent, // VkExtent2D colorExtent;
1562 1u, // uint32_t numLayers;
1563 getDefaultDrawCommands(), // DrawCommandVec drawArgs;
1564 false, // bool indirect;
1565 {}, // ViewportVec viewports; // If empty, a single default viewport is used.
1566 tcu::Nothing, // tcu::Maybe<FragmentSize> fragmentSize;
1567 };
1568 return new FullScreenColorInstance(context, iterationParams, expectedColors);
1569 }
1570
1571 // GlobalInvocationId builtin case.
1572 class GlobalInvocationIdCase : public MeshShaderBuiltinCase
1573 {
1574 public:
GlobalInvocationIdCase(tcu::TestContext & testCtx,const std::string & name,bool taskNeeded)1575 GlobalInvocationIdCase(tcu::TestContext &testCtx, const std::string &name, bool taskNeeded)
1576 : MeshShaderBuiltinCase(testCtx, name, taskNeeded)
1577 , m_jobSize(getLargeJobSize())
1578 , m_extent{m_jobSize.numTasks * m_jobSize.localSize, 1u}
1579 {
1580 }
~GlobalInvocationIdCase(void)1581 virtual ~GlobalInvocationIdCase(void)
1582 {
1583 }
1584
1585 void initPrograms(vk::SourceCollections &programCollection) const override;
1586 TestInstance *createInstance(Context &context) const override;
1587
1588 protected:
1589 const JobSize m_jobSize;
1590 const VkExtent2D m_extent;
1591 };
1592
initPrograms(vk::SourceCollections & programCollection) const1593 void GlobalInvocationIdCase::initPrograms(vk::SourceCollections &programCollection) const
1594 {
1595 const auto &localSize = m_jobSize.localSize;
1596
1597 // Task data.
1598 std::ostringstream taskDataDecl;
1599 taskDataDecl << "taskNV TaskData {\n"
1600 << " uint pixelId[" << localSize << "];\n"
1601 << " uint size;\n"
1602 << "} td;\n";
1603 const auto taskDataDeclStr = taskDataDecl.str();
1604
1605 // Mesh shader: each work group fills one pixel.
1606 {
1607 const std::string pixel = (m_taskNeeded ? "td.pixelId[gl_LocalInvocationIndex]" : "gl_GlobalInvocationID.x");
1608 const std::string len = (m_taskNeeded ? "td.size" : de::toString(m_extent.width));
1609 const std::string baseIndex = "(gl_LocalInvocationIndex * 3u)";
1610 const auto maxVert = localSize * 3u;
1611
1612 std::ostringstream mesh;
1613 mesh << "#version 460\n"
1614 << "#extension GL_NV_mesh_shader : enable\n"
1615 << "\n"
1616 << "layout (local_size_x=" << localSize << ") in;\n"
1617 << "layout (triangles) out;\n"
1618 << "layout (max_vertices=" << maxVert << ", max_primitives=" << localSize << ") out;\n"
1619 << "\n"
1620 << (m_taskNeeded ? ("in " + taskDataDeclStr) : "") << "\n"
1621 << "void main ()\n"
1622 << "{\n"
1623 << " gl_PrimitiveCountNV = " << localSize << ";\n"
1624 << "\n"
1625 << triangleForPixel(pixel, len, baseIndex) << "}\n";
1626 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1627 }
1628
1629 if (m_taskNeeded)
1630 {
1631 std::ostringstream task;
1632 task << "#version 460\n"
1633 << "#extension GL_NV_mesh_shader : enable\n"
1634 << "\n"
1635 << "layout (local_size_x=" << localSize << ") in;\n"
1636 << "\n"
1637 << "out " << taskDataDeclStr << "\n"
1638 << "void main ()\n"
1639 << "{\n"
1640 << " gl_TaskCountNV = 1;\n"
1641 << " td.pixelId[gl_LocalInvocationIndex] = gl_GlobalInvocationID.x;\n"
1642 << " td.size = " << m_extent.width << ";\n"
1643 << "}\n";
1644 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
1645 }
1646
1647 // Basic fragment shader.
1648 {
1649 const auto frag = getBasicFragShader();
1650 programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
1651 }
1652 }
1653
createInstance(Context & context) const1654 TestInstance *GlobalInvocationIdCase::createInstance(Context &context) const
1655 {
1656 // Must match the shader.
1657 const ColorVec expectedColors(1u, tcu::Vec4(0.0, 0.0, 1.0, 1.0));
1658 const IterationParams iterationParams = {
1659 m_extent, // VkExtent2D colorExtent;
1660 1u, // uint32_t numLayers;
1661 getDefaultDrawCommands(m_jobSize.numTasks), // DrawCommandVec drawArgs;
1662 false, // bool indirect;
1663 {}, // ViewportVec viewports; // If empty, a single default viewport is used.
1664 tcu::Nothing, // tcu::Maybe<FragmentSize> fragmentSize;
1665 };
1666 return new FullScreenColorInstance(context, iterationParams, expectedColors);
1667 }
1668
1669 // DrawIndex builtin case.
1670 class DrawIndexCase : public MeshShaderBuiltinCase
1671 {
1672 public:
DrawIndexCase(tcu::TestContext & testCtx,const std::string & name,bool taskNeeded)1673 DrawIndexCase(tcu::TestContext &testCtx, const std::string &name, bool taskNeeded)
1674 : MeshShaderBuiltinCase(testCtx, name, taskNeeded)
1675 , m_extent(getLinearExtent())
1676 {
1677 }
~DrawIndexCase(void)1678 virtual ~DrawIndexCase(void)
1679 {
1680 }
1681
1682 void initPrograms(vk::SourceCollections &programCollection) const override;
1683 TestInstance *createInstance(Context &context) const override;
1684
1685 protected:
1686 const VkExtent2D m_extent;
1687 };
1688
initPrograms(vk::SourceCollections & programCollection) const1689 void DrawIndexCase::initPrograms(vk::SourceCollections &programCollection) const
1690 {
1691 const std::string taskDataDecl = "taskNV TaskData {\n"
1692 " uint id;\n"
1693 " uint size;\n"
1694 "} td;\n";
1695
1696 const auto drawIndex = "uint(gl_DrawID)";
1697
1698 // Mesh shader: each work group fills one pixel.
1699 {
1700 const std::string pixel = (m_taskNeeded ? "td.id" : drawIndex);
1701 const std::string len = (m_taskNeeded ? "td.size" : de::toString(m_extent.width));
1702
1703 std::ostringstream mesh;
1704 mesh << "#version 460\n"
1705 << "#extension GL_NV_mesh_shader : enable\n"
1706 << "\n"
1707 << "layout (local_size_x=1) in;\n"
1708 << "layout (triangles) out;\n"
1709 << "layout (max_vertices=3, max_primitives=1) out;\n"
1710 << "\n"
1711 << (m_taskNeeded ? ("in " + taskDataDecl) : "") << "\n"
1712 << "void main ()\n"
1713 << "{\n"
1714 << " gl_PrimitiveCountNV = 1u;\n"
1715 << "\n"
1716 << triangleForPixel(pixel, len, "0") << "}\n";
1717 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
1718 }
1719
1720 if (m_taskNeeded)
1721 {
1722 std::ostringstream task;
1723 task << "#version 460\n"
1724 << "#extension GL_NV_mesh_shader : enable\n"
1725 << "\n"
1726 << "layout (local_size_x=1) in;\n"
1727 << "\n"
1728 << "out " << taskDataDecl << "\n"
1729 << "void main ()\n"
1730 << "{\n"
1731 << " gl_TaskCountNV = 1u;\n"
1732 << " td.id = " << drawIndex << ";\n"
1733 << " td.size = " << m_extent.width << ";\n"
1734 << "}\n";
1735 programCollection.glslSources.add("task") << glu::TaskSource(task.str());
1736 }
1737
1738 // Basic fragment shader.
1739 {
1740 const auto frag = getBasicFragShader();
1741 programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
1742 }
1743 }
1744
createInstance(Context & context) const1745 TestInstance *DrawIndexCase::createInstance(Context &context) const
1746 {
1747 // Must match the shader.
1748 const ColorVec expectedColors(1u, tcu::Vec4(0.0, 0.0, 1.0, 1.0));
1749 const DrawCommandVec commands(m_extent.width, makeDrawMeshTasksIndirectCommandNV(1u, 0u));
1750 const IterationParams iterationParams = {
1751 m_extent, // VkExtent2D colorExtent;
1752 1u, // uint32_t numLayers;
1753 commands, // DrawCommandVec drawArgs;
1754 true, // bool indirect;
1755 {}, // ViewportVec viewports; // If empty, a single default viewport is used.
1756 tcu::Nothing, // tcu::Maybe<FragmentSize> fragmentSize;
1757 };
1758 return new FullScreenColorInstance(context, iterationParams, expectedColors);
1759 }
1760
1761 // Primitive Shading Rate case.
1762 class PrimitiveShadingRateCase : public MeshShaderBuiltinCase
1763 {
1764 public:
PrimitiveShadingRateCase(tcu::TestContext & testCtx,const std::string & name,FragmentSize topSize,FragmentSize bottomSize)1765 PrimitiveShadingRateCase(tcu::TestContext &testCtx, const std::string &name, FragmentSize topSize,
1766 FragmentSize bottomSize)
1767 : MeshShaderBuiltinCase(testCtx, name, false /*taskNeeded*/)
1768 , m_topSize(topSize)
1769 , m_bottomSize(bottomSize)
1770 {
1771 }
~PrimitiveShadingRateCase(void)1772 virtual ~PrimitiveShadingRateCase(void)
1773 {
1774 }
1775
1776 void initPrograms(vk::SourceCollections &programCollection) const override;
1777 void checkSupport(Context &context) const override;
1778 TestInstance *createInstance(Context &context) const override;
1779
1780 protected:
1781 const FragmentSize m_topSize;
1782 const FragmentSize m_bottomSize;
1783 };
1784
initPrograms(vk::SourceCollections & programCollection) const1785 void PrimitiveShadingRateCase::initPrograms(vk::SourceCollections &programCollection) const
1786 {
1787 // Shading rate masks to use.
1788 const auto topMask = getGLSLShadingRateMask(m_topSize);
1789 const auto bottomMask = getGLSLShadingRateMask(m_bottomSize);
1790 const auto topMaskVal = getSPVShadingRateValue(m_topSize);
1791 const auto bottomMaskVal = getSPVShadingRateValue(m_bottomSize);
1792
1793 // Mesh shader.
1794 {
1795 // Similar to the GLSL code below if glslang accepted it.
1796 // Top quad with two triangles and bottom quad with two triangles.
1797 // One shading rate mask each.
1798 #if 0
1799 #version 460
1800 #extension GL_NV_mesh_shader : enable
1801 #extension GL_EXT_fragment_shading_rate : enable
1802
1803 layout (local_size_x=1) in;
1804 layout (triangles) out;
1805 layout (max_vertices=6, max_primitives=4) out;
1806
1807 perprimitiveNV out gl_MeshPerPrimitiveNV {
1808 int gl_PrimitiveShadingRateEXT;
1809 } gl_MeshPrimitivesNV[];
1810
1811 void main ()
1812 {
1813 gl_PrimitiveCountNV = 4u;
1814
1815 const vec4 topLeft = vec4(-1.0, -1.0, 0.0, 1.0);
1816 const vec4 midLeft = vec4(-1.0, 0.0, 0.0, 1.0);
1817 const vec4 botLeft = vec4(-1.0, 1.0, 0.0, 1.0);
1818
1819 const vec4 topRight = vec4( 1.0, -1.0, 0.0, 1.0);
1820 const vec4 midRight = vec4( 1.0, 0.0, 0.0, 1.0);
1821 const vec4 botRight = vec4( 1.0, 1.0, 0.0, 1.0);
1822
1823 gl_MeshVerticesNV[0].gl_Position = topLeft;
1824 gl_MeshVerticesNV[1].gl_Position = midLeft;
1825 gl_MeshVerticesNV[2].gl_Position = botLeft;
1826
1827 gl_MeshVerticesNV[3].gl_Position = topRight;
1828 gl_MeshVerticesNV[4].gl_Position = midRight;
1829 gl_MeshVerticesNV[5].gl_Position = botRight;
1830
1831 gl_PrimitiveIndicesNV[0] = 0u;
1832 gl_PrimitiveIndicesNV[1] = 1u;
1833 gl_PrimitiveIndicesNV[2] = 3u;
1834 gl_PrimitiveIndicesNV[3] = 1u;
1835 gl_PrimitiveIndicesNV[4] = 4u;
1836 gl_PrimitiveIndicesNV[5] = 3u;
1837 gl_PrimitiveIndicesNV[6] = 1u;
1838 gl_PrimitiveIndicesNV[7] = 2u;
1839 gl_PrimitiveIndicesNV[8] = 4u;
1840 gl_PrimitiveIndicesNV[9] = 2u;
1841 gl_PrimitiveIndicesNV[10] = 5u;
1842 gl_PrimitiveIndicesNV[11] = 4u;
1843
1844 gl_MeshPrimitivesNV[0].gl_PrimitiveShadingRateEXT = TOP_MASK;
1845 gl_MeshPrimitivesNV[1].gl_PrimitiveShadingRateEXT = TOP_MASK;
1846 gl_MeshPrimitivesNV[2].gl_PrimitiveShadingRateEXT = BOTTOM_MASK;
1847 gl_MeshPrimitivesNV[3].gl_PrimitiveShadingRateEXT = BOTTOM_MASK;
1848 }
1849 #endif
1850 std::ostringstream meshSPV;
1851 meshSPV << "; SPIR-V\n"
1852 << "; Version: 1.0\n"
1853 << "; Generator: Khronos Glslang Reference Front End; 10\n"
1854 << "; Bound: 81\n"
1855 << "; Schema: 0\n"
1856 << " OpCapability MeshShadingNV\n"
1857 << " OpCapability FragmentShadingRateKHR\n" // Added manually.
1858 << " OpExtension \"SPV_NV_mesh_shader\"\n"
1859 << " OpExtension \"SPV_KHR_fragment_shading_rate\"\n" // Added manually.
1860 << " %1 = OpExtInstImport \"GLSL.std.450\"\n"
1861 << " OpMemoryModel Logical GLSL450\n"
1862 << " OpEntryPoint MeshNV %4 \"main\" %8 %20 %47 %73\n"
1863 << " OpExecutionMode %4 LocalSize 1 1 1\n"
1864 << " OpExecutionMode %4 OutputVertices 6\n"
1865 << " OpExecutionMode %4 OutputPrimitivesNV 4\n"
1866 << " OpExecutionMode %4 OutputTrianglesNV\n"
1867 << " OpDecorate %8 BuiltIn PrimitiveCountNV\n"
1868 << " OpMemberDecorate %16 0 BuiltIn Position\n"
1869 << " OpMemberDecorate %16 1 BuiltIn PointSize\n"
1870 << " OpMemberDecorate %16 2 BuiltIn ClipDistance\n"
1871 << " OpMemberDecorate %16 3 BuiltIn CullDistance\n"
1872 << " OpMemberDecorate %16 4 PerViewNV\n"
1873 << " OpMemberDecorate %16 4 BuiltIn PositionPerViewNV\n"
1874 << " OpMemberDecorate %16 5 PerViewNV\n"
1875 << " OpMemberDecorate %16 5 BuiltIn ClipDistancePerViewNV\n"
1876 << " OpMemberDecorate %16 6 PerViewNV\n"
1877 << " OpMemberDecorate %16 6 BuiltIn CullDistancePerViewNV\n"
1878 << " OpDecorate %16 Block\n"
1879 << " OpDecorate %47 BuiltIn PrimitiveIndicesNV\n"
1880 << " OpMemberDecorate %70 0 PerPrimitiveNV\n"
1881 << " OpMemberDecorate %70 0 BuiltIn PrimitiveShadingRateKHR\n" // Replaced PrimitiveID with this.
1882 << " OpDecorate %70 Block\n"
1883 << " OpDecorate %80 BuiltIn WorkgroupSize\n"
1884 << " %2 = OpTypeVoid\n"
1885 << " %3 = OpTypeFunction %2\n"
1886 << " %6 = OpTypeInt 32 0\n"
1887 << " %7 = OpTypePointer Output %6\n"
1888 << " %8 = OpVariable %7 Output\n"
1889 << " %9 = OpConstant %6 4\n"
1890 << "%10 = OpTypeFloat 32\n"
1891 << "%11 = OpTypeVector %10 4\n"
1892 << "%12 = OpConstant %6 1\n"
1893 << "%13 = OpTypeArray %10 %12\n"
1894 << "%14 = OpTypeArray %11 %9\n"
1895 << "%15 = OpTypeArray %13 %9\n"
1896 << "%16 = OpTypeStruct %11 %10 %13 %13 %14 %15 %15\n"
1897 << "%17 = OpConstant %6 6\n"
1898 << "%18 = OpTypeArray %16 %17\n"
1899 << "%19 = OpTypePointer Output %18\n"
1900 << "%20 = OpVariable %19 Output\n"
1901 << "%21 = OpTypeInt 32 1\n"
1902 << "%tm = OpConstant %21 " << topMaskVal << "\n" // Added mask value line.
1903 << "%bm = OpConstant %21 " << bottomMaskVal << "\n" // Ditto.
1904 << "%22 = OpConstant %21 0\n"
1905 << "%23 = OpConstant %10 -1\n"
1906 << "%24 = OpConstant %10 0\n"
1907 << "%25 = OpConstant %10 1\n"
1908 << "%26 = OpConstantComposite %11 %23 %23 %24 %25\n"
1909 << "%27 = OpTypePointer Output %11\n"
1910 << "%29 = OpConstant %21 1\n"
1911 << "%30 = OpConstantComposite %11 %23 %24 %24 %25\n"
1912 << "%32 = OpConstant %21 2\n"
1913 << "%33 = OpConstantComposite %11 %23 %25 %24 %25\n"
1914 << "%35 = OpConstant %21 3\n"
1915 << "%36 = OpConstantComposite %11 %25 %23 %24 %25\n"
1916 << "%38 = OpConstant %21 4\n"
1917 << "%39 = OpConstantComposite %11 %25 %24 %24 %25\n"
1918 << "%41 = OpConstant %21 5\n"
1919 << "%42 = OpConstantComposite %11 %25 %25 %24 %25\n"
1920 << "%44 = OpConstant %6 12\n"
1921 << "%45 = OpTypeArray %6 %44\n"
1922 << "%46 = OpTypePointer Output %45\n"
1923 << "%47 = OpVariable %46 Output\n"
1924 << "%48 = OpConstant %6 0\n"
1925 << "%51 = OpConstant %6 3\n"
1926 << "%56 = OpConstant %21 6\n"
1927 << "%58 = OpConstant %21 7\n"
1928 << "%59 = OpConstant %6 2\n"
1929 << "%61 = OpConstant %21 8\n"
1930 << "%63 = OpConstant %21 9\n"
1931 << "%65 = OpConstant %21 10\n"
1932 << "%66 = OpConstant %6 5\n"
1933 << "%68 = OpConstant %21 11\n"
1934 << "%70 = OpTypeStruct %21\n"
1935 << "%71 = OpTypeArray %70 %9\n"
1936 << "%72 = OpTypePointer Output %71\n"
1937 << "%73 = OpVariable %72 Output\n"
1938 << "%74 = OpTypePointer Output %21\n"
1939 << "%79 = OpTypeVector %6 3\n"
1940 << "%80 = OpConstantComposite %79 %12 %12 %12\n"
1941 << " %4 = OpFunction %2 None %3\n"
1942 << " %5 = OpLabel\n"
1943 << " OpStore %8 %9\n"
1944 << "%28 = OpAccessChain %27 %20 %22 %22\n"
1945 << " OpStore %28 %26\n"
1946 << "%31 = OpAccessChain %27 %20 %29 %22\n"
1947 << " OpStore %31 %30\n"
1948 << "%34 = OpAccessChain %27 %20 %32 %22\n"
1949 << " OpStore %34 %33\n"
1950 << "%37 = OpAccessChain %27 %20 %35 %22\n"
1951 << " OpStore %37 %36\n"
1952 << "%40 = OpAccessChain %27 %20 %38 %22\n"
1953 << " OpStore %40 %39\n"
1954 << "%43 = OpAccessChain %27 %20 %41 %22\n"
1955 << " OpStore %43 %42\n"
1956 << "%49 = OpAccessChain %7 %47 %22\n"
1957 << " OpStore %49 %48\n"
1958 << "%50 = OpAccessChain %7 %47 %29\n"
1959 << " OpStore %50 %12\n"
1960 << "%52 = OpAccessChain %7 %47 %32\n"
1961 << " OpStore %52 %51\n"
1962 << "%53 = OpAccessChain %7 %47 %35\n"
1963 << " OpStore %53 %12\n"
1964 << "%54 = OpAccessChain %7 %47 %38\n"
1965 << " OpStore %54 %9\n"
1966 << "%55 = OpAccessChain %7 %47 %41\n"
1967 << " OpStore %55 %51\n"
1968 << "%57 = OpAccessChain %7 %47 %56\n"
1969 << " OpStore %57 %12\n"
1970 << "%60 = OpAccessChain %7 %47 %58\n"
1971 << " OpStore %60 %59\n"
1972 << "%62 = OpAccessChain %7 %47 %61\n"
1973 << " OpStore %62 %9\n"
1974 << "%64 = OpAccessChain %7 %47 %63\n"
1975 << " OpStore %64 %59\n"
1976 << "%67 = OpAccessChain %7 %47 %65\n"
1977 << " OpStore %67 %66\n"
1978 << "%69 = OpAccessChain %7 %47 %68\n"
1979 << " OpStore %69 %9\n"
1980 << "%75 = OpAccessChain %74 %73 %22 %22\n"
1981 << " OpStore %75 %tm\n" // Store the proper mask here. First triangle, top primitive.
1982 << "%76 = OpAccessChain %74 %73 %29 %22\n"
1983 << " OpStore %76 %tm\n" // Second triangle, top primitive.
1984 << "%77 = OpAccessChain %74 %73 %32 %22\n"
1985 << " OpStore %77 %bm\n" // Third triangle, bottom primitive.
1986 << "%78 = OpAccessChain %74 %73 %35 %22\n"
1987 << " OpStore %78 %bm\n" // Fourth triangle, bottom primitive.
1988 << " OpReturn\n"
1989 << " OpFunctionEnd\n";
1990 programCollection.spirvAsmSources.add("mesh") << meshSPV.str();
1991 }
1992
1993 // Frag shader.
1994 {
1995 const auto extent = getDefaultExtent();
1996 const auto halfHeight = static_cast<float>(extent.height) / 2.0f;
1997
1998 std::ostringstream frag;
1999 frag << "#version 460\n"
2000 << "#extension GL_NV_mesh_shader : enable\n"
2001 << "#extension GL_EXT_fragment_shading_rate : enable\n"
2002 << "\n"
2003 << "layout (location=0) out vec4 outColor;\n"
2004 << "\n"
2005 << "void main ()\n"
2006 << "{\n"
2007 // Checks the shading rate matches.
2008 << " const int expectedRate = ((gl_FragCoord.y < " << halfHeight << ")? " << topMask << " : "
2009 << bottomMask << ");\n"
2010 << " outColor = ((gl_ShadingRateEXT == expectedRate) ? vec4(0.0, 0.0, 1.0, 1.0) : vec4(0.0, 0.0, 0.0, "
2011 "1.0));\n"
2012 << "}\n";
2013 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
2014 }
2015 }
2016
checkSupport(Context & context) const2017 void PrimitiveShadingRateCase::checkSupport(Context &context) const
2018 {
2019 MeshShaderBuiltinCase::checkSupport(context);
2020
2021 context.requireDeviceFunctionality("VK_KHR_fragment_shading_rate");
2022 }
2023
createInstance(Context & context) const2024 TestInstance *PrimitiveShadingRateCase::createInstance(Context &context) const
2025 {
2026 const ColorVec expectedColors(1u, tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
2027 FragmentSizeVector fsInUse{m_topSize, m_bottomSize};
2028 const IterationParams iterationParams = {
2029 getDefaultExtent(), // VkExtent2D colorExtent;
2030 1u, // uint32_t numLayers;
2031 getDefaultDrawCommands(), // DrawCommandVec drawArgs;
2032 false, // bool indirect;
2033 {}, // ViewportVec viewports; // If empty, a single default viewport is used.
2034 tcu::just(getBadShadingRateSize(begin(fsInUse), end(fsInUse))), // tcu::Maybe<FragmentSize> fragmentSize;
2035 };
2036 return new FullScreenColorInstance(context, iterationParams, expectedColors);
2037 }
2038
2039 } // namespace
2040
createMeshShaderBuiltinTests(tcu::TestContext & testCtx)2041 tcu::TestCaseGroup *createMeshShaderBuiltinTests(tcu::TestContext &testCtx)
2042 {
2043 GroupPtr mainGroup(new tcu::TestCaseGroup(testCtx, "builtin"));
2044
2045 mainGroup->addChild(new PositionCase(testCtx, "position"));
2046 mainGroup->addChild(new PointSizeCase(testCtx, "point_size"));
2047 mainGroup->addChild(new ClipDistanceCase(testCtx, "clip_distance"));
2048 mainGroup->addChild(new CullDistanceCase(testCtx, "cull_distance"));
2049 mainGroup->addChild(new PrimitiveIdCase(testCtx, "primitive_id_glsl", true /*glslFrag*/));
2050 mainGroup->addChild(new PrimitiveIdCase(testCtx, "primitive_id_spirv", false /*glslFrag*/));
2051 mainGroup->addChild(new LayerCase(testCtx, "layer", false /*shareVertices*/));
2052 mainGroup->addChild(new LayerCase(testCtx, "layer_shared", true /*shareVertices*/));
2053 mainGroup->addChild(new ViewportIndexCase(testCtx, "viewport_index", false /*shareVertices*/));
2054 mainGroup->addChild(new ViewportIndexCase(testCtx, "viewport_index_shared", true /*shareVertices*/));
2055 mainGroup->addChild(new WorkGroupIdCase(testCtx, "work_group_id_in_mesh", false /*taskNeeded*/));
2056 mainGroup->addChild(new WorkGroupIdCase(testCtx, "work_group_id_in_task", true /*taskNeeded*/));
2057 mainGroup->addChild(
2058 new LocalInvocationCase(testCtx, "local_invocation_id_in_mesh", false /*taskNeeded*/, LocalInvocation::ID));
2059 mainGroup->addChild(
2060 new LocalInvocationCase(testCtx, "local_invocation_id_in_task", true /*taskNeeded*/, LocalInvocation::ID));
2061 mainGroup->addChild(new LocalInvocationCase(testCtx, "local_invocation_index_in_task", true /*taskNeeded*/,
2062 LocalInvocation::INDEX));
2063 mainGroup->addChild(new LocalInvocationCase(testCtx, "local_invocation_index_in_mesh", false /*taskNeeded*/,
2064 LocalInvocation::INDEX));
2065 mainGroup->addChild(new GlobalInvocationIdCase(testCtx, "global_invocation_id_in_mesh", false /*taskNeeded*/));
2066 mainGroup->addChild(new GlobalInvocationIdCase(testCtx, "global_invocation_id_in_task", true /*taskNeeded*/));
2067 mainGroup->addChild(new DrawIndexCase(testCtx, "draw_index_in_mesh", false /*taskNeeded*/));
2068 mainGroup->addChild(new DrawIndexCase(testCtx, "draw_index_in_task", true /*taskNeeded*/));
2069
2070 // Primitive shading rate tests.
2071 {
2072 const auto sizeCount = static_cast<int>(FragmentSize::SIZE_COUNT);
2073
2074 for (int i = 0; i < sizeCount; ++i)
2075 for (int j = 0; j < sizeCount; ++j)
2076 {
2077 const auto topSize = static_cast<FragmentSize>(i);
2078 const auto bottomSize = static_cast<FragmentSize>(j);
2079
2080 const auto topExtent = getShadingRateSize(topSize);
2081 const auto bottomExtent = getShadingRateSize(bottomSize);
2082
2083 const auto testName = "primitive_shading_rate_" + std::to_string(topExtent.width) + "x" +
2084 std::to_string(topExtent.height) + "_" + std::to_string(bottomExtent.width) +
2085 "x" + std::to_string(bottomExtent.height);
2086
2087 mainGroup->addChild(new PrimitiveShadingRateCase(testCtx, testName, topSize, bottomSize));
2088 }
2089 }
2090
2091 return mainGroup.release();
2092 }
2093
2094 } // namespace MeshShader
2095 } // namespace vkt
2096