1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 Advanced Micro Devices, Inc.
6 * Copyright (c) 2017 The Khronos Group Inc.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 *      http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief Tests for VK_EXT_sample_locations
25 *//*--------------------------------------------------------------------*/
26
27#include "vktPipelineMultisampleSampleLocationsExtTests.hpp"
28#include "vktPipelineSampleLocationsUtil.hpp"
29#include "vktPipelineMakeUtil.hpp"
30#include "vktTestCase.hpp"
31#include "vktTestGroupUtil.hpp"
32#include "vktTestCaseUtil.hpp"
33
34#include "vkPlatform.hpp"
35#include "vkMemUtil.hpp"
36#include "vkQueryUtil.hpp"
37#include "vkTypeUtil.hpp"
38#include "vkRefUtil.hpp"
39#include "vkBuilderUtil.hpp"
40#include "vkPrograms.hpp"
41#include "vkImageUtil.hpp"
42#include "vkCmdUtil.hpp"
43#include "vkObjUtil.hpp"
44
45#include "deUniquePtr.hpp"
46#include "deRandom.hpp"
47#include "deMath.h"
48
49#include "tcuTestLog.hpp"
50#include "tcuImageCompare.hpp"
51#include "tcuTextureUtil.hpp"
52#include "tcuRGBA.hpp"
53#include "tcuVectorUtil.hpp"
54
55#include <string>
56#include <vector>
57#include <set>
58#include <algorithm>
59
60namespace vkt
61{
62namespace pipeline
63{
64namespace
65{
66using namespace vk;
67using de::UniquePtr;
68using de::MovePtr;
69using tcu::Vec4;
70using tcu::Vec2;
71using tcu::UVec2;
72using tcu::UVec4;
73using tcu::RGBA;
74
75static const deUint32		STENCIL_REFERENCE	= 1u;
76static const float			DEPTH_CLEAR			= 1.0f;
77static const float			DEPTH_REFERENCE     = 0.5f;
78static const Vec4			CLEAR_COLOR_0		= Vec4(0.0f, 0.0f,  0.0f,  1.0f);
79static const Vec4			CLEAR_COLOR_1		= Vec4(0.5f, 0.25f, 0.75f, 1.0f);
80static const VkDeviceSize	ZERO				= 0u;
81
82template<typename T>
83inline const T* dataOrNullPtr (const std::vector<T>& v)
84{
85	return (v.empty() ? DE_NULL : &v[0]);
86}
87
88template<typename T>
89inline T* dataOrNullPtr (std::vector<T>& v)
90{
91	return (v.empty() ? DE_NULL : &v[0]);
92}
93
94template<typename T>
95inline void append (std::vector<T>& first, const std::vector<T>& second)
96{
97	first.insert(first.end(), second.begin(), second.end());
98}
99
100//! Order a Vector by X, Y, Z, and W
101template<typename VectorT>
102struct LessThan
103{
104	bool operator()(const VectorT& v1, const VectorT& v2) const
105	{
106		for (int i = 0; i < VectorT::SIZE; ++i)
107		{
108			if (v1[i] == v2[i])
109				continue;
110			else
111				return v1[i] < v2[i];
112		}
113
114		return false;
115	}
116};
117
118//! Similar to the class in vktTestCaseUtil.hpp, but uses Arg0 directly rather than through a InstanceFunction1
119template<typename Arg0>
120class FunctionProgramsSimple1
121{
122public:
123	typedef void	(*Function)				(vk::SourceCollections& dst, Arg0 arg0);
124					FunctionProgramsSimple1	(Function func) : m_func(func)							{}
125	void			init					(vk::SourceCollections& dst, const Arg0& arg0) const	{ m_func(dst, arg0); }
126
127private:
128	const Function	m_func;
129};
130
131//! Convenience function to create a TestCase based on a freestanding initPrograms and a TestInstance implementation
132template<typename Instance, typename Arg0>
133void addInstanceTestCaseWithPrograms (tcu::TestCaseGroup*								group,
134									  const std::string&								name,
135									  typename FunctionSupport1<Arg0>::Function			checkSupport,
136									  typename FunctionProgramsSimple1<Arg0>::Function	initPrograms,
137									  Arg0												arg0)
138{
139	group->addChild(new InstanceFactory1WithSupport<Instance, Arg0, FunctionSupport1<Arg0>, FunctionProgramsSimple1<Arg0> >(
140		group->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, FunctionProgramsSimple1<Arg0>(initPrograms), arg0, typename FunctionSupport1<Arg0>::Args(checkSupport, arg0)));
141}
142
143void checkSupportSampleLocations (Context& context)
144{
145	context.requireDeviceFunctionality("VK_EXT_sample_locations");
146}
147
148std::string getString (const VkSampleCountFlagBits sampleCount)
149{
150	std::ostringstream str;
151	str << "samples_" << static_cast<deUint32>(sampleCount);
152	return str.str();
153}
154
155bool isSupportedDepthStencilFormat (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkFormat format)
156{
157	VkFormatProperties formatProps;
158	vki.getPhysicalDeviceFormatProperties(physDevice, format, &formatProps);
159	return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
160}
161
162VkFormat findSupportedDepthStencilFormat (Context& context, const bool useDepth, const bool useStencil)
163{
164	const InstanceInterface&	vki			= context.getInstanceInterface();
165	const VkPhysicalDevice		physDevice	= context.getPhysicalDevice();
166
167	if (useDepth && !useStencil)
168		return VK_FORMAT_D16_UNORM;		// must be supported
169
170	// One of these formats must be supported.
171
172	if (isSupportedDepthStencilFormat(vki, physDevice, VK_FORMAT_D24_UNORM_S8_UINT))
173		return VK_FORMAT_D24_UNORM_S8_UINT;
174
175	if (isSupportedDepthStencilFormat(vki, physDevice, VK_FORMAT_D32_SFLOAT_S8_UINT))
176		return VK_FORMAT_D32_SFLOAT_S8_UINT;
177
178	return VK_FORMAT_UNDEFINED;
179}
180
181void checkFragmentShadingRateRequirements(Context& context, deUint32 sampleCount)
182{
183	const auto&	vki = context.getInstanceInterface();
184	const auto	physicalDevice = context.getPhysicalDevice();
185
186	context.requireDeviceFunctionality("VK_KHR_fragment_shading_rate");
187
188	if (!context.getFragmentShadingRateFeatures().pipelineFragmentShadingRate)
189		TCU_THROW(NotSupportedError, "pipelineFragmentShadingRate not supported");
190
191	// Fetch information about supported fragment shading rates
192	deUint32 supportedFragmentShadingRateCount = 0;
193	vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, DE_NULL);
194
195	std::vector<vk::VkPhysicalDeviceFragmentShadingRateKHR> supportedFragmentShadingRates(supportedFragmentShadingRateCount,
196		{
197			vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR,
198			DE_NULL,
199			vk::VK_SAMPLE_COUNT_1_BIT,
200			{1, 1}
201		});
202	vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, supportedFragmentShadingRates.data());
203
204	bool requiredRateFound = false;
205	for (const auto& rate : supportedFragmentShadingRates)
206	{
207		if ((rate.fragmentSize.width == 2u) &&
208			(rate.fragmentSize.height == 2u) &&
209			(rate.sampleCounts & sampleCount))
210		{
211			requiredRateFound = true;
212			break;
213		}
214	}
215
216	if (!requiredRateFound)
217		TCU_THROW(NotSupportedError, "Required FragmentShadingRate not supported");
218}
219
220VkImageAspectFlags getImageAspectFlags (const VkFormat format)
221{
222	const tcu::TextureFormat tcuFormat = mapVkFormat(format);
223
224	if      (tcuFormat.order == tcu::TextureFormat::DS)		return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
225	else if (tcuFormat.order == tcu::TextureFormat::D)		return VK_IMAGE_ASPECT_DEPTH_BIT;
226	else if (tcuFormat.order == tcu::TextureFormat::S)		return VK_IMAGE_ASPECT_STENCIL_BIT;
227
228	DE_FATAL("Format not handled");
229	return 0u;
230}
231
232VkPhysicalDeviceSampleLocationsPropertiesEXT getSampleLocationsPropertiesEXT (Context& context)
233{
234	const InstanceInterface&	vki				= context.getInstanceInterface();
235	const VkPhysicalDevice		physicalDevice	= context.getPhysicalDevice();
236
237	VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties;
238	deMemset(&sampleLocationsProperties, 0, sizeof(sampleLocationsProperties));
239
240	sampleLocationsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT;
241	sampleLocationsProperties.pNext = DE_NULL;
242
243	VkPhysicalDeviceProperties2 properties =
244	{
245		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,			// VkStructureType               sType;
246		&sampleLocationsProperties,								// void*                         pNext;
247		VkPhysicalDeviceProperties(),							// VkPhysicalDeviceProperties    properties;
248	};
249
250	vki.getPhysicalDeviceProperties2(physicalDevice, &properties);
251
252	return sampleLocationsProperties;
253}
254
255inline deUint32 numSamplesPerPixel (const MultisamplePixelGrid& pixelGrid)
256{
257	return static_cast<deUint32>(pixelGrid.samplesPerPixel());
258}
259
260inline VkSampleLocationsInfoEXT makeEmptySampleLocationsInfo ()
261{
262	const VkSampleLocationsInfoEXT info =
263	{
264		VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT,				// VkStructureType               sType;
265		DE_NULL,													// const void*                   pNext;
266		(VkSampleCountFlagBits)0,									// VkSampleCountFlagBits         sampleLocationsPerPixel;
267		makeExtent2D(0,0),											// VkExtent2D                    sampleLocationGridSize;
268		0,															// uint32_t                      sampleLocationsCount;
269		DE_NULL,													// const VkSampleLocationEXT*    pSampleLocations;
270	};
271	return info;
272}
273
274void logPixelGrid (tcu::TestLog& log, const VkPhysicalDeviceSampleLocationsPropertiesEXT& sampleLocationsProperties, const MultisamplePixelGrid& pixelGrid)
275{
276	log << tcu::TestLog::Section("pixelGrid", "Multisample pixel grid configuration:")
277		<< tcu::TestLog::Message << sampleLocationsProperties << tcu::TestLog::EndMessage
278		<< tcu::TestLog::Message << "Specified grid size = " << pixelGrid.size() << tcu::TestLog::EndMessage;
279
280	for (deUint32 gridY = 0; gridY < pixelGrid.size().y(); ++gridY)
281	for (deUint32 gridX = 0; gridX < pixelGrid.size().x(); ++gridX)
282	{
283		log << tcu::TestLog::Message << "Pixel(" << gridX << ", " << gridY <<")" << tcu::TestLog::EndMessage;
284
285		for (deUint32 sampleNdx = 0; sampleNdx < numSamplesPerPixel(pixelGrid); ++sampleNdx)
286		{
287			const VkSampleLocationEXT& loc = pixelGrid.getSample(gridX, gridY, sampleNdx);
288			log << tcu::TestLog::Message << "* Sample(" << sampleNdx <<") = " << Vec2(loc.x, loc.y) << tcu::TestLog::EndMessage;
289		}
290	}
291
292	log << tcu::TestLog::Message << "Sample locations visualization" << tcu::TestLog::EndMessage;
293
294	{
295		const deUint32		height	= deMinu32(1u << sampleLocationsProperties.sampleLocationSubPixelBits, 16u);	// increase if you want more precision
296		const deUint32		width	= 2 * height;	// works well with a fixed-size font
297		std::vector<char>	buffer	(width * height);
298
299		for (deUint32 gridY = 0; gridY < pixelGrid.size().y(); ++gridY)
300		for (deUint32 gridX = 0; gridX < pixelGrid.size().x(); ++gridX)
301		{
302			std::fill(buffer.begin(), buffer.end(), '.');
303
304			for (deUint32 sampleNdx = 0; sampleNdx < numSamplesPerPixel(pixelGrid); ++sampleNdx)
305			{
306				const VkSampleLocationEXT&	loc		= pixelGrid.getSample(gridX, gridY, sampleNdx);
307				const deUint32				ndx		= deMinu32(width  - 1, static_cast<deUint32>(static_cast<float>(width)  * loc.x)) +
308													  deMinu32(height - 1, static_cast<deUint32>(static_cast<float>(height) * loc.y)) * width;
309				const deUint32				evenNdx = ndx - ndx % 2;
310
311				buffer[evenNdx    ] = '[';
312				buffer[evenNdx + 1] = ']';
313			}
314
315			std::ostringstream str;
316			str << "Pixel(" << gridX << ", " << gridY <<")\n";
317
318			for (deUint32 lineNdx = 0; lineNdx < height; ++lineNdx)
319			{
320				str.write(&buffer[width * lineNdx], width);
321				str << "\n";
322			}
323
324			log << tcu::TestLog::Message << str.str() << tcu::TestLog::EndMessage;
325		}
326	}
327
328	log << tcu::TestLog::EndSection;
329}
330
331//! Place samples very close to each other
332void fillSampleLocationsPacked (MultisamplePixelGrid& grid, const deUint32 subPixelBits)
333{
334	const deUint32	numLocations	= 1u << subPixelBits;
335	const int		offset[3]		= { -1, 0, 1 };
336	de::Random		rng				(214);
337
338	for (deUint32 gridY = 0; gridY < grid.size().y(); ++gridY)
339	for (deUint32 gridX = 0; gridX < grid.size().x(); ++gridX)
340	{
341		// Will start placing from this location
342		const UVec2 baseLocationNdx (rng.getUint32() % numLocations,
343									 rng.getUint32() % numLocations);
344		UVec2		locationNdx		= baseLocationNdx;
345
346		std::set<UVec2, LessThan<UVec2> >	takenLocationIndices;
347		for (deUint32 sampleNdx = 0; sampleNdx < numSamplesPerPixel(grid); /* no increment */)
348		{
349			if (takenLocationIndices.find(locationNdx) == takenLocationIndices.end())
350			{
351				const VkSampleLocationEXT location =
352				{
353					static_cast<float>(locationNdx.x()) / static_cast<float>(numLocations),	// float x;
354					static_cast<float>(locationNdx.y()) / static_cast<float>(numLocations),	// float y;
355				};
356
357				grid.setSample(gridX, gridY, sampleNdx, location);
358				takenLocationIndices.insert(locationNdx);
359
360				++sampleNdx;	// next sample
361			}
362
363			// Find next location by applying a small offset. Just keep iterating if a redundant location is chosen
364			locationNdx.x() = static_cast<deUint32>(deClamp32(locationNdx.x() + offset[rng.getUint32() % DE_LENGTH_OF_ARRAY(offset)], 0u, numLocations - 1));
365			locationNdx.y() = static_cast<deUint32>(deClamp32(locationNdx.y() + offset[rng.getUint32() % DE_LENGTH_OF_ARRAY(offset)], 0u, numLocations - 1));
366		}
367	}
368}
369
370//! Unorm/int compare, very low threshold as we are expecting near-exact values
371bool compareGreenImage (tcu::TestLog& log, const char* name, const char* description, const tcu::ConstPixelBufferAccess& image)
372{
373	tcu::TextureLevel greenImage(image.getFormat(), image.getWidth(), image.getHeight());
374	tcu::clear(greenImage.getAccess(), tcu::RGBA::green().toIVec());
375	return tcu::intThresholdCompare(log, name, description, greenImage.getAccess(), image, tcu::UVec4(2u), tcu::COMPARE_LOG_RESULT);
376}
377
378//! Silent compare - no logging
379bool intThresholdCompare (const tcu::ConstPixelBufferAccess& reference, const tcu::ConstPixelBufferAccess& result, const UVec4& threshold)
380{
381	using namespace tcu;
382
383	int						width				= reference.getWidth();
384	int						height				= reference.getHeight();
385	int						depth				= reference.getDepth();
386	UVec4					maxDiff				(0, 0, 0, 0);
387
388	TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
389
390	for (int z = 0; z < depth; z++)
391	{
392		for (int y = 0; y < height; y++)
393		{
394			for (int x = 0; x < width; x++)
395			{
396				IVec4	refPix	= reference.getPixelInt(x, y, z);
397				IVec4	cmpPix	= result.getPixelInt(x, y, z);
398				UVec4	diff	= abs(refPix - cmpPix).cast<deUint32>();
399
400				maxDiff = max(maxDiff, diff);
401			}
402		}
403	}
404
405	return boolAll(lessThanEqual(maxDiff, threshold));
406}
407
408int countUniqueColors (const tcu::ConstPixelBufferAccess& image)
409{
410	std::set<Vec4, LessThan<Vec4> > colors;
411
412	for (int y = 0; y < image.getHeight(); ++y)
413	for (int x = 0; x < image.getWidth();  ++x)
414	{
415		colors.insert(image.getPixel(x, y));
416	}
417
418	return static_cast<int>(colors.size());
419}
420
421Move<VkImage> makeImage (const DeviceInterface&			vk,
422						 const VkDevice					device,
423						 const VkImageCreateFlags		flags,
424						 const VkFormat					format,
425						 const UVec2&					size,
426						 const VkSampleCountFlagBits	samples,
427						 const VkImageUsageFlags		usage)
428{
429	const VkImageCreateInfo imageParams =
430	{
431		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
432		DE_NULL,										// const void*				pNext;
433		flags,											// VkImageCreateFlags		flags;
434		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
435		format,											// VkFormat					format;
436		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
437		1u,												// deUint32					mipLevels;
438		1u,												// deUint32					arrayLayers;
439		samples,										// VkSampleCountFlagBits	samples;
440		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
441		usage,											// VkImageUsageFlags		usage;
442		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
443		0u,												// deUint32					queueFamilyIndexCount;
444		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
445		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
446	};
447	return createImage(vk, device, &imageParams);
448}
449
450Move<VkEvent> makeEvent (const DeviceInterface& vk, const VkDevice device)
451{
452	const VkEventCreateInfo createInfo =
453	{
454		VK_STRUCTURE_TYPE_EVENT_CREATE_INFO,		// VkStructureType       sType;
455		DE_NULL,									// const void*           pNext;
456		(VkEventCreateFlags)0,						// VkEventCreateFlags    flags;
457	};
458	return createEvent(vk, device, &createInfo);
459}
460
461//! Generate NDC space sample locations at each framebuffer pixel
462//! Data is filled starting at pixel (0,0) and for each pixel there are numSamples locations
463std::vector<Vec2> genFramebufferSampleLocations (const MultisamplePixelGrid& pixelGrid, const UVec2& gridSize, const UVec2& framebufferSize)
464{
465	std::vector<Vec2>	locations;
466
467	for (deUint32 y			= 0; y			< framebufferSize.y();				++y)
468	for (deUint32 x			= 0; x			< framebufferSize.x();				++x)
469	for (deUint32 sampleNdx	= 0; sampleNdx	< numSamplesPerPixel(pixelGrid);	++sampleNdx)
470	{
471		const VkSampleLocationEXT&	location = pixelGrid.getSample(x % gridSize.x(), y % gridSize.y(), sampleNdx);
472		const float					globalX  = location.x + static_cast<float>(x);
473		const float					globalY  = location.y + static_cast<float>(y);
474
475		// Transform to [-1, 1] space
476		locations.push_back(Vec2(-1.0f + 2.0f * (globalX / static_cast<float>(framebufferSize.x())),
477								 -1.0f + 2.0f * (globalY / static_cast<float>(framebufferSize.y()))));
478	}
479
480	return locations;
481}
482
483struct PositionColor
484{
485	tcu::Vec4	position;
486	tcu::Vec4	color;
487
488	PositionColor (const tcu::Vec4& pos, const tcu::Vec4& col) : position(pos), color(col) {}
489};
490
491std::vector<PositionColor> genVerticesFullQuad (const Vec4& color = Vec4(1.0f), const float z = 0.0f)
492{
493	const PositionColor vertices[] =
494	{
495		PositionColor(Vec4( 1.0f, -1.0f, z, 1.0f), color),
496		PositionColor(Vec4(-1.0f, -1.0f, z, 1.0f), color),
497		PositionColor(Vec4(-1.0f,  1.0f, z, 1.0f), color),
498
499		PositionColor(Vec4(-1.0f,  1.0f, z, 1.0f), color),
500		PositionColor(Vec4( 1.0f,  1.0f, z, 1.0f), color),
501		PositionColor(Vec4( 1.0f, -1.0f, z, 1.0f), color),
502	};
503
504	return std::vector<PositionColor>(vertices, vertices + DE_LENGTH_OF_ARRAY(vertices));
505}
506
507//! Some abstract geometry with angled edges, to make multisampling visible.
508std::vector<PositionColor> genVerticesShapes (const Vec4& color = Vec4(1.0f), const float z = 0.0f)
509{
510	std::vector<PositionColor> vertices;
511
512	const float numSteps  = 16.0f;
513	const float angleStep = (2.0f * DE_PI) / numSteps;
514
515	for (float a = 0.0f; a <= 2.0f * DE_PI; a += angleStep)
516	{
517		vertices.push_back(PositionColor(Vec4(1.0f * deFloatCos(a),				1.0f * deFloatSin(a),				z, 1.0f), color));
518		vertices.push_back(PositionColor(Vec4(0.1f * deFloatCos(a - angleStep), 0.1f * deFloatSin(a - angleStep),	z, 1.0f), color));
519		vertices.push_back(PositionColor(Vec4(0.1f * deFloatCos(a + angleStep), 0.1f * deFloatSin(a + angleStep),	z, 1.0f), color));
520	}
521
522	return vertices;
523}
524
525//! Stencil op that only allows drawing over the cleared area of an attachment.
526inline VkStencilOpState stencilOpStateDrawOnce (void)
527{
528	return makeStencilOpState(
529		VK_STENCIL_OP_KEEP,		// stencil fail
530		VK_STENCIL_OP_ZERO,		// depth & stencil pass
531		VK_STENCIL_OP_KEEP,		// depth only fail
532		VK_COMPARE_OP_EQUAL,	// compare op
533		~0u,					// compare mask
534		~0u,					// write mask
535		STENCIL_REFERENCE);		// reference
536}
537
538//! Stencil op that simply increments the buffer with each passing test.
539inline VkStencilOpState stencilOpStateIncrement(void)
540{
541	return makeStencilOpState(
542		VK_STENCIL_OP_KEEP,						// stencil fail
543		VK_STENCIL_OP_INCREMENT_AND_CLAMP,		// depth & stencil pass
544		VK_STENCIL_OP_KEEP,						// depth only fail
545		VK_COMPARE_OP_ALWAYS,					// compare op
546		~0u,									// compare mask
547		~0u,									// write mask
548		STENCIL_REFERENCE);						// reference
549}
550
551//! A few preconfigured vertex attribute configurations
552enum VertexInputConfig
553{
554	VERTEX_INPUT_NONE = 0u,
555	VERTEX_INPUT_VEC4,
556	VERTEX_INPUT_VEC4_VEC4,
557};
558
559//! Create a MSAA pipeline, with max per-sample shading
560void preparePipelineWrapper (GraphicsPipelineWrapper&			gpw,
561							 const std::vector<VkDynamicState>&	dynamicState,
562							 const PipelineLayoutWrapper&		pipelineLayout,
563							 const VkRenderPass					renderPass,
564							 const ShaderWrapper				vertexModule,
565							 const ShaderWrapper				fragmentModule,
566							 const deUint32						subpassIndex,
567							 const VkViewport&					viewport,
568							 const VkRect2D						scissor,
569							 const VkSampleCountFlagBits		numSamples,
570							 const bool							useSampleLocations,
571							 const VkSampleLocationsInfoEXT&	sampleLocationsInfo,
572							 const bool							useDepth,
573							 const bool							useStencil,
574							 const VertexInputConfig			vertexInputConfig,
575							 const VkPrimitiveTopology			topology,
576							 const VkStencilOpState&			stencilOpState,
577							 const bool							useFragmentShadingRate)
578{
579	std::vector<VkVertexInputBindingDescription>	vertexInputBindingDescriptions;
580	std::vector<VkVertexInputAttributeDescription>	vertexInputAttributeDescriptions;
581
582	const deUint32 sizeofVec4 = static_cast<deUint32>(sizeof(Vec4));
583
584	switch (vertexInputConfig)
585	{
586	case VERTEX_INPUT_NONE:
587		break;
588
589	case VERTEX_INPUT_VEC4:
590		vertexInputBindingDescriptions.push_back(makeVertexInputBindingDescription(0u, sizeofVec4, VK_VERTEX_INPUT_RATE_VERTEX));
591		vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u));
592		break;
593
594	case VERTEX_INPUT_VEC4_VEC4:
595		vertexInputBindingDescriptions.push_back(makeVertexInputBindingDescription(0u, 2u * sizeofVec4, VK_VERTEX_INPUT_RATE_VERTEX));
596		vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u));
597		vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, sizeofVec4));
598		break;
599
600	default:
601		DE_FATAL("Vertex input config not supported");
602		break;
603	}
604
605	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
606	{
607		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType							sType;
608		DE_NULL,														// const void*								pNext;
609		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags	flags;
610		static_cast<deUint32>(vertexInputBindingDescriptions.size()),	// uint32_t									vertexBindingDescriptionCount;
611		dataOrNullPtr(vertexInputBindingDescriptions),					// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
612		static_cast<deUint32>(vertexInputAttributeDescriptions.size()),	// uint32_t									vertexAttributeDescriptionCount;
613		dataOrNullPtr(vertexInputAttributeDescriptions),				// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
614	};
615
616	const VkPipelineSampleLocationsStateCreateInfoEXT pipelineSampleLocationsCreateInfo =
617	{
618		VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT,	// VkStructureType             sType;
619		DE_NULL,															// const void*                 pNext;
620		useSampleLocations,													// VkBool32                    sampleLocationsEnable;
621		sampleLocationsInfo,												// VkSampleLocationsInfoEXT    sampleLocationsInfo;
622	};
623
624	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
625	{
626		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	// VkStructureType							sType;
627		&pipelineSampleLocationsCreateInfo,							// const void*								pNext;
628		(VkPipelineMultisampleStateCreateFlags)0,					// VkPipelineMultisampleStateCreateFlags	flags;
629		numSamples,													// VkSampleCountFlagBits					rasterizationSamples;
630		VK_TRUE,													// VkBool32									sampleShadingEnable;
631		1.0f,														// float									minSampleShading;
632		DE_NULL,													// const VkSampleMask*						pSampleMask;
633		VK_FALSE,													// VkBool32									alphaToCoverageEnable;
634		VK_FALSE													// VkBool32									alphaToOneEnable;
635	};
636
637	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
638	{
639		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType							sType;
640		DE_NULL,													// const void*								pNext;
641		(VkPipelineDepthStencilStateCreateFlags)0,					// VkPipelineDepthStencilStateCreateFlags	flags;
642		useDepth,													// VkBool32									depthTestEnable;
643		true,														// VkBool32									depthWriteEnable;
644		VK_COMPARE_OP_LESS,											// VkCompareOp								depthCompareOp;
645		VK_FALSE,													// VkBool32									depthBoundsTestEnable;
646		useStencil,													// VkBool32									stencilTestEnable;
647		stencilOpState,												// VkStencilOpState							front;
648		stencilOpState,												// VkStencilOpState							back;
649		0.0f,														// float									minDepthBounds;
650		1.0f,														// float									maxDepthBounds;
651	};
652
653	const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
654	{
655		VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,		// VkStructureType						sType;
656		DE_NULL,													// const void*							pNext;
657		(VkPipelineDynamicStateCreateFlags)0,						// VkPipelineDynamicStateCreateFlags	flags;
658		static_cast<deUint32>(dynamicState.size()),					// uint32_t								dynamicStateCount;
659		dataOrNullPtr(dynamicState),								// const VkDynamicState*				pDynamicStates;
660	};
661
662	const VkPipelineColorBlendAttachmentState colorBlendAttachmentState
663	{
664		VK_FALSE,																								// VkBool32                 blendEnable
665		VK_BLEND_FACTOR_ZERO,																					// VkBlendFactor            srcColorBlendFactor
666		VK_BLEND_FACTOR_ZERO,																					// VkBlendFactor            dstColorBlendFactor
667		VK_BLEND_OP_ADD,																						// VkBlendOp                colorBlendOp
668		VK_BLEND_FACTOR_ZERO,																					// VkBlendFactor            srcAlphaBlendFactor
669		VK_BLEND_FACTOR_ZERO,																					// VkBlendFactor            dstAlphaBlendFactor
670		VK_BLEND_OP_ADD,																						// VkBlendOp                alphaBlendOp
671		VK_COLOR_COMPONENT_R_BIT																				// VkColorComponentFlags    colorWriteMask
672		| VK_COLOR_COMPONENT_G_BIT
673		| VK_COLOR_COMPONENT_B_BIT
674		| VK_COLOR_COMPONENT_A_BIT
675	};
676
677	VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfoDefault = initVulkanStructure();
678	colorBlendStateCreateInfoDefault.attachmentCount	= 1u;
679	colorBlendStateCreateInfoDefault.pAttachments		= &colorBlendAttachmentState;
680
681	const std::vector<VkViewport>	viewports	{ viewport };
682	const std::vector<VkRect2D>		scissors	{ scissor };
683
684	VkPipelineFragmentShadingRateStateCreateInfoKHR shadingRateStateCreateInfo
685	{
686		VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR,									// VkStructureType						sType;
687		DE_NULL,																								// const void*							pNext;
688		{ 2, 2 },																								// VkExtent2D							fragmentSize;
689		{ VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR, VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR },		// VkFragmentShadingRateCombinerOpKHR	combinerOps[2];
690	};
691
692	gpw.setDefaultTopology(topology)
693	   .setDynamicState(&dynamicStateCreateInfo)
694	   .setDefaultRasterizationState()
695	   .setupVertexInputState(&vertexInputStateInfo)
696	   .setupPreRasterizationShaderState(viewports,
697								scissors,
698								pipelineLayout,
699								renderPass,
700								subpassIndex,
701								vertexModule,
702								nullptr, ShaderWrapper(), ShaderWrapper(), ShaderWrapper(), DE_NULL,
703								(useFragmentShadingRate ? &shadingRateStateCreateInfo : nullptr))
704	   .setupFragmentShaderState(pipelineLayout,
705								renderPass,
706								subpassIndex,
707								fragmentModule,
708								&pipelineDepthStencilStateInfo,
709								&pipelineMultisampleStateInfo)
710	   .setupFragmentOutputState(renderPass, subpassIndex, &colorBlendStateCreateInfoDefault, &pipelineMultisampleStateInfo)
711	   .setMonolithicPipelineLayout(pipelineLayout)
712	   .buildPipeline();
713}
714
715void preparePipelineWrapperSinglePassColor (GraphicsPipelineWrapper&			gpw,
716											const std::vector<VkDynamicState>&	dynamicState,
717											const PipelineLayoutWrapper&		pipelineLayout,
718											const VkRenderPass					renderPass,
719											const ShaderWrapper					vertexModule,
720											const ShaderWrapper					fragmentModule,
721											const VkViewport&					viewport,
722											const VkRect2D						scissor,
723											const VkSampleCountFlagBits			numSamples,
724											const bool							useSampleLocations,
725											const VkSampleLocationsInfoEXT&		sampleLocationsInfo,
726											const VertexInputConfig				vertexInputConfig,
727											const VkPrimitiveTopology			topology,
728											const bool							useFragmentShadingRate)
729{
730	preparePipelineWrapper(gpw, dynamicState, pipelineLayout, renderPass, vertexModule, fragmentModule,
731						   /*subpass*/ 0u, viewport, scissor, numSamples, useSampleLocations, sampleLocationsInfo,
732						   /*depth test*/ false, /*stencil test*/ false, vertexInputConfig, topology, stencilOpStateIncrement(), useFragmentShadingRate);
733}
734
735//! Utility to build and maintain render pass, framebuffer and related resources.
736//! Use bake() before using the render pass.
737class RenderTarget
738{
739public:
740	RenderTarget (void)
741	{
742		nextSubpass();
743	}
744
745	//! Returns an attachment index that is used to reference this attachment later
746	deUint32 addAttachment (const VkImage						image,
747							const VkImageView					imageView,
748							const VkAttachmentDescriptionFlags	flags,
749							const VkFormat						format,
750							const VkSampleCountFlagBits			numSamples,
751							const VkAttachmentLoadOp			loadOp,
752							const VkAttachmentStoreOp			storeOp,
753							const VkAttachmentLoadOp			stencilLoadOp,
754							const VkAttachmentStoreOp			stencilStoreOp,
755							const VkImageLayout					initialLayout,
756							const VkImageLayout					finalLayout,
757							const VkClearValue					clearValue,
758							const VkSampleLocationsInfoEXT*		pInitialSampleLocations = DE_NULL)
759	{
760		const deUint32 index = static_cast<deUint32>(m_attachments.size());
761
762		m_images.push_back(image);
763		m_attachments.push_back(imageView);
764		m_attachmentDescriptions.push_back(makeAttachmentDescription(
765			flags,										// VkAttachmentDescriptionFlags		flags;
766			format,										// VkFormat							format;
767			numSamples,									// VkSampleCountFlagBits			samples;
768			loadOp,										// VkAttachmentLoadOp				loadOp;
769			storeOp,									// VkAttachmentStoreOp				storeOp;
770			stencilLoadOp,								// VkAttachmentLoadOp				stencilLoadOp;
771			stencilStoreOp,								// VkAttachmentStoreOp				stencilStoreOp;
772			initialLayout,								// VkImageLayout					initialLayout;
773			finalLayout									// VkImageLayout					finalLayout;
774		));
775		m_clearValues.push_back(clearValue);			// always add, even if unused
776
777		if (pInitialSampleLocations)
778		{
779			const VkAttachmentSampleLocationsEXT attachmentSampleLocations =
780			{
781				index,						// uint32_t                    attachmentIndex;
782				*pInitialSampleLocations,	// VkSampleLocationsInfoEXT    sampleLocationsInfo;
783			};
784			m_attachmentSampleLocations.push_back(attachmentSampleLocations);
785		}
786
787		return index;
788	}
789
790	void addSubpassColorAttachment (const deUint32 attachmentIndex, const VkImageLayout subpassLayout)
791	{
792		m_subpasses.back().colorAttachmentReferences.push_back(
793			makeAttachmentReference(attachmentIndex, subpassLayout));
794		m_subpasses.back().resolveAttachmentReferences.push_back(
795			makeAttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED));
796	}
797
798	void addSubpassColorAttachmentWithResolve (const deUint32 colorAttachmentIndex, const VkImageLayout colorSubpassLayout, const deUint32 resolveAttachmentIndex, const VkImageLayout resolveSubpassLayout, const VkSampleLocationsInfoEXT* pSampleLocations = DE_NULL)
799	{
800		m_subpasses.back().colorAttachmentReferences.push_back(
801			makeAttachmentReference(colorAttachmentIndex, colorSubpassLayout));
802		m_subpasses.back().resolveAttachmentReferences.push_back(
803			makeAttachmentReference(resolveAttachmentIndex, resolveSubpassLayout));
804
805		if (pSampleLocations)
806		{
807			const VkSubpassSampleLocationsEXT subpassSampleLocations =
808			{
809				static_cast<deUint32>(m_subpasses.size() - 1),		// uint32_t                    subpassIndex;
810				*pSampleLocations,									// VkSampleLocationsInfoEXT    sampleLocationsInfo;
811			};
812			m_subpassSampleLocations.push_back(subpassSampleLocations);
813		}
814	}
815
816	void addSubpassDepthStencilAttachment (const deUint32 attachmentIndex, const VkImageLayout subpassLayout, const VkSampleLocationsInfoEXT* pSampleLocations = DE_NULL)
817	{
818		m_subpasses.back().depthStencilAttachmentReferences.push_back(
819			makeAttachmentReference(attachmentIndex, subpassLayout));
820
821		if (pSampleLocations)
822		{
823			const VkSubpassSampleLocationsEXT subpassSampleLocations =
824			{
825				static_cast<deUint32>(m_subpasses.size() - 1),		// uint32_t                    subpassIndex;
826				*pSampleLocations,									// VkSampleLocationsInfoEXT    sampleLocationsInfo;
827			};
828			m_subpassSampleLocations.push_back(subpassSampleLocations);
829		}
830	}
831
832	void addSubpassInputAttachment (const deUint32 attachmentIndex, const VkImageLayout subpassLayout)
833	{
834		m_subpasses.back().inputAttachmentReferences.push_back(
835			makeAttachmentReference(attachmentIndex, subpassLayout));
836	}
837
838	void addSubpassPreserveAttachment (const deUint32 attachmentIndex)
839	{
840		m_subpasses.back().preserveAttachmentReferences.push_back(attachmentIndex);
841	}
842
843	void nextSubpass (void)
844	{
845		m_subpasses.push_back(SubpassDescription());
846	}
847
848	//! Create a RenderPass and Framebuffer based on provided attachments
849	void bake (const DeviceInterface&							vk,
850			   const VkDevice									device,
851			   const PipelineConstructionType					pipelineConstructionType,
852			   const UVec2&										framebufferSize)
853	{
854		const deUint32 numSubpasses = static_cast<deUint32>(m_subpasses.size());
855
856		std::vector<VkSubpassDescription>	subpassDescriptions;
857		std::vector<VkSubpassDependency>	subpassDependencies;
858		for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
859		{
860			const SubpassDescription&	sd			= m_subpasses[subpassNdx];
861			const VkSubpassDescription	description	=
862			{
863				(VkSubpassDescriptionFlags)0,									// VkSubpassDescriptionFlags		flags;
864				VK_PIPELINE_BIND_POINT_GRAPHICS,								// VkPipelineBindPoint				pipelineBindPoint;
865				static_cast<deUint32>(sd.inputAttachmentReferences.size()),		// deUint32							inputAttachmentCount;
866				dataOrNullPtr(sd.inputAttachmentReferences),					// const VkAttachmentReference*		pInputAttachments;
867				static_cast<deUint32>(sd.colorAttachmentReferences.size()),		// deUint32							colorAttachmentCount;
868				dataOrNullPtr(sd.colorAttachmentReferences),					// const VkAttachmentReference*		pColorAttachments;
869				dataOrNullPtr(sd.resolveAttachmentReferences),					// const VkAttachmentReference*		pResolveAttachments;
870				dataOrNullPtr(sd.depthStencilAttachmentReferences),				// const VkAttachmentReference*		pDepthStencilAttachment;
871				static_cast<deUint32>(sd.preserveAttachmentReferences.size()),	// deUint32							preserveAttachmentCount;
872				dataOrNullPtr(sd.preserveAttachmentReferences)					// const deUint32*					pPreserveAttachments;
873			};
874			subpassDescriptions.push_back(description);
875
876			// Add a very coarse dependency enforcing sequential ordering of subpasses
877			if (subpassNdx > 0)
878			{
879				static const VkAccessFlags	accessAny	= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
880														| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
881														| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
882														| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
883														| VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
884				const VkSubpassDependency	dependency	=
885				{
886					subpassNdx - 1,								// uint32_t                srcSubpass;
887					subpassNdx,									// uint32_t                dstSubpass;
888					VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,			// VkPipelineStageFlags    srcStageMask;
889					VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,			// VkPipelineStageFlags    dstStageMask;
890					accessAny,									// VkAccessFlags           srcAccessMask;
891					accessAny,									// VkAccessFlags           dstAccessMask;
892					(VkDependencyFlags)0,						// VkDependencyFlags       dependencyFlags;
893				};
894				subpassDependencies.push_back(dependency);
895			}
896		}
897		// add a final dependency to synchronize results for the copy commands that will follow the renderpass
898		const VkSubpassDependency finalDependency = {
899			numSubpasses - 1,																			// uint32_t                srcSubpass;
900			VK_SUBPASS_EXTERNAL,																		// uint32_t                dstSubpass;
901			VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,	// VkPipelineStageFlags    srcStageMask;
902			VK_PIPELINE_STAGE_TRANSFER_BIT,																// VkPipelineStageFlags    dstStageMask;
903			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,		// VkAccessFlags           srcAccessMask;
904			VK_ACCESS_TRANSFER_READ_BIT,																// VkAccessFlags           dstAccessMask;
905			(VkDependencyFlags)0,																		// VkDependencyFlags       dependencyFlags;
906		};
907		subpassDependencies.push_back(finalDependency);
908
909		const VkRenderPassCreateInfo renderPassInfo =
910		{
911			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,						// VkStructureType					sType;
912			DE_NULL,														// const void*						pNext;
913			(VkRenderPassCreateFlags)0,										// VkRenderPassCreateFlags			flags;
914			static_cast<deUint32>(m_attachmentDescriptions.size()),			// deUint32							attachmentCount;
915			dataOrNullPtr(m_attachmentDescriptions),						// const VkAttachmentDescription*	pAttachments;
916			static_cast<deUint32>(subpassDescriptions.size()),				// deUint32							subpassCount;
917			dataOrNullPtr(subpassDescriptions),								// const VkSubpassDescription*		pSubpasses;
918			static_cast<deUint32>(subpassDependencies.size()),				// deUint32							dependencyCount;
919			dataOrNullPtr(subpassDependencies)								// const VkSubpassDependency*		pDependencies;
920		};
921
922		m_renderPass  = RenderPassWrapper(pipelineConstructionType, vk, device, &renderPassInfo);
923		m_renderPass.createFramebuffer(vk, device, static_cast<deUint32>(m_attachments.size()), dataOrNullPtr(m_images), dataOrNullPtr(m_attachments), framebufferSize.x(), framebufferSize.y());
924	}
925
926	const RenderPassWrapper& getRenderPassWrapper (void) const
927	{
928		return m_renderPass;
929	}
930
931	VkRenderPass getRenderPass (void) const
932	{
933		return *m_renderPass;
934	}
935
936	VkFramebuffer getFramebuffer(void) const
937	{
938		return m_renderPass.getFramebuffer();
939	}
940
941	void recordBeginRenderPass (const DeviceInterface&	vk,
942								const VkCommandBuffer	cmdBuffer,
943								const VkRect2D&			renderArea,
944								const VkSubpassContents	subpassContents) const
945	{
946		const VkRenderPassSampleLocationsBeginInfoEXT renderPassSampleLocationsBeginInfo =
947		{
948			VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT,	// VkStructureType                          sType;
949			DE_NULL,														// const void*                              pNext;
950			static_cast<deUint32>(m_attachmentSampleLocations.size()),		// uint32_t                                 attachmentInitialSampleLocationsCount;
951			dataOrNullPtr(m_attachmentSampleLocations),						// const VkAttachmentSampleLocationsEXT*    pAttachmentInitialSampleLocations;
952			static_cast<deUint32>(m_subpassSampleLocations.size()),			// uint32_t                                 postSubpassSampleLocationsCount;
953			dataOrNullPtr(m_subpassSampleLocations),						// const VkSubpassSampleLocationsEXT*       pPostSubpassSampleLocations;
954		};
955		m_renderPass.begin(vk, cmdBuffer, renderArea, static_cast<deUint32>(m_clearValues.size()), dataOrNullPtr(m_clearValues), subpassContents, &renderPassSampleLocationsBeginInfo);
956	}
957
958	void nextSubpass (const DeviceInterface& vk, const VkCommandBuffer cmdBuffer, const VkSubpassContents subpassContents) const
959	{
960		m_renderPass.nextSubpass(vk, cmdBuffer, subpassContents);
961	}
962
963	void endRenderPass (const DeviceInterface& vk, const VkCommandBuffer cmdBuffer) const
964	{
965		m_renderPass.end(vk, cmdBuffer);
966	}
967
968private:
969	struct SubpassDescription
970	{
971		std::vector<VkAttachmentReference>	inputAttachmentReferences;
972		std::vector<VkAttachmentReference>	colorAttachmentReferences;
973		std::vector<VkAttachmentReference>	resolveAttachmentReferences;
974		std::vector<VkAttachmentReference>	depthStencilAttachmentReferences;
975		std::vector<deUint32>				preserveAttachmentReferences;
976	};
977
978	std::vector<SubpassDescription>				m_subpasses;
979	std::vector<VkImage>						m_images;
980	std::vector<VkImageView>					m_attachments;
981	std::vector<VkAttachmentDescription>		m_attachmentDescriptions;
982	std::vector<VkClearValue>					m_clearValues;
983	std::vector<VkAttachmentSampleLocationsEXT>	m_attachmentSampleLocations;
984	std::vector<VkSubpassSampleLocationsEXT>	m_subpassSampleLocations;
985	RenderPassWrapper							m_renderPass;
986
987	// No copying allowed
988	RenderTarget (const RenderTarget&);
989	RenderTarget& operator=(const RenderTarget&);
990};
991
992void recordImageBarrier (const DeviceInterface&				vk,
993						 const VkCommandBuffer				cmdBuffer,
994						 const VkImage						image,
995						 const VkImageAspectFlags			aspect,
996						 const VkPipelineStageFlags			srcStageMask,
997						 const VkPipelineStageFlags			dstStageMask,
998						 const VkAccessFlags				srcAccessMask,
999						 const VkAccessFlags				dstAccessMask,
1000						 const VkImageLayout				oldLayout,
1001						 const VkImageLayout				newLayout,
1002						 const VkSampleLocationsInfoEXT*	pSampleLocationsInfo = DE_NULL)
1003{
1004	const VkImageMemoryBarrier barrier =
1005	{
1006		VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType            sType;
1007		pSampleLocationsInfo,										// const void*                pNext;
1008		srcAccessMask,												// VkAccessFlags              srcAccessMask;
1009		dstAccessMask,												// VkAccessFlags              dstAccessMask;
1010		oldLayout,													// VkImageLayout              oldLayout;
1011		newLayout,													// VkImageLayout              newLayout;
1012		VK_QUEUE_FAMILY_IGNORED,									// uint32_t                   srcQueueFamilyIndex;
1013		VK_QUEUE_FAMILY_IGNORED,									// uint32_t                   dstQueueFamilyIndex;
1014		image,														// VkImage                    image;
1015		makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u),			// VkImageSubresourceRange    subresourceRange;
1016	};
1017
1018	vk.cmdPipelineBarrier(cmdBuffer, srcStageMask, dstStageMask, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
1019}
1020
1021void recordWaitEventWithImage (const DeviceInterface&			vk,
1022							   const VkCommandBuffer			cmdBuffer,
1023							   const VkEvent					event,
1024							   const VkImage					image,
1025							   const VkImageAspectFlags			aspect,
1026							   const VkPipelineStageFlags		srcStageMask,
1027							   const VkPipelineStageFlags		dstStageMask,
1028							   const VkAccessFlags				srcAccessMask,
1029							   const VkAccessFlags				dstAccessMask,
1030							   const VkImageLayout				oldLayout,
1031							   const VkImageLayout				newLayout,
1032							   const VkSampleLocationsInfoEXT*	pSampleLocationsInfo = DE_NULL)
1033{
1034	const VkImageMemoryBarrier barrier =
1035	{
1036		VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType            sType;
1037		pSampleLocationsInfo,										// const void*                pNext;
1038		srcAccessMask,												// VkAccessFlags              srcAccessMask;
1039		dstAccessMask,												// VkAccessFlags              dstAccessMask;
1040		oldLayout,													// VkImageLayout              oldLayout;
1041		newLayout,													// VkImageLayout              newLayout;
1042		VK_QUEUE_FAMILY_IGNORED,									// uint32_t                   srcQueueFamilyIndex;
1043		VK_QUEUE_FAMILY_IGNORED,									// uint32_t                   dstQueueFamilyIndex;
1044		image,														// VkImage                    image;
1045		makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u),			// VkImageSubresourceRange    subresourceRange;
1046	};
1047
1048	vk.cmdWaitEvents(
1049		cmdBuffer,													// VkCommandBuffer                             commandBuffer,
1050		1u,															// uint32_t                                    eventCount,
1051		&event,														// const VkEvent*                              pEvents,
1052		srcStageMask,												// VkPipelineStageFlags                        srcStageMask,
1053		dstStageMask,												// VkPipelineStageFlags                        dstStageMask,
1054		0u,															// uint32_t                                    memoryBarrierCount,
1055		DE_NULL,													// const VkMemoryBarrier*                      pMemoryBarriers,
1056		0u,															// uint32_t                                    bufferMemoryBarrierCount,
1057		DE_NULL,													// const VkBufferMemoryBarrier*                pBufferMemoryBarriers,
1058		1u,															// uint32_t                                    imageMemoryBarrierCount,
1059		&barrier);													// const VkImageMemoryBarrier*                 pImageMemoryBarriers);
1060}
1061
1062void recordCopyImageToBuffer (const DeviceInterface&	vk,
1063							  const VkCommandBuffer		cmdBuffer,
1064							  const UVec2&				imageSize,
1065							  const VkImage				srcImage,
1066							  const VkBuffer			dstBuffer)
1067{
1068	// Resolve image -> host buffer
1069	{
1070		const VkBufferImageCopy region =
1071		{
1072			0ull,																// VkDeviceSize                bufferOffset;
1073			0u,																	// uint32_t                    bufferRowLength;
1074			0u,																	// uint32_t                    bufferImageHeight;
1075			makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u),	// VkImageSubresourceLayers    imageSubresource;
1076			makeOffset3D(0, 0, 0),												// VkOffset3D                  imageOffset;
1077			makeExtent3D(imageSize.x(), imageSize.y(), 1u),						// VkExtent3D                  imageExtent;
1078		};
1079
1080		vk.cmdCopyImageToBuffer(cmdBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstBuffer, 1u, &region);
1081	}
1082	// Buffer write barrier
1083	{
1084		const VkBufferMemoryBarrier barrier =
1085		{
1086			VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType    sType;
1087			DE_NULL,										// const void*        pNext;
1088			VK_ACCESS_TRANSFER_WRITE_BIT,					// VkAccessFlags      srcAccessMask;
1089			VK_ACCESS_HOST_READ_BIT,						// VkAccessFlags      dstAccessMask;
1090			VK_QUEUE_FAMILY_IGNORED,						// uint32_t           srcQueueFamilyIndex;
1091			VK_QUEUE_FAMILY_IGNORED,						// uint32_t           dstQueueFamilyIndex;
1092			dstBuffer,										// VkBuffer           buffer;
1093			0ull,											// VkDeviceSize       offset;
1094			VK_WHOLE_SIZE,									// VkDeviceSize       size;
1095		};
1096
1097		vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
1098							  0u, DE_NULL, 1u, &barrier, DE_NULL, 0u);
1099	}
1100}
1101
1102void recordClearAttachments (const DeviceInterface&		vk,
1103							 const VkCommandBuffer		cmdBuffer,
1104							 const deUint32				colorAttachment,
1105							 const VkClearValue&		colorClearValue,
1106							 const VkImageAspectFlags	depthStencilAspect,
1107							 const VkClearValue&		depthStencilClearValue,
1108							 const VkRect2D&			clearRect)
1109{
1110	std::vector<VkClearAttachment> attachments;
1111
1112	const VkClearRect rect =
1113	{
1114		clearRect,					// VkRect2D    rect;
1115		0u,							// uint32_t    baseArrayLayer;
1116		1u,							// uint32_t    layerCount;
1117	};
1118
1119	// Clear color
1120	{
1121		const VkClearAttachment attachment =
1122		{
1123			VK_IMAGE_ASPECT_COLOR_BIT,	// VkImageAspectFlags    aspectMask;
1124			colorAttachment,			// uint32_t              colorAttachment;
1125			colorClearValue,			// VkClearValue          clearValue;
1126		};
1127		attachments.push_back(attachment);
1128	}
1129
1130	if ((depthStencilAspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0u)
1131	{
1132		const VkClearAttachment attachment =
1133		{
1134			depthStencilAspect,			// VkImageAspectFlags    aspectMask;
1135			VK_ATTACHMENT_UNUSED,		// uint32_t              colorAttachment;
1136			depthStencilClearValue,		// VkClearValue          clearValue;
1137		};
1138		attachments.push_back(attachment);
1139	}
1140
1141	vk.cmdClearAttachments(cmdBuffer, static_cast<deUint32>(attachments.size()), dataOrNullPtr(attachments), 1u, &rect);
1142}
1143
1144//! Suitable for executing in a render pass, no queries
1145void beginSecondaryCommandBuffer (const DeviceInterface&			vk,
1146								  const VkCommandBuffer				commandBuffer,
1147								  const RenderPassWrapper&			renderPass,
1148								  const deUint32					subpass,
1149								  const VkSampleCountFlagBits		samples,
1150								  const PipelineConstructionType	pct)
1151{
1152	DE_UNREF(samples);
1153	DE_UNREF(pct);
1154	VkCommandBufferInheritanceInfo inheritanceInfo =
1155	{
1156		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,		// VkStructureType                  sType;
1157		DE_NULL,												// const void*                      pNext;
1158		*renderPass,											// VkRenderPass                     renderPass;
1159		subpass,												// uint32_t                         subpass;
1160		renderPass.getFramebuffer(),							// VkFramebuffer                    framebuffer;
1161		VK_FALSE,												// VkBool32                         occlusionQueryEnable;
1162		(VkQueryControlFlags)0,									// VkQueryControlFlags              queryFlags;
1163		(VkQueryPipelineStatisticFlags)0,						// VkQueryPipelineStatisticFlags    pipelineStatistics;
1164	};
1165
1166	const VkCommandBufferBeginInfo beginInfo =
1167	{
1168		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,		// VkStructureType                          sType;
1169		DE_NULL,											// const void*                              pNext;
1170		(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
1171		|VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT),	// VkCommandBufferUsageFlags                flags;
1172		&inheritanceInfo,									// const VkCommandBufferInheritanceInfo*    pInheritanceInfo;
1173	};
1174
1175#ifndef CTS_USES_VULKANSC
1176	vk::VkCommandBufferInheritanceRenderingInfo inheritanceRenderingInfo = vk::initVulkanStructure();
1177	inheritanceRenderingInfo.flags = (VkRenderingFlags)0u;
1178	inheritanceRenderingInfo.viewMask = 0x0;
1179	inheritanceRenderingInfo.rasterizationSamples = samples;
1180	std::vector<vk::VkFormat> colorFormats;
1181	if (isConstructionTypeShaderObject(pct))
1182	{
1183		renderPass.fillInheritanceRenderingInfo(subpass, &colorFormats, &inheritanceRenderingInfo);
1184		inheritanceInfo.pNext = &inheritanceRenderingInfo;
1185	}
1186#endif
1187
1188	VK_CHECK(vk.beginCommandBuffer(commandBuffer, &beginInfo));
1189}
1190
1191//! Verify results of a VkPhysicalDeviceSampleLocationsPropertiesEXT query with VkPhysicalDeviceProperties2KHR
1192tcu::TestStatus testQuerySampleLocationProperties (Context& context)
1193{
1194	const VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties = getSampleLocationsPropertiesEXT(context);
1195
1196	context.getTestContext().getLog()
1197		<< tcu::TestLog::Section("VkPhysicalDeviceSampleLocationsPropertiesEXT", "Query results")
1198		<< tcu::TestLog::Message << sampleLocationsProperties << tcu::TestLog::EndMessage
1199		<< tcu::TestLog::EndSection;
1200
1201	const VkSampleCountFlags allowedSampleCounts = (VK_SAMPLE_COUNT_2_BIT  |
1202													VK_SAMPLE_COUNT_4_BIT  |
1203													VK_SAMPLE_COUNT_8_BIT  |
1204													VK_SAMPLE_COUNT_16_BIT |
1205													VK_SAMPLE_COUNT_32_BIT |
1206													VK_SAMPLE_COUNT_64_BIT);
1207
1208	if ((sampleLocationsProperties.sampleLocationSampleCounts & allowedSampleCounts) == 0)
1209	{
1210		return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: sampleLocationSampleCounts should specify at least one MSAA sample count");
1211	}
1212
1213	if (sampleLocationsProperties.maxSampleLocationGridSize.width  == 0u     ||
1214		sampleLocationsProperties.maxSampleLocationGridSize.height == 0u     ||
1215		sampleLocationsProperties.maxSampleLocationGridSize.width  >  16384u || // max not specified, but try to catch nonsense values like -1
1216		sampleLocationsProperties.maxSampleLocationGridSize.height >  16384u)
1217	{
1218		return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: maxSampleLocationGridSize must be at least (1,1) size");
1219	}
1220
1221	for (int i = 0; i < 2; ++i)
1222	{
1223		if (sampleLocationsProperties.sampleLocationCoordinateRange[i] < 0.0f ||
1224			sampleLocationsProperties.sampleLocationCoordinateRange[i] > 1.0f)
1225		{
1226			return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: sampleLocationCoordinateRange[] values must be in [0, 1] range");
1227		}
1228	}
1229
1230	if (sampleLocationsProperties.sampleLocationSubPixelBits == 0u  ||
1231		sampleLocationsProperties.sampleLocationSubPixelBits >  64u)	// max not specified, but try to catch nonsense values
1232	{
1233		return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: sampleLocationSubPixelBits should be greater than 0");
1234	}
1235
1236	return tcu::TestStatus::pass("Pass");
1237}
1238
1239//! Verify results of vkGetPhysicalDeviceMultisamplePropertiesEXT queries
1240tcu::TestStatus testQueryMultisampleProperties (Context& context)
1241{
1242	const InstanceInterface&	vki				= context.getInstanceInterface();
1243	const VkPhysicalDevice		physicalDevice	= context.getPhysicalDevice();
1244	tcu::TestLog&				log				= context.getTestContext().getLog();
1245
1246	const VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties = getSampleLocationsPropertiesEXT(context);
1247
1248	const VkSampleCountFlagBits	sampleCountRange[] =
1249	{
1250		VK_SAMPLE_COUNT_1_BIT,
1251		VK_SAMPLE_COUNT_2_BIT,
1252		VK_SAMPLE_COUNT_4_BIT,
1253		VK_SAMPLE_COUNT_8_BIT,
1254		VK_SAMPLE_COUNT_16_BIT,
1255		VK_SAMPLE_COUNT_32_BIT,
1256		VK_SAMPLE_COUNT_64_BIT,
1257	};
1258
1259	bool allOk = true;
1260
1261	for (const VkSampleCountFlagBits* pLoopNumSamples = sampleCountRange; pLoopNumSamples < DE_ARRAY_END(sampleCountRange); ++pLoopNumSamples)
1262	{
1263		VkMultisamplePropertiesEXT multisampleProperties =
1264		{
1265			VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT,		// VkStructureType    sType;
1266			DE_NULL,											// void*              pNext;
1267			VkExtent2D(),										// VkExtent2D         maxSampleLocationGridSize;
1268		};
1269
1270		vki.getPhysicalDeviceMultisamplePropertiesEXT(physicalDevice, *pLoopNumSamples, &multisampleProperties);
1271
1272		log << tcu::TestLog::Section("getPhysicalDeviceMultisamplePropertiesEXT", "Query results")
1273			<< tcu::TestLog::Message << "Sample count: " << *pLoopNumSamples << tcu::TestLog::EndMessage
1274			<< tcu::TestLog::Message << multisampleProperties << tcu::TestLog::EndMessage;
1275
1276		const bool isSupportedSampleCount = (*pLoopNumSamples & sampleLocationsProperties.sampleLocationSampleCounts) != 0;
1277
1278		if (isSupportedSampleCount)
1279		{
1280			if (!(multisampleProperties.maxSampleLocationGridSize.width  >= sampleLocationsProperties.maxSampleLocationGridSize.width &&
1281				  multisampleProperties.maxSampleLocationGridSize.height >= sampleLocationsProperties.maxSampleLocationGridSize.height))
1282			{
1283				allOk = false;
1284				log << tcu::TestLog::Message
1285					<< "FAIL: Grid size should be the same or larger than VkPhysicalDeviceSampleLocationsPropertiesEXT::maxSampleLocationGridSize"
1286					<< tcu::TestLog::EndMessage;
1287			}
1288		}
1289		else
1290		{
1291			if (!(multisampleProperties.maxSampleLocationGridSize.width  == 0u &&
1292				  multisampleProperties.maxSampleLocationGridSize.height == 0u))
1293			{
1294				allOk = false;
1295				log << tcu::TestLog::Message << "FAIL: Expected (0, 0) grid size" << tcu::TestLog::EndMessage;
1296			}
1297		}
1298
1299		log << tcu::TestLog::EndSection;
1300	}
1301
1302	return allOk ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Some values were incorrect");
1303}
1304
1305// These tests only use a color attachment and focus on per-sample data
1306namespace VerifySamples
1307{
1308
1309//! Data layout used in verify sample locations and interpolation cases
1310namespace SampleDataSSBO
1311{
1312
1313static VkDeviceSize	STATIC_SIZE		= 6 * sizeof(deUint32);
1314
1315static UVec2&		renderSize		(void* const basePtr) { return *reinterpret_cast<UVec2*>	(static_cast<deUint8*>(basePtr) + 0 * sizeof(deUint32)); }
1316static UVec2&		gridSize		(void* const basePtr) { return *reinterpret_cast<UVec2*>	(static_cast<deUint8*>(basePtr) + 2 * sizeof(deUint32)); }
1317static deUint32&	samplesPerPixel	(void* const basePtr) { return *reinterpret_cast<deUint32*>	(static_cast<deUint8*>(basePtr) + 4 * sizeof(deUint32)); }
1318
1319template<typename T>
1320static T*			sampleData		(void* const basePtr) { DE_STATIC_ASSERT(sizeof(T) == sizeof(Vec2));
1321															return  reinterpret_cast<T*>		(static_cast<deUint8*>(basePtr) + STATIC_SIZE); }
1322
1323} // SampleDataSSBO
1324
1325enum TestOptionFlagBits
1326{
1327	TEST_OPTION_DYNAMIC_STATE_BIT				= 0x1,	//!< Use dynamic pipeline state to pass in sample locations
1328	TEST_OPTION_CLOSELY_PACKED_BIT				= 0x2,	//!< Place samples as close as possible to each other
1329	TEST_OPTION_FRAGMENT_SHADING_RATE_BIT		= 0x4,	//!< Use VK_KHR_fragment_shading_rate
1330	TEST_OPTION_VARIABLE_SAMPLE_LOCATIONS_BIT	= 0x8	//!< Use variable sample locations
1331};
1332typedef deUint32 TestOptionFlags;
1333
1334struct TestParams
1335{
1336	PipelineConstructionType	pipelineConstructionType;
1337	VkSampleCountFlagBits		numSamples;
1338	TestOptionFlags				options;
1339};
1340
1341void checkSupportVerifyTests (Context& context, const TestParams params)
1342{
1343	checkSupportSampleLocations(context);
1344
1345	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
1346
1347	if ((context.getDeviceProperties().limits.framebufferColorSampleCounts & params.numSamples) == 0u)
1348		TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported");
1349
1350	if ((getSampleLocationsPropertiesEXT(context).sampleLocationSampleCounts & params.numSamples) == 0u)
1351		TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: sample count not supported");
1352
1353	if (TEST_OPTION_FRAGMENT_SHADING_RATE_BIT & params.options)
1354		checkFragmentShadingRateRequirements(context, params.numSamples);
1355
1356	if (TEST_OPTION_VARIABLE_SAMPLE_LOCATIONS_BIT & params.options && !getSampleLocationsPropertiesEXT(context).variableSampleLocations)
1357		TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: variableSampleLocations not supported");
1358
1359	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), params.pipelineConstructionType);
1360}
1361
1362std::string declareSampleDataSSBO (void)
1363{
1364	std::ostringstream str;
1365	str << "layout(set = 0, binding = 0, std430) readonly buffer SampleData {\n"	// make sure this matches SampleDataSSBO definition
1366		<< "    uvec2 renderSize;\n"
1367		<< "    uvec2 gridSize;\n"
1368		<< "    uint  samplesPerPixel;\n"
1369		<< "          // padding 1-uint size;\n"
1370		<< "    vec2  data[];\n"
1371		<< "} sb_data;\n";
1372	return str.str();
1373}
1374
1375void addProgramsVerifyLocationGeometry (SourceCollections& programCollection, const TestParams)
1376{
1377	// Vertex shader
1378	{
1379		std::ostringstream src;
1380		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1381			<< "\n"
1382			<< "layout(location = 0) in vec4 in_position;\n"
1383			<< "\n"
1384			<< "out gl_PerVertex {\n"
1385			<< "    vec4 gl_Position;\n"
1386			<< "};\n"
1387			<< "\n"
1388			<< "void main(void)\n"
1389			<< "{\n"
1390			<< "    gl_Position = in_position;\n"
1391			<< "}\n";
1392
1393		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1394	}
1395
1396	// Fragment shader
1397	{
1398		std::ostringstream src;
1399		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1400			<< "\n"
1401			<< "layout(location = 0) out vec4 o_color;\n"
1402			<< "\n"
1403			<< declareSampleDataSSBO()
1404			<< "\n"
1405			<< "void main(void)\n"
1406			<< "{\n"
1407			<< "    uvec2 fragCoord = uvec2(gl_FragCoord.xy);\n"
1408			<< "    uint  index     = (fragCoord.y * sb_data.renderSize.x + fragCoord.x) * sb_data.samplesPerPixel + gl_SampleID;\n"
1409			<< "\n"
1410			<< "    if (gl_PrimitiveID == index)\n"
1411			<< "        o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1412			<< "    else\n"
1413			<< "        o_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1414			<< "}\n";
1415
1416		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
1417	}
1418}
1419
1420void addProgramsVerifyInterpolation (SourceCollections& programCollection, const TestParams)
1421{
1422	// Vertex shader
1423	{
1424		std::ostringstream src;
1425		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1426			<< "\n"
1427			<< "layout(location = 0) in  vec4 in_position;\n"
1428			<< "layout(location = 0) out vec2 o_position;\n"
1429			<< "\n"
1430			<< "out gl_PerVertex {\n"
1431			<< "    vec4 gl_Position;\n"
1432			<< "};\n"
1433			<< "\n"
1434			<< "void main(void)\n"
1435			<< "{\n"
1436			<< "    gl_Position = in_position;\n"
1437			<< "    o_position  = in_position.xy;\n"	// user-data that will be interpolated
1438			<< "}\n";
1439
1440		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1441	}
1442
1443	// Fragment shader
1444	{
1445		std::ostringstream src;
1446		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1447			<< "\n"
1448			<< "layout(location = 0) sample in  vec2 in_value;\n"
1449			<< "layout(location = 0)        out vec4 o_color;\n"
1450			<< "\n"
1451			<< declareSampleDataSSBO()
1452			<< "\n"
1453			<< "void main(void)\n"
1454			<< "{\n"
1455			<< "    uvec2 fragCoord         = uvec2(gl_FragCoord.xy);\n"
1456			<< "    uint  index             = (fragCoord.y * sb_data.renderSize.x + fragCoord.x) * sb_data.samplesPerPixel + gl_SampleID;\n"
1457			<< "    vec2  diff              = abs(sb_data.data[index] - in_value);\n"
1458			<< "    vec2  threshold         = vec2(0.002);\n"
1459			<< "\n"
1460			<< "    if (all(lessThan(diff, threshold)))\n"
1461			<< "        o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1462			<< "    else\n"
1463			<< "        o_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1464			<< "}\n";
1465
1466		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
1467	}
1468}
1469
1470class TestBase : public TestInstance
1471{
1472public:
1473	TestBase (Context& context, const TestParams params)
1474		: TestInstance					(context)
1475		, m_params						(params)
1476		, m_sampleLocationsProperties	(getSampleLocationsPropertiesEXT(context))
1477		, m_colorFormat					(VK_FORMAT_R8G8B8A8_UNORM)
1478		, m_numVertices					(0)
1479		, m_currentGridNdx				(0)
1480	{
1481		VkMultisamplePropertiesEXT multisampleProperties =
1482		{
1483			VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT,		// VkStructureType    sType;
1484			DE_NULL,											// void*              pNext;
1485			VkExtent2D(),										// VkExtent2D         maxSampleLocationGridSize;
1486		};
1487
1488		m_context.getInstanceInterface().getPhysicalDeviceMultisamplePropertiesEXT(m_context.getPhysicalDevice(), m_params.numSamples, &multisampleProperties);
1489
1490		// Generate grid size combinations
1491		for (deUint32 y = multisampleProperties.maxSampleLocationGridSize.height; y >= 1u; y >>= 1)
1492		for (deUint32 x = multisampleProperties.maxSampleLocationGridSize.width;  x >= 1u; x >>= 1)
1493		{
1494			DE_ASSERT(multisampleProperties.maxSampleLocationGridSize.width  % x == 0u);
1495			DE_ASSERT(multisampleProperties.maxSampleLocationGridSize.height % y == 0u);
1496			m_gridSizes.push_back(UVec2(x, y));
1497		}
1498	}
1499
1500	tcu::TestStatus iterate (void)
1501	{
1502		// Will be executed several times, for all possible pixel grid sizes
1503		if (!(currentGridSize().x() >= 1 && currentGridSize().y() >= 1))
1504			return tcu::TestStatus::fail("maxSampleLocationGridSize is invalid");
1505
1506		// Prepare the pixel grid
1507		{
1508			const deUint32	pixelGridRepetitions = 2;	// just to make sure the pattern is consistently applied across the framebuffer
1509			m_renderSize = UVec2(pixelGridRepetitions * currentGridSize().x(),
1510								 pixelGridRepetitions * currentGridSize().y());
1511			m_pixelGrid = MovePtr<MultisamplePixelGrid>(new MultisamplePixelGrid(currentGridSize(), m_params.numSamples));
1512
1513			if ((m_params.options & TEST_OPTION_CLOSELY_PACKED_BIT) != 0u)
1514				fillSampleLocationsPacked(*m_pixelGrid, m_sampleLocationsProperties.sampleLocationSubPixelBits);
1515			else
1516				fillSampleLocationsRandom(*m_pixelGrid, m_sampleLocationsProperties.sampleLocationSubPixelBits);
1517
1518			logPixelGrid (m_context.getTestContext().getLog(), m_sampleLocationsProperties, *m_pixelGrid);
1519		}
1520
1521		// Create images
1522		{
1523			const DeviceInterface&	vk			= m_context.getDeviceInterface();
1524			const VkDevice			device		= m_context.getDevice();
1525			Allocator&				allocator	= m_context.getDefaultAllocator();
1526
1527			// Images and staging buffers
1528
1529			m_colorImage		= makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize, m_params.numSamples, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
1530			m_colorImageAlloc	= bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
1531			m_colorImageView	= makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
1532
1533			m_resolveImage		= makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1534			m_resolveImageAlloc	= bindImage(vk, device, allocator, *m_resolveImage, MemoryRequirement::Any);
1535			m_resolveImageView	= makeImageView(vk, device, *m_resolveImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
1536
1537			const VkDeviceSize	colorBufferSize = m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(m_colorFormat));
1538			m_colorBuffer		= makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1539			m_colorBufferAlloc	= bindBuffer(vk, device, allocator, *m_colorBuffer, MemoryRequirement::HostVisible);
1540		}
1541
1542		if (!testPixelGrid())
1543			return tcu::TestStatus::fail("Fail");
1544
1545		if (shrinkCurrentGrid())
1546			return tcu::TestStatus::incomplete();
1547		else
1548			return tcu::TestStatus::pass("Pass");
1549	}
1550
1551protected:
1552	//! Return true if the test passed the current grid size
1553	virtual bool testPixelGrid (void) = 0;
1554
1555	const UVec2& currentGridSize (void)
1556	{
1557		return m_gridSizes[m_currentGridNdx];
1558	}
1559
1560	//! Return false if the grid is already at (1, 1) size
1561	bool shrinkCurrentGrid (void)
1562	{
1563		if (m_gridSizes.size() <= m_currentGridNdx + 1)
1564			return false;
1565
1566		++m_currentGridNdx;
1567		return true;
1568	}
1569
1570	void drawSinglePass (const VertexInputConfig vertexInputConfig)
1571	{
1572		DE_ASSERT(m_descriptorSetLayout);
1573
1574		const InstanceInterface&		vki				= m_context.getInstanceInterface();
1575		const DeviceInterface&			vk				= m_context.getDeviceInterface();
1576		const VkPhysicalDevice			physicalDevice	= m_context.getPhysicalDevice();
1577		const VkDevice					device			= m_context.getDevice();
1578		const VkViewport				viewport		= makeViewport(m_renderSize);
1579		const VkRect2D					renderArea		= makeRect2D(m_renderSize);
1580		const VkRect2D					scissor			= makeRect2D(m_renderSize);
1581		const ShaderWrapper				vertexModule	(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1582		const ShaderWrapper				fragmentModule	(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
1583		const PipelineLayoutWrapper		pipelineLayout	(m_params.pipelineConstructionType, vk, device, *m_descriptorSetLayout);
1584
1585		const bool						useDynamicStateSampleLocations	= ((m_params.options & TEST_OPTION_DYNAMIC_STATE_BIT) != 0u);
1586		const bool						useFragmentShadingRate			= ((m_params.options & TEST_OPTION_FRAGMENT_SHADING_RATE_BIT) != 0u);
1587		const VkSampleLocationsInfoEXT	sampleLocationsInfo				= makeSampleLocationsInfo(*m_pixelGrid);
1588
1589		RenderTarget rt;
1590
1591		rt.addAttachment(
1592			*m_colorImage,												// VkImage						image,
1593			*m_colorImageView,											// VkImageView					imageView,
1594			(VkAttachmentDescriptionFlags)0,							// VkAttachmentDescriptionFlags	flags,
1595			m_colorFormat,												// VkFormat						format,
1596			m_params.numSamples,										// VkSampleCountFlagBits		numSamples,
1597			VK_ATTACHMENT_LOAD_OP_CLEAR,								// VkAttachmentLoadOp			loadOp,
1598			VK_ATTACHMENT_STORE_OP_STORE,								// VkAttachmentStoreOp			storeOp,
1599			VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			stencilLoadOp,
1600			VK_ATTACHMENT_STORE_OP_DONT_CARE,							// VkAttachmentStoreOp			stencilStoreOp,
1601			VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout				initialLayout,
1602			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout				finalLayout,
1603			makeClearValueColor(CLEAR_COLOR_0));						// VkClearValue					clearValue,
1604
1605		rt.addAttachment(
1606			*m_resolveImage,												// VkImage						image
1607			*m_resolveImageView,										// VkImageView					imageView,
1608			(VkAttachmentDescriptionFlags)0,							// VkAttachmentDescriptionFlags	flags,
1609			m_colorFormat,												// VkFormat						format,
1610			VK_SAMPLE_COUNT_1_BIT,										// VkSampleCountFlagBits		numSamples,
1611			VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			loadOp,
1612			VK_ATTACHMENT_STORE_OP_STORE,								// VkAttachmentStoreOp			storeOp,
1613			VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			stencilLoadOp,
1614			VK_ATTACHMENT_STORE_OP_DONT_CARE,							// VkAttachmentStoreOp			stencilStoreOp,
1615			VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout				initialLayout,
1616			VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout				finalLayout,
1617			VkClearValue());											// VkClearValue					clearValue,
1618
1619		if (TEST_OPTION_VARIABLE_SAMPLE_LOCATIONS_BIT & m_params.options)
1620		{
1621			rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1622				1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, &sampleLocationsInfo);
1623		}
1624		else
1625		{
1626			rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1627				1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
1628		}
1629
1630		rt.bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
1631
1632		GraphicsPipelineWrapper pipeline(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
1633
1634		if (useDynamicStateSampleLocations)
1635		{
1636			std::vector<VkDynamicState>	dynamicState;
1637			dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
1638
1639			preparePipelineWrapperSinglePassColor(
1640				pipeline, dynamicState, pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule, viewport, scissor,
1641				m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(), vertexInputConfig, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, useFragmentShadingRate);
1642		}
1643		else
1644		{
1645			preparePipelineWrapperSinglePassColor(
1646				pipeline, std::vector<VkDynamicState>(), pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule, viewport, scissor,
1647				m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo, vertexInputConfig, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, useFragmentShadingRate);
1648		}
1649
1650		const Unique<VkCommandPool>		cmdPool		(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
1651		const Unique<VkCommandBuffer>	cmdBuffer	(makeCommandBuffer(vk, device, *cmdPool));
1652
1653		beginCommandBuffer(vk, *cmdBuffer);
1654
1655		rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
1656
1657		vk.cmdBindVertexBuffers(*cmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(), /*offsets*/ &ZERO);
1658		pipeline.bind(*cmdBuffer);
1659
1660		if (useDynamicStateSampleLocations)
1661			vk.cmdSetSampleLocationsEXT(*cmdBuffer, &sampleLocationsInfo);
1662
1663		if (m_descriptorSet)
1664			vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
1665
1666		vk.cmdDraw(*cmdBuffer, m_numVertices, 1u, 0u, 0u);
1667		rt.endRenderPass(vk, *cmdBuffer);
1668
1669		recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
1670
1671		endCommandBuffer(vk, *cmdBuffer);
1672		submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
1673
1674		invalidateAlloc(vk, device, *m_colorBufferAlloc);
1675	}
1676
1677	void createSampleDataBufferAndDescriptors (const VkDeviceSize bufferSize)
1678	{
1679		// Make sure the old descriptor set is destroyed before we destroy its pool
1680		m_descriptorSet	= Move<VkDescriptorSet>();
1681
1682		const DeviceInterface&	vk			= m_context.getDeviceInterface();
1683		const VkDevice			device		= m_context.getDevice();
1684		Allocator&				allocator	= m_context.getDefaultAllocator();
1685
1686		m_sampleDataBuffer		= makeBuffer(vk, device, bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1687		m_sampleDataBufferAlloc	= bindBuffer(vk, device, allocator, *m_sampleDataBuffer, MemoryRequirement::HostVisible);
1688
1689		m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1690			.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
1691			.build(vk, device);
1692
1693		m_descriptorPool = DescriptorPoolBuilder()
1694			.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1695			.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1696
1697		m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
1698
1699		const VkDescriptorBufferInfo bufferDescriptorInfo = makeDescriptorBufferInfo(*m_sampleDataBuffer, 0ull, bufferSize);
1700		DescriptorSetUpdateBuilder()
1701			.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
1702			.update(vk, device);
1703
1704		SampleDataSSBO::renderSize		(m_sampleDataBufferAlloc->getHostPtr()) = m_renderSize;
1705		SampleDataSSBO::gridSize		(m_sampleDataBufferAlloc->getHostPtr()) = m_pixelGrid->size();
1706		SampleDataSSBO::samplesPerPixel	(m_sampleDataBufferAlloc->getHostPtr()) = m_pixelGrid->samplesPerPixel();
1707
1708		flushAlloc(vk, device, *m_sampleDataBufferAlloc);
1709	}
1710
1711	template<typename Vertex>
1712	void createVertexBuffer (const std::vector<Vertex>& vertices)
1713	{
1714		const DeviceInterface&	vk					= m_context.getDeviceInterface();
1715		const VkDevice			device				= m_context.getDevice();
1716		Allocator&				allocator			= m_context.getDefaultAllocator();
1717		const VkDeviceSize		vertexBufferSize	= static_cast<VkDeviceSize>(vertices.size() * sizeof(vertices[0]));
1718
1719		m_numVertices		= static_cast<deUint32>(vertices.size());
1720		m_vertexBuffer		= makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1721		m_vertexBufferAlloc	= bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
1722
1723		deMemcpy(m_vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices), static_cast<std::size_t>(vertexBufferSize));
1724		flushAlloc(vk, device, *m_vertexBufferAlloc);
1725	}
1726
1727	const TestParams									m_params;
1728	const VkPhysicalDeviceSampleLocationsPropertiesEXT	m_sampleLocationsProperties;
1729	const VkFormat										m_colorFormat;
1730	UVec2												m_renderSize;
1731	MovePtr<MultisamplePixelGrid>						m_pixelGrid;
1732	deUint32											m_numVertices;
1733	Move<VkBuffer>										m_vertexBuffer;
1734	MovePtr<Allocation>									m_vertexBufferAlloc;
1735	Move<VkImage>										m_colorImage;
1736	Move<VkImageView>									m_colorImageView;
1737	MovePtr<Allocation>									m_colorImageAlloc;
1738	Move<VkImage>										m_resolveImage;
1739	Move<VkImageView>									m_resolveImageView;
1740	MovePtr<Allocation>									m_resolveImageAlloc;
1741	Move<VkBuffer>										m_colorBuffer;
1742	MovePtr<Allocation>									m_colorBufferAlloc;
1743	Move<VkBuffer>										m_sampleDataBuffer;
1744	MovePtr<Allocation>									m_sampleDataBufferAlloc;
1745	Move<VkDescriptorSetLayout>							m_descriptorSetLayout;
1746	Move<VkDescriptorPool>								m_descriptorPool;
1747	Move<VkDescriptorSet>								m_descriptorSet;
1748
1749private:
1750	deUint32											m_currentGridNdx;
1751	std::vector<UVec2>									m_gridSizes;
1752};
1753
1754//! Check that each custom sample has the expected position
1755class VerifyLocationTest : public TestBase
1756{
1757public:
1758	VerifyLocationTest (Context& context, const TestParams params) : TestBase(context, params) {}
1759
1760	bool testPixelGrid (void)
1761	{
1762		// Create vertices
1763		{
1764			// For each sample location (in the whole framebuffer), create a sub-pixel triangle that contains it.
1765			// NDC viewport size is 2.0 in X and Y and NDC pixel width/height depends on the framebuffer resolution.
1766			const Vec2			pixelSize	= Vec2(2.0f) / m_renderSize.cast<float>();
1767			const Vec2			offset		= pixelSize / UVec2(1u << m_sampleLocationsProperties.sampleLocationSubPixelBits).cast<float>();
1768			std::vector<Vec4>	vertices;
1769
1770			// Surround with a roughly centered triangle
1771			const float y1 = 0.5f  * offset.y();
1772			const float y2 = 0.35f * offset.y();
1773			const float x1 = 0.5f  * offset.x();
1774
1775			const std::vector<Vec2>	locations = genFramebufferSampleLocations(*m_pixelGrid, m_pixelGrid->size(), m_renderSize);
1776			for (std::vector<Vec2>::const_iterator iter = locations.begin(); iter != locations.end(); ++iter)
1777			{
1778				vertices.push_back(Vec4(iter->x(),      iter->y() - y1, 0.0f, 1.0f));
1779				vertices.push_back(Vec4(iter->x() - x1, iter->y() + y2, 0.0f, 1.0f));
1780				vertices.push_back(Vec4(iter->x() + x1, iter->y() + y2, 0.0f, 1.0f));
1781			}
1782
1783			createVertexBuffer(vertices);
1784		}
1785
1786		createSampleDataBufferAndDescriptors(SampleDataSSBO::STATIC_SIZE);	// no per-sample data used
1787
1788		drawSinglePass(VERTEX_INPUT_VEC4);	// sample locations are taken from the pixel grid
1789
1790		// Verify
1791
1792		const tcu::ConstPixelBufferAccess image (tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1), m_colorBufferAlloc->getHostPtr()));
1793
1794		return compareGreenImage(m_context.getTestContext().getLog(), "resolve0", "Resolved test image", image);
1795	}
1796};
1797
1798//! Verify that vertex attributes are correctly interpolated at each custom sample location
1799class VerifyInterpolationTest : public TestBase
1800{
1801public:
1802	VerifyInterpolationTest (Context& context, const TestParams params) : TestBase(context, params)	{}
1803
1804	bool testPixelGrid (void)
1805	{
1806		createVertexBuffer(genVerticesFullQuad());
1807
1808		// Create sample data SSBO
1809		{
1810			const deUint32		numSamples		= m_pixelGrid->samplesPerPixel();
1811			const deUint32		numDataEntries	= numSamples * m_renderSize.x() * m_renderSize.y();
1812			const VkDeviceSize  bufferSize		= SampleDataSSBO::STATIC_SIZE + sizeof(Vec2) * numDataEntries;
1813
1814			createSampleDataBufferAndDescriptors(bufferSize);
1815
1816			Vec2* const				pSampleData	= SampleDataSSBO::sampleData<Vec2>(m_sampleDataBufferAlloc->getHostPtr());
1817			const std::vector<Vec2>	locations	= genFramebufferSampleLocations(*m_pixelGrid, m_pixelGrid->size(), m_renderSize);
1818
1819			// Fill SSBO with interpolated values (here: from -1.0 to 1.0 across the render area in both x and y)
1820			DE_ASSERT(locations.size() == numDataEntries);
1821			std::copy(locations.begin(), locations.end(), pSampleData);
1822
1823			flushAlloc(m_context.getDeviceInterface(), m_context.getDevice(), *m_sampleDataBufferAlloc);
1824		}
1825
1826		drawSinglePass(VERTEX_INPUT_VEC4_VEC4);	// sample locations are taken from the pixel grid
1827
1828		// Verify
1829
1830		const tcu::ConstPixelBufferAccess image (tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1), m_colorBufferAlloc->getHostPtr()));
1831
1832		return compareGreenImage(m_context.getTestContext().getLog(), "resolve0", "Resolved test image", image);
1833	}
1834};
1835
1836template<typename Test, typename ProgramsFunc>
1837void addCases (tcu::TestCaseGroup* group, const VkSampleCountFlagBits numSamples, PipelineConstructionType pipelineConstructionType, bool useFragmentShadingRate, const ProgramsFunc initPrograms)
1838{
1839	TestParams params;
1840	deMemset(&params, 0, sizeof(params));
1841
1842	params.pipelineConstructionType	= pipelineConstructionType;
1843	params.numSamples				= numSamples;
1844
1845	struct TestOptions
1846	{
1847		std::string		testSuffix;
1848		TestOptionFlags	testFlags;
1849
1850	};
1851
1852	TestOptions testOpts[]	=
1853	{
1854		{ "",				useFragmentShadingRate ? (TestOptionFlags)TEST_OPTION_FRAGMENT_SHADING_RATE_BIT : (TestOptionFlags)0 | (TestOptionFlags)TEST_OPTION_VARIABLE_SAMPLE_LOCATIONS_BIT },
1855		{ "_invariable",	useFragmentShadingRate ? (TestOptionFlags)TEST_OPTION_FRAGMENT_SHADING_RATE_BIT : (TestOptionFlags)0 }
1856	};
1857
1858	for (const auto &options : testOpts)
1859	{
1860		params.options	= options.testFlags;
1861
1862		addInstanceTestCaseWithPrograms<Test>(group, (getString(numSamples) + options.testSuffix).c_str(), checkSupportVerifyTests, initPrograms, params);
1863
1864		params.options	|= (TestOptionFlags)TEST_OPTION_DYNAMIC_STATE_BIT;
1865		addInstanceTestCaseWithPrograms<Test>(group, (getString(numSamples) + "_dynamic" + options.testSuffix).c_str(), checkSupportVerifyTests, initPrograms, params);
1866
1867		params.options	|= (TestOptionFlags)TEST_OPTION_CLOSELY_PACKED_BIT;
1868		addInstanceTestCaseWithPrograms<Test>(group, (getString(numSamples) + "_packed" + options.testSuffix).c_str(), checkSupportVerifyTests, initPrograms, params);
1869	}
1870}
1871
1872} // VerifySamples
1873
1874// Draw tests with at least two "passes" where sample locations may change.
1875// Test case is based on a combination of parameters defined below. Not all combinations are compatible.
1876namespace Draw
1877{
1878
1879//! Options common to all test cases
1880enum TestOptionFlagBits
1881{
1882	TEST_OPTION_SAME_PATTERN_BIT				= 1u << 0,	//!< Use the same sample pattern for all operations
1883	TEST_OPTION_DYNAMIC_STATE_BIT				= 1u << 1,	//!< Use dynamic pipeline state to pass in sample locations
1884	TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT	= 1u << 2,	//!< Put drawing commands in a secondary buffer, including sample locations change (if dynamic)
1885	TEST_OPTION_GENERAL_LAYOUT_BIT				= 1u << 3,	//!< Transition the image to general layout at some point in rendering
1886	TEST_OPTION_WAIT_EVENTS_BIT					= 1u << 4,	//!< Use image memory barriers with vkCmdWaitEvents rather than vkCmdPipelineBarrier
1887	TEST_OPTION_FRAGMENT_SHADING_RATE_BIT		= 1u << 5,	//!< Use VK_KHR_fragment_shading_rate
1888};
1889typedef deUint32 TestOptionFlags;
1890
1891//! Determines where draws/clears with custom samples occur in the test
1892enum TestDrawIn
1893{
1894	TEST_DRAW_IN_RENDER_PASSES = 0u,	//!< Each operation in a separate render pass
1895	TEST_DRAW_IN_SUBPASSES,				//!< Each operation in a separate subpass of the same render pass
1896	TEST_DRAW_IN_SAME_SUBPASS,			//!< Each operation in the same subpass
1897};
1898
1899//! How a clear before the second pass will be done
1900enum TestClears
1901{
1902	TEST_CLEARS_NO_CLEAR = 0u,				//!< Don't clear
1903	TEST_CLEARS_LOAD_OP_CLEAR,				//!< Render pass attachment load clear
1904	TEST_CLEARS_CMD_CLEAR_ATTACHMENTS,		//!< vkCmdClearAttachments within a subpass
1905	TEST_CLEARS_CMD_CLEAR_IMAGE,			//!< vkCmdClear{Color|DepthStencil}Image outside a render pass
1906};
1907
1908//! What type of image will be verified with custom samples
1909enum TestImageAspect
1910{
1911	TEST_IMAGE_ASPECT_COLOR = 0u,			//!< Color image
1912	TEST_IMAGE_ASPECT_DEPTH,				//!< Depth aspect of an image (can be mixed format)
1913	TEST_IMAGE_ASPECT_STENCIL,				//!< Stencil aspect of an image (can be mixed format)
1914};
1915
1916struct TestParams
1917{
1918	PipelineConstructionType	pipelineConstructionType;
1919	VkSampleCountFlagBits		numSamples;
1920	TestOptionFlags				options;
1921	TestDrawIn					drawIn;
1922	TestClears					clears;
1923	TestImageAspect				imageAspect;
1924};
1925
1926void checkSupportDrawTests (Context& context, const TestParams params)
1927{
1928	checkSupportSampleLocations(context);
1929
1930	if ((context.getDeviceProperties().limits.framebufferColorSampleCounts & params.numSamples) == 0u)
1931		TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported");
1932
1933	if ((getSampleLocationsPropertiesEXT(context).sampleLocationSampleCounts & params.numSamples) == 0u)
1934		TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: sample count not supported");
1935
1936	// Are we allowed to modify the sample pattern within the same subpass?
1937	if (params.drawIn == TEST_DRAW_IN_SAME_SUBPASS && ((params.options & TEST_OPTION_SAME_PATTERN_BIT) == 0) && !getSampleLocationsPropertiesEXT(context).variableSampleLocations)
1938		TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: variableSampleLocations not supported");
1939
1940	if (TEST_OPTION_FRAGMENT_SHADING_RATE_BIT & params.options)
1941		checkFragmentShadingRateRequirements(context, params.numSamples);
1942
1943	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), params.pipelineConstructionType);
1944
1945#ifndef CTS_USES_VULKANSC
1946	if (TEST_OPTION_WAIT_EVENTS_BIT & params.options &&
1947		context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && !context.getPortabilitySubsetFeatures().events)
1948	{
1949		TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Events are not supported by this implementation");
1950	}
1951#endif // CTS_USES_VULKANSC
1952}
1953
1954const char* getString (const TestImageAspect aspect)
1955{
1956	switch (aspect)
1957	{
1958		case TEST_IMAGE_ASPECT_COLOR:	return "color";
1959		case TEST_IMAGE_ASPECT_DEPTH:	return "depth";
1960		case TEST_IMAGE_ASPECT_STENCIL:	return "stencil";
1961	}
1962	DE_ASSERT(0);
1963	return DE_NULL;
1964}
1965
1966const char* getString (const TestDrawIn drawIn)
1967{
1968	switch (drawIn)
1969	{
1970		case TEST_DRAW_IN_RENDER_PASSES:	return "separate_renderpass";
1971		case TEST_DRAW_IN_SUBPASSES:		return "separate_subpass";
1972		case TEST_DRAW_IN_SAME_SUBPASS:		return "same_subpass";
1973	}
1974	DE_ASSERT(0);
1975	return DE_NULL;
1976}
1977
1978const char* getString (const TestClears clears)
1979{
1980	switch (clears)
1981	{
1982		case TEST_CLEARS_NO_CLEAR:				return "no_clear";
1983		case TEST_CLEARS_LOAD_OP_CLEAR:			return "load_op_clear";
1984		case TEST_CLEARS_CMD_CLEAR_ATTACHMENTS:	return "clear_attachments";
1985		case TEST_CLEARS_CMD_CLEAR_IMAGE:		return "clear_image";
1986	}
1987	DE_ASSERT(0);
1988	return DE_NULL;
1989}
1990
1991std::string getTestOptionFlagsString (const deUint32 flags)
1992{
1993	std::ostringstream str;
1994
1995	if ((flags & TEST_OPTION_SAME_PATTERN_BIT) != 0)				str << (str.tellp() > 0 ? "_" : "") << "same_pattern";
1996	if ((flags & TEST_OPTION_DYNAMIC_STATE_BIT) != 0)				str << (str.tellp() > 0 ? "_" : "") << "dynamic";
1997	if ((flags & TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT) != 0)	str << (str.tellp() > 0 ? "_" : "") << "secondary_cmd_buf";
1998	if ((flags & TEST_OPTION_GENERAL_LAYOUT_BIT) != 0)				str << (str.tellp() > 0 ? "_" : "") << "general_layout";
1999	if ((flags & TEST_OPTION_WAIT_EVENTS_BIT) != 0)					str << (str.tellp() > 0 ? "_" : "") << "event";
2000
2001	return str.str();
2002}
2003
2004void initPrograms (SourceCollections& programCollection, const TestParams)
2005{
2006	// Vertex shader
2007	{
2008		std::ostringstream src;
2009		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
2010			<< "\n"
2011			<< "layout(location = 0) in  vec4 in_position;\n"
2012			<< "layout(location = 1) in  vec4 in_color;\n"
2013			<< "layout(location = 0) out vec4 o_color;\n"
2014			<< "\n"
2015			<< "out gl_PerVertex {\n"
2016			<< "    vec4 gl_Position;\n"
2017			<< "};\n"
2018			<< "\n"
2019			<< "void main(void)\n"
2020			<< "{\n"
2021			<< "    gl_Position = in_position;\n"
2022			<< "    o_color     = in_color;\n"
2023			<< "\n"
2024			// We use instance index to draw the left shape (index = 0) or the right shape (index = 1).
2025			// Vertices are squished and moved to either half of the viewport.
2026			<< "    if (gl_InstanceIndex == 0)\n"
2027			<< "        gl_Position.x = 0.5 * (gl_Position.x - 1.0);\n"
2028			<< "    else if (gl_InstanceIndex == 1)\n"
2029			<< "        gl_Position.x = 0.5 * (gl_Position.x + 1.0);\n"
2030			<< "}\n";
2031
2032		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
2033	}
2034
2035	// Fragment shader
2036	{
2037		std::ostringstream src;
2038		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
2039			<< "\n"
2040			<< "layout(location = 0) in  vec4 in_color;\n"
2041			<< "layout(location = 0) out vec4 o_color;\n"
2042			<< "\n"
2043			<< "void main(void)\n"
2044			<< "{\n"
2045			<< "    o_color = in_color;\n"
2046			<< "}\n";
2047
2048		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
2049	}
2050}
2051
2052//! Draw shapes using changing sample patterns. Add clears and other operations as necessary
2053class DrawTest : public TestInstance
2054{
2055	static const deUint32 NUM_PASSES = 2u;
2056
2057public:
2058	DrawTest (Context& context, const TestParams params)
2059		: TestInstance					(context)
2060		, m_params						(params)
2061		, m_sampleLocationsProperties	(getSampleLocationsPropertiesEXT(context))
2062		, m_renderSize					(64, 32)
2063		, m_numVertices					(0)
2064		, m_colorFormat					(VK_FORMAT_R8G8B8A8_UNORM)
2065		, m_depthStencilFormat			(VK_FORMAT_UNDEFINED)
2066		, m_depthStencilAspect			(0)
2067	{
2068		VkMultisamplePropertiesEXT multisampleProperties =
2069		{
2070			VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT,		// VkStructureType    sType;
2071			DE_NULL,											// void*              pNext;
2072			VkExtent2D(),										// VkExtent2D         maxSampleLocationGridSize;
2073		};
2074
2075		// For this test always use the full pixel grid
2076
2077		m_context.getInstanceInterface().getPhysicalDeviceMultisamplePropertiesEXT(m_context.getPhysicalDevice(), m_params.numSamples, &multisampleProperties);
2078		m_gridSize.x() = multisampleProperties.maxSampleLocationGridSize.width;
2079		m_gridSize.y() = multisampleProperties.maxSampleLocationGridSize.height;
2080	}
2081
2082	tcu::TestStatus iterate (void)
2083	{
2084		// Requirements
2085		if (!(m_gridSize.x() >= 1 && m_gridSize.y() >= 1))
2086			return tcu::TestStatus::fail("maxSampleLocationGridSize is invalid");
2087
2088		// Images
2089		{
2090			const DeviceInterface&	vk					 = m_context.getDeviceInterface();
2091			const VkDevice			device				 = m_context.getDevice();
2092			Allocator&				allocator			 = m_context.getDefaultAllocator();
2093			const VkImageUsageFlags	colorImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2094
2095			m_colorImage		= makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize, m_params.numSamples, colorImageUsageFlags);
2096			m_colorImageAlloc	= bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
2097			m_colorImageView	= makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat,
2098												makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
2099
2100			m_resolveImage		= makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize, VK_SAMPLE_COUNT_1_BIT, colorImageUsageFlags);
2101			m_resolveImageAlloc	= bindImage(vk, device, allocator, *m_resolveImage, MemoryRequirement::Any);
2102			m_resolveImageView	= makeImageView(vk, device, *m_resolveImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat,
2103												makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
2104
2105			const VkDeviceSize	colorBufferSize = m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(m_colorFormat));
2106			m_colorBuffer		= makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
2107			m_colorBufferAlloc	= bindBuffer(vk, device, allocator, *m_colorBuffer, MemoryRequirement::HostVisible);
2108
2109			if (m_params.imageAspect != TEST_IMAGE_ASPECT_COLOR)
2110			{
2111				const VkImageUsageFlags depthStencilImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2112
2113				m_depthStencilFormat	 = findSupportedDepthStencilFormat(m_context, useDepth(), useStencil());
2114				m_depthStencilAspect	 = (useDepth()   ? VK_IMAGE_ASPECT_DEPTH_BIT   : (VkImageAspectFlagBits)0) |
2115										   (useStencil() ? VK_IMAGE_ASPECT_STENCIL_BIT : (VkImageAspectFlagBits)0);
2116				m_depthStencilImage		 = makeImage(vk, device, VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT,
2117													 m_depthStencilFormat, m_renderSize, m_params.numSamples, depthStencilImageUsageFlags);
2118				m_depthStencilImageAlloc = bindImage(vk, device, allocator, *m_depthStencilImage, MemoryRequirement::Any);
2119				m_depthStencilImageView	 = makeImageView(vk, device, *m_depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, m_depthStencilFormat,
2120														 makeImageSubresourceRange(m_depthStencilAspect, 0u, 1u, 0u, 1u));
2121			}
2122		}
2123
2124		// Vertices
2125		{
2126			const DeviceInterface&	vk			= m_context.getDeviceInterface();
2127			const VkDevice			device		= m_context.getDevice();
2128			Allocator&				allocator	= m_context.getDefaultAllocator();
2129
2130			std::vector<PositionColor> vertices;
2131
2132			if (useDepth())
2133			{
2134				append(vertices, genVerticesShapes  (RGBA::black().toVec(), DEPTH_REFERENCE / 2.0f));	// mask above (z = 0.0 is nearest)
2135				append(vertices, genVerticesFullQuad(RGBA::white().toVec(), DEPTH_REFERENCE));			// fill below the mask, using the depth test
2136			}
2137			else if (useStencil())
2138			{
2139				append(vertices, genVerticesShapes  (RGBA::black().toVec(), DEPTH_REFERENCE));			// first mask
2140				append(vertices, genVerticesFullQuad(RGBA::white().toVec(), DEPTH_REFERENCE / 2.0f));	// then fill the whole area, using the stencil test
2141			}
2142			else
2143				vertices = genVerticesShapes();
2144
2145			const VkDeviceSize vertexBufferSize = static_cast<VkDeviceSize>(vertices.size() * sizeof(vertices[0]));
2146
2147			m_numVertices       = static_cast<deUint32>(vertices.size());
2148			m_vertexBuffer      = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
2149			m_vertexBufferAlloc = bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
2150
2151			deMemcpy(m_vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices), static_cast<std::size_t>(vertexBufferSize));
2152			flushAlloc(vk, device, *m_vertexBufferAlloc);
2153		}
2154
2155		// Multisample pixel grids - set up two sample patterns for two draw passes
2156		{
2157			const deUint32 numGrids = (useSameSamplePattern() ? 1u : NUM_PASSES);
2158			m_pixelGrids.reserve(numGrids);
2159
2160			for (deUint32 passNdx = 0u; passNdx < numGrids; ++passNdx)
2161			{
2162				const deUint32 seed = 142u + 75u * passNdx;
2163				m_pixelGrids.push_back(MultisamplePixelGrid(m_gridSize, m_params.numSamples));
2164				fillSampleLocationsRandom(m_pixelGrids.back(), m_sampleLocationsProperties.sampleLocationSubPixelBits, seed);
2165				logPixelGrid (m_context.getTestContext().getLog(), m_sampleLocationsProperties, m_pixelGrids.back());
2166			}
2167		}
2168
2169		// Some test cases will not clear the left hand image, so we can use it directly
2170		const bool isClearCase		= (m_params.clears != TEST_CLEARS_NO_CLEAR);
2171		const bool hasLeftSideImage = (!isClearCase ||
2172										(m_params.drawIn != TEST_DRAW_IN_RENDER_PASSES && m_params.clears != TEST_CLEARS_CMD_CLEAR_ATTACHMENTS));
2173
2174		// Render second pass reference image with the first pattern
2175		tcu::TextureLevel refImagePattern0;
2176		if (!useSameSamplePattern() && !hasLeftSideImage)
2177		{
2178			const tcu::TextureFormat colorFormat = mapVkFormat(m_colorFormat);
2179
2180			drawPatternChangeReference();
2181
2182			refImagePattern0.setStorage(colorFormat, m_renderSize.x(), m_renderSize.y());
2183			tcu::copy(refImagePattern0.getAccess(), tcu::ConstPixelBufferAccess(colorFormat, tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1), m_colorBufferAlloc->getHostPtr()));
2184		}
2185
2186		// Two-pass rendering
2187
2188		switch (m_params.drawIn)
2189		{
2190			case TEST_DRAW_IN_RENDER_PASSES:	drawRenderPasses();	break;
2191			case TEST_DRAW_IN_SUBPASSES:		drawSubpasses();	break;
2192			case TEST_DRAW_IN_SAME_SUBPASS:		drawSameSubpass();	break;
2193
2194			default:
2195				DE_ASSERT(0);
2196				break;
2197		}
2198
2199		// Log the result
2200
2201		const tcu::ConstPixelBufferAccess image (tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1), m_colorBufferAlloc->getHostPtr()));
2202
2203		m_context.getTestContext().getLog()
2204			<< tcu::TestLog::ImageSet("Result", "Final result")
2205			<< tcu::TestLog::Image("resolve0", "resolve0", image)
2206			<< tcu::TestLog::EndImageSet;
2207
2208		// Verify result
2209		{
2210			DE_ASSERT((m_renderSize.x() % 2) == 0);
2211			DE_ASSERT((m_renderSize.y() % 2) == 0);
2212
2213			// Count colors in each image half separately, each half may have its own background color
2214			const int  numBackgroundColors		= 1;
2215			const int  numExpectedColorsRight	= numBackgroundColors + static_cast<int>(m_params.numSamples);
2216			const int  numExpectedColorsLeft	= (isClearCase ? numBackgroundColors : numExpectedColorsRight);
2217			const int  numActualColorsLeft		= countUniqueColors(tcu::getSubregion(image, 0,					 0, m_renderSize.x()/2, m_renderSize.y()));
2218			const int  numActualColorsRight		= countUniqueColors(tcu::getSubregion(image, m_renderSize.x()/2, 0, m_renderSize.x()/2, m_renderSize.y()));
2219
2220			if (numActualColorsLeft != numExpectedColorsLeft || numActualColorsRight != numExpectedColorsRight)
2221			{
2222				std::ostringstream msg;
2223				msg << "Expected " << numExpectedColorsLeft << " unique colors, but got " << numActualColorsLeft;
2224
2225				if (numActualColorsLeft != numActualColorsRight)
2226					msg << " and " << numActualColorsRight;
2227
2228				m_context.getTestContext().getLog()
2229					<< tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
2230
2231				return tcu::TestStatus::fail("Resolved image has incorrect pixels");
2232			}
2233
2234			if (hasLeftSideImage)
2235			{
2236				// Compare the left and the right half
2237				const bool match = intThresholdCompare(tcu::getSubregion(image,	0,					0, m_renderSize.x()/2,	m_renderSize.y()),
2238													   tcu::getSubregion(image,	m_renderSize.x()/2, 0, m_renderSize.x()/2,	m_renderSize.y()),
2239													   UVec4(2u));
2240				if (useSameSamplePattern() && !match)
2241					return tcu::TestStatus::fail("Multisample pattern should be identical in both image halves");
2242				else if (!useSameSamplePattern() && match)
2243					return tcu::TestStatus::fail("Multisample pattern doesn't seem to change between left and right image halves");
2244			}
2245			else if (!useSameSamplePattern())
2246			{
2247				// Compare the right half with the previously rendered reference image -- patterns should be different
2248				bool match = intThresholdCompare(tcu::getSubregion(refImagePattern0.getAccess(),	m_renderSize.x()/2, 0, m_renderSize.x()/2,	m_renderSize.y()),
2249												 tcu::getSubregion(image,							m_renderSize.x()/2, 0, m_renderSize.x()/2,	m_renderSize.y()),
2250												 UVec4(2u));
2251
2252				if (match)
2253					return tcu::TestStatus::fail("Multisample pattern doesn't seem to change between passes");
2254			}
2255		}
2256
2257		return tcu::TestStatus::pass("Pass");
2258	}
2259
2260protected:
2261	bool useDepth				(void) const { return m_params.imageAspect == TEST_IMAGE_ASPECT_DEPTH; }
2262	bool useStencil				(void) const { return m_params.imageAspect == TEST_IMAGE_ASPECT_STENCIL; }
2263	bool useSameSamplePattern	(void) const { return (m_params.options & TEST_OPTION_SAME_PATTERN_BIT) != 0u; }
2264	bool useDynamicState		(void) const { return (m_params.options & TEST_OPTION_DYNAMIC_STATE_BIT) != 0u; }
2265	bool useSecondaryCmdBuffer	(void) const { return (m_params.options & TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT) != 0u; }
2266	bool useGeneralLayout		(void) const { return (m_params.options & TEST_OPTION_GENERAL_LAYOUT_BIT) != 0u; }
2267	bool useWaitEvents			(void) const { return (m_params.options & TEST_OPTION_WAIT_EVENTS_BIT) != 0u; }
2268	bool useFragmentShadingRate	(void) const { return (m_params.options & TEST_OPTION_FRAGMENT_SHADING_RATE_BIT) != 0u; }
2269
2270	//! Draw the second pass image, but with sample pattern from the first pass -- used to verify that the pattern is different
2271	void drawPatternChangeReference (void)
2272	{
2273		const InstanceInterface&		vki					= m_context.getInstanceInterface();
2274		const DeviceInterface&			vk					= m_context.getDeviceInterface();
2275		const VkPhysicalDevice			physicalDevice		= m_context.getPhysicalDevice();
2276		const VkDevice					device				= m_context.getDevice();
2277		const VkViewport				viewport			= makeViewport(m_renderSize);
2278		const VkRect2D					renderArea			= makeRect2D(m_renderSize);
2279		const VkRect2D					scissor				= makeRect2D(m_renderSize);
2280		const ShaderWrapper				vertexModule		(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2281		const ShaderWrapper				fragmentModule		(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2282		const PipelineLayoutWrapper		pipelineLayout		(m_params.pipelineConstructionType, vk, device);
2283		const VkSampleLocationsInfoEXT	sampleLocationsInfo	= makeSampleLocationsInfo(m_pixelGrids[0]);
2284		const VkClearValue				clearColor0			= (m_params.clears == TEST_CLEARS_NO_CLEAR ? makeClearValueColor(CLEAR_COLOR_0) : makeClearValueColor(CLEAR_COLOR_1));
2285
2286		RenderTarget rt;
2287
2288		rt.addAttachment(
2289			*m_colorImage,												// VkImage						image
2290			*m_colorImageView,											// VkImageView					imageView,
2291			(VkAttachmentDescriptionFlags)0,							// VkAttachmentDescriptionFlags	flags,
2292			m_colorFormat,												// VkFormat						format,
2293			m_params.numSamples,										// VkSampleCountFlagBits		numSamples,
2294			VK_ATTACHMENT_LOAD_OP_CLEAR,								// VkAttachmentLoadOp			loadOp,
2295			VK_ATTACHMENT_STORE_OP_STORE,								// VkAttachmentStoreOp			storeOp,
2296			VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			stencilLoadOp,
2297			VK_ATTACHMENT_STORE_OP_DONT_CARE,							// VkAttachmentStoreOp			stencilStoreOp,
2298			VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout				initialLayout,
2299			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout				finalLayout,
2300			clearColor0);												// VkClearValue					clearValue,
2301
2302		rt.addAttachment(
2303			*m_resolveImage,											// VkImage						image
2304			*m_resolveImageView,										// VkImageView					imageView,
2305			(VkAttachmentDescriptionFlags)0,							// VkAttachmentDescriptionFlags	flags,
2306			m_colorFormat,												// VkFormat						format,
2307			VK_SAMPLE_COUNT_1_BIT,										// VkSampleCountFlagBits		numSamples,
2308			VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			loadOp,
2309			VK_ATTACHMENT_STORE_OP_STORE,								// VkAttachmentStoreOp			storeOp,
2310			VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			stencilLoadOp,
2311			VK_ATTACHMENT_STORE_OP_DONT_CARE,							// VkAttachmentStoreOp			stencilStoreOp,
2312			VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout				initialLayout,
2313			VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout				finalLayout,
2314			VkClearValue());											// VkClearValue					clearValue,
2315
2316		rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2317												1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2318
2319		if (useDepth() || useStencil())
2320		{
2321			rt.addAttachment(
2322				*m_depthStencilImage,											// VkImage						image
2323				*m_depthStencilImageView,										// VkImageView					imageView,
2324				(VkAttachmentDescriptionFlags)0,								// VkAttachmentDescriptionFlags	flags,
2325				m_depthStencilFormat,											// VkFormat						format,
2326				m_params.numSamples,											// VkSampleCountFlagBits		numSamples,
2327				VK_ATTACHMENT_LOAD_OP_CLEAR,									// VkAttachmentLoadOp			loadOp,
2328				VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp			storeOp,
2329				VK_ATTACHMENT_LOAD_OP_CLEAR,									// VkAttachmentLoadOp			stencilLoadOp,
2330				VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp			stencilStoreOp,
2331				VK_IMAGE_LAYOUT_UNDEFINED,										// VkImageLayout				initialLayout,
2332				VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,				// VkImageLayout				finalLayout,
2333				makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE),		// VkClearValue					clearValue,
2334				&sampleLocationsInfo);											// VkSampleLocationsInfoEXT*	pInitialSampleLocations
2335
2336			rt.addSubpassDepthStencilAttachment(2u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &sampleLocationsInfo);
2337		}
2338
2339		rt.bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
2340
2341		GraphicsPipelineWrapper pipeline(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
2342		preparePipelineWrapper(pipeline, std::vector<VkDynamicState>(), pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
2343				/*subpass index*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo,
2344				useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2345
2346		const Unique<VkCommandPool>		cmdPool				(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2347		const Unique<VkCommandBuffer>	cmdBuffer			(makeCommandBuffer(vk, device, *cmdPool));
2348		Move<VkCommandBuffer>			secondaryCmdBuffer;
2349		VkCommandBuffer					currentCmdBuffer	= *cmdBuffer;
2350
2351		beginCommandBuffer(vk, currentCmdBuffer);
2352		rt.recordBeginRenderPass(vk, currentCmdBuffer, renderArea, (useSecondaryCmdBuffer() ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE));
2353
2354		// For maximum consistency also use a secondary command buffer, if the two-pass path uses it
2355		if (useSecondaryCmdBuffer())
2356		{
2357			secondaryCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2358			currentCmdBuffer = *secondaryCmdBuffer;
2359
2360			beginSecondaryCommandBuffer(vk, currentCmdBuffer, rt.getRenderPassWrapper(), /*subpass*/ 0u, m_params.numSamples, m_params.pipelineConstructionType);
2361		}
2362
2363		vk.cmdBindVertexBuffers(currentCmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(), /*offsets*/ &ZERO);
2364		pipeline.bind(currentCmdBuffer);
2365
2366		// Draw the right shape only
2367		vk.cmdDraw(currentCmdBuffer, m_numVertices, /*instance count*/ 1u, /*first vertex*/ 0u, /*first instance*/ 1u);
2368
2369		if (useSecondaryCmdBuffer())
2370		{
2371			endCommandBuffer(vk, currentCmdBuffer);
2372			currentCmdBuffer = *cmdBuffer;
2373
2374			vk.cmdExecuteCommands(currentCmdBuffer, 1u, &secondaryCmdBuffer.get());
2375		}
2376
2377		rt.endRenderPass(vk, *cmdBuffer);
2378
2379		recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
2380
2381		endCommandBuffer(vk, *cmdBuffer);
2382		submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
2383
2384		invalidateAlloc(vk, device, *m_colorBufferAlloc);
2385	}
2386
2387	//! Draw two shapes with distinct sample patterns, each in its own render pass
2388	void drawRenderPasses (void)
2389	{
2390		const InstanceInterface&		vki					= m_context.getInstanceInterface();
2391		const DeviceInterface&			vk					= m_context.getDeviceInterface();
2392		const VkPhysicalDevice			physicalDevice		= m_context.getPhysicalDevice();
2393		const VkDevice					device				= m_context.getDevice();
2394		const VkViewport				viewport			= makeViewport(m_renderSize);
2395		const VkRect2D					renderArea			= makeRect2D(m_renderSize);
2396		const VkRect2D					scissor				= makeRect2D(m_renderSize);
2397		const ShaderWrapper				vertexModule		(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2398		const ShaderWrapper				fragmentModule		(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2399		const PipelineLayoutWrapper		pipelineLayout		(m_params.pipelineConstructionType, vk, device);
2400		const VkClearValue				clearColor0			= makeClearValueColor(CLEAR_COLOR_0);
2401		const VkClearValue				clearColor1			= makeClearValueColor(CLEAR_COLOR_1);
2402		const VkClearValue				clearDepthStencil0	= makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE);
2403		const VkSampleLocationsInfoEXT	sampleLocationsInfo	[NUM_PASSES] =
2404		{
2405			makeSampleLocationsInfo(m_pixelGrids[0]),
2406			makeSampleLocationsInfo(m_pixelGrids[useSameSamplePattern() ? 0 : 1]),
2407		};
2408		const Unique<VkCommandPool>		cmdPool				(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2409		Move<VkCommandBuffer>			cmdBuffer			[NUM_PASSES] =
2410		{
2411			makeCommandBuffer(vk, device, *cmdPool),
2412			makeCommandBuffer(vk, device, *cmdPool),
2413		};
2414		Move<VkCommandBuffer>					secondaryCmdBuffer	[NUM_PASSES];
2415		RenderTarget							rt					[NUM_PASSES];
2416		std::vector<GraphicsPipelineWrapper>	pipelines;
2417		Move<VkEvent>							event				[2];	/*color and depth/stencil*/
2418
2419		// Layouts expected by the second render pass
2420		const VkImageLayout	colorLayout1		= useGeneralLayout() && !(useDepth() || useStencil()) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2421		const VkImageLayout	depthStencilLayout1	= useGeneralLayout() && (useDepth() || useStencil())  ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2422
2423		// First render pass - no resolves
2424		{
2425			rt[0].addAttachment(
2426				*m_colorImage,												// VkImage						image
2427				*m_colorImageView,											// VkImageView					imageView,
2428				(VkAttachmentDescriptionFlags)0,							// VkAttachmentDescriptionFlags	flags,
2429				m_colorFormat,												// VkFormat						format,
2430				m_params.numSamples,										// VkSampleCountFlagBits		numSamples,
2431				VK_ATTACHMENT_LOAD_OP_CLEAR,								// VkAttachmentLoadOp			loadOp,
2432				VK_ATTACHMENT_STORE_OP_STORE,								// VkAttachmentStoreOp			storeOp,
2433				VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			stencilLoadOp,
2434				VK_ATTACHMENT_STORE_OP_DONT_CARE,							// VkAttachmentStoreOp			stencilStoreOp,
2435				VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout				initialLayout,
2436				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout				finalLayout,
2437				clearColor0);												// VkClearValue					clearValue,
2438
2439			rt[0].addSubpassColorAttachment(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2440
2441			if (useDepth() || useStencil())
2442			{
2443				rt[0].addAttachment(
2444					*m_depthStencilImage,											// VkImage						image
2445					*m_depthStencilImageView,										// VkImageView					imageView,
2446					(VkAttachmentDescriptionFlags)0,								// VkAttachmentDescriptionFlags	flags,
2447					m_depthStencilFormat,											// VkFormat						format,
2448					m_params.numSamples,											// VkSampleCountFlagBits		numSamples,
2449					VK_ATTACHMENT_LOAD_OP_CLEAR,									// VkAttachmentLoadOp			loadOp,
2450					VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp			storeOp,
2451					VK_ATTACHMENT_LOAD_OP_CLEAR,									// VkAttachmentLoadOp			stencilLoadOp,
2452					VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp			stencilStoreOp,
2453					VK_IMAGE_LAYOUT_UNDEFINED,										// VkImageLayout				initialLayout,
2454					VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,				// VkImageLayout				finalLayout,
2455					clearDepthStencil0,												// VkClearValue					clearValue,
2456					&sampleLocationsInfo[0]);										// VkSampleLocationsInfoEXT*	pInitialSampleLocations
2457
2458				rt[0].addSubpassDepthStencilAttachment(1u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &sampleLocationsInfo[0]);
2459			}
2460
2461			rt[0].bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
2462		}
2463
2464		// Second render pass
2465		{
2466			const VkAttachmentLoadOp loadOp	= (m_params.clears == TEST_CLEARS_LOAD_OP_CLEAR ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD);
2467
2468			rt[1].addAttachment(
2469				*m_colorImage,												// VkImage						image
2470				*m_colorImageView,											// VkImageView					imageView,
2471				(VkAttachmentDescriptionFlags)0,							// VkAttachmentDescriptionFlags	flags,
2472				m_colorFormat,												// VkFormat						format,
2473				m_params.numSamples,										// VkSampleCountFlagBits		numSamples,
2474				loadOp,														// VkAttachmentLoadOp			loadOp,
2475				VK_ATTACHMENT_STORE_OP_STORE,								// VkAttachmentStoreOp			storeOp,
2476				VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			stencilLoadOp,
2477				VK_ATTACHMENT_STORE_OP_DONT_CARE,							// VkAttachmentStoreOp			stencilStoreOp,
2478				colorLayout1,												// VkImageLayout				initialLayout,
2479				colorLayout1,												// VkImageLayout				finalLayout,
2480				clearColor1);												// VkClearValue					clearValue,
2481
2482			rt[1].addAttachment(
2483				*m_resolveImage,											// VkImage						image
2484				*m_resolveImageView,										// VkImageView					imageView,
2485				(VkAttachmentDescriptionFlags)0,							// VkAttachmentDescriptionFlags	flags,
2486				m_colorFormat,												// VkFormat						format,
2487				VK_SAMPLE_COUNT_1_BIT,										// VkSampleCountFlagBits		numSamples,
2488				VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			loadOp,
2489				VK_ATTACHMENT_STORE_OP_STORE,								// VkAttachmentStoreOp			storeOp,
2490				VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			stencilLoadOp,
2491				VK_ATTACHMENT_STORE_OP_DONT_CARE,							// VkAttachmentStoreOp			stencilStoreOp,
2492				VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout				initialLayout,
2493				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout				finalLayout,
2494				VkClearValue());											// VkClearValue					clearValue,
2495
2496			rt[1].addSubpassColorAttachmentWithResolve(0u, colorLayout1,
2497													   1u, colorLayout1);
2498
2499			if (useDepth() || useStencil())
2500			{
2501				rt[1].addAttachment(
2502					*m_depthStencilImage,											// VkImage						image
2503					*m_depthStencilImageView,										// VkImageView					imageView,
2504					(VkAttachmentDescriptionFlags)0,								// VkAttachmentDescriptionFlags	flags,
2505					m_depthStencilFormat,											// VkFormat						format,
2506					m_params.numSamples,											// VkSampleCountFlagBits		numSamples,
2507					loadOp,															// VkAttachmentLoadOp			loadOp,
2508					VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp			storeOp,
2509					loadOp,															// VkAttachmentLoadOp			stencilLoadOp,
2510					VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp			stencilStoreOp,
2511					depthStencilLayout1,											// VkImageLayout				initialLayout,
2512					depthStencilLayout1,											// VkImageLayout				finalLayout,
2513					clearDepthStencil0,												// VkClearValue					clearValue,
2514					&sampleLocationsInfo[1]);										// VkSampleLocationsInfoEXT*	pInitialSampleLocations
2515
2516				rt[1].addSubpassDepthStencilAttachment(2u, depthStencilLayout1, &sampleLocationsInfo[1]);
2517			}
2518
2519			rt[1].bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
2520		}
2521
2522		// Pipelines
2523		pipelines.reserve(NUM_PASSES);
2524		if (useDynamicState())
2525		{
2526			std::vector<VkDynamicState>	dynamicState;
2527			dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
2528
2529			for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2530			{
2531				pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
2532				preparePipelineWrapper(pipelines.back(), dynamicState, pipelineLayout, rt[passNdx].getRenderPass(), vertexModule, fragmentModule,
2533					/*subpass index*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(),
2534					useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2535			}
2536		}
2537		else for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2538		{
2539			pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
2540			preparePipelineWrapper(pipelines.back(), std::vector<VkDynamicState>(), pipelineLayout, rt[passNdx].getRenderPass(), vertexModule, fragmentModule,
2541				/*subpass index*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo[passNdx],
2542				useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2543		}
2544
2545		// Record secondary command buffers
2546
2547		if (useSecondaryCmdBuffer())
2548		{
2549			secondaryCmdBuffer[0] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2550			secondaryCmdBuffer[1] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2551
2552			// First render pass contents
2553			beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[0], rt[0].getRenderPassWrapper(), /*subpass*/ 0u, m_params.numSamples, m_params.pipelineConstructionType);
2554			recordFirstPassContents(*secondaryCmdBuffer[0], pipelines[0], sampleLocationsInfo[0]);
2555			endCommandBuffer(vk, *secondaryCmdBuffer[0]);
2556
2557			// Second render pass contents
2558			beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[1], rt[1].getRenderPassWrapper(), /*subpass*/ 0u, m_params.numSamples, m_params.pipelineConstructionType);
2559			recordSecondPassContents(*secondaryCmdBuffer[1], pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
2560			endCommandBuffer(vk, *secondaryCmdBuffer[1]);
2561		}
2562
2563		// Record primary command buffers
2564
2565		VkCommandBuffer currentCmdBuffer = *cmdBuffer[0];
2566		beginCommandBuffer(vk, currentCmdBuffer);
2567
2568		// First render pass
2569		if (useSecondaryCmdBuffer())
2570		{
2571			rt[0].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2572			vk.cmdExecuteCommands(currentCmdBuffer, 1u, &secondaryCmdBuffer[0].get());
2573			rt[0].endRenderPass(vk, currentCmdBuffer);
2574		}
2575		else
2576		{
2577			rt[0].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
2578			recordFirstPassContents(currentCmdBuffer, pipelines[0], sampleLocationsInfo[0]);
2579			rt[0].endRenderPass(vk, currentCmdBuffer);
2580		}
2581
2582		endCommandBuffer(vk, currentCmdBuffer);
2583
2584		// Record the second primary command buffer
2585		currentCmdBuffer = *cmdBuffer[1];
2586		beginCommandBuffer(vk, currentCmdBuffer);
2587
2588		if (m_params.clears == TEST_CLEARS_CMD_CLEAR_IMAGE)
2589		{
2590			{
2591				const VkImageLayout finalLayout = (useWaitEvents() ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : colorLayout1);
2592
2593				recordImageBarrier(vk, currentCmdBuffer, *m_colorImage,
2594									VK_IMAGE_ASPECT_COLOR_BIT,								// VkImageAspectFlags	aspect,
2595									VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,			// VkPipelineStageFlags srcStageMask,
2596									VK_PIPELINE_STAGE_TRANSFER_BIT,							// VkPipelineStageFlags dstStageMask,
2597									VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,					// VkAccessFlags		srcAccessMask,
2598									VK_ACCESS_TRANSFER_WRITE_BIT,							// VkAccessFlags		dstAccessMask,
2599									VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,				// VkImageLayout		oldLayout,
2600									VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);					// VkImageLayout		newLayout)
2601
2602				const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
2603				vk.cmdClearColorImage(currentCmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor1.color, 1u, &subresourceRange);
2604
2605				recordImageBarrier(vk, currentCmdBuffer, *m_colorImage,
2606						VK_IMAGE_ASPECT_COLOR_BIT,											// VkImageAspectFlags	aspect,
2607						VK_PIPELINE_STAGE_TRANSFER_BIT,										// VkPipelineStageFlags srcStageMask,
2608						VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,						// VkPipelineStageFlags dstStageMask,
2609						VK_ACCESS_TRANSFER_WRITE_BIT,										// VkAccessFlags		srcAccessMask,
2610						(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
2611						 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT),								// VkAccessFlags		dstAccessMask,
2612						VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,								// VkImageLayout		oldLayout,
2613						finalLayout);														// VkImageLayout		newLayout)
2614			}
2615
2616			if (useDepth() || useStencil())
2617			{
2618				const VkImageLayout finalLayout = (useWaitEvents() ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : depthStencilLayout1);
2619
2620				recordImageBarrier(vk, currentCmdBuffer, *m_depthStencilImage,
2621								   getImageAspectFlags(m_depthStencilFormat),			// VkImageAspectFlags	aspect,
2622								   VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,			// VkPipelineStageFlags srcStageMask,
2623								   VK_PIPELINE_STAGE_TRANSFER_BIT,						// VkPipelineStageFlags dstStageMask,
2624								   VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,		// VkAccessFlags		srcAccessMask,
2625								   VK_ACCESS_TRANSFER_WRITE_BIT,						// VkAccessFlags		dstAccessMask,
2626								   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	// VkImageLayout		oldLayout,
2627								   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,				// VkImageLayout		newLayout)
2628								   &sampleLocationsInfo[0]);							// VkSampleLocationsInfoEXT
2629
2630				const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(m_depthStencilAspect, 0u, 1u, 0u, 1u);
2631				vk.cmdClearDepthStencilImage(currentCmdBuffer, *m_depthStencilImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearDepthStencil0.depthStencil, 1u, &subresourceRange);
2632
2633				recordImageBarrier(vk, currentCmdBuffer, *m_depthStencilImage,
2634								   getImageAspectFlags(m_depthStencilFormat),			// VkImageAspectFlags	aspect,
2635								   VK_PIPELINE_STAGE_TRANSFER_BIT,						// VkPipelineStageFlags srcStageMask,
2636								   VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,			// VkPipelineStageFlags dstStageMask,
2637								   VK_ACCESS_TRANSFER_WRITE_BIT,						// VkAccessFlags		srcAccessMask,
2638								   (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
2639									VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT),		// VkAccessFlags		dstAccessMask,
2640								   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,				// VkImageLayout		oldLayout,
2641								   finalLayout,											// VkImageLayout		newLayout)
2642								   &sampleLocationsInfo[0]);							// VkSampleLocationsInfoEXT
2643			}
2644		}
2645		else if (!useWaitEvents())
2646		{
2647			// Barrier between the render passes
2648
2649			recordImageBarrier(vk, currentCmdBuffer, *m_colorImage,
2650							   VK_IMAGE_ASPECT_COLOR_BIT,								// VkImageAspectFlags	aspect,
2651							   VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,			// VkPipelineStageFlags srcStageMask,
2652							   VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,			// VkPipelineStageFlags dstStageMask,
2653							   VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,					// VkAccessFlags		srcAccessMask,
2654							   (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
2655								VK_ACCESS_COLOR_ATTACHMENT_READ_BIT),					// VkAccessFlags		dstAccessMask,
2656							   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,				// VkImageLayout		oldLayout,
2657							   colorLayout1);											// VkImageLayout		newLayout)
2658
2659			if (useDepth() || useStencil())
2660			{
2661				recordImageBarrier(vk, currentCmdBuffer, *m_depthStencilImage,
2662								   getImageAspectFlags(m_depthStencilFormat),			// VkImageAspectFlags	aspect,
2663								   VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,			// VkPipelineStageFlags srcStageMask,
2664								   VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,			// VkPipelineStageFlags dstStageMask,
2665								   VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,		// VkAccessFlags		srcAccessMask,
2666								   (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
2667									VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT),		// VkAccessFlags		dstAccessMask,
2668								   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	// VkImageLayout		oldLayout,
2669								   depthStencilLayout1);								// VkImageLayout		newLayout)
2670			}
2671		}
2672
2673		if (useWaitEvents())
2674		{
2675			// Use events to sync both render passes
2676			event[0] = makeEvent(vk, device);
2677			vk.cmdSetEvent(currentCmdBuffer, *event[0], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2678
2679			recordWaitEventWithImage(vk, currentCmdBuffer, *event[0], *m_colorImage,
2680									 VK_IMAGE_ASPECT_COLOR_BIT,								// VkImageAspectFlags		aspect,
2681									 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,			// VkPipelineStageFlags		srcStageMask,
2682									 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,			// VkPipelineStageFlags		dstStageMask,
2683									 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,					// VkAccessFlags			srcAccessMask,
2684									 (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
2685									  VK_ACCESS_COLOR_ATTACHMENT_READ_BIT),					// VkAccessFlags			dstAccessMask,
2686									 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,				// VkImageLayout			oldLayout,
2687									 colorLayout1);											// VkImageLayout			newLayout,
2688
2689			if (useDepth() || useStencil())
2690			{
2691				event[1] = makeEvent(vk, device);
2692				vk.cmdSetEvent(currentCmdBuffer, *event[1], VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
2693
2694				recordWaitEventWithImage(vk, currentCmdBuffer, *event[1], *m_depthStencilImage,
2695										 getImageAspectFlags(m_depthStencilFormat),			// VkImageAspectFlags		aspect,
2696										 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,			// VkPipelineStageFlags		srcStageMask,
2697										 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,		// VkPipelineStageFlags		dstStageMask,
2698										 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,		// VkAccessFlags			srcAccessMask,
2699										 (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
2700										  VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT),		// VkAccessFlags			dstAccessMask,
2701										 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	// VkImageLayout			oldLayout,
2702										 depthStencilLayout1);								// VkImageLayout			newLayout,
2703			}
2704		}
2705
2706		// Second render pass
2707		if (useSecondaryCmdBuffer())
2708		{
2709			rt[1].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2710			vk.cmdExecuteCommands(currentCmdBuffer, 1u, &secondaryCmdBuffer[1].get());
2711			rt[1].endRenderPass(vk, currentCmdBuffer);
2712		}
2713		else
2714		{
2715			rt[1].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
2716			recordSecondPassContents(currentCmdBuffer, pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
2717			rt[1].endRenderPass(vk, currentCmdBuffer);
2718		}
2719
2720		// Resolve image -> host buffer
2721		recordCopyImageToBuffer(vk, currentCmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
2722
2723		endCommandBuffer(vk, currentCmdBuffer);
2724
2725		// Submit work
2726		{
2727			const Unique<VkFence>	fence	(createFence(vk, device));
2728			const VkCommandBuffer	buffers	[NUM_PASSES] =
2729			{
2730				*cmdBuffer[0],
2731				*cmdBuffer[1],
2732			};
2733
2734			const VkSubmitInfo submitInfo =
2735			{
2736				VK_STRUCTURE_TYPE_SUBMIT_INFO,		// VkStructureType                sType;
2737				DE_NULL,							// const void*                    pNext;
2738				0u,									// uint32_t                       waitSemaphoreCount;
2739				DE_NULL,							// const VkSemaphore*             pWaitSemaphores;
2740				DE_NULL,							// const VkPipelineStageFlags*    pWaitDstStageMask;
2741				DE_LENGTH_OF_ARRAY(buffers),		// uint32_t                       commandBufferCount;
2742				buffers,							// const VkCommandBuffer*         pCommandBuffers;
2743				0u,									// uint32_t                       signalSemaphoreCount;
2744				DE_NULL,							// const VkSemaphore*             pSignalSemaphores;
2745			};
2746			VK_CHECK(vk.queueSubmit(m_context.getUniversalQueue(), 1u, &submitInfo, *fence));
2747			VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), DE_TRUE, ~0ull));
2748		}
2749
2750		invalidateAlloc(vk, device, *m_colorBufferAlloc);
2751	}
2752
2753	void recordFirstPassContents (const VkCommandBuffer				cmdBuffer,
2754								  const GraphicsPipelineWrapper&	pipeline,
2755								  const VkSampleLocationsInfoEXT&	sampleLocationsInfo)
2756	{
2757		const DeviceInterface& vk = m_context.getDeviceInterface();
2758
2759		vk.cmdBindVertexBuffers(cmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(), /*offsets*/ &ZERO);
2760		pipeline.bind(cmdBuffer);
2761
2762		if (useDynamicState())
2763			vk.cmdSetSampleLocationsEXT(cmdBuffer, &sampleLocationsInfo);
2764
2765		if (m_params.clears == TEST_CLEARS_NO_CLEAR)
2766			vk.cmdDraw(cmdBuffer, m_numVertices, /*instance count*/ 1u, /*first vertex*/ 0u, /*first instance*/ 0u);			// left shape only
2767		else
2768			vk.cmdDraw(cmdBuffer, m_numVertices, /*instance count*/ NUM_PASSES, /*first vertex*/ 0u, /*first instance*/ 0u);	// both shapes
2769	}
2770
2771	void recordSecondPassContents (const VkCommandBuffer			cmdBuffer,
2772								   const GraphicsPipelineWrapper&	pipeline,
2773								   const VkSampleLocationsInfoEXT&	sampleLocationsInfo,
2774								   const VkClearValue&				clearColor,
2775								   const VkClearValue&				clearDepthStencil,
2776								   const VkRect2D&					clearRect)
2777	{
2778		const DeviceInterface& vk = m_context.getDeviceInterface();
2779
2780		vk.cmdBindVertexBuffers(cmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(), /*offsets*/ &ZERO);
2781		pipeline.bind(cmdBuffer);
2782
2783		if (m_params.clears == TEST_CLEARS_CMD_CLEAR_ATTACHMENTS)
2784			recordClearAttachments(vk, cmdBuffer, 0u, clearColor, m_depthStencilAspect, clearDepthStencil, clearRect);
2785
2786		if (useDynamicState())
2787			vk.cmdSetSampleLocationsEXT(cmdBuffer, &sampleLocationsInfo);
2788
2789		// Draw the right shape only
2790		vk.cmdDraw(cmdBuffer, m_numVertices, /*instance count*/ 1u, /*first vertex*/ 0u, /*first instance*/ 1u);
2791	}
2792
2793	//! Draw two shapes in two subpasses of the same render pass
2794	void drawSubpasses (void)
2795	{
2796		DE_ASSERT(m_params.clears != TEST_CLEARS_CMD_CLEAR_IMAGE);			// not possible in a render pass
2797		DE_ASSERT(m_params.clears != TEST_CLEARS_LOAD_OP_CLEAR);			// can't specify a load op for a subpass
2798		DE_ASSERT((m_params.options & TEST_OPTION_WAIT_EVENTS_BIT) == 0);	// can't change layouts inside a subpass
2799
2800		const InstanceInterface&		vki					= m_context.getInstanceInterface();
2801		const DeviceInterface&			vk					= m_context.getDeviceInterface();
2802		const VkPhysicalDevice			physicalDevice		= m_context.getPhysicalDevice();
2803		const VkDevice					device				= m_context.getDevice();
2804		const VkViewport				viewport			= makeViewport(m_renderSize);
2805		const VkRect2D					renderArea			= makeRect2D(m_renderSize);
2806		const VkRect2D					scissor				= makeRect2D(m_renderSize);
2807		const ShaderWrapper				vertexModule		(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2808		const ShaderWrapper				fragmentModule		(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2809		const PipelineLayoutWrapper		pipelineLayout		(m_params.pipelineConstructionType, vk, device);
2810		const VkClearValue				clearColor0			= makeClearValueColor(CLEAR_COLOR_0);
2811		const VkClearValue				clearColor1			= makeClearValueColor(CLEAR_COLOR_1);
2812		const VkClearValue				clearDepthStencil0	= makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE);
2813		const VkSampleLocationsInfoEXT	sampleLocationsInfo	[NUM_PASSES] =
2814		{
2815			makeSampleLocationsInfo(m_pixelGrids[0]),
2816			makeSampleLocationsInfo(m_pixelGrids[useSameSamplePattern() ? 0 : 1]),
2817		};
2818		const Unique<VkCommandPool>				cmdPool				(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2819		const Unique<VkCommandBuffer>			cmdBuffer			(makeCommandBuffer(vk, device, *cmdPool));
2820		Move<VkCommandBuffer>					secondaryCmdBuffer	[NUM_PASSES];
2821		RenderTarget							rt;
2822		std::vector<GraphicsPipelineWrapper>	pipelines;
2823		Move<VkEvent>							event;
2824
2825		// Layouts used in the second subpass
2826		const VkImageLayout	colorLayout1		= useGeneralLayout() && !(useDepth() || useStencil()) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2827		const VkImageLayout	depthStencilLayout1	= useGeneralLayout() && (useDepth() || useStencil())  ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2828
2829		// Prepare the render pass
2830		{
2831			rt.addAttachment(
2832				*m_colorImage,												// VkImage						image
2833				*m_colorImageView,											// VkImageView					imageView,
2834				(VkAttachmentDescriptionFlags)0,							// VkAttachmentDescriptionFlags	flags,
2835				m_colorFormat,												// VkFormat						format,
2836				m_params.numSamples,										// VkSampleCountFlagBits		numSamples,
2837				VK_ATTACHMENT_LOAD_OP_CLEAR,								// VkAttachmentLoadOp			loadOp,
2838				VK_ATTACHMENT_STORE_OP_STORE,								// VkAttachmentStoreOp			storeOp,
2839				VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			stencilLoadOp,
2840				VK_ATTACHMENT_STORE_OP_DONT_CARE,							// VkAttachmentStoreOp			stencilStoreOp,
2841				VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout				initialLayout,
2842				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout				finalLayout,
2843				clearColor0);												// VkClearValue					clearValue,
2844
2845			rt.addAttachment(
2846				*m_resolveImage,											// VkImage						image
2847				*m_resolveImageView,										// VkImageView					imageView,
2848				(VkAttachmentDescriptionFlags)0,							// VkAttachmentDescriptionFlags	flags,
2849				m_colorFormat,												// VkFormat						format,
2850				VK_SAMPLE_COUNT_1_BIT,										// VkSampleCountFlagBits		numSamples,
2851				VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			loadOp,
2852				VK_ATTACHMENT_STORE_OP_STORE,								// VkAttachmentStoreOp			storeOp,
2853				VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			stencilLoadOp,
2854				VK_ATTACHMENT_STORE_OP_DONT_CARE,							// VkAttachmentStoreOp			stencilStoreOp,
2855				VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout				initialLayout,
2856				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout				finalLayout,
2857				VkClearValue());											// VkClearValue					clearValue,
2858
2859			// First subpass
2860			rt.addSubpassColorAttachment(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2861
2862			if (useDepth() || useStencil())
2863			{
2864				rt.addAttachment(
2865					*m_depthStencilImage,											// VkImage						image
2866					*m_depthStencilImageView,										// VkImageView					imageView,
2867					(VkAttachmentDescriptionFlags)0,								// VkAttachmentDescriptionFlags	flags,
2868					m_depthStencilFormat,											// VkFormat						format,
2869					m_params.numSamples,											// VkSampleCountFlagBits		numSamples,
2870					VK_ATTACHMENT_LOAD_OP_CLEAR,									// VkAttachmentLoadOp			loadOp,
2871					VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp			storeOp,
2872					VK_ATTACHMENT_LOAD_OP_CLEAR,									// VkAttachmentLoadOp			stencilLoadOp,
2873					VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp			stencilStoreOp,
2874					VK_IMAGE_LAYOUT_UNDEFINED,										// VkImageLayout				initialLayout,
2875					VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,				// VkImageLayout				finalLayout,
2876					clearDepthStencil0,												// VkClearValue					clearValue,
2877					&sampleLocationsInfo[0]);										// VkSampleLocationsInfoEXT*	pInitialSampleLocations
2878
2879				rt.addSubpassDepthStencilAttachment(2u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &sampleLocationsInfo[0]);
2880			}
2881
2882			// Second subpass
2883			rt.nextSubpass();
2884			rt.addSubpassColorAttachmentWithResolve(0u, colorLayout1,
2885													1u, colorLayout1);
2886
2887			if (useDepth() || useStencil())
2888				rt.addSubpassDepthStencilAttachment(2u, depthStencilLayout1, &sampleLocationsInfo[1]);
2889
2890			rt.bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
2891		}
2892
2893		// Pipelines
2894		pipelines.reserve(NUM_PASSES);
2895		if (useDynamicState())
2896		{
2897			std::vector<VkDynamicState>	dynamicState;
2898			dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
2899
2900			for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2901			{
2902				pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
2903				preparePipelineWrapper(pipelines.back(), dynamicState, pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
2904					/*subpass*/ passNdx, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(),
2905					useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2906			}
2907		}
2908		else for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2909		{
2910			pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
2911			preparePipelineWrapper(pipelines.back(), std::vector<VkDynamicState>(), pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
2912				/*subpass*/ passNdx, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo[passNdx],
2913				useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2914		}
2915
2916		// Record secondary command buffers
2917
2918		if (useSecondaryCmdBuffer())
2919		{
2920			secondaryCmdBuffer[0] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2921			secondaryCmdBuffer[1] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2922
2923			// First subpass contents
2924			beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[0], rt.getRenderPassWrapper(), /*subpass*/ 0u, m_params.numSamples, m_params.pipelineConstructionType);
2925			recordFirstPassContents(*secondaryCmdBuffer[0], pipelines[0], sampleLocationsInfo[0]);
2926			endCommandBuffer(vk, *secondaryCmdBuffer[0]);
2927
2928			// Second subpass contents
2929			beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[1], rt.getRenderPassWrapper(), /*subpass*/ 1u, m_params.numSamples, m_params.pipelineConstructionType);
2930			recordSecondPassContents(*secondaryCmdBuffer[1], pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
2931			endCommandBuffer(vk, *secondaryCmdBuffer[1]);
2932		}
2933
2934		// Record primary command buffer
2935
2936		beginCommandBuffer(vk, *cmdBuffer);
2937
2938		if (useSecondaryCmdBuffer())
2939		{
2940			rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2941			vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer[0].get());
2942
2943			rt.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2944			vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer[1].get());
2945		}
2946		else
2947		{
2948			rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
2949			recordFirstPassContents(*cmdBuffer, pipelines[0], sampleLocationsInfo[0]);
2950
2951			rt.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
2952			recordSecondPassContents(*cmdBuffer, pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
2953		}
2954
2955		rt.endRenderPass(vk, *cmdBuffer);
2956
2957		// Resolve image -> host buffer
2958		recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
2959
2960		endCommandBuffer(vk, *cmdBuffer);
2961
2962		submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
2963		invalidateAlloc(vk, device, *m_colorBufferAlloc);
2964	}
2965
2966	//! Draw two shapes within the same subpass of a renderpass
2967	void drawSameSubpass (void)
2968	{
2969		DE_ASSERT(m_params.clears != TEST_CLEARS_CMD_CLEAR_IMAGE);				// not possible in a render pass
2970		DE_ASSERT(m_params.clears != TEST_CLEARS_LOAD_OP_CLEAR);				// can't specify a load op for a subpass
2971		DE_ASSERT((m_params.options & TEST_OPTION_WAIT_EVENTS_BIT) == 0);		// can't change layouts inside a subpass
2972		DE_ASSERT((m_params.options & TEST_OPTION_GENERAL_LAYOUT_BIT) == 0);	// can't change layouts inside a subpass
2973
2974		const InstanceInterface&		vki					= m_context.getInstanceInterface();
2975		const DeviceInterface&			vk					= m_context.getDeviceInterface();
2976		const VkPhysicalDevice			physicalDevice		= m_context.getPhysicalDevice();
2977		const VkDevice					device				= m_context.getDevice();
2978		const VkViewport				viewport			= makeViewport(m_renderSize);
2979		const VkRect2D					renderArea			= makeRect2D(m_renderSize);
2980		const VkRect2D					scissor				= makeRect2D(m_renderSize);
2981		const ShaderWrapper				vertexModule		(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2982		const ShaderWrapper				fragmentModule		(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2983		const PipelineLayoutWrapper		pipelineLayout		(m_params.pipelineConstructionType, vk, device);
2984		const VkClearValue				clearColor0			= makeClearValueColor(CLEAR_COLOR_0);
2985		const VkClearValue				clearColor1			= makeClearValueColor(CLEAR_COLOR_1);
2986		const VkClearValue				clearDepthStencil0	= makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE);
2987		const VkSampleLocationsInfoEXT	sampleLocationsInfo	[NUM_PASSES] =
2988		{
2989			makeSampleLocationsInfo(m_pixelGrids[0]),
2990			makeSampleLocationsInfo(m_pixelGrids[useSameSamplePattern() ? 0 : 1]),
2991		};
2992		const bool								useFragmentShadingRate	(TEST_OPTION_FRAGMENT_SHADING_RATE_BIT & m_params.options);
2993		const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2994		const Unique<VkCommandBuffer>			cmdBuffer				(makeCommandBuffer(vk, device, *cmdPool));
2995		Move<VkCommandBuffer>					secondaryCmdBuffer;
2996		RenderTarget							rt;
2997		std::vector<GraphicsPipelineWrapper>	pipelines;
2998		Move<VkEvent>							event;
2999
3000		// Prepare the render pass
3001		{
3002			rt.addAttachment(
3003				*m_colorImage,												// VkImage						image
3004				*m_colorImageView,											// VkImageView					imageView,
3005				(VkAttachmentDescriptionFlags)0,							// VkAttachmentDescriptionFlags	flags,
3006				m_colorFormat,												// VkFormat						format,
3007				m_params.numSamples,										// VkSampleCountFlagBits		numSamples,
3008				VK_ATTACHMENT_LOAD_OP_CLEAR,								// VkAttachmentLoadOp			loadOp,
3009				VK_ATTACHMENT_STORE_OP_STORE,								// VkAttachmentStoreOp			storeOp,
3010				VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			stencilLoadOp,
3011				VK_ATTACHMENT_STORE_OP_DONT_CARE,							// VkAttachmentStoreOp			stencilStoreOp,
3012				VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout				initialLayout,
3013				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout				finalLayout,
3014				clearColor0);												// VkClearValue					clearValue,
3015
3016			rt.addAttachment(
3017				*m_resolveImage,											// VkImage						image
3018				*m_resolveImageView,										// VkImageView					imageView,
3019				(VkAttachmentDescriptionFlags)0,							// VkAttachmentDescriptionFlags	flags,
3020				m_colorFormat,												// VkFormat						format,
3021				VK_SAMPLE_COUNT_1_BIT,										// VkSampleCountFlagBits		numSamples,
3022				VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			loadOp,
3023				VK_ATTACHMENT_STORE_OP_STORE,								// VkAttachmentStoreOp			storeOp,
3024				VK_ATTACHMENT_LOAD_OP_DONT_CARE,							// VkAttachmentLoadOp			stencilLoadOp,
3025				VK_ATTACHMENT_STORE_OP_DONT_CARE,							// VkAttachmentStoreOp			stencilStoreOp,
3026				VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout				initialLayout,
3027				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout				finalLayout,
3028				VkClearValue());											// VkClearValue					clearValue,
3029
3030			rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
3031													1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
3032
3033			if (useDepth() || useStencil())
3034			{
3035				rt.addAttachment(
3036					*m_depthStencilImage,											// VkImage						image
3037					*m_depthStencilImageView,										// VkImageView					imageView,
3038					(VkAttachmentDescriptionFlags)0,								// VkAttachmentDescriptionFlags	flags,
3039					m_depthStencilFormat,											// VkFormat						format,
3040					m_params.numSamples,											// VkSampleCountFlagBits		numSamples,
3041					VK_ATTACHMENT_LOAD_OP_CLEAR,									// VkAttachmentLoadOp			loadOp,
3042					VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp			storeOp,
3043					VK_ATTACHMENT_LOAD_OP_CLEAR,									// VkAttachmentLoadOp			stencilLoadOp,
3044					VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp			stencilStoreOp,
3045					VK_IMAGE_LAYOUT_UNDEFINED,										// VkImageLayout				initialLayout,
3046					VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,				// VkImageLayout				finalLayout,
3047					clearDepthStencil0,												// VkClearValue					clearValue,
3048					&sampleLocationsInfo[0]);										// VkSampleLocationsInfoEXT*	pInitialSampleLocations
3049
3050				rt.addSubpassDepthStencilAttachment(2u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &sampleLocationsInfo[0]);
3051			}
3052
3053			rt.bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
3054		}
3055
3056		// Pipelines
3057		pipelines.reserve(NUM_PASSES);
3058		if (useDynamicState())
3059		{
3060			std::vector<VkDynamicState>	dynamicState;
3061			dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
3062
3063			for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
3064			{
3065				pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
3066				preparePipelineWrapper(pipelines.back(), dynamicState, pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
3067					/*subpass*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(),
3068					useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate);
3069			}
3070		}
3071		else for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
3072		{
3073			pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
3074			preparePipelineWrapper(pipelines.back(), std::vector<VkDynamicState>(), pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
3075				/*subpass*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo[passNdx],
3076				useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate);
3077		}
3078
3079		// Record secondary command buffers
3080
3081		if (useSecondaryCmdBuffer())
3082		{
3083			secondaryCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
3084
3085			beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer, rt.getRenderPassWrapper(), /*subpass*/ 0u, m_params.numSamples, m_params.pipelineConstructionType);
3086			recordFirstPassContents(*secondaryCmdBuffer, pipelines[0], sampleLocationsInfo[0]);
3087			recordSecondPassContents(*secondaryCmdBuffer, pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
3088			endCommandBuffer(vk, *secondaryCmdBuffer);
3089		}
3090
3091		// Record primary command buffer
3092
3093		beginCommandBuffer(vk, *cmdBuffer);
3094
3095		if (useSecondaryCmdBuffer())
3096		{
3097			rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
3098			vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer.get());
3099		}
3100		else
3101		{
3102			rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
3103			recordFirstPassContents(*cmdBuffer, pipelines[0], sampleLocationsInfo[0]);
3104			recordSecondPassContents(*cmdBuffer, pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
3105		}
3106
3107		rt.endRenderPass(vk, *cmdBuffer);
3108
3109		// Resolve image -> host buffer
3110		recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
3111
3112		endCommandBuffer(vk, *cmdBuffer);
3113
3114		submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
3115		invalidateAlloc(vk, device, *m_colorBufferAlloc);
3116	}
3117
3118	const TestParams									m_params;
3119	const VkPhysicalDeviceSampleLocationsPropertiesEXT	m_sampleLocationsProperties;
3120	const UVec2											m_renderSize;
3121	UVec2												m_gridSize;
3122	std::vector<MultisamplePixelGrid>					m_pixelGrids;
3123	deUint32											m_numVertices;
3124	Move<VkBuffer>										m_vertexBuffer;
3125	MovePtr<Allocation>									m_vertexBufferAlloc;
3126	const VkFormat										m_colorFormat;
3127	Move<VkImage>										m_colorImage;
3128	Move<VkImageView>									m_colorImageView;
3129	MovePtr<Allocation>									m_colorImageAlloc;
3130	VkFormat											m_depthStencilFormat;
3131	VkImageAspectFlags									m_depthStencilAspect;
3132	Move<VkImage>										m_depthStencilImage;
3133	Move<VkImageView>									m_depthStencilImageView;
3134	MovePtr<Allocation>									m_depthStencilImageAlloc;
3135	Move<VkImage>										m_resolveImage;
3136	Move<VkImageView>									m_resolveImageView;
3137	MovePtr<Allocation>									m_resolveImageAlloc;
3138	Move<VkBuffer>										m_colorBuffer;
3139	MovePtr<Allocation>									m_colorBufferAlloc;
3140};
3141
3142} // Draw
3143
3144void createTestsInGroup (tcu::TestCaseGroup* rootGroup, PipelineConstructionType pipelineConstructionType, bool useFragmentShadingRate)
3145{
3146	// Queries
3147	if (!useFragmentShadingRate && (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC))
3148	{
3149		MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(rootGroup->getTestContext(), "query"));
3150
3151		addFunctionCase(group.get(), "sample_locations_properties", checkSupportSampleLocations, testQuerySampleLocationProperties);
3152		addFunctionCase(group.get(), "multisample_properties",		checkSupportSampleLocations, testQueryMultisampleProperties);
3153
3154		rootGroup->addChild(group.release());
3155	}
3156
3157	const VkSampleCountFlagBits	sampleCountRange[] =
3158	{
3159		VK_SAMPLE_COUNT_2_BIT,
3160		VK_SAMPLE_COUNT_4_BIT,
3161		VK_SAMPLE_COUNT_8_BIT,
3162		VK_SAMPLE_COUNT_16_BIT,
3163		// There are no implementations that support 32 or 64 programmable samples currently
3164	};
3165
3166	// Verify custom sample locations and interpolation
3167	{
3168		using namespace VerifySamples;
3169
3170		MovePtr<tcu::TestCaseGroup> groupLocation		(new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_location"));
3171		MovePtr<tcu::TestCaseGroup> groupInterpolation	(new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_interpolation"));
3172
3173		for (const VkSampleCountFlagBits* pLoopNumSamples = sampleCountRange; pLoopNumSamples < DE_ARRAY_END(sampleCountRange); ++pLoopNumSamples)
3174		{
3175			addCases<VerifyLocationTest>	 (groupLocation.get(),		*pLoopNumSamples, pipelineConstructionType, useFragmentShadingRate, addProgramsVerifyLocationGeometry);
3176			addCases<VerifyInterpolationTest>(groupInterpolation.get(),	*pLoopNumSamples, pipelineConstructionType, useFragmentShadingRate, addProgramsVerifyInterpolation);
3177		}
3178
3179		rootGroup->addChild(groupLocation.release());
3180		rootGroup->addChild(groupInterpolation.release());
3181	}
3182
3183	// Draw with custom samples and various options
3184	{
3185		using namespace Draw;
3186
3187		const deUint32 globalOption = useFragmentShadingRate ? static_cast<deUint32>(TEST_OPTION_FRAGMENT_SHADING_RATE_BIT) : 0u;
3188		const deUint32 optionSets[] =
3189		{
3190			globalOption | TEST_OPTION_SAME_PATTERN_BIT,
3191			globalOption | 0u,
3192			globalOption | TEST_OPTION_DYNAMIC_STATE_BIT,
3193			globalOption | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3194			globalOption | TEST_OPTION_DYNAMIC_STATE_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3195			globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT,
3196			globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_DYNAMIC_STATE_BIT,
3197			globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3198			globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_DYNAMIC_STATE_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3199			globalOption | TEST_OPTION_WAIT_EVENTS_BIT,
3200			globalOption | TEST_OPTION_WAIT_EVENTS_BIT | TEST_OPTION_GENERAL_LAYOUT_BIT,
3201			globalOption | TEST_OPTION_WAIT_EVENTS_BIT | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3202		};
3203
3204		const struct
3205		{
3206			TestDrawIn	drawIn;
3207			TestClears	clears;
3208		} drawClearSets[] =
3209		{
3210			{ TEST_DRAW_IN_RENDER_PASSES,	TEST_CLEARS_NO_CLEAR				},
3211			{ TEST_DRAW_IN_RENDER_PASSES,	TEST_CLEARS_LOAD_OP_CLEAR			},
3212			{ TEST_DRAW_IN_RENDER_PASSES,	TEST_CLEARS_CMD_CLEAR_ATTACHMENTS	},
3213			{ TEST_DRAW_IN_RENDER_PASSES,	TEST_CLEARS_CMD_CLEAR_IMAGE			},
3214			{ TEST_DRAW_IN_SUBPASSES,		TEST_CLEARS_NO_CLEAR				},
3215			{ TEST_DRAW_IN_SUBPASSES,		TEST_CLEARS_CMD_CLEAR_ATTACHMENTS	},
3216			{ TEST_DRAW_IN_SAME_SUBPASS,	TEST_CLEARS_NO_CLEAR				},
3217			{ TEST_DRAW_IN_SAME_SUBPASS,	TEST_CLEARS_CMD_CLEAR_ATTACHMENTS	},
3218		};
3219
3220		const TestImageAspect aspectRange[] =
3221		{
3222			TEST_IMAGE_ASPECT_COLOR,
3223			TEST_IMAGE_ASPECT_DEPTH,
3224			TEST_IMAGE_ASPECT_STENCIL,
3225		};
3226
3227		MovePtr<tcu::TestCaseGroup> drawGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), "draw"));
3228		for (const TestImageAspect* pLoopImageAspect = aspectRange; pLoopImageAspect != DE_ARRAY_END(aspectRange); ++pLoopImageAspect)
3229		{
3230			MovePtr<tcu::TestCaseGroup> aspectGroup (new tcu::TestCaseGroup(drawGroup->getTestContext(), getString(*pLoopImageAspect)));
3231			for (const VkSampleCountFlagBits* pLoopNumSamples = sampleCountRange; pLoopNumSamples < DE_ARRAY_END(sampleCountRange); ++pLoopNumSamples)
3232			{
3233				MovePtr<tcu::TestCaseGroup> samplesGroup (new tcu::TestCaseGroup(aspectGroup->getTestContext(), getString(*pLoopNumSamples).c_str()));
3234
3235				for (deUint32		 loopDrawSetNdx = 0u;		  loopDrawSetNdx <  DE_LENGTH_OF_ARRAY(drawClearSets); ++loopDrawSetNdx)
3236				for (const deUint32* pLoopOptions	= optionSets; pLoopOptions	 != DE_ARRAY_END(optionSets);		   ++pLoopOptions)
3237				{
3238					const TestParams params
3239					{
3240						pipelineConstructionType,					// PipelineConstructionType	pipelineConstructionType;
3241						*pLoopNumSamples,							// VkSampleCountFlagBits	numSamples;
3242						*pLoopOptions,								// TestOptionFlags			options;
3243						drawClearSets[loopDrawSetNdx].drawIn,		// TestDrawIn				drawIn;
3244						drawClearSets[loopDrawSetNdx].clears,		// TestClears				clears;
3245						*pLoopImageAspect,							// TestImageAspect			imageAspect;
3246					};
3247
3248					// Filter out incompatible parameter combinations
3249					if (params.imageAspect != TEST_IMAGE_ASPECT_COLOR)
3250					{
3251						// If the sample pattern is changed, the D/S image must be cleared or the result is undefined
3252						if (((params.options & TEST_OPTION_SAME_PATTERN_BIT) == 0u) && (params.clears == TEST_CLEARS_NO_CLEAR))
3253							continue;
3254					}
3255
3256					// We are using events to change image layout and this is only allowed outside a render pass
3257					if (((params.options & TEST_OPTION_WAIT_EVENTS_BIT) != 0u) && (params.drawIn != TEST_DRAW_IN_RENDER_PASSES))
3258						continue;
3259
3260					// Can't change image layout inside a subpass
3261					if (((params.options & TEST_OPTION_GENERAL_LAYOUT_BIT) != 0u) && (params.drawIn == TEST_DRAW_IN_SAME_SUBPASS))
3262						continue;
3263
3264					std::ostringstream caseName;
3265					caseName << getString(params.drawIn) << "_"
3266							 << getString(params.clears) << (params.options != 0 ? "_" : "")
3267							 << getTestOptionFlagsString(params.options);
3268
3269					addInstanceTestCaseWithPrograms<DrawTest>(samplesGroup.get(), caseName.str().c_str(), checkSupportDrawTests, initPrograms, params);
3270				}
3271				aspectGroup->addChild(samplesGroup.release());
3272			}
3273			drawGroup->addChild(aspectGroup.release());
3274		}
3275		rootGroup->addChild(drawGroup.release());
3276	}
3277}
3278
3279} // anonymous ns
3280
3281tcu::TestCaseGroup* createMultisampleSampleLocationsExtTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType, bool useFragmentShadingRate)
3282{
3283	return createTestGroup(testCtx, "sample_locations_ext", createTestsInGroup, pipelineConstructionType, useFragmentShadingRate);
3284}
3285
3286} // pipeline
3287} // vkt
3288