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