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