1/*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief VkSwapchain Tests
22 *//*--------------------------------------------------------------------*/
23
24#include "vktWsiSwapchainTests.hpp"
25
26#include "vktTestCaseUtil.hpp"
27#include "vktTestGroupUtil.hpp"
28
29#include "vkDefs.hpp"
30#include "vkPlatform.hpp"
31#include "vkStrUtil.hpp"
32#include "vkRef.hpp"
33#include "vkRefUtil.hpp"
34#include "vkQueryUtil.hpp"
35#include "vkMemUtil.hpp"
36#include "vkDeviceUtil.hpp"
37#include "vkPrograms.hpp"
38#include "vkTypeUtil.hpp"
39#include "vkWsiPlatform.hpp"
40#include "vkWsiUtil.hpp"
41#include "vkAllocationCallbackUtil.hpp"
42
43#include "tcuTestLog.hpp"
44#include "tcuFormatUtil.hpp"
45#include "tcuPlatform.hpp"
46#include "tcuResultCollector.hpp"
47
48#include "deUniquePtr.hpp"
49#include "deStringUtil.hpp"
50#include "deArrayUtil.hpp"
51#include "deSharedPtr.hpp"
52
53#include <limits>
54
55namespace vkt
56{
57namespace wsi
58{
59
60namespace
61{
62
63using namespace vk;
64using namespace vk::wsi;
65
66using tcu::TestLog;
67using tcu::Maybe;
68using tcu::UVec2;
69
70using de::MovePtr;
71using de::UniquePtr;
72
73using std::string;
74using std::vector;
75
76typedef vector<VkExtensionProperties> Extensions;
77
78void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
79{
80	for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
81		 requiredExtName != requiredExtensions.end();
82		 ++requiredExtName)
83	{
84		if (!isExtensionSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
85			TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
86	}
87}
88
89Move<VkInstance> createInstanceWithWsi (const PlatformInterface&		vkp,
90										const Extensions&				supportedExtensions,
91										Type							wsiType,
92										const VkAllocationCallbacks*	pAllocator	= DE_NULL)
93{
94	vector<string>	extensions;
95
96	extensions.push_back("VK_KHR_surface");
97	extensions.push_back(getExtensionName(wsiType));
98
99	// VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
100	// the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
101	// but using them without enabling the extension is not allowed. Thus we have
102	// two options:
103	//
104	// 1) Filter out non-core formats to stay within valid usage.
105	//
106	// 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
107	//
108	// We opt for (2) as it provides basic coverage for the extension as a bonus.
109	if (isExtensionSupported(supportedExtensions, RequiredExtension("VK_EXT_swapchain_colorspace")))
110		extensions.push_back("VK_EXT_swapchain_colorspace");
111
112	checkAllSupported(supportedExtensions, extensions);
113
114	return createDefaultInstance(vkp, vector<string>(), extensions, pAllocator);
115}
116
117VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
118{
119	VkPhysicalDeviceFeatures features;
120	deMemset(&features, 0, sizeof(features));
121	return features;
122}
123
124Move<VkDevice> createDeviceWithWsi (const InstanceInterface&		vki,
125									VkPhysicalDevice				physicalDevice,
126									const Extensions&				supportedExtensions,
127									const deUint32					queueFamilyIndex,
128									const VkAllocationCallbacks*	pAllocator = DE_NULL)
129{
130	const float						queuePriorities[]	= { 1.0f };
131	const VkDeviceQueueCreateInfo	queueInfos[]		=
132	{
133		{
134			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
135			DE_NULL,
136			(VkDeviceQueueCreateFlags)0,
137			queueFamilyIndex,
138			DE_LENGTH_OF_ARRAY(queuePriorities),
139			&queuePriorities[0]
140		}
141	};
142	const VkPhysicalDeviceFeatures	features		= getDeviceFeaturesForWsi();
143	const char* const				extensions[]	= { "VK_KHR_swapchain" };
144	const VkDeviceCreateInfo		deviceParams	=
145	{
146		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
147		DE_NULL,
148		(VkDeviceCreateFlags)0,
149		DE_LENGTH_OF_ARRAY(queueInfos),
150		&queueInfos[0],
151		0u,									// enabledLayerCount
152		DE_NULL,							// ppEnabledLayerNames
153		DE_LENGTH_OF_ARRAY(extensions),		// enabledExtensionCount
154		DE_ARRAY_BEGIN(extensions),			// ppEnabledExtensionNames
155		&features
156	};
157
158	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
159	{
160		if (!isExtensionSupported(supportedExtensions, RequiredExtension(extensions[ndx])))
161			TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
162	}
163
164	return createDevice(vki, physicalDevice, &deviceParams, pAllocator);
165}
166
167deUint32 getNumQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
168{
169	deUint32	numFamilies		= 0;
170
171	vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
172
173	return numFamilies;
174}
175
176vector<deUint32> getSupportedQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
177{
178	const deUint32		numTotalFamilyIndices	= getNumQueueFamilyIndices(vki, physicalDevice);
179	vector<deUint32>	supportedFamilyIndices;
180
181	for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
182	{
183		if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
184			supportedFamilyIndices.push_back(queueFamilyNdx);
185	}
186
187	return supportedFamilyIndices;
188}
189
190deUint32 chooseQueueFamilyIndex (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
191{
192	const vector<deUint32>	supportedFamilyIndices	= getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
193
194	if (supportedFamilyIndices.empty())
195		TCU_THROW(NotSupportedError, "Device doesn't support presentation");
196
197	return supportedFamilyIndices[0];
198}
199
200struct InstanceHelper
201{
202	const vector<VkExtensionProperties>	supportedExtensions;
203	const Unique<VkInstance>			instance;
204	const InstanceDriver				vki;
205
206	InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
207		: supportedExtensions	(enumerateInstanceExtensionProperties(context.getPlatformInterface(),
208																	  DE_NULL))
209		, instance				(createInstanceWithWsi(context.getPlatformInterface(),
210													   supportedExtensions,
211													   wsiType,
212													   pAllocator))
213		, vki					(context.getPlatformInterface(), *instance)
214	{}
215};
216
217VkQueue getDeviceQueue (const DeviceInterface& vkd, VkDevice device, deUint32 queueFamilyIndex, deUint32 queueIndex)
218{
219	VkQueue queue = (VkQueue)0;
220	vkd.getDeviceQueue(device, queueFamilyIndex, queueIndex, &queue);
221	return queue;
222}
223
224struct DeviceHelper
225{
226	const VkPhysicalDevice	physicalDevice;
227	const deUint32			queueFamilyIndex;
228	const Unique<VkDevice>	device;
229	const DeviceDriver		vkd;
230	const VkQueue			queue;
231
232	DeviceHelper (Context&						context,
233				  const InstanceInterface&		vki,
234				  VkInstance					instance,
235				  VkSurfaceKHR					surface,
236				  const VkAllocationCallbacks*	pAllocator = DE_NULL)
237		: physicalDevice	(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
238		, queueFamilyIndex	(chooseQueueFamilyIndex(vki, physicalDevice, surface))
239		, device			(createDeviceWithWsi(vki,
240												 physicalDevice,
241												 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
242												 queueFamilyIndex,
243												 pAllocator))
244		, vkd				(vki, *device)
245		, queue				(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
246	{
247	}
248};
249
250MovePtr<Display> createDisplay (const vk::Platform&	platform,
251								const Extensions&	supportedExtensions,
252								Type				wsiType)
253{
254	try
255	{
256		return MovePtr<Display>(platform.createWsiDisplay(wsiType));
257	}
258	catch (const tcu::NotSupportedError& e)
259	{
260		if (isExtensionSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))))
261		{
262			// If VK_KHR_{platform}_surface was supported, vk::Platform implementation
263			// must support creating native display & window for that WSI type.
264			throw tcu::TestError(e.getMessage());
265		}
266		else
267			throw;
268	}
269}
270
271MovePtr<Window> createWindow (const Display& display, const Maybe<UVec2>& initialSize)
272{
273	try
274	{
275		return MovePtr<Window>(display.createWindow(initialSize));
276	}
277	catch (const tcu::NotSupportedError& e)
278	{
279		// See createDisplay - assuming that wsi::Display was supported platform port
280		// should also support creating a window.
281		throw tcu::TestError(e.getMessage());
282	}
283}
284
285struct NativeObjects
286{
287	const UniquePtr<Display>	display;
288	const UniquePtr<Window>		window;
289
290	NativeObjects (Context&				context,
291				   const Extensions&	supportedExtensions,
292				   Type					wsiType,
293				   const Maybe<UVec2>&	initialWindowSize = tcu::nothing<UVec2>())
294		: display	(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
295		, window	(createWindow(*display, initialWindowSize))
296	{}
297};
298
299enum TestDimension
300{
301	TEST_DIMENSION_MIN_IMAGE_COUNT = 0,	//!< Test all supported image counts
302	TEST_DIMENSION_IMAGE_FORMAT,		//!< Test all supported formats
303	TEST_DIMENSION_IMAGE_EXTENT,		//!< Test various (supported) extents
304	TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
305	TEST_DIMENSION_IMAGE_USAGE,
306	TEST_DIMENSION_IMAGE_SHARING_MODE,
307	TEST_DIMENSION_PRE_TRANSFORM,
308	TEST_DIMENSION_COMPOSITE_ALPHA,
309	TEST_DIMENSION_PRESENT_MODE,
310	TEST_DIMENSION_CLIPPED,
311
312	TEST_DIMENSION_LAST
313};
314
315const char* getTestDimensionName (TestDimension dimension)
316{
317	static const char* const s_names[] =
318	{
319		"min_image_count",
320		"image_format",
321		"image_extent",
322		"image_array_layers",
323		"image_usage",
324		"image_sharing_mode",
325		"pre_transform",
326		"composite_alpha",
327		"present_mode",
328		"clipped"
329	};
330	return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
331}
332
333struct TestParameters
334{
335	Type			wsiType;
336	TestDimension	dimension;
337
338	TestParameters (Type wsiType_, TestDimension dimension_)
339		: wsiType	(wsiType_)
340		, dimension	(dimension_)
341	{}
342
343	TestParameters (void)
344		: wsiType	(TYPE_LAST)
345		, dimension	(TEST_DIMENSION_LAST)
346	{}
347};
348
349vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (Type								wsiType,
350																  TestDimension						dimension,
351																  const VkSurfaceCapabilitiesKHR&	capabilities,
352																  const vector<VkSurfaceFormatKHR>&	formats,
353																  const vector<VkPresentModeKHR>&	presentModes)
354{
355	const PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
356	vector<VkSwapchainCreateInfoKHR>	cases;
357	const VkSurfaceTransformFlagBitsKHR defaultTransform	= (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
358	const VkSwapchainCreateInfoKHR		baseParameters		=
359	{
360		VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
361		DE_NULL,
362		(VkSwapchainCreateFlagsKHR)0,
363		(VkSurfaceKHR)0,
364		capabilities.minImageCount,
365		formats[0].format,
366		formats[0].colorSpace,
367		(platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
368			? capabilities.minImageExtent : capabilities.currentExtent),
369		1u,									// imageArrayLayers
370		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
371		VK_SHARING_MODE_EXCLUSIVE,
372		0u,
373		(const deUint32*)DE_NULL,
374		defaultTransform,
375		VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
376		VK_PRESENT_MODE_FIFO_KHR,
377		VK_FALSE,							// clipped
378		(VkSwapchainKHR)0					// oldSwapchain
379	};
380
381	switch (dimension)
382	{
383		case TEST_DIMENSION_MIN_IMAGE_COUNT:
384		{
385			const deUint32	maxImageCountToTest	= de::clamp(16u, capabilities.minImageCount, (capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u);
386
387			for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
388			{
389				cases.push_back(baseParameters);
390				cases.back().minImageCount = imageCount;
391			}
392
393			break;
394		}
395
396		case TEST_DIMENSION_IMAGE_FORMAT:
397		{
398			for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
399			{
400				cases.push_back(baseParameters);
401				cases.back().imageFormat		= curFmt->format;
402				cases.back().imageColorSpace	= curFmt->colorSpace;
403			}
404
405			break;
406		}
407
408		case TEST_DIMENSION_IMAGE_EXTENT:
409		{
410			static const VkExtent2D	s_testSizes[]	=
411			{
412				{ 1, 1 },
413				{ 16, 32 },
414				{ 32, 16 },
415				{ 632, 231 },
416				{ 117, 998 },
417			};
418
419			if (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
420				platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
421			{
422				for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
423				{
424					cases.push_back(baseParameters);
425					cases.back().imageExtent.width	= de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
426					cases.back().imageExtent.height	= de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
427				}
428			}
429
430			if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
431			{
432				cases.push_back(baseParameters);
433				cases.back().imageExtent = capabilities.currentExtent;
434			}
435
436			if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
437			{
438				cases.push_back(baseParameters);
439				cases.back().imageExtent = capabilities.minImageExtent;
440
441				cases.push_back(baseParameters);
442				cases.back().imageExtent = capabilities.maxImageExtent;
443			}
444
445			break;
446		}
447
448		case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
449		{
450			const deUint32	maxLayers	= de::min(capabilities.maxImageArrayLayers, 16u);
451
452			for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
453			{
454				cases.push_back(baseParameters);
455				cases.back().imageArrayLayers = numLayers;
456			}
457
458			break;
459		}
460
461		case TEST_DIMENSION_IMAGE_USAGE:
462		{
463			for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
464			{
465				if ((flags & ~capabilities.supportedUsageFlags) == 0)
466				{
467					cases.push_back(baseParameters);
468					cases.back().imageUsage = flags;
469				}
470			}
471
472			break;
473		}
474
475		case TEST_DIMENSION_IMAGE_SHARING_MODE:
476		{
477			cases.push_back(baseParameters);
478			cases.back().imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
479
480			cases.push_back(baseParameters);
481			cases.back().imageSharingMode = VK_SHARING_MODE_CONCURRENT;
482
483			break;
484		}
485
486		case TEST_DIMENSION_PRE_TRANSFORM:
487		{
488			for (deUint32 transform = 1u;
489				 transform <= capabilities.supportedTransforms;
490				 transform = transform<<1u)
491			{
492				if ((transform & capabilities.supportedTransforms) != 0)
493				{
494					cases.push_back(baseParameters);
495					cases.back().preTransform = (VkSurfaceTransformFlagBitsKHR)transform;
496				}
497			}
498
499			break;
500		}
501
502		case TEST_DIMENSION_COMPOSITE_ALPHA:
503		{
504			for (deUint32 alphaMode = 1u;
505				 alphaMode <= capabilities.supportedCompositeAlpha;
506				 alphaMode = alphaMode<<1u)
507			{
508				if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
509				{
510					cases.push_back(baseParameters);
511					cases.back().compositeAlpha = (VkCompositeAlphaFlagBitsKHR)alphaMode;
512				}
513			}
514
515			break;
516		}
517
518		case TEST_DIMENSION_PRESENT_MODE:
519		{
520			for (vector<VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
521			{
522				cases.push_back(baseParameters);
523				cases.back().presentMode = *curMode;
524			}
525
526			break;
527		}
528
529		case TEST_DIMENSION_CLIPPED:
530		{
531			cases.push_back(baseParameters);
532			cases.back().clipped = VK_FALSE;
533
534			cases.push_back(baseParameters);
535			cases.back().clipped = VK_TRUE;
536
537			break;
538		}
539
540		default:
541			DE_FATAL("Impossible");
542	}
543
544	DE_ASSERT(!cases.empty());
545	return cases;
546}
547
548vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (Type								wsiType,
549																  TestDimension						dimension,
550																  const InstanceInterface&			vki,
551																  VkPhysicalDevice					physicalDevice,
552																  VkSurfaceKHR						surface)
553{
554	const VkSurfaceCapabilitiesKHR		capabilities	= getPhysicalDeviceSurfaceCapabilities(vki,
555																							   physicalDevice,
556																							   surface);
557	const vector<VkSurfaceFormatKHR>	formats			= getPhysicalDeviceSurfaceFormats(vki,
558																						  physicalDevice,
559																						  surface);
560	const vector<VkPresentModeKHR>		presentModes	= getPhysicalDeviceSurfacePresentModes(vki,
561																							   physicalDevice,
562																							   surface);
563
564	return generateSwapchainParameterCases(wsiType, dimension, capabilities, formats, presentModes);
565}
566
567tcu::TestStatus createSwapchainTest (Context& context, TestParameters params)
568{
569	const InstanceHelper					instHelper	(context, params.wsiType);
570	const NativeObjects						native		(context, instHelper.supportedExtensions, params.wsiType);
571	const Unique<VkSurfaceKHR>				surface		(createSurface(instHelper.vki, *instHelper.instance, params.wsiType, *native.display, *native.window));
572	const DeviceHelper						devHelper	(context, instHelper.vki, *instHelper.instance, *surface);
573	const vector<VkSwapchainCreateInfoKHR>	cases		(generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
574
575	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
576	{
577		VkSwapchainCreateInfoKHR	curParams	= cases[caseNdx];
578
579		curParams.surface				= *surface;
580		curParams.queueFamilyIndexCount	= 1u;
581		curParams.pQueueFamilyIndices	= &devHelper.queueFamilyIndex;
582
583		context.getTestContext().getLog()
584			<< TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": " << curParams << TestLog::EndMessage;
585
586		{
587			const Unique<VkSwapchainKHR>	swapchain	(createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
588		}
589	}
590
591	return tcu::TestStatus::pass("Creating swapchain succeeded");
592}
593
594tcu::TestStatus createSwapchainSimulateOOMTest (Context& context, TestParameters params)
595{
596	const size_t				maxCases			= 300u;
597	const deUint32				maxAllocs			= 1024u;
598
599	tcu::TestLog&				log					= context.getTestContext().getLog();
600	tcu::ResultCollector		results				(log);
601
602	AllocationCallbackRecorder	allocationRecorder	(getSystemAllocator());
603	DeterministicFailAllocator	failingAllocator	(allocationRecorder.getCallbacks(),
604													 DeterministicFailAllocator::MODE_DO_NOT_COUNT,
605													 0);
606	{
607		const InstanceHelper					instHelper	(context, params.wsiType, failingAllocator.getCallbacks());
608		const NativeObjects						native		(context, instHelper.supportedExtensions, params.wsiType);
609		const Unique<VkSurfaceKHR>				surface		(createSurface(instHelper.vki,
610																			*instHelper.instance,
611																			params.wsiType,
612																			*native.display,
613																			*native.window,
614																			failingAllocator.getCallbacks()));
615		const DeviceHelper						devHelper	(context, instHelper.vki, *instHelper.instance, *surface, failingAllocator.getCallbacks());
616		const vector<VkSwapchainCreateInfoKHR>	allCases	(generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
617
618		if (maxCases < allCases.size())
619			log << TestLog::Message << "Note: Will only test first " << maxCases << " cases out of total of " << allCases.size() << " parameter combinations" << TestLog::EndMessage;
620
621		for (size_t caseNdx = 0; caseNdx < de::min(maxCases, allCases.size()); ++caseNdx)
622		{
623			log << TestLog::Message << "Testing parameter case " << caseNdx << ": " << allCases[caseNdx] << TestLog::EndMessage;
624
625			for (deUint32 numPassingAllocs = 0; numPassingAllocs <= maxAllocs; ++numPassingAllocs)
626			{
627				bool	gotOOM	= false;
628
629				failingAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
630
631				log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
632
633				try
634				{
635					VkSwapchainCreateInfoKHR	curParams	= allCases[caseNdx];
636
637					curParams.surface				= *surface;
638					curParams.queueFamilyIndexCount	= 1u;
639					curParams.pQueueFamilyIndices	= &devHelper.queueFamilyIndex;
640
641					{
642						const Unique<VkSwapchainKHR>	swapchain	(createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
643					}
644				}
645				catch (const OutOfMemoryError& e)
646				{
647					log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
648					gotOOM = true;
649				}
650
651				if (!gotOOM)
652				{
653					log << TestLog::Message << "Creating swapchain succeeded!" << TestLog::EndMessage;
654
655					if (numPassingAllocs == 0)
656						results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
657
658					break;
659				}
660				else if (numPassingAllocs == maxAllocs)
661					results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Creating swapchain did not succeed, callback limit exceeded");
662			}
663		}
664
665		context.getTestContext().touchWatchdog();
666	}
667
668	if (!validateAndLog(log, allocationRecorder, 0u))
669		results.fail("Detected invalid system allocation callback");
670
671	return tcu::TestStatus(results.getResult(), results.getMessage());
672}
673
674struct GroupParameters
675{
676	typedef FunctionInstance1<TestParameters>::Function	Function;
677
678	Type		wsiType;
679	Function	function;
680
681	GroupParameters (Type wsiType_, Function function_)
682		: wsiType	(wsiType_)
683		, function	(function_)
684	{}
685
686	GroupParameters (void)
687		: wsiType	(TYPE_LAST)
688		, function	((Function)DE_NULL)
689	{}
690};
691
692void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
693{
694	for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
695	{
696		const TestDimension		testDimension	= (TestDimension)dimensionNdx;
697
698		addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
699	}
700}
701
702VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type						wsiType,
703													  const InstanceInterface&	vki,
704													  VkPhysicalDevice			physicalDevice,
705													  VkSurfaceKHR				surface,
706													  const tcu::UVec2&			desiredSize,
707													  deUint32					desiredImageCount)
708{
709	const VkSurfaceCapabilitiesKHR		capabilities		= getPhysicalDeviceSurfaceCapabilities(vki,
710																								   physicalDevice,
711																								   surface);
712	const vector<VkSurfaceFormatKHR>	formats				= getPhysicalDeviceSurfaceFormats(vki,
713																							  physicalDevice,
714																							  surface);
715	const PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
716	const VkSurfaceTransformFlagBitsKHR transform			= (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
717	const VkSwapchainCreateInfoKHR		parameters			=
718	{
719		VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
720		DE_NULL,
721		(VkSwapchainCreateFlagsKHR)0,
722		surface,
723		de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
724		formats[0].format,
725		formats[0].colorSpace,
726		(platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
727			? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
728		1u,									// imageArrayLayers
729		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
730		VK_SHARING_MODE_EXCLUSIVE,
731		0u,
732		(const deUint32*)DE_NULL,
733		transform,
734		VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
735		VK_PRESENT_MODE_FIFO_KHR,
736		VK_FALSE,							// clipped
737		(VkSwapchainKHR)0					// oldSwapchain
738	};
739
740	return parameters;
741}
742
743typedef de::SharedPtr<Unique<VkImageView> >		ImageViewSp;
744typedef de::SharedPtr<Unique<VkFramebuffer> >	FramebufferSp;
745
746class TriangleRenderer
747{
748public:
749									TriangleRenderer	(const DeviceInterface&		vkd,
750														 const VkDevice				device,
751														 Allocator&					allocator,
752														 const BinaryCollection&	binaryRegistry,
753														 const vector<VkImage>		swapchainImages,
754														 const VkFormat				framebufferFormat,
755														 const UVec2&				renderSize);
756									~TriangleRenderer	(void);
757
758	void							recordFrame			(VkCommandBuffer			cmdBuffer,
759														 deUint32					imageNdx,
760														 deUint32					frameNdx) const;
761
762	static void						getPrograms			(SourceCollections& dst);
763
764private:
765	static Move<VkRenderPass>		createRenderPass	(const DeviceInterface&		vkd,
766														 const VkDevice				device,
767														 const VkFormat				colorAttachmentFormat);
768	static Move<VkPipelineLayout>	createPipelineLayout(const DeviceInterface&		vkd,
769														 VkDevice					device);
770	static Move<VkPipeline>			createPipeline		(const DeviceInterface&		vkd,
771														 const VkDevice				device,
772														 const VkRenderPass			renderPass,
773														 const VkPipelineLayout		pipelineLayout,
774														 const BinaryCollection&	binaryCollection,
775														 const UVec2&				renderSize);
776
777	static Move<VkImageView>		createAttachmentView(const DeviceInterface&		vkd,
778														 const VkDevice				device,
779														 const VkImage				image,
780														 const VkFormat				format);
781	static Move<VkFramebuffer>		createFramebuffer	(const DeviceInterface&		vkd,
782														 const VkDevice				device,
783														 const VkRenderPass			renderPass,
784														 const VkImageView			colorAttachment,
785														 const UVec2&				renderSize);
786
787	static Move<VkBuffer>			createBuffer		(const DeviceInterface&		vkd,
788														 VkDevice					device,
789														 VkDeviceSize				size,
790														 VkBufferUsageFlags			usage);
791
792	const DeviceInterface&			m_vkd;
793
794	const vector<VkImage>			m_swapchainImages;
795	const tcu::UVec2				m_renderSize;
796
797	const Unique<VkRenderPass>		m_renderPass;
798	const Unique<VkPipelineLayout>	m_pipelineLayout;
799	const Unique<VkPipeline>		m_pipeline;
800
801	const Unique<VkBuffer>			m_vertexBuffer;
802	const UniquePtr<Allocation>		m_vertexBufferMemory;
803
804	vector<ImageViewSp>				m_attachmentViews;
805	vector<FramebufferSp>			m_framebuffers;
806};
807
808Move<VkRenderPass> TriangleRenderer::createRenderPass (const DeviceInterface&	vkd,
809													   const VkDevice			device,
810													   const VkFormat			colorAttachmentFormat)
811{
812	const VkAttachmentDescription	colorAttDesc		=
813	{
814		(VkAttachmentDescriptionFlags)0,
815		colorAttachmentFormat,
816		VK_SAMPLE_COUNT_1_BIT,
817		VK_ATTACHMENT_LOAD_OP_CLEAR,
818		VK_ATTACHMENT_STORE_OP_STORE,
819		VK_ATTACHMENT_LOAD_OP_DONT_CARE,
820		VK_ATTACHMENT_STORE_OP_DONT_CARE,
821		VK_IMAGE_LAYOUT_UNDEFINED,
822		VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
823	};
824	const VkAttachmentReference		colorAttRef			=
825	{
826		0u,
827		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
828	};
829	const VkSubpassDescription		subpassDesc			=
830	{
831		(VkSubpassDescriptionFlags)0u,
832		VK_PIPELINE_BIND_POINT_GRAPHICS,
833		0u,							// inputAttachmentCount
834		DE_NULL,					// pInputAttachments
835		1u,							// colorAttachmentCount
836		&colorAttRef,				// pColorAttachments
837		DE_NULL,					// pResolveAttachments
838		DE_NULL,					// depthStencilAttachment
839		0u,							// preserveAttachmentCount
840		DE_NULL,					// pPreserveAttachments
841	};
842	const VkSubpassDependency		dependencies[]		=
843	{
844		{
845			VK_SUBPASS_EXTERNAL,	// srcSubpass
846			0u,						// dstSubpass
847			VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
848			VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
849			VK_ACCESS_MEMORY_READ_BIT,
850			(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
851			 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
852			VK_DEPENDENCY_BY_REGION_BIT
853		},
854		{
855			0u,						// srcSubpass
856			VK_SUBPASS_EXTERNAL,	// dstSubpass
857			VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
858			VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
859			(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
860			 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
861			VK_ACCESS_MEMORY_READ_BIT,
862			VK_DEPENDENCY_BY_REGION_BIT
863		},
864	};
865	const VkRenderPassCreateInfo	renderPassParams	=
866	{
867		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
868		DE_NULL,
869		(VkRenderPassCreateFlags)0,
870		1u,
871		&colorAttDesc,
872		1u,
873		&subpassDesc,
874		DE_LENGTH_OF_ARRAY(dependencies),
875		dependencies,
876	};
877
878	return vk::createRenderPass(vkd, device, &renderPassParams);
879}
880
881Move<VkPipelineLayout> TriangleRenderer::createPipelineLayout (const DeviceInterface&	vkd,
882															   const VkDevice			device)
883{
884	const VkPushConstantRange						pushConstantRange		=
885	{
886		VK_SHADER_STAGE_VERTEX_BIT,
887		0u,											// offset
888		(deUint32)sizeof(deUint32),					// size
889	};
890	const VkPipelineLayoutCreateInfo				pipelineLayoutParams	=
891	{
892		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
893		DE_NULL,
894		(vk::VkPipelineLayoutCreateFlags)0,
895		0u,											// setLayoutCount
896		DE_NULL,									// pSetLayouts
897		1u,
898		&pushConstantRange,
899	};
900
901	return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
902}
903
904Move<VkPipeline> TriangleRenderer::createPipeline (const DeviceInterface&	vkd,
905												   const VkDevice			device,
906												   const VkRenderPass		renderPass,
907												   const VkPipelineLayout	pipelineLayout,
908												   const BinaryCollection&	binaryCollection,
909												   const UVec2&				renderSize)
910{
911	// \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
912	//		 and can be deleted immediately following that call.
913	const Unique<VkShaderModule>					vertShaderModule		(createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
914	const Unique<VkShaderModule>					fragShaderModule		(createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
915
916	const VkSpecializationInfo						emptyShaderSpecParams	=
917	{
918		0u,											// mapEntryCount
919		DE_NULL,									// pMap
920		0,											// dataSize
921		DE_NULL,									// pData
922	};
923	const VkPipelineShaderStageCreateInfo			shaderStageParams[]		=
924	{
925		{
926			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
927			DE_NULL,
928			(VkPipelineShaderStageCreateFlags)0,
929			VK_SHADER_STAGE_VERTEX_BIT,
930			*vertShaderModule,
931			"main",
932			&emptyShaderSpecParams,
933		},
934		{
935			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
936			DE_NULL,
937			(VkPipelineShaderStageCreateFlags)0,
938			VK_SHADER_STAGE_FRAGMENT_BIT,
939			*fragShaderModule,
940			"main",
941			&emptyShaderSpecParams,
942		}
943	};
944	const VkPipelineDepthStencilStateCreateInfo		depthStencilParams		=
945	{
946		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
947		DE_NULL,
948		(VkPipelineDepthStencilStateCreateFlags)0,
949		DE_FALSE,									// depthTestEnable
950		DE_FALSE,									// depthWriteEnable
951		VK_COMPARE_OP_ALWAYS,						// depthCompareOp
952		DE_FALSE,									// depthBoundsTestEnable
953		DE_FALSE,									// stencilTestEnable
954		{
955			VK_STENCIL_OP_KEEP,							// failOp
956			VK_STENCIL_OP_KEEP,							// passOp
957			VK_STENCIL_OP_KEEP,							// depthFailOp
958			VK_COMPARE_OP_ALWAYS,						// compareOp
959			0u,											// compareMask
960			0u,											// writeMask
961			0u,											// reference
962		},											// front
963		{
964			VK_STENCIL_OP_KEEP,							// failOp
965			VK_STENCIL_OP_KEEP,							// passOp
966			VK_STENCIL_OP_KEEP,							// depthFailOp
967			VK_COMPARE_OP_ALWAYS,						// compareOp
968			0u,											// compareMask
969			0u,											// writeMask
970			0u,											// reference
971		},											// back
972		-1.0f,										// minDepthBounds
973		+1.0f,										// maxDepthBounds
974	};
975	const VkViewport								viewport0				=
976	{
977		0.0f,										// x
978		0.0f,										// y
979		(float)renderSize.x(),						// width
980		(float)renderSize.y(),						// height
981		0.0f,										// minDepth
982		1.0f,										// maxDepth
983	};
984	const VkRect2D									scissor0				=
985	{
986		{ 0u, 0u, },								// offset
987		{ renderSize.x(), renderSize.y() },			// extent
988	};
989	const VkPipelineViewportStateCreateInfo			viewportParams			=
990	{
991		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
992		DE_NULL,
993		(VkPipelineViewportStateCreateFlags)0,
994		1u,
995		&viewport0,
996		1u,
997		&scissor0
998	};
999	const VkPipelineMultisampleStateCreateInfo		multisampleParams		=
1000	{
1001		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
1002		DE_NULL,
1003		(VkPipelineMultisampleStateCreateFlags)0,
1004		VK_SAMPLE_COUNT_1_BIT,						// rasterizationSamples
1005		VK_FALSE,									// sampleShadingEnable
1006		0.0f,										// minSampleShading
1007		(const VkSampleMask*)DE_NULL,				// sampleMask
1008		VK_FALSE,									// alphaToCoverageEnable
1009		VK_FALSE,									// alphaToOneEnable
1010	};
1011	const VkPipelineRasterizationStateCreateInfo	rasterParams			=
1012	{
1013		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
1014		DE_NULL,
1015		(VkPipelineRasterizationStateCreateFlags)0,
1016		VK_FALSE,									// depthClampEnable
1017		VK_FALSE,									// rasterizerDiscardEnable
1018		VK_POLYGON_MODE_FILL,						// polygonMode
1019		VK_CULL_MODE_NONE,							// cullMode
1020		VK_FRONT_FACE_COUNTER_CLOCKWISE,			// frontFace
1021		VK_FALSE,									// depthBiasEnable
1022		0.0f,										// depthBiasConstantFactor
1023		0.0f,										// depthBiasClamp
1024		0.0f,										// depthBiasSlopeFactor
1025		1.0f,										// lineWidth
1026	};
1027	const VkPipelineInputAssemblyStateCreateInfo	inputAssemblyParams		=
1028	{
1029		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
1030		DE_NULL,
1031		(VkPipelineInputAssemblyStateCreateFlags)0,
1032		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
1033		DE_FALSE,									// primitiveRestartEnable
1034	};
1035	const VkVertexInputBindingDescription			vertexBinding0			=
1036	{
1037		0u,											// binding
1038		(deUint32)sizeof(tcu::Vec4),				// stride
1039		VK_VERTEX_INPUT_RATE_VERTEX,				// inputRate
1040	};
1041	const VkVertexInputAttributeDescription			vertexAttrib0			=
1042	{
1043		0u,											// location
1044		0u,											// binding
1045		VK_FORMAT_R32G32B32A32_SFLOAT,				// format
1046		0u,											// offset
1047	};
1048	const VkPipelineVertexInputStateCreateInfo		vertexInputStateParams	=
1049	{
1050		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
1051		DE_NULL,
1052		(VkPipelineVertexInputStateCreateFlags)0,
1053		1u,
1054		&vertexBinding0,
1055		1u,
1056		&vertexAttrib0,
1057	};
1058	const VkPipelineColorBlendAttachmentState		attBlendParams0			=
1059	{
1060		VK_FALSE,									// blendEnable
1061		VK_BLEND_FACTOR_ONE,						// srcColorBlendFactor
1062		VK_BLEND_FACTOR_ZERO,						// dstColorBlendFactor
1063		VK_BLEND_OP_ADD,							// colorBlendOp
1064		VK_BLEND_FACTOR_ONE,						// srcAlphaBlendFactor
1065		VK_BLEND_FACTOR_ZERO,						// dstAlphaBlendFactor
1066		VK_BLEND_OP_ADD,							// alphaBlendOp
1067		(VK_COLOR_COMPONENT_R_BIT|
1068		 VK_COLOR_COMPONENT_G_BIT|
1069		 VK_COLOR_COMPONENT_B_BIT|
1070		 VK_COLOR_COMPONENT_A_BIT),					// colorWriteMask
1071	};
1072	const VkPipelineColorBlendStateCreateInfo		blendParams				=
1073	{
1074		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
1075		DE_NULL,
1076		(VkPipelineColorBlendStateCreateFlags)0,
1077		VK_FALSE,									// logicOpEnable
1078		VK_LOGIC_OP_COPY,
1079		1u,
1080		&attBlendParams0,
1081		{ 0.0f, 0.0f, 0.0f, 0.0f },					// blendConstants[4]
1082	};
1083	const VkGraphicsPipelineCreateInfo				pipelineParams			=
1084	{
1085		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
1086		DE_NULL,
1087		(VkPipelineCreateFlags)0,
1088		(deUint32)DE_LENGTH_OF_ARRAY(shaderStageParams),
1089		shaderStageParams,
1090		&vertexInputStateParams,
1091		&inputAssemblyParams,
1092		(const VkPipelineTessellationStateCreateInfo*)DE_NULL,
1093		&viewportParams,
1094		&rasterParams,
1095		&multisampleParams,
1096		&depthStencilParams,
1097		&blendParams,
1098		(const VkPipelineDynamicStateCreateInfo*)DE_NULL,
1099		pipelineLayout,
1100		renderPass,
1101		0u,											// subpass
1102		DE_NULL,									// basePipelineHandle
1103		0u,											// basePipelineIndex
1104	};
1105
1106	return vk::createGraphicsPipeline(vkd, device, (VkPipelineCache)0, &pipelineParams);
1107}
1108
1109Move<VkImageView> TriangleRenderer::createAttachmentView (const DeviceInterface&	vkd,
1110														  const VkDevice			device,
1111														  const VkImage				image,
1112														  const VkFormat			format)
1113{
1114	const VkImageViewCreateInfo		viewParams	=
1115	{
1116		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1117		DE_NULL,
1118		(VkImageViewCreateFlags)0,
1119		image,
1120		VK_IMAGE_VIEW_TYPE_2D,
1121		format,
1122		vk::makeComponentMappingRGBA(),
1123		{
1124			VK_IMAGE_ASPECT_COLOR_BIT,
1125			0u,						// baseMipLevel
1126			1u,						// levelCount
1127			0u,						// baseArrayLayer
1128			1u,						// layerCount
1129		},
1130	};
1131
1132	return vk::createImageView(vkd, device, &viewParams);
1133}
1134
1135Move<VkFramebuffer> TriangleRenderer::createFramebuffer	(const DeviceInterface&		vkd,
1136														 const VkDevice				device,
1137														 const VkRenderPass			renderPass,
1138														 const VkImageView			colorAttachment,
1139														 const UVec2&				renderSize)
1140{
1141	const VkFramebufferCreateInfo	framebufferParams	=
1142	{
1143		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1144		DE_NULL,
1145		(VkFramebufferCreateFlags)0,
1146		renderPass,
1147		1u,
1148		&colorAttachment,
1149		renderSize.x(),
1150		renderSize.y(),
1151		1u,							// layers
1152	};
1153
1154	return vk::createFramebuffer(vkd, device, &framebufferParams);
1155}
1156
1157Move<VkBuffer> TriangleRenderer::createBuffer (const DeviceInterface&	vkd,
1158											   VkDevice					device,
1159											   VkDeviceSize				size,
1160											   VkBufferUsageFlags		usage)
1161{
1162	const VkBufferCreateInfo	bufferParams	=
1163	{
1164		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1165		DE_NULL,
1166		(VkBufferCreateFlags)0,
1167		size,
1168		usage,
1169		VK_SHARING_MODE_EXCLUSIVE,
1170		0,
1171		DE_NULL
1172	};
1173
1174	return vk::createBuffer(vkd, device, &bufferParams);
1175}
1176
1177TriangleRenderer::TriangleRenderer (const DeviceInterface&	vkd,
1178									const VkDevice			device,
1179									Allocator&				allocator,
1180									const BinaryCollection&	binaryRegistry,
1181									const vector<VkImage>	swapchainImages,
1182									const VkFormat			framebufferFormat,
1183									const UVec2&			renderSize)
1184	: m_vkd					(vkd)
1185	, m_swapchainImages		(swapchainImages)
1186	, m_renderSize			(renderSize)
1187	, m_renderPass			(createRenderPass(vkd, device, framebufferFormat))
1188	, m_pipelineLayout		(createPipelineLayout(vkd, device))
1189	, m_pipeline			(createPipeline(vkd, device, *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
1190	, m_vertexBuffer		(createBuffer(vkd, device, (VkDeviceSize)(sizeof(float)*4*3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
1191	, m_vertexBufferMemory	(allocator.allocate(getBufferMemoryRequirements(vkd, device, *m_vertexBuffer),
1192							 MemoryRequirement::HostVisible))
1193{
1194	m_attachmentViews.resize(swapchainImages.size());
1195	m_framebuffers.resize(swapchainImages.size());
1196
1197	for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
1198	{
1199		m_attachmentViews[imageNdx]	= ImageViewSp(new Unique<VkImageView>(createAttachmentView(vkd, device, swapchainImages[imageNdx], framebufferFormat)));
1200		m_framebuffers[imageNdx]	= FramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vkd, device, *m_renderPass, **m_attachmentViews[imageNdx], renderSize)));
1201	}
1202
1203	VK_CHECK(vkd.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset()));
1204
1205	{
1206		const VkMappedMemoryRange	memRange	=
1207		{
1208			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
1209			DE_NULL,
1210			m_vertexBufferMemory->getMemory(),
1211			m_vertexBufferMemory->getOffset(),
1212			VK_WHOLE_SIZE
1213		};
1214		const tcu::Vec4				vertices[]	=
1215		{
1216			tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
1217			tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
1218			tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
1219		};
1220		DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
1221
1222		deMemcpy(m_vertexBufferMemory->getHostPtr(), &vertices[0], sizeof(vertices));
1223		VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &memRange));
1224	}
1225}
1226
1227TriangleRenderer::~TriangleRenderer (void)
1228{
1229}
1230
1231void TriangleRenderer::recordFrame (VkCommandBuffer	cmdBuffer,
1232									deUint32		imageNdx,
1233									deUint32		frameNdx) const
1234{
1235	const VkFramebuffer	curFramebuffer	= **m_framebuffers[imageNdx];
1236
1237	{
1238		const VkCommandBufferBeginInfo	cmdBufBeginParams	=
1239		{
1240			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1241			DE_NULL,
1242			(VkCommandBufferUsageFlags)0,
1243			(const VkCommandBufferInheritanceInfo*)DE_NULL,
1244		};
1245		VK_CHECK(m_vkd.beginCommandBuffer(cmdBuffer, &cmdBufBeginParams));
1246	}
1247
1248	{
1249		const VkClearValue			clearValue		= makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
1250		const VkRenderPassBeginInfo	passBeginParams	=
1251		{
1252			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
1253			DE_NULL,
1254			*m_renderPass,
1255			curFramebuffer,
1256			{
1257				{ 0, 0 },
1258				{ (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y() }
1259			},													// renderArea
1260			1u,													// clearValueCount
1261			&clearValue,										// pClearValues
1262		};
1263		m_vkd.cmdBeginRenderPass(cmdBuffer, &passBeginParams, VK_SUBPASS_CONTENTS_INLINE);
1264	}
1265
1266	m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1267
1268	{
1269		const VkDeviceSize bindingOffset = 0;
1270		m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
1271	}
1272
1273	m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
1274	m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1275	m_vkd.cmdEndRenderPass(cmdBuffer);
1276
1277	VK_CHECK(m_vkd.endCommandBuffer(cmdBuffer));
1278}
1279
1280void TriangleRenderer::getPrograms (SourceCollections& dst)
1281{
1282	dst.glslSources.add("tri-vert") << glu::VertexSource(
1283		"#version 310 es\n"
1284		"layout(location = 0) in highp vec4 a_position;\n"
1285		"layout(push_constant) uniform FrameData\n"
1286		"{\n"
1287		"    highp uint frameNdx;\n"
1288		"} frameData;\n"
1289		"void main (void)\n"
1290		"{\n"
1291		"    highp float angle = float(frameData.frameNdx) / 100.0;\n"
1292		"    highp float c     = cos(angle);\n"
1293		"    highp float s     = sin(angle);\n"
1294		"    highp mat4  t     = mat4( c, -s,  0,  0,\n"
1295		"                              s,  c,  0,  0,\n"
1296		"                              0,  0,  1,  0,\n"
1297		"                              0,  0,  0,  1);\n"
1298		"    gl_Position = t * a_position;\n"
1299		"}\n");
1300	dst.glslSources.add("tri-frag") << glu::FragmentSource(
1301		"#version 310 es\n"
1302		"layout(location = 0) out lowp vec4 o_color;\n"
1303		"void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1304}
1305
1306typedef de::SharedPtr<Unique<VkCommandBuffer> >	CommandBufferSp;
1307typedef de::SharedPtr<Unique<VkFence> >			FenceSp;
1308typedef de::SharedPtr<Unique<VkSemaphore> >		SemaphoreSp;
1309
1310Move<VkFence> createFence (const DeviceInterface&	vkd,
1311						   const VkDevice			device)
1312{
1313	const VkFenceCreateInfo	fenceParams	=
1314	{
1315		VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1316		DE_NULL,
1317		(VkFenceCreateFlags)0,
1318	};
1319	return vk::createFence(vkd, device, &fenceParams);
1320}
1321
1322vector<FenceSp> createFences (const DeviceInterface&	vkd,
1323							  const VkDevice			device,
1324							  size_t					numFences)
1325{
1326	vector<FenceSp> fences(numFences);
1327
1328	for (size_t ndx = 0; ndx < numFences; ++ndx)
1329		fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
1330
1331	return fences;
1332}
1333
1334Move<VkSemaphore> createSemaphore (const DeviceInterface&	vkd,
1335								   const VkDevice			device)
1336{
1337	const VkSemaphoreCreateInfo	semaphoreParams	=
1338	{
1339		VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
1340		DE_NULL,
1341		(VkSemaphoreCreateFlags)0,
1342	};
1343	return vk::createSemaphore(vkd, device, &semaphoreParams);
1344}
1345
1346vector<SemaphoreSp> createSemaphores (const DeviceInterface&	vkd,
1347									  const VkDevice			device,
1348									  size_t					numSemaphores)
1349{
1350	vector<SemaphoreSp> semaphores(numSemaphores);
1351
1352	for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1353		semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
1354
1355	return semaphores;
1356}
1357
1358Move<VkCommandPool> createCommandPool (const DeviceInterface&	vkd,
1359									   const VkDevice			device,
1360									   VkCommandPoolCreateFlags	flags,
1361									   deUint32					queueFamilyIndex)
1362{
1363	const VkCommandPoolCreateInfo	commandPoolParams	=
1364	{
1365		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1366		DE_NULL,
1367		flags,
1368		queueFamilyIndex
1369	};
1370
1371	return createCommandPool(vkd, device, &commandPoolParams);
1372}
1373
1374vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface&		vkd,
1375												const VkDevice				device,
1376												const VkCommandPool			commandPool,
1377												const VkCommandBufferLevel	level,
1378												const size_t				numCommandBuffers)
1379{
1380	const VkCommandBufferAllocateInfo	allocInfo	=
1381	{
1382		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1383		DE_NULL,
1384		commandPool,
1385		level,
1386		1u,
1387	};
1388
1389	vector<CommandBufferSp>				buffers		(numCommandBuffers);
1390
1391	for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1392		buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, &allocInfo)));
1393
1394	return buffers;
1395}
1396
1397tcu::TestStatus basicRenderTest (Context& context, Type wsiType)
1398{
1399	const tcu::UVec2				desiredSize					(256, 256);
1400	const InstanceHelper			instHelper					(context, wsiType);
1401	const NativeObjects				native						(context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1402	const Unique<VkSurfaceKHR>		surface						(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1403	const DeviceHelper				devHelper					(context, instHelper.vki, *instHelper.instance, *surface);
1404	const DeviceInterface&			vkd							= devHelper.vkd;
1405	const VkDevice					device						= *devHelper.device;
1406	SimpleAllocator					allocator					(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1407	const VkSwapchainCreateInfoKHR	swapchainInfo				= getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1408	const Unique<VkSwapchainKHR>	swapchain					(createSwapchainKHR(vkd, device, &swapchainInfo));
1409	const vector<VkImage>			swapchainImages				= getSwapchainImages(vkd, device, *swapchain);
1410
1411	const TriangleRenderer			renderer					(vkd,
1412																 device,
1413																 allocator,
1414																 context.getBinaryCollection(),
1415																 swapchainImages,
1416																 swapchainInfo.imageFormat,
1417																 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1418
1419	const Unique<VkCommandPool>		commandPool					(createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1420
1421	const size_t					maxQueuedFrames				= swapchainImages.size()*2;
1422
1423	// We need to keep hold of fences from vkAcquireNextImageKHR to actually
1424	// limit number of frames we allow to be queued.
1425	const vector<FenceSp>			imageReadyFences			(createFences(vkd, device, maxQueuedFrames));
1426
1427	// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1428	// the semaphore in same time as the fence we use to meter rendering.
1429	const vector<SemaphoreSp>		imageReadySemaphores		(createSemaphores(vkd, device, maxQueuedFrames+1));
1430
1431	// For rest we simply need maxQueuedFrames as we will wait for image
1432	// from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1433	// previous uses must have completed.
1434	const vector<SemaphoreSp>		renderingCompleteSemaphores	(createSemaphores(vkd, device, maxQueuedFrames));
1435	const vector<CommandBufferSp>	commandBuffers				(allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1436
1437	try
1438	{
1439		const deUint32	numFramesToRender	= 60*10;
1440
1441		for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1442		{
1443			const VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
1444			const VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1445			deUint32			imageNdx			= ~0u;
1446
1447			if (frameNdx >= maxQueuedFrames)
1448				VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1449
1450			VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1451
1452			{
1453				const VkResult	acquireResult	= vkd.acquireNextImageKHR(device,
1454																		  *swapchain,
1455																		  std::numeric_limits<deUint64>::max(),
1456																		  imageReadySemaphore,
1457																		  imageReadyFence,
1458																		  &imageNdx);
1459
1460				if (acquireResult == VK_SUBOPTIMAL_KHR)
1461					context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1462				else
1463					VK_CHECK(acquireResult);
1464			}
1465
1466			TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1467
1468			{
1469				const VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1470				const VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
1471				const VkPipelineStageFlags	waitDstStage				= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1472				const VkSubmitInfo			submitInfo					=
1473				{
1474					VK_STRUCTURE_TYPE_SUBMIT_INFO,
1475					DE_NULL,
1476					1u,
1477					&imageReadySemaphore,
1478					&waitDstStage,
1479					1u,
1480					&commandBuffer,
1481					1u,
1482					&renderingCompleteSemaphore
1483				};
1484				const VkPresentInfoKHR		presentInfo					=
1485				{
1486					VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1487					DE_NULL,
1488					1u,
1489					&renderingCompleteSemaphore,
1490					1u,
1491					&*swapchain,
1492					&imageNdx,
1493					(VkResult*)DE_NULL
1494				};
1495
1496				renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1497				VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, (VkFence)0));
1498				VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1499			}
1500		}
1501
1502		VK_CHECK(vkd.deviceWaitIdle(device));
1503	}
1504	catch (...)
1505	{
1506		// Make sure device is idle before destroying resources
1507		vkd.deviceWaitIdle(device);
1508		throw;
1509	}
1510
1511	return tcu::TestStatus::pass("Rendering tests succeeded");
1512}
1513
1514vector<tcu::UVec2> getSwapchainSizeSequence (const VkSurfaceCapabilitiesKHR& capabilities, const tcu::UVec2& defaultSize)
1515{
1516	vector<tcu::UVec2> sizes(3);
1517	sizes[0] = defaultSize / 2u;
1518	sizes[1] = defaultSize;
1519	sizes[2] = defaultSize * 2u;
1520
1521	for (deUint32 i = 0; i < sizes.size(); ++i)
1522	{
1523		sizes[i].x() = de::clamp(sizes[i].x(), capabilities.minImageExtent.width,  capabilities.maxImageExtent.width);
1524		sizes[i].y() = de::clamp(sizes[i].y(), capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
1525	}
1526
1527	return sizes;
1528}
1529
1530tcu::TestStatus resizeSwapchainTest (Context& context, Type wsiType)
1531{
1532	const tcu::UVec2				desiredSize			(256, 256);
1533	const InstanceHelper			instHelper			(context, wsiType);
1534	const NativeObjects				native				(context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1535	const Unique<VkSurfaceKHR>		surface				(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1536	const DeviceHelper				devHelper			(context, instHelper.vki, *instHelper.instance, *surface);
1537	const PlatformProperties&		platformProperties	= getPlatformProperties(wsiType);
1538	const VkSurfaceCapabilitiesKHR	capabilities		= getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
1539	const DeviceInterface&			vkd					= devHelper.vkd;
1540	const VkDevice					device				= *devHelper.device;
1541	SimpleAllocator					allocator			(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1542	vector<tcu::UVec2>				sizes				= getSwapchainSizeSequence(capabilities, desiredSize);
1543	Move<VkSwapchainKHR>			prevSwapchain;
1544
1545	DE_ASSERT(platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE);
1546	DE_UNREF(platformProperties);
1547
1548	for (deUint32 sizeNdx = 0; sizeNdx < sizes.size(); ++sizeNdx)
1549	{
1550		// \todo [2016-05-30 jesse] This test currently waits for idle and
1551		// recreates way more than necessary when recreating the swapchain. Make
1552		// it match expected real app behavior better by smoothly switching from
1553		// old to new swapchain. Once that is done, it will also be possible to
1554		// test creating a new swapchain while images from the previous one are
1555		// still acquired.
1556
1557		VkSwapchainCreateInfoKHR		swapchainInfo				= getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, sizes[sizeNdx], 2);
1558		swapchainInfo.oldSwapchain = *prevSwapchain;
1559
1560		Move<VkSwapchainKHR>			swapchain					(createSwapchainKHR(vkd, device, &swapchainInfo));
1561		const vector<VkImage>			swapchainImages				= getSwapchainImages(vkd, device, *swapchain);
1562		const TriangleRenderer			renderer					(vkd,
1563																	device,
1564																	allocator,
1565																	context.getBinaryCollection(),
1566																	swapchainImages,
1567																	swapchainInfo.imageFormat,
1568																	tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1569		const Unique<VkCommandPool>		commandPool					(createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1570		const size_t					maxQueuedFrames				= swapchainImages.size()*2;
1571
1572		// We need to keep hold of fences from vkAcquireNextImageKHR to actually
1573		// limit number of frames we allow to be queued.
1574		const vector<FenceSp>			imageReadyFences			(createFences(vkd, device, maxQueuedFrames));
1575
1576		// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1577		// the semaphore in same time as the fence we use to meter rendering.
1578		const vector<SemaphoreSp>		imageReadySemaphores		(createSemaphores(vkd, device, maxQueuedFrames+1));
1579
1580		// For rest we simply need maxQueuedFrames as we will wait for image
1581		// from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1582		// previous uses must have completed.
1583		const vector<SemaphoreSp>		renderingCompleteSemaphores	(createSemaphores(vkd, device, maxQueuedFrames));
1584		const vector<CommandBufferSp>	commandBuffers				(allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1585
1586		try
1587		{
1588			const deUint32	numFramesToRender	= 60;
1589
1590			for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1591			{
1592				const VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
1593				const VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1594				deUint32			imageNdx			= ~0u;
1595
1596				if (frameNdx >= maxQueuedFrames)
1597					VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1598
1599				VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1600
1601				{
1602					const VkResult	acquireResult	= vkd.acquireNextImageKHR(device,
1603																			  *swapchain,
1604																			  std::numeric_limits<deUint64>::max(),
1605																			  imageReadySemaphore,
1606																			  imageReadyFence,
1607																			  &imageNdx);
1608
1609					if (acquireResult == VK_SUBOPTIMAL_KHR)
1610						context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1611					else
1612						VK_CHECK(acquireResult);
1613				}
1614
1615				TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1616
1617				{
1618					const VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1619					const VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
1620					const VkPipelineStageFlags	waitDstStage				= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1621					const VkSubmitInfo			submitInfo					=
1622					{
1623						VK_STRUCTURE_TYPE_SUBMIT_INFO,
1624						DE_NULL,
1625						1u,
1626						&imageReadySemaphore,
1627						&waitDstStage,
1628						1u,
1629						&commandBuffer,
1630						1u,
1631						&renderingCompleteSemaphore
1632					};
1633					const VkPresentInfoKHR		presentInfo					=
1634					{
1635						VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1636						DE_NULL,
1637						1u,
1638						&renderingCompleteSemaphore,
1639						1u,
1640						&*swapchain,
1641						&imageNdx,
1642						(VkResult*)DE_NULL
1643					};
1644
1645					renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1646					VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, (VkFence)0));
1647					VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1648				}
1649			}
1650
1651			VK_CHECK(vkd.deviceWaitIdle(device));
1652
1653			prevSwapchain = swapchain;
1654		}
1655		catch (...)
1656		{
1657			// Make sure device is idle before destroying resources
1658			vkd.deviceWaitIdle(device);
1659			throw;
1660		}
1661	}
1662
1663	return tcu::TestStatus::pass("Resizing tests succeeded");
1664}
1665
1666tcu::TestStatus getImagesIncompleteResultTest (Context& context, Type wsiType)
1667{
1668	const tcu::UVec2				desiredSize		(256, 256);
1669	const InstanceHelper			instHelper		(context, wsiType);
1670	const NativeObjects				native			(context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1671	const Unique<VkSurfaceKHR>		surface			(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1672	const DeviceHelper				devHelper		(context, instHelper.vki, *instHelper.instance, *surface);
1673	const VkSwapchainCreateInfoKHR	swapchainInfo	= getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1674	const Unique<VkSwapchainKHR>	swapchain		(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
1675
1676	vector<VkImage>		swapchainImages	= getSwapchainImages(devHelper.vkd, *devHelper.device, *swapchain);
1677
1678	ValidateQueryBits::fillBits(swapchainImages.begin(), swapchainImages.end());
1679
1680	const deUint32		usedCount		= static_cast<deUint32>(swapchainImages.size() / 2);
1681	deUint32			count			= usedCount;
1682	const VkResult		result			= devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &count, &swapchainImages[0]);
1683
1684	if (count != usedCount || result != VK_INCOMPLETE || !ValidateQueryBits::checkBits(swapchainImages.begin() + count, swapchainImages.end()))
1685		return tcu::TestStatus::fail("Get swapchain images didn't return VK_INCOMPLETE");
1686	else
1687		return tcu::TestStatus::pass("Get swapchain images tests succeeded");
1688}
1689
1690tcu::TestStatus destroyNullHandleSwapchainTest (Context& context, Type wsiType)
1691{
1692	const InstanceHelper		instHelper	(context, wsiType);
1693	const NativeObjects			native		(context, instHelper.supportedExtensions, wsiType);
1694	const Unique<VkSurfaceKHR>	surface		(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1695	const DeviceHelper			devHelper	(context, instHelper.vki, *instHelper.instance, *surface);
1696	const VkSwapchainKHR		nullHandle	= DE_NULL;
1697
1698	// Default allocator
1699	devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, DE_NULL);
1700
1701	// Custom allocator
1702	{
1703		AllocationCallbackRecorder	recordingAllocator	(getSystemAllocator(), 1u);
1704
1705		devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, recordingAllocator.getCallbacks());
1706
1707		if (recordingAllocator.getNumRecords() != 0u)
1708			return tcu::TestStatus::fail("Implementation allocated/freed the memory");
1709	}
1710
1711	return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
1712}
1713
1714void getBasicRenderPrograms (SourceCollections& dst, Type)
1715{
1716	TriangleRenderer::getPrograms(dst);
1717}
1718
1719void populateRenderGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1720{
1721	addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType);
1722}
1723
1724void populateGetImagesGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1725{
1726	addFunctionCase(testGroup, "incomplete", "Test VK_INCOMPLETE return code", getImagesIncompleteResultTest, wsiType);
1727}
1728
1729void populateModifyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1730{
1731	const PlatformProperties&	platformProperties	= getPlatformProperties(wsiType);
1732
1733	if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
1734	{
1735		addFunctionCaseWithPrograms(testGroup, "resize", "Resize Swapchain Test", getBasicRenderPrograms, resizeSwapchainTest, wsiType);
1736	}
1737
1738	// \todo [2016-05-30 jesse] Add tests for modifying preTransform, compositeAlpha, presentMode
1739}
1740
1741void populateDestroyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1742{
1743	addFunctionCase(testGroup, "null_handle", "Destroying a VK_NULL_HANDLE swapchain", destroyNullHandleSwapchainTest, wsiType);
1744}
1745
1746} // anonymous
1747
1748void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1749{
1750	addTestGroup(testGroup, "create",			"Create VkSwapchain with various parameters",					populateSwapchainGroup,		GroupParameters(wsiType, createSwapchainTest));
1751	addTestGroup(testGroup, "simulate_oom",		"Simulate OOM using callbacks during swapchain construction",	populateSwapchainGroup,		GroupParameters(wsiType, createSwapchainSimulateOOMTest));
1752	addTestGroup(testGroup, "render",			"Rendering Tests",												populateRenderGroup,		wsiType);
1753	addTestGroup(testGroup, "modify",			"Modify VkSwapchain",											populateModifyGroup,		wsiType);
1754	addTestGroup(testGroup, "destroy",			"Destroy VkSwapchain",											populateDestroyGroup,		wsiType);
1755	addTestGroup(testGroup, "get_images",		"Get swapchain images",											populateGetImagesGroup,		wsiType);
1756}
1757
1758} // wsi
1759} // vkt
1760