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