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