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