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 "vktTestCase.hpp"
27
28 #include "vkBuilderUtil.hpp"
29 #include "vkImageWithMemory.hpp"
30 #include "vkBufferWithMemory.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkImageUtil.hpp"
35
36 #include "tcuImageCompare.hpp"
37
38 #include <utility>
39 #include <vector>
40 #include <string>
41 #include <sstream>
42
43 namespace vkt
44 {
45 namespace MeshShader
46 {
47
48 namespace
49 {
50
51 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
52
53 using namespace vk;
54
checkTaskMeshShaderSupport(Context & context,bool requireTask,bool requireMesh)55 void checkTaskMeshShaderSupport (Context& context, bool requireTask, bool requireMesh)
56 {
57 context.requireDeviceFunctionality("VK_NV_mesh_shader");
58
59 DE_ASSERT(requireTask || requireMesh);
60
61 const auto& meshFeatures = context.getMeshShaderFeatures();
62
63 if (requireTask && !meshFeatures.taskShader)
64 TCU_THROW(NotSupportedError, "Task shader not supported");
65
66 if (requireMesh && !meshFeatures.meshShader)
67 TCU_THROW(NotSupportedError, "Mesh shader not supported");
68 }
69
commonMeshFragShader()70 std::string commonMeshFragShader ()
71 {
72 std::string frag =
73 "#version 450\n"
74 "#extension GL_NV_mesh_shader : enable\n"
75 "\n"
76 "layout (location=0) in perprimitiveNV vec4 triangleColor;\n"
77 "layout (location=0) out vec4 outColor;\n"
78 "\n"
79 "void main ()\n"
80 "{\n"
81 " outColor = triangleColor;\n"
82 "}\n"
83 ;
84 return frag;
85 }
86
87 struct MeshTriangleRendererParams
88 {
89 std::vector<tcu::Vec4> vertexCoords;
90 std::vector<uint32_t> vertexIndices;
91 uint32_t taskCount;
92 tcu::Vec4 expectedColor;
93
MeshTriangleRendererParamsvkt::MeshShader::__anonffc8bf9d0111::MeshTriangleRendererParams94 MeshTriangleRendererParams (std::vector<tcu::Vec4> vertexCoords_, std::vector<uint32_t> vertexIndices_, uint32_t taskCount_, const tcu::Vec4& expectedColor_)
95 : vertexCoords (std::move(vertexCoords_))
96 , vertexIndices (std::move(vertexIndices_))
97 , taskCount (taskCount_)
98 , expectedColor (expectedColor_)
99 {}
100
MeshTriangleRendererParamsvkt::MeshShader::__anonffc8bf9d0111::MeshTriangleRendererParams101 MeshTriangleRendererParams (MeshTriangleRendererParams&& other)
102 : MeshTriangleRendererParams (std::move(other.vertexCoords), std::move(other.vertexIndices), other.taskCount, other.expectedColor)
103 {}
104 };
105
106 class MeshOnlyTriangleCase : public vkt::TestCase
107 {
108 public:
MeshOnlyTriangleCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)109 MeshOnlyTriangleCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description) : vkt::TestCase (testCtx, name, description) {}
~MeshOnlyTriangleCase(void)110 virtual ~MeshOnlyTriangleCase (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 class MeshTaskTriangleCase : public vkt::TestCase
118 {
119 public:
MeshTaskTriangleCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)120 MeshTaskTriangleCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description) : vkt::TestCase (testCtx, name, description) {}
~MeshTaskTriangleCase(void)121 virtual ~MeshTaskTriangleCase (void) {}
122
123 void initPrograms (vk::SourceCollections& programCollection) const override;
124 TestInstance* createInstance (Context& context) const override;
125 void checkSupport (Context& context) const override;
126 };
127
128 // Note: not actually task-only. The task shader will not emit mesh shader work groups.
129 class TaskOnlyTriangleCase : public vkt::TestCase
130 {
131 public:
TaskOnlyTriangleCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)132 TaskOnlyTriangleCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description) : vkt::TestCase (testCtx, name, description) {}
~TaskOnlyTriangleCase(void)133 virtual ~TaskOnlyTriangleCase (void) {}
134
135 void initPrograms (vk::SourceCollections& programCollection) const override;
136 TestInstance* createInstance (Context& context) const override;
137 void checkSupport (Context& context) const override;
138 };
139
140 class MeshTriangleRenderer : public vkt::TestInstance
141 {
142 public:
MeshTriangleRenderer(Context & context,MeshTriangleRendererParams params)143 MeshTriangleRenderer (Context& context, MeshTriangleRendererParams params) : vkt::TestInstance(context), m_params(std::move(params)) {}
~MeshTriangleRenderer(void)144 virtual ~MeshTriangleRenderer (void) {}
145
146 tcu::TestStatus iterate (void) override;
147
148 protected:
149 MeshTriangleRendererParams m_params;
150 };
151
checkSupport(Context & context) const152 void MeshOnlyTriangleCase::checkSupport (Context& context) const
153 {
154 checkTaskMeshShaderSupport(context, false, true);
155 }
156
checkSupport(Context & context) const157 void MeshTaskTriangleCase::checkSupport (Context& context) const
158 {
159 checkTaskMeshShaderSupport(context, true, true);
160 }
161
checkSupport(Context & context) const162 void TaskOnlyTriangleCase::checkSupport (Context& context) const
163 {
164 checkTaskMeshShaderSupport(context, true, true);
165 }
166
initPrograms(SourceCollections & dst) const167 void MeshOnlyTriangleCase::initPrograms (SourceCollections& dst) const
168 {
169 std::ostringstream mesh;
170 mesh
171 << "#version 450\n"
172 << "#extension GL_NV_mesh_shader : enable\n"
173 << "\n"
174 // We will actually output a single triangle and most invocations will do no work.
175 << "layout(local_size_x=32) in;\n"
176 << "layout(triangles) out;\n"
177 << "layout(max_vertices=256, max_primitives=256) out;\n"
178 << "\n"
179 // Unique vertex coordinates.
180 << "layout (set=0, binding=0) uniform CoordsBuffer {\n"
181 << " vec4 coords[3];\n"
182 << "} cb;\n"
183 // Unique vertex indices.
184 << "layout (set=0, binding=1, std430) readonly buffer IndexBuffer {\n"
185 << " uint indices[3];\n"
186 << "} ib;\n"
187 << "\n"
188 // Triangle color.
189 << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
190 << "\n"
191 << "void main ()\n"
192 << "{\n"
193 << " gl_PrimitiveCountNV = 1u;\n"
194 << " triangleColor[0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
195 << "\n"
196 << " const uint vertex = gl_LocalInvocationIndex;\n"
197 << " if (vertex < 3u)\n"
198 << " {\n"
199 << " const uint vertexIndex = ib.indices[vertex];\n"
200 << " gl_PrimitiveIndicesNV[vertex] = vertexIndex;\n"
201 << " gl_MeshVerticesNV[vertexIndex].gl_Position = cb.coords[vertexIndex];\n"
202 << " }\n"
203 << "}\n"
204 ;
205 dst.glslSources.add("mesh") << glu::MeshSource(mesh.str());
206
207 dst.glslSources.add("frag") << glu::FragmentSource(commonMeshFragShader());
208 }
209
initPrograms(SourceCollections & dst) const210 void MeshTaskTriangleCase::initPrograms (SourceCollections& dst) const
211 {
212 std::string taskDataDecl =
213 "taskNV TaskData {\n"
214 " uint triangleIndex;\n"
215 "} td;\n"
216 ;
217
218 std::ostringstream task;
219 task
220 // Each work group spawns 1 task each (2 in total) and each task will draw 1 triangle.
221 << "#version 450\n"
222 << "#extension GL_NV_mesh_shader : enable\n"
223 << "\n"
224 << "layout(local_size_x=32) in;\n"
225 << "\n"
226 << "out " << taskDataDecl
227 << "\n"
228 << "void main ()\n"
229 << "{\n"
230 << " if (gl_LocalInvocationIndex == 0u)\n"
231 << " {\n"
232 << " gl_TaskCountNV = 1u;\n"
233 << " td.triangleIndex = gl_WorkGroupID.x;\n"
234 << " }\n"
235 << "}\n"
236 ;
237 dst.glslSources.add("task") << glu::TaskSource(task.str());
238
239 std::ostringstream mesh;
240 mesh
241 << "#version 450\n"
242 << "#extension GL_NV_mesh_shader : enable\n"
243 << "\n"
244 // We will actually output a single triangle and most invocations will do no work.
245 << "layout(local_size_x=32) in;\n"
246 << "layout(triangles) out;\n"
247 << "layout(max_vertices=256, max_primitives=256) out;\n"
248 << "\n"
249 // Unique vertex coordinates.
250 << "layout (set=0, binding=0) uniform CoordsBuffer {\n"
251 << " vec4 coords[4];\n"
252 << "} cb;\n"
253 // Unique vertex indices.
254 << "layout (set=0, binding=1, std430) readonly buffer IndexBuffer {\n"
255 << " uint indices[6];\n"
256 << "} ib;\n"
257 << "\n"
258 // Triangle color.
259 << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
260 << "\n"
261 << "in " << taskDataDecl
262 << "\n"
263 << "void main ()\n"
264 << "{\n"
265 << " if (gl_LocalInvocationIndex == 0u)\n"
266 << " {\n"
267 << " gl_PrimitiveCountNV = 1u;\n"
268 << " triangleColor[0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
269 << " }\n"
270 << "\n"
271 // Each "active" invocation will copy one vertex.
272 << " if (gl_LocalInvocationIndex < 3u)\n"
273 << " {\n"
274 << "\n"
275 << " const uint triangleVertex = gl_LocalInvocationIndex;\n"
276 << " const uint coordsIndex = ib.indices[td.triangleIndex * 3u + triangleVertex];\n"
277 << "\n"
278 // Copy vertex coordinates.
279 << " gl_MeshVerticesNV[triangleVertex].gl_Position = cb.coords[coordsIndex];\n"
280 // Index renumbering: final indices will always be 0, 1, 2.
281 << " gl_PrimitiveIndicesNV[triangleVertex] = triangleVertex;\n"
282 << " }\n"
283 << "}\n"
284 ;
285 dst.glslSources.add("mesh") << glu::MeshSource(mesh.str());
286
287 dst.glslSources.add("frag") << glu::FragmentSource(commonMeshFragShader());
288 }
289
initPrograms(SourceCollections & dst) const290 void TaskOnlyTriangleCase::initPrograms (SourceCollections& dst) const
291 {
292 // The task shader does not spawn any mesh shader invocations.
293 std::ostringstream task;
294 task
295 << "#version 450\n"
296 << "#extension GL_NV_mesh_shader : enable\n"
297 << "\n"
298 << "layout(local_size_x=1) in;\n"
299 << "\n"
300 << "void main ()\n"
301 << "{\n"
302 << " gl_TaskCountNV = 0u;\n"
303 << "}\n"
304 ;
305 dst.glslSources.add("task") << glu::TaskSource(task.str());
306
307 // Same shader as the mesh only case, but it should not be launched.
308 std::ostringstream mesh;
309 mesh
310 << "#version 450\n"
311 << "#extension GL_NV_mesh_shader : enable\n"
312 << "\n"
313 << "layout(local_size_x=32) in;\n"
314 << "layout(triangles) out;\n"
315 << "layout(max_vertices=256, max_primitives=256) out;\n"
316 << "\n"
317 << "layout (set=0, binding=0) uniform CoordsBuffer {\n"
318 << " vec4 coords[3];\n"
319 << "} cb;\n"
320 << "layout (set=0, binding=1, std430) readonly buffer IndexBuffer {\n"
321 << " uint indices[3];\n"
322 << "} ib;\n"
323 << "\n"
324 << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
325 << "\n"
326 << "void main ()\n"
327 << "{\n"
328 << " gl_PrimitiveCountNV = 1u;\n"
329 << " triangleColor[0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
330 << "\n"
331 << " const uint vertex = gl_LocalInvocationIndex;\n"
332 << " if (vertex < 3u)\n"
333 << " {\n"
334 << " const uint vertexIndex = ib.indices[vertex];\n"
335 << " gl_PrimitiveIndicesNV[vertex] = vertexIndex;\n"
336 << " gl_MeshVerticesNV[vertexIndex].gl_Position = cb.coords[vertexIndex];\n"
337 << " }\n"
338 << "}\n"
339 ;
340 dst.glslSources.add("mesh") << glu::MeshSource(mesh.str());
341
342 dst.glslSources.add("frag") << glu::FragmentSource(commonMeshFragShader());
343 }
344
createInstance(Context & context) const345 TestInstance* MeshOnlyTriangleCase::createInstance (Context& context) const
346 {
347 const std::vector<tcu::Vec4> vertexCoords =
348 {
349 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
350 tcu::Vec4(-1.0f, 3.0f, 0.0f, 1.0f),
351 tcu::Vec4( 3.0f, -1.0f, 0.0f, 1.0f),
352 };
353 const std::vector<uint32_t> vertexIndices = { 0u, 1u, 2u };
354 MeshTriangleRendererParams params (std::move(vertexCoords), std::move(vertexIndices), 1u, tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
355
356 return new MeshTriangleRenderer(context, std::move(params));
357 }
358
createInstance(Context & context) const359 TestInstance* MeshTaskTriangleCase::createInstance (Context& context) const
360 {
361 const std::vector<tcu::Vec4> vertexCoords =
362 {
363 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
364 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
365 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
366 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
367 };
368 const std::vector<uint32_t> vertexIndices = { 2u, 0u, 1u, 1u, 3u, 2u };
369 MeshTriangleRendererParams params (std::move(vertexCoords), std::move(vertexIndices), 2u, tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
370
371 return new MeshTriangleRenderer(context, std::move(params));
372 }
373
createInstance(Context & context) const374 TestInstance* TaskOnlyTriangleCase::createInstance (Context& context) const
375 {
376 const std::vector<tcu::Vec4> vertexCoords =
377 {
378 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
379 tcu::Vec4(-1.0f, 3.0f, 0.0f, 1.0f),
380 tcu::Vec4( 3.0f, -1.0f, 0.0f, 1.0f),
381 };
382 const std::vector<uint32_t> vertexIndices = { 0u, 1u, 2u };
383 // Note we expect the clear color.
384 MeshTriangleRendererParams params (std::move(vertexCoords), std::move(vertexIndices), 1u, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
385
386 return new MeshTriangleRenderer(context, std::move(params));
387 }
388
iterate()389 tcu::TestStatus MeshTriangleRenderer::iterate ()
390 {
391 const auto& vkd = m_context.getDeviceInterface();
392 const auto device = m_context.getDevice();
393 auto& alloc = m_context.getDefaultAllocator();
394 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
395 const auto queue = m_context.getUniversalQueue();
396
397 const auto vertexBufferStages = VK_SHADER_STAGE_MESH_BIT_NV;
398 const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(m_params.vertexCoords));
399 const auto vertexBufferUsage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
400 const auto vertexBufferLoc = DescriptorSetUpdateBuilder::Location::binding(0u);
401 const auto vertexBufferType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
402
403 const auto indexBufferStages = VK_SHADER_STAGE_MESH_BIT_NV;
404 const auto indexBufferSize = static_cast<VkDeviceSize>(de::dataSize(m_params.vertexIndices));
405 const auto indexBufferUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
406 const auto indexBufferLoc = DescriptorSetUpdateBuilder::Location::binding(1u);
407 const auto indexBufferType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
408
409 // Vertex buffer.
410 const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, vertexBufferUsage);
411 BufferWithMemory vertexBuffer (vkd, device, alloc, vertexBufferInfo, MemoryRequirement::HostVisible);
412 auto& vertexBufferAlloc = vertexBuffer.getAllocation();
413 void* vertexBufferDataPtr = vertexBufferAlloc.getHostPtr();
414
415 deMemcpy(vertexBufferDataPtr, m_params.vertexCoords.data(), static_cast<size_t>(vertexBufferSize));
416 flushAlloc(vkd, device, vertexBufferAlloc);
417
418 // Index buffer.
419 const auto indexBufferInfo = makeBufferCreateInfo(indexBufferSize, indexBufferUsage);
420 BufferWithMemory indexBuffer (vkd, device, alloc, indexBufferInfo, MemoryRequirement::HostVisible);
421 auto& indexBufferAlloc = indexBuffer.getAllocation();
422 void* indexBufferDataPtr = indexBufferAlloc.getHostPtr();
423
424 deMemcpy(indexBufferDataPtr, m_params.vertexIndices.data(), static_cast<size_t>(indexBufferSize));
425 flushAlloc(vkd, device, indexBufferAlloc);
426
427 // Color buffer.
428 const auto colorBufferFormat = VK_FORMAT_R8G8B8A8_UNORM;
429 const auto colorBufferExtent = makeExtent3D(8u, 8u, 1u);
430 const auto colorBufferUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
431
432 const VkImageCreateInfo colorBufferInfo =
433 {
434 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
435 nullptr, // const void* pNext;
436 0u, // VkImageCreateFlags flags;
437 VK_IMAGE_TYPE_2D, // VkImageType imageType;
438 colorBufferFormat, // VkFormat format;
439 colorBufferExtent, // VkExtent3D extent;
440 1u, // uint32_t mipLevels;
441 1u, // uint32_t arrayLayers;
442 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
443 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
444 colorBufferUsage, // VkImageUsageFlags usage;
445 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
446 0u, // uint32_t queueFamilyIndexCount;
447 nullptr, // const uint32_t* pQueueFamilyIndices;
448 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
449 };
450 ImageWithMemory colorBuffer(vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
451
452 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
453 const auto colorBufferView = makeImageView(vkd, device, colorBuffer.get(), VK_IMAGE_VIEW_TYPE_2D, colorBufferFormat, colorSRR);
454
455 // Render pass.
456 const auto renderPass = makeRenderPass(vkd, device, colorBufferFormat);
457
458 // Framebuffer.
459 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorBufferView.get(), colorBufferExtent.width, colorBufferExtent.height);
460
461 // Set layout.
462 DescriptorSetLayoutBuilder layoutBuilder;
463 layoutBuilder.addSingleBinding(vertexBufferType, vertexBufferStages);
464 layoutBuilder.addSingleBinding(indexBufferType, indexBufferStages);
465 const auto setLayout = layoutBuilder.build(vkd, device);
466
467 // Descriptor pool.
468 DescriptorPoolBuilder poolBuilder;
469 poolBuilder.addType(vertexBufferType);
470 poolBuilder.addType(indexBufferType);
471 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
472
473 // Descriptor set.
474 const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
475
476 // Update descriptor set.
477 DescriptorSetUpdateBuilder updateBuilder;
478 const auto vertexBufferDescInfo = makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertexBufferSize);
479 const auto indexBufferDescInfo = makeDescriptorBufferInfo(indexBuffer.get(), 0ull, indexBufferSize);
480 updateBuilder.writeSingle(descriptorSet.get(), vertexBufferLoc, vertexBufferType, &vertexBufferDescInfo);
481 updateBuilder.writeSingle(descriptorSet.get(), indexBufferLoc, indexBufferType, &indexBufferDescInfo);
482 updateBuilder.update(vkd, device);
483
484 // Pipeline layout.
485 const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
486
487 // Shader modules.
488 Move<VkShaderModule> taskModule;
489 const auto& binaries = m_context.getBinaryCollection();
490
491 if (binaries.contains("task"))
492 taskModule = createShaderModule(vkd, device, binaries.get("task"), 0u);
493 const auto meshModule = createShaderModule(vkd, device, binaries.get("mesh"), 0u);
494 const auto fragModule = createShaderModule(vkd, device, binaries.get("frag"), 0u);
495
496 // Graphics pipeline.
497 std::vector<VkViewport> viewports (1u, makeViewport(colorBufferExtent));
498 std::vector<VkRect2D> scissors (1u, makeRect2D(colorBufferExtent));
499 const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(), taskModule.get(), meshModule.get(), fragModule.get(), renderPass.get(), viewports, scissors);
500
501 // Command pool and buffer.
502 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
503 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
504 const auto cmdBuffer = cmdBufferPtr.get();
505
506 // Output buffer.
507 const auto tcuFormat = mapVkFormat(colorBufferFormat);
508 const auto outBufferSize = static_cast<VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) * colorBufferExtent.width * colorBufferExtent.height);
509 const auto outBufferUsage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
510 const auto outBufferInfo = makeBufferCreateInfo(outBufferSize, outBufferUsage);
511 BufferWithMemory outBuffer (vkd, device, alloc, outBufferInfo, MemoryRequirement::HostVisible);
512 auto& outBufferAlloc = outBuffer.getAllocation();
513 void* outBufferData = outBufferAlloc.getHostPtr();
514
515 // Draw triangle.
516 beginCommandBuffer(vkd, cmdBuffer);
517 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)/*clear color*/);
518 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
519 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
520 vkd.cmdDrawMeshTasksNV(cmdBuffer, m_params.taskCount, 0u);
521 endRenderPass(vkd, cmdBuffer);
522
523 // Copy color buffer to output buffer.
524 const tcu::IVec3 imageDim (static_cast<int>(colorBufferExtent.width), static_cast<int>(colorBufferExtent.height), static_cast<int>(colorBufferExtent.depth));
525 const tcu::IVec2 imageSize (imageDim.x(), imageDim.y());
526
527 copyImageToBuffer(vkd, cmdBuffer, colorBuffer.get(), outBuffer.get(), imageSize);
528 endCommandBuffer(vkd, cmdBuffer);
529 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
530
531 // Invalidate alloc.
532 invalidateAlloc(vkd, device, outBufferAlloc);
533 tcu::ConstPixelBufferAccess outPixels(tcuFormat, imageDim, outBufferData);
534
535 auto& log = m_context.getTestContext().getLog();
536 const tcu::Vec4 threshold (0.0f); // The color can be represented exactly.
537
538 if (!tcu::floatThresholdCompare(log, "Result", "", m_params.expectedColor, outPixels, threshold, tcu::COMPARE_LOG_EVERYTHING))
539 return tcu::TestStatus::fail("Failed; check log for details");
540
541 return tcu::TestStatus::pass("Pass");
542 }
543
544 }
545
createMeshShaderSmokeTests(tcu::TestContext & testCtx)546 tcu::TestCaseGroup* createMeshShaderSmokeTests (tcu::TestContext& testCtx)
547 {
548 GroupPtr smokeTests (new tcu::TestCaseGroup(testCtx, "smoke", "Mesh Shader Smoke Tests"));
549
550 smokeTests->addChild(new MeshOnlyTriangleCase(testCtx, "mesh_shader_triangle", ""));
551 smokeTests->addChild(new MeshTaskTriangleCase(testCtx, "mesh_task_shader_triangle", ""));
552 smokeTests->addChild(new TaskOnlyTriangleCase(testCtx, "task_only_shader_triangle", ""));
553
554 return smokeTests.release();
555 }
556
557 } // MeshShader
558 } // vkt
559