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