vktWsiSwapchainTests.cpp revision 2dd2c2dc560092c80b636551237758b62fae78d7
1783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann/*-------------------------------------------------------------------------
2398ee59bebad6835dab57b60157eff16d511709eMarc R. Hoffmann * Vulkan Conformance Tests
3783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann * ------------------------
4783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann *
5783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann * Copyright (c) 2016 Google Inc.
6783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann *
7783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann * Licensed under the Apache License, Version 2.0 (the "License");
8783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann * you may not use this file except in compliance with the License.
9783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann * You may obtain a copy of the License at
10783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann *
11783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann *      http://www.apache.org/licenses/LICENSE-2.0
12783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann *
13783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann * Unless required by applicable law or agreed to in writing, software
14783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann * distributed under the License is distributed on an "AS IS" BASIS,
15783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann * See the License for the specific language governing permissions and
17783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann * limitations under the License.
18783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann *
19783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann *//*!
20783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann * \file
21783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann * \brief VkSwapchain Tests
22783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann *//*--------------------------------------------------------------------*/
23783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann
24783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann#include "vktWsiSwapchainTests.hpp"
25783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann
26783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann#include "vktTestCaseUtil.hpp"
27783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann#include "vktTestGroupUtil.hpp"
28783aa63e134c6ba067e38e8a49207bd801693510Marc R. Hoffmann
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(),
611														 m_numPassingAllocs,
612														 DeterministicFailAllocator::MODE_DO_NOT_COUNT);
613		bool						gotOOM				= false;
614
615		log << TestLog::Message << "Testing with " << m_numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
616
617		try
618		{
619			const InstanceHelper					instHelper	(m_context, m_params.wsiType, failingAllocator.getCallbacks());
620			const NativeObjects						native		(m_context, instHelper.supportedExtensions, m_params.wsiType);
621			const Unique<VkSurfaceKHR>				surface		(createSurface(instHelper.vki,
622																			   *instHelper.instance,
623																			   m_params.wsiType,
624																			   *native.display,
625																			   *native.window,
626																			   failingAllocator.getCallbacks()));
627			const DeviceHelper						devHelper	(m_context, instHelper.vki, *instHelper.instance, *surface, failingAllocator.getCallbacks());
628			const vector<VkSwapchainCreateInfoKHR>	cases		(generateSwapchainParameterCases(m_params.wsiType, m_params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
629
630			// We don't care testing OOM paths in VkInstance, VkSurface, or VkDevice
631			// creation as they are tested elsewhere.
632			failingAllocator.setMode(DeterministicFailAllocator::MODE_COUNT_AND_FAIL);
633
634			for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
635			{
636				VkSwapchainCreateInfoKHR	curParams	= cases[caseNdx];
637
638				curParams.surface				= *surface;
639				curParams.queueFamilyIndexCount	= 1u;
640				curParams.pQueueFamilyIndices	= &devHelper.queueFamilyIndex;
641
642				log
643					<< TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << TestLog::EndMessage;
644
645				{
646					const Unique<VkSwapchainKHR>	swapchain	(createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
647				}
648			}
649		}
650		catch (const OutOfMemoryError& e)
651		{
652			log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
653			gotOOM = true;
654		}
655
656		if (!validateAndLog(log, allocationRecorder, 0u))
657			return tcu::TestStatus::fail("Detected invalid system allocation callback");
658
659		if (!gotOOM)
660		{
661			log << TestLog::Message << "Creating surface succeeded!" << TestLog::EndMessage;
662
663			if (m_numPassingAllocs == 0)
664				return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
665			else
666				return tcu::TestStatus::pass("OOM simulation completed");
667		}
668
669		m_numPassingAllocs++;
670		return tcu::TestStatus::incomplete();
671	}
672	else
673		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Creating swapchain did not succeed, callback limit exceeded");
674}
675
676struct GroupParameters
677{
678	typedef FunctionInstance1<TestParameters>::Function	Function;
679
680	Type		wsiType;
681	Function	function;
682
683	GroupParameters (Type wsiType_, Function function_)
684		: wsiType	(wsiType_)
685		, function	(function_)
686	{}
687
688	GroupParameters (void)
689		: wsiType	(TYPE_LAST)
690		, function	((Function)DE_NULL)
691	{}
692};
693
694void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
695{
696	for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
697	{
698		const TestDimension		testDimension	= (TestDimension)dimensionNdx;
699
700		addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
701	}
702}
703
704void populateSwapchainOOMGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
705{
706	for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
707	{
708		const TestDimension		testDimension	= (TestDimension)dimensionNdx;
709
710		testGroup->addChild(new InstanceFactory1<CreateSwapchainSimulateOOMTest, TestParameters>(testGroup->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, getTestDimensionName(testDimension), "", TestParameters(wsiType, testDimension)));
711	}
712}
713
714VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type						wsiType,
715													  const InstanceInterface&	vki,
716													  VkPhysicalDevice			physicalDevice,
717													  VkSurfaceKHR				surface,
718													  const tcu::UVec2&			desiredSize,
719													  deUint32					desiredImageCount)
720{
721	const VkSurfaceCapabilitiesKHR		capabilities		= getPhysicalDeviceSurfaceCapabilities(vki,
722																								   physicalDevice,
723																								   surface);
724	const vector<VkSurfaceFormatKHR>	formats				= getPhysicalDeviceSurfaceFormats(vki,
725																							  physicalDevice,
726																							  surface);
727	const PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
728	const VkSurfaceTransformFlagBitsKHR transform			= (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
729	const VkSwapchainCreateInfoKHR		parameters			=
730	{
731		VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
732		DE_NULL,
733		(VkSwapchainCreateFlagsKHR)0,
734		surface,
735		de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
736		formats[0].format,
737		formats[0].colorSpace,
738		(platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
739			? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
740		1u,									// imageArrayLayers
741		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
742		VK_SHARING_MODE_EXCLUSIVE,
743		0u,
744		(const deUint32*)DE_NULL,
745		transform,
746		VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
747		VK_PRESENT_MODE_FIFO_KHR,
748		VK_FALSE,							// clipped
749		(VkSwapchainKHR)0					// oldSwapchain
750	};
751
752	return parameters;
753}
754
755typedef de::SharedPtr<Unique<VkImageView> >		ImageViewSp;
756typedef de::SharedPtr<Unique<VkFramebuffer> >	FramebufferSp;
757
758class TriangleRenderer
759{
760public:
761									TriangleRenderer	(const DeviceInterface&		vkd,
762														 const VkDevice				device,
763														 Allocator&					allocator,
764														 const BinaryCollection&	binaryRegistry,
765														 const vector<VkImage>		swapchainImages,
766														 const VkFormat				framebufferFormat,
767														 const UVec2&				renderSize);
768									~TriangleRenderer	(void);
769
770	void							recordFrame			(VkCommandBuffer			cmdBuffer,
771														 deUint32					imageNdx,
772														 deUint32					frameNdx) const;
773
774	static void						getPrograms			(SourceCollections& dst);
775
776private:
777	static Move<VkRenderPass>		createRenderPass	(const DeviceInterface&		vkd,
778														 const VkDevice				device,
779														 const VkFormat				colorAttachmentFormat);
780	static Move<VkPipelineLayout>	createPipelineLayout(const DeviceInterface&		vkd,
781														 VkDevice					device);
782	static Move<VkPipeline>			createPipeline		(const DeviceInterface&		vkd,
783														 const VkDevice				device,
784														 const VkRenderPass			renderPass,
785														 const VkPipelineLayout		pipelineLayout,
786														 const BinaryCollection&	binaryCollection,
787														 const UVec2&				renderSize);
788
789	static Move<VkImageView>		createAttachmentView(const DeviceInterface&		vkd,
790														 const VkDevice				device,
791														 const VkImage				image,
792														 const VkFormat				format);
793	static Move<VkFramebuffer>		createFramebuffer	(const DeviceInterface&		vkd,
794														 const VkDevice				device,
795														 const VkRenderPass			renderPass,
796														 const VkImageView			colorAttachment,
797														 const UVec2&				renderSize);
798
799	static Move<VkBuffer>			createBuffer		(const DeviceInterface&		vkd,
800														 VkDevice					device,
801														 VkDeviceSize				size,
802														 VkBufferUsageFlags			usage);
803
804	const DeviceInterface&			m_vkd;
805
806	const vector<VkImage>			m_swapchainImages;
807	const tcu::UVec2				m_renderSize;
808
809	const Unique<VkRenderPass>		m_renderPass;
810	const Unique<VkPipelineLayout>	m_pipelineLayout;
811	const Unique<VkPipeline>		m_pipeline;
812
813	const Unique<VkBuffer>			m_vertexBuffer;
814	const UniquePtr<Allocation>		m_vertexBufferMemory;
815
816	vector<ImageViewSp>				m_attachmentViews;
817	vector<FramebufferSp>			m_framebuffers;
818};
819
820Move<VkRenderPass> TriangleRenderer::createRenderPass (const DeviceInterface&	vkd,
821													   const VkDevice			device,
822													   const VkFormat			colorAttachmentFormat)
823{
824	const VkAttachmentDescription	colorAttDesc		=
825	{
826		(VkAttachmentDescriptionFlags)0,
827		colorAttachmentFormat,
828		VK_SAMPLE_COUNT_1_BIT,
829		VK_ATTACHMENT_LOAD_OP_CLEAR,
830		VK_ATTACHMENT_STORE_OP_STORE,
831		VK_ATTACHMENT_LOAD_OP_DONT_CARE,
832		VK_ATTACHMENT_STORE_OP_DONT_CARE,
833		VK_IMAGE_LAYOUT_UNDEFINED,
834		VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
835	};
836	const VkAttachmentReference		colorAttRef			=
837	{
838		0u,
839		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
840	};
841	const VkSubpassDescription		subpassDesc			=
842	{
843		(VkSubpassDescriptionFlags)0u,
844		VK_PIPELINE_BIND_POINT_GRAPHICS,
845		0u,							// inputAttachmentCount
846		DE_NULL,					// pInputAttachments
847		1u,							// colorAttachmentCount
848		&colorAttRef,				// pColorAttachments
849		DE_NULL,					// pResolveAttachments
850		DE_NULL,					// depthStencilAttachment
851		0u,							// preserveAttachmentCount
852		DE_NULL,					// pPreserveAttachments
853	};
854	const VkSubpassDependency		dependencies[]		=
855	{
856		{
857			VK_SUBPASS_EXTERNAL,	// srcSubpass
858			0u,						// dstSubpass
859			VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
860			VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
861			VK_ACCESS_MEMORY_READ_BIT,
862			(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
863			 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
864			VK_DEPENDENCY_BY_REGION_BIT
865		},
866		{
867			0u,						// srcSubpass
868			VK_SUBPASS_EXTERNAL,	// dstSubpass
869			VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
870			VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
871			(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
872			 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
873			VK_ACCESS_MEMORY_READ_BIT,
874			VK_DEPENDENCY_BY_REGION_BIT
875		},
876	};
877	const VkRenderPassCreateInfo	renderPassParams	=
878	{
879		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
880		DE_NULL,
881		(VkRenderPassCreateFlags)0,
882		1u,
883		&colorAttDesc,
884		1u,
885		&subpassDesc,
886		DE_LENGTH_OF_ARRAY(dependencies),
887		dependencies,
888	};
889
890	return vk::createRenderPass(vkd, device, &renderPassParams);
891}
892
893Move<VkPipelineLayout> TriangleRenderer::createPipelineLayout (const DeviceInterface&	vkd,
894															   const VkDevice			device)
895{
896	const VkPushConstantRange						pushConstantRange		=
897	{
898		VK_SHADER_STAGE_VERTEX_BIT,
899		0u,											// offset
900		(deUint32)sizeof(deUint32),					// size
901	};
902	const VkPipelineLayoutCreateInfo				pipelineLayoutParams	=
903	{
904		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
905		DE_NULL,
906		(vk::VkPipelineLayoutCreateFlags)0,
907		0u,											// setLayoutCount
908		DE_NULL,									// pSetLayouts
909		1u,
910		&pushConstantRange,
911	};
912
913	return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
914}
915
916Move<VkPipeline> TriangleRenderer::createPipeline (const DeviceInterface&	vkd,
917												   const VkDevice			device,
918												   const VkRenderPass		renderPass,
919												   const VkPipelineLayout	pipelineLayout,
920												   const BinaryCollection&	binaryCollection,
921												   const UVec2&				renderSize)
922{
923	// \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
924	//		 and can be deleted immediately following that call.
925	const Unique<VkShaderModule>					vertShaderModule		(createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
926	const Unique<VkShaderModule>					fragShaderModule		(createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
927
928	const VkSpecializationInfo						emptyShaderSpecParams	=
929	{
930		0u,											// mapEntryCount
931		DE_NULL,									// pMap
932		0,											// dataSize
933		DE_NULL,									// pData
934	};
935	const VkPipelineShaderStageCreateInfo			shaderStageParams[]		=
936	{
937		{
938			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
939			DE_NULL,
940			(VkPipelineShaderStageCreateFlags)0,
941			VK_SHADER_STAGE_VERTEX_BIT,
942			*vertShaderModule,
943			"main",
944			&emptyShaderSpecParams,
945		},
946		{
947			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
948			DE_NULL,
949			(VkPipelineShaderStageCreateFlags)0,
950			VK_SHADER_STAGE_FRAGMENT_BIT,
951			*fragShaderModule,
952			"main",
953			&emptyShaderSpecParams,
954		}
955	};
956	const VkPipelineDepthStencilStateCreateInfo		depthStencilParams		=
957	{
958		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
959		DE_NULL,
960		(VkPipelineDepthStencilStateCreateFlags)0,
961		DE_FALSE,									// depthTestEnable
962		DE_FALSE,									// depthWriteEnable
963		VK_COMPARE_OP_ALWAYS,						// depthCompareOp
964		DE_FALSE,									// depthBoundsTestEnable
965		DE_FALSE,									// stencilTestEnable
966		{
967			VK_STENCIL_OP_KEEP,							// failOp
968			VK_STENCIL_OP_KEEP,							// passOp
969			VK_STENCIL_OP_KEEP,							// depthFailOp
970			VK_COMPARE_OP_ALWAYS,						// compareOp
971			0u,											// compareMask
972			0u,											// writeMask
973			0u,											// reference
974		},											// front
975		{
976			VK_STENCIL_OP_KEEP,							// failOp
977			VK_STENCIL_OP_KEEP,							// passOp
978			VK_STENCIL_OP_KEEP,							// depthFailOp
979			VK_COMPARE_OP_ALWAYS,						// compareOp
980			0u,											// compareMask
981			0u,											// writeMask
982			0u,											// reference
983		},											// back
984		-1.0f,										// minDepthBounds
985		+1.0f,										// maxDepthBounds
986	};
987	const VkViewport								viewport0				=
988	{
989		0.0f,										// x
990		0.0f,										// y
991		(float)renderSize.x(),						// width
992		(float)renderSize.y(),						// height
993		0.0f,										// minDepth
994		1.0f,										// maxDepth
995	};
996	const VkRect2D									scissor0				=
997	{
998		{ 0u, 0u, },								// offset
999		{ renderSize.x(), renderSize.y() },			// extent
1000	};
1001	const VkPipelineViewportStateCreateInfo			viewportParams			=
1002	{
1003		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
1004		DE_NULL,
1005		(VkPipelineViewportStateCreateFlags)0,
1006		1u,
1007		&viewport0,
1008		1u,
1009		&scissor0
1010	};
1011	const VkPipelineMultisampleStateCreateInfo		multisampleParams		=
1012	{
1013		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
1014		DE_NULL,
1015		(VkPipelineMultisampleStateCreateFlags)0,
1016		VK_SAMPLE_COUNT_1_BIT,						// rasterizationSamples
1017		VK_FALSE,									// sampleShadingEnable
1018		0.0f,										// minSampleShading
1019		(const VkSampleMask*)DE_NULL,				// sampleMask
1020		VK_FALSE,									// alphaToCoverageEnable
1021		VK_FALSE,									// alphaToOneEnable
1022	};
1023	const VkPipelineRasterizationStateCreateInfo	rasterParams			=
1024	{
1025		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
1026		DE_NULL,
1027		(VkPipelineRasterizationStateCreateFlags)0,
1028		VK_FALSE,									// depthClampEnable
1029		VK_FALSE,									// rasterizerDiscardEnable
1030		VK_POLYGON_MODE_FILL,						// polygonMode
1031		VK_CULL_MODE_NONE,							// cullMode
1032		VK_FRONT_FACE_COUNTER_CLOCKWISE,			// frontFace
1033		VK_FALSE,									// depthBiasEnable
1034		0.0f,										// depthBiasConstantFactor
1035		0.0f,										// depthBiasClamp
1036		0.0f,										// depthBiasSlopeFactor
1037		1.0f,										// lineWidth
1038	};
1039	const VkPipelineInputAssemblyStateCreateInfo	inputAssemblyParams		=
1040	{
1041		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
1042		DE_NULL,
1043		(VkPipelineInputAssemblyStateCreateFlags)0,
1044		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
1045		DE_FALSE,									// primitiveRestartEnable
1046	};
1047	const VkVertexInputBindingDescription			vertexBinding0			=
1048	{
1049		0u,											// binding
1050		(deUint32)sizeof(tcu::Vec4),				// stride
1051		VK_VERTEX_INPUT_RATE_VERTEX,				// inputRate
1052	};
1053	const VkVertexInputAttributeDescription			vertexAttrib0			=
1054	{
1055		0u,											// location
1056		0u,											// binding
1057		VK_FORMAT_R32G32B32A32_SFLOAT,				// format
1058		0u,											// offset
1059	};
1060	const VkPipelineVertexInputStateCreateInfo		vertexInputStateParams	=
1061	{
1062		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
1063		DE_NULL,
1064		(VkPipelineVertexInputStateCreateFlags)0,
1065		1u,
1066		&vertexBinding0,
1067		1u,
1068		&vertexAttrib0,
1069	};
1070	const VkPipelineColorBlendAttachmentState		attBlendParams0			=
1071	{
1072		VK_FALSE,									// blendEnable
1073		VK_BLEND_FACTOR_ONE,						// srcColorBlendFactor
1074		VK_BLEND_FACTOR_ZERO,						// dstColorBlendFactor
1075		VK_BLEND_OP_ADD,							// colorBlendOp
1076		VK_BLEND_FACTOR_ONE,						// srcAlphaBlendFactor
1077		VK_BLEND_FACTOR_ZERO,						// dstAlphaBlendFactor
1078		VK_BLEND_OP_ADD,							// alphaBlendOp
1079		(VK_COLOR_COMPONENT_R_BIT|
1080		 VK_COLOR_COMPONENT_G_BIT|
1081		 VK_COLOR_COMPONENT_B_BIT|
1082		 VK_COLOR_COMPONENT_A_BIT),					// colorWriteMask
1083	};
1084	const VkPipelineColorBlendStateCreateInfo		blendParams				=
1085	{
1086		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
1087		DE_NULL,
1088		(VkPipelineColorBlendStateCreateFlags)0,
1089		VK_FALSE,									// logicOpEnable
1090		VK_LOGIC_OP_COPY,
1091		1u,
1092		&attBlendParams0,
1093		{ 0.0f, 0.0f, 0.0f, 0.0f },					// blendConstants[4]
1094	};
1095	const VkGraphicsPipelineCreateInfo				pipelineParams			=
1096	{
1097		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
1098		DE_NULL,
1099		(VkPipelineCreateFlags)0,
1100		(deUint32)DE_LENGTH_OF_ARRAY(shaderStageParams),
1101		shaderStageParams,
1102		&vertexInputStateParams,
1103		&inputAssemblyParams,
1104		(const VkPipelineTessellationStateCreateInfo*)DE_NULL,
1105		&viewportParams,
1106		&rasterParams,
1107		&multisampleParams,
1108		&depthStencilParams,
1109		&blendParams,
1110		(const VkPipelineDynamicStateCreateInfo*)DE_NULL,
1111		pipelineLayout,
1112		renderPass,
1113		0u,											// subpass
1114		DE_NULL,									// basePipelineHandle
1115		0u,											// basePipelineIndex
1116	};
1117
1118	return vk::createGraphicsPipeline(vkd, device, (VkPipelineCache)0, &pipelineParams);
1119}
1120
1121Move<VkImageView> TriangleRenderer::createAttachmentView (const DeviceInterface&	vkd,
1122														  const VkDevice			device,
1123														  const VkImage				image,
1124														  const VkFormat			format)
1125{
1126	const VkImageViewCreateInfo		viewParams	=
1127	{
1128		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1129		DE_NULL,
1130		(VkImageViewCreateFlags)0,
1131		image,
1132		VK_IMAGE_VIEW_TYPE_2D,
1133		format,
1134		vk::makeComponentMappingRGBA(),
1135		{
1136			VK_IMAGE_ASPECT_COLOR_BIT,
1137			0u,						// baseMipLevel
1138			1u,						// levelCount
1139			0u,						// baseArrayLayer
1140			1u,						// layerCount
1141		},
1142	};
1143
1144	return vk::createImageView(vkd, device, &viewParams);
1145}
1146
1147Move<VkFramebuffer> TriangleRenderer::createFramebuffer	(const DeviceInterface&		vkd,
1148														 const VkDevice				device,
1149														 const VkRenderPass			renderPass,
1150														 const VkImageView			colorAttachment,
1151														 const UVec2&				renderSize)
1152{
1153	const VkFramebufferCreateInfo	framebufferParams	=
1154	{
1155		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1156		DE_NULL,
1157		(VkFramebufferCreateFlags)0,
1158		renderPass,
1159		1u,
1160		&colorAttachment,
1161		renderSize.x(),
1162		renderSize.y(),
1163		1u,							// layers
1164	};
1165
1166	return vk::createFramebuffer(vkd, device, &framebufferParams);
1167}
1168
1169Move<VkBuffer> TriangleRenderer::createBuffer (const DeviceInterface&	vkd,
1170											   VkDevice					device,
1171											   VkDeviceSize				size,
1172											   VkBufferUsageFlags		usage)
1173{
1174	const VkBufferCreateInfo	bufferParams	=
1175	{
1176		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1177		DE_NULL,
1178		(VkBufferCreateFlags)0,
1179		size,
1180		usage,
1181		VK_SHARING_MODE_EXCLUSIVE,
1182		0,
1183		DE_NULL
1184	};
1185
1186	return vk::createBuffer(vkd, device, &bufferParams);
1187}
1188
1189TriangleRenderer::TriangleRenderer (const DeviceInterface&	vkd,
1190									const VkDevice			device,
1191									Allocator&				allocator,
1192									const BinaryCollection&	binaryRegistry,
1193									const vector<VkImage>	swapchainImages,
1194									const VkFormat			framebufferFormat,
1195									const UVec2&			renderSize)
1196	: m_vkd					(vkd)
1197	, m_swapchainImages		(swapchainImages)
1198	, m_renderSize			(renderSize)
1199	, m_renderPass			(createRenderPass(vkd, device, framebufferFormat))
1200	, m_pipelineLayout		(createPipelineLayout(vkd, device))
1201	, m_pipeline			(createPipeline(vkd, device, *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
1202	, m_vertexBuffer		(createBuffer(vkd, device, (VkDeviceSize)(sizeof(float)*4*3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
1203	, m_vertexBufferMemory	(allocator.allocate(getBufferMemoryRequirements(vkd, device, *m_vertexBuffer),
1204							 MemoryRequirement::HostVisible))
1205{
1206	m_attachmentViews.resize(swapchainImages.size());
1207	m_framebuffers.resize(swapchainImages.size());
1208
1209	for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
1210	{
1211		m_attachmentViews[imageNdx]	= ImageViewSp(new Unique<VkImageView>(createAttachmentView(vkd, device, swapchainImages[imageNdx], framebufferFormat)));
1212		m_framebuffers[imageNdx]	= FramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vkd, device, *m_renderPass, **m_attachmentViews[imageNdx], renderSize)));
1213	}
1214
1215	VK_CHECK(vkd.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset()));
1216
1217	{
1218		const VkMappedMemoryRange	memRange	=
1219		{
1220			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
1221			DE_NULL,
1222			m_vertexBufferMemory->getMemory(),
1223			m_vertexBufferMemory->getOffset(),
1224			VK_WHOLE_SIZE
1225		};
1226		const tcu::Vec4				vertices[]	=
1227		{
1228			tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
1229			tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
1230			tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
1231		};
1232		DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
1233
1234		deMemcpy(m_vertexBufferMemory->getHostPtr(), &vertices[0], sizeof(vertices));
1235		VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &memRange));
1236	}
1237}
1238
1239TriangleRenderer::~TriangleRenderer (void)
1240{
1241}
1242
1243void TriangleRenderer::recordFrame (VkCommandBuffer	cmdBuffer,
1244									deUint32		imageNdx,
1245									deUint32		frameNdx) const
1246{
1247	const VkFramebuffer	curFramebuffer	= **m_framebuffers[imageNdx];
1248
1249	{
1250		const VkCommandBufferBeginInfo	cmdBufBeginParams	=
1251		{
1252			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1253			DE_NULL,
1254			(VkCommandBufferUsageFlags)0,
1255			(const VkCommandBufferInheritanceInfo*)DE_NULL,
1256		};
1257		VK_CHECK(m_vkd.beginCommandBuffer(cmdBuffer, &cmdBufBeginParams));
1258	}
1259
1260	{
1261		const VkClearValue			clearValue		= makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
1262		const VkRenderPassBeginInfo	passBeginParams	=
1263		{
1264			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
1265			DE_NULL,
1266			*m_renderPass,
1267			curFramebuffer,
1268			{
1269				{ 0, 0 },
1270				{ (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y() }
1271			},													// renderArea
1272			1u,													// clearValueCount
1273			&clearValue,										// pClearValues
1274		};
1275		m_vkd.cmdBeginRenderPass(cmdBuffer, &passBeginParams, VK_SUBPASS_CONTENTS_INLINE);
1276	}
1277
1278	m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1279
1280	{
1281		const VkDeviceSize bindingOffset = 0;
1282		m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
1283	}
1284
1285	m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
1286	m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1287	m_vkd.cmdEndRenderPass(cmdBuffer);
1288
1289	VK_CHECK(m_vkd.endCommandBuffer(cmdBuffer));
1290}
1291
1292void TriangleRenderer::getPrograms (SourceCollections& dst)
1293{
1294	dst.glslSources.add("tri-vert") << glu::VertexSource(
1295		"#version 310 es\n"
1296		"layout(location = 0) in highp vec4 a_position;\n"
1297		"layout(push_constant) uniform FrameData\n"
1298		"{\n"
1299		"    highp uint frameNdx;\n"
1300		"} frameData;\n"
1301		"void main (void)\n"
1302		"{\n"
1303		"    highp float angle = float(frameData.frameNdx) / 100.0;\n"
1304		"    highp float c     = cos(angle);\n"
1305		"    highp float s     = sin(angle);\n"
1306		"    highp mat4  t     = mat4( c, -s,  0,  0,\n"
1307		"                              s,  c,  0,  0,\n"
1308		"                              0,  0,  1,  0,\n"
1309		"                              0,  0,  0,  1);\n"
1310		"    gl_Position = t * a_position;\n"
1311		"}\n");
1312	dst.glslSources.add("tri-frag") << glu::FragmentSource(
1313		"#version 310 es\n"
1314		"layout(location = 0) out lowp vec4 o_color;\n"
1315		"void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1316}
1317
1318typedef de::SharedPtr<Unique<VkCommandBuffer> >	CommandBufferSp;
1319typedef de::SharedPtr<Unique<VkFence> >			FenceSp;
1320typedef de::SharedPtr<Unique<VkSemaphore> >		SemaphoreSp;
1321
1322Move<VkFence> createFence (const DeviceInterface&	vkd,
1323						   const VkDevice			device)
1324{
1325	const VkFenceCreateInfo	fenceParams	=
1326	{
1327		VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1328		DE_NULL,
1329		(VkFenceCreateFlags)0,
1330	};
1331	return vk::createFence(vkd, device, &fenceParams);
1332}
1333
1334vector<FenceSp> createFences (const DeviceInterface&	vkd,
1335							  const VkDevice			device,
1336							  size_t					numFences)
1337{
1338	vector<FenceSp> fences(numFences);
1339
1340	for (size_t ndx = 0; ndx < numFences; ++ndx)
1341		fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
1342
1343	return fences;
1344}
1345
1346Move<VkSemaphore> createSemaphore (const DeviceInterface&	vkd,
1347								   const VkDevice			device)
1348{
1349	const VkSemaphoreCreateInfo	semaphoreParams	=
1350	{
1351		VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
1352		DE_NULL,
1353		(VkSemaphoreCreateFlags)0,
1354	};
1355	return vk::createSemaphore(vkd, device, &semaphoreParams);
1356}
1357
1358vector<SemaphoreSp> createSemaphores (const DeviceInterface&	vkd,
1359									  const VkDevice			device,
1360									  size_t					numSemaphores)
1361{
1362	vector<SemaphoreSp> semaphores(numSemaphores);
1363
1364	for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1365		semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
1366
1367	return semaphores;
1368}
1369
1370Move<VkCommandPool> createCommandPool (const DeviceInterface&	vkd,
1371									   const VkDevice			device,
1372									   VkCommandPoolCreateFlags	flags,
1373									   deUint32					queueFamilyIndex)
1374{
1375	const VkCommandPoolCreateInfo	commandPoolParams	=
1376	{
1377		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1378		DE_NULL,
1379		flags,
1380		queueFamilyIndex
1381	};
1382
1383	return createCommandPool(vkd, device, &commandPoolParams);
1384}
1385
1386vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface&		vkd,
1387												const VkDevice				device,
1388												const VkCommandPool			commandPool,
1389												const VkCommandBufferLevel	level,
1390												const size_t				numCommandBuffers)
1391{
1392	const VkCommandBufferAllocateInfo	allocInfo	=
1393	{
1394		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1395		DE_NULL,
1396		commandPool,
1397		level,
1398		1u,
1399	};
1400
1401	vector<CommandBufferSp>				buffers		(numCommandBuffers);
1402
1403	for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1404		buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, &allocInfo)));
1405
1406	return buffers;
1407}
1408
1409tcu::TestStatus basicRenderTest (Context& context, Type wsiType)
1410{
1411	const tcu::UVec2				desiredSize					(256, 256);
1412	const InstanceHelper			instHelper					(context, wsiType);
1413	const NativeObjects				native						(context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1414	const Unique<VkSurfaceKHR>		surface						(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1415	const DeviceHelper				devHelper					(context, instHelper.vki, *instHelper.instance, *surface);
1416	const DeviceInterface&			vkd							= devHelper.vkd;
1417	const VkDevice					device						= *devHelper.device;
1418	SimpleAllocator					allocator					(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1419	const VkSwapchainCreateInfoKHR	swapchainInfo				= getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1420	const Unique<VkSwapchainKHR>	swapchain					(createSwapchainKHR(vkd, device, &swapchainInfo));
1421	const vector<VkImage>			swapchainImages				= getSwapchainImages(vkd, device, *swapchain);
1422
1423	const TriangleRenderer			renderer					(vkd,
1424																 device,
1425																 allocator,
1426																 context.getBinaryCollection(),
1427																 swapchainImages,
1428																 swapchainInfo.imageFormat,
1429																 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1430
1431	const Unique<VkCommandPool>		commandPool					(createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1432
1433	const size_t					maxQueuedFrames				= swapchainImages.size()*2;
1434
1435	// We need to keep hold of fences from vkAcquireNextImageKHR to actually
1436	// limit number of frames we allow to be queued.
1437	const vector<FenceSp>			imageReadyFences			(createFences(vkd, device, maxQueuedFrames));
1438
1439	// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1440	// the semaphore in same time as the fence we use to meter rendering.
1441	const vector<SemaphoreSp>		imageReadySemaphores		(createSemaphores(vkd, device, maxQueuedFrames+1));
1442
1443	// For rest we simply need maxQueuedFrames as we will wait for image
1444	// from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1445	// previous uses must have completed.
1446	const vector<SemaphoreSp>		renderingCompleteSemaphores	(createSemaphores(vkd, device, maxQueuedFrames));
1447	const vector<CommandBufferSp>	commandBuffers				(allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1448
1449	try
1450	{
1451		const deUint32	numFramesToRender	= 60*10;
1452
1453		for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1454		{
1455			const VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
1456			const VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1457			deUint32			imageNdx			= ~0u;
1458
1459			if (frameNdx >= maxQueuedFrames)
1460				VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1461
1462			VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1463
1464			{
1465				const VkResult	acquireResult	= vkd.acquireNextImageKHR(device,
1466																		  *swapchain,
1467																		  std::numeric_limits<deUint64>::max(),
1468																		  imageReadySemaphore,
1469																		  imageReadyFence,
1470																		  &imageNdx);
1471
1472				if (acquireResult == VK_SUBOPTIMAL_KHR)
1473					context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1474				else
1475					VK_CHECK(acquireResult);
1476			}
1477
1478			TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1479
1480			{
1481				const VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1482				const VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
1483				const VkPipelineStageFlags	waitDstStage				= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1484				const VkSubmitInfo			submitInfo					=
1485				{
1486					VK_STRUCTURE_TYPE_SUBMIT_INFO,
1487					DE_NULL,
1488					1u,
1489					&imageReadySemaphore,
1490					&waitDstStage,
1491					1u,
1492					&commandBuffer,
1493					1u,
1494					&renderingCompleteSemaphore
1495				};
1496				const VkPresentInfoKHR		presentInfo					=
1497				{
1498					VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1499					DE_NULL,
1500					1u,
1501					&renderingCompleteSemaphore,
1502					1u,
1503					&*swapchain,
1504					&imageNdx,
1505					(VkResult*)DE_NULL
1506				};
1507
1508				renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1509				VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, (VkFence)0));
1510				VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1511			}
1512		}
1513
1514		VK_CHECK(vkd.deviceWaitIdle(device));
1515	}
1516	catch (...)
1517	{
1518		// Make sure device is idle before destroying resources
1519		vkd.deviceWaitIdle(device);
1520		throw;
1521	}
1522
1523	return tcu::TestStatus::pass("Rendering tests suceeded");
1524}
1525
1526vector<tcu::UVec2> getSwapchainSizeSequence (const VkSurfaceCapabilitiesKHR& capabilities, const tcu::UVec2& defaultSize)
1527{
1528	vector<tcu::UVec2> sizes(3);
1529	sizes[0] = defaultSize / 2u;
1530	sizes[1] = defaultSize;
1531	sizes[2] = defaultSize * 2u;
1532
1533	for (deUint32 i = 0; i < sizes.size(); ++i)
1534	{
1535		sizes[i].x() = de::clamp(sizes[i].x(), capabilities.minImageExtent.width,  capabilities.maxImageExtent.width);
1536		sizes[i].y() = de::clamp(sizes[i].y(), capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
1537	}
1538
1539	return sizes;
1540}
1541
1542tcu::TestStatus resizeSwapchainTest (Context& context, Type wsiType)
1543{
1544	const tcu::UVec2				desiredSize			(256, 256);
1545	const InstanceHelper			instHelper			(context, wsiType);
1546	const NativeObjects				native				(context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1547	const Unique<VkSurfaceKHR>		surface				(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1548	const DeviceHelper				devHelper			(context, instHelper.vki, *instHelper.instance, *surface);
1549	const PlatformProperties&		platformProperties	= getPlatformProperties(wsiType);
1550	const VkSurfaceCapabilitiesKHR	capabilities		= getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
1551	const DeviceInterface&			vkd					= devHelper.vkd;
1552	const VkDevice					device				= *devHelper.device;
1553	SimpleAllocator					allocator			(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1554	vector<tcu::UVec2>				sizes				= getSwapchainSizeSequence(capabilities, desiredSize);
1555	Move<VkSwapchainKHR>			prevSwapchain;
1556
1557	DE_ASSERT(platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE);
1558	DE_UNREF(platformProperties);
1559
1560	for (deUint32 sizeNdx = 0; sizeNdx < sizes.size(); ++sizeNdx)
1561	{
1562		// \todo [2016-05-30 jesse] This test currently waits for idle and
1563		// recreates way more than necessary when recreating the swapchain. Make
1564		// it match expected real app behavior better by smoothly switching from
1565		// old to new swapchain. Once that is done, it will also be possible to
1566		// test creating a new swapchain while images from the previous one are
1567		// still acquired.
1568
1569		VkSwapchainCreateInfoKHR		swapchainInfo				= getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, sizes[sizeNdx], 2);
1570		swapchainInfo.oldSwapchain = *prevSwapchain;
1571
1572		Move<VkSwapchainKHR>			swapchain					(createSwapchainKHR(vkd, device, &swapchainInfo));
1573		const vector<VkImage>			swapchainImages				= getSwapchainImages(vkd, device, *swapchain);
1574		const TriangleRenderer			renderer					(vkd,
1575																	device,
1576																	allocator,
1577																	context.getBinaryCollection(),
1578																	swapchainImages,
1579																	swapchainInfo.imageFormat,
1580																	tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1581		const Unique<VkCommandPool>		commandPool					(createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1582		const size_t					maxQueuedFrames				= swapchainImages.size()*2;
1583
1584		// We need to keep hold of fences from vkAcquireNextImageKHR to actually
1585		// limit number of frames we allow to be queued.
1586		const vector<FenceSp>			imageReadyFences			(createFences(vkd, device, maxQueuedFrames));
1587
1588		// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1589		// the semaphore in same time as the fence we use to meter rendering.
1590		const vector<SemaphoreSp>		imageReadySemaphores		(createSemaphores(vkd, device, maxQueuedFrames+1));
1591
1592		// For rest we simply need maxQueuedFrames as we will wait for image
1593		// from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1594		// previous uses must have completed.
1595		const vector<SemaphoreSp>		renderingCompleteSemaphores	(createSemaphores(vkd, device, maxQueuedFrames));
1596		const vector<CommandBufferSp>	commandBuffers				(allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1597
1598		try
1599		{
1600			const deUint32	numFramesToRender	= 60;
1601
1602			for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1603			{
1604				const VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
1605				const VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1606				deUint32			imageNdx			= ~0u;
1607
1608				if (frameNdx >= maxQueuedFrames)
1609					VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1610
1611				VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1612
1613				{
1614					const VkResult	acquireResult	= vkd.acquireNextImageKHR(device,
1615																			  *swapchain,
1616																			  std::numeric_limits<deUint64>::max(),
1617																			  imageReadySemaphore,
1618																			  imageReadyFence,
1619																			  &imageNdx);
1620
1621					if (acquireResult == VK_SUBOPTIMAL_KHR)
1622						context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1623					else
1624						VK_CHECK(acquireResult);
1625				}
1626
1627				TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1628
1629				{
1630					const VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1631					const VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
1632					const VkPipelineStageFlags	waitDstStage				= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1633					const VkSubmitInfo			submitInfo					=
1634					{
1635						VK_STRUCTURE_TYPE_SUBMIT_INFO,
1636						DE_NULL,
1637						1u,
1638						&imageReadySemaphore,
1639						&waitDstStage,
1640						1u,
1641						&commandBuffer,
1642						1u,
1643						&renderingCompleteSemaphore
1644					};
1645					const VkPresentInfoKHR		presentInfo					=
1646					{
1647						VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1648						DE_NULL,
1649						1u,
1650						&renderingCompleteSemaphore,
1651						1u,
1652						&*swapchain,
1653						&imageNdx,
1654						(VkResult*)DE_NULL
1655					};
1656
1657					renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1658					VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, (VkFence)0));
1659					VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1660				}
1661			}
1662
1663			VK_CHECK(vkd.deviceWaitIdle(device));
1664
1665			prevSwapchain = swapchain;
1666		}
1667		catch (...)
1668		{
1669			// Make sure device is idle before destroying resources
1670			vkd.deviceWaitIdle(device);
1671			throw;
1672		}
1673	}
1674
1675	return tcu::TestStatus::pass("Resizing tests suceeded");
1676}
1677
1678void getBasicRenderPrograms (SourceCollections& dst, Type)
1679{
1680	TriangleRenderer::getPrograms(dst);
1681}
1682
1683void populateRenderGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1684{
1685	addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType);
1686}
1687
1688void populateModifyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1689{
1690	const PlatformProperties&	platformProperties	= getPlatformProperties(wsiType);
1691
1692	if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
1693	{
1694		addFunctionCaseWithPrograms(testGroup, "resize", "Resize Swapchain Test", getBasicRenderPrograms, resizeSwapchainTest, wsiType);
1695	}
1696
1697	// \todo [2016-05-30 jesse] Add tests for modifying preTransform, compositeAlpha, presentMode
1698}
1699
1700} // anonymous
1701
1702void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1703{
1704	addTestGroup(testGroup, "create",			"Create VkSwapchain with various parameters",					populateSwapchainGroup,		GroupParameters(wsiType, createSwapchainTest));
1705	addTestGroup(testGroup, "simulate_oom",		"Simulate OOM using callbacks during swapchain construction",	populateSwapchainOOMGroup,	wsiType);
1706	addTestGroup(testGroup, "render",			"Rendering Tests",												populateRenderGroup,		wsiType);
1707	addTestGroup(testGroup, "modify",			"Modify VkSwapchain",											populateModifyGroup,		wsiType);
1708}
1709
1710} // wsi
1711} // vkt
1712