• 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 "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