• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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