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