• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "vktCustomInstancesDevices.hpp"
29 #include "vktNativeObjectsUtil.hpp"
30 
31 #include "vkDefs.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkStrUtil.hpp"
34 #include "vkRef.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkMemUtil.hpp"
38 #include "vkDeviceUtil.hpp"
39 #include "vkPrograms.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkWsiPlatform.hpp"
42 #include "vkWsiUtil.hpp"
43 #include "vkAllocationCallbackUtil.hpp"
44 #include "vkCmdUtil.hpp"
45 #include "vkObjTypeImpl.inl"
46 #include "vkObjUtil.hpp"
47 
48 #include "tcuCommandLine.hpp"
49 #include "tcuTestLog.hpp"
50 #include "tcuFormatUtil.hpp"
51 #include "tcuPlatform.hpp"
52 #include "tcuResultCollector.hpp"
53 
54 #include "deUniquePtr.hpp"
55 #include "deStringUtil.hpp"
56 #include "deArrayUtil.hpp"
57 #include "deSharedPtr.hpp"
58 
59 #include <limits>
60 #include <algorithm>
61 #include <iterator>
62 
63 namespace vkt
64 {
65 namespace wsi
66 {
67 
68 namespace
69 {
70 
71 using namespace vk;
72 using namespace vk::wsi;
73 
74 using tcu::TestLog;
75 using tcu::Maybe;
76 using tcu::UVec2;
77 
78 using de::MovePtr;
79 using de::UniquePtr;
80 using de::SharedPtr;
81 
82 using std::string;
83 using std::vector;
84 
85 typedef vector<VkExtensionProperties> Extensions;
86 
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)87 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
88 {
89 	for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
90 		 requiredExtName != requiredExtensions.end();
91 		 ++requiredExtName)
92 	{
93 		if (!isExtensionSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
94 			TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
95 	}
96 }
97 
createInstanceWithWsi(Context & context,const Extensions & supportedExtensions,Type wsiType,const vector<string> extraExtensions,const VkAllocationCallbacks * pAllocator=DE_NULL)98 CustomInstance createInstanceWithWsi (Context&						context,
99 									  const Extensions&				supportedExtensions,
100 									  Type							wsiType,
101 									  const vector<string>			extraExtensions,
102 									  const VkAllocationCallbacks*	pAllocator	= DE_NULL)
103 {
104 	vector<string>	extensions = extraExtensions;
105 
106 	extensions.push_back("VK_KHR_surface");
107 	extensions.push_back(getExtensionName(wsiType));
108 
109 	// VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
110 	// the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
111 	// but using them without enabling the extension is not allowed. Thus we have
112 	// two options:
113 	//
114 	// 1) Filter out non-core formats to stay within valid usage.
115 	//
116 	// 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
117 	//
118 	// We opt for (2) as it provides basic coverage for the extension as a bonus.
119 	if (isExtensionSupported(supportedExtensions, RequiredExtension("VK_EXT_swapchain_colorspace")))
120 		extensions.push_back("VK_EXT_swapchain_colorspace");
121 
122 	checkAllSupported(supportedExtensions, extensions);
123 
124 	return vkt::createCustomInstanceWithExtensions(context, extensions, pAllocator);
125 }
126 
getDeviceFeaturesForWsi(void)127 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
128 {
129 	VkPhysicalDeviceFeatures features;
130 	deMemset(&features, 0, sizeof(features));
131 	return features;
132 }
133 
createDeviceWithWsi(const PlatformInterface & vkp,deUint32 apiVersion,VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const vector<string> & additionalExtensions,const vector<deUint32> & queueFamilyIndices,bool validationEnabled,const VkAllocationCallbacks * pAllocator=DE_NULL)134 Move<VkDevice> createDeviceWithWsi (const PlatformInterface&		vkp,
135 									deUint32						apiVersion,
136 									VkInstance						instance,
137 									const InstanceInterface&		vki,
138 									VkPhysicalDevice				physicalDevice,
139 									const Extensions&				supportedExtensions,
140 									const vector<string>&			additionalExtensions,
141 									const vector<deUint32>&			queueFamilyIndices,
142 									bool							validationEnabled,
143 									const VkAllocationCallbacks*	pAllocator = DE_NULL)
144 {
145 	const float						queuePriorities[] = { 1.0f };
146 	vector<VkDeviceQueueCreateInfo>	queueInfos;
147 
148 	for (const auto familyIndex : queueFamilyIndices)
149 	{
150 		const VkDeviceQueueCreateInfo info =
151 		{
152 			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
153 			nullptr,
154 			(VkDeviceQueueCreateFlags)0,
155 			familyIndex,
156 			DE_LENGTH_OF_ARRAY(queuePriorities),
157 			&queuePriorities[0],
158 		};
159 
160 		queueInfos.push_back(info);
161 	}
162 
163 	vector<string> extensions;
164 	extensions.push_back("VK_KHR_swapchain");
165 	extensions.insert(end(extensions), begin(additionalExtensions), end(additionalExtensions));
166 
167 	for (const auto& extName : extensions)
168 	{
169 		if (!isCoreDeviceExtension(apiVersion, extName) && !isExtensionSupported(supportedExtensions, RequiredExtension(extName)))
170 			TCU_THROW(NotSupportedError, extName + " is not supported");
171 	}
172 
173 	const void *					pNext			= nullptr;
174 	const VkPhysicalDeviceFeatures	features		= getDeviceFeaturesForWsi();
175 
176 	VkDevicePrivateDataCreateInfoEXT pdci = initVulkanStructure();
177 	pdci.privateDataSlotRequestCount = 4u;
178 
179 	VkPhysicalDevicePrivateDataFeaturesEXT privateDataFeatures = initVulkanStructure(&pdci);
180 	privateDataFeatures.privateData = VK_TRUE;
181 
182 	if (de::contains(begin(extensions), end(extensions), "VK_EXT_private_data"))
183 	{
184 		pNext = &privateDataFeatures;
185 	}
186 
187 	// Convert from std::vector<std::string> to std::vector<const char*>.
188 	std::vector<const char*> extensionsChar;
189 	extensionsChar.reserve(extensions.size());
190 	std::transform(begin(extensions), end(extensions), std::back_inserter(extensionsChar), [](const std::string& s) { return s.c_str(); });
191 
192 	const VkDeviceCreateInfo deviceParams =
193 	{
194 		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
195 		pNext,
196 		(VkDeviceCreateFlags)0,
197 		static_cast<deUint32>(queueInfos.size()),
198 		queueInfos.data(),
199 		0u,												// enabledLayerCount
200 		nullptr,										// ppEnabledLayerNames
201 		static_cast<deUint32>(extensionsChar.size()),	// enabledExtensionCount
202 		extensionsChar.data(),							// ppEnabledExtensionNames
203 		&features
204 	};
205 
206 	return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
207 }
208 
createDeviceWithWsi(const PlatformInterface & vkp,deUint32 apiVersion,VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const vector<string> & additionalExtensions,const deUint32 queueFamilyIndex,bool validationEnabled,const VkAllocationCallbacks * pAllocator=DE_NULL)209 Move<VkDevice> createDeviceWithWsi (const PlatformInterface&		vkp,
210 									deUint32						apiVersion,
211 									VkInstance						instance,
212 									const InstanceInterface&		vki,
213 									VkPhysicalDevice				physicalDevice,
214 									const Extensions&				supportedExtensions,
215 									const vector<string>&			additionalExtensions,
216 									const deUint32					queueFamilyIndex,
217 									bool							validationEnabled,
218 									const VkAllocationCallbacks*	pAllocator = DE_NULL)
219 {
220 	return createDeviceWithWsi(vkp, apiVersion, instance, vki, physicalDevice, supportedExtensions, additionalExtensions, vector<deUint32>(1u, queueFamilyIndex), validationEnabled, pAllocator);
221 }
222 
223 struct InstanceHelper
224 {
225 	const vector<VkExtensionProperties>	supportedExtensions;
226 	const CustomInstance				instance;
227 	const InstanceDriver&				vki;
228 
InstanceHelpervkt::wsi::__anonc927807a0111::InstanceHelper229 	InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
230 		: supportedExtensions	(enumerateInstanceExtensionProperties(context.getPlatformInterface(),
231 																	  DE_NULL))
232 		, instance				(createInstanceWithWsi(context,
233 													   supportedExtensions,
234 													   wsiType,
235 													   vector<string>(),
236 													   pAllocator))
237 		, vki					(instance.getDriver())
238 	{}
239 
InstanceHelpervkt::wsi::__anonc927807a0111::InstanceHelper240 	InstanceHelper (Context& context, Type wsiType, const vector<string>& extensions, const VkAllocationCallbacks* pAllocator = DE_NULL)
241 		: supportedExtensions	(enumerateInstanceExtensionProperties(context.getPlatformInterface(),
242 																	  DE_NULL))
243 		, instance				(createInstanceWithWsi(context,
244 													   supportedExtensions,
245 													   wsiType,
246 													   extensions,
247 													   pAllocator))
248 		, vki					(instance.getDriver())
249 	{}
250 };
251 
252 struct DeviceHelper
253 {
254 	const VkPhysicalDevice	physicalDevice;
255 	const deUint32			queueFamilyIndex;
256 	const Unique<VkDevice>	device;
257 	const DeviceDriver		vkd;
258 	const VkQueue			queue;
259 
DeviceHelpervkt::wsi::__anonc927807a0111::DeviceHelper260 	DeviceHelper (Context&						context,
261 				  const InstanceInterface&		vki,
262 				  VkInstance					instance,
263 				  const vector<VkSurfaceKHR>&	surface,
264 				  const vector<string>&			additionalExtensions = vector<string>(),
265 				  const VkAllocationCallbacks*	pAllocator = DE_NULL)
266 		: physicalDevice	(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
267 		, queueFamilyIndex	(chooseQueueFamilyIndex(vki, physicalDevice, surface))
268 		, device			(createDeviceWithWsi(context.getPlatformInterface(),
269 												 context.getUsedApiVersion(),
270 												 instance,
271 												 vki,
272 												 physicalDevice,
273 												 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
274 												 additionalExtensions,
275 												 queueFamilyIndex,
276 												 context.getTestContext().getCommandLine().isValidationEnabled(),
277 												 pAllocator))
278 		, vkd				(context.getPlatformInterface(), instance, *device)
279 		, queue				(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
280 	{
281 	}
282 
283 	// Single-surface shortcut.
DeviceHelpervkt::wsi::__anonc927807a0111::DeviceHelper284 	DeviceHelper (Context&						context,
285 				  const InstanceInterface&		vki,
286 				  VkInstance					instance,
287 				  VkSurfaceKHR					surface,
288 				  const vector<string>&			additionalExtensions = vector<string>(),
289 				  const VkAllocationCallbacks*	pAllocator = DE_NULL)
290 		: DeviceHelper(context, vki, instance, vector<VkSurfaceKHR>(1u, surface), additionalExtensions, pAllocator)
291 	{
292 	}
293 };
294 
295 // Similar to the one above with no queues and multiple queue families.
296 struct MultiQueueDeviceHelper
297 {
298 	const VkPhysicalDevice	physicalDevice;
299 	const vector<deUint32>	queueFamilyIndices;
300 	const Unique<VkDevice>	device;
301 	const DeviceDriver		vkd;
302 
MultiQueueDeviceHelpervkt::wsi::__anonc927807a0111::MultiQueueDeviceHelper303 	MultiQueueDeviceHelper (Context&						context,
304 							const InstanceInterface&		vki,
305 							VkInstance						instance,
306 							const vector<VkSurfaceKHR>&		surface,
307 							const vector<string>&			additionalExtensions = vector<string>(),
308 							const VkAllocationCallbacks*	pAllocator = DE_NULL)
309 		: physicalDevice	(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
310 		, queueFamilyIndices(getCompatibleQueueFamilyIndices(vki, physicalDevice, surface))
311 		, device			(createDeviceWithWsi(context.getPlatformInterface(),
312 												 context.getUsedApiVersion(),
313 												 instance,
314 												 vki,
315 												 physicalDevice,
316 												 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
317 												 additionalExtensions,
318 												 queueFamilyIndices,
319 												 context.getTestContext().getCommandLine().isValidationEnabled(),
320 												 pAllocator))
321 		, vkd				(context.getPlatformInterface(), instance, *device)
322 	{
323 	}
324 
325 	// Single-surface shortcut.
MultiQueueDeviceHelpervkt::wsi::__anonc927807a0111::MultiQueueDeviceHelper326 	MultiQueueDeviceHelper (Context&						context,
327 							const InstanceInterface&		vki,
328 							VkInstance						instance,
329 							VkSurfaceKHR					surface,
330 							const vector<string>			additionalExtensions = vector<string>(),
331 							const VkAllocationCallbacks*	pAllocator = DE_NULL)
332 		: MultiQueueDeviceHelper(context, vki, instance, vector<VkSurfaceKHR>(1u, surface), additionalExtensions, pAllocator)
333 	{
334 	}
335 };
336 
337 enum TestDimension
338 {
339 	TEST_DIMENSION_MIN_IMAGE_COUNT = 0,	//!< Test all supported image counts
340 	TEST_DIMENSION_IMAGE_FORMAT,		//!< Test all supported formats
341 	TEST_DIMENSION_IMAGE_EXTENT,		//!< Test various (supported) extents
342 	TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
343 	TEST_DIMENSION_IMAGE_USAGE,
344 	TEST_DIMENSION_IMAGE_SHARING_MODE,
345 	TEST_DIMENSION_PRE_TRANSFORM,
346 	TEST_DIMENSION_COMPOSITE_ALPHA,
347 	TEST_DIMENSION_PRESENT_MODE,
348 	TEST_DIMENSION_CLIPPED,
349 	TEST_DIMENSION_EXCLUSIVE_NONZERO,	//!< Test VK_SHARING_MODE_EXCLUSIVE and a nonzero queue count.
350 
351 	TEST_DIMENSION_LAST
352 };
353 
getTestDimensionName(TestDimension dimension)354 const char* getTestDimensionName (TestDimension dimension)
355 {
356 	static const char* const s_names[] =
357 	{
358 		"min_image_count",
359 		"image_format",
360 		"image_extent",
361 		"image_array_layers",
362 		"image_usage",
363 		"image_sharing_mode",
364 		"pre_transform",
365 		"composite_alpha",
366 		"present_mode",
367 		"clipped",
368 		"exclusive_nonzero_queues",
369 	};
370 	static_assert(static_cast<int>(de::arrayLength(s_names)) == TEST_DIMENSION_LAST,
371 		"Array of names does not provide a 1:1 mapping to TestDimension");
372 	return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
373 }
374 
375 struct TestParameters
376 {
377 	Type			wsiType;
378 	TestDimension	dimension;
379 
TestParametersvkt::wsi::__anonc927807a0111::TestParameters380 	TestParameters (Type wsiType_, TestDimension dimension_)
381 		: wsiType	(wsiType_)
382 		, dimension	(dimension_)
383 	{}
384 
TestParametersvkt::wsi::__anonc927807a0111::TestParameters385 	TestParameters (void)
386 		: wsiType	(TYPE_LAST)
387 		, dimension	(TEST_DIMENSION_LAST)
388 	{}
389 };
390 
generateSwapchainParameterCases(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,Type wsiType,TestDimension dimension,const VkSurfaceCapabilitiesKHR & capabilities,const vector<VkSurfaceFormatKHR> & formats,const vector<VkPresentModeKHR> & presentModes)391 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (const InstanceInterface&			vki,
392 																  VkPhysicalDevice					physicalDevice,
393 																  Type								wsiType,
394 																  TestDimension						dimension,
395 																  const VkSurfaceCapabilitiesKHR&	capabilities,
396 																  const vector<VkSurfaceFormatKHR>&	formats,
397 																  const vector<VkPresentModeKHR>&	presentModes)
398 {
399 	const PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
400 	vector<VkSwapchainCreateInfoKHR>	cases;
401 	const VkSurfaceTransformFlagBitsKHR defaultTransform	= (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
402 	const VkSwapchainCreateInfoKHR		baseParameters		=
403 	{
404 		VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
405 		DE_NULL,
406 		(VkSwapchainCreateFlagsKHR)0,
407 		(VkSurfaceKHR)0,
408 		capabilities.minImageCount,
409 		formats[0].format,
410 		formats[0].colorSpace,
411 		(platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
412 			? capabilities.minImageExtent : capabilities.currentExtent),
413 		1u,									// imageArrayLayers
414 		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
415 		VK_SHARING_MODE_EXCLUSIVE,
416 		0u,
417 		nullptr,
418 		defaultTransform,
419 		VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
420 		VK_PRESENT_MODE_FIFO_KHR,
421 		VK_FALSE,							// clipped
422 		(VkSwapchainKHR)0					// oldSwapchain
423 	};
424 
425 	switch (dimension)
426 	{
427 		case TEST_DIMENSION_MIN_IMAGE_COUNT:
428 		{
429 			const deUint32	maxImageCountToTest	= de::clamp(16u, capabilities.minImageCount, (capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u);
430 
431 			for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
432 			{
433 				cases.push_back(baseParameters);
434 				cases.back().minImageCount = imageCount;
435 			}
436 
437 			break;
438 		}
439 
440 		case TEST_DIMENSION_IMAGE_FORMAT:
441 		{
442 			for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
443 			{
444 				cases.push_back(baseParameters);
445 				cases.back().imageFormat		= curFmt->format;
446 				cases.back().imageColorSpace	= curFmt->colorSpace;
447 			}
448 
449 			break;
450 		}
451 
452 		case TEST_DIMENSION_IMAGE_EXTENT:
453 		{
454 			static const VkExtent2D	s_testSizes[]	=
455 			{
456 				{ 1, 1 },
457 				{ 16, 32 },
458 				{ 32, 16 },
459 				{ 632, 231 },
460 				{ 117, 998 },
461 			};
462 
463 			if (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
464 				platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
465 			{
466 				for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
467 				{
468 					cases.push_back(baseParameters);
469 					cases.back().imageExtent.width	= de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
470 					cases.back().imageExtent.height	= de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
471 				}
472 			}
473 
474 			if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
475 			{
476 				cases.push_back(baseParameters);
477 				cases.back().imageExtent = capabilities.currentExtent;
478 			}
479 
480 			if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
481 			{
482 				cases.push_back(baseParameters);
483 				cases.back().imageExtent = capabilities.minImageExtent;
484 
485 				cases.push_back(baseParameters);
486 				cases.back().imageExtent = capabilities.maxImageExtent;
487 			}
488 
489 			break;
490 		}
491 
492 		case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
493 		{
494 			const deUint32	maxLayers	= de::min(capabilities.maxImageArrayLayers, 16u);
495 
496 			for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
497 			{
498 				cases.push_back(baseParameters);
499 				cases.back().imageArrayLayers = numLayers;
500 			}
501 
502 			break;
503 		}
504 
505 		case TEST_DIMENSION_IMAGE_USAGE:
506 		{
507 			for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
508 			{
509 				VkImageFormatProperties imageProps;
510 
511 				if (vki.getPhysicalDeviceImageFormatProperties(physicalDevice,
512 															   baseParameters.imageFormat,
513 															   VK_IMAGE_TYPE_2D,
514 															   VK_IMAGE_TILING_OPTIMAL,
515 															   flags,
516 															   (VkImageCreateFlags)0u,
517 															   &imageProps) != VK_SUCCESS)
518 					continue;
519 
520 				if ((flags & ~capabilities.supportedUsageFlags) == 0)
521 				{
522 					cases.push_back(baseParameters);
523 					cases.back().imageUsage = flags;
524 				}
525 			}
526 
527 			break;
528 		}
529 
530 		case TEST_DIMENSION_IMAGE_SHARING_MODE:
531 		{
532 #if 0
533 			// Skipping since this matches the base parameters.
534 			cases.push_back(baseParameters);
535 			cases.back().imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
536 #endif
537 
538 			cases.push_back(baseParameters);
539 			cases.back().imageSharingMode = VK_SHARING_MODE_CONCURRENT;
540 
541 			break;
542 		}
543 
544 		case TEST_DIMENSION_PRE_TRANSFORM:
545 		{
546 			for (deUint32 transform = 1u;
547 				 transform <= capabilities.supportedTransforms;
548 				 transform = transform<<1u)
549 			{
550 				if ((transform & capabilities.supportedTransforms) != 0)
551 				{
552 					cases.push_back(baseParameters);
553 					cases.back().preTransform = (VkSurfaceTransformFlagBitsKHR)transform;
554 				}
555 			}
556 
557 			break;
558 		}
559 
560 		case TEST_DIMENSION_COMPOSITE_ALPHA:
561 		{
562 			for (deUint32 alphaMode = 1u;
563 				 alphaMode <= capabilities.supportedCompositeAlpha;
564 				 alphaMode = alphaMode<<1u)
565 			{
566 				if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
567 				{
568 					cases.push_back(baseParameters);
569 					cases.back().compositeAlpha = (VkCompositeAlphaFlagBitsKHR)alphaMode;
570 				}
571 			}
572 
573 			break;
574 		}
575 
576 		case TEST_DIMENSION_PRESENT_MODE:
577 		{
578 			for (vector<VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
579 			{
580 				cases.push_back(baseParameters);
581 				cases.back().presentMode = *curMode;
582 			}
583 
584 			break;
585 		}
586 
587 		case TEST_DIMENSION_CLIPPED:
588 		{
589 			cases.push_back(baseParameters);
590 			cases.back().clipped = VK_FALSE;
591 
592 			cases.push_back(baseParameters);
593 			cases.back().clipped = VK_TRUE;
594 
595 			break;
596 		}
597 
598 		case TEST_DIMENSION_EXCLUSIVE_NONZERO:
599 		{
600 			// Test the implementation doesn't attempt to do anything with the queue index array in exclusive sharing mode.
601 			cases.push_back(baseParameters);
602 			cases.back().queueFamilyIndexCount = 2u;
603 
604 			break;
605 		}
606 
607 		default:
608 			DE_FATAL("Impossible");
609 	}
610 
611 	DE_ASSERT(!cases.empty());
612 	return cases;
613 }
614 
generateSwapchainParameterCases(Type wsiType,TestDimension dimension,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)615 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (Type								wsiType,
616 																  TestDimension						dimension,
617 																  const InstanceInterface&			vki,
618 																  VkPhysicalDevice					physicalDevice,
619 																  VkSurfaceKHR						surface)
620 {
621 	const VkSurfaceCapabilitiesKHR		capabilities	= getPhysicalDeviceSurfaceCapabilities(vki,
622 																							   physicalDevice,
623 																							   surface);
624 	const vector<VkSurfaceFormatKHR>	formats			= getPhysicalDeviceSurfaceFormats(vki,
625 																						  physicalDevice,
626 																						  surface);
627 	const vector<VkPresentModeKHR>		presentModes	= getPhysicalDeviceSurfacePresentModes(vki,
628 																							   physicalDevice,
629 																							   surface);
630 
631 	return generateSwapchainParameterCases(vki, physicalDevice, wsiType, dimension, capabilities, formats, presentModes);
632 }
633 
createSwapchainTest(Context & context,TestParameters params)634 tcu::TestStatus createSwapchainTest (Context& context, TestParameters params)
635 {
636 	tcu::TestLog&							log			= context.getTestContext().getLog();
637 	const InstanceHelper					instHelper	(context, params.wsiType);
638 	const NativeObjects						native		(context, instHelper.supportedExtensions, params.wsiType);
639 	const Unique<VkSurfaceKHR>				surface		(createSurface(instHelper.vki, instHelper.instance, params.wsiType, native.getDisplay(), native.getWindow()));
640 	const MultiQueueDeviceHelper			devHelper	(context, instHelper.vki, instHelper.instance, *surface);
641 	const vector<VkSwapchainCreateInfoKHR>	cases		(generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
642 	const VkSurfaceCapabilitiesKHR			capabilities(getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface));
643 
644 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
645 	{
646 		std::ostringstream subcase;
647 		subcase << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": ";
648 
649 		VkSwapchainCreateInfoKHR	curParams	= cases[caseNdx];
650 
651 		if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
652 		{
653 			const auto numFamilies = static_cast<deUint32>(devHelper.queueFamilyIndices.size());
654 			if (numFamilies < 2u)
655 				TCU_THROW(NotSupportedError, "Only " + de::toString(numFamilies) + " queue families available for VK_SHARING_MODE_CONCURRENT");
656 
657 			curParams.queueFamilyIndexCount	= numFamilies;
658 			curParams.pQueueFamilyIndices	= devHelper.queueFamilyIndices.data();
659 		}
660 
661 		// Overwrite surface.
662 		curParams.surface = *surface;
663 
664 		log << TestLog::Message << subcase.str() << curParams << TestLog::EndMessage;
665 
666 		// The Vulkan 1.1.87 spec contains the following VU for VkSwapchainCreateInfoKHR:
667 		//
668 		//     * imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D
669 		//     VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties.
670 		VkImageFormatProperties properties;
671 		const VkResult propertiesResult = instHelper.vki.getPhysicalDeviceImageFormatProperties(devHelper.physicalDevice,
672 																								curParams.imageFormat,
673 																								VK_IMAGE_TYPE_2D,
674 																								VK_IMAGE_TILING_OPTIMAL,
675 																								curParams.imageUsage,
676 																								0, // flags
677 																								&properties);
678 
679 		log << TestLog::Message << subcase.str()
680 			<< "vkGetPhysicalDeviceImageFormatProperties => "
681 			<< getResultStr(propertiesResult) << TestLog::EndMessage;
682 
683 		switch (propertiesResult) {
684 		case VK_SUCCESS:
685 			{
686 				// The maxExtents case might not be able to create the requested surface due to insufficient
687 				// memory, so in this case *only* we handle the OOM exception.
688 				if (params.dimension == TEST_DIMENSION_IMAGE_EXTENT &&
689 					capabilities.maxImageExtent.width == curParams.imageExtent.width &&
690 					capabilities.maxImageExtent.height == curParams.imageExtent.height)
691 				{
692 					try
693 					{
694 						const Unique<VkSwapchainKHR>	swapchain	(createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
695 
696 						log << TestLog::Message << subcase.str()
697 							<< "Creating swapchain succeeded" << TestLog::EndMessage;
698 					}
699 					catch (const OutOfMemoryError& e)
700 					{
701 						log << TestLog::Message << subcase.str() << "vkCreateSwapchainKHR with maxImageExtent encountered " << e.getError() << TestLog::EndMessage;
702 					}
703 				}
704 				else
705 				{
706 					const Unique<VkSwapchainKHR>	swapchain	(createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
707 
708 					log << TestLog::Message << subcase.str()
709 						<< "Creating swapchain succeeded" << TestLog::EndMessage;
710 				}
711 			}
712 			break;
713 		case VK_ERROR_FORMAT_NOT_SUPPORTED:
714 			log << TestLog::Message << subcase.str()
715 				<< "Skip because vkGetPhysicalDeviceImageFormatProperties returned VK_ERROR_FORMAT_NOT_SUPPORTED" << TestLog::EndMessage;
716 			break;
717 		default:
718 			log << TestLog::Message << subcase.str()
719 				<< "Fail because vkGetPhysicalDeviceImageFormatProperties returned "
720 				<< getResultStr(propertiesResult) << TestLog::EndMessage;
721 			return tcu::TestStatus::fail("Unexpected result from vkGetPhysicalDeviceImageFormatProperties");
722 		}
723 	}
724 
725 	return tcu::TestStatus::pass("No sub-case failed");
726 }
727 
HandleToInt(T t)728 template<typename T> static deUint64 HandleToInt(T t) { return t.getInternal(); }
729 
createSwapchainPrivateDataTest(Context & context,TestParameters params)730 tcu::TestStatus createSwapchainPrivateDataTest (Context& context, TestParameters params)
731 {
732 	if (!context.getPrivateDataFeaturesEXT().privateData)
733 		TCU_THROW(NotSupportedError, "privateData not supported");
734 
735 	tcu::TestLog&							log			= context.getTestContext().getLog();
736 	const InstanceHelper					instHelper	(context, params.wsiType);
737 	const NativeObjects						native		(context, instHelper.supportedExtensions, params.wsiType);
738 	const Unique<VkSurfaceKHR>				surface		(createSurface(instHelper.vki, instHelper.instance, params.wsiType, native.getDisplay(), native.getWindow()));
739 	const vector<string>					extraExts	(1u, "VK_EXT_private_data");
740 	const MultiQueueDeviceHelper			devHelper	(context, instHelper.vki, instHelper.instance, *surface, extraExts);
741 	const vector<VkSwapchainCreateInfoKHR>	cases		(generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
742 
743 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
744 	{
745 		std::ostringstream subcase;
746 		subcase << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": ";
747 
748 		VkSwapchainCreateInfoKHR	curParams	= cases[caseNdx];
749 
750 		if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
751 		{
752 			const deUint32 numFamilies = static_cast<deUint32>(devHelper.queueFamilyIndices.size());
753 			if (numFamilies < 2u)
754 				TCU_THROW(NotSupportedError, "Only " + de::toString(numFamilies) + " queue families available for VK_SHARING_MODE_CONCURRENT");
755 			curParams.queueFamilyIndexCount	= numFamilies;
756 		}
757 		else
758 		{
759 			// Take only the first queue.
760 			if (devHelper.queueFamilyIndices.empty())
761 				TCU_THROW(NotSupportedError, "No queue families compatible with the given surface");
762 			curParams.queueFamilyIndexCount	= 1u;
763 		}
764 		curParams.pQueueFamilyIndices	= devHelper.queueFamilyIndices.data();
765 		curParams.surface				= *surface;
766 
767 		log << TestLog::Message << subcase.str() << curParams << TestLog::EndMessage;
768 
769 		// The Vulkan 1.1.87 spec contains the following VU for VkSwapchainCreateInfoKHR:
770 		//
771 		//     * imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D
772 		//     VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties.
773 		VkImageFormatProperties properties;
774 		const VkResult propertiesResult = instHelper.vki.getPhysicalDeviceImageFormatProperties(devHelper.physicalDevice,
775 																								curParams.imageFormat,
776 																								VK_IMAGE_TYPE_2D,
777 																								VK_IMAGE_TILING_OPTIMAL,
778 																								curParams.imageUsage,
779 																								0, // flags
780 																								&properties);
781 
782 		log << TestLog::Message << subcase.str()
783 			<< "vkGetPhysicalDeviceImageFormatProperties => "
784 			<< getResultStr(propertiesResult) << TestLog::EndMessage;
785 
786 		switch (propertiesResult) {
787 		case VK_SUCCESS:
788 			{
789 				const Unique<VkSwapchainKHR>	swapchain	(createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
790 
791 				const int numSlots = 100;
792 				typedef Unique<VkPrivateDataSlotEXT>				PrivateDataSlotUp;
793 				typedef SharedPtr<PrivateDataSlotUp>				PrivateDataSlotSp;
794 				vector<PrivateDataSlotSp> slots;
795 
796 				const VkPrivateDataSlotCreateInfoEXT createInfo =
797 				{
798 					VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT,	// VkStructureType                    sType;
799 					DE_NULL,												// const void*                        pNext;
800 					0u,														// VkPrivateDataSlotCreateFlagsEXT    flags;
801 				};
802 
803 				for (int i = 0; i < numSlots; ++i)
804 				{
805 					Move<VkPrivateDataSlotEXT> s = createPrivateDataSlotEXT(devHelper.vkd, *devHelper.device, &createInfo, DE_NULL);
806 					slots.push_back(PrivateDataSlotSp(new PrivateDataSlotUp(s)));
807 				}
808 
809 				// Based on code in vktApiObjectManagementTests.cpp
810 				for (int r = 0; r < 3; ++r)
811 				{
812 					deUint64 data;
813 
814 					for (int i = 0; i < numSlots; ++i)
815 					{
816 						data = 1234;
817 						devHelper.vkd.getPrivateDataEXT(*devHelper.device, getObjectType<VkSwapchainKHR>(), HandleToInt(swapchain.get()), **slots[i], &data);
818 						// Don't test default value of zero on Android, due to spec erratum
819 						if (params.wsiType != TYPE_ANDROID)
820 						{
821 							if (data != 0)
822 								return tcu::TestStatus::fail("Expected initial value of zero");
823 						}
824 					}
825 
826 					for (int i = 0; i < numSlots; ++i)
827 						VK_CHECK(devHelper.vkd.setPrivateDataEXT(*devHelper.device, getObjectType<VkSwapchainKHR>(), HandleToInt(swapchain.get()), **slots[i], i*i*i + 1));
828 
829 					for (int i = 0; i < numSlots; ++i)
830 					{
831 						data = 1234;
832 						devHelper.vkd.getPrivateDataEXT(*devHelper.device, getObjectType<VkSwapchainKHR>(), HandleToInt(swapchain.get()), **slots[i], &data);
833 						if (data != (deUint64)(i*i*i + 1))
834 							return tcu::TestStatus::fail("Didn't read back set value");
835 					}
836 
837 					// Destroy and realloc slots for the next iteration
838 					slots.clear();
839 					for (int i = 0; i < numSlots; ++i)
840 					{
841 						Move<VkPrivateDataSlotEXT> s = createPrivateDataSlotEXT(devHelper.vkd, *devHelper.device, &createInfo, DE_NULL);
842 						slots.push_back(PrivateDataSlotSp(new PrivateDataSlotUp(s)));
843 					}
844 				}
845 
846 
847 			}
848 			break;
849 		case VK_ERROR_FORMAT_NOT_SUPPORTED:
850 			log << TestLog::Message << subcase.str()
851 				<< "Skip because vkGetPhysicalDeviceImageFormatProperties returned VK_ERROR_FORMAT_NOT_SUPPORTED" << TestLog::EndMessage;
852 			break;
853 		default:
854 			log << TestLog::Message << subcase.str()
855 				<< "Fail because vkGetPhysicalDeviceImageFormatProperties returned "
856 				<< getResultStr(propertiesResult) << TestLog::EndMessage;
857 			return tcu::TestStatus::fail("Unexpected result from vkGetPhysicalDeviceImageFormatProperties");
858 		}
859 	}
860 
861 	return tcu::TestStatus::pass("No sub-case failed");
862 }
863 
createSwapchainSimulateOOMTest(Context & context,TestParameters params)864 tcu::TestStatus createSwapchainSimulateOOMTest (Context& context, TestParameters params)
865 {
866 	const size_t				maxCases			= 300u;
867 	const deUint32				maxAllocs			= 1024u;
868 
869 	tcu::TestLog&				log					= context.getTestContext().getLog();
870 	tcu::ResultCollector		results				(log);
871 
872 	AllocationCallbackRecorder	allocationRecorder	(getSystemAllocator());
873 	DeterministicFailAllocator	failingAllocator	(allocationRecorder.getCallbacks(),
874 													 DeterministicFailAllocator::MODE_DO_NOT_COUNT,
875 													 0);
876 	{
877 		const InstanceHelper					instHelper	(context, params.wsiType, failingAllocator.getCallbacks());
878 		const NativeObjects						native		(context, instHelper.supportedExtensions, params.wsiType);
879 		const Unique<VkSurfaceKHR>				surface		(createSurface(instHelper.vki,
880 																			instHelper.instance,
881 																			params.wsiType,
882 																			native.getDisplay(),
883 																			native.getWindow(),
884 																			failingAllocator.getCallbacks()));
885 		const DeviceHelper						devHelper	(context, instHelper.vki, instHelper.instance, *surface, vector<string>(), failingAllocator.getCallbacks());
886 		const vector<VkSwapchainCreateInfoKHR>	allCases	(generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
887 		const VkSurfaceCapabilitiesKHR			capabilities(getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface));
888 
889 		if (maxCases < allCases.size())
890 			log << TestLog::Message << "Note: Will only test first " << maxCases << " cases out of total of " << allCases.size() << " parameter combinations" << TestLog::EndMessage;
891 
892 		for (size_t caseNdx = 0; caseNdx < de::min(maxCases, allCases.size()); ++caseNdx)
893 		{
894 			log << TestLog::Message << "Testing parameter case " << caseNdx << ": " << allCases[caseNdx] << TestLog::EndMessage;
895 
896 			for (deUint32 numPassingAllocs = 0; numPassingAllocs <= maxAllocs; ++numPassingAllocs)
897 			{
898 				bool						gotOOM		= false;
899 				VkSwapchainCreateInfoKHR	curParams	= allCases[caseNdx];
900 				curParams.surface				= *surface;
901 				curParams.queueFamilyIndexCount	= 1u;
902 				curParams.pQueueFamilyIndices	= &devHelper.queueFamilyIndex;
903 
904 				failingAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
905 
906 				log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
907 
908 				try
909 				{
910 					// With concurrent sharing mode, at least two queues are needed.
911 					if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
912 						continue;
913 
914 					const Unique<VkSwapchainKHR>	swapchain	(createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
915 				}
916 				catch (const OutOfMemoryError& e)
917 				{
918 					log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
919 					gotOOM = true;
920 				}
921 
922 				if (!gotOOM)
923 				{
924 					log << TestLog::Message << "Creating swapchain succeeded!" << TestLog::EndMessage;
925 
926 					if (numPassingAllocs == 0)
927 						results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
928 
929 					break;
930 				}
931 				else if (numPassingAllocs == maxAllocs)
932 				{
933 					// The maxExtents case might not be able to create the requested surface due to insufficient
934 					// memory, so in this case *only* we allow the OOM exception upto maxAllocs.
935 					if (params.dimension == TEST_DIMENSION_IMAGE_EXTENT &&
936 						capabilities.maxImageExtent.width == curParams.imageExtent.width &&
937 						capabilities.maxImageExtent.height == curParams.imageExtent.height)
938 						break;
939 
940 					results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Creating swapchain did not succeed, callback limit exceeded");
941 				}
942 			}
943 
944 			context.getTestContext().touchWatchdog();
945 		}
946 	}
947 
948 	if (!validateAndLog(log, allocationRecorder, 0u))
949 		results.fail("Detected invalid system allocation callback");
950 
951 	return tcu::TestStatus(results.getResult(), results.getMessage());
952 }
953 
testImageSwapchainCreateInfo(Context & context,Type wsiType)954 tcu::TestStatus testImageSwapchainCreateInfo (Context& context, Type wsiType)
955 {
956 	const tcu::UVec2			desiredSize			(256, 256);
957 	const InstanceHelper		instHelper			(context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
958 	const NativeObjects			native				(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
959 	const Unique<VkSurfaceKHR>	surface				(createSurface(instHelper.vki,
960 																   instHelper.instance,
961 																   wsiType,
962 																   native.getDisplay(),
963 																   native.getWindow()));
964 	const DeviceHelper			devHelper			(context, instHelper.vki, instHelper.instance, *surface, vector<string>(1u, "VK_KHR_bind_memory2"));
965 	const Extensions&			deviceExtensions	= enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL);
966 
967 	// structures this tests checks were added in revision 69
968 	if (!isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_swapchain", 69)))
969 		TCU_THROW(NotSupportedError, "Required extension revision is not supported");
970 
971 	const VkSurfaceCapabilitiesKHR		capabilities		= getPhysicalDeviceSurfaceCapabilities(instHelper.vki,
972 																								   devHelper.physicalDevice,
973 																								   *surface);
974 	const vector<VkSurfaceFormatKHR>	formats				= getPhysicalDeviceSurfaceFormats(instHelper.vki,
975 																							  devHelper.physicalDevice,
976 																							  *surface);
977 	const PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
978 	const VkSurfaceTransformFlagBitsKHR transform			= (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
979 	const deUint32						desiredImageCount	= 2;
980 	const VkSwapchainCreateInfoKHR		swapchainInfo		=
981 	{
982 		VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
983 		DE_NULL,
984 		(VkSwapchainCreateFlagsKHR)0,
985 		*surface,
986 		de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
987 		formats[0].format,
988 		formats[0].colorSpace,
989 		(platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
990 			? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
991 		1u,
992 		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
993 		VK_SHARING_MODE_EXCLUSIVE,
994 		0u,
995 		(const deUint32*)DE_NULL,
996 		transform,
997 		VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
998 		VK_PRESENT_MODE_FIFO_KHR,
999 		VK_FALSE,							// clipped
1000 		(VkSwapchainKHR)0					// oldSwapchain
1001 	};
1002 
1003 	const Unique<VkSwapchainKHR>	swapchain	(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
1004 	deUint32						numImages	= 0;
1005 	VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
1006 	if (numImages == 0)
1007 		return tcu::TestStatus::pass("Pass");
1008 
1009 	VkImageSwapchainCreateInfoKHR imageSwapchainCreateInfo =
1010 	{
1011 		VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
1012 		DE_NULL,
1013 		*swapchain
1014 	};
1015 
1016 	VkImageCreateInfo imageCreateInfo =
1017 	{
1018 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1019 		&imageSwapchainCreateInfo,
1020 		(VkImageCreateFlags)0u,					// flags
1021 		VK_IMAGE_TYPE_2D,						// imageType
1022 		formats[0].format,						// format
1023 		{										// extent
1024 			desiredSize.x(),					//   width
1025 			desiredSize.y(),					//   height
1026 			1u									//   depth
1027 		},
1028 		1u,										// mipLevels
1029 		1u,										// arrayLayers
1030 		VK_SAMPLE_COUNT_1_BIT,					// samples
1031 		VK_IMAGE_TILING_OPTIMAL,				// tiling
1032 		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,	// usage
1033 		VK_SHARING_MODE_EXCLUSIVE,				// sharingMode
1034 		0u,										// queueFamilyIndexCount
1035 		DE_NULL,								// pQueueFamilyIndices
1036 		VK_IMAGE_LAYOUT_UNDEFINED				// initialLayout
1037 	};
1038 
1039 	typedef vk::Unique<VkImage>			UniqueImage;
1040 	typedef de::SharedPtr<UniqueImage>	ImageSp;
1041 
1042 	std::vector<ImageSp>							images						(numImages);
1043 	std::vector<VkBindImageMemorySwapchainInfoKHR>	bindImageMemorySwapchainInfo(numImages);
1044 	std::vector<VkBindImageMemoryInfo>				bindImageMemoryInfos		(numImages);
1045 
1046 	for (deUint32 idx = 0; idx < numImages; ++idx)
1047 	{
1048 		// Create image
1049 		images[idx] = ImageSp(new UniqueImage(createImage(devHelper.vkd, *devHelper.device, &imageCreateInfo)));
1050 
1051 		VkBindImageMemorySwapchainInfoKHR bimsInfo =
1052 		{
1053 			VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR,
1054 			DE_NULL,
1055 			*swapchain,
1056 			idx
1057 		};
1058 		bindImageMemorySwapchainInfo[idx] = bimsInfo;
1059 
1060 		VkBindImageMemoryInfo bimInfo =
1061 		{
1062 			VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
1063 			&bindImageMemorySwapchainInfo[idx],
1064 			**images[idx],
1065 			DE_NULL,				// If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
1066 			0u						// If swapchain <in VkBindImageMemorySwapchainInfoKHR> is not NULL, the swapchain and imageIndex are used to determine the memory that the image is bound to, instead of memory and memoryOffset.
1067 		};
1068 
1069 		bindImageMemoryInfos[idx] = bimInfo;
1070 	}
1071 
1072 	VK_CHECK(devHelper.vkd.bindImageMemory2(*devHelper.device, numImages, &bindImageMemoryInfos[0]));
1073 
1074 	return tcu::TestStatus::pass("Pass");
1075 }
1076 
1077 struct GroupParameters
1078 {
1079 	typedef FunctionInstance1<TestParameters>::Function	Function;
1080 
1081 	Type		wsiType;
1082 	Function	function;
1083 
GroupParametersvkt::wsi::__anonc927807a0111::GroupParameters1084 	GroupParameters (Type wsiType_, Function function_)
1085 		: wsiType	(wsiType_)
1086 		, function	(function_)
1087 	{}
1088 
GroupParametersvkt::wsi::__anonc927807a0111::GroupParameters1089 	GroupParameters (void)
1090 		: wsiType	(TYPE_LAST)
1091 		, function	((Function)DE_NULL)
1092 	{}
1093 };
1094 
populateSwapchainGroup(tcu::TestCaseGroup * testGroup,GroupParameters params)1095 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
1096 {
1097 	for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
1098 	{
1099 		const TestDimension		testDimension	= (TestDimension)dimensionNdx;
1100 
1101 		addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
1102 	}
1103 
1104 	addFunctionCase(testGroup, "image_swapchain_create_info", "Test VkImageSwapchainCreateInfoKHR", testImageSwapchainCreateInfo, params.wsiType);
1105 }
1106 
populateSwapchainPrivateDataGroup(tcu::TestCaseGroup * testGroup,GroupParameters params)1107 void populateSwapchainPrivateDataGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
1108 {
1109 	for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
1110 	{
1111 		const TestDimension		testDimension	= (TestDimension)dimensionNdx;
1112 		if (testDimension == TEST_DIMENSION_IMAGE_EXTENT)
1113 			continue;
1114 
1115 		addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
1116 	}
1117 }
1118 
getBasicSwapchainParameters(Type wsiType,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,const tcu::UVec2 & desiredSize,deUint32 desiredImageCount)1119 VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type						wsiType,
1120 													  const InstanceInterface&	vki,
1121 													  VkPhysicalDevice			physicalDevice,
1122 													  VkSurfaceKHR				surface,
1123 													  const tcu::UVec2&			desiredSize,
1124 													  deUint32					desiredImageCount)
1125 {
1126 	const VkSurfaceCapabilitiesKHR		capabilities		= getPhysicalDeviceSurfaceCapabilities(vki,
1127 																								   physicalDevice,
1128 																								   surface);
1129 	const vector<VkSurfaceFormatKHR>	formats				= getPhysicalDeviceSurfaceFormats(vki,
1130 																							  physicalDevice,
1131 																							  surface);
1132 	const PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
1133 	const VkSurfaceTransformFlagBitsKHR transform			= (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
1134 	const VkSwapchainCreateInfoKHR		parameters			=
1135 	{
1136 		VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
1137 		DE_NULL,
1138 		(VkSwapchainCreateFlagsKHR)0,
1139 		surface,
1140 		de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
1141 		formats[0].format,
1142 		formats[0].colorSpace,
1143 		(platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
1144 			? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
1145 		1u,									// imageArrayLayers
1146 		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1147 		VK_SHARING_MODE_EXCLUSIVE,
1148 		0u,
1149 		(const deUint32*)DE_NULL,
1150 		transform,
1151 		VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
1152 		VK_PRESENT_MODE_FIFO_KHR,
1153 		VK_FALSE,							// clipped
1154 		(VkSwapchainKHR)0					// oldSwapchain
1155 	};
1156 
1157 	return parameters;
1158 }
1159 
1160 typedef de::SharedPtr<Unique<VkCommandBuffer> >	CommandBufferSp;
1161 typedef de::SharedPtr<Unique<VkFence> >			FenceSp;
1162 typedef de::SharedPtr<Unique<VkSemaphore> >		SemaphoreSp;
1163 
createFences(const DeviceInterface & vkd,const VkDevice device,size_t numFences,bool isSignaled=true)1164 vector<FenceSp> createFences (const DeviceInterface&	vkd,
1165 							  const VkDevice			device,
1166 							  size_t					numFences,
1167 							  bool                      isSignaled = true)
1168 {
1169 	vector<FenceSp> fences(numFences);
1170 
1171 	for (size_t ndx = 0; ndx < numFences; ++ndx)
1172 		fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device, (isSignaled) ? vk::VK_FENCE_CREATE_SIGNALED_BIT : 0)));
1173 
1174 	return fences;
1175 }
1176 
createSemaphores(const DeviceInterface & vkd,const VkDevice device,size_t numSemaphores)1177 vector<SemaphoreSp> createSemaphores (const DeviceInterface&	vkd,
1178 									  const VkDevice			device,
1179 									  size_t					numSemaphores)
1180 {
1181 	vector<SemaphoreSp> semaphores(numSemaphores);
1182 
1183 	for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1184 		semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
1185 
1186 	return semaphores;
1187 }
1188 
allocateCommandBuffers(const DeviceInterface & vkd,const VkDevice device,const VkCommandPool commandPool,const VkCommandBufferLevel level,const size_t numCommandBuffers)1189 vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface&		vkd,
1190 												const VkDevice				device,
1191 												const VkCommandPool			commandPool,
1192 												const VkCommandBufferLevel	level,
1193 												const size_t				numCommandBuffers)
1194 {
1195 	vector<CommandBufferSp>				buffers		(numCommandBuffers);
1196 
1197 	for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1198 		buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1199 
1200 	return buffers;
1201 }
1202 
1203 class AcquireNextImageWrapper
1204 {
1205 public:
1206 
AcquireNextImageWrapper(const DeviceInterface & vkd,VkDevice device,deUint32 deviceMask,VkSwapchainKHR swapchain,deUint64 timeout)1207 	AcquireNextImageWrapper(const DeviceInterface&	vkd,
1208 							VkDevice				device,
1209 							deUint32				deviceMask,
1210 							VkSwapchainKHR			swapchain,
1211 							deUint64				timeout)
1212 		: m_vkd			(vkd)
1213 		, m_device		(device)
1214 		, m_swapchain	(swapchain)
1215 		, m_timeout		(timeout)
1216 	{
1217 		DE_UNREF(deviceMask);	// needed for compatibility with acquireNextImage2KHR
1218 	}
1219 
featureAvailable(Context &)1220 	bool featureAvailable(Context&)
1221 	{
1222 		return true;			// needed for compatibility with acquireNextImage2KHR
1223 	}
1224 
call(VkSemaphore semaphore,VkFence fence,deUint32 * imageIndex)1225 	VkResult call(VkSemaphore semaphore, VkFence fence, deUint32* imageIndex)
1226 	{
1227 		return m_vkd.acquireNextImageKHR(m_device,
1228 										 m_swapchain,
1229 										 m_timeout,
1230 										 semaphore,
1231 										 fence,
1232 										 imageIndex);
1233 	}
1234 
1235 protected:
1236 
1237 	const DeviceInterface&	m_vkd;
1238 	VkDevice				m_device;
1239 	VkSwapchainKHR			m_swapchain;
1240 	deUint64				m_timeout;
1241 };
1242 
1243 class AcquireNextImage2Wrapper
1244 {
1245 public:
1246 
AcquireNextImage2Wrapper(const DeviceInterface & vkd,VkDevice device,deUint32 deviceMask,VkSwapchainKHR swapchain,deUint64 timeout)1247 	AcquireNextImage2Wrapper(const DeviceInterface&	vkd,
1248 							 VkDevice				device,
1249 							 deUint32				deviceMask,
1250 							 VkSwapchainKHR			swapchain,
1251 							 deUint64				timeout)
1252 		: m_vkd		(vkd)
1253 		, m_device	(device)
1254 	{
1255 		m_info.sType		= VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR;
1256 		m_info.pNext		= DE_NULL;
1257 		m_info.swapchain	= swapchain;
1258 		m_info.timeout		= timeout;
1259 		m_info.semaphore	= DE_NULL;
1260 		m_info.fence		= DE_NULL;
1261 		m_info.deviceMask	= deviceMask;
1262 	}
1263 
featureAvailable(Context & context)1264 	bool featureAvailable(Context& context)
1265 	{
1266 		return context.isDeviceFunctionalitySupported("VK_KHR_device_group");
1267 	}
1268 
call(VkSemaphore semaphore,VkFence fence,deUint32 * imageIndex)1269 	VkResult call(VkSemaphore semaphore, VkFence fence, deUint32* imageIndex)
1270 	{
1271 		m_info.semaphore	= semaphore;
1272 		m_info.fence		= fence;
1273 		return m_vkd.acquireNextImage2KHR(m_device,
1274 										  &m_info,
1275 										  imageIndex);
1276 	}
1277 
1278 protected:
1279 
1280 	const DeviceInterface&		m_vkd;
1281 	VkDevice					m_device;
1282 	VkAcquireNextImageInfoKHR	m_info;
1283 };
1284 
1285 
1286 template <typename AcquireWrapperType>
basicRenderTest(Context & context,Type wsiType)1287 tcu::TestStatus basicRenderTest (Context& context, Type wsiType)
1288 {
1289 	const tcu::UVec2				desiredSize					(256, 256);
1290 	const InstanceHelper			instHelper					(context, wsiType);
1291 	const NativeObjects				native						(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1292 	const Unique<VkSurfaceKHR>		surface						(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
1293 	const DeviceHelper				devHelper					(context, instHelper.vki, instHelper.instance, *surface);
1294 	const DeviceInterface&			vkd							= devHelper.vkd;
1295 	const VkDevice					device						= *devHelper.device;
1296 	SimpleAllocator					allocator					(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1297 	const VkSwapchainCreateInfoKHR	swapchainInfo				= getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1298 	const Unique<VkSwapchainKHR>	swapchain					(createSwapchainKHR(vkd, device, &swapchainInfo));
1299 	const vector<VkImage>			swapchainImages				= getSwapchainImages(vkd, device, *swapchain);
1300 
1301 	AcquireWrapperType acquireImageWrapper(vkd, device, 1u, *swapchain, std::numeric_limits<deUint64>::max());
1302 	if (!acquireImageWrapper.featureAvailable(context))
1303 		TCU_THROW(NotSupportedError, "Required extension is not supported");
1304 
1305 	const WsiTriangleRenderer		renderer					(vkd,
1306 																 device,
1307 																 allocator,
1308 																 context.getBinaryCollection(),
1309 																 false,
1310 																 swapchainImages,
1311 																 swapchainImages,
1312 																 swapchainInfo.imageFormat,
1313 																 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1314 
1315 	const Unique<VkCommandPool>		commandPool					(createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1316 
1317 	const size_t					maxQueuedFrames				= swapchainImages.size()*2;
1318 
1319 	// We need to keep hold of fences from vkAcquireNextImage(2)KHR to actually
1320 	// limit number of frames we allow to be queued.
1321 	const vector<FenceSp>			imageReadyFences			(createFences(vkd, device, maxQueuedFrames));
1322 
1323 	// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1324 	// the semaphore in same time as the fence we use to meter rendering.
1325 	const vector<SemaphoreSp>		imageReadySemaphores		(createSemaphores(vkd, device, maxQueuedFrames+1));
1326 
1327 	// For rest we simply need maxQueuedFrames as we will wait for image
1328 	// from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1329 	// previous uses must have completed.
1330 	const vector<SemaphoreSp>		renderingCompleteSemaphores	(createSemaphores(vkd, device, maxQueuedFrames));
1331 	const vector<CommandBufferSp>	commandBuffers				(allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1332 
1333 	try
1334 	{
1335 		const deUint32	numFramesToRender	= 60*10;
1336 
1337 		for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1338 		{
1339 			const VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
1340 			const VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1341 			deUint32			imageNdx			= ~0u;
1342 
1343 			VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1344 			VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1345 
1346 			{
1347 				const VkResult	acquireResult	= acquireImageWrapper.call(imageReadySemaphore, (VkFence)0, &imageNdx);
1348 
1349 				if (acquireResult == VK_SUBOPTIMAL_KHR)
1350 					context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1351 				else
1352 					VK_CHECK(acquireResult);
1353 			}
1354 
1355 			TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1356 
1357 			{
1358 				const VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1359 				const VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
1360 				const VkPipelineStageFlags	waitDstStage				= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1361 				const VkSubmitInfo			submitInfo					=
1362 				{
1363 					VK_STRUCTURE_TYPE_SUBMIT_INFO,
1364 					DE_NULL,
1365 					1u,
1366 					&imageReadySemaphore,
1367 					&waitDstStage,
1368 					1u,
1369 					&commandBuffer,
1370 					1u,
1371 					&renderingCompleteSemaphore
1372 				};
1373 				const VkPresentInfoKHR		presentInfo					=
1374 				{
1375 					VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1376 					DE_NULL,
1377 					1u,
1378 					&renderingCompleteSemaphore,
1379 					1u,
1380 					&*swapchain,
1381 					&imageNdx,
1382 					(VkResult*)DE_NULL
1383 				};
1384 
1385 				renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1386 				VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
1387 				VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1388 			}
1389 		}
1390 
1391 		VK_CHECK(vkd.deviceWaitIdle(device));
1392 	}
1393 	catch (...)
1394 	{
1395 		// Make sure device is idle before destroying resources
1396 		vkd.deviceWaitIdle(device);
1397 		throw;
1398 	}
1399 
1400 	return tcu::TestStatus::pass("Rendering tests succeeded");
1401 }
1402 
1403 class FrameStreamObjects
1404 {
1405 public:
1406 	struct FrameObjects
1407 	{
1408 		const vk::VkFence&			renderCompleteFence;
1409 		const vk::VkSemaphore&		renderCompleteSemaphore;
1410 		const vk::VkSemaphore&		imageAvailableSemaphore;
1411 		const vk::VkCommandBuffer&	commandBuffer;
1412 	};
1413 
FrameStreamObjects(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool cmdPool,size_t maxQueuedFrames)1414 	FrameStreamObjects (const vk::DeviceInterface& vkd, vk::VkDevice device, vk::VkCommandPool cmdPool, size_t maxQueuedFrames)
1415 		: renderingCompleteFences(createFences(vkd, device, maxQueuedFrames))
1416 		, renderingCompleteSemaphores(createSemaphores(vkd, device, maxQueuedFrames))
1417 		, imageAvailableSemaphores(createSemaphores(vkd, device, maxQueuedFrames))
1418 		, commandBuffers(allocateCommandBuffers(vkd, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames))
1419 		, m_maxQueuedFrames(maxQueuedFrames)
1420 		, m_nextFrame(0u)
1421 	{}
1422 
frameNumber(void) const1423 	size_t frameNumber (void) const { DE_ASSERT(m_nextFrame > 0u); return m_nextFrame - 1u; }
1424 
newFrame()1425 	FrameObjects newFrame ()
1426 	{
1427 		const size_t mod = m_nextFrame % m_maxQueuedFrames;
1428 		FrameObjects ret =
1429 		{
1430 			**renderingCompleteFences[mod],
1431 			**renderingCompleteSemaphores[mod],
1432 			**imageAvailableSemaphores[mod],
1433 			**commandBuffers[mod],
1434 		};
1435 		++m_nextFrame;
1436 		return ret;
1437 	}
1438 
1439 private:
1440 	const vector<FenceSp>			renderingCompleteFences;
1441 	const vector<SemaphoreSp>		renderingCompleteSemaphores;
1442 	const vector<SemaphoreSp>		imageAvailableSemaphores;
1443 	const vector<CommandBufferSp>	commandBuffers;
1444 
1445 	const size_t	m_maxQueuedFrames;
1446 	size_t			m_nextFrame;
1447 };
1448 
1449 struct MultiSwapchainParams
1450 {
1451 	Type	wsiType;
1452 	size_t	swapchainCount;
1453 };
1454 
1455 struct AccumulatedPresentInfo
1456 {
1457 	vector<VkSemaphore>		semaphores;
1458 	vector<VkSwapchainKHR>	swapchains;
1459 	vector<deUint32>		imageIndices;
1460 
AccumulatedPresentInfovkt::wsi::__anonc927807a0111::AccumulatedPresentInfo1461 	AccumulatedPresentInfo ()
1462 		: semaphores(), swapchains(), imageIndices()
1463 	{
1464 	}
1465 
push_backvkt::wsi::__anonc927807a0111::AccumulatedPresentInfo1466 	void push_back (VkSemaphore sem, VkSwapchainKHR sc, deUint32 index)
1467 	{
1468 		semaphores.push_back(sem);
1469 		swapchains.push_back(sc);
1470 		imageIndices.push_back(index);
1471 	}
1472 
resetvkt::wsi::__anonc927807a0111::AccumulatedPresentInfo1473 	void reset ()
1474 	{
1475 		semaphores.resize(0);
1476 		swapchains.resize(0);
1477 		imageIndices.resize(0);
1478 	}
1479 
sizevkt::wsi::__anonc927807a0111::AccumulatedPresentInfo1480 	size_t size () const
1481 	{
1482 		// Any of the vectors would do.
1483 		return semaphores.size();
1484 	}
1485 };
1486 
1487 template <typename AcquireWrapperType>
multiSwapchainRenderTest(Context & context,MultiSwapchainParams params)1488 tcu::TestStatus multiSwapchainRenderTest (Context& context, MultiSwapchainParams params)
1489 {
1490 	DE_ASSERT(params.swapchainCount > 0);
1491 
1492 	const tcu::UVec2		desiredSize	(256, 256);
1493 	const InstanceHelper	instHelper	(context, params.wsiType);
1494 
1495 	// Create native window system objects, surfaces and helper surface vector.
1496 	std::unique_ptr<NativeObjects> native;
1497 	try
1498 	{
1499 		native.reset(new NativeObjects(context, instHelper.supportedExtensions, params.wsiType, params.swapchainCount, tcu::just(desiredSize)));
1500 	}
1501 	catch(tcu::ResourceError&)
1502 	{
1503 		std::ostringstream msg;
1504 		msg << "Unable to create " << params.swapchainCount << " windows";
1505 		TCU_THROW(NotSupportedError, msg.str());
1506 	}
1507 
1508 	vector<Move<VkSurfaceKHR>>	surface;
1509 	vector<VkSurfaceKHR>		surfaceKHR;	// The plain Vulkan objects from the vector above.
1510 
1511 	for (size_t i = 0; i < params.swapchainCount; ++i)
1512 	{
1513 		surface.emplace_back(createSurface(instHelper.vki, instHelper.instance, params.wsiType, native->getDisplay(), native->getWindow(i)));
1514 		surfaceKHR.push_back(surface.back().get());
1515 	}
1516 
1517 	// Create a device compatible with all surfaces.
1518 	const DeviceHelper		devHelper	(context, instHelper.vki, instHelper.instance, surfaceKHR);
1519 	const DeviceInterface&	vkd			= devHelper.vkd;
1520 	const VkDevice			device		= *devHelper.device;
1521 	SimpleAllocator			allocator	(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1522 
1523 	// Create several swapchains and images.
1524 	vector<VkSwapchainCreateInfoKHR>	swapchainInfo;
1525 	vector<Move<VkSwapchainKHR>>		swapchain;
1526 	vector<vector<VkImage>>				swapchainImages;
1527 	vector<AcquireWrapperType>			acquireImageWrapper;
1528 	for (size_t i = 0; i < params.swapchainCount; ++i)
1529 	{
1530 		swapchainInfo.emplace_back(getBasicSwapchainParameters(params.wsiType, instHelper.vki, devHelper.physicalDevice, *surface[i], desiredSize, 2));
1531 		swapchain.emplace_back(createSwapchainKHR(vkd, device, &swapchainInfo.back()));
1532 		swapchainImages.emplace_back(getSwapchainImages(vkd, device, swapchain.back().get()));
1533 		acquireImageWrapper.emplace_back(vkd, device, 1u, swapchain.back().get(), std::numeric_limits<deUint64>::max());
1534 	}
1535 
1536 	// Every acquire wrapper requires the same features, so we only check the first one.
1537 	if (!acquireImageWrapper.front().featureAvailable(context))
1538 		TCU_THROW(NotSupportedError, "Required extension is not supported");
1539 
1540 	// Renderer per swapchain.
1541 	vector<WsiTriangleRenderer> renderer;
1542 	for (size_t i = 0; i < params.swapchainCount; ++i)
1543 	{
1544 		renderer.emplace_back(vkd,
1545 							  device,
1546 							  allocator,
1547 							  context.getBinaryCollection(),
1548 							  false,
1549 							  swapchainImages[i],
1550 							  swapchainImages[i],
1551 							  swapchainInfo[i].imageFormat,
1552 							  tcu::UVec2(swapchainInfo[i].imageExtent.width, swapchainInfo[i].imageExtent.height));
1553 	}
1554 
1555 	const Unique<VkCommandPool>	commandPool			(createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1556 	const size_t				maxQueuedFrames		= swapchainImages.front().size()*2;	// Limit in-flight frames.
1557 
1558 	vector<FrameStreamObjects>	frameStreamObjects;
1559 	for (size_t i = 0; i < params.swapchainCount; ++i)
1560 		frameStreamObjects.emplace_back(vkd, device, commandPool.get(), maxQueuedFrames);
1561 
1562 	try
1563 	{
1564 		// 3 seconds for 60 Hz screens.
1565 		const deUint32			kNumFramesToRender		= 60*3*static_cast<deUint32>(params.swapchainCount);
1566 		AccumulatedPresentInfo	accumulatedPresentInfo;
1567 
1568 		for (size_t frameNdx = 0; frameNdx < kNumFramesToRender; ++frameNdx)
1569 		{
1570 			size_t		swapchainIndex	= frameNdx % params.swapchainCount;
1571 			auto&		fsObjects		= frameStreamObjects[swapchainIndex];
1572 			auto		frameObjects	= fsObjects.newFrame();
1573 			deUint32	imageNdx		= std::numeric_limits<deUint32>::max();
1574 
1575 			VK_CHECK(vkd.waitForFences(device, 1u, &frameObjects.renderCompleteFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1576 			VK_CHECK(vkd.resetFences(device, 1u, &frameObjects.renderCompleteFence));
1577 
1578 			{
1579 				const VkResult acquireResult = acquireImageWrapper[swapchainIndex].call(frameObjects.imageAvailableSemaphore, (VkFence)DE_NULL, &imageNdx);
1580 				if (acquireResult == VK_SUBOPTIMAL_KHR)
1581 					context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1582 				else
1583 					VK_CHECK(acquireResult);
1584 			}
1585 
1586 			TCU_CHECK(static_cast<size_t>(imageNdx) < swapchainImages[swapchainIndex].size());
1587 
1588 			{
1589 				const VkPipelineStageFlags	waitDstStage	= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1590 				const VkSubmitInfo			submitInfo		=
1591 				{
1592 					VK_STRUCTURE_TYPE_SUBMIT_INFO,
1593 					DE_NULL,
1594 					1u,
1595 					&frameObjects.imageAvailableSemaphore,
1596 					&waitDstStage,
1597 					1u,
1598 					&frameObjects.commandBuffer,
1599 					1u,
1600 					&frameObjects.renderCompleteSemaphore,
1601 				};
1602 
1603 				renderer[swapchainIndex].recordFrame(frameObjects.commandBuffer, imageNdx, static_cast<deUint32>(frameNdx));
1604 				VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, frameObjects.renderCompleteFence));
1605 
1606 				// Save present information for the current frame.
1607 				accumulatedPresentInfo.push_back(frameObjects.renderCompleteSemaphore, swapchain[swapchainIndex].get(), imageNdx);
1608 
1609 				// Present frames when we have accumulated one frame per swapchain.
1610 				if (accumulatedPresentInfo.size() == params.swapchainCount)
1611 				{
1612 					DE_ASSERT(	accumulatedPresentInfo.semaphores.size() == accumulatedPresentInfo.swapchains.size()	&&
1613 								accumulatedPresentInfo.semaphores.size() == accumulatedPresentInfo.imageIndices.size()	);
1614 
1615 					vector<VkResult> results(params.swapchainCount, VK_ERROR_DEVICE_LOST);
1616 
1617 					const VkPresentInfoKHR presentInfo =
1618 					{
1619 						VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1620 						DE_NULL,
1621 						static_cast<deUint32>(accumulatedPresentInfo.semaphores.size()),
1622 						accumulatedPresentInfo.semaphores.data(),
1623 						static_cast<deUint32>(accumulatedPresentInfo.swapchains.size()),
1624 						accumulatedPresentInfo.swapchains.data(),
1625 						accumulatedPresentInfo.imageIndices.data(),
1626 						results.data(),
1627 					};
1628 
1629 					// Check both the global result and the individual results.
1630 					VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1631 					for (const auto& result : results)
1632 						VK_CHECK_WSI(result);
1633 
1634 					accumulatedPresentInfo.reset();
1635 				}
1636 			}
1637 		}
1638 
1639 		VK_CHECK(vkd.deviceWaitIdle(device));
1640 	}
1641 	catch (...)
1642 	{
1643 		// Make sure device is idle before destroying resources
1644 		vkd.deviceWaitIdle(device);
1645 		throw;
1646 	}
1647 
1648 	return tcu::TestStatus::pass("Rendering tests succeeded");
1649 }
1650 
deviceGroupRenderTest(Context & context,Type wsiType)1651 tcu::TestStatus deviceGroupRenderTest (Context& context, Type wsiType)
1652 {
1653 	const InstanceHelper		instHelper			(context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
1654 	const tcu::CommandLine&		cmdLine				= context.getTestContext().getCommandLine();
1655 	VkPhysicalDevice			physicalDevice		= chooseDevice(instHelper.vki, instHelper.instance, cmdLine);
1656 	const Extensions&			supportedExtensions	= enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
1657 
1658 	std::vector<const char*> deviceExtensions;
1659 	deviceExtensions.push_back("VK_KHR_swapchain");
1660 	if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
1661 		deviceExtensions.push_back("VK_KHR_device_group");
1662 
1663 	for (std::size_t ndx = 0; ndx < deviceExtensions.size(); ++ndx)
1664 	{
1665 		if (!isExtensionSupported(supportedExtensions, RequiredExtension(deviceExtensions[ndx])))
1666 			TCU_THROW(NotSupportedError, (string(deviceExtensions[ndx]) + " is not supported").c_str());
1667 	}
1668 
1669 	const tcu::UVec2								desiredSize					(256, 256);
1670 	const NativeObjects								native						(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1671 	const Unique<VkSurfaceKHR>						surface						(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
1672 
1673 	const deUint32									devGroupIdx					= cmdLine.getVKDeviceGroupId() - 1;
1674 	const deUint32									deviceIdx					= context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
1675 	const vector<VkPhysicalDeviceGroupProperties>	deviceGroupProps			= enumeratePhysicalDeviceGroups(instHelper.vki, instHelper.instance);
1676 	deUint32										physicalDevicesInGroupCount	= deviceGroupProps[devGroupIdx].physicalDeviceCount;
1677 	const VkPhysicalDevice*							physicalDevicesInGroup		= deviceGroupProps[devGroupIdx].physicalDevices;
1678 	deUint32										queueFamilyIndex			= chooseQueueFamilyIndex(instHelper.vki, physicalDevicesInGroup[deviceIdx], *surface);
1679 	const std::vector<VkQueueFamilyProperties>		queueProps					= getPhysicalDeviceQueueFamilyProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]);
1680 	const float										queuePriority				= 1.0f;
1681 	const deUint32									firstDeviceID				= 0;
1682 	const deUint32									secondDeviceID				= 1;
1683 
1684 	// create a device group
1685 	const VkDeviceGroupDeviceCreateInfo groupDeviceInfo =
1686 	{
1687 		VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR,			// stype
1688 		DE_NULL,														// pNext
1689 		physicalDevicesInGroupCount,									// physicalDeviceCount
1690 		physicalDevicesInGroup											// physicalDevices
1691 	};
1692 	const VkDeviceQueueCreateInfo deviceQueueCreateInfo =
1693 	{
1694 		VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,						// type
1695 		DE_NULL,														// pNext
1696 		(VkDeviceQueueCreateFlags)0u,									// flags
1697 		queueFamilyIndex,												// queueFamilyIndex
1698 		1u,																// queueCount
1699 		&queuePriority,													// pQueuePriorities
1700 	};
1701 
1702 	const VkDeviceCreateInfo	deviceCreateInfo =
1703 	{
1704 		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,							// sType
1705 		&groupDeviceInfo,												// pNext
1706 		(VkDeviceCreateFlags)0u,										// flags
1707 		1,																// queueRecordCount
1708 		&deviceQueueCreateInfo,											// pRequestedQueues
1709 		0,																// layerCount
1710 		DE_NULL,														// ppEnabledLayerNames
1711 		deUint32(deviceExtensions.size()),								// enabledExtensionCount
1712 		&deviceExtensions[0],											// ppEnabledExtensionNames
1713 		DE_NULL,														// pEnabledFeatures
1714 	};
1715 
1716 	Move<VkDevice>					groupDevice					= createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(), instHelper.instance, instHelper.vki, physicalDevicesInGroup[deviceIdx], &deviceCreateInfo);
1717 	const DeviceDriver				vkd							(context.getPlatformInterface(), instHelper.instance, *groupDevice);
1718 	VkQueue							queue						(getDeviceQueue(vkd, *groupDevice, queueFamilyIndex, 0));
1719 	SimpleAllocator					allocator					(vkd, *groupDevice, getPhysicalDeviceMemoryProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]));
1720 
1721 	// create swapchain for device group
1722 	VkDeviceGroupSwapchainCreateInfoKHR deviceGroupSwapchainInfo = initVulkanStructure();
1723 	deviceGroupSwapchainInfo.modes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
1724 
1725 	VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType,
1726 																		 instHelper.vki,
1727 																		 physicalDevicesInGroup[deviceIdx],
1728 																		 *surface,
1729 																		 desiredSize,
1730 																		 2);
1731 	swapchainInfo.pNext = &deviceGroupSwapchainInfo;
1732 
1733 	const Unique<VkSwapchainKHR>	swapchain					(createSwapchainKHR(vkd, *groupDevice, &swapchainInfo));
1734 	const vector<VkImage>			swapchainImages				= getSwapchainImages(vkd, *groupDevice, *swapchain);
1735 
1736 	const WsiTriangleRenderer		renderer					(vkd,
1737 																 *groupDevice,
1738 																 allocator,
1739 																 context.getBinaryCollection(),
1740 																 false,
1741 																 swapchainImages,
1742 																 swapchainImages,
1743 																 swapchainInfo.imageFormat,
1744 																 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1745 
1746 	const Unique<VkCommandPool>		commandPool					(createCommandPool(vkd, *groupDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1747 
1748 	const size_t					maxQueuedFrames				= swapchainImages.size()*2;
1749 
1750 	// We need to keep hold of fences from vkAcquireNextImage2KHR
1751 	// to actually limit number of frames we allow to be queued.
1752 	const vector<FenceSp>			imageReadyFences			(createFences(vkd, *groupDevice, maxQueuedFrames));
1753 
1754 	// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to
1755 	// pass the semaphore in same time as the fence we use to meter rendering.
1756 	const vector<SemaphoreSp>		imageReadySemaphores		(createSemaphores(vkd, *groupDevice, maxQueuedFrames+1));
1757 
1758 	// For rest we simply need maxQueuedFrames as we will wait for image from frameNdx-maxQueuedFrames
1759 	// to become available to us, guaranteeing that previous uses must have completed.
1760 	const vector<SemaphoreSp>		renderingCompleteSemaphores	(createSemaphores(vkd, *groupDevice, maxQueuedFrames));
1761 	const vector<CommandBufferSp>	commandBuffers				(allocateCommandBuffers(vkd, *groupDevice, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1762 
1763 	try
1764 	{
1765 		const deUint32	numFramesToRender = 60*10;
1766 
1767 		for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1768 		{
1769 			const VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
1770 			const VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1771 			deUint32			imageNdx			= ~0u;
1772 
1773 			VK_CHECK(vkd.waitForFences(*groupDevice, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1774 			VK_CHECK(vkd.resetFences(*groupDevice, 1, &imageReadyFence));
1775 
1776 			{
1777 				VkAcquireNextImageInfoKHR acquireNextImageInfo =
1778 				{
1779 					VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR,
1780 					DE_NULL,
1781 					*swapchain,
1782 					std::numeric_limits<deUint64>::max(),
1783 					imageReadySemaphore,
1784 					(VkFence)0,
1785 					(1 << firstDeviceID)
1786 				};
1787 
1788 				const VkResult acquireResult = vkd.acquireNextImage2KHR(*groupDevice, &acquireNextImageInfo, &imageNdx);
1789 
1790 				if (acquireResult == VK_SUBOPTIMAL_KHR)
1791 					context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1792 				else
1793 					VK_CHECK(acquireResult);
1794 			}
1795 
1796 			TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1797 
1798 			{
1799 				const VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1800 				const VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
1801 				const VkPipelineStageFlags	waitDstStage				= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1802 
1803 				// render triangle using one or two subdevices when available
1804 				renderer.recordDeviceGroupFrame(commandBuffer, firstDeviceID, secondDeviceID, physicalDevicesInGroupCount, imageNdx, frameNdx);
1805 
1806 				// submit queue
1807 				deUint32 deviceMask = (1 << firstDeviceID);
1808 				std::vector<deUint32> deviceIndices(1, firstDeviceID);
1809 				if (physicalDevicesInGroupCount > 1)
1810 				{
1811 					deviceMask |= (1 << secondDeviceID);
1812 					deviceIndices.push_back(secondDeviceID);
1813 				}
1814 				const VkDeviceGroupSubmitInfo deviceGroupSubmitInfo =
1815 				{
1816 					VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR,		// sType
1817 					DE_NULL,											// pNext
1818 					deUint32(deviceIndices.size()),						// waitSemaphoreCount
1819 					&deviceIndices[0],									// pWaitSemaphoreDeviceIndices
1820 					1u,													// commandBufferCount
1821 					&deviceMask,										// pCommandBufferDeviceMasks
1822 					deUint32(deviceIndices.size()),						// signalSemaphoreCount
1823 					&deviceIndices[0],									// pSignalSemaphoreDeviceIndices
1824 				};
1825 				const VkSubmitInfo submitInfo =
1826 				{
1827 					VK_STRUCTURE_TYPE_SUBMIT_INFO,						// sType
1828 					&deviceGroupSubmitInfo,								// pNext
1829 					1u,													// waitSemaphoreCount
1830 					&imageReadySemaphore,								// pWaitSemaphores
1831 					&waitDstStage,										// pWaitDstStageMask
1832 					1u,													// commandBufferCount
1833 					&commandBuffer,										// pCommandBuffers
1834 					1u,													// signalSemaphoreCount
1835 					&renderingCompleteSemaphore,						// pSignalSemaphores
1836 				};
1837 				VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, imageReadyFence));
1838 
1839 				// present swapchain image
1840 				deviceMask = (1 << firstDeviceID);
1841 				const VkDeviceGroupPresentInfoKHR deviceGroupPresentInfo =
1842 				{
1843 					VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR,
1844 					DE_NULL,
1845 					1u,
1846 					&deviceMask,
1847 					VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR,
1848 				};
1849 				const VkPresentInfoKHR presentInfo =
1850 				{
1851 					VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1852 					&deviceGroupPresentInfo,
1853 					1u,
1854 					&renderingCompleteSemaphore,
1855 					1u,
1856 					&*swapchain,
1857 					&imageNdx,
1858 					(VkResult*)DE_NULL
1859 				};
1860 				VK_CHECK_WSI(vkd.queuePresentKHR(queue, &presentInfo));
1861 			}
1862 		}
1863 
1864 		VK_CHECK(vkd.deviceWaitIdle(*groupDevice));
1865 	}
1866 	catch (...)
1867 	{
1868 		// Make sure device is idle before destroying resources
1869 		vkd.deviceWaitIdle(*groupDevice);
1870 		throw;
1871 	}
1872 
1873 	return tcu::TestStatus::pass("Rendering tests succeeded");
1874 }
1875 
deviceGroupRenderTest2(Context & context,Type wsiType)1876 tcu::TestStatus deviceGroupRenderTest2 (Context& context, Type wsiType)
1877 {
1878 	const InstanceHelper		instHelper			(context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
1879 	const tcu::CommandLine&		cmdLine				= context.getTestContext().getCommandLine();
1880 	VkPhysicalDevice			physicalDevice		= chooseDevice(instHelper.vki, instHelper.instance, cmdLine);
1881 	const Extensions&			deviceExtensions	= enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
1882 
1883 	// structures this tests checks were added in revision 69
1884 	if (!isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_swapchain", 69)))
1885 		TCU_THROW(NotSupportedError, "Required extension revision is not supported");
1886 
1887 	std::vector<const char*> requiredExtensions;
1888 	requiredExtensions.push_back("VK_KHR_swapchain");
1889 	if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
1890 	{
1891 		requiredExtensions.push_back("VK_KHR_device_group");
1892 		if (!isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_device_group")))
1893 			TCU_THROW(NotSupportedError, "VK_KHR_device_group is not supported");
1894 	}
1895 
1896 	const tcu::UVec2								desiredSize					(256, 256);
1897 	const NativeObjects								native						(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1898 	const Unique<VkSurfaceKHR>						surface						(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
1899 
1900 	const deUint32									devGroupIdx					= cmdLine.getVKDeviceGroupId() - 1;
1901 	const deUint32									deviceIdx					= context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
1902 	const vector<VkPhysicalDeviceGroupProperties>	deviceGroupProps			= enumeratePhysicalDeviceGroups(instHelper.vki, instHelper.instance);
1903 	deUint32										physicalDevicesInGroupCount	= deviceGroupProps[devGroupIdx].physicalDeviceCount;
1904 	const VkPhysicalDevice*							physicalDevicesInGroup		= deviceGroupProps[devGroupIdx].physicalDevices;
1905 	deUint32										queueFamilyIndex			= chooseQueueFamilyIndex(instHelper.vki, physicalDevicesInGroup[deviceIdx], *surface);
1906 	const std::vector<VkQueueFamilyProperties>		queueProps					= getPhysicalDeviceQueueFamilyProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]);
1907 	const float										queuePriority				= 1.0f;
1908 	const deUint32									firstDeviceID				= 0;
1909 	const deUint32									secondDeviceID				= 1;
1910 	const deUint32									deviceIndices[]				= { firstDeviceID, secondDeviceID };
1911 
1912 	if (physicalDevicesInGroupCount < 2)
1913 		TCU_THROW(NotSupportedError, "Test requires more than 1 device in device group");
1914 
1915 	// create a device group
1916 	const VkDeviceGroupDeviceCreateInfo groupDeviceInfo =
1917 	{
1918 		VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR,			// stype
1919 		DE_NULL,														// pNext
1920 		physicalDevicesInGroupCount,									// physicalDeviceCount
1921 		physicalDevicesInGroup											// physicalDevices
1922 	};
1923 	const VkDeviceQueueCreateInfo deviceQueueCreateInfo =
1924 	{
1925 		VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,						// type
1926 		DE_NULL,														// pNext
1927 		(VkDeviceQueueCreateFlags)0u,									// flags
1928 		queueFamilyIndex,												// queueFamilyIndex
1929 		1u,																// queueCount
1930 		&queuePriority,													// pQueuePriorities
1931 	};
1932 
1933 	const VkDeviceCreateInfo deviceCreateInfo =
1934 	{
1935 		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,							// sType
1936 		&groupDeviceInfo,												// pNext
1937 		(VkDeviceCreateFlags)0u,										// flags
1938 		1,																// queueRecordCount
1939 		&deviceQueueCreateInfo,											// pRequestedQueues
1940 		0,																// layerCount
1941 		DE_NULL,														// ppEnabledLayerNames
1942 		deUint32(requiredExtensions.size()),							// enabledExtensionCount
1943 		&requiredExtensions[0],											// ppEnabledExtensionNames
1944 		DE_NULL,														// pEnabledFeatures
1945 	};
1946 
1947 	Move<VkDevice>						groupDevice			= createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(), instHelper.instance, instHelper.vki, physicalDevicesInGroup[deviceIdx], &deviceCreateInfo);
1948 	const DeviceDriver					vkd					(context.getPlatformInterface(), instHelper.instance, *groupDevice);
1949 	VkQueue								queue				(getDeviceQueue(vkd, *groupDevice, queueFamilyIndex, 0));
1950 	SimpleAllocator						allocator			(vkd, *groupDevice, getPhysicalDeviceMemoryProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]));
1951 
1952 	// create swapchain for device group
1953 	const VkSurfaceCapabilitiesKHR		capabilities		= getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevice, *surface);
1954 	const vector<VkSurfaceFormatKHR>	formats				= getPhysicalDeviceSurfaceFormats(instHelper.vki, physicalDevice, *surface);
1955 	const PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
1956 	const VkSurfaceTransformFlagBitsKHR transform			= (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
1957 	const deUint32						desiredImageCount	= 2;
1958 
1959 	struct VkDeviceGroupSwapchainCreateInfoKHR deviceGroupSwapchainInfo =
1960 	{
1961 		VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
1962 		DE_NULL,
1963 		VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR
1964 	};
1965 	const VkSwapchainCreateInfoKHR swapchainInfo =
1966 	{
1967 		VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
1968 		&deviceGroupSwapchainInfo,
1969 		VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR,
1970 		*surface,
1971 		de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
1972 		formats[0].format,
1973 		formats[0].colorSpace,
1974 		(platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
1975 			? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
1976 		1u,
1977 		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1978 		VK_SHARING_MODE_EXCLUSIVE,
1979 		0u,
1980 		(const deUint32*)DE_NULL,
1981 		transform,
1982 		VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
1983 		VK_PRESENT_MODE_FIFO_KHR,
1984 		VK_FALSE,
1985 		(VkSwapchainKHR)0
1986 	};
1987 
1988 	const Unique<VkSwapchainKHR>	swapchain	(createSwapchainKHR(vkd, *groupDevice, &swapchainInfo));
1989 	deUint32						numImages	= 0;
1990 	VK_CHECK(vkd.getSwapchainImagesKHR(*groupDevice, *swapchain, &numImages, DE_NULL));
1991 	if (numImages == 0)
1992 		return tcu::TestStatus::pass("Pass");
1993 
1994 	VkImageSwapchainCreateInfoKHR imageSwapchainCreateInfo =
1995 	{
1996 		VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
1997 		DE_NULL,
1998 		*swapchain
1999 	};
2000 
2001 	VkImageCreateInfo imageCreateInfo =
2002 	{
2003 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2004 		&imageSwapchainCreateInfo,
2005 		VK_IMAGE_CREATE_ALIAS_BIT |
2006 		VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR,		// flags
2007 		VK_IMAGE_TYPE_2D,											// imageType
2008 		formats[0].format,											// format
2009 		{															// extent
2010 			desiredSize.x(),										//   width
2011 			desiredSize.y(),										//   height
2012 			1u														//   depth
2013 		},
2014 		1u,															// mipLevels
2015 		1u,															// arrayLayers
2016 		VK_SAMPLE_COUNT_1_BIT,										// samples
2017 		VK_IMAGE_TILING_OPTIMAL,									// tiling
2018 		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,						// usage
2019 		VK_SHARING_MODE_EXCLUSIVE,									// sharingMode
2020 		0u,															// queueFamilyIndexCount
2021 		DE_NULL,													// pQueueFamilyIndices
2022 		VK_IMAGE_LAYOUT_UNDEFINED									// initialLayout
2023 	};
2024 
2025 	typedef vk::Unique<VkImage>			UniqueImage;
2026 	typedef de::SharedPtr<UniqueImage>	ImageSp;
2027 
2028 	vector<ImageSp>								images							(numImages);
2029 	vector<VkImage>								rawImages						(numImages);
2030 	vector<ImageSp>								imagesSfr						(numImages);
2031 	vector<VkImage>								rawImagesSfr					(numImages);
2032 	vector<VkBindImageMemorySwapchainInfoKHR>	bindImageMemorySwapchainInfo	(numImages);
2033 
2034 	// Create non-SFR image aliases for image layout transition
2035 	{
2036 		vector<VkBindImageMemoryInfo>				bindImageMemoryInfos			(numImages);
2037 
2038 		for (deUint32 idx = 0; idx < numImages; ++idx)
2039 		{
2040 			// Create image
2041 			images[idx] = ImageSp(new UniqueImage(createImage(vkd, *groupDevice, &imageCreateInfo)));
2042 
2043 			VkBindImageMemorySwapchainInfoKHR bimsInfo =
2044 			{
2045 				VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR,
2046 				DE_NULL,
2047 				*swapchain,
2048 				idx
2049 			};
2050 			bindImageMemorySwapchainInfo[idx] = bimsInfo;
2051 
2052 			VkBindImageMemoryInfo bimInfo =
2053 			{
2054 				VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
2055 				&bindImageMemorySwapchainInfo[idx],
2056 				**images[idx],
2057 				DE_NULL,				// If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
2058 				0u						// If swapchain <in VkBindImageMemorySwapchainInfoKHR> is not NULL, the swapchain and imageIndex are used to determine the memory that the image is bound to, instead of memory and memoryOffset.
2059 			};
2060 			bindImageMemoryInfos[idx]	= bimInfo;
2061 			rawImages[idx]				= **images[idx];
2062 		}
2063 
2064 		VK_CHECK(vkd.bindImageMemory2(*groupDevice, numImages, &bindImageMemoryInfos[0]));
2065 	}
2066 
2067 	// Create the SFR images
2068 	{
2069 		vector<VkBindImageMemoryDeviceGroupInfo	>	bindImageMemoryDeviceGroupInfo	(numImages);
2070 		vector<VkBindImageMemoryInfo>				bindImageMemoryInfos			(numImages);
2071 		for (deUint32 idx = 0; idx < numImages; ++idx)
2072 		{
2073 			// Create image
2074 			imagesSfr[idx] = ImageSp(new UniqueImage(createImage(vkd, *groupDevice, &imageCreateInfo)));
2075 
2076 		// Split into 2 vertical halves
2077 		// NOTE: the same split has to be done also in WsiTriangleRenderer::recordDeviceGroupFrame
2078 		const deUint32	halfWidth			= desiredSize.x() / 2;
2079 		const deUint32	height				= desiredSize.y();
2080 		const VkRect2D	sfrRects[] =
2081 		{
2082 			{	{ 0, 0 },					{ halfWidth, height }	},		// offset, extent
2083 			{	{ (deInt32)halfWidth, 0 },	{ halfWidth, height }	},		// offset, extent
2084 			{	{ 0, 0 },					{ halfWidth, height }	},		// offset, extent
2085 			{	{ (deInt32)halfWidth, 0 },	{ halfWidth, height }	}		// offset, extent
2086 		};
2087 
2088 		VkBindImageMemoryDeviceGroupInfo bimdgInfo =
2089 		{
2090 			VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO,
2091 			&bindImageMemorySwapchainInfo[idx],
2092 			DE_LENGTH_OF_ARRAY(deviceIndices),
2093 			deviceIndices,
2094 			DE_LENGTH_OF_ARRAY(sfrRects),
2095 			sfrRects
2096 		};
2097 		bindImageMemoryDeviceGroupInfo[idx] = bimdgInfo;
2098 
2099 		VkBindImageMemoryInfo bimInfo =
2100 		{
2101 			VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
2102 			&bindImageMemoryDeviceGroupInfo[idx],
2103 				**imagesSfr[idx],
2104 			DE_NULL,				// If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
2105 			0u						// If swapchain <in VkBindImageMemorySwapchainInfoKHR> is not NULL, the swapchain and imageIndex are used to determine the memory that the image is bound to, instead of memory and memoryOffset.
2106 		};
2107 		bindImageMemoryInfos[idx]	= bimInfo;
2108 			rawImagesSfr[idx]			= **imagesSfr[idx];
2109 	}
2110 
2111 	VK_CHECK(vkd.bindImageMemory2(*groupDevice, numImages, &bindImageMemoryInfos[0]));
2112 	}
2113 
2114 	VkPeerMemoryFeatureFlags peerMemoryFeatures = 0u;
2115 	vkd.getDeviceGroupPeerMemoryFeatures(*groupDevice, 0, firstDeviceID, secondDeviceID, &peerMemoryFeatures);
2116 	bool explicitLayoutTransitions = !(peerMemoryFeatures & VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT) ||
2117 									 !(peerMemoryFeatures & VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT);
2118 
2119 	const WsiTriangleRenderer			renderer					(vkd,
2120 																 *groupDevice,
2121 																 allocator,
2122 																 context.getBinaryCollection(),
2123 																 explicitLayoutTransitions,
2124 																 rawImagesSfr,
2125 																 rawImages,
2126 																 swapchainInfo.imageFormat,
2127 																 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
2128 
2129 	const Unique<VkCommandPool>		commandPool					(createCommandPool(vkd, *groupDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2130 
2131 	const size_t					maxQueuedFrames				= rawImagesSfr.size()*2;
2132 
2133 	// We need to keep hold of fences from vkAcquireNextImage2KHR
2134 	// to actually limit number of frames we allow to be queued.
2135 	const vector<FenceSp>			imageReadyFences			(createFences(vkd, *groupDevice, maxQueuedFrames));
2136 
2137 	// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to
2138 	// pass the semaphore in same time as the fence we use to meter rendering.
2139 	const vector<SemaphoreSp>		imageReadySemaphores		(createSemaphores(vkd, *groupDevice, maxQueuedFrames+1));
2140 
2141 	// For rest we simply need maxQueuedFrames as we will wait for image from frameNdx-maxQueuedFrames
2142 	// to become available to us, guaranteeing that previous uses must have completed.
2143 	const vector<SemaphoreSp>		renderingCompleteSemaphores	(createSemaphores(vkd, *groupDevice, maxQueuedFrames));
2144 	const vector<CommandBufferSp>	commandBuffers				(allocateCommandBuffers(vkd, *groupDevice, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
2145 
2146 	try
2147 	{
2148 		const deUint32	numFramesToRender = 60*10;
2149 
2150 		for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
2151 		{
2152 			const VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
2153 			const VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
2154 			deUint32			imageNdx			= ~0u;
2155 
2156 			VK_CHECK(vkd.waitForFences(*groupDevice, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
2157 			VK_CHECK(vkd.resetFences(*groupDevice, 1, &imageReadyFence));
2158 
2159 			{
2160 				VkAcquireNextImageInfoKHR acquireNextImageInfo =
2161 				{
2162 					VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR,
2163 					DE_NULL,
2164 					*swapchain,
2165 					std::numeric_limits<deUint64>::max(),
2166 					imageReadySemaphore,
2167 					(VkFence)0,
2168 					(1 << firstDeviceID)
2169 				};
2170 
2171 				const VkResult acquireResult = vkd.acquireNextImage2KHR(*groupDevice, &acquireNextImageInfo, &imageNdx);
2172 
2173 				if (acquireResult == VK_SUBOPTIMAL_KHR)
2174 					context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
2175 				else
2176 					VK_CHECK(acquireResult);
2177 			}
2178 
2179 			TCU_CHECK((size_t)imageNdx < rawImagesSfr.size());
2180 
2181 			{
2182 				const VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
2183 				const VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
2184 				const VkPipelineStageFlags	waitDstStage				= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2185 
2186 				// render triangle using one or two subdevices when available
2187 				renderer.recordDeviceGroupFrame(commandBuffer, firstDeviceID, secondDeviceID, physicalDevicesInGroupCount, imageNdx, frameNdx);
2188 
2189 				// submit queue
2190 				deUint32 deviceMask = (1 << firstDeviceID) | (1 << secondDeviceID);
2191 				const VkDeviceGroupSubmitInfo deviceGroupSubmitInfo =
2192 				{
2193 					VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR,		// sType
2194 					DE_NULL,											// pNext
2195 					DE_LENGTH_OF_ARRAY(deviceIndices),					// waitSemaphoreCount
2196 					deviceIndices,										// pWaitSemaphoreDeviceIndices
2197 					1u,													// commandBufferCount
2198 					&deviceMask,										// pCommandBufferDeviceMasks
2199 					DE_LENGTH_OF_ARRAY(deviceIndices),					// signalSemaphoreCount
2200 					deviceIndices,										// pSignalSemaphoreDeviceIndices
2201 				};
2202 				const VkSubmitInfo submitInfo =
2203 				{
2204 					VK_STRUCTURE_TYPE_SUBMIT_INFO,						// sType
2205 					&deviceGroupSubmitInfo,								// pNext
2206 					1u,													// waitSemaphoreCount
2207 					&imageReadySemaphore,								// pWaitSemaphores
2208 					&waitDstStage,										// pWaitDstStageMask
2209 					1u,													// commandBufferCount
2210 					&commandBuffer,										// pCommandBuffers
2211 					1u,													// signalSemaphoreCount
2212 					&renderingCompleteSemaphore,						// pSignalSemaphores
2213 				};
2214 				VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, imageReadyFence));
2215 
2216 				// present swapchain image -  asume that first device has a presentation engine
2217 				deviceMask = (1 << firstDeviceID);
2218 				const VkDeviceGroupPresentInfoKHR deviceGroupPresentInfo =
2219 				{
2220 					VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR,
2221 					DE_NULL,
2222 					1u,
2223 					&deviceMask,
2224 					VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR,
2225 				};
2226 				const VkPresentInfoKHR presentInfo =
2227 				{
2228 					VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
2229 					&deviceGroupPresentInfo,
2230 					1u,
2231 					&renderingCompleteSemaphore,
2232 					1u,
2233 					&*swapchain,
2234 					&imageNdx,
2235 					(VkResult*)DE_NULL
2236 				};
2237 				VK_CHECK(vkd.queuePresentKHR(queue, &presentInfo));
2238 			}
2239 		}
2240 
2241 		VK_CHECK(vkd.deviceWaitIdle(*groupDevice));
2242 	}
2243 	catch (...)
2244 	{
2245 		// Make sure device is idle before destroying resources
2246 		vkd.deviceWaitIdle(*groupDevice);
2247 		throw;
2248 	}
2249 
2250 	return tcu::TestStatus::pass("Rendering tests succeeded");
2251 }
2252 
getSwapchainSizeSequence(const VkSurfaceCapabilitiesKHR & capabilities,const tcu::UVec2 & defaultSize)2253 vector<tcu::UVec2> getSwapchainSizeSequence (const VkSurfaceCapabilitiesKHR& capabilities, const tcu::UVec2& defaultSize)
2254 {
2255 	vector<tcu::UVec2> sizes(3);
2256 	sizes[0] = defaultSize / 2u;
2257 	sizes[1] = defaultSize;
2258 	sizes[2] = defaultSize * 2u;
2259 
2260 	for (deUint32 i = 0; i < sizes.size(); ++i)
2261 	{
2262 		sizes[i].x() = de::clamp(sizes[i].x(), capabilities.minImageExtent.width,  capabilities.maxImageExtent.width);
2263 		sizes[i].y() = de::clamp(sizes[i].y(), capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
2264 	}
2265 
2266 	return sizes;
2267 }
2268 
resizeSwapchainTest(Context & context,Type wsiType)2269 tcu::TestStatus resizeSwapchainTest (Context& context, Type wsiType)
2270 {
2271 	const tcu::UVec2				desiredSize			(256, 256);
2272 	const InstanceHelper			instHelper			(context, wsiType);
2273 	const NativeObjects				native				(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2274 	const Unique<VkSurfaceKHR>		surface				(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2275 	const DeviceHelper				devHelper			(context, instHelper.vki, instHelper.instance, *surface);
2276 	const PlatformProperties&		platformProperties	= getPlatformProperties(wsiType);
2277 	const VkSurfaceCapabilitiesKHR	capabilities		= getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
2278 	const DeviceInterface&			vkd					= devHelper.vkd;
2279 	const VkDevice					device				= *devHelper.device;
2280 	SimpleAllocator					allocator			(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
2281 	vector<tcu::UVec2>				sizes				= getSwapchainSizeSequence(capabilities, desiredSize);
2282 	Move<VkSwapchainKHR>			prevSwapchain;
2283 
2284 	DE_ASSERT(platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE);
2285 	DE_UNREF(platformProperties);
2286 
2287 	for (deUint32 sizeNdx = 0; sizeNdx < sizes.size(); ++sizeNdx)
2288 	{
2289 		// \todo [2016-05-30 jesse] This test currently waits for idle and
2290 		// recreates way more than necessary when recreating the swapchain. Make
2291 		// it match expected real app behavior better by smoothly switching from
2292 		// old to new swapchain. Once that is done, it will also be possible to
2293 		// test creating a new swapchain while images from the previous one are
2294 		// still acquired.
2295 
2296 		VkSwapchainCreateInfoKHR		swapchainInfo				= getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, sizes[sizeNdx], 2);
2297 		swapchainInfo.oldSwapchain = *prevSwapchain;
2298 
2299 		Move<VkSwapchainKHR>			swapchain					(createSwapchainKHR(vkd, device, &swapchainInfo));
2300 		const vector<VkImage>			swapchainImages				= getSwapchainImages(vkd, device, *swapchain);
2301 		const WsiTriangleRenderer		renderer					(vkd,
2302 																	device,
2303 																	allocator,
2304 																	context.getBinaryCollection(),
2305 																	false,
2306 																	swapchainImages,
2307 																	swapchainImages,
2308 																	swapchainInfo.imageFormat,
2309 																	tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
2310 		const Unique<VkCommandPool>		commandPool					(createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
2311 		const size_t					maxQueuedFrames				= swapchainImages.size()*2;
2312 
2313 		// We need to keep hold of fences from vkAcquireNextImageKHR to actually
2314 		// limit number of frames we allow to be queued.
2315 		const vector<FenceSp>			imageReadyFences			(createFences(vkd, device, maxQueuedFrames));
2316 
2317 		// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
2318 		// the semaphore in same time as the fence we use to meter rendering.
2319 		const vector<SemaphoreSp>		imageReadySemaphores		(createSemaphores(vkd, device, maxQueuedFrames+1));
2320 
2321 		// For rest we simply need maxQueuedFrames as we will wait for image
2322 		// from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
2323 		// previous uses must have completed.
2324 		const vector<SemaphoreSp>		renderingCompleteSemaphores	(createSemaphores(vkd, device, maxQueuedFrames));
2325 		const vector<CommandBufferSp>	commandBuffers				(allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
2326 
2327 		try
2328 		{
2329 			const deUint32	numFramesToRender	= 60;
2330 
2331 			for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
2332 			{
2333 				const VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
2334 				const VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
2335 				deUint32			imageNdx			= ~0u;
2336 
2337 				VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
2338 				VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
2339 
2340 				{
2341 					const VkResult	acquireResult	= vkd.acquireNextImageKHR(device,
2342 																			  *swapchain,
2343 																			  std::numeric_limits<deUint64>::max(),
2344 																			  imageReadySemaphore,
2345 																			  DE_NULL,
2346 																			  &imageNdx);
2347 
2348 					if (acquireResult == VK_SUBOPTIMAL_KHR)
2349 						context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
2350 					else
2351 						VK_CHECK(acquireResult);
2352 				}
2353 
2354 				TCU_CHECK((size_t)imageNdx < swapchainImages.size());
2355 
2356 				{
2357 					const VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
2358 					const VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
2359 					const VkPipelineStageFlags	waitDstStage				= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2360 					const VkSubmitInfo			submitInfo					=
2361 					{
2362 						VK_STRUCTURE_TYPE_SUBMIT_INFO,
2363 						DE_NULL,
2364 						1u,
2365 						&imageReadySemaphore,
2366 						&waitDstStage,
2367 						1u,
2368 						&commandBuffer,
2369 						1u,
2370 						&renderingCompleteSemaphore
2371 					};
2372 					const VkPresentInfoKHR		presentInfo					=
2373 					{
2374 						VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
2375 						DE_NULL,
2376 						1u,
2377 						&renderingCompleteSemaphore,
2378 						1u,
2379 						&*swapchain,
2380 						&imageNdx,
2381 						(VkResult*)DE_NULL
2382 					};
2383 
2384 					renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
2385 					VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
2386 					VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
2387 				}
2388 			}
2389 
2390 			VK_CHECK(vkd.deviceWaitIdle(device));
2391 
2392 			prevSwapchain = swapchain;
2393 		}
2394 		catch (...)
2395 		{
2396 			// Make sure device is idle before destroying resources
2397 			vkd.deviceWaitIdle(device);
2398 			throw;
2399 		}
2400 	}
2401 
2402 	return tcu::TestStatus::pass("Resizing tests succeeded");
2403 }
2404 
getImagesIncompleteResultTest(Context & context,Type wsiType)2405 tcu::TestStatus getImagesIncompleteResultTest (Context& context, Type wsiType)
2406 {
2407 	const tcu::UVec2				desiredSize		(256, 256);
2408 	const InstanceHelper			instHelper		(context, wsiType);
2409 	const NativeObjects				native			(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2410 	const Unique<VkSurfaceKHR>		surface			(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2411 	const DeviceHelper				devHelper		(context, instHelper.vki, instHelper.instance, *surface);
2412 	const VkSwapchainCreateInfoKHR	swapchainInfo	= getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2413 	const Unique<VkSwapchainKHR>	swapchain		(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2414 
2415 	vector<VkImage>		swapchainImages	= getSwapchainImages(devHelper.vkd, *devHelper.device, *swapchain);
2416 
2417 	ValidateQueryBits::fillBits(swapchainImages.begin(), swapchainImages.end());
2418 
2419 	const deUint32		usedCount		= static_cast<deUint32>(swapchainImages.size() / 2);
2420 	deUint32			count			= usedCount;
2421 	const VkResult		result			= devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &count, &swapchainImages[0]);
2422 
2423 	if (count != usedCount || result != VK_INCOMPLETE || !ValidateQueryBits::checkBits(swapchainImages.begin() + count, swapchainImages.end()))
2424 		return tcu::TestStatus::fail("Get swapchain images didn't return VK_INCOMPLETE");
2425 	else
2426 		return tcu::TestStatus::pass("Get swapchain images tests succeeded");
2427 }
2428 
getImagesResultsCountTest(Context & context,Type wsiType)2429 tcu::TestStatus getImagesResultsCountTest (Context& context, Type wsiType)
2430 {
2431 	const tcu::UVec2				desiredSize(256, 256);
2432 	const InstanceHelper			instHelper(context, wsiType);
2433 	const NativeObjects				native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2434 	const Unique<VkSurfaceKHR>		surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2435 	const DeviceHelper				devHelper(context, instHelper.vki, instHelper.instance, *surface);
2436 	const VkSwapchainCreateInfoKHR	swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2437 	const Unique<VkSwapchainKHR>	swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2438 
2439 	deUint32	numImages = 0;
2440 
2441 	VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2442 
2443 	if (numImages > 0)
2444 	{
2445 		std::vector<VkImage>	images			(numImages + 1);
2446 		const deUint32			numImagesOrig	= numImages;
2447 
2448 		// check if below call properly overwrites formats count
2449 		numImages++;
2450 
2451 		VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, &images[0]));
2452 
2453 		if ((size_t)numImages != numImagesOrig)
2454 			TCU_FAIL("Image count changed between calls");
2455 	}
2456 	return tcu::TestStatus::pass("Get swapchain images tests succeeded");
2457 }
2458 
destroyNullHandleSwapchainTest(Context & context,Type wsiType)2459 tcu::TestStatus destroyNullHandleSwapchainTest (Context& context, Type wsiType)
2460 {
2461 	const InstanceHelper		instHelper	(context, wsiType);
2462 	const NativeObjects			native		(context, instHelper.supportedExtensions, wsiType);
2463 	const Unique<VkSurfaceKHR>	surface		(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2464 	const DeviceHelper			devHelper	(context, instHelper.vki, instHelper.instance, *surface);
2465 	const VkSwapchainKHR		nullHandle	= DE_NULL;
2466 
2467 	// Default allocator
2468 	devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, DE_NULL);
2469 
2470 	// Custom allocator
2471 	{
2472 		AllocationCallbackRecorder	recordingAllocator	(getSystemAllocator(), 1u);
2473 
2474 		devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, recordingAllocator.getCallbacks());
2475 
2476 		if (recordingAllocator.getNumRecords() != 0u)
2477 			return tcu::TestStatus::fail("Implementation allocated/freed the memory");
2478 	}
2479 
2480 	return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
2481 }
2482 
destroyOldSwapchainTest(Context & context,Type wsiType)2483 tcu::TestStatus destroyOldSwapchainTest (Context& context, Type wsiType)
2484 {
2485 	const tcu::UVec2			desiredSize			(256, 256);
2486 	const InstanceHelper		instHelper			(context, wsiType);
2487 	const NativeObjects			native				(context, instHelper.supportedExtensions, wsiType);
2488 	const Unique<VkSurfaceKHR>	surface				(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2489 	const DeviceHelper			devHelper			(context, instHelper.vki, instHelper.instance, *surface);
2490 
2491 	// Create the first swapchain.
2492 	VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2493 	VkSwapchainKHR swapchain = 0;
2494 	VK_CHECK(devHelper.vkd.createSwapchainKHR(*devHelper.device, &swapchainInfo, DE_NULL, &swapchain));
2495 
2496 	// Create a new swapchain replacing the old one.
2497 	swapchainInfo.oldSwapchain = swapchain;
2498 	VkSwapchainKHR recreatedSwapchain = 0;
2499 	VK_CHECK(devHelper.vkd.createSwapchainKHR(*devHelper.device, &swapchainInfo, DE_NULL, &recreatedSwapchain));
2500 
2501 	// Destroying the old swapchain should have no effect.
2502 	devHelper.vkd.destroySwapchainKHR(*devHelper.device, swapchain, DE_NULL);
2503 
2504 	// Destroy the new swapchain for cleanup.
2505 	devHelper.vkd.destroySwapchainKHR(*devHelper.device, recreatedSwapchain, DE_NULL);
2506 
2507 	return tcu::TestStatus::pass("Destroying an old swapchain has no effect.");
2508 }
2509 
acquireTooManyTest(Context & context,Type wsiType)2510 tcu::TestStatus acquireTooManyTest (Context& context, Type wsiType)
2511 {
2512 	const tcu::UVec2               desiredSize     (256, 256);
2513 	const InstanceHelper           instHelper      (context, wsiType);
2514 	const NativeObjects            native          (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
2515 	const Unique<VkSurfaceKHR>     surface         (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2516 	const DeviceHelper             devHelper       (context, instHelper.vki, instHelper.instance, *surface);
2517 	const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2518 	const Unique<VkSwapchainKHR>   swapchain       (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2519 
2520 	deUint32 numImages;
2521 	VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2522 	const deUint32 minImageCount = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface).minImageCount;
2523 	if (numImages < minImageCount) return tcu::TestStatus::fail("Get swapchain images returned less than minImageCount images");
2524 	const deUint32 numAcquirableImages = numImages - minImageCount + 1;
2525 
2526 	const auto fences = createFences(devHelper.vkd, *devHelper.device, numAcquirableImages + 1, false);
2527 	deUint32 dummy;
2528 	for (deUint32 i = 0; i < numAcquirableImages; ++i) {
2529 		VK_CHECK_WSI(devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, std::numeric_limits<deUint64>::max(), (VkSemaphore)0, **fences[i], &dummy));
2530 	}
2531 
2532 	const auto result = devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, 0, (VkSemaphore)0, **fences[numAcquirableImages], &dummy);
2533 
2534 	if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR && result != VK_NOT_READY ){
2535 		return tcu::TestStatus::fail("Implementation failed to respond well acquiring too many images with 0 timeout");
2536 	}
2537 
2538 	// cleanup
2539 	const deUint32 numFences = (result == VK_NOT_READY) ? static_cast<deUint32>(fences.size() - 1) : static_cast<deUint32>(fences.size());
2540 	vector<vk::VkFence> fencesRaw(numFences);
2541 	std::transform(fences.begin(), fences.begin() + numFences, fencesRaw.begin(), [](const FenceSp& f) -> vk::VkFence{ return **f; });
2542 	VK_CHECK(devHelper.vkd.waitForFences(*devHelper.device, numFences, fencesRaw.data(), VK_TRUE, std::numeric_limits<deUint64>::max()));
2543 
2544 	return tcu::TestStatus::pass("Acquire too many swapchain images test succeeded");
2545 }
2546 
acquireTooManyTimeoutTest(Context & context,Type wsiType)2547 tcu::TestStatus acquireTooManyTimeoutTest (Context& context, Type wsiType)
2548 {
2549 	const tcu::UVec2               desiredSize     (256, 256);
2550 	const InstanceHelper           instHelper      (context, wsiType);
2551 	const NativeObjects            native          (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
2552 	const Unique<VkSurfaceKHR>     surface         (createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow()));
2553 	const DeviceHelper             devHelper       (context, instHelper.vki, instHelper.instance, *surface);
2554 	const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2555 	const Unique<VkSwapchainKHR>   swapchain       (createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2556 
2557 	deUint32 numImages;
2558 	VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2559 	const deUint32 minImageCount = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface).minImageCount;
2560 	if (numImages < minImageCount) return tcu::TestStatus::fail("Get swapchain images returned less than minImageCount images");
2561 	const deUint32 numAcquirableImages = numImages - minImageCount + 1;
2562 
2563 	const auto fences = createFences(devHelper.vkd, *devHelper.device, numAcquirableImages + 1, false);
2564 	deUint32 dummy;
2565 	for (deUint32 i = 0; i < numAcquirableImages; ++i) {
2566 		VK_CHECK_WSI(devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, std::numeric_limits<deUint64>::max(), (VkSemaphore)0, **fences[i], &dummy));
2567 	}
2568 
2569 	const deUint64 millisecond = 1000000;
2570 	const deUint64 timeout = 50 * millisecond; // arbitrary realistic non-0 non-infinite timeout
2571 	const auto result = devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, timeout, (VkSemaphore)0, **fences[numAcquirableImages], &dummy);
2572 
2573 	if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR && result != VK_TIMEOUT ){
2574 		return tcu::TestStatus::fail("Implementation failed to respond well acquiring too many images with timeout");
2575 	}
2576 
2577 	// cleanup
2578 	const deUint32 numFences = (result == VK_TIMEOUT) ? static_cast<deUint32>(fences.size() - 1) : static_cast<deUint32>(fences.size());
2579 	vector<vk::VkFence> fencesRaw(numFences);
2580 	std::transform(fences.begin(), fences.begin() + numFences, fencesRaw.begin(), [](const FenceSp& f) -> vk::VkFence{ return **f; });
2581 	VK_CHECK(devHelper.vkd.waitForFences(*devHelper.device, numFences, fencesRaw.data(), VK_TRUE, std::numeric_limits<deUint64>::max()));
2582 
2583 	return tcu::TestStatus::pass("Acquire too many swapchain images test succeeded");
2584 }
2585 
getBasicRenderPrograms(SourceCollections & dst,Type)2586 void getBasicRenderPrograms (SourceCollections& dst, Type)
2587 {
2588 	WsiTriangleRenderer::getPrograms(dst);
2589 }
2590 
getBasicRenderPrograms(SourceCollections & dst,MultiSwapchainParams)2591 void getBasicRenderPrograms (SourceCollections& dst, MultiSwapchainParams)
2592 {
2593 	WsiTriangleRenderer::getPrograms(dst);
2594 }
2595 
populateRenderGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2596 void populateRenderGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2597 {
2598 	addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest<AcquireNextImageWrapper>, wsiType);
2599 	addFunctionCaseWithPrograms(testGroup, "basic2", "Basic Rendering Test using AcquireNextImage2", getBasicRenderPrograms, basicRenderTest<AcquireNextImage2Wrapper>, wsiType);
2600 	addFunctionCaseWithPrograms(testGroup, "device_group", "Basic Rendering Test using device_group", getBasicRenderPrograms, deviceGroupRenderTest, wsiType);
2601 	addFunctionCaseWithPrograms(testGroup, "device_group2", "Rendering Test using device_group and VkImageSwapchainCreateInfo", getBasicRenderPrograms, deviceGroupRenderTest2, wsiType);
2602 
2603 	const MultiSwapchainParams kTwoSwapchains	{ wsiType, 2u	};
2604 	const MultiSwapchainParams kTenSwapchains	{ wsiType, 10u	};
2605 
2606 	addFunctionCaseWithPrograms(testGroup, "2swapchains", "2 Swapchains Rendering Test", getBasicRenderPrograms, multiSwapchainRenderTest<AcquireNextImageWrapper>, kTwoSwapchains);
2607 	addFunctionCaseWithPrograms(testGroup, "2swapchains2", "2 Swapchains Rendering Test using AcquireNextImage2", getBasicRenderPrograms, multiSwapchainRenderTest<AcquireNextImage2Wrapper>, kTwoSwapchains);
2608 	addFunctionCaseWithPrograms(testGroup, "10swapchains", "10 Swapchains Rendering Test", getBasicRenderPrograms, multiSwapchainRenderTest<AcquireNextImageWrapper>, kTenSwapchains);
2609 	addFunctionCaseWithPrograms(testGroup, "10swapchains2", "10 Swapchains Rendering Test using AcquireNextImage2", getBasicRenderPrograms, multiSwapchainRenderTest<AcquireNextImage2Wrapper>, kTenSwapchains);
2610 }
2611 
populateGetImagesGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2612 void populateGetImagesGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2613 {
2614 	addFunctionCase(testGroup, "incomplete", "Test VK_INCOMPLETE return code", getImagesIncompleteResultTest, wsiType);
2615 	addFunctionCase(testGroup, "count",	"Test proper count of images", getImagesResultsCountTest, wsiType);
2616 }
2617 
populateModifyGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2618 void populateModifyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2619 {
2620 	const PlatformProperties&	platformProperties	= getPlatformProperties(wsiType);
2621 
2622 	if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
2623 	{
2624 		addFunctionCaseWithPrograms(testGroup, "resize", "Resize Swapchain Test", getBasicRenderPrograms, resizeSwapchainTest, wsiType);
2625 	}
2626 
2627 	// \todo [2016-05-30 jesse] Add tests for modifying preTransform, compositeAlpha, presentMode
2628 }
2629 
populateDestroyGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2630 void populateDestroyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2631 {
2632 	addFunctionCase(testGroup, "null_handle", "Destroying a VK_NULL_HANDLE swapchain", destroyNullHandleSwapchainTest, wsiType);
2633 	addFunctionCase(testGroup, "old_swapchain", "Destroying an old swapchain", destroyOldSwapchainTest, wsiType);
2634 }
2635 
populateAcquireGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2636 void populateAcquireGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2637 {
2638 	addFunctionCase(testGroup, "too_many", "Test acquiring too many images with 0 timeout", acquireTooManyTest, wsiType);
2639 	addFunctionCase(testGroup, "too_many_timeout", "Test acquiring too many images with timeout", acquireTooManyTimeoutTest, wsiType);
2640 }
2641 
2642 } // anonymous
2643 
createSwapchainTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)2644 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
2645 {
2646 	addTestGroup(testGroup, "create",			"Create VkSwapchain with various parameters",					populateSwapchainGroup,					GroupParameters(wsiType, createSwapchainTest));
2647 	addTestGroup(testGroup, "simulate_oom",		"Simulate OOM using callbacks during swapchain construction",	populateSwapchainGroup,					GroupParameters(wsiType, createSwapchainSimulateOOMTest));
2648 	addTestGroup(testGroup, "render",			"Rendering Tests",												populateRenderGroup,					wsiType);
2649 	addTestGroup(testGroup, "modify",			"Modify VkSwapchain",											populateModifyGroup,					wsiType);
2650 	addTestGroup(testGroup, "destroy",			"Destroy VkSwapchain",											populateDestroyGroup,					wsiType);
2651 	addTestGroup(testGroup, "get_images",		"Get swapchain images",											populateGetImagesGroup,					wsiType);
2652 	addTestGroup(testGroup, "acquire",			"Ancquire next swapchain image",								populateAcquireGroup,					wsiType);
2653 	addTestGroup(testGroup, "private_data",		"Create VkSwapchain and use VK_EXT_private_data",				populateSwapchainPrivateDataGroup,		GroupParameters(wsiType, createSwapchainPrivateDataTest));
2654 }
2655 
2656 } // wsi
2657 } // vkt
2658