Home | History | Annotate | Download | only in protected_memory
      1 /*-------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2017 The Khronos Group Inc.
      6  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
      7  *
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *      http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  *
     20  *//*!
     21  * \file
     22  * \brief Protected memory interaction with VkSwapchain Tests
     23  *//*--------------------------------------------------------------------*/
     24 
     25 #include "vktProtectedMemWsiSwapchainTests.hpp"
     26 
     27 #include "vktTestCaseUtil.hpp"
     28 #include "vktTestGroupUtil.hpp"
     29 
     30 #include "vkDefs.hpp"
     31 #include "vkPlatform.hpp"
     32 #include "vkStrUtil.hpp"
     33 #include "vkRef.hpp"
     34 #include "vkRefUtil.hpp"
     35 #include "vkQueryUtil.hpp"
     36 #include "vkMemUtil.hpp"
     37 #include "vkDeviceUtil.hpp"
     38 #include "vkPrograms.hpp"
     39 #include "vkTypeUtil.hpp"
     40 #include "vkWsiPlatform.hpp"
     41 #include "vkWsiUtil.hpp"
     42 #include "vkAllocationCallbackUtil.hpp"
     43 
     44 #include "tcuTestLog.hpp"
     45 #include "tcuFormatUtil.hpp"
     46 #include "tcuPlatform.hpp"
     47 #include "tcuResultCollector.hpp"
     48 
     49 #include "deUniquePtr.hpp"
     50 #include "deStringUtil.hpp"
     51 #include "deArrayUtil.hpp"
     52 #include "deSharedPtr.hpp"
     53 
     54 #include <limits>
     55 
     56 #include "vktProtectedMemContext.hpp"
     57 #include "vktProtectedMemUtils.hpp"
     58 
     59 namespace vkt
     60 {
     61 namespace ProtectedMem
     62 {
     63 
     64 namespace
     65 {
     66 
     67 typedef std::vector<vk::VkExtensionProperties> Extensions;
     68 
     69 void checkAllSupported (const Extensions& supportedExtensions, const std::vector<std::string>& requiredExtensions)
     70 {
     71 	for (std::vector<std::string>::const_iterator requiredExtName = requiredExtensions.begin();
     72 		 requiredExtName != requiredExtensions.end();
     73 		 ++requiredExtName)
     74 	{
     75 		if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
     76 			TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
     77 	}
     78 }
     79 
     80 std::vector<std::string> getRequiredWsiExtensions (const Extensions&	supportedExtensions,
     81 												   vk::wsi::Type		wsiType)
     82 {
     83 	std::vector<std::string>	extensions;
     84 
     85 	extensions.push_back("VK_KHR_surface");
     86 	extensions.push_back(getExtensionName(wsiType));
     87 
     88 	// VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
     89 	// the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
     90 	// but using them without enabling the extension is not allowed. Thus we have
     91 	// two options:
     92 	//
     93 	// 1) Filter out non-core formats to stay within valid usage.
     94 	//
     95 	// 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
     96 	//
     97 	// We opt for (2) as it provides basic coverage for the extension as a bonus.
     98 	if (isExtensionSupported(supportedExtensions, vk::RequiredExtension("VK_EXT_swapchain_colorspace")))
     99 		extensions.push_back("VK_EXT_swapchain_colorspace");
    100 
    101 	checkAllSupported(supportedExtensions, extensions);
    102 
    103 	return extensions;
    104 }
    105 
    106 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform&	platform,
    107 											 const Extensions&		supportedExtensions,
    108 											 vk::wsi::Type			wsiType)
    109 {
    110 	try
    111 	{
    112 		return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
    113 	}
    114 	catch (const tcu::NotSupportedError& e)
    115 	{
    116 		if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))))
    117 		{
    118 			// If VK_KHR_{platform}_surface was supported, vk::Platform implementation
    119 			// must support creating native display & window for that WSI type.
    120 			throw tcu::TestError(e.getMessage());
    121 		}
    122 		else
    123 			throw;
    124 	}
    125 }
    126 
    127 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const tcu::Maybe<tcu::UVec2>& initialSize)
    128 {
    129 	try
    130 	{
    131 		return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
    132 	}
    133 	catch (const tcu::NotSupportedError& e)
    134 	{
    135 		// See createDisplay - assuming that wsi::Display was supported platform port
    136 		// should also support creating a window.
    137 		throw tcu::TestError(e.getMessage());
    138 	}
    139 }
    140 
    141 struct NativeObjects
    142 {
    143 	const de::UniquePtr<vk::wsi::Display>	display;
    144 	const de::UniquePtr<vk::wsi::Window>	window;
    145 
    146 	NativeObjects (Context&							context,
    147 				   const Extensions&				supportedExtensions,
    148 				   vk::wsi::Type					wsiType,
    149 				   const tcu::Maybe<tcu::UVec2>&	initialWindowSize = tcu::nothing<tcu::UVec2>())
    150 		: display				(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
    151 		, window				(createWindow(*display, initialWindowSize))
    152 	{}
    153 };
    154 
    155 enum TestDimension
    156 {
    157 	TEST_DIMENSION_MIN_IMAGE_COUNT = 0,	//!< Test all supported image counts
    158 	TEST_DIMENSION_IMAGE_FORMAT,		//!< Test all supported formats
    159 	TEST_DIMENSION_IMAGE_EXTENT,		//!< Test various (supported) extents
    160 	TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
    161 	TEST_DIMENSION_IMAGE_USAGE,
    162 	TEST_DIMENSION_IMAGE_SHARING_MODE,
    163 	TEST_DIMENSION_PRE_TRANSFORM,
    164 	TEST_DIMENSION_COMPOSITE_ALPHA,
    165 	TEST_DIMENSION_PRESENT_MODE,
    166 	TEST_DIMENSION_CLIPPED,
    167 
    168 	TEST_DIMENSION_LAST
    169 };
    170 
    171 const char* getTestDimensionName (TestDimension dimension)
    172 {
    173 	static const char* const s_names[] =
    174 	{
    175 		"min_image_count",
    176 		"image_format",
    177 		"image_extent",
    178 		"image_array_layers",
    179 		"image_usage",
    180 		"image_sharing_mode",
    181 		"pre_transform",
    182 		"composite_alpha",
    183 		"present_mode",
    184 		"clipped"
    185 	};
    186 	return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
    187 }
    188 
    189 struct TestParameters
    190 {
    191 	vk::wsi::Type	wsiType;
    192 	TestDimension	dimension;
    193 
    194 	TestParameters (vk::wsi::Type wsiType_, TestDimension dimension_)
    195 		: wsiType	(wsiType_)
    196 		, dimension	(dimension_)
    197 	{}
    198 
    199 	TestParameters (void)
    200 		: wsiType	(vk::wsi::TYPE_LAST)
    201 		, dimension	(TEST_DIMENSION_LAST)
    202 	{}
    203 };
    204 
    205 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type								wsiType,
    206 																		   TestDimension								dimension,
    207 																		   const ProtectedContext&						context,
    208 																		   const vk::VkSurfaceCapabilitiesKHR&			capabilities,
    209 																		   const std::vector<vk::VkSurfaceFormatKHR>&	formats,
    210 																		   const std::vector<vk::VkPresentModeKHR>&		presentModes)
    211 {
    212 	std::vector<vk::VkSwapchainCreateInfoKHR>	cases;
    213 	const vk::wsi::PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
    214 	const vk::VkSurfaceTransformFlagBitsKHR		defaultTransform	= (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
    215 																		? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
    216 	const vk::VkSwapchainCreateInfoKHR			baseParameters		=
    217 	{
    218 		vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
    219 		DE_NULL,
    220 		vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
    221 		(vk::VkSurfaceKHR)0,
    222 		capabilities.minImageCount,
    223 		formats[0].format,
    224 		formats[0].colorSpace,
    225 		(platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
    226 			? capabilities.minImageExtent : capabilities.currentExtent),
    227 		1u,									// imageArrayLayers
    228 		vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
    229 		vk::VK_SHARING_MODE_EXCLUSIVE,
    230 		0u,
    231 		(const deUint32*)DE_NULL,
    232 		defaultTransform,
    233 		vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
    234 		vk::VK_PRESENT_MODE_FIFO_KHR,
    235 		VK_FALSE,							// clipped
    236 		(vk::VkSwapchainKHR)0				// oldSwapchain
    237 	};
    238 
    239 	switch (dimension)
    240 	{
    241 		case TEST_DIMENSION_MIN_IMAGE_COUNT:
    242 		{
    243 			// Estimate how much memory each swapchain image consumes. This isn't perfect, since
    244 			// swapchain images may have additional constraints that equivalent non-swapchain
    245 			// images don't have. But it's the best we can do.
    246 			const vk::DeviceInterface&				vkd					= context.getDeviceInterface();
    247 			vk::VkDevice							device				= context.getDevice();
    248 			vk::VkMemoryRequirements				memoryRequirements;
    249 			{
    250 				const vk::VkImageCreateInfo			imageInfo			=
    251 				{
    252 					vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
    253 					DE_NULL,
    254 					vk::VK_IMAGE_CREATE_PROTECTED_BIT,
    255 					vk::VK_IMAGE_TYPE_2D,
    256 					baseParameters.imageFormat,
    257 					{
    258 						baseParameters.imageExtent.width,
    259 						baseParameters.imageExtent.height,
    260 						1,
    261 					},
    262 					1,	// mipLevels
    263 					baseParameters.imageArrayLayers,
    264 					vk::VK_SAMPLE_COUNT_1_BIT,
    265 					vk::VK_IMAGE_TILING_OPTIMAL,
    266 					baseParameters.imageUsage,
    267 					baseParameters.imageSharingMode,
    268 					baseParameters.queueFamilyIndexCount,
    269 					baseParameters.pQueueFamilyIndices,
    270 					vk::VK_IMAGE_LAYOUT_UNDEFINED
    271 				};
    272 				vk::Move<vk::VkImage>				image				= vk::createImage(vkd, device, &imageInfo);
    273 
    274 				memoryRequirements	= vk::getImageMemoryRequirements(vkd, device, *image);
    275 			}
    276 
    277 			// Determine the maximum memory heap space available for protected images
    278 			vk::VkPhysicalDeviceMemoryProperties	memoryProperties	= vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
    279 			vk::VkDeviceSize						protectedHeapSize	= 0;
    280 			deUint32								protectedHeapMask	= 0;
    281 			for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
    282 			{
    283 				deUint32 heapIndex	= memoryProperties.memoryTypes[memType].heapIndex;
    284 				if ((memoryRequirements.memoryTypeBits & (1u << memType)) != 0 &&
    285 					(memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0 &&
    286 					(protectedHeapMask & (1u << heapIndex)) == 0)
    287 				{
    288 					protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
    289 					protectedHeapMask |= 1u << heapIndex;
    290 				}
    291 			}
    292 
    293 			// If the implementation doesn't have a max image count, min+16 means we won't clamp.
    294 			// Limit it to how many protected images we estimate can be allocated, with one image
    295 			// worth of slack for alignment, swapchain-specific constraints, etc.
    296 			const deUint32	maxImageCount		= de::min((capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u,
    297 														  deUint32(protectedHeapSize / memoryRequirements.size) - 1);
    298 			const deUint32	maxImageCountToTest	= de::clamp(16u, capabilities.minImageCount, maxImageCount);
    299 			for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
    300 			{
    301 				cases.push_back(baseParameters);
    302 				cases.back().minImageCount = imageCount;
    303 			}
    304 
    305 			break;
    306 		}
    307 
    308 		case TEST_DIMENSION_IMAGE_FORMAT:
    309 		{
    310 			for (std::vector<vk::VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
    311 			{
    312 				cases.push_back(baseParameters);
    313 				cases.back().imageFormat		= curFmt->format;
    314 				cases.back().imageColorSpace	= curFmt->colorSpace;
    315 			}
    316 
    317 			break;
    318 		}
    319 
    320 		case TEST_DIMENSION_IMAGE_EXTENT:
    321 		{
    322 			static const vk::VkExtent2D	s_testSizes[]	=
    323 			{
    324 				{ 1, 1 },
    325 				{ 16, 32 },
    326 				{ 32, 16 },
    327 				{ 632, 231 },
    328 				{ 117, 998 },
    329 			};
    330 
    331 			if (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
    332 				platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
    333 			{
    334 				for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
    335 				{
    336 					cases.push_back(baseParameters);
    337 					cases.back().imageExtent.width	= de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
    338 					cases.back().imageExtent.height	= de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
    339 				}
    340 			}
    341 
    342 			if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
    343 			{
    344 				cases.push_back(baseParameters);
    345 				cases.back().imageExtent = capabilities.currentExtent;
    346 			}
    347 
    348 			if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
    349 			{
    350 				cases.push_back(baseParameters);
    351 				cases.back().imageExtent = capabilities.minImageExtent;
    352 
    353 				cases.push_back(baseParameters);
    354 				cases.back().imageExtent = capabilities.maxImageExtent;
    355 			}
    356 
    357 			break;
    358 		}
    359 
    360 		case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
    361 		{
    362 			const deUint32	maxLayers	= de::min(capabilities.maxImageArrayLayers, 16u);
    363 
    364 			for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
    365 			{
    366 				cases.push_back(baseParameters);
    367 				cases.back().imageArrayLayers = numLayers;
    368 			}
    369 
    370 			break;
    371 		}
    372 
    373 		case TEST_DIMENSION_IMAGE_USAGE:
    374 		{
    375 			for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
    376 			{
    377 				if ((flags & ~capabilities.supportedUsageFlags) == 0)
    378 				{
    379 					cases.push_back(baseParameters);
    380 					cases.back().imageUsage = flags;
    381 				}
    382 			}
    383 
    384 			break;
    385 		}
    386 
    387 		case TEST_DIMENSION_IMAGE_SHARING_MODE:
    388 		{
    389 			cases.push_back(baseParameters);
    390 			cases.back().imageSharingMode = vk::VK_SHARING_MODE_EXCLUSIVE;
    391 
    392 			cases.push_back(baseParameters);
    393 			cases.back().imageSharingMode = vk::VK_SHARING_MODE_CONCURRENT;
    394 
    395 			break;
    396 		}
    397 
    398 		case TEST_DIMENSION_PRE_TRANSFORM:
    399 		{
    400 			for (deUint32 transform = 1u;
    401 				 transform <= capabilities.supportedTransforms;
    402 				 transform = transform<<1u)
    403 			{
    404 				if ((transform & capabilities.supportedTransforms) != 0)
    405 				{
    406 					cases.push_back(baseParameters);
    407 					cases.back().preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform;
    408 				}
    409 			}
    410 
    411 			break;
    412 		}
    413 
    414 		case TEST_DIMENSION_COMPOSITE_ALPHA:
    415 		{
    416 			for (deUint32 alphaMode = 1u;
    417 				 alphaMode <= capabilities.supportedCompositeAlpha;
    418 				 alphaMode = alphaMode<<1u)
    419 			{
    420 				if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
    421 				{
    422 					cases.push_back(baseParameters);
    423 					cases.back().compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alphaMode;
    424 				}
    425 			}
    426 
    427 			break;
    428 		}
    429 
    430 		case TEST_DIMENSION_PRESENT_MODE:
    431 		{
    432 			for (std::vector<vk::VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
    433 			{
    434 				cases.push_back(baseParameters);
    435 				cases.back().presentMode = *curMode;
    436 			}
    437 
    438 			break;
    439 		}
    440 
    441 		case TEST_DIMENSION_CLIPPED:
    442 		{
    443 			cases.push_back(baseParameters);
    444 			cases.back().clipped = VK_FALSE;
    445 
    446 			cases.push_back(baseParameters);
    447 			cases.back().clipped = VK_TRUE;
    448 
    449 			break;
    450 		}
    451 
    452 		default:
    453 			DE_FATAL("Impossible");
    454 	}
    455 
    456 	DE_ASSERT(!cases.empty());
    457 	return cases;
    458 }
    459 
    460 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type					wsiType,
    461 																		   TestDimension					dimension,
    462 																		   const ProtectedContext&			context,
    463 																		   vk::VkSurfaceKHR					surface)
    464 {
    465 	const vk::InstanceInterface&				vki				= context.getInstanceDriver();
    466 	vk::VkPhysicalDevice						physicalDevice	= context.getPhysicalDevice();
    467 	const vk::VkSurfaceCapabilitiesKHR			capabilities	= vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
    468 																											   physicalDevice,
    469 																											   surface);
    470 	const std::vector<vk::VkSurfaceFormatKHR>	formats			= vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
    471 																										   physicalDevice,
    472 																										   surface);
    473 	const std::vector<vk::VkPresentModeKHR>		presentModes	= vk::wsi::getPhysicalDeviceSurfacePresentModes(vki,
    474 																											    physicalDevice,
    475 																											    surface);
    476 
    477 	return generateSwapchainParameterCases(wsiType, dimension, context, capabilities, formats, presentModes);
    478 }
    479 
    480 tcu::TestStatus createSwapchainTest (Context& baseCtx, TestParameters params)
    481 {
    482 	std::vector<vk::VkExtensionProperties>			supportedExtensions (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
    483 	std::vector<std::string>						instExts	= getRequiredWsiExtensions(supportedExtensions, params.wsiType);
    484 	std::vector<std::string>						devExts;
    485 	devExts.push_back("VK_KHR_swapchain");
    486 
    487 	const NativeObjects								native		(baseCtx, supportedExtensions, params.wsiType);
    488 	ProtectedContext								context		(baseCtx, params.wsiType, *native.display, *native.window, instExts, devExts);
    489 	vk::VkSurfaceKHR								surface		= context.getSurface();
    490 	const std::vector<vk::VkSwapchainCreateInfoKHR>	cases		(generateSwapchainParameterCases(params.wsiType,
    491 																								 params.dimension,
    492 																								 context,
    493 																								 surface));
    494 	deUint32										queueIdx	= context.getQueueFamilyIndex();
    495 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
    496 	{
    497 		vk::VkSwapchainCreateInfoKHR	curParams	= cases[caseNdx];
    498 
    499 		curParams.surface				= surface;
    500 		curParams.queueFamilyIndexCount	= 1u;
    501 		curParams.pQueueFamilyIndices	= &queueIdx;
    502 
    503 		context.getTestContext().getLog()
    504 			<< tcu::TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": " << curParams << tcu::TestLog::EndMessage;
    505 
    506 		{
    507 			const vk::Unique<vk::VkSwapchainKHR>	swapchain	(createSwapchainKHR(context.getDeviceDriver(), context.getDevice(), &curParams));
    508 		}
    509 	}
    510 
    511 	return tcu::TestStatus::pass("Creating swapchain succeeded");
    512 }
    513 
    514 struct GroupParameters
    515 {
    516 	typedef FunctionInstance1<TestParameters>::Function	Function;
    517 
    518 	vk::wsi::Type	wsiType;
    519 	Function		function;
    520 
    521 	GroupParameters (vk::wsi::Type wsiType_, Function function_)
    522 		: wsiType	(wsiType_)
    523 		, function	(function_)
    524 	{}
    525 
    526 	GroupParameters (void)
    527 		: wsiType	(vk::wsi::TYPE_LAST)
    528 		, function	((Function)DE_NULL)
    529 	{}
    530 };
    531 
    532 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
    533 {
    534 	for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
    535 	{
    536 		const TestDimension		testDimension	= (TestDimension)dimensionNdx;
    537 
    538 		addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
    539 	}
    540 }
    541 
    542 vk::VkSwapchainCreateInfoKHR getBasicSwapchainParameters (vk::wsi::Type					wsiType,
    543 														  const vk::InstanceInterface&	vki,
    544 														  vk::VkPhysicalDevice			physicalDevice,
    545 														  vk::VkSurfaceKHR				surface,
    546 														  const tcu::UVec2&				desiredSize,
    547 														  deUint32						desiredImageCount)
    548 {
    549 	const vk::VkSurfaceCapabilitiesKHR			capabilities		= vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
    550 																												    physicalDevice,
    551 																												    surface);
    552 	const std::vector<vk::VkSurfaceFormatKHR>	formats				= vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
    553 																											   physicalDevice,
    554 																											   surface);
    555 	const vk::wsi::PlatformProperties&			platformProperties	= vk::wsi::getPlatformProperties(wsiType);
    556 	const vk::VkSurfaceTransformFlagBitsKHR		transform			= (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
    557 																		? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
    558 	const vk::VkSwapchainCreateInfoKHR			parameters			=
    559 	{
    560 		vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
    561 		DE_NULL,
    562 		vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
    563 		surface,
    564 		de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
    565 		formats[0].format,
    566 		formats[0].colorSpace,
    567 		(platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
    568 			? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
    569 		1u,									// imageArrayLayers
    570 		vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
    571 		vk::VK_SHARING_MODE_EXCLUSIVE,
    572 		0u,
    573 		(const deUint32*)DE_NULL,
    574 		transform,
    575 		vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
    576 		vk::VK_PRESENT_MODE_FIFO_KHR,
    577 		VK_FALSE,							// clipped
    578 		(vk::VkSwapchainKHR)0				// oldSwapchain
    579 	};
    580 
    581 	return parameters;
    582 }
    583 
    584 typedef de::SharedPtr<vk::Unique<vk::VkImageView> >		ImageViewSp;
    585 typedef de::SharedPtr<vk::Unique<vk::VkFramebuffer> >	FramebufferSp;
    586 
    587 class TriangleRenderer
    588 {
    589 public:
    590 												TriangleRenderer	(ProtectedContext&				context,
    591 																	 const vk::BinaryCollection&	binaryRegistry,
    592 																	 const std::vector<vk::VkImage>	swapchainImages,
    593 																	 const vk::VkFormat				framebufferFormat,
    594 																	 const tcu::UVec2&				renderSize);
    595 												~TriangleRenderer	(void);
    596 
    597 	void										recordFrame			(vk::VkCommandBuffer			cmdBuffer,
    598 																	 deUint32						imageNdx,
    599 																	 deUint32						frameNdx) const;
    600 
    601 	static void									getPrograms			(vk::SourceCollections&			dst);
    602 
    603 private:
    604 	static vk::Move<vk::VkRenderPass>			createRenderPass	(const vk::DeviceInterface&		vkd,
    605 																	 const vk::VkDevice				device,
    606 																	 const vk::VkFormat				colorAttachmentFormat);
    607 	static vk::Move<vk::VkPipelineLayout>		createPipelineLayout(const vk::DeviceInterface&		vkd,
    608 																	 vk::VkDevice					device);
    609 	static vk::Move<vk::VkPipeline>				createPipeline		(const vk::DeviceInterface&		vkd,
    610 																	 const vk::VkDevice				device,
    611 																	 const vk::VkRenderPass			renderPass,
    612 																	 const vk::VkPipelineLayout		pipelineLayout,
    613 																	 const vk::BinaryCollection&	binaryCollection,
    614 																	 const tcu::UVec2&				renderSize);
    615 
    616 	const vk::DeviceInterface&					m_vkd;
    617 
    618 	const std::vector<vk::VkImage>				m_swapchainImages;
    619 	const tcu::UVec2							m_renderSize;
    620 
    621 	const vk::Unique<vk::VkRenderPass>			m_renderPass;
    622 	const vk::Unique<vk::VkPipelineLayout>		m_pipelineLayout;
    623 	const vk::Unique<vk::VkPipeline>			m_pipeline;
    624 
    625 	const de::UniquePtr<vk::BufferWithMemory>	m_vertexBuffer;
    626 
    627 	std::vector<ImageViewSp>					m_attachmentViews;
    628 	std::vector<FramebufferSp>					m_framebuffers;
    629 };
    630 
    631 vk::Move<vk::VkRenderPass> TriangleRenderer::createRenderPass (const vk::DeviceInterface&	vkd,
    632 															   const vk::VkDevice			device,
    633 															   const vk::VkFormat			colorAttachmentFormat)
    634 {
    635 	const vk::VkAttachmentDescription	colorAttDesc		=
    636 	{
    637 		(vk::VkAttachmentDescriptionFlags)0,
    638 		colorAttachmentFormat,
    639 		vk::VK_SAMPLE_COUNT_1_BIT,
    640 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
    641 		vk::VK_ATTACHMENT_STORE_OP_STORE,
    642 		vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
    643 		vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
    644 		vk::VK_IMAGE_LAYOUT_UNDEFINED,
    645 		vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
    646 	};
    647 	const vk::VkAttachmentReference		colorAttRef			=
    648 	{
    649 		0u,
    650 		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
    651 	};
    652 	const vk::VkSubpassDescription		subpassDesc			=
    653 	{
    654 		(vk::VkSubpassDescriptionFlags)0u,
    655 		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
    656 		0u,							// inputAttachmentCount
    657 		DE_NULL,					// pInputAttachments
    658 		1u,							// colorAttachmentCount
    659 		&colorAttRef,				// pColorAttachments
    660 		DE_NULL,					// pResolveAttachments
    661 		DE_NULL,					// depthStencilAttachment
    662 		0u,							// preserveAttachmentCount
    663 		DE_NULL,					// pPreserveAttachments
    664 	};
    665 	const vk::VkSubpassDependency		dependencies[]		=
    666 	{
    667 		{
    668 			VK_SUBPASS_EXTERNAL,	// srcSubpass
    669 			0u,						// dstSubpass
    670 			vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
    671 			vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
    672 			vk::VK_ACCESS_MEMORY_READ_BIT,
    673 			(vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
    674 			 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
    675 			vk::VK_DEPENDENCY_BY_REGION_BIT
    676 		},
    677 		{
    678 			0u,						// srcSubpass
    679 			VK_SUBPASS_EXTERNAL,	// dstSubpass
    680 			vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
    681 			vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
    682 			(vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
    683 			 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
    684 			vk::VK_ACCESS_MEMORY_READ_BIT,
    685 			vk::VK_DEPENDENCY_BY_REGION_BIT
    686 		},
    687 	};
    688 	const vk::VkRenderPassCreateInfo	renderPassParams	=
    689 	{
    690 		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
    691 		DE_NULL,
    692 		(vk::VkRenderPassCreateFlags)0,
    693 		1u,
    694 		&colorAttDesc,
    695 		1u,
    696 		&subpassDesc,
    697 		DE_LENGTH_OF_ARRAY(dependencies),
    698 		dependencies,
    699 	};
    700 
    701 	return vk::createRenderPass(vkd, device, &renderPassParams);
    702 }
    703 
    704 vk::Move<vk::VkPipelineLayout> TriangleRenderer::createPipelineLayout (const vk::DeviceInterface&	vkd,
    705 																	   const vk::VkDevice			device)
    706 {
    707 	const vk::VkPushConstantRange					pushConstantRange		=
    708 	{
    709 		vk::VK_SHADER_STAGE_VERTEX_BIT,
    710 		0u,											// offset
    711 		(deUint32)sizeof(deUint32),					// size
    712 	};
    713 	const vk::VkPipelineLayoutCreateInfo			pipelineLayoutParams	=
    714 	{
    715 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
    716 		DE_NULL,
    717 		(vk::VkPipelineLayoutCreateFlags)0,
    718 		0u,											// setLayoutCount
    719 		DE_NULL,									// pSetLayouts
    720 		1u,
    721 		&pushConstantRange,
    722 	};
    723 
    724 	return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
    725 }
    726 
    727 vk::Move<vk::VkPipeline> TriangleRenderer::createPipeline (const vk::DeviceInterface&	vkd,
    728 														   const vk::VkDevice			device,
    729 														   const vk::VkRenderPass		renderPass,
    730 														   const vk::VkPipelineLayout	pipelineLayout,
    731 														   const vk::BinaryCollection&	binaryCollection,
    732 														   const tcu::UVec2&			renderSize)
    733 {
    734 	// \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
    735 	//		 and can be deleted immediately following that call.
    736 	const vk::Unique<vk::VkShaderModule>				vertShaderModule		(createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
    737 	const vk::Unique<vk::VkShaderModule>				fragShaderModule		(createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
    738 
    739 	const vk::VkPipelineShaderStageCreateInfo			shaderStageParams[]		=
    740 	{
    741 		{
    742 			vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
    743 			DE_NULL,
    744 			(vk::VkPipelineShaderStageCreateFlags)0,
    745 			vk::VK_SHADER_STAGE_VERTEX_BIT,
    746 			*vertShaderModule,
    747 			"main",
    748 			DE_NULL
    749 		},
    750 		{
    751 			vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
    752 			DE_NULL,
    753 			(vk::VkPipelineShaderStageCreateFlags)0,
    754 			vk::VK_SHADER_STAGE_FRAGMENT_BIT,
    755 			*fragShaderModule,
    756 			"main",
    757 			DE_NULL
    758 		}
    759 	};
    760 	const vk::VkPipelineDepthStencilStateCreateInfo		depthStencilParams		=
    761 	{
    762 		vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
    763 		DE_NULL,
    764 		(vk::VkPipelineDepthStencilStateCreateFlags)0,
    765 		DE_FALSE,									// depthTestEnable
    766 		DE_FALSE,									// depthWriteEnable
    767 		vk::VK_COMPARE_OP_ALWAYS,					// depthCompareOp
    768 		DE_FALSE,									// depthBoundsTestEnable
    769 		DE_FALSE,									// stencilTestEnable
    770 		{
    771 			vk::VK_STENCIL_OP_KEEP,						// failOp
    772 			vk::VK_STENCIL_OP_KEEP,						// passOp
    773 			vk::VK_STENCIL_OP_KEEP,						// depthFailOp
    774 			vk::VK_COMPARE_OP_ALWAYS,					// compareOp
    775 			0u,											// compareMask
    776 			0u,											// writeMask
    777 			0u,											// reference
    778 		},											// front
    779 		{
    780 			vk::VK_STENCIL_OP_KEEP,						// failOp
    781 			vk::VK_STENCIL_OP_KEEP,						// passOp
    782 			vk::VK_STENCIL_OP_KEEP,						// depthFailOp
    783 			vk::VK_COMPARE_OP_ALWAYS,					// compareOp
    784 			0u,											// compareMask
    785 			0u,											// writeMask
    786 			0u,											// reference
    787 		},											// back
    788 		-1.0f,										// minDepthBounds
    789 		+1.0f,										// maxDepthBounds
    790 	};
    791 	const vk::VkViewport								viewport0				=
    792 	{
    793 		0.0f,										// x
    794 		0.0f,										// y
    795 		(float)renderSize.x(),						// width
    796 		(float)renderSize.y(),						// height
    797 		0.0f,										// minDepth
    798 		1.0f,										// maxDepth
    799 	};
    800 	const vk::VkRect2D									scissor0				=
    801 	{
    802 		{ 0u, 0u, },								// offset
    803 		{ renderSize.x(), renderSize.y() },			// extent
    804 	};
    805 	const vk::VkPipelineViewportStateCreateInfo			viewportParams			=
    806 	{
    807 		vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
    808 		DE_NULL,
    809 		(vk::VkPipelineViewportStateCreateFlags)0,
    810 		1u,
    811 		&viewport0,
    812 		1u,
    813 		&scissor0
    814 	};
    815 	const vk::VkPipelineMultisampleStateCreateInfo		multisampleParams		=
    816 	{
    817 		vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
    818 		DE_NULL,
    819 		(vk::VkPipelineMultisampleStateCreateFlags)0,
    820 		vk::VK_SAMPLE_COUNT_1_BIT,					// rasterizationSamples
    821 		VK_FALSE,									// sampleShadingEnable
    822 		0.0f,										// minSampleShading
    823 		(const vk::VkSampleMask*)DE_NULL,			// sampleMask
    824 		VK_FALSE,									// alphaToCoverageEnable
    825 		VK_FALSE,									// alphaToOneEnable
    826 	};
    827 	const vk::VkPipelineRasterizationStateCreateInfo	rasterParams			=
    828 	{
    829 		vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
    830 		DE_NULL,
    831 		(vk::VkPipelineRasterizationStateCreateFlags)0,
    832 		VK_FALSE,										// depthClampEnable
    833 		VK_FALSE,										// rasterizerDiscardEnable
    834 		vk::VK_POLYGON_MODE_FILL,						// polygonMode
    835 		vk::VK_CULL_MODE_NONE,							// cullMode
    836 		vk::VK_FRONT_FACE_COUNTER_CLOCKWISE,			// frontFace
    837 		VK_FALSE,										// depthBiasEnable
    838 		0.0f,											// depthBiasConstantFactor
    839 		0.0f,											// depthBiasClamp
    840 		0.0f,											// depthBiasSlopeFactor
    841 		1.0f,											// lineWidth
    842 	};
    843 	const vk::VkPipelineInputAssemblyStateCreateInfo	inputAssemblyParams		=
    844 	{
    845 		vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
    846 		DE_NULL,
    847 		(vk::VkPipelineInputAssemblyStateCreateFlags)0,
    848 		vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
    849 		DE_FALSE,									// primitiveRestartEnable
    850 	};
    851 	const vk::VkVertexInputBindingDescription			vertexBinding0			=
    852 	{
    853 		0u,											// binding
    854 		(deUint32)sizeof(tcu::Vec4),				// stride
    855 		vk::VK_VERTEX_INPUT_RATE_VERTEX,			// inputRate
    856 	};
    857 	const vk::VkVertexInputAttributeDescription			vertexAttrib0			=
    858 	{
    859 		0u,											// location
    860 		0u,											// binding
    861 		vk::VK_FORMAT_R32G32B32A32_SFLOAT,			// format
    862 		0u,											// offset
    863 	};
    864 	const vk::VkPipelineVertexInputStateCreateInfo		vertexInputStateParams	=
    865 	{
    866 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
    867 		DE_NULL,
    868 		(vk::VkPipelineVertexInputStateCreateFlags)0,
    869 		1u,
    870 		&vertexBinding0,
    871 		1u,
    872 		&vertexAttrib0,
    873 	};
    874 	const vk::VkPipelineColorBlendAttachmentState		attBlendParams0			=
    875 	{
    876 		VK_FALSE,									// blendEnable
    877 		vk::VK_BLEND_FACTOR_ONE,					// srcColorBlendFactor
    878 		vk::VK_BLEND_FACTOR_ZERO,					// dstColorBlendFactor
    879 		vk::VK_BLEND_OP_ADD,						// colorBlendOp
    880 		vk::VK_BLEND_FACTOR_ONE,					// srcAlphaBlendFactor
    881 		vk::VK_BLEND_FACTOR_ZERO,					// dstAlphaBlendFactor
    882 		vk::VK_BLEND_OP_ADD,						// alphaBlendOp
    883 		(vk::VK_COLOR_COMPONENT_R_BIT|
    884 		 vk::VK_COLOR_COMPONENT_G_BIT|
    885 		 vk::VK_COLOR_COMPONENT_B_BIT|
    886 		 vk::VK_COLOR_COMPONENT_A_BIT),				// colorWriteMask
    887 	};
    888 	const vk::VkPipelineColorBlendStateCreateInfo		blendParams				=
    889 	{
    890 		vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
    891 		DE_NULL,
    892 		(vk::VkPipelineColorBlendStateCreateFlags)0,
    893 		VK_FALSE,									// logicOpEnable
    894 		vk::VK_LOGIC_OP_COPY,
    895 		1u,
    896 		&attBlendParams0,
    897 		{ 0.0f, 0.0f, 0.0f, 0.0f },					// blendConstants[4]
    898 	};
    899 	const vk::VkGraphicsPipelineCreateInfo				pipelineParams			=
    900 	{
    901 		vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
    902 		DE_NULL,
    903 		(vk::VkPipelineCreateFlags)0,
    904 		(deUint32)DE_LENGTH_OF_ARRAY(shaderStageParams),
    905 		shaderStageParams,
    906 		&vertexInputStateParams,
    907 		&inputAssemblyParams,
    908 		(const vk::VkPipelineTessellationStateCreateInfo*)DE_NULL,
    909 		&viewportParams,
    910 		&rasterParams,
    911 		&multisampleParams,
    912 		&depthStencilParams,
    913 		&blendParams,
    914 		(const vk::VkPipelineDynamicStateCreateInfo*)DE_NULL,
    915 		pipelineLayout,
    916 		renderPass,
    917 		0u,											// subpass
    918 		DE_NULL,									// basePipelineHandle
    919 		0u,											// basePipelineIndex
    920 	};
    921 
    922 	return vk::createGraphicsPipeline(vkd, device, (vk::VkPipelineCache)0, &pipelineParams);
    923 }
    924 
    925 TriangleRenderer::TriangleRenderer (ProtectedContext&				context,
    926 									const vk::BinaryCollection&		binaryRegistry,
    927 									const std::vector<vk::VkImage>	swapchainImages,
    928 									const vk::VkFormat				framebufferFormat,
    929 									const tcu::UVec2&				renderSize)
    930 	: m_vkd					(context.getDeviceInterface())
    931 	, m_swapchainImages		(swapchainImages)
    932 	, m_renderSize			(renderSize)
    933 	, m_renderPass			(createRenderPass(m_vkd, context.getDevice(), framebufferFormat))
    934 	, m_pipelineLayout		(createPipelineLayout(m_vkd, context.getDevice()))
    935 	, m_pipeline			(createPipeline(m_vkd, context.getDevice(), *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
    936 	, m_vertexBuffer		(makeBuffer(context,
    937 									PROTECTION_DISABLED,
    938 									context.getQueueFamilyIndex(),
    939 									(deUint32)(sizeof(float)*4*3),
    940 									vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
    941 									vk::MemoryRequirement::HostVisible))
    942 {
    943 	m_attachmentViews.resize(swapchainImages.size());
    944 	m_framebuffers.resize(swapchainImages.size());
    945 
    946 	for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
    947 	{
    948 		m_attachmentViews[imageNdx]	= ImageViewSp(new vk::Unique<vk::VkImageView>(createImageView(context, swapchainImages[imageNdx], framebufferFormat)));
    949 		m_framebuffers[imageNdx]	= FramebufferSp(new vk::Unique<vk::VkFramebuffer>(createFramebuffer(context,
    950 																										renderSize.x(),
    951 																										renderSize.y(),
    952 																										*m_renderPass,
    953 																										**m_attachmentViews[imageNdx])));
    954 	}
    955 
    956 	// Upload vertex data
    957 	{
    958 		const tcu::Vec4				vertices[]	=
    959 		{
    960 			tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
    961 			tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
    962 			tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
    963 		};
    964 		DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
    965 
    966 		deMemcpy(m_vertexBuffer->getAllocation().getHostPtr(), &vertices[0], sizeof(vertices));
    967 		vk::flushMappedMemoryRange(m_vkd, context.getDevice(), m_vertexBuffer->getAllocation().getMemory(), m_vertexBuffer->getAllocation().getOffset(), sizeof(vertices));
    968 	}
    969 }
    970 
    971 TriangleRenderer::~TriangleRenderer (void)
    972 {
    973 }
    974 
    975 void TriangleRenderer::recordFrame (vk::VkCommandBuffer	cmdBuffer,
    976 									deUint32			imageNdx,
    977 									deUint32			frameNdx) const
    978 {
    979 	const vk::VkFramebuffer	curFramebuffer	= **m_framebuffers[imageNdx];
    980 
    981 	beginCommandBuffer(m_vkd, cmdBuffer);
    982 
    983 	{
    984 		const vk::VkClearValue			clearValue		= vk::makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
    985 		const vk::VkRenderPassBeginInfo	passBeginParams	=
    986 		{
    987 			vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
    988 			DE_NULL,
    989 			*m_renderPass,
    990 			curFramebuffer,
    991 			{
    992 				{ 0, 0 },
    993 				{ (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y() }
    994 			},													// renderArea
    995 			1u,													// clearValueCount
    996 			&clearValue,										// pClearValues
    997 		};
    998 		m_vkd.cmdBeginRenderPass(cmdBuffer, &passBeginParams, vk::VK_SUBPASS_CONTENTS_INLINE);
    999 	}
   1000 
   1001 	m_vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
   1002 
   1003 	{
   1004 		const vk::VkDeviceSize bindingOffset = 0;
   1005 		m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer->get(), &bindingOffset);
   1006 	}
   1007 
   1008 	m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
   1009 	m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
   1010 	m_vkd.cmdEndRenderPass(cmdBuffer);
   1011 
   1012 	VK_CHECK(m_vkd.endCommandBuffer(cmdBuffer));
   1013 }
   1014 
   1015 void TriangleRenderer::getPrograms (vk::SourceCollections& dst)
   1016 {
   1017 	dst.glslSources.add("tri-vert") << glu::VertexSource(
   1018 		"#version 310 es\n"
   1019 		"layout(location = 0) in highp vec4 a_position;\n"
   1020 		"layout(push_constant) uniform FrameData\n"
   1021 		"{\n"
   1022 		"    highp uint frameNdx;\n"
   1023 		"} frameData;\n"
   1024 		"void main (void)\n"
   1025 		"{\n"
   1026 		"    highp float angle = float(frameData.frameNdx) / 100.0;\n"
   1027 		"    highp float c     = cos(angle);\n"
   1028 		"    highp float s     = sin(angle);\n"
   1029 		"    highp mat4  t     = mat4( c, -s,  0,  0,\n"
   1030 		"                              s,  c,  0,  0,\n"
   1031 		"                              0,  0,  1,  0,\n"
   1032 		"                              0,  0,  0,  1);\n"
   1033 		"    gl_Position = t * a_position;\n"
   1034 		"}\n");
   1035 	dst.glslSources.add("tri-frag") << glu::FragmentSource(
   1036 		"#version 310 es\n"
   1037 		"layout(location = 0) out lowp vec4 o_color;\n"
   1038 		"void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
   1039 }
   1040 
   1041 typedef de::SharedPtr<vk::Unique<vk::VkCommandBuffer> >	CommandBufferSp;
   1042 typedef de::SharedPtr<vk::Unique<vk::VkFence> >			FenceSp;
   1043 typedef de::SharedPtr<vk::Unique<vk::VkSemaphore> >		SemaphoreSp;
   1044 
   1045 std::vector<FenceSp> createFences (const vk::DeviceInterface&	vkd,
   1046 								   const vk::VkDevice			device,
   1047 								   size_t						numFences)
   1048 {
   1049 	std::vector<FenceSp> fences(numFences);
   1050 
   1051 	for (size_t ndx = 0; ndx < numFences; ++ndx)
   1052 		fences[ndx] = FenceSp(new vk::Unique<vk::VkFence>(createFence(vkd, device)));
   1053 
   1054 	return fences;
   1055 }
   1056 
   1057 std::vector<SemaphoreSp> createSemaphores (const vk::DeviceInterface&	vkd,
   1058 										   const vk::VkDevice			device,
   1059 										   size_t						numSemaphores)
   1060 {
   1061 	std::vector<SemaphoreSp> semaphores(numSemaphores);
   1062 
   1063 	for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
   1064 		semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device)));
   1065 
   1066 	return semaphores;
   1067 }
   1068 
   1069 std::vector<CommandBufferSp> allocateCommandBuffers (const vk::DeviceInterface&		vkd,
   1070 													 const vk::VkDevice				device,
   1071 													 const vk::VkCommandPool		commandPool,
   1072 													 const vk::VkCommandBufferLevel	level,
   1073 													 const size_t					numCommandBuffers)
   1074 {
   1075 	std::vector<CommandBufferSp>			buffers		(numCommandBuffers);
   1076 
   1077 	for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
   1078 		buffers[ndx] = CommandBufferSp(new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
   1079 
   1080 	return buffers;
   1081 }
   1082 
   1083 tcu::TestStatus basicRenderTest (Context& baseCtx, vk::wsi::Type wsiType)
   1084 {
   1085 	std::vector<vk::VkExtensionProperties>	supportedExtensions			(enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
   1086 	std::vector<std::string>				instExts					= getRequiredWsiExtensions(supportedExtensions, wsiType);
   1087 	std::vector<std::string>				devExts;
   1088 	devExts.push_back("VK_KHR_swapchain");
   1089 
   1090 	const tcu::UVec2						desiredSize					(256, 256);
   1091 	const NativeObjects						native						(baseCtx,  supportedExtensions, wsiType, tcu::just(desiredSize));
   1092 	ProtectedContext						context						(baseCtx, wsiType, *native.display, *native.window, instExts, devExts);
   1093 	vk::VkSurfaceKHR						surface						= context.getSurface();
   1094 	const vk::DeviceInterface&				vkd							= context.getDeviceInterface();
   1095 	const vk::VkDevice						device						= context.getDevice();
   1096 	const vk::VkSwapchainCreateInfoKHR		swapchainInfo				= getBasicSwapchainParameters(wsiType,
   1097 																								  context.getInstanceDriver(),
   1098 																								  context.getPhysicalDevice(),
   1099 																								  surface,
   1100 																								  desiredSize,
   1101 																								  2);
   1102 	const vk::Unique<vk::VkSwapchainKHR>	swapchain					(createSwapchainKHR(vkd, device, &swapchainInfo));
   1103 	const std::vector<vk::VkImage>			swapchainImages				= vk::wsi::getSwapchainImages(vkd, device, *swapchain);
   1104 
   1105 	const TriangleRenderer					renderer					(context,
   1106 																		 context.getBinaryCollection(),
   1107 																		 swapchainImages,
   1108 																		 swapchainInfo.imageFormat,
   1109 																		 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
   1110 
   1111 	const vk::Unique<vk::VkCommandPool>		commandPool					(makeCommandPool(vkd, device, PROTECTION_ENABLED,
   1112 																					 context.getQueueFamilyIndex()));
   1113 
   1114 	const size_t							maxQueuedFrames				= swapchainImages.size()*2;
   1115 
   1116 	// We need to keep hold of fences from vkAcquireNextImageKHR to actually
   1117 	// limit number of frames we allow to be queued.
   1118 	const std::vector<FenceSp>				imageReadyFences			(createFences(vkd, device, maxQueuedFrames));
   1119 
   1120 	// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
   1121 	// the semaphore in same time as the fence we use to meter rendering.
   1122 	const std::vector<SemaphoreSp>			imageReadySemaphores		(createSemaphores(vkd, device, maxQueuedFrames+1));
   1123 
   1124 	// For rest we simply need maxQueuedFrames as we will wait for image
   1125 	// from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
   1126 	// previous uses must have completed.
   1127 	const std::vector<SemaphoreSp>			renderingCompleteSemaphores	(createSemaphores(vkd, device, maxQueuedFrames));
   1128 	const std::vector<CommandBufferSp>		commandBuffers				(allocateCommandBuffers(vkd,
   1129 																								device,
   1130 																								*commandPool,
   1131 																								vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
   1132 																								maxQueuedFrames));
   1133 
   1134 	try
   1135 	{
   1136 		const deUint32	numFramesToRender	= 60*10;
   1137 
   1138 		for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
   1139 		{
   1140 			const vk::VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
   1141 			const vk::VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
   1142 			deUint32				imageNdx			= ~0u;
   1143 
   1144 			if (frameNdx >= maxQueuedFrames)
   1145 				VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
   1146 
   1147 			VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
   1148 
   1149 			{
   1150 				const vk::VkResult	acquireResult	= vkd.acquireNextImageKHR(device,
   1151 																			  *swapchain,
   1152 																			  std::numeric_limits<deUint64>::max(),
   1153 																			  imageReadySemaphore,
   1154 																			  imageReadyFence,
   1155 																			  &imageNdx);
   1156 
   1157 				if (acquireResult == vk::VK_SUBOPTIMAL_KHR)
   1158 					context.getTestContext().getLog() << tcu::TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << tcu::TestLog::EndMessage;
   1159 				else
   1160 					VK_CHECK(acquireResult);
   1161 			}
   1162 
   1163 			TCU_CHECK((size_t)imageNdx < swapchainImages.size());
   1164 
   1165 			{
   1166 				const vk::VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
   1167 				const vk::VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
   1168 				const vk::VkPipelineStageFlags	waitDstStage				= vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
   1169 				vk::VkSubmitInfo				submitInfo					=
   1170 				{
   1171 					vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
   1172 					DE_NULL,
   1173 					1u,
   1174 					&imageReadySemaphore,
   1175 					&waitDstStage,
   1176 					1u,
   1177 					&commandBuffer,
   1178 					1u,
   1179 					&renderingCompleteSemaphore
   1180 				};
   1181 
   1182 				const vk::VkProtectedSubmitInfo		protectedInfo   =
   1183 				{
   1184 					vk::VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO,		// sType
   1185 					DE_NULL,											// pNext
   1186 					VK_TRUE,											// protectedSubmit
   1187 				};
   1188 				submitInfo.pNext = &protectedInfo;
   1189 
   1190 				const vk::VkPresentInfoKHR		presentInfo					=
   1191 				{
   1192 					vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
   1193 					DE_NULL,
   1194 					1u,
   1195 					&renderingCompleteSemaphore,
   1196 					1u,
   1197 					&*swapchain,
   1198 					&imageNdx,
   1199 					(vk::VkResult*)DE_NULL
   1200 				};
   1201 
   1202 				renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
   1203 				VK_CHECK(vkd.queueSubmit(context.getQueue(), 1u, &submitInfo, (vk::VkFence)0));
   1204 				VK_CHECK(vkd.queuePresentKHR(context.getQueue(), &presentInfo));
   1205 			}
   1206 		}
   1207 
   1208 		VK_CHECK(vkd.deviceWaitIdle(device));
   1209 	}
   1210 	catch (...)
   1211 	{
   1212 		// Make sure device is idle before destroying resources
   1213 		vkd.deviceWaitIdle(device);
   1214 		throw;
   1215 	}
   1216 
   1217 	return tcu::TestStatus::pass("Rendering tests succeeded");
   1218 }
   1219 
   1220 void getBasicRenderPrograms (vk::SourceCollections& dst, vk::wsi::Type)
   1221 {
   1222 	TriangleRenderer::getPrograms(dst);
   1223 }
   1224 
   1225 void populateRenderGroup (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
   1226 {
   1227 	addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType);
   1228 }
   1229 
   1230 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
   1231 {
   1232 	addTestGroup(testGroup, "create",			"Create VkSwapchain with various parameters",					populateSwapchainGroup,		GroupParameters(wsiType, createSwapchainTest));
   1233 	addTestGroup(testGroup, "render",			"Rendering Tests",												populateRenderGroup,		wsiType);
   1234 }
   1235 
   1236 void createTypeSpecificTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
   1237 {
   1238 	addTestGroup(testGroup, "swapchain", "VkSwapchain Tests", createSwapchainTests, wsiType);
   1239 }
   1240 
   1241 } // anonymous
   1242 
   1243 tcu::TestCaseGroup* createSwapchainTests (tcu::TestContext& testCtx)
   1244 {
   1245 	de::MovePtr<tcu::TestCaseGroup> wsiTestGroup (new tcu::TestCaseGroup(testCtx, "wsi", "WSI Tests"));
   1246 
   1247 	for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
   1248 	{
   1249 		const vk::wsi::Type	wsiType		= (vk::wsi::Type)typeNdx;
   1250 
   1251 		addTestGroup(&*wsiTestGroup, getName(wsiType), "", createTypeSpecificTests, wsiType);
   1252 	}
   1253 
   1254 	return wsiTestGroup.release();
   1255 }
   1256 
   1257 } // wsi
   1258 } // vkt
   1259