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 Smoke Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktMeshShaderSmokeTests.hpp"
26 #include "vktMeshShaderUtil.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktTestCaseUtil.hpp"
29
30 #include "vkBuilderUtil.hpp"
31 #include "vkImageWithMemory.hpp"
32 #include "vkBufferWithMemory.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkCmdUtil.hpp"
36 #include "vkImageUtil.hpp"
37
38 #include "tcuImageCompare.hpp"
39 #include "tcuTestLog.hpp"
40 #include "tcuTextureUtil.hpp"
41
42 #include <utility>
43 #include <vector>
44 #include <string>
45 #include <sstream>
46
47 namespace vkt
48 {
49 namespace MeshShader
50 {
51
52 namespace
53 {
54
55 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
56
57 using namespace vk;
58
commonMeshFragShader()59 std::string commonMeshFragShader ()
60 {
61 std::string frag =
62 "#version 450\n"
63 "#extension GL_NV_mesh_shader : enable\n"
64 "\n"
65 "layout (location=0) in perprimitiveNV vec4 triangleColor;\n"
66 "layout (location=0) out vec4 outColor;\n"
67 "\n"
68 "void main ()\n"
69 "{\n"
70 " outColor = triangleColor;\n"
71 "}\n"
72 ;
73 return frag;
74 }
75
76 struct MeshTriangleRendererParams
77 {
78 std::vector<tcu::Vec4> vertexCoords;
79 std::vector<uint32_t> vertexIndices;
80 uint32_t taskCount;
81 tcu::Vec4 expectedColor;
82
MeshTriangleRendererParamsvkt::MeshShader::__anonc50b989a0111::MeshTriangleRendererParams83 MeshTriangleRendererParams (std::vector<tcu::Vec4> vertexCoords_, std::vector<uint32_t> vertexIndices_, uint32_t taskCount_, const tcu::Vec4& expectedColor_)
84 : vertexCoords (std::move(vertexCoords_))
85 , vertexIndices (std::move(vertexIndices_))
86 , taskCount (taskCount_)
87 , expectedColor (expectedColor_)
88 {}
89
MeshTriangleRendererParamsvkt::MeshShader::__anonc50b989a0111::MeshTriangleRendererParams90 MeshTriangleRendererParams (MeshTriangleRendererParams&& other)
91 : MeshTriangleRendererParams (std::move(other.vertexCoords), std::move(other.vertexIndices), other.taskCount, other.expectedColor)
92 {}
93 };
94
95 class MeshOnlyTriangleCase : public vkt::TestCase
96 {
97 public:
MeshOnlyTriangleCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)98 MeshOnlyTriangleCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description) : vkt::TestCase (testCtx, name, description) {}
~MeshOnlyTriangleCase(void)99 virtual ~MeshOnlyTriangleCase (void) {}
100
101 void initPrograms (vk::SourceCollections& programCollection) const override;
102 TestInstance* createInstance (Context& context) const override;
103 void checkSupport (Context& context) const override;
104 };
105
106 class MeshTaskTriangleCase : public vkt::TestCase
107 {
108 public:
MeshTaskTriangleCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)109 MeshTaskTriangleCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description) : vkt::TestCase (testCtx, name, description) {}
~MeshTaskTriangleCase(void)110 virtual ~MeshTaskTriangleCase (void) {}
111
112 void initPrograms (vk::SourceCollections& programCollection) const override;
113 TestInstance* createInstance (Context& context) const override;
114 void checkSupport (Context& context) const override;
115 };
116
117 // Note: not actually task-only. The task shader will not emit mesh shader work groups.
118 class TaskOnlyTriangleCase : public vkt::TestCase
119 {
120 public:
TaskOnlyTriangleCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)121 TaskOnlyTriangleCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description) : vkt::TestCase (testCtx, name, description) {}
~TaskOnlyTriangleCase(void)122 virtual ~TaskOnlyTriangleCase (void) {}
123
124 void initPrograms (vk::SourceCollections& programCollection) const override;
125 TestInstance* createInstance (Context& context) const override;
126 void checkSupport (Context& context) const override;
127 };
128
129 class MeshTriangleRenderer : public vkt::TestInstance
130 {
131 public:
MeshTriangleRenderer(Context & context,MeshTriangleRendererParams params)132 MeshTriangleRenderer (Context& context, MeshTriangleRendererParams params) : vkt::TestInstance(context), m_params(std::move(params)) {}
~MeshTriangleRenderer(void)133 virtual ~MeshTriangleRenderer (void) {}
134
135 tcu::TestStatus iterate (void) override;
136
137 protected:
138 MeshTriangleRendererParams m_params;
139 };
140
checkSupport(Context & context) const141 void MeshOnlyTriangleCase::checkSupport (Context& context) const
142 {
143 checkTaskMeshShaderSupportNV(context, false, true);
144 }
145
checkSupport(Context & context) const146 void MeshTaskTriangleCase::checkSupport (Context& context) const
147 {
148 checkTaskMeshShaderSupportNV(context, true, true);
149 }
150
checkSupport(Context & context) const151 void TaskOnlyTriangleCase::checkSupport (Context& context) const
152 {
153 checkTaskMeshShaderSupportNV(context, true, true);
154 }
155
initPrograms(SourceCollections & dst) const156 void MeshOnlyTriangleCase::initPrograms (SourceCollections& dst) const
157 {
158 std::ostringstream mesh;
159 mesh
160 << "#version 450\n"
161 << "#extension GL_NV_mesh_shader : enable\n"
162 << "\n"
163 // We will actually output a single triangle and most invocations will do no work.
164 << "layout(local_size_x=32) in;\n"
165 << "layout(triangles) out;\n"
166 << "layout(max_vertices=256, max_primitives=256) out;\n"
167 << "\n"
168 // Unique vertex coordinates.
169 << "layout (set=0, binding=0) uniform CoordsBuffer {\n"
170 << " vec4 coords[3];\n"
171 << "} cb;\n"
172 // Unique vertex indices.
173 << "layout (set=0, binding=1, std430) readonly buffer IndexBuffer {\n"
174 << " uint indices[3];\n"
175 << "} ib;\n"
176 << "\n"
177 // Triangle color.
178 << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
179 << "\n"
180 << "void main ()\n"
181 << "{\n"
182 << " gl_PrimitiveCountNV = 1u;\n"
183 << " triangleColor[0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
184 << "\n"
185 << " const uint vertex = gl_LocalInvocationIndex;\n"
186 << " if (vertex < 3u)\n"
187 << " {\n"
188 << " const uint vertexIndex = ib.indices[vertex];\n"
189 << " gl_PrimitiveIndicesNV[vertex] = vertexIndex;\n"
190 << " gl_MeshVerticesNV[vertexIndex].gl_Position = cb.coords[vertexIndex];\n"
191 << " }\n"
192 << "}\n"
193 ;
194 dst.glslSources.add("mesh") << glu::MeshSource(mesh.str());
195
196 dst.glslSources.add("frag") << glu::FragmentSource(commonMeshFragShader());
197 }
198
initPrograms(SourceCollections & dst) const199 void MeshTaskTriangleCase::initPrograms (SourceCollections& dst) const
200 {
201 std::string taskDataDecl =
202 "taskNV TaskData {\n"
203 " uint triangleIndex;\n"
204 "} td;\n"
205 ;
206
207 std::ostringstream task;
208 task
209 // Each work group spawns 1 task each (2 in total) and each task will draw 1 triangle.
210 << "#version 450\n"
211 << "#extension GL_NV_mesh_shader : enable\n"
212 << "\n"
213 << "layout(local_size_x=32) in;\n"
214 << "\n"
215 << "out " << taskDataDecl
216 << "\n"
217 << "void main ()\n"
218 << "{\n"
219 << " if (gl_LocalInvocationIndex == 0u)\n"
220 << " {\n"
221 << " gl_TaskCountNV = 1u;\n"
222 << " td.triangleIndex = gl_WorkGroupID.x;\n"
223 << " }\n"
224 << "}\n"
225 ;
226 dst.glslSources.add("task") << glu::TaskSource(task.str());
227
228 std::ostringstream mesh;
229 mesh
230 << "#version 450\n"
231 << "#extension GL_NV_mesh_shader : enable\n"
232 << "\n"
233 // We will actually output a single triangle and most invocations will do no work.
234 << "layout(local_size_x=32) in;\n"
235 << "layout(triangles) out;\n"
236 << "layout(max_vertices=256, max_primitives=256) out;\n"
237 << "\n"
238 // Unique vertex coordinates.
239 << "layout (set=0, binding=0) uniform CoordsBuffer {\n"
240 << " vec4 coords[4];\n"
241 << "} cb;\n"
242 // Unique vertex indices.
243 << "layout (set=0, binding=1, std430) readonly buffer IndexBuffer {\n"
244 << " uint indices[6];\n"
245 << "} ib;\n"
246 << "\n"
247 // Triangle color.
248 << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
249 << "\n"
250 << "in " << taskDataDecl
251 << "\n"
252 << "void main ()\n"
253 << "{\n"
254 << " if (gl_LocalInvocationIndex == 0u)\n"
255 << " {\n"
256 << " gl_PrimitiveCountNV = 1u;\n"
257 << " triangleColor[0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
258 << " }\n"
259 << "\n"
260 // Each "active" invocation will copy one vertex.
261 << " if (gl_LocalInvocationIndex < 3u)\n"
262 << " {\n"
263 << "\n"
264 << " const uint triangleVertex = gl_LocalInvocationIndex;\n"
265 << " const uint coordsIndex = ib.indices[td.triangleIndex * 3u + triangleVertex];\n"
266 << "\n"
267 // Copy vertex coordinates.
268 << " gl_MeshVerticesNV[triangleVertex].gl_Position = cb.coords[coordsIndex];\n"
269 // Index renumbering: final indices will always be 0, 1, 2.
270 << " gl_PrimitiveIndicesNV[triangleVertex] = triangleVertex;\n"
271 << " }\n"
272 << "}\n"
273 ;
274 dst.glslSources.add("mesh") << glu::MeshSource(mesh.str());
275
276 dst.glslSources.add("frag") << glu::FragmentSource(commonMeshFragShader());
277 }
278
initPrograms(SourceCollections & dst) const279 void TaskOnlyTriangleCase::initPrograms (SourceCollections& dst) const
280 {
281 // The task shader does not spawn any mesh shader invocations.
282 std::ostringstream task;
283 task
284 << "#version 450\n"
285 << "#extension GL_NV_mesh_shader : enable\n"
286 << "\n"
287 << "layout(local_size_x=1) in;\n"
288 << "\n"
289 << "void main ()\n"
290 << "{\n"
291 << " gl_TaskCountNV = 0u;\n"
292 << "}\n"
293 ;
294 dst.glslSources.add("task") << glu::TaskSource(task.str());
295
296 // Same shader as the mesh only case, but it should not be launched.
297 std::ostringstream mesh;
298 mesh
299 << "#version 450\n"
300 << "#extension GL_NV_mesh_shader : enable\n"
301 << "\n"
302 << "layout(local_size_x=32) in;\n"
303 << "layout(triangles) out;\n"
304 << "layout(max_vertices=256, max_primitives=256) out;\n"
305 << "\n"
306 << "layout (set=0, binding=0) uniform CoordsBuffer {\n"
307 << " vec4 coords[3];\n"
308 << "} cb;\n"
309 << "layout (set=0, binding=1, std430) readonly buffer IndexBuffer {\n"
310 << " uint indices[3];\n"
311 << "} ib;\n"
312 << "\n"
313 << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
314 << "\n"
315 << "void main ()\n"
316 << "{\n"
317 << " gl_PrimitiveCountNV = 1u;\n"
318 << " triangleColor[0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
319 << "\n"
320 << " const uint vertex = gl_LocalInvocationIndex;\n"
321 << " if (vertex < 3u)\n"
322 << " {\n"
323 << " const uint vertexIndex = ib.indices[vertex];\n"
324 << " gl_PrimitiveIndicesNV[vertex] = vertexIndex;\n"
325 << " gl_MeshVerticesNV[vertexIndex].gl_Position = cb.coords[vertexIndex];\n"
326 << " }\n"
327 << "}\n"
328 ;
329 dst.glslSources.add("mesh") << glu::MeshSource(mesh.str());
330
331 dst.glslSources.add("frag") << glu::FragmentSource(commonMeshFragShader());
332 }
333
createInstance(Context & context) const334 TestInstance* MeshOnlyTriangleCase::createInstance (Context& context) const
335 {
336 const std::vector<tcu::Vec4> vertexCoords =
337 {
338 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
339 tcu::Vec4(-1.0f, 3.0f, 0.0f, 1.0f),
340 tcu::Vec4( 3.0f, -1.0f, 0.0f, 1.0f),
341 };
342 const std::vector<uint32_t> vertexIndices = { 0u, 1u, 2u };
343 MeshTriangleRendererParams params (std::move(vertexCoords), std::move(vertexIndices), 1u, tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
344
345 return new MeshTriangleRenderer(context, std::move(params));
346 }
347
createInstance(Context & context) const348 TestInstance* MeshTaskTriangleCase::createInstance (Context& context) const
349 {
350 const std::vector<tcu::Vec4> vertexCoords =
351 {
352 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
353 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
354 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
355 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
356 };
357 const std::vector<uint32_t> vertexIndices = { 2u, 0u, 1u, 1u, 3u, 2u };
358 MeshTriangleRendererParams params (std::move(vertexCoords), std::move(vertexIndices), 2u, tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
359
360 return new MeshTriangleRenderer(context, std::move(params));
361 }
362
createInstance(Context & context) const363 TestInstance* TaskOnlyTriangleCase::createInstance (Context& context) const
364 {
365 const std::vector<tcu::Vec4> vertexCoords =
366 {
367 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
368 tcu::Vec4(-1.0f, 3.0f, 0.0f, 1.0f),
369 tcu::Vec4( 3.0f, -1.0f, 0.0f, 1.0f),
370 };
371 const std::vector<uint32_t> vertexIndices = { 0u, 1u, 2u };
372 // Note we expect the clear color.
373 MeshTriangleRendererParams params (std::move(vertexCoords), std::move(vertexIndices), 1u, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
374
375 return new MeshTriangleRenderer(context, std::move(params));
376 }
377
iterate()378 tcu::TestStatus MeshTriangleRenderer::iterate ()
379 {
380 const auto& vkd = m_context.getDeviceInterface();
381 const auto device = m_context.getDevice();
382 auto& alloc = m_context.getDefaultAllocator();
383 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
384 const auto queue = m_context.getUniversalQueue();
385
386 const auto vertexBufferStages = VK_SHADER_STAGE_MESH_BIT_NV;
387 const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(m_params.vertexCoords));
388 const auto vertexBufferUsage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
389 const auto vertexBufferLoc = DescriptorSetUpdateBuilder::Location::binding(0u);
390 const auto vertexBufferType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
391
392 const auto indexBufferStages = VK_SHADER_STAGE_MESH_BIT_NV;
393 const auto indexBufferSize = static_cast<VkDeviceSize>(de::dataSize(m_params.vertexIndices));
394 const auto indexBufferUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
395 const auto indexBufferLoc = DescriptorSetUpdateBuilder::Location::binding(1u);
396 const auto indexBufferType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
397
398 // Vertex buffer.
399 const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, vertexBufferUsage);
400 BufferWithMemory vertexBuffer (vkd, device, alloc, vertexBufferInfo, MemoryRequirement::HostVisible);
401 auto& vertexBufferAlloc = vertexBuffer.getAllocation();
402 void* vertexBufferDataPtr = vertexBufferAlloc.getHostPtr();
403
404 deMemcpy(vertexBufferDataPtr, m_params.vertexCoords.data(), static_cast<size_t>(vertexBufferSize));
405 flushAlloc(vkd, device, vertexBufferAlloc);
406
407 // Index buffer.
408 const auto indexBufferInfo = makeBufferCreateInfo(indexBufferSize, indexBufferUsage);
409 BufferWithMemory indexBuffer (vkd, device, alloc, indexBufferInfo, MemoryRequirement::HostVisible);
410 auto& indexBufferAlloc = indexBuffer.getAllocation();
411 void* indexBufferDataPtr = indexBufferAlloc.getHostPtr();
412
413 deMemcpy(indexBufferDataPtr, m_params.vertexIndices.data(), static_cast<size_t>(indexBufferSize));
414 flushAlloc(vkd, device, indexBufferAlloc);
415
416 // Color buffer.
417 const auto colorBufferFormat = VK_FORMAT_R8G8B8A8_UNORM;
418 const auto colorBufferExtent = makeExtent3D(8u, 8u, 1u);
419 const auto colorBufferUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
420
421 const VkImageCreateInfo colorBufferInfo =
422 {
423 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
424 nullptr, // const void* pNext;
425 0u, // VkImageCreateFlags flags;
426 VK_IMAGE_TYPE_2D, // VkImageType imageType;
427 colorBufferFormat, // VkFormat format;
428 colorBufferExtent, // VkExtent3D extent;
429 1u, // uint32_t mipLevels;
430 1u, // uint32_t arrayLayers;
431 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
432 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
433 colorBufferUsage, // VkImageUsageFlags usage;
434 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
435 0u, // uint32_t queueFamilyIndexCount;
436 nullptr, // const uint32_t* pQueueFamilyIndices;
437 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
438 };
439 ImageWithMemory colorBuffer(vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
440
441 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
442 const auto colorBufferView = makeImageView(vkd, device, colorBuffer.get(), VK_IMAGE_VIEW_TYPE_2D, colorBufferFormat, colorSRR);
443
444 // Render pass.
445 const auto renderPass = makeRenderPass(vkd, device, colorBufferFormat);
446
447 // Framebuffer.
448 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorBufferView.get(), colorBufferExtent.width, colorBufferExtent.height);
449
450 // Set layout.
451 DescriptorSetLayoutBuilder layoutBuilder;
452 layoutBuilder.addSingleBinding(vertexBufferType, vertexBufferStages);
453 layoutBuilder.addSingleBinding(indexBufferType, indexBufferStages);
454 const auto setLayout = layoutBuilder.build(vkd, device);
455
456 // Descriptor pool.
457 DescriptorPoolBuilder poolBuilder;
458 poolBuilder.addType(vertexBufferType);
459 poolBuilder.addType(indexBufferType);
460 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
461
462 // Descriptor set.
463 const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
464
465 // Update descriptor set.
466 DescriptorSetUpdateBuilder updateBuilder;
467 const auto vertexBufferDescInfo = makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertexBufferSize);
468 const auto indexBufferDescInfo = makeDescriptorBufferInfo(indexBuffer.get(), 0ull, indexBufferSize);
469 updateBuilder.writeSingle(descriptorSet.get(), vertexBufferLoc, vertexBufferType, &vertexBufferDescInfo);
470 updateBuilder.writeSingle(descriptorSet.get(), indexBufferLoc, indexBufferType, &indexBufferDescInfo);
471 updateBuilder.update(vkd, device);
472
473 // Pipeline layout.
474 const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
475
476 // Shader modules.
477 Move<VkShaderModule> taskModule;
478 const auto& binaries = m_context.getBinaryCollection();
479
480 if (binaries.contains("task"))
481 taskModule = createShaderModule(vkd, device, binaries.get("task"), 0u);
482 const auto meshModule = createShaderModule(vkd, device, binaries.get("mesh"), 0u);
483 const auto fragModule = createShaderModule(vkd, device, binaries.get("frag"), 0u);
484
485 // Graphics pipeline.
486 std::vector<VkViewport> viewports (1u, makeViewport(colorBufferExtent));
487 std::vector<VkRect2D> scissors (1u, makeRect2D(colorBufferExtent));
488 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(), taskModule.get(), meshModule.get(), fragModule.get(), renderPass.get(), viewports, scissors);
489
490 // Command pool and buffer.
491 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
492 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
493 const auto cmdBuffer = cmdBufferPtr.get();
494
495 // Output buffer.
496 const auto tcuFormat = mapVkFormat(colorBufferFormat);
497 const auto outBufferSize = static_cast<VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) * colorBufferExtent.width * colorBufferExtent.height);
498 const auto outBufferUsage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
499 const auto outBufferInfo = makeBufferCreateInfo(outBufferSize, outBufferUsage);
500 BufferWithMemory outBuffer (vkd, device, alloc, outBufferInfo, MemoryRequirement::HostVisible);
501 auto& outBufferAlloc = outBuffer.getAllocation();
502 void* outBufferData = outBufferAlloc.getHostPtr();
503
504 // Draw triangle.
505 beginCommandBuffer(vkd, cmdBuffer);
506 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)/*clear color*/);
507 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
508 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
509 vkd.cmdDrawMeshTasksNV(cmdBuffer, m_params.taskCount, 0u);
510 endRenderPass(vkd, cmdBuffer);
511
512 // Copy color buffer to output buffer.
513 const tcu::IVec3 imageDim (static_cast<int>(colorBufferExtent.width), static_cast<int>(colorBufferExtent.height), static_cast<int>(colorBufferExtent.depth));
514 const tcu::IVec2 imageSize (imageDim.x(), imageDim.y());
515
516 copyImageToBuffer(vkd, cmdBuffer, colorBuffer.get(), outBuffer.get(), imageSize);
517 endCommandBuffer(vkd, cmdBuffer);
518 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
519
520 // Invalidate alloc.
521 invalidateAlloc(vkd, device, outBufferAlloc);
522 tcu::ConstPixelBufferAccess outPixels(tcuFormat, imageDim, outBufferData);
523
524 auto& log = m_context.getTestContext().getLog();
525 const tcu::Vec4 threshold (0.0f); // The color can be represented exactly.
526
527 if (!tcu::floatThresholdCompare(log, "Result", "", m_params.expectedColor, outPixels, threshold, tcu::COMPARE_LOG_ON_ERROR))
528 return tcu::TestStatus::fail("Failed; check log for details");
529
530 return tcu::TestStatus::pass("Pass");
531 }
532
gradientImageExtent()533 VkExtent3D gradientImageExtent ()
534 {
535 return makeExtent3D(256u, 256u, 1u);
536 }
537
checkMeshSupport(Context & context,tcu::Maybe<FragmentSize> fragmentSize)538 void checkMeshSupport (Context& context, tcu::Maybe<FragmentSize> fragmentSize)
539 {
540 DE_UNREF(fragmentSize);
541 checkTaskMeshShaderSupportNV(context, false, true);
542 }
543
initGradientPrograms(vk::SourceCollections & programCollection,tcu::Maybe<FragmentSize> fragmentSize)544 void initGradientPrograms (vk::SourceCollections& programCollection, tcu::Maybe<FragmentSize> fragmentSize)
545 {
546 const auto extent = gradientImageExtent();
547
548 std::ostringstream frag;
549 frag
550 << "#version 450\n"
551 << "\n"
552 << "layout (location=0) in vec4 inColor;\n"
553 << "layout (location=0) out vec4 outColor;\n"
554 << "\n"
555 << "void main ()\n"
556 << "{\n"
557 << " outColor = inColor;\n"
558 << "}\n"
559 ;
560 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
561
562 const auto useFragmentSize = static_cast<bool>(fragmentSize);
563
564 if (!useFragmentSize)
565 {
566 std::ostringstream mesh;
567 mesh
568 << "#version 450\n"
569 << "#extension GL_NV_mesh_shader : enable\n"
570 << "\n"
571 << "layout(local_size_x=4) in;\n"
572 << "layout(triangles) out;\n"
573 << "layout(max_vertices=256, max_primitives=256) out;\n"
574 << "\n"
575 << "layout (location=0) out vec4 outColor[];\n"
576 << "\n"
577 << "void main ()\n"
578 << "{\n"
579 << " gl_PrimitiveCountNV = 2u;\n"
580 << "\n"
581 << " const uint vertex = gl_LocalInvocationIndex;\n"
582 << " const uint primitive = gl_LocalInvocationIndex;\n"
583 << "\n"
584 << " const vec4 topLeft = vec4(-1.0, -1.0, 0.0, 1.0);\n"
585 << " const vec4 botLeft = vec4(-1.0, 1.0, 0.0, 1.0);\n"
586 << " const vec4 topRight = vec4( 1.0, -1.0, 0.0, 1.0);\n"
587 << " const vec4 botRight = vec4( 1.0, 1.0, 0.0, 1.0);\n"
588 << " const vec4 positions[4] = vec4[](topLeft, botLeft, topRight, botRight);\n"
589 << "\n"
590 // Green changes according to the width.
591 // Blue changes according to the height.
592 // Value 0 at the center of the first pixel and value 1 at the center of the last pixel.
593 << " const float width = " << extent.width << ";\n"
594 << " const float height = " << extent.height << ";\n"
595 << " const float halfWidth = (1.0 / (width - 1.0)) / 2.0;\n"
596 << " const float halfHeight = (1.0 / (height - 1.0)) / 2.0;\n"
597 << " const float minGreen = -halfWidth;\n"
598 << " const float maxGreen = 1.0+halfWidth;\n"
599 << " const float minBlue = -halfHeight;\n"
600 << " const float maxBlue = 1.0+halfHeight;\n"
601 << " const vec4 colors[4] = vec4[](\n"
602 << " vec4(0, minGreen, minBlue, 1.0),\n"
603 << " vec4(0, minGreen, maxBlue, 1.0),\n"
604 << " vec4(0, maxGreen, minBlue, 1.0),\n"
605 << " vec4(0, maxGreen, maxBlue, 1.0)\n"
606 << " );\n"
607 << "\n"
608 << " const uint indices[6] = uint[](0, 1, 2, 1, 3, 2);\n"
609 << "\n"
610 << " if (vertex < 4u)\n"
611 << " {\n"
612 << " gl_MeshVerticesNV[vertex].gl_Position = positions[vertex];\n"
613 << " outColor[vertex] = colors[vertex];\n"
614 << " }\n"
615 << " if (primitive < 2u)\n"
616 << " {\n"
617 << " for (uint i = 0; i < 3; ++i) {\n"
618 << " const uint arrayPos = 3u * primitive + i;\n"
619 << " gl_PrimitiveIndicesNV[arrayPos] = indices[arrayPos];\n"
620 << " }\n"
621 << " }\n"
622 << "}\n"
623 ;
624 ;
625 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
626 }
627 else
628 {
629 const int shadingRateVal = getSPVShadingRateValue(fragmentSize.get());
630 DE_ASSERT(shadingRateVal != 0);
631
632 // The following shader is largely equivalent to the GLSL below if it was accepted by glslang.
633 #if 0
634 #version 450
635 #extension GL_NV_mesh_shader : enable
636
637 layout(local_size_x=4) in;
638 layout(triangles) out;
639 layout(max_vertices=256, max_primitives=256) out;
640
641 layout (location=0) out vec4 outColor[];
642
643 perprimitiveNV out gl_MeshPerPrimitiveNV {
644 int gl_PrimitiveShadingRateEXT;
645 } gl_MeshPrimitivesNV[];
646
647 void main ()
648 {
649 gl_PrimitiveCountNV = 2u;
650
651 const uint vertex = gl_LocalInvocationIndex;
652 const uint primitive = gl_LocalInvocationIndex;
653
654 const vec4 topLeft = vec4(-1.0, -1.0, 0.0, 1.0);
655 const vec4 botLeft = vec4(-1.0, 1.0, 0.0, 1.0);
656 const vec4 topRight = vec4( 1.0, -1.0, 0.0, 1.0);
657 const vec4 botRight = vec4( 1.0, 1.0, 0.0, 1.0);
658 const vec4 positions[4] = vec4[](topLeft, botLeft, topRight, botRight);
659
660 const float width = IMAGE_WIDTH;
661 const float height = IMAGE_HEIGHT;
662 const float halfWidth = (1.0 / (width - 1.0)) / 2.0;
663 const float halfHeight = (1.0 / (height - 1.0)) / 2.0;
664 const float minGreen = -halfWidth;
665 const float maxGreen = 1.0+halfWidth;
666 const float minBlue = -halfHeight;
667 const float maxBlue = 1.0+halfHeight;
668 const vec4 colors[4] = vec4[](
669 vec4(0, minGreen, minBlue, 1.0),
670 vec4(0, minGreen, maxBlue, 1.0),
671 vec4(0, maxGreen, minBlue, 1.0),
672 vec4(0, maxGreen, maxBlue, 1.0)
673 );
674
675 const uint indices[6] = uint[](0, 1, 2, 1, 3, 2);
676
677 if (vertex < 4u)
678 {
679 gl_MeshVerticesNV[vertex].gl_Position = positions[vertex];
680 outColor[vertex] = colors[vertex];
681 }
682 if (primitive < 2u)
683 {
684 gl_MeshPrimitivesNV[primitive].gl_PrimitiveShadingRateEXT = SHADING_RATE;
685 for (uint i = 0; i < 3; ++i)
686 {
687 const uint arrayPos = 3u * primitive + i;
688 gl_PrimitiveIndicesNV[arrayPos] = indices[arrayPos];
689 }
690 }
691 }
692 #endif
693
694 #undef SPV_PRECOMPUTED_CONSTANTS
695 std::ostringstream meshSPV;
696 meshSPV
697
698 << "; SPIR-V\n"
699 << "; Version: 1.0\n"
700 << "; Generator: Khronos Glslang Reference Front End; 10\n"
701 << "; Bound: 145\n"
702 << "; Schema: 0\n"
703 << " OpCapability MeshShadingNV\n"
704 << " OpCapability FragmentShadingRateKHR\n" // Added.
705 << " OpExtension \"SPV_NV_mesh_shader\"\n"
706 << " OpExtension \"SPV_KHR_fragment_shading_rate\"\n" // Added.
707 << " %1 = OpExtInstImport \"GLSL.std.450\"\n"
708 << " OpMemoryModel Logical GLSL450\n"
709 << " OpEntryPoint MeshNV %4 \"main\" %8 %13 %74 %93 %106 %129\n"
710 << " OpExecutionMode %4 LocalSize 4 1 1\n"
711 << " OpExecutionMode %4 OutputVertices 256\n"
712 << " OpExecutionMode %4 OutputPrimitivesNV 256\n"
713 << " OpExecutionMode %4 OutputTrianglesNV\n"
714 << " OpDecorate %8 BuiltIn PrimitiveCountNV\n"
715 << " OpDecorate %13 BuiltIn LocalInvocationIndex\n"
716 // These will be actual constants.
717 //<< " OpDecorate %21 SpecId 0\n"
718 //<< " OpDecorate %27 SpecId 1\n"
719 << " OpMemberDecorate %70 0 BuiltIn Position\n"
720 << " OpMemberDecorate %70 1 BuiltIn PointSize\n"
721 << " OpMemberDecorate %70 2 BuiltIn ClipDistance\n"
722 << " OpMemberDecorate %70 3 BuiltIn CullDistance\n"
723 << " OpMemberDecorate %70 4 PerViewNV\n"
724 << " OpMemberDecorate %70 4 BuiltIn PositionPerViewNV\n"
725 << " OpMemberDecorate %70 5 PerViewNV\n"
726 << " OpMemberDecorate %70 5 BuiltIn ClipDistancePerViewNV\n"
727 << " OpMemberDecorate %70 6 PerViewNV\n"
728 << " OpMemberDecorate %70 6 BuiltIn CullDistancePerViewNV\n"
729 << " OpDecorate %70 Block\n"
730 << " OpDecorate %93 Location 0\n"
731 << " OpMemberDecorate %103 0 PerPrimitiveNV\n"
732 << " OpMemberDecorate %103 0 BuiltIn PrimitiveShadingRateKHR\n" // Replaced PrimitiveID.
733 << " OpDecorate %103 Block\n"
734 << " OpDecorate %129 BuiltIn PrimitiveIndicesNV\n"
735 << " OpDecorate %144 BuiltIn WorkgroupSize\n"
736 << " %2 = OpTypeVoid\n"
737 << " %3 = OpTypeFunction %2\n"
738 << " %6 = OpTypeInt 32 0\n"
739 << " %7 = OpTypePointer Output %6\n"
740 << " %8 = OpVariable %7 Output\n"
741 << " %9 = OpConstant %6 2\n"
742 << " %10 = OpTypePointer Function %6\n"
743 << " %12 = OpTypePointer Input %6\n"
744 << " %13 = OpVariable %12 Input\n"
745 << " %17 = OpTypeFloat 32\n"
746 << " %18 = OpTypePointer Function %17\n"
747 << " %20 = OpConstant %17 1\n"
748 << " %21 = OpConstant %17 " << extent.width << "\n" // Made constant instead of spec constant.
749 << " %24 = OpConstant %17 2\n"
750 << " %27 = OpConstant %17 " << extent.height << "\n" // Made constant instead of spec constant.
751 << " %43 = OpTypeVector %17 4\n"
752 << " %44 = OpConstant %6 4\n"
753 << " %45 = OpTypeArray %43 %44\n"
754 << " %46 = OpTypePointer Function %45\n"
755 << " %48 = OpConstant %17 0\n"
756 << " %63 = OpTypeBool\n"
757 << " %67 = OpConstant %6 1\n"
758 << " %68 = OpTypeArray %17 %67\n"
759 << " %69 = OpTypeArray %68 %44\n"
760 << " %70 = OpTypeStruct %43 %17 %68 %68 %45 %69 %69\n"
761 << " %71 = OpConstant %6 256\n"
762 << " %72 = OpTypeArray %70 %71\n"
763 << " %73 = OpTypePointer Output %72\n"
764 << " %74 = OpVariable %73 Output\n"
765 << " %76 = OpTypeInt 32 1\n"
766 << " %77 = OpConstant %76 0\n"
767 << " %78 = OpConstant %17 -1\n"
768 << " %79 = OpConstantComposite %43 %78 %78 %48 %20\n"
769 << " %80 = OpConstantComposite %43 %78 %20 %48 %20\n"
770 << " %81 = OpConstantComposite %43 %20 %78 %48 %20\n"
771 << " %82 = OpConstantComposite %43 %20 %20 %48 %20\n"
772 << " %83 = OpConstantComposite %45 %79 %80 %81 %82\n"
773 << " %86 = OpTypePointer Function %43\n"
774 << " %89 = OpTypePointer Output %43\n"
775 << " %91 = OpTypeArray %43 %71\n"
776 << " %92 = OpTypePointer Output %91\n"
777 << " %93 = OpVariable %92 Output\n"
778 << " %103 = OpTypeStruct %76\n"
779 << " %104 = OpTypeArray %103 %71\n"
780 << " %105 = OpTypePointer Output %104\n"
781 << " %106 = OpVariable %105 Output\n"
782 << " %108 = OpConstant %76 " << shadingRateVal << "\n" // Used mask value here.
783 << " %109 = OpTypePointer Output %76\n"
784 << " %112 = OpConstant %6 0\n"
785 << " %119 = OpConstant %6 3\n"
786 << " %126 = OpConstant %6 768\n"
787 << " %127 = OpTypeArray %6 %126\n"
788 << " %128 = OpTypePointer Output %127\n"
789 << " %129 = OpVariable %128 Output\n"
790 << " %131 = OpConstant %6 6\n"
791 << " %132 = OpTypeArray %6 %131\n"
792 << " %133 = OpConstantComposite %132 %112 %67 %9 %67 %119 %9\n"
793 << " %135 = OpTypePointer Function %132\n"
794 << " %141 = OpConstant %76 1\n"
795 << " %143 = OpTypeVector %6 3\n"
796 << " %144 = OpConstantComposite %143 %44 %67 %67\n"
797 << " %4 = OpFunction %2 None %3\n"
798 << " %5 = OpLabel\n"
799 << " %11 = OpVariable %10 Function\n"
800 << " %15 = OpVariable %10 Function\n"
801 << " %19 = OpVariable %18 Function\n"
802 << " %26 = OpVariable %18 Function\n"
803 << " %31 = OpVariable %18 Function\n"
804 << " %34 = OpVariable %18 Function\n"
805 << " %37 = OpVariable %18 Function\n"
806 << " %40 = OpVariable %18 Function\n"
807 << " %47 = OpVariable %46 Function\n"
808 << " %85 = OpVariable %46 Function\n"
809 << " %111 = OpVariable %10 Function\n"
810 << " %121 = OpVariable %10 Function\n"
811 << " %136 = OpVariable %135 Function\n"
812 << " OpStore %8 %9\n"
813 << " %14 = OpLoad %6 %13\n"
814 << " OpStore %11 %14\n"
815 << " %16 = OpLoad %6 %13\n"
816 << " OpStore %15 %16\n"
817 << " %22 = OpFSub %17 %21 %20\n"
818 << " %23 = OpFDiv %17 %20 %22\n"
819 << " %25 = OpFDiv %17 %23 %24\n"
820 << " OpStore %19 %25\n"
821 << " %28 = OpFSub %17 %27 %20\n"
822 << " %29 = OpFDiv %17 %20 %28\n"
823 << " %30 = OpFDiv %17 %29 %24\n"
824 << " OpStore %26 %30\n"
825 << " %32 = OpLoad %17 %19\n"
826 << " %33 = OpFNegate %17 %32\n"
827 << " OpStore %31 %33\n"
828 << " %35 = OpLoad %17 %26\n"
829 << " %36 = OpFNegate %17 %35\n"
830 << " OpStore %34 %36\n"
831 << " %38 = OpLoad %17 %19\n"
832 << " %39 = OpFAdd %17 %20 %38\n"
833 << " OpStore %37 %39\n"
834 << " %41 = OpLoad %17 %26\n"
835 << " %42 = OpFAdd %17 %20 %41\n"
836 << " OpStore %40 %42\n"
837 << " %49 = OpLoad %17 %31\n"
838 << " %50 = OpLoad %17 %34\n"
839 << " %51 = OpCompositeConstruct %43 %48 %49 %50 %20\n"
840 << " %52 = OpLoad %17 %31\n"
841 << " %53 = OpLoad %17 %40\n"
842 << " %54 = OpCompositeConstruct %43 %48 %52 %53 %20\n"
843 << " %55 = OpLoad %17 %37\n"
844 << " %56 = OpLoad %17 %34\n"
845 << " %57 = OpCompositeConstruct %43 %48 %55 %56 %20\n"
846 << " %58 = OpLoad %17 %37\n"
847 << " %59 = OpLoad %17 %40\n"
848 << " %60 = OpCompositeConstruct %43 %48 %58 %59 %20\n"
849 << " %61 = OpCompositeConstruct %45 %51 %54 %57 %60\n"
850 << " OpStore %47 %61\n"
851 << " %62 = OpLoad %6 %11\n"
852 << " %64 = OpULessThan %63 %62 %44\n"
853 << " OpSelectionMerge %66 None\n"
854 << " OpBranchConditional %64 %65 %66\n"
855 << " %65 = OpLabel\n"
856 << " %75 = OpLoad %6 %11\n"
857 << " %84 = OpLoad %6 %11\n"
858 << " OpStore %85 %83\n"
859 << " %87 = OpAccessChain %86 %85 %84\n"
860 << " %88 = OpLoad %43 %87\n"
861 << " %90 = OpAccessChain %89 %74 %75 %77\n"
862 << " OpStore %90 %88\n"
863 << " %94 = OpLoad %6 %11\n"
864 << " %95 = OpLoad %6 %11\n"
865 << " %96 = OpAccessChain %86 %47 %95\n"
866 << " %97 = OpLoad %43 %96\n"
867 << " %98 = OpAccessChain %89 %93 %94\n"
868 << " OpStore %98 %97\n"
869 << " OpBranch %66\n"
870 << " %66 = OpLabel\n"
871 << " %99 = OpLoad %6 %15\n"
872 << " %100 = OpULessThan %63 %99 %9\n"
873 << " OpSelectionMerge %102 None\n"
874 << " OpBranchConditional %100 %101 %102\n"
875 << " %101 = OpLabel\n"
876 << " %107 = OpLoad %6 %15\n"
877 << " %110 = OpAccessChain %109 %106 %107 %77\n"
878 << " OpStore %110 %108\n"
879 << " OpStore %111 %112\n"
880 << " OpBranch %113\n"
881 << " %113 = OpLabel\n"
882 << " OpLoopMerge %115 %116 None\n"
883 << " OpBranch %117\n"
884 << " %117 = OpLabel\n"
885 << " %118 = OpLoad %6 %111\n"
886 << " %120 = OpULessThan %63 %118 %119\n"
887 << " OpBranchConditional %120 %114 %115\n"
888 << " %114 = OpLabel\n"
889 << " %122 = OpLoad %6 %15\n"
890 << " %123 = OpIMul %6 %119 %122\n"
891 << " %124 = OpLoad %6 %111\n"
892 << " %125 = OpIAdd %6 %123 %124\n"
893 << " OpStore %121 %125\n"
894 << " %130 = OpLoad %6 %121\n"
895 << " %134 = OpLoad %6 %121\n"
896 << " OpStore %136 %133\n"
897 << " %137 = OpAccessChain %10 %136 %134\n"
898 << " %138 = OpLoad %6 %137\n"
899 << " %139 = OpAccessChain %7 %129 %130\n"
900 << " OpStore %139 %138\n"
901 << " OpBranch %116\n"
902 << " %116 = OpLabel\n"
903 << " %140 = OpLoad %6 %111\n"
904 << " %142 = OpIAdd %6 %140 %141\n"
905 << " OpStore %111 %142\n"
906 << " OpBranch %113\n"
907 << " %115 = OpLabel\n"
908 << " OpBranch %102\n"
909 << " %102 = OpLabel\n"
910 << " OpReturn\n"
911 << " OpFunctionEnd\n"
912 ;
913 programCollection.spirvAsmSources.add("mesh") << meshSPV.str();
914 }
915 }
916
coordColorFormat(int x,int y,const tcu::Vec4 & color)917 std::string coordColorFormat (int x, int y, const tcu::Vec4& color)
918 {
919 std::ostringstream msg;
920 msg << "[" << x << ", " << y << "]=(" << color.x() << ", " << color.y() << ", " << color.z() << ", " << color.w() << ")";
921 return msg.str();
922 }
923
testFullscreenGradient(Context & context,tcu::Maybe<FragmentSize> fragmentSize)924 tcu::TestStatus testFullscreenGradient (Context& context, tcu::Maybe<FragmentSize> fragmentSize)
925 {
926 const auto& vkd = context.getDeviceInterface();
927 const auto device = context.getDevice();
928 auto& alloc = context.getDefaultAllocator();
929 const auto qIndex = context.getUniversalQueueFamilyIndex();
930 const auto queue = context.getUniversalQueue();
931 const auto useFragmentSize = static_cast<bool>(fragmentSize);
932 const auto defaultFragmentSize = FragmentSize::SIZE_1X1;
933 const auto rateSize = getShadingRateSize(useFragmentSize ? fragmentSize.get() : defaultFragmentSize);
934
935 // Color buffer.
936 const auto colorBufferFormat = VK_FORMAT_R8G8B8A8_UNORM;
937 const auto colorBufferExtent = makeExtent3D(256u, 256u, 1u); // Big enough for a detailed gradient, small enough to get unique colors.
938 const auto colorBufferUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
939
940 const VkImageCreateInfo colorBufferInfo =
941 {
942 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
943 nullptr, // const void* pNext;
944 0u, // VkImageCreateFlags flags;
945 VK_IMAGE_TYPE_2D, // VkImageType imageType;
946 colorBufferFormat, // VkFormat format;
947 colorBufferExtent, // VkExtent3D extent;
948 1u, // uint32_t mipLevels;
949 1u, // uint32_t arrayLayers;
950 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
951 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
952 colorBufferUsage, // VkImageUsageFlags usage;
953 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
954 0u, // uint32_t queueFamilyIndexCount;
955 nullptr, // const uint32_t* pQueueFamilyIndices;
956 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
957 };
958 ImageWithMemory colorBuffer(vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
959
960 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
961 const auto colorBufferView = makeImageView(vkd, device, colorBuffer.get(), VK_IMAGE_VIEW_TYPE_2D, colorBufferFormat, colorSRR);
962
963 // Render pass.
964 const auto renderPass = makeRenderPass(vkd, device, colorBufferFormat);
965
966 // Framebuffer.
967 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorBufferView.get(), colorBufferExtent.width, colorBufferExtent.height);
968
969 // Set layout.
970 DescriptorSetLayoutBuilder layoutBuilder;
971 const auto setLayout = layoutBuilder.build(vkd, device);
972
973 // Pipeline layout.
974 const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
975
976 // Shader modules.
977 Move<VkShaderModule> taskModule;
978 const auto& binaries = context.getBinaryCollection();
979
980 const auto meshModule = createShaderModule(vkd, device, binaries.get("mesh"), 0u);
981 const auto fragModule = createShaderModule(vkd, device, binaries.get("frag"), 0u);
982
983 using ShadingRateInfoPtr = de::MovePtr<VkPipelineFragmentShadingRateStateCreateInfoKHR>;
984 ShadingRateInfoPtr pNext;
985 if (useFragmentSize)
986 {
987 pNext = ShadingRateInfoPtr(new VkPipelineFragmentShadingRateStateCreateInfoKHR);
988 *pNext = initVulkanStructure();
989
990 pNext->fragmentSize = getShadingRateSize(FragmentSize::SIZE_1X1); // 1x1 will not be used as the primitive rate in tests with fragment size.
991 pNext->combinerOps[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR;
992 pNext->combinerOps[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR;
993 }
994
995 // Graphics pipeline.
996 std::vector<VkViewport> viewports (1u, makeViewport(colorBufferExtent));
997 std::vector<VkRect2D> scissors (1u, makeRect2D(colorBufferExtent));
998 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
999 taskModule.get(), meshModule.get(), fragModule.get(),
1000 renderPass.get(), viewports, scissors, 0u, nullptr, nullptr, nullptr, nullptr, nullptr, 0u, pNext.get());
1001
1002 // Command pool and buffer.
1003 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
1004 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1005 const auto cmdBuffer = cmdBufferPtr.get();
1006
1007 // Output buffer.
1008 const auto tcuFormat = mapVkFormat(colorBufferFormat);
1009 const auto outBufferSize = static_cast<VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) * colorBufferExtent.width * colorBufferExtent.height);
1010 const auto outBufferUsage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
1011 const auto outBufferInfo = makeBufferCreateInfo(outBufferSize, outBufferUsage);
1012 BufferWithMemory outBuffer (vkd, device, alloc, outBufferInfo, MemoryRequirement::HostVisible);
1013 auto& outBufferAlloc = outBuffer.getAllocation();
1014 void* outBufferData = outBufferAlloc.getHostPtr();
1015
1016 // Draw triangles.
1017 beginCommandBuffer(vkd, cmdBuffer);
1018 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)/*clear color*/);
1019 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
1020 vkd.cmdDrawMeshTasksNV(cmdBuffer, 1u, 0u);
1021 endRenderPass(vkd, cmdBuffer);
1022
1023 // Copy color buffer to output buffer.
1024 const tcu::IVec3 imageDim (static_cast<int>(colorBufferExtent.width), static_cast<int>(colorBufferExtent.height), static_cast<int>(colorBufferExtent.depth));
1025 const tcu::IVec2 imageSize (imageDim.x(), imageDim.y());
1026
1027 copyImageToBuffer(vkd, cmdBuffer, colorBuffer.get(), outBuffer.get(), imageSize);
1028 endCommandBuffer(vkd, cmdBuffer);
1029 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1030
1031 // Invalidate alloc.
1032 invalidateAlloc(vkd, device, outBufferAlloc);
1033 tcu::ConstPixelBufferAccess outPixels(tcuFormat, imageDim, outBufferData);
1034
1035 // Create reference image.
1036 tcu::TextureLevel refLevel (tcuFormat, imageDim.x(), imageDim.y(), imageDim.z());
1037 tcu::PixelBufferAccess refAccess (refLevel);
1038 for (int y = 0; y < imageDim.y(); ++y)
1039 for (int x = 0; x < imageDim.x(); ++x)
1040 {
1041 const tcu::IVec4 color (0, x, y, 255);
1042 refAccess.setPixel(color, x, y);
1043 }
1044
1045 const tcu::TextureFormat maskFormat (tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
1046 tcu::TextureLevel errorMask (maskFormat, imageDim.x(), imageDim.y(), imageDim.z());
1047 tcu::PixelBufferAccess errorAccess (errorMask);
1048 const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f);
1049 const tcu::Vec4 red (1.0f, 0.0f, 0.0f, 1.0f);
1050 auto& log = context.getTestContext().getLog();
1051
1052 // Each block needs to have the same color and be equal to one of the pixel colors of that block in the reference image.
1053 const auto blockWidth = static_cast<int>(rateSize.width);
1054 const auto blockHeight = static_cast<int>(rateSize.height);
1055
1056 tcu::clear(errorAccess, green);
1057 bool globalFail = false;
1058
1059 for (int y = 0; y < imageDim.y() / blockHeight; ++y)
1060 for (int x = 0; x < imageDim.x() / blockWidth; ++x)
1061 {
1062 bool blockFail = false;
1063 std::vector<tcu::Vec4> candidates;
1064
1065 candidates.reserve(rateSize.width * rateSize.height);
1066
1067 const auto cornerY = y * blockHeight;
1068 const auto cornerX = x * blockWidth;
1069 const auto cornerColor = outPixels.getPixel(cornerX, cornerY);
1070
1071 for (int blockY = 0; blockY < blockHeight; ++blockY)
1072 for (int blockX = 0; blockX < blockWidth; ++blockX)
1073 {
1074 const auto absY = cornerY + blockY;
1075 const auto absX = cornerX + blockX;
1076 const auto resColor = outPixels.getPixel(absX, absY);
1077
1078 candidates.push_back(refAccess.getPixel(absX, absY));
1079
1080 if (cornerColor != resColor)
1081 {
1082 std::ostringstream msg;
1083 msg << "Block not uniform: "
1084 << coordColorFormat(cornerX, cornerY, cornerColor)
1085 << " vs "
1086 << coordColorFormat(absX, absY, resColor);
1087 log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
1088
1089 blockFail = true;
1090 }
1091 }
1092
1093 if (!de::contains(begin(candidates), end(candidates), cornerColor))
1094 {
1095 std::ostringstream msg;
1096 msg << "Block color does not match any reference color at [" << cornerX << ", " << cornerY << "]";
1097 log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
1098 blockFail = true;
1099 }
1100
1101 if (blockFail)
1102 {
1103 const auto blockAccess = tcu::getSubregion(errorAccess, cornerX, cornerY, blockWidth, blockHeight);
1104 tcu::clear(blockAccess, red);
1105 globalFail = true;
1106 }
1107 }
1108
1109 if (globalFail)
1110 {
1111 log << tcu::TestLog::Image("Result", "", outPixels);
1112 log << tcu::TestLog::Image("Reference", "", refAccess);
1113 log << tcu::TestLog::Image("ErrorMask", "", errorAccess);
1114
1115 TCU_FAIL("Color mismatch; check log for more details");
1116 }
1117
1118 return tcu::TestStatus::pass("Pass");
1119 }
1120
1121 }
1122
createMeshShaderSmokeTests(tcu::TestContext & testCtx)1123 tcu::TestCaseGroup* createMeshShaderSmokeTests (tcu::TestContext& testCtx)
1124 {
1125 GroupPtr smokeTests (new tcu::TestCaseGroup(testCtx, "smoke", "Mesh Shader Smoke Tests"));
1126
1127 smokeTests->addChild(new MeshOnlyTriangleCase(testCtx, "mesh_shader_triangle", ""));
1128 smokeTests->addChild(new MeshTaskTriangleCase(testCtx, "mesh_task_shader_triangle", ""));
1129 smokeTests->addChild(new TaskOnlyTriangleCase(testCtx, "task_only_shader_triangle", ""));
1130
1131 addFunctionCaseWithPrograms(smokeTests.get(), "fullscreen_gradient", "", checkMeshSupport, initGradientPrograms, testFullscreenGradient, tcu::nothing<FragmentSize>());
1132 addFunctionCaseWithPrograms(smokeTests.get(), "fullscreen_gradient_fs2x2", "", checkMeshSupport, initGradientPrograms, testFullscreenGradient, tcu::just(FragmentSize::SIZE_2X2));
1133 addFunctionCaseWithPrograms(smokeTests.get(), "fullscreen_gradient_fs2x1", "", checkMeshSupport, initGradientPrograms, testFullscreenGradient, tcu::just(FragmentSize::SIZE_2X1));
1134
1135 return smokeTests.release();
1136 }
1137
1138 } // MeshShader
1139 } // vkt
1140