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