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