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