• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 Google Inc.
6  * Copyright (c) 2022 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief VK_EXT_surface_maintenance1 and VK_EXT_swapchain_maintenance1 extension tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktWsiMaintenance1Tests.hpp"
26 
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktCustomInstancesDevices.hpp"
30 
31 #include "vkMemUtil.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkDeviceUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkWsiPlatform.hpp"
38 #include "vkWsiUtil.hpp"
39 
40 #include "deRandom.hpp"
41 
42 #include "tcuTestLog.hpp"
43 #include "tcuPlatform.hpp"
44 #include "tcuResultCollector.hpp"
45 #include "tcuCommandLine.hpp"
46 
47 #include <limits>
48 #include <random>
49 #include <set>
50 
51 #if ( DE_OS == DE_OS_WIN32 )
52 	#define NOMINMAX
53 	#define WIN32_LEAN_AND_MEAN
54 	#include <windows.h>
55 #endif
56 
57 namespace vkt
58 {
59 namespace wsi
60 {
61 
62 namespace
63 {
64 
65 using namespace vk;
66 using namespace vk::wsi;
67 
68 typedef std::vector<VkExtensionProperties> Extensions;
69 
70 constexpr uint64_t kMaxFenceWaitTimeout = 2000000000ul;
71 
72 template <typename T>
checkAllSupported(const Extensions & supportedExtensions,const std::vector<T> & requiredExtensions)73 void checkAllSupported (const Extensions& supportedExtensions,
74 						const std::vector<T>& requiredExtensions)
75 {
76 	for (auto &requiredExtension : requiredExtensions)
77 	{
78 		if (!isExtensionStructSupported(supportedExtensions, RequiredExtension(requiredExtension)))
79 			TCU_THROW(NotSupportedError, (std::string(requiredExtension) + " is not supported").c_str());
80 	}
81 }
82 
createInstanceWithWsi(Context & context,const Extensions & supportedExtensions,Type wsiType,bool requireDeviceGroup,const VkAllocationCallbacks * pAllocator=DE_NULL)83 CustomInstance createInstanceWithWsi (Context&						context,
84 									  const Extensions&				supportedExtensions,
85 									  Type							wsiType,
86 									  bool							requireDeviceGroup,
87 									  const VkAllocationCallbacks*	pAllocator	= DE_NULL)
88 {
89 	const deUint32	version		= context.getUsedApiVersion();
90 	std::vector<std::string>	extensions;
91 
92 	extensions.push_back("VK_KHR_surface");
93 	extensions.push_back(getExtensionName(wsiType));
94 	if (isDisplaySurface(wsiType))
95 		extensions.push_back("VK_KHR_display");
96 
97 	if (!vk::isCoreInstanceExtension(version, "VK_KHR_get_physical_device_properties2"))
98 		extensions.push_back("VK_KHR_get_physical_device_properties2");
99 
100 	if (isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_KHR_get_surface_capabilities2")))
101 		extensions.push_back("VK_KHR_get_surface_capabilities2");
102 
103 	extensions.push_back("VK_EXT_surface_maintenance1");
104 
105 	if (requireDeviceGroup)
106 		extensions.push_back("VK_KHR_device_group_creation");
107 
108 	checkAllSupported(supportedExtensions, extensions);
109 
110 	return createCustomInstanceWithExtensions(context, extensions, pAllocator);
111 }
112 
getDeviceFeaturesForWsi(void)113 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
114 {
115 	VkPhysicalDeviceFeatures features;
116 	deMemset(&features, 0, sizeof(features));
117 	return features;
118 }
119 
createDeviceWithWsi(const vk::PlatformInterface & vkp,VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const deUint32 queueFamilyIndex,const VkAllocationCallbacks * pAllocator,bool requireSwapchainMaintenance1,bool requireDeviceGroup,bool validationEnabled)120 Move<VkDevice> createDeviceWithWsi (const vk::PlatformInterface&	vkp,
121 									VkInstance						instance,
122 									const InstanceInterface&		vki,
123 									VkPhysicalDevice				physicalDevice,
124 									const Extensions&				supportedExtensions,
125 									const deUint32					queueFamilyIndex,
126 									const VkAllocationCallbacks*	pAllocator,
127 									bool							requireSwapchainMaintenance1,
128 									bool							requireDeviceGroup,
129 									bool							validationEnabled)
130 {
131 	const float						queuePriorities[]	= { 1.0f };
132 	const VkDeviceQueueCreateInfo	queueInfos[]		=
133 	{
134 		{
135 			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
136 			DE_NULL,
137 			(VkDeviceQueueCreateFlags)0,
138 			queueFamilyIndex,
139 			DE_LENGTH_OF_ARRAY(queuePriorities),
140 			&queuePriorities[0],
141 		}
142 	};
143 	const VkPhysicalDeviceFeatures	features		= getDeviceFeaturesForWsi();
144 	std::vector<const char *>		extensions;
145 
146 	extensions.push_back("VK_KHR_swapchain");
147 	if (requireSwapchainMaintenance1)
148 	{
149 		extensions.push_back("VK_EXT_swapchain_maintenance1");
150 	}
151 	if (requireDeviceGroup)
152 	{
153 		extensions.push_back("VK_KHR_device_group");
154 	}
155 	if (isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_KHR_shared_presentable_image")))
156 	{
157 		extensions.push_back("VK_KHR_shared_presentable_image");
158 	}
159 
160 	checkAllSupported(supportedExtensions, extensions);
161 
162 	VkDeviceCreateInfo		deviceParams	=
163 	{
164 		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
165 		DE_NULL,
166 		(VkDeviceCreateFlags)0,
167 		DE_LENGTH_OF_ARRAY(queueInfos),
168 		&queueInfos[0],
169 		0u,									// enabledLayerCount
170 		DE_NULL,							// ppEnabledLayerNames
171 		(deUint32)extensions.size(),
172 		extensions.empty() ? DE_NULL : &extensions[0],
173 		&features,
174 	};
175 
176 	return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
177 }
178 
179 struct InstanceHelper
180 {
181 	const std::vector<VkExtensionProperties>	supportedExtensions;
182 	const CustomInstance				instance;
183 	const InstanceDriver&				vki;
184 
InstanceHelpervkt::wsi::__anon2c8c76950111::InstanceHelper185 	InstanceHelper (Context&	context,
186 					Type		wsiType,
187 					bool		requireDeviceGroup,
188 					const		VkAllocationCallbacks* pAllocator = DE_NULL)
189 		: supportedExtensions	(enumerateInstanceExtensionProperties(context.getPlatformInterface(),
190 																	  DE_NULL))
191 		, instance				(createInstanceWithWsi(context,
192 													   supportedExtensions,
193 													   wsiType,
194 													   requireDeviceGroup,
195 													   pAllocator))
196 		, vki					(instance.getDriver())
197 	{}
198 };
199 
200 struct DeviceHelper
201 {
202 	const VkPhysicalDevice	physicalDevice;
203 	const deUint32			queueFamilyIndex;
204 	const Unique<VkDevice>	device;
205 	const DeviceDriver		vkd;
206 	const VkQueue			queue;
207 
DeviceHelpervkt::wsi::__anon2c8c76950111::DeviceHelper208 	DeviceHelper (Context&						context,
209 				  const InstanceInterface&		vki,
210 				  VkInstance					instance,
211 				  VkSurfaceKHR					surface,
212 				  bool							requireSwapchainMaintenance1,
213 				  bool							requireDeviceGroup,
214 				  const VkAllocationCallbacks*	pAllocator = DE_NULL)
215 		: physicalDevice			(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
216 		, queueFamilyIndex			(chooseQueueFamilyIndex(vki, physicalDevice, surface))
217 		, device					(createDeviceWithWsi(context.getPlatformInterface(),
218 														 instance,
219 														 vki,
220 														 physicalDevice,
221 														 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
222 														 queueFamilyIndex,
223 														 pAllocator,
224 														 requireSwapchainMaintenance1,
225 														 requireDeviceGroup,
226 														 context.getTestContext().getCommandLine().isValidationEnabled()))
227 		, vkd						(context.getPlatformInterface(), instance, *device)
228 		, queue						(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
229 	{
230 	}
231 };
232 
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,Type wsiType)233 de::MovePtr<Display> createDisplay (const vk::Platform&	platform,
234 									const Extensions&	supportedExtensions,
235 									Type				wsiType)
236 {
237 	try
238 	{
239 		return de::MovePtr<Display>(platform.createWsiDisplay(wsiType));
240 	}
241 	catch (const tcu::NotSupportedError& e)
242 	{
243 		if (isExtensionStructSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))) &&
244 		    platform.hasDisplay(wsiType))
245 		{
246 			// If VK_KHR_{platform}_surface was supported, vk::Platform implementation
247 			// must support creating native display & window for that WSI type.
248 			throw tcu::TestError(e.getMessage());
249 		}
250 		else
251 			throw;
252 	}
253 }
254 
createWindow(const Display & display,const tcu::Maybe<tcu::UVec2> & initialSize)255 de::MovePtr<Window> createWindow (const Display& display,
256 								  const tcu::Maybe<tcu::UVec2>& initialSize)
257 {
258 	try
259 	{
260 		return de::MovePtr<Window>(display.createWindow(initialSize));
261 	}
262 	catch (const tcu::NotSupportedError& e)
263 	{
264 		// See createDisplay - assuming that wsi::Display was supported platform port
265 		// should also support creating a window.
266 		throw tcu::TestError(e.getMessage());
267 	}
268 }
269 
270 constexpr deUint32 kDefaultWindowWidth = 128;
271 constexpr deUint32 kDefaultWindowHeight = 256;
272 
273 struct TestNativeObjects
274 {
275 	const de::UniquePtr<Display>		display;
276 	tcu::UVec2							windowSize;
277 	std::vector<de::MovePtr<Window>>	windows;
278 
TestNativeObjectsvkt::wsi::__anon2c8c76950111::TestNativeObjects279 	TestNativeObjects	(Context&				context,
280 						 const Extensions&		supportedExtensions,
281 						 Type					wsiType,
282 						 deUint32				windowCount)
283 		: display		(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
284 		, windowSize	(tcu::UVec2(kDefaultWindowWidth, kDefaultWindowHeight))
285 	{
286 		for (deUint32 i = 0; i < windowCount; ++i)
287 		{
288 			windows.push_back(createWindow(*display, windowSize));
289 			windows.back()->setVisible(true);
290 			if (wsiType == TYPE_WIN32)
291 			{
292 				windows.back()->setForeground();
293 			}
294 		}
295 	}
296 };
297 
getBasicSwapchainParameters(VkSurfaceKHR surface,VkSurfaceFormatKHR surfaceFormat,const tcu::UVec2 & desiredSize,VkPresentModeKHR presentMode,VkSurfaceTransformFlagBitsKHR transform,deUint32 desiredImageCount,bool deferMemoryAllocation)298 VkSwapchainCreateInfoKHR getBasicSwapchainParameters (VkSurfaceKHR					surface,
299 													  VkSurfaceFormatKHR			surfaceFormat,
300 													  const tcu::UVec2&				desiredSize,
301 													  VkPresentModeKHR				presentMode,
302 													  VkSurfaceTransformFlagBitsKHR	transform,
303 													  deUint32						desiredImageCount,
304 													  bool							deferMemoryAllocation)
305 {
306 	const VkSwapchainCreateInfoKHR		parameters	=
307 	{
308 		VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
309 		DE_NULL,
310 		(VkSwapchainCreateFlagsKHR)(deferMemoryAllocation ? VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT : 0),
311 		surface,
312 		desiredImageCount,
313 		surfaceFormat.format,
314 		surfaceFormat.colorSpace,
315 		vk::makeExtent2D(desiredSize.x(), desiredSize.y()),
316 		1u,									// imageArrayLayers
317 		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
318 		VK_SHARING_MODE_EXCLUSIVE,
319 		0u,
320 		(const deUint32*)DE_NULL,
321 		transform,
322 		VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
323 		presentMode,
324 		VK_FALSE,							// clipped
325 		DE_NULL,							// oldSwapchain
326 	};
327 
328 	return parameters;
329 }
330 
getPhysicalDeviceSurfaceCapabilities(const vk::InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,VkImageUsageFlags * sharedImageUsage)331 VkSurfaceCapabilitiesKHR getPhysicalDeviceSurfaceCapabilities (const vk::InstanceInterface&	vki,
332 															   VkPhysicalDevice				physicalDevice,
333 															   VkSurfaceKHR					surface,
334 															   VkImageUsageFlags*			sharedImageUsage)
335 {
336 	const VkPhysicalDeviceSurfaceInfo2KHR	info		=
337 	{
338 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
339 		DE_NULL,
340 		surface,
341 	};
342 	VkSharedPresentSurfaceCapabilitiesKHR	sharedCapabilities;
343 	VkSurfaceCapabilities2KHR				capabilities;
344 
345 	sharedCapabilities.sType	= VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR;
346 	sharedCapabilities.pNext	= DE_NULL;
347 
348 	capabilities.sType			= VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
349 	capabilities.pNext			= sharedImageUsage ? &sharedCapabilities : DE_NULL;
350 
351 	VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &info, &capabilities));
352 
353 	if (sharedImageUsage)
354 	{
355 		*sharedImageUsage		= sharedCapabilities.sharedPresentSupportedUsageFlags;
356 	}
357 
358 	return capabilities.surfaceCapabilities;
359 }
360 
getSurfaceCompatiblePresentModes(const vk::InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,VkPresentModeKHR presentMode)361 std::vector<VkPresentModeKHR> getSurfaceCompatiblePresentModes (const vk::InstanceInterface&	vki,
362 																VkPhysicalDevice				physicalDevice,
363 																VkSurfaceKHR					surface,
364 																VkPresentModeKHR				presentMode)
365 {
366 	VkSurfacePresentModeEXT					presentModeInfo	=
367 	{
368 		VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT,
369 		DE_NULL,
370 		presentMode,
371 	};
372 	const VkPhysicalDeviceSurfaceInfo2KHR	info			=
373 	{
374 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
375 		&presentModeInfo,
376 		surface,
377 	};
378 
379 	// Currently there are 6 present modes, 100 should cover all future ones!
380 	std::vector<VkPresentModeKHR>			compatibleModes	(100);
381 
382 	VkSurfacePresentModeCompatibilityEXT	compatibility	=
383 	{
384 		VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT,
385 		DE_NULL,
386 		(deUint32)compatibleModes.size(),
387 		compatibleModes.data(),
388 	};
389 	VkSurfaceCapabilities2KHR				capabilities	=
390 	{
391 		VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
392 		&compatibility,
393 		{},
394 	};
395 
396 	VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &info, &capabilities));
397 
398 	compatibleModes.resize(compatibility.presentModeCount);
399 	return compatibleModes;
400 }
401 
getSurfaceScalingCapabilities(const vk::InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkPresentModeKHR presentMode,VkSurfaceKHR surface)402 VkSurfacePresentScalingCapabilitiesEXT getSurfaceScalingCapabilities (const vk::InstanceInterface&	vki,
403 																	  VkPhysicalDevice				physicalDevice,
404 																	  VkPresentModeKHR				presentMode,
405 																	  VkSurfaceKHR					surface)
406 {
407 	VkSurfacePresentModeEXT					presentModeInfo	=
408 	{
409 		VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT,
410 		DE_NULL,
411 		presentMode,
412 	};
413 	const VkPhysicalDeviceSurfaceInfo2KHR	info			=
414 	{
415 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
416 		&presentModeInfo,
417 		surface,
418 	};
419 
420 	VkSurfacePresentScalingCapabilitiesEXT	scaling			=
421 	{
422 		VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT,
423 		DE_NULL,
424 		0,
425 		0,
426 		0,
427 		{},
428 		{},
429 	};
430 	VkSurfaceCapabilities2KHR				capabilities	=
431 	{
432 		VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
433 		&scaling,
434 		{},
435 	};
436 
437 	VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &info, &capabilities));
438 
439 	return scaling;
440 }
441 
getPerPresentSurfaceCapabilities(const vk::InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,VkPresentModeKHR presentMode)442 VkSurfaceCapabilitiesKHR getPerPresentSurfaceCapabilities (const vk::InstanceInterface&	vki,
443 														   VkPhysicalDevice				physicalDevice,
444 														   VkSurfaceKHR					surface,
445 														   VkPresentModeKHR				presentMode)
446 {
447 	VkSurfacePresentModeEXT					presentModeInfo	=
448 	{
449 		VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT,
450 		DE_NULL,
451 		presentMode,
452 	};
453 	const VkPhysicalDeviceSurfaceInfo2KHR	info			=
454 	{
455 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
456 		&presentModeInfo,
457 		surface,
458 	};
459 
460 	VkSurfaceCapabilities2KHR				capabilities	=
461 	{
462 		VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
463 		DE_NULL,
464 		{},
465 	};
466 
467 	VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &info, &capabilities));
468 
469 	return capabilities.surfaceCapabilities;
470 }
471 
472 typedef de::SharedPtr<Unique<VkCommandBuffer>>	CommandBufferSp;
473 typedef de::SharedPtr<Unique<VkFence>>			FenceSp;
474 typedef de::SharedPtr<Unique<VkSemaphore>>		SemaphoreSp;
475 typedef de::SharedPtr<Unique<VkImage>>			ImageSp;
476 
createFences(const DeviceInterface & vkd,const VkDevice device,size_t numFences)477 std::vector<FenceSp> createFences (const DeviceInterface&	vkd,
478 								   const VkDevice			device,
479 								   size_t					numFences)
480 {
481 	std::vector<FenceSp> fences(numFences);
482 
483 	for (size_t ndx = 0; ndx < numFences; ++ndx)
484 		fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
485 
486 	return fences;
487 }
488 
createSemaphores(const DeviceInterface & vkd,const VkDevice device,size_t numSemaphores)489 std::vector<SemaphoreSp> createSemaphores (const DeviceInterface&	vkd,
490 										   const VkDevice			device,
491 										   size_t					numSemaphores)
492 {
493 	std::vector<SemaphoreSp> semaphores(numSemaphores);
494 
495 	for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
496 		semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
497 
498 	return semaphores;
499 }
500 
allocateCommandBuffers(const DeviceInterface & vkd,const VkDevice device,const VkCommandPool commandPool,const VkCommandBufferLevel level,const size_t numCommandBuffers)501 std::vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface&		vkd,
502 													 const VkDevice				device,
503 													 const VkCommandPool		commandPool,
504 													 const VkCommandBufferLevel	level,
505 													 const size_t				numCommandBuffers)
506 {
507 	std::vector<CommandBufferSp>				buffers		(numCommandBuffers);
508 
509 	for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
510 		buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
511 
512 	return buffers;
513 }
514 
createBufferAndBindMemory(const DeviceHelper & devHelper,SimpleAllocator & allocator,const tcu::UVec4 color,deUint32 count,de::MovePtr<Allocation> * pAlloc)515 Move<VkBuffer> createBufferAndBindMemory (const DeviceHelper& devHelper, SimpleAllocator& allocator, const tcu::UVec4 color, deUint32 count, de::MovePtr<Allocation>* pAlloc)
516 {
517 	const DeviceInterface&	vkd				= devHelper.vkd;
518 	const VkDevice			device			= *devHelper.device;
519 	const deUint32			queueIndex		= devHelper.queueFamilyIndex;
520 
521 	const VkBufferCreateInfo bufferParams =
522 	{
523 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,       // VkStructureType      sType;
524 		DE_NULL,                                    // const void*          pNext;
525 		0u,                                         // VkBufferCreateFlags  flags;
526 		count * 4,                                  // VkDeviceSize         size;
527 		vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT,       // VkBufferUsageFlags   usage;
528 		VK_SHARING_MODE_EXCLUSIVE,                  // VkSharingMode        sharingMode;
529 		1u,                                         // deUint32             queueFamilyCount;
530 		&queueIndex                                 // const deUint32*      pQueueFamilyIndices;
531 	};
532 
533 	Move<VkBuffer> buffer = createBuffer(vkd, device, &bufferParams);
534 
535 	*pAlloc = allocator.allocate(getBufferMemoryRequirements(vkd, device, *buffer), MemoryRequirement::HostVisible);
536 	VK_CHECK(vkd.bindBufferMemory(device, *buffer, (*pAlloc)->getMemory(), (*pAlloc)->getOffset()));
537 
538 	// Upload color to buffer.  Assuming RGBA, but surface format could be different, such as BGRA.  For the purposes of the test, that doesn't matter.
539 	const deUint32			color32			= color.x() | color.y() << 8 | color.z() << 16 | color.w() << 24;
540 	std::vector<deUint32>	colors			(count, color32);
541 	deMemcpy((*pAlloc)->getHostPtr(), colors.data(), colors.size() * sizeof(colors[0]));
542 	flushAlloc(vkd, device, **pAlloc);
543 
544 	return buffer;
545 }
546 
copyBufferToImage(const DeviceInterface & vkd,VkCommandBuffer commandBuffer,VkBuffer buffer,VkImage image,const tcu::UVec2 offset,const tcu::UVec2 extent)547 void copyBufferToImage(const DeviceInterface& vkd, VkCommandBuffer commandBuffer, VkBuffer buffer, VkImage image, const tcu::UVec2 offset, const tcu::UVec2 extent)
548 {
549 	const VkBufferImageCopy	region			=
550 	{
551 		0,
552 		0,
553 		0,
554 		{
555 			vk::VK_IMAGE_ASPECT_COLOR_BIT,
556 			0,
557 			0,
558 			1,
559 		},
560 		{ (deInt32)offset.x(), (deInt32)offset.y(), 0 },
561 		{
562 			extent.x(),
563 			extent.y(),
564 			1u,
565 		},
566 	};
567 
568 	vkd.cmdCopyBufferToImage(commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
569 }
570 
571 struct PresentFenceTestConfig
572 {
573 	vk::wsi::Type					wsiType;
574 	std::vector<VkPresentModeKHR>	modes;
575 	bool							deferMemoryAllocation;
576 	bool							bindImageMemory;
577 	bool							changePresentModes;
578 	bool							verifyFenceOrdering;
579 };
580 
canDoMultiSwapchainPresent(vk::wsi::Type wsiType)581 bool canDoMultiSwapchainPresent(vk::wsi::Type wsiType)
582 {
583 	// Android has a bug with the implementation of multi-swapchain present.
584 	// This bug has existed since Vulkan 1.0 and is unrelated to
585 	// VK_EXT_swapchain_maintenance1.  Once that bug is fixed, multi-swapchain
586 	// present tests can be enabled for this platform.
587 	return wsiType != TYPE_ANDROID;
588 }
589 
getIterations(std::vector<VkPresentModeKHR> presentModes,std::vector<std::vector<VkPresentModeKHR>> compatiblePresentModes,bool testResizesWindowsFrequently)590 deUint32 getIterations(std::vector<VkPresentModeKHR> presentModes,
591 					   std::vector<std::vector<VkPresentModeKHR>> compatiblePresentModes,
592 					   bool testResizesWindowsFrequently)
593 {
594 	// Look at all the modes that will be used by the test.
595 	bool						hasFifo			= false;
596 	bool						hasShared		= false;
597 	bool						hasNoVsync		= false;
598 
599 	std::set<VkPresentModeKHR>	allModes;
600 
601 	for (VkPresentModeKHR mode : presentModes)
602 		allModes.insert(mode);
603 
604 	for (const auto &compatibleModes : compatiblePresentModes)
605 		for (VkPresentModeKHR mode : compatibleModes)
606 			allModes.insert(mode);
607 
608 	for (VkPresentModeKHR mode : allModes)
609 	{
610 		switch (mode)
611 		{
612 		case VK_PRESENT_MODE_FIFO_KHR:
613 		case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
614 			hasFifo = true;
615 			break;
616 		case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR:
617 		case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR:
618 			hasShared = true;
619 			break;
620 		case VK_PRESENT_MODE_IMMEDIATE_KHR:
621 		case VK_PRESENT_MODE_MAILBOX_KHR:
622 		default:
623 			hasNoVsync = true;
624 			break;
625 		}
626 	}
627 
628 	// Return an iteration count that is as high as possible while keeping the test time and memory usage reasonable.
629 	//
630 	// - If FIFO is used, limit to 120 (~2s on 60Hz)
631 	// - Else, limit to 1000
632 
633 	if (hasFifo)
634 		return testResizesWindowsFrequently ? 60 : 120;
635 
636 	(void)hasShared;
637 	(void)hasNoVsync;
638 	deUint32 iterations = 1000;
639 
640 	// If the test resizes windows frequently, reduce the testing time as that's a very slow operation.
641 	if (testResizesWindowsFrequently)
642 		iterations /= 50;
643 
644 	return iterations;
645 }
646 
bindSingleImageMemory(const DeviceInterface & vkd,const VkDevice device,const VkSwapchainKHR swapchain,const VkSwapchainCreateInfoKHR swapchainCreateInfo,deUint32 imageIndex)647 ImageSp bindSingleImageMemory(const DeviceInterface&			vkd,
648 							  const VkDevice					device,
649 							  const VkSwapchainKHR				swapchain,
650 							  const VkSwapchainCreateInfoKHR	swapchainCreateInfo,
651 							  deUint32							imageIndex)
652 {
653 	VkImageSwapchainCreateInfoKHR imageSwapchainCreateInfo =
654 	{
655 		VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
656 		DE_NULL,
657 		swapchain,
658 	};
659 
660 	VkImageCreateInfo imageCreateInfo =
661 	{
662 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
663 		&imageSwapchainCreateInfo,
664 		(VkImageCreateFlags)0u,							// flags
665 		VK_IMAGE_TYPE_2D,								// imageType
666 		swapchainCreateInfo.imageFormat,				// format
667 		{												// extent
668 			swapchainCreateInfo.imageExtent.width,		//   width
669 			swapchainCreateInfo.imageExtent.height,		//   height
670 			1u,											//   depth
671 		},
672 		1u,												// mipLevels
673 		1u,												// arrayLayers
674 		VK_SAMPLE_COUNT_1_BIT,							// samples
675 		VK_IMAGE_TILING_OPTIMAL,						// tiling
676 		swapchainCreateInfo.imageUsage,					// usage
677 		VK_SHARING_MODE_EXCLUSIVE,						// sharingMode
678 		0u,												// queueFamilyIndexCount
679 		DE_NULL,										// pQueueFamilyIndices
680 		VK_IMAGE_LAYOUT_UNDEFINED,						// initialLayout
681 	};
682 
683 	ImageSp								image = ImageSp(new Unique<VkImage>(createImage(vkd, device, &imageCreateInfo)));
684 
685 	VkBindImageMemorySwapchainInfoKHR	bimSwapchainInfo =
686 	{
687 		VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR,
688 		DE_NULL,
689 		swapchain,
690 		imageIndex,
691 	};
692 
693 	VkBindImageMemoryInfo				bimInfo =
694 	{
695 		VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
696 		&bimSwapchainInfo,
697 		**image,
698 		DE_NULL,
699 		0u,
700 	};
701 
702 	VK_CHECK(vkd.bindImageMemory2(device, 1, &bimInfo));
703 
704 	return image;
705 }
706 
bindImageMemory(const DeviceInterface & vkd,const VkDevice device,const VkSwapchainKHR swapchain,const VkSwapchainCreateInfoKHR swapchainCreateInfo)707 std::vector<ImageSp> bindImageMemory(const DeviceInterface&				vkd,
708 									 const VkDevice						device,
709 									 const VkSwapchainKHR				swapchain,
710 									 const VkSwapchainCreateInfoKHR		swapchainCreateInfo)
711 {
712 	deUint32 numImages = 0;
713 	VK_CHECK(vkd.getSwapchainImagesKHR(device, swapchain, &numImages, DE_NULL));
714 
715 	std::vector<ImageSp>							images				(numImages);
716 
717 	for (deUint32 i = 0; i < numImages; ++i)
718 	{
719 		images[i] = bindSingleImageMemory(vkd, device, swapchain, swapchainCreateInfo, i);
720 	}
721 
722 	return images;
723 }
724 
verifyFenceSignalOrdering(const DeviceInterface & vkd,const VkDevice device,const std::vector<FenceSp> & fences,const deUint32 stride,const deUint32 offset,const deUint32 lastKnownSignaled,const deUint32 maxIndex,tcu::ResultCollector * results)725 void verifyFenceSignalOrdering(const DeviceInterface&		vkd,
726 							   const VkDevice				device,
727 							   const std::vector<FenceSp>	&fences,
728 							   const deUint32				stride,
729 							   const deUint32				offset,
730 							   const deUint32				lastKnownSignaled,
731 							   const deUint32				maxIndex,
732 							   tcu::ResultCollector*		results)
733 {
734 	// Go over fences from end to last-known-signaled.  Verify that fences are
735 	// signaled in order by making sure that a consecutive set of fences are
736 	// encountered that are not signaled, followed by potentially a number of
737 	// fences that are.
738 	bool visitedSignaledFence = false;
739 	for (deUint32 i = maxIndex; i > lastKnownSignaled; --i)
740 	{
741 		const VkFence fence = **fences[(i - 1) * stride + offset];
742 		bool isSignaled = vkd.getFenceStatus(device, fence) != VK_NOT_READY;
743 
744 		// Ordering guarantee is broken if an unsignaled fence is encountered when a later fence is signaled.
745 		results->check(isSignaled || !visitedSignaledFence,
746 			"Encountered unsignaled fence while a later fence is signaled");
747 
748 		if (isSignaled)
749 		{
750 			visitedSignaledFence = true;
751 		}
752 	}
753 }
754 
presentFenceTest(Context & context,const PresentFenceTestConfig testParams)755 tcu::TestStatus presentFenceTest(Context& context, const PresentFenceTestConfig testParams)
756 {
757 	tcu::TestLog&							log				= context.getTestContext().getLog();
758 	tcu::ResultCollector					results			(log);
759 
760 	const deUint32							surfaceCount	= (deUint32)testParams.modes.size();
761 	const InstanceHelper					instHelper		(context, testParams.wsiType, testParams.bindImageMemory);
762 	const TestNativeObjects					native			(context, instHelper.supportedExtensions, testParams.wsiType, surfaceCount);
763 	std::vector<Move<VkSurfaceKHR>>			surfaces;
764 	for (deUint32 i = 0; i < surfaceCount; ++i)
765 	{
766 		surfaces.push_back(createSurface(instHelper.vki, instHelper.instance, testParams.wsiType, *native.display, *native.windows[i], context.getTestContext().getCommandLine()));
767 	}
768 
769 	const DeviceHelper						devHelper		(context, instHelper.vki, instHelper.instance, *surfaces[0], true, testParams.bindImageMemory);
770 	const DeviceInterface&					vkd				= devHelper.vkd;
771 	const VkDevice							device			= *devHelper.device;
772 
773 	for (deUint32 i = 0; i < surfaceCount; ++i)
774 	{
775 		const std::vector<VkPresentModeKHR>	presentModes	= getPhysicalDeviceSurfacePresentModes(instHelper.vki, devHelper.physicalDevice, *surfaces[i]);
776 		if (std::find(presentModes.begin(), presentModes.end(), testParams.modes[i]) == presentModes.end())
777 			TCU_THROW(NotSupportedError, "Present mode not supported");
778 	}
779 
780 	std::vector<VkSurfaceFormatKHR>			surfaceFormats	= getPhysicalDeviceSurfaceFormats(instHelper.vki, devHelper.physicalDevice, *surfaces[0]);
781 	if (surfaceFormats.empty())
782 		return tcu::TestStatus::fail("No VkSurfaceFormatKHR defined");
783 
784 	std::vector<bool>						isSharedPresentMode	(surfaceCount);
785 
786 	for (deUint32 i = 0; i < surfaceCount; ++i)
787 	{
788 		isSharedPresentMode[i]				= testParams.modes[i] == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
789 												testParams.modes[i] == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR;
790 	}
791 
792 	std::vector<VkSwapchainCreateInfoKHR>	swapchainInfo;
793 	std::vector<Move<VkSwapchainKHR>>		swapchains;
794 	std::vector<VkSwapchainKHR>				swapchainHandles;
795 	std::vector<std::vector<VkImage>>		swapchainImages;
796 	std::vector<std::vector<ImageSp>>		bimImages;
797 	std::vector<std::vector<VkPresentModeKHR>> compatiblePresentModes;
798 	for (deUint32 i = 0; i < surfaceCount; ++i)
799 	{
800 		VkImageUsageFlags						sharedImageUsage	= 0;
801 		const VkSurfaceCapabilitiesKHR			capabilities	= getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surfaces[i], isSharedPresentMode[i] ? &sharedImageUsage : DE_NULL);
802 		const VkSurfaceTransformFlagBitsKHR		transform		= (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
803 
804 		if (isSharedPresentMode[i] && (sharedImageUsage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0)
805 			TCU_THROW(NotSupportedError, "Transfer dst with shared present mode not supported");
806 
807 		swapchainInfo.push_back(getBasicSwapchainParameters(*surfaces[i], surfaceFormats[0], native.windowSize, testParams.modes[i], transform, isSharedPresentMode[i] ? 1 : capabilities.minImageCount, testParams.deferMemoryAllocation));
808 
809 		VkSwapchainPresentModesCreateInfoEXT	compatibleModesCreateInfo	=
810 		{
811 			VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT,
812 			DE_NULL,
813 			0,
814 			DE_NULL,
815 		};
816 		if (testParams.changePresentModes)
817 		{
818 			compatiblePresentModes.push_back(getSurfaceCompatiblePresentModes(instHelper.vki, devHelper.physicalDevice, *surfaces[i], testParams.modes[i]));
819 
820 			compatibleModesCreateInfo.presentModeCount	= (deUint32)compatiblePresentModes.back().size();
821 			compatibleModesCreateInfo.pPresentModes	= compatiblePresentModes.back().data();
822 			swapchainInfo.back().pNext				= &compatibleModesCreateInfo;
823 		}
824 
825 		swapchains.push_back(createSwapchainKHR(vkd, device, &swapchainInfo.back()));
826 		swapchainHandles.push_back(*swapchains.back());
827 
828 		if (testParams.bindImageMemory)
829 		{
830 			deUint32 numImages = 0;
831 			VK_CHECK(vkd.getSwapchainImagesKHR(device, *swapchains.back(), &numImages, DE_NULL));
832 			swapchainImages.push_back(std::vector<VkImage>(numImages, DE_NULL));
833 
834 			// If memory allocation is deferred, bind image memory lazily at acquire time.
835 			if (testParams.deferMemoryAllocation)
836 			{
837 				bimImages.push_back(std::vector<ImageSp>(numImages));
838 			}
839 			else
840 			{
841 				bimImages.push_back(bindImageMemory(vkd, device, *swapchains.back(), swapchainInfo.back()));
842 				for (size_t j = 0; j < bimImages.back().size(); ++j)
843 				{
844 					swapchainImages.back()[j]					= **bimImages.back()[j];
845 				}
846 			}
847 		}
848 		else
849 		{
850 			swapchainImages.push_back(getSwapchainImages(vkd, device, *swapchains.back()));
851 		}
852 	}
853 
854 	const Unique<VkCommandPool>				commandPool		(createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
855 
856 	const deUint32							iterations		= getIterations(testParams.modes, compatiblePresentModes, false);
857 
858 	// Do iterations presents, each with an associated fence.  Destroy the wait semaphores as soon as the corresponding fence signals.
859 	const std::vector<FenceSp>				presentFences	(createFences(vkd, device, iterations * surfaceCount));
860 	const std::vector<SemaphoreSp>			acquireSems		(createSemaphores(vkd, device, iterations * surfaceCount));
861 	std::vector<SemaphoreSp>				presentSems		(createSemaphores(vkd, device, iterations));
862 
863 	const std::vector<CommandBufferSp>		commandBuffers	(allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, iterations));
864 
865 	const deUint64							foreverNs		= 0xFFFFFFFFFFFFFFFFul;
866 
867 	VkImageSubresourceRange					range			=
868 	{
869 		VK_IMAGE_ASPECT_COLOR_BIT,
870 		0,
871 		1,
872 		0,
873 		1,
874 	};
875 
876 	const deUint32							configHash		=
877 		(deUint32)testParams.wsiType |
878 		(deUint32)testParams.modes[0] << 4 |
879 		(deUint32)testParams.deferMemoryAllocation << 28 |
880 		(deUint32)testParams.bindImageMemory << 29 |
881 		(deUint32)testParams.changePresentModes << 30 |
882 		(deUint32)testParams.verifyFenceOrdering << 31;
883 	de::Random								rng				(0x53A4C8A1u ^ configHash);
884 
885 	try
886 	{
887 		std::vector<deUint32>				nextUnfinishedPresent(surfaceCount, 0);
888 
889 		for (deUint32 i = 0; i < iterations; ++i)
890 		{
891 			const VkSemaphore*				presentSem		= &**presentSems[i];
892 			std::vector<VkSemaphore>		acquireSem;
893 			std::vector<VkFence>			presentFence;
894 			std::vector<deUint32>			imageIndex		(surfaceCount, 0x12345);	// initialize to junk value
895 			// Acquire an image and clear it
896 			beginCommandBuffer(vkd, **commandBuffers[i], 0u);
897 
898 			VkImageMemoryBarrier barrier = {
899 				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
900 				DE_NULL,
901 				0,
902 				0,
903 				VK_IMAGE_LAYOUT_UNDEFINED,
904 				VK_IMAGE_LAYOUT_UNDEFINED,
905 				VK_QUEUE_FAMILY_IGNORED,
906 				VK_QUEUE_FAMILY_IGNORED,
907 				DE_NULL,
908 				range,
909 			};
910 
911 			for (deUint32 j = 0; j < surfaceCount; ++j)
912 			{
913 				acquireSem.push_back(**acquireSems[i * surfaceCount + j]);
914 				presentFence.push_back(**presentFences[i * surfaceCount+ j]);
915 
916 				VK_CHECK(vkd.acquireNextImageKHR(device, *swapchains[j], foreverNs, acquireSem[j], DE_NULL, &imageIndex[j]));
917 
918 				// If memory allocation is deferred and bind image memory is used, lazily bind image memory now if this is the first time the image is acquired.
919 				VkImage&					acquiredImage	= swapchainImages[j][imageIndex[j]];
920 				if (acquiredImage == DE_NULL)
921 				{
922 					DE_ASSERT(testParams.bindImageMemory && testParams.deferMemoryAllocation);
923 					DE_ASSERT(!bimImages[j][imageIndex[j]]);
924 
925 					bimImages[j][imageIndex[j]] = bindSingleImageMemory(vkd, device, *swapchains[j], swapchainInfo[j], imageIndex[j]);
926 					acquiredImage = **bimImages[j][imageIndex[j]];
927 				}
928 
929 
930 				barrier.newLayout			= isSharedPresentMode[j] ? VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
931 				barrier.image				= acquiredImage;
932 
933 				vkd.cmdPipelineBarrier(**commandBuffers[i],
934 						VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
935 						VK_PIPELINE_STAGE_TRANSFER_BIT,
936 						0u,
937 						0, DE_NULL,
938 						0, DE_NULL,
939 						1, &barrier);
940 			}
941 
942 			for (deUint32 j = 0; j < surfaceCount; ++j)
943 			{
944 				VkClearColorValue				clearValue;
945 				clearValue.float32[0]			= static_cast<float>((i + j * 5) % 33) / 32.0f;
946 				clearValue.float32[1]			= static_cast<float>(((i + j * 5) + 7) % 33) / 32.0f;
947 				clearValue.float32[2]			= static_cast<float>(((i + j * 5) + 17) % 33) / 32.0f;
948 				clearValue.float32[3]			= 1.0f;
949 
950 				vkd.cmdClearColorImage(**commandBuffers[i], swapchainImages[j][imageIndex[j]], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue, 1, &range);
951 			}
952 
953 			barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
954 
955 			for (deUint32 j = 0; j < surfaceCount; ++j)
956 			{
957 				if (!isSharedPresentMode[j])
958 				{
959 					barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
960 					barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
961 				}
962 				else
963 				{
964 					barrier.oldLayout = VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR;
965 				}
966 				barrier.image = swapchainImages[j][imageIndex[j]];
967 
968 				vkd.cmdPipelineBarrier(**commandBuffers[i],
969 						VK_PIPELINE_STAGE_TRANSFER_BIT,
970 						VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
971 						0u,
972 						0, DE_NULL,
973 						0, DE_NULL,
974 						1, &barrier);
975 			}
976 
977 			endCommandBuffer(vkd, **commandBuffers[i]);
978 
979 			// Submit the command buffer
980 			VkPipelineStageFlags			waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
981 			const VkSubmitInfo				submitInfo =
982 			{
983 				VK_STRUCTURE_TYPE_SUBMIT_INFO,
984 				DE_NULL,
985 				surfaceCount,
986 				acquireSem.data(),
987 				&waitStage,
988 				1u,
989 				&**commandBuffers[i],
990 				1u,
991 				presentSem,
992 			};
993 			VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, DE_NULL));
994 
995 			// Present the frame
996 			VkSwapchainPresentFenceInfoEXT presentFenceInfo		=
997 			{
998 				VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT,
999 				DE_NULL,
1000 				surfaceCount,
1001 				presentFence.data(),
1002 			};
1003 			std::vector<VkResult> result(surfaceCount);
1004 
1005 			VkSwapchainPresentModeInfoEXT	presentModeInfo		=
1006 			{
1007 				VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT,
1008 				DE_NULL,
1009 				surfaceCount,
1010 				DE_NULL,
1011 			};
1012 			std::vector<VkPresentModeKHR>	presentModes;
1013 			if (testParams.changePresentModes && rng.getUint32() % 10 != 0)
1014 			{
1015 				presentModes.resize(surfaceCount);
1016 				presentModeInfo.pPresentModes				= presentModes.data();
1017 				presentFenceInfo.pNext						= &presentModeInfo;
1018 
1019 				// Randomly switch modes.  This is randomly not done to test that the driver doens't expect it to be specified every time.
1020 				for (deUint32 j = 0; j < surfaceCount; ++j)
1021 				{
1022 					deUint32				randomIndex		= rng.getUint32() % (deUint32)compatiblePresentModes[j].size();
1023 					presentModes[j]							= compatiblePresentModes[j][randomIndex];
1024 				}
1025 			}
1026 
1027 			const VkPresentInfoKHR presentInfo	=
1028 			{
1029 				VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1030 				&presentFenceInfo,
1031 				1u,
1032 				presentSem,
1033 				surfaceCount,
1034 				swapchainHandles.data(),
1035 				imageIndex.data(),
1036 				result.data(),
1037 			};
1038 			VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1039 			for (deUint32 j = 0; j < surfaceCount; ++j)
1040 			{
1041 				VK_CHECK_WSI(result[j]);
1042 			}
1043 
1044 			for (deUint32 j = 0; j < surfaceCount; ++j)
1045 			{
1046 				// Check previous presents; if any is signaled, immediatey destroy its wait semaphore
1047 				while (nextUnfinishedPresent[j] < i)
1048 				{
1049 					if (vkd.getFenceStatus(device, **presentFences[nextUnfinishedPresent[j] * surfaceCount + j]) != VK_NOT_READY)
1050 						break;
1051 
1052 					presentSems[nextUnfinishedPresent[j]].clear();
1053 					++nextUnfinishedPresent[j];
1054 				}
1055 
1056 				if (testParams.verifyFenceOrdering)
1057 					verifyFenceSignalOrdering(vkd, device, presentFences, surfaceCount, j, nextUnfinishedPresent[j], iterations, &results);
1058 			}
1059 		}
1060 
1061 		// Wait for outstanding presents and destroy their wait semaphores
1062 		for (deUint32 j = 0; j < surfaceCount; ++j)
1063 		{
1064 			if (testParams.verifyFenceOrdering)
1065 				verifyFenceSignalOrdering(vkd, device, presentFences, surfaceCount, j, nextUnfinishedPresent[j], iterations, &results);
1066 
1067 			while (nextUnfinishedPresent[j] < iterations)
1068 			{
1069 				VK_CHECK(vkd.waitForFences(device, 1u, &**presentFences[nextUnfinishedPresent[j] * surfaceCount + j], VK_TRUE, kMaxFenceWaitTimeout));
1070 				presentSems[nextUnfinishedPresent[j]].clear();
1071 				++nextUnfinishedPresent[j];
1072 			}
1073 		}
1074 	}
1075 	catch (...)
1076 	{
1077 		// Make sure device is idle before destroying resources
1078 		vkd.deviceWaitIdle(device);
1079 		throw;
1080 	}
1081 
1082 	for (deUint32 i = 0; i < surfaceCount; ++i)
1083 	{
1084 		native.windows[i]->setVisible(false);
1085 	}
1086 
1087 	return tcu::TestStatus(results.getResult(), results.getMessage());
1088 }
1089 
populatePresentFenceGroup(tcu::TestCaseGroup * testGroup,Type wsiType)1090 void populatePresentFenceGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1091 {
1092 	const struct
1093 	{
1094 		VkPresentModeKHR	mode;
1095 		const char*			name;
1096 	} presentModes[] =
1097 	{
1098 		{ VK_PRESENT_MODE_IMMEDIATE_KHR,					"immediate"		},
1099 		{ VK_PRESENT_MODE_MAILBOX_KHR,						"mailbox"		},
1100 		{ VK_PRESENT_MODE_FIFO_KHR,							"fifo"			},
1101 		{ VK_PRESENT_MODE_FIFO_RELAXED_KHR,					"fifo_relaxed"	},
1102 		{ VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,		"demand"		},
1103 		{ VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,	"continuous"	},
1104 	};
1105 
1106 	for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
1107 	{
1108 		de::MovePtr<tcu::TestCaseGroup>	presentModeGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), presentModes[presentModeNdx].name, presentModes[presentModeNdx].name));
1109 
1110 		PresentFenceTestConfig			config;
1111 		config.wsiType					= wsiType;
1112 		config.modes					= std::vector<VkPresentModeKHR>(1, presentModes[presentModeNdx].mode);
1113 		config.deferMemoryAllocation	= false;
1114 		config.bindImageMemory			= false;
1115 		config.changePresentModes		= false;
1116 		config.verifyFenceOrdering		= false;
1117 
1118 		addFunctionCase(&*presentModeGroup, "basic", "Basic present fence test", presentFenceTest, config);
1119 
1120 		config.verifyFenceOrdering		= true;
1121 		addFunctionCase(&*presentModeGroup, "ordering", "Test ordering guarantee of present fence signals", presentFenceTest, config);
1122 
1123 		if (canDoMultiSwapchainPresent(wsiType))
1124 		{
1125 			config.verifyFenceOrdering		= false;
1126 			config.modes					= std::vector<VkPresentModeKHR>(3, presentModes[presentModeNdx].mode);
1127 			addFunctionCase(&*presentModeGroup, "multi_swapchain", "Present fence test with multiple swapchains", presentFenceTest, config);
1128 
1129 			config.verifyFenceOrdering		= true;
1130 			addFunctionCase(&*presentModeGroup, "mult_swapchain_ordering", "Test ordering guarantee of present fence signals with multiple swapchains", presentFenceTest, config);
1131 		}
1132 
1133 		testGroup->addChild(presentModeGroup.release());
1134 	}
1135 }
1136 
1137 struct PresentModesTestConfig
1138 {
1139 	vk::wsi::Type		wsiType;
1140 	VkPresentModeKHR	mode;
1141 };
1142 
verifyCompatiblePresentModes(const std::vector<VkPresentModeKHR> & supportedModes,const VkPresentModeKHR queryMode,const std::vector<VkPresentModeKHR> & compatibleModes,const std::vector<VkPresentModeKHR> * previouslyQueriedCompatibleModes)1143 tcu::TestStatus verifyCompatiblePresentModes(const std::vector<VkPresentModeKHR>&	supportedModes,
1144 											 const VkPresentModeKHR					queryMode,
1145 											 const std::vector<VkPresentModeKHR>&	compatibleModes,
1146 											 const std::vector<VkPresentModeKHR>*	previouslyQueriedCompatibleModes)
1147 {
1148 	// Every returned compatible mode must be supported by the surface
1149 	for (size_t i = 0; i < compatibleModes.size(); ++i)
1150 		if (std::find(supportedModes.begin(), supportedModes.end(), compatibleModes[i]) == supportedModes.end())
1151 			return tcu::TestStatus::fail("Returned compatible present mode " + de::toString(compatibleModes[i]) + " is not a supported present mode");
1152 
1153 	// The original mode being queried must always be in the compatible list
1154 	if (!compatibleModes.empty() && std::find(compatibleModes.begin(), compatibleModes.end(), queryMode) == compatibleModes.end())
1155 		return tcu::TestStatus::fail("Returned compatible present modes does not include the mode used in the query");
1156 
1157 	// There should be no duplicates in the returned modes
1158 	std::set<VkPresentModeKHR> visitedModes;
1159 	for (VkPresentModeKHR compatibleMode : compatibleModes)
1160 	{
1161 		if (visitedModes.find(compatibleMode) != visitedModes.end())
1162 			return tcu::TestStatus::fail("Duplicate mode " + de::toString(compatibleMode) + " returned in list of compatible present modes");
1163 		visitedModes.insert(compatibleMode);
1164 	}
1165 
1166 	// If provided, the returned list of modes should match the last previous query
1167 	if (previouslyQueriedCompatibleModes)
1168 	{
1169 		for (VkPresentModeKHR previousCompatibleMode : *previouslyQueriedCompatibleModes)
1170 			if (visitedModes.find(previousCompatibleMode) == visitedModes.end())
1171 				return tcu::TestStatus::fail("Different sets of compatible modes returned on re-query (present mode " + de::toString(previousCompatibleMode) + " missing on requery)");
1172 	}
1173 
1174 	return tcu::TestStatus::pass("");
1175 }
1176 
presentModesQueryTest(Context & context,const PresentModesTestConfig testParams)1177 tcu::TestStatus presentModesQueryTest(Context& context, const PresentModesTestConfig testParams)
1178 {
1179 	const InstanceHelper					instHelper		(context, testParams.wsiType, false);
1180 	const TestNativeObjects					native			(context, instHelper.supportedExtensions, testParams.wsiType, 1);
1181 	Unique<VkSurfaceKHR>					surface			(createSurface(instHelper.vki, instHelper.instance, testParams.wsiType, *native.display, *native.windows[0], context.getTestContext().getCommandLine()));
1182 	const DeviceHelper						devHelper		(context, instHelper.vki, instHelper.instance, *surface, false, false);
1183 
1184 	const std::vector<VkPresentModeKHR>		presentModes	= getPhysicalDeviceSurfacePresentModes(instHelper.vki, devHelper.physicalDevice, *surface);
1185 	if (std::find(presentModes.begin(), presentModes.end(), testParams.mode) == presentModes.end())
1186 		TCU_THROW(NotSupportedError, "Present mode not supported");
1187 
1188 	// Get the compatible present modes with the given one.
1189 	VkSurfacePresentModeEXT					presentModeInfo	=
1190 	{
1191 		VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT,
1192 		DE_NULL,
1193 		testParams.mode,
1194 	};
1195 	const VkPhysicalDeviceSurfaceInfo2KHR	surfaceInfo		=
1196 	{
1197 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
1198 		&presentModeInfo,
1199 		*surface,
1200 	};
1201 	VkSurfacePresentModeCompatibilityEXT	compatibility	=
1202 	{
1203 		VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT,
1204 		DE_NULL,
1205 		0,
1206 		DE_NULL,
1207 	};
1208 	VkSurfaceCapabilities2KHR				capabilities	=
1209 	{
1210 		VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
1211 		&compatibility,
1212 		{},
1213 	};
1214 
1215 	// Test that querying only the count works.
1216 	VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(devHelper.physicalDevice, &surfaceInfo, &capabilities));
1217 
1218 	// The return value must be at least one, as every mode is compatible with itself.
1219 	if (compatibility.presentModeCount < 1)
1220 		return tcu::TestStatus::fail("Empty compatible present mode list");
1221 
1222 	// Test again providing a buffer that's too small
1223 	constexpr VkPresentModeKHR				invalidValue	= (VkPresentModeKHR)0x1234;
1224 	std::vector<VkPresentModeKHR>			compatibleModes	(compatibility.presentModeCount, invalidValue);
1225 	compatibility.pPresentModes								= compatibleModes.data();
1226 
1227 	uint32_t								originalCompatibleModesCount = compatibility.presentModeCount;
1228 
1229 	// Check result when count is 0
1230 	compatibility.presentModeCount									= 0;
1231 	VkResult result = instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(devHelper.physicalDevice, &surfaceInfo, &capabilities);
1232 	if (result != VK_SUCCESS)
1233 		return tcu::TestStatus::fail("Wrong result when the size is 0");
1234 
1235 	// Check result when count is too small
1236 	compatibility.presentModeCount									= originalCompatibleModesCount - 1;
1237 	result = instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(devHelper.physicalDevice, &surfaceInfo, &capabilities);
1238 	if (result != VK_SUCCESS)
1239 		return tcu::TestStatus::fail("Wrong result when the size is too small");
1240 
1241 	// Make sure whatever _is_ returned is valid.
1242 	if (compatibility.presentModeCount > originalCompatibleModesCount - 1)
1243 		return tcu::TestStatus::fail("Re-query returned more results than provided");
1244 
1245 	// Ensure the rest of the array is not overwritten
1246 	for (size_t i = compatibility.presentModeCount; i < compatibleModes.size(); ++i)
1247 	{
1248 		if (compatibleModes[i] != invalidValue)
1249 			return tcu::TestStatus::fail("Query overwrote beyond returned count");
1250 	}
1251 	compatibleModes.resize(compatibility.presentModeCount);
1252 	tcu::TestStatus status = verifyCompatiblePresentModes(presentModes, testParams.mode, compatibleModes, nullptr);
1253 	if (status.isFail())
1254 		return status;
1255 
1256 	// Check result when count is correct
1257 	compatibility.presentModeCount									= originalCompatibleModesCount;
1258 	std::vector<VkPresentModeKHR>			compatibleModes2(compatibility.presentModeCount, invalidValue);
1259 	compatibility.pPresentModes								= compatibleModes2.data();
1260 
1261 	VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(devHelper.physicalDevice, &surfaceInfo, &capabilities));
1262 
1263 	// Make sure returned modes are valid.
1264 	if (compatibility.presentModeCount != originalCompatibleModesCount)
1265 		return tcu::TestStatus::fail("Re-query returned different results count than provided");
1266 
1267 	status = verifyCompatiblePresentModes(presentModes, testParams.mode, compatibleModes2, &compatibleModes);
1268 	if (status.isFail())
1269 		return status;
1270 
1271 	// Check that querying with a count higher than supported still returns as many results as before.
1272 	compatibility.presentModeCount									= originalCompatibleModesCount * 2;
1273 	std::vector<VkPresentModeKHR>			compatibleModes3(compatibility.presentModeCount, invalidValue);
1274 	compatibility.pPresentModes								= compatibleModes3.data();
1275 
1276 	VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(devHelper.physicalDevice, &surfaceInfo, &capabilities));
1277 
1278 	// Make sure returned modes are the same as before.
1279 	if (compatibility.presentModeCount != originalCompatibleModesCount)
1280 		return tcu::TestStatus::fail("Re-query returned different results count than provided");
1281 
1282 	// Ensure the rest of the array is not overwritten
1283 	for (size_t i = compatibility.presentModeCount; i < compatibleModes3.size(); ++i)
1284 	{
1285 		if (compatibleModes3[i] != invalidValue)
1286 			return tcu::TestStatus::fail("Query overwrote beyond returned count");
1287 	}
1288 
1289 	compatibleModes3.resize(compatibility.presentModeCount);
1290 	status = verifyCompatiblePresentModes(presentModes, testParams.mode, compatibleModes3, &compatibleModes2);
1291 	if (status.isFail())
1292 		return status;
1293 
1294 	return tcu::TestStatus::pass("Tests ran successfully");
1295 }
1296 
populatePresentModesGroup(tcu::TestCaseGroup * testGroup,Type wsiType)1297 void populatePresentModesGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1298 {
1299 	const struct
1300 	{
1301 		VkPresentModeKHR	mode;
1302 		const char*			name;
1303 	} presentModes[] =
1304 	{
1305 		{ VK_PRESENT_MODE_IMMEDIATE_KHR,					"immediate"		},
1306 		{ VK_PRESENT_MODE_MAILBOX_KHR,						"mailbox"		},
1307 		{ VK_PRESENT_MODE_FIFO_KHR,							"fifo"			},
1308 		{ VK_PRESENT_MODE_FIFO_RELAXED_KHR,					"fifo_relaxed"	},
1309 		{ VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,		"demand"		},
1310 		{ VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,	"continuous"	},
1311 	};
1312 
1313 	for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
1314 	{
1315 		de::MovePtr<tcu::TestCaseGroup>	presentModeGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), presentModes[presentModeNdx].name, presentModes[presentModeNdx].name));
1316 
1317 		{
1318 			PresentModesTestConfig		config;
1319 			config.wsiType				= wsiType;
1320 			config.mode					= presentModes[presentModeNdx].mode;
1321 
1322 			addFunctionCase(&*presentModeGroup, "query", "Query compatible present modes", presentModesQueryTest, config);
1323 		}
1324 
1325 		{
1326 			PresentFenceTestConfig			config;
1327 			config.wsiType					= wsiType;
1328 			config.modes					= std::vector<VkPresentModeKHR>(1, presentModes[presentModeNdx].mode);
1329 			config.deferMemoryAllocation	= false;
1330 			config.bindImageMemory			= false;
1331 			config.changePresentModes		= true;
1332 			config.verifyFenceOrdering		= false;
1333 
1334 			addFunctionCase(&*presentModeGroup, "change_modes", "Switch between compatible modes", presentFenceTest, config);
1335 
1336 			if (canDoMultiSwapchainPresent(wsiType))
1337 			{
1338 				config.modes					= std::vector<VkPresentModeKHR>(4, presentModes[presentModeNdx].mode);
1339 
1340 				addFunctionCase(&*presentModeGroup, "change_modes_multi_swapchain", "Switch between compatible modes with multiple swapchains", presentFenceTest, config);
1341 
1342 				config.modes					= std::vector<VkPresentModeKHR>(2, presentModes[presentModeNdx].mode);
1343 				config.deferMemoryAllocation	= true;
1344 
1345 				addFunctionCase(&*presentModeGroup, "change_modes_with_deferred_alloc", "Switch between compatible modes while swapchain uses deferred allocation", presentFenceTest, config);
1346 			}
1347 		}
1348 
1349 		testGroup->addChild(presentModeGroup.release());
1350 	}
1351 
1352 	if (canDoMultiSwapchainPresent(wsiType))
1353 	{
1354 		de::MovePtr<tcu::TestCaseGroup>	heterogenousGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), "heterogenous", "Switch between compatible modes with multiple swapchains in different modes"));
1355 
1356 		std::vector<VkPresentModeKHR>	modes(3);
1357 		for (size_t i = 0; i < DE_LENGTH_OF_ARRAY(presentModes); i++)
1358 		{
1359 			for (size_t j = 0; j < DE_LENGTH_OF_ARRAY(presentModes); j++)
1360 			{
1361 				for (size_t k = 0; k < DE_LENGTH_OF_ARRAY(presentModes); k++)
1362 				{
1363 					// Skip if not actually heterogenous
1364 					if (i == j && i == k)
1365 						continue;
1366 
1367 					std::string						testName	= presentModes[i].name;
1368 					testName									+= "_";
1369 					testName									+= presentModes[j].name;
1370 					testName									+= "_";
1371 					testName									+= presentModes[k].name;
1372 
1373 					modes[0]									= presentModes[i].mode;
1374 					modes[1]									= presentModes[j].mode;
1375 					modes[2]									= presentModes[k].mode;
1376 
1377 					PresentFenceTestConfig			config;
1378 					config.wsiType					= wsiType;
1379 					config.modes					= modes;
1380 					config.deferMemoryAllocation	= false;
1381 					config.bindImageMemory			= false;
1382 					config.changePresentModes		= true;
1383 					config.verifyFenceOrdering		= false;
1384 
1385 					addFunctionCase(&*heterogenousGroup, testName, testName, presentFenceTest, config);
1386 				}
1387 			}
1388 		}
1389 
1390 		testGroup->addChild(heterogenousGroup.release());
1391 	}
1392 }
1393 
1394 enum class SwapchainWindowSize
1395 {
1396 	Identical,
1397 	SwapchainBigger,
1398 	SwapchainSmaller,
1399 };
1400 
1401 enum class SwapchainWindowAspect
1402 {
1403 	Identical,
1404 	SwapchainTaller,
1405 	SwapchainWider,
1406 };
1407 
1408 struct ScalingQueryTestConfig
1409 {
1410 	vk::wsi::Type					wsiType;
1411 	VkPresentModeKHR				mode;
1412 };
1413 
1414 struct ScalingTestConfig
1415 {
1416 	vk::wsi::Type					wsiType;
1417 	VkPresentModeKHR				mode;
1418 	VkPresentScalingFlagsEXT		scaling;
1419 	VkPresentGravityFlagsEXT		gravityX;
1420 	VkPresentGravityFlagsEXT		gravityY;
1421 	SwapchainWindowSize				size;
1422 	SwapchainWindowAspect			aspect;
1423 	// Either have the swapchain be created with a different size, or resize the window after swapchain creation
1424 	bool							resizeWindow;
1425 };
1426 
scalingQueryTest(Context & context,const ScalingQueryTestConfig testParams)1427 tcu::TestStatus scalingQueryTest(Context& context, const ScalingQueryTestConfig testParams)
1428 {
1429 	const InstanceHelper					instHelper		(context, testParams.wsiType, false);
1430 	const TestNativeObjects					native			(context, instHelper.supportedExtensions, testParams.wsiType, 1);
1431 	Unique<VkSurfaceKHR>					surface			(createSurface(instHelper.vki, instHelper.instance, testParams.wsiType, *native.display, *native.windows[0], context.getTestContext().getCommandLine()));
1432 	const DeviceHelper						devHelper		(context, instHelper.vki, instHelper.instance, *surface, false, false);
1433 
1434 	// Query the scaling capabilities and make sure they only report acceptable values.
1435 	VkSurfacePresentScalingCapabilitiesEXT	scaling			= getSurfaceScalingCapabilities(instHelper.vki, devHelper.physicalDevice, testParams.mode, *surface);
1436 
1437 	constexpr VkPresentScalingFlagsEXT		scalingFlags	= VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT | VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_EXT | VK_PRESENT_SCALING_STRETCH_BIT_EXT;
1438 	constexpr VkPresentGravityFlagsEXT		gravityFlags	= VK_PRESENT_GRAVITY_MIN_BIT_EXT | VK_PRESENT_GRAVITY_MAX_BIT_EXT | VK_PRESENT_GRAVITY_CENTERED_BIT_EXT;
1439 
1440 	if ((scaling.supportedPresentScaling & ~scalingFlags) != 0)
1441 		return tcu::TestStatus::fail("Invalid bits in scaling flags");
1442 
1443 	if ((scaling.supportedPresentGravityX & ~gravityFlags) != 0)
1444 		return tcu::TestStatus::fail("Invalid bits in gravity flags (x axis)");
1445 
1446 	if ((scaling.supportedPresentGravityY & ~gravityFlags) != 0)
1447 		return tcu::TestStatus::fail("Invalid bits in gravity flags (y axis)");
1448 
1449 	return tcu::TestStatus::pass("Tests ran successfully");
1450 }
1451 
scalingQueryCompatibleModesTest(Context & context,const ScalingQueryTestConfig testParams)1452 tcu::TestStatus scalingQueryCompatibleModesTest(Context& context, const ScalingQueryTestConfig testParams)
1453 {
1454 	const InstanceHelper					instHelper		(context, testParams.wsiType, false);
1455 	const TestNativeObjects					native			(context, instHelper.supportedExtensions, testParams.wsiType, 1);
1456 	Unique<VkSurfaceKHR>					surface			(createSurface(instHelper.vki, instHelper.instance, testParams.wsiType, *native.display, *native.windows[0], context.getTestContext().getCommandLine()));
1457 	const DeviceHelper						devHelper		(context, instHelper.vki, instHelper.instance, *surface, false, false);
1458 
1459 	// Query compatible present modes, and scaling capabilities for each mode.  They must all be identical.
1460 	VkSurfacePresentModeEXT					presentModeInfo	=
1461 	{
1462 		VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT,
1463 		DE_NULL,
1464 		testParams.mode,
1465 	};
1466 	const VkPhysicalDeviceSurfaceInfo2KHR	surfaceInfo		=
1467 	{
1468 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
1469 		&presentModeInfo,
1470 		*surface,
1471 	};
1472 	VkSurfacePresentModeCompatibilityEXT	compatibility	=
1473 	{
1474 		VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT,
1475 		DE_NULL,
1476 		0,
1477 		DE_NULL,
1478 	};
1479 	VkSurfaceCapabilities2KHR				capabilities	=
1480 	{
1481 		VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
1482 		&compatibility,
1483 		{},
1484 	};
1485 
1486 	VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(devHelper.physicalDevice, &surfaceInfo, &capabilities));
1487 	std::vector<VkPresentModeKHR>			compatibleModes	(compatibility.presentModeCount, (VkPresentModeKHR)0x5678);
1488 	compatibility.pPresentModes								= compatibleModes.data();
1489 
1490 	VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(devHelper.physicalDevice, &surfaceInfo, &capabilities));
1491 
1492 	std::vector<VkSurfacePresentScalingCapabilitiesEXT>	scaling(compatibility.presentModeCount);
1493 
1494 	for (uint32_t i = 0; i < compatibility.presentModeCount; ++i)
1495 		scaling[i]											= getSurfaceScalingCapabilities(instHelper.vki, devHelper.physicalDevice, compatibleModes[i], *surface);
1496 
1497 	for (uint32_t i = 1; i < compatibility.presentModeCount; ++i)
1498 	{
1499 		if (scaling[i].supportedPresentScaling != scaling[0].supportedPresentScaling)
1500 			return tcu::TestStatus::fail("Different scaling flags for compatible present modes is not allowed");
1501 
1502 		if (scaling[i].supportedPresentGravityX != scaling[0].supportedPresentGravityX)
1503 			return tcu::TestStatus::fail("Different gravity flags (x axis) for compatible present modes is not allowed");
1504 
1505 		if (scaling[i].supportedPresentGravityY != scaling[0].supportedPresentGravityY)
1506 			return tcu::TestStatus::fail("Different gravity flags (y axis) for compatible present modes is not allowed");
1507 	}
1508 
1509 	return tcu::TestStatus::pass("Tests ran successfully");
1510 }
1511 
scalingTest(Context & context,const ScalingTestConfig testParams)1512 tcu::TestStatus scalingTest(Context& context, const ScalingTestConfig testParams)
1513 {
1514 	const InstanceHelper					instHelper		(context, testParams.wsiType, false);
1515 	const TestNativeObjects					native			(context, instHelper.supportedExtensions, testParams.wsiType, 1);
1516 	Unique<VkSurfaceKHR>					surface			(createSurface(instHelper.vki, instHelper.instance, testParams.wsiType, *native.display, *native.windows[0], context.getTestContext().getCommandLine()));
1517 
1518 	const DeviceHelper						devHelper		(context, instHelper.vki, instHelper.instance, *surface, true, false);
1519 	const DeviceInterface&					vkd				= devHelper.vkd;
1520 	const VkDevice							device			= *devHelper.device;
1521 	SimpleAllocator							allocator		(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1522 
1523 	std::vector<VkSurfaceFormatKHR>			surfaceFormats	= getPhysicalDeviceSurfaceFormats(instHelper.vki, devHelper.physicalDevice, *surface);
1524 	if(surfaceFormats.empty())
1525 		return tcu::TestStatus::fail("No VkSurfaceFormatKHR defined");
1526 
1527 	const VkSurfaceCapabilitiesKHR			capabilities	= getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface, DE_NULL);
1528 	const VkSurfaceTransformFlagBitsKHR		transform		= (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
1529 
1530 	const std::vector<VkPresentModeKHR>		presentModes	= getPhysicalDeviceSurfacePresentModes(instHelper.vki, devHelper.physicalDevice, *surface);
1531 	if (std::find(presentModes.begin(), presentModes.end(), testParams.mode) == presentModes.end())
1532 		TCU_THROW(NotSupportedError, "Present mode not supported");
1533 
1534 	// Skip if configuration is not supported
1535 	VkSurfacePresentScalingCapabilitiesEXT	scaling			= getSurfaceScalingCapabilities(instHelper.vki, devHelper.physicalDevice, testParams.mode, *surface);
1536 
1537 	if ((scaling.supportedPresentScaling & testParams.scaling) == 0)
1538 		TCU_THROW(NotSupportedError, "Scaling mode is not supported");
1539 	if (testParams.scaling != VK_PRESENT_SCALING_STRETCH_BIT_EXT)
1540 	{
1541 		if ((scaling.supportedPresentGravityX & testParams.gravityX) == 0)
1542 			TCU_THROW(NotSupportedError, "Gravity mode is not supported (x axis)");
1543 		if ((scaling.supportedPresentGravityY & testParams.gravityY) == 0)
1544 			TCU_THROW(NotSupportedError, "Gravity mode is not supported (y axis)");
1545 	}
1546 
1547 	tcu::UVec2								swapchainSize	= native.windowSize;
1548 	if (!testParams.resizeWindow)
1549 	{
1550 		switch (testParams.size)
1551 		{
1552 		case SwapchainWindowSize::SwapchainBigger:
1553 			swapchainSize.x()				*= 2;
1554 			swapchainSize.y()				*= 2;
1555 			break;
1556 		case SwapchainWindowSize::SwapchainSmaller:
1557 			swapchainSize.x()				/= 2;
1558 			swapchainSize.y()				/= 2;
1559 			break;
1560 		default:
1561 			break;
1562 		}
1563 		switch (testParams.aspect)
1564 		{
1565 		case SwapchainWindowAspect::SwapchainTaller:
1566 			swapchainSize.y()				+= swapchainSize.y() / 2;
1567 			break;
1568 		case SwapchainWindowAspect::SwapchainWider:
1569 			swapchainSize.x()				+= swapchainSize.x() / 2;
1570 			break;
1571 		default:
1572 			break;
1573 		}
1574 	}
1575 
1576 	VkSwapchainCreateInfoKHR				swapchainInfo	= getBasicSwapchainParameters(*surface, surfaceFormats[0], swapchainSize, testParams.mode, transform, capabilities.minImageCount, false);
1577 
1578 	VkSwapchainPresentScalingCreateInfoEXT	scalingInfo		=
1579 	{
1580 		VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT,
1581 		DE_NULL,
1582 		testParams.scaling,
1583 		testParams.gravityX,
1584 		testParams.gravityY,
1585 	};
1586 	swapchainInfo.pNext										= &scalingInfo;
1587 
1588 	const Unique<VkSwapchainKHR>			swapchain		(createSwapchainKHR(vkd, device, &swapchainInfo));
1589 	std::vector<VkImage>					swapchainImages	= getSwapchainImages(vkd, device, *swapchain);
1590 
1591 	const Unique<VkCommandPool>				commandPool		(createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1592 
1593 	constexpr deUint32						iterations		= 100;
1594 
1595 	// Do testParams.iterations presents, with a fence associated with the last one.
1596 	FenceSp									presentFence	= FenceSp(new Unique<VkFence>(createFence(vkd, device)));
1597 	const std::vector<SemaphoreSp>			acquireSems		(createSemaphores(vkd, device, iterations));
1598 	const std::vector<SemaphoreSp>			presentSems		(createSemaphores(vkd, device, iterations));
1599 
1600 	const std::vector<CommandBufferSp>		commandBuffers	(allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, iterations));
1601 
1602 	const deUint64							foreverNs		= 0xFFFFFFFFFFFFFFFFul;
1603 
1604 	VkImageSubresourceRange					range			=
1605 	{
1606 		VK_IMAGE_ASPECT_COLOR_BIT,
1607 		0,
1608 		1,
1609 		0,
1610 		1,
1611 	};
1612 
1613 	tcu::UVec2								windowSize	= native.windowSize;
1614 	if (testParams.resizeWindow)
1615 	{
1616 		switch (testParams.size)
1617 		{
1618 		case SwapchainWindowSize::SwapchainBigger:
1619 			windowSize.x()					/= 2;
1620 			windowSize.y()					/= 2;
1621 			break;
1622 		case SwapchainWindowSize::SwapchainSmaller:
1623 			windowSize.x()					*= 2;
1624 			windowSize.y()					*= 2;
1625 			break;
1626 		default:
1627 			break;
1628 		}
1629 		switch (testParams.aspect)
1630 		{
1631 		case SwapchainWindowAspect::SwapchainTaller:
1632 			windowSize.x()					+= windowSize.x() / 2;
1633 			break;
1634 		case SwapchainWindowAspect::SwapchainWider:
1635 			windowSize.y()					+= windowSize.y() / 2;
1636 			break;
1637 		default:
1638 			break;
1639 		}
1640 
1641 		native.windows[0]->resize(windowSize);
1642 	}
1643 
1644 	const deUint32							quarterPixels	= swapchainSize.x() * swapchainSize.y() / 4;
1645 	const tcu::UVec4						red				(255, 30, 20, 255);
1646 	const tcu::UVec4						green			(0, 255, 50, 255);
1647 	const tcu::UVec4						blue			(40, 60, 255, 255);
1648 	const tcu::UVec4						yellow			(200, 220, 20, 255);
1649 	de::MovePtr<Allocation>					redMemory;
1650 	de::MovePtr<Allocation>					greenMemory;
1651 	de::MovePtr<Allocation>					blueMemory;
1652 	de::MovePtr<Allocation>					yellowMemory;
1653 	const vk::Move<vk::VkBuffer>			redBuffer		= createBufferAndBindMemory(devHelper, allocator, red, quarterPixels, &redMemory);
1654 	const vk::Move<vk::VkBuffer>			greenBuffer		= createBufferAndBindMemory(devHelper, allocator, green, quarterPixels, &greenMemory);
1655 	const vk::Move<vk::VkBuffer>			blueBuffer		= createBufferAndBindMemory(devHelper, allocator, blue, quarterPixels, &blueMemory);
1656 	const vk::Move<vk::VkBuffer>			yellowBuffer	= createBufferAndBindMemory(devHelper, allocator, yellow, quarterPixels, &yellowMemory);
1657 
1658 	try
1659 	{
1660 		for (deUint32 i = 0; i < iterations; ++i)
1661 		{
1662 			const VkSemaphore				presentSem		= **presentSems[i];
1663 			const VkSemaphore				acquireSem		= **acquireSems[i];
1664 			deUint32						imageIndex		= 0x12345;	// initialize to junk value
1665 
1666 			VK_CHECK(vkd.acquireNextImageKHR(device, *swapchain, foreverNs, acquireSem, DE_NULL, &imageIndex));
1667 
1668 			beginCommandBuffer(vkd, **commandBuffers[i], 0u);
1669 
1670 			VkImageMemoryBarrier barrier = {
1671 				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
1672 				DE_NULL,
1673 				0,
1674 				0,
1675 				VK_IMAGE_LAYOUT_UNDEFINED,
1676 				VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1677 				VK_QUEUE_FAMILY_IGNORED,
1678 				VK_QUEUE_FAMILY_IGNORED,
1679 				swapchainImages[imageIndex],
1680 				range,
1681 			};
1682 
1683 			vkd.cmdPipelineBarrier(**commandBuffers[i],
1684 					VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1685 					VK_PIPELINE_STAGE_TRANSFER_BIT,
1686 					0u,
1687 					0, DE_NULL,
1688 					0, DE_NULL,
1689 					1, &barrier);
1690 
1691 			const tcu::UVec2				halfSwapchainSize	= swapchainSize / 2u;
1692 			copyBufferToImage(vkd, **commandBuffers[i], *redBuffer, swapchainImages[imageIndex], tcu::UVec2(0, 0), halfSwapchainSize);
1693 			copyBufferToImage(vkd, **commandBuffers[i], *greenBuffer, swapchainImages[imageIndex], tcu::UVec2(halfSwapchainSize.x(), 0), tcu::UVec2(swapchainSize.x() - halfSwapchainSize.x(), halfSwapchainSize.y()));
1694 			copyBufferToImage(vkd, **commandBuffers[i], *blueBuffer, swapchainImages[imageIndex], tcu::UVec2(0, halfSwapchainSize.y()), tcu::UVec2(halfSwapchainSize.x(), swapchainSize.y() - halfSwapchainSize.y()));
1695 			copyBufferToImage(vkd, **commandBuffers[i], *yellowBuffer, swapchainImages[imageIndex], halfSwapchainSize, tcu::UVec2(swapchainSize.x() - halfSwapchainSize.x(), swapchainSize.y() - halfSwapchainSize.y()));
1696 
1697 			barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1698 			barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1699 			barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
1700 
1701 			vkd.cmdPipelineBarrier(**commandBuffers[i],
1702 					VK_PIPELINE_STAGE_TRANSFER_BIT,
1703 					VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1704 					0u,
1705 					0, DE_NULL,
1706 					0, DE_NULL,
1707 					1, &barrier);
1708 
1709 			endCommandBuffer(vkd, **commandBuffers[i]);
1710 
1711 			// Submit the command buffer
1712 			VkPipelineStageFlags			waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
1713 			const VkSubmitInfo				submitInfo =
1714 			{
1715 				VK_STRUCTURE_TYPE_SUBMIT_INFO,
1716 				DE_NULL,
1717 				1,
1718 				&acquireSem,
1719 				&waitStage,
1720 				1u,
1721 				&**commandBuffers[i],
1722 				1u,
1723 				&presentSem,
1724 			};
1725 			VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, DE_NULL));
1726 
1727 			// Present the frame
1728 			const VkSwapchainPresentFenceInfoEXT presentFenceInfo =
1729 			{
1730 				VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT,
1731 				DE_NULL,
1732 				1,
1733 				&**presentFence,
1734 			};
1735 			VkResult result;
1736 
1737 			const VkPresentInfoKHR presentInfo =
1738 			{
1739 				VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1740 				// Signal the present fence on the last present.
1741 				i + 1 == iterations ? &presentFenceInfo : nullptr,
1742 				1u,
1743 				&presentSem,
1744 				1,
1745 				&*swapchain,
1746 				&imageIndex,
1747 				&result,
1748 			};
1749 			VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1750 			VK_CHECK_WSI(result);
1751 
1752 			// TODO: wait for present, capture the screen and verify that scaling is done correctly.
1753 		}
1754 
1755 		// Wait for all presents before terminating the test (when semaphores are destroyed)
1756 		VK_CHECK(vkd.waitForFences(device, 1u, &**presentFence, VK_TRUE, kMaxFenceWaitTimeout));
1757 	}
1758 	catch (...)
1759 	{
1760 		// Make sure device is idle before destroying resources
1761 		vkd.deviceWaitIdle(device);
1762 		throw;
1763 	}
1764 
1765 	native.windows[0]->setVisible(false);
1766 
1767 	return tcu::TestStatus::pass("Tests ran successfully");
1768 }
1769 
populateScalingTests(tcu::TestCaseGroup * testGroup,Type wsiType,bool resizeWindow)1770 void populateScalingTests (tcu::TestCaseGroup *testGroup, Type wsiType, bool resizeWindow)
1771 {
1772 	const struct
1773 	{
1774 		VkPresentModeKHR	mode;
1775 		const char*			name;
1776 	} presentModes[] =
1777 	{
1778 		{ VK_PRESENT_MODE_IMMEDIATE_KHR,					"immediate"		},
1779 		{ VK_PRESENT_MODE_MAILBOX_KHR,						"mailbox"		},
1780 		{ VK_PRESENT_MODE_FIFO_KHR,							"fifo"			},
1781 		{ VK_PRESENT_MODE_FIFO_RELAXED_KHR,					"fifo_relaxed"	},
1782 		{ VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,		"demand"		},
1783 		{ VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,	"continuous"	},
1784 	};
1785 
1786 	const struct
1787 	{
1788 		VkPresentScalingFlagBitsEXT		scaling;
1789 		const char*						name;
1790 	} scalingFlags[] =
1791 	{
1792 		{ VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT,			"one_to_one"		},
1793 		{ VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_EXT,	"aspect_stretch"	},
1794 		{ VK_PRESENT_SCALING_STRETCH_BIT_EXT,				"stretch"			},
1795 	};
1796 
1797 	const struct
1798 	{
1799 		VkPresentGravityFlagBitsEXT		gravity;
1800 		const char*						name;
1801 	} gravityFlags[] =
1802 	{
1803 		{ VK_PRESENT_GRAVITY_MIN_BIT_EXT,		"min"		},
1804 		{ VK_PRESENT_GRAVITY_MAX_BIT_EXT,		"max"		},
1805 		{ VK_PRESENT_GRAVITY_CENTERED_BIT_EXT,	"center"	},
1806 	};
1807 
1808 	for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
1809 	{
1810 		de::MovePtr<tcu::TestCaseGroup>	presentModeGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), presentModes[presentModeNdx].name, presentModes[presentModeNdx].name));
1811 
1812 		{
1813 			ScalingQueryTestConfig	config;
1814 			config.wsiType			= wsiType;
1815 			config.mode				= presentModes[presentModeNdx].mode;
1816 
1817 			de::MovePtr<tcu::TestCaseGroup>	queryGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), "query", "Query supported scaling modes"));
1818 			addFunctionCase(&*queryGroup, "basic", "Basic test", scalingQueryTest, config);
1819 			addFunctionCase(&*queryGroup, "verify_compatible_present_modes", "Verify compatible present modes have the same scaling capabilities", scalingQueryCompatibleModesTest, config);
1820 			presentModeGroup->addChild(queryGroup.release());
1821 		}
1822 
1823 		for (size_t scalingFlagNdx = 0; scalingFlagNdx < DE_LENGTH_OF_ARRAY(scalingFlags); scalingFlagNdx++)
1824 		{
1825 			de::MovePtr<tcu::TestCaseGroup>	scalingFlagGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), scalingFlags[scalingFlagNdx].name, scalingFlags[scalingFlagNdx].name));
1826 
1827 			const bool isStretch = scalingFlags[scalingFlagNdx].scaling == VK_PRESENT_SCALING_STRETCH_BIT_EXT;
1828 
1829 			for (size_t gravityFlagXNdx = 0; gravityFlagXNdx < DE_LENGTH_OF_ARRAY(gravityFlags); gravityFlagXNdx++)
1830 			{
1831 				for (size_t gravityFlagYNdx = 0; gravityFlagYNdx < DE_LENGTH_OF_ARRAY(gravityFlags); gravityFlagYNdx++)
1832 				{
1833 					std::string						testName	= gravityFlags[gravityFlagXNdx].name;
1834 					testName									+= "_";
1835 					testName									+= gravityFlags[gravityFlagYNdx].name;
1836 
1837 					de::MovePtr<tcu::TestCaseGroup>	gravityFlagsGroup	(new tcu::TestCaseGroup(scalingFlagGroup->getTestContext(), testName.c_str(), testName.c_str()));
1838 
1839 					ScalingTestConfig		config;
1840 					config.wsiType			= wsiType;
1841 					config.mode				= presentModes[presentModeNdx].mode;
1842 					config.scaling			= scalingFlags[scalingFlagNdx].scaling;
1843 					config.gravityX			= gravityFlags[gravityFlagXNdx].gravity;
1844 					config.gravityY			= gravityFlags[gravityFlagYNdx].gravity;
1845 					config.size				= SwapchainWindowSize::Identical;
1846 					config.aspect			= SwapchainWindowAspect::Identical;
1847 					config.resizeWindow		= resizeWindow;
1848 
1849 					// Gravity does not apply to stretch
1850 					de::MovePtr<tcu::TestCaseGroup> *group = isStretch ? &scalingFlagGroup : &gravityFlagsGroup;
1851 
1852 					addFunctionCase(&**group, "same_size_and_aspect", "Basic test without actual scaling", scalingTest, config);
1853 
1854 					config.size				= SwapchainWindowSize::SwapchainBigger;
1855 					addFunctionCase(&**group, "swapchain_bigger_same_aspect", "Swapchain is bigger than window, but has same aspect", scalingTest, config);
1856 
1857 					config.size				= SwapchainWindowSize::SwapchainSmaller;
1858 					addFunctionCase(&**group, "swapchain_smaller_same_aspect", "Swapchain is smaller than window, but has same aspect", scalingTest, config);
1859 
1860 					config.size				= SwapchainWindowSize::Identical;
1861 					config.aspect			= SwapchainWindowAspect::SwapchainTaller;
1862 					addFunctionCase(&**group, "swapchain_taller", "Swapchain has same width, but is taller than window", scalingTest, config);
1863 
1864 					config.size				= SwapchainWindowSize::SwapchainBigger;
1865 					addFunctionCase(&**group, "swapchain_bigger_taller_aspect", "Swapchain is bigger than window, and is taller in aspect ratio", scalingTest, config);
1866 
1867 					config.size				= SwapchainWindowSize::SwapchainSmaller;
1868 					addFunctionCase(&**group, "swapchain_smaller_taller_aspect", "Swapchain is smaller than window, but is taller in aspect ratio", scalingTest, config);
1869 
1870 					config.size				= SwapchainWindowSize::Identical;
1871 					config.aspect			= SwapchainWindowAspect::SwapchainWider;
1872 					addFunctionCase(&**group, "swapchain_wider", "Swapchain has same height, but is wider than window", scalingTest, config);
1873 
1874 					config.size				= SwapchainWindowSize::SwapchainBigger;
1875 					addFunctionCase(&**group, "swapchain_bigger_wider_aspect", "Swapchain is bigger than window, and is wider in aspect ratio", scalingTest, config);
1876 
1877 					config.size				= SwapchainWindowSize::SwapchainSmaller;
1878 					addFunctionCase(&**group, "swapchain_smaller_wider_aspect", "Swapchain is smaller than window, but is wider in aspect ratio", scalingTest, config);
1879 
1880 					if (isStretch)
1881 					{
1882 						break;
1883 					}
1884 
1885 					scalingFlagGroup->addChild(gravityFlagsGroup.release());
1886 				}
1887 
1888 				if (isStretch)
1889 				{
1890 					break;
1891 				}
1892 			}
1893 
1894 			presentModeGroup->addChild(scalingFlagGroup.release());
1895 		}
1896 
1897 		testGroup->addChild(presentModeGroup.release());
1898 	}
1899 }
1900 
populateScalingGroup(tcu::TestCaseGroup * testGroup,Type wsiType)1901 void populateScalingGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1902 {
1903 	populateScalingTests(testGroup, wsiType, false);
1904 
1905 	de::MovePtr<tcu::TestCaseGroup>	resizeWindowGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), "resize_window", "Resize the window instead of creating the swapchain with a different size"));
1906 	populateScalingTests(&*resizeWindowGroup, wsiType, true);
1907 	testGroup->addChild(resizeWindowGroup.release());
1908 }
1909 
populateDeferredAllocGroup(tcu::TestCaseGroup * testGroup,Type wsiType)1910 void populateDeferredAllocGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1911 {
1912 	const struct
1913 	{
1914 		VkPresentModeKHR	mode;
1915 		const char*			name;
1916 	} presentModes[] =
1917 	{
1918 		{ VK_PRESENT_MODE_IMMEDIATE_KHR,					"immediate"		},
1919 		{ VK_PRESENT_MODE_MAILBOX_KHR,						"mailbox"		},
1920 		{ VK_PRESENT_MODE_FIFO_KHR,							"fifo"			},
1921 		{ VK_PRESENT_MODE_FIFO_RELAXED_KHR,					"fifo_relaxed"	},
1922 		{ VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,		"demand"		},
1923 		{ VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,	"continuous"	},
1924 	};
1925 
1926 	for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
1927 	{
1928 		de::MovePtr<tcu::TestCaseGroup>	presentModeGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), presentModes[presentModeNdx].name, presentModes[presentModeNdx].name));
1929 
1930 		PresentFenceTestConfig			config;
1931 		config.wsiType					= wsiType;
1932 		config.modes					= std::vector<VkPresentModeKHR>(1, presentModes[presentModeNdx].mode);
1933 		config.deferMemoryAllocation	= true;
1934 		config.bindImageMemory			= false;
1935 		config.changePresentModes		= false;
1936 		config.verifyFenceOrdering		= false;
1937 
1938 		addFunctionCase(&*presentModeGroup, "basic", "Basic deferred allocation test", presentFenceTest, config);
1939 
1940 		config.bindImageMemory			= true;
1941 
1942 		// Bind image memory + shared present mode crashing on some drivers for unrelated reasons to VK_EXT_swapchain_maintenance1.  Will enable this test separately.
1943 		if (presentModes[presentModeNdx].mode != VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR && presentModes[presentModeNdx].mode != VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR)
1944 		{
1945 			addFunctionCase(&*presentModeGroup, "bind_image", "Bind image with VkBindImageMemorySwapchainInfoKHR", presentFenceTest, config);
1946 		}
1947 
1948 		if (canDoMultiSwapchainPresent(wsiType))
1949 		{
1950 			config.modes					= std::vector<VkPresentModeKHR>(2, presentModes[presentModeNdx].mode);
1951 
1952 			addFunctionCase(&*presentModeGroup, "bind_image_multi_swapchain", "Bind image with VkBindImageMemorySwapchainInfoKHR with multiple swapchains", presentFenceTest, config);
1953 		}
1954 
1955 		testGroup->addChild(presentModeGroup.release());
1956 	}
1957 }
1958 
1959 enum class ResizeWindow
1960 {
1961 	No,
1962 	BeforeAcquire,
1963 	BeforePresent,
1964 };
1965 
1966 struct ReleaseImagesTestConfig
1967 {
1968 	vk::wsi::Type					wsiType;
1969 	VkPresentModeKHR				mode;
1970 	VkPresentScalingFlagsEXT		scaling;
1971 	ResizeWindow					resizeWindow;
1972 	bool							releaseBeforePresent;
1973 	bool							releaseBeforeRetire;
1974 };
1975 
releaseImagesTest(Context & context,const ReleaseImagesTestConfig testParams)1976 tcu::TestStatus releaseImagesTest(Context& context, const ReleaseImagesTestConfig testParams)
1977 {
1978 	const InstanceHelper					instHelper		(context, testParams.wsiType, false);
1979 	const TestNativeObjects					native			(context, instHelper.supportedExtensions, testParams.wsiType, 1);
1980 	Unique<VkSurfaceKHR>					surface			(createSurface(instHelper.vki, instHelper.instance, testParams.wsiType, *native.display, *native.windows[0], context.getTestContext().getCommandLine()));
1981 
1982 	const DeviceHelper						devHelper		(context, instHelper.vki, instHelper.instance, *surface, true, false);
1983 	const DeviceInterface&					vkd				= devHelper.vkd;
1984 	const VkDevice							device			= *devHelper.device;
1985 
1986 	std::vector<VkSurfaceFormatKHR>			surfaceFormats	= getPhysicalDeviceSurfaceFormats(instHelper.vki, devHelper.physicalDevice, *surface);
1987 	if(surfaceFormats.empty())
1988 		return tcu::TestStatus::fail("No VkSurfaceFormatKHR defined");
1989 
1990 	const VkSurfaceCapabilitiesKHR			capabilities	= getPerPresentSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface, testParams.mode);
1991 	const VkSurfaceTransformFlagBitsKHR		transform		= (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
1992 
1993 	const std::vector<VkPresentModeKHR>		presentModes	= getPhysicalDeviceSurfacePresentModes(instHelper.vki, devHelper.physicalDevice, *surface);
1994 	if (std::find(presentModes.begin(), presentModes.end(), testParams.mode) == presentModes.end())
1995 		TCU_THROW(NotSupportedError, "Present mode not supported");
1996 
1997 	if (testParams.scaling != 0)
1998 	{
1999 		// Skip if configuration is not supported
2000 		VkSurfacePresentScalingCapabilitiesEXT	scaling			= getSurfaceScalingCapabilities(instHelper.vki, devHelper.physicalDevice, testParams.mode, *surface);
2001 
2002 		if ((scaling.supportedPresentScaling & testParams.scaling) == 0)
2003 			TCU_THROW(NotSupportedError, "Scaling mode is not supported");
2004 	}
2005 
2006 	const bool isSharedPresentMode = testParams.mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || testParams.mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR;
2007 	if (isSharedPresentMode && (capabilities.minImageCount != 1 || capabilities.maxImageCount != 1))
2008 	{
2009 		return tcu::TestStatus::fail("min and max image count for shared present modes must be 1");
2010 	}
2011 
2012 	deUint32								imageCount		= capabilities.minImageCount + 10;
2013 	if (capabilities.maxImageCount > 0)
2014 		imageCount											= de::min(imageCount, capabilities.maxImageCount);
2015 
2016 	VkSwapchainCreateInfoKHR				swapchainInfo	= getBasicSwapchainParameters(*surface, surfaceFormats[0], native.windowSize, testParams.mode, transform, imageCount, false);
2017 
2018 	VkSwapchainPresentScalingCreateInfoEXT	scalingInfo		=
2019 	{
2020 		VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT,
2021 		DE_NULL,
2022 		testParams.scaling,
2023 		0,
2024 		0,
2025 	};
2026 	swapchainInfo.pNext										= &scalingInfo;
2027 
2028 	Move<VkSwapchainKHR>					swapchain		(createSwapchainKHR(vkd, device, &swapchainInfo));
2029 	std::vector<VkImage>					swapchainImages	= getSwapchainImages(vkd, device, *swapchain);
2030 
2031 	const Unique<VkCommandPool>				commandPool		(createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
2032 
2033 	const deUint32							iterations		= getIterations({testParams.mode}, {}, testParams.resizeWindow != ResizeWindow::No);
2034 
2035 	// Do testParams.iterations presents, with a fence associated with the last one.
2036 	FenceSp									presentFence	= FenceSp(new Unique<VkFence>(createFence(vkd, device)));
2037 	const std::vector<SemaphoreSp>			acquireSems		(createSemaphores(vkd, device, iterations));
2038 	const std::vector<SemaphoreSp>			presentSems		(createSemaphores(vkd, device, iterations));
2039 
2040 	const std::vector<CommandBufferSp>		commandBuffers	(allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, iterations));
2041 
2042 	const deUint64							foreverNs		= 0xFFFFFFFFFFFFFFFFul;
2043 
2044 	VkImageSubresourceRange					range			=
2045 	{
2046 		VK_IMAGE_ASPECT_COLOR_BIT,
2047 		0,
2048 		1,
2049 		0,
2050 		1,
2051 	};
2052 
2053 	const deUint32							configHash		=
2054 		(deUint32)testParams.wsiType |
2055 		(deUint32)testParams.mode << 4 |
2056 		(deUint32)testParams.scaling << 24 |
2057 		(deUint32)testParams.resizeWindow << 28 |
2058 		(deUint32)testParams.releaseBeforePresent << 30 |
2059 		(deUint32)testParams.releaseBeforeRetire << 31;
2060 	de::Random								rng				(0x53A4C8A1u ^ configHash);
2061 
2062 	try
2063 	{
2064 		for (deUint32 i = 0; i < iterations; ++i)
2065 		{
2066 			// Decide on how many acquires to do, and whether a presentation is to be done.  Presentation is always done for the last iteration, to facilitate clean up (by adding a present fence).
2067 			const deUint32					maxAllowedAcquires	= (deUint32)swapchainImages.size() - capabilities.minImageCount + 1;
2068 			const deUint32					acquireCount	= rng.getUint32() % maxAllowedAcquires + 1;
2069 			const bool						doPresent		= i + 1 == iterations || rng.getUint32() % 10 != 0;
2070 			const bool						doResize		= testParams.resizeWindow != ResizeWindow::No && rng.getUint32() % 10 != 0;
2071 			const deUint32					presentIndex	= doPresent ? rng.getUint32() % acquireCount : acquireCount;
2072 
2073 			// Resize the window if requested.
2074 			if (doResize && testParams.resizeWindow == ResizeWindow::BeforeAcquire)
2075 			{
2076 				tcu::UVec2					windowSize		= native.windowSize;
2077 				windowSize.x()								= windowSize.x() - 20 + rng.getUint32() % 41;
2078 				windowSize.y()								= windowSize.y() - 20 + rng.getUint32() % 41;
2079 
2080 				native.windows[0]->resize(windowSize);
2081 			}
2082 
2083 			// Acquire N times
2084 			const VkSemaphore				presentSem		= **presentSems[i];
2085 			const VkSemaphore				acquireSem		= **acquireSems[i];
2086 			std::vector<deUint32>			acquiredIndices	(acquireCount, 0x12345);
2087 
2088 			VkResult result = vkd.acquireNextImageKHR(device, *swapchain, foreverNs, presentIndex == 0 ? acquireSem : DE_NULL, DE_NULL, &acquiredIndices[0]);
2089 
2090 			// If out of date, recreate the swapchain and reacquire.
2091 			if (result == VK_ERROR_OUT_OF_DATE_KHR)
2092 			{
2093 				swapchainInfo.oldSwapchain					= *swapchain;
2094 				Move<VkSwapchainKHR>		newSwapchain	(createSwapchainKHR(vkd, device, &swapchainInfo));
2095 				swapchain									= std::move(newSwapchain);
2096 
2097 				const size_t previousImageCount				= swapchainImages.size();
2098 				swapchainImages								= getSwapchainImages(vkd, device, *swapchain);
2099 				if (previousImageCount != swapchainImages.size())
2100 					TCU_THROW(InternalError, "Unexpected change in number of swapchain images when recreated during window resize");
2101 
2102 				result = vkd.acquireNextImageKHR(device, *swapchain, foreverNs, presentIndex == 0 ? acquireSem : DE_NULL, DE_NULL, &acquiredIndices[0]);
2103 			}
2104 
2105 			VK_CHECK_WSI(result);
2106 
2107 			for (deUint32 j = 1; j < acquireCount; ++j)
2108 			{
2109 				VK_CHECK_WSI(vkd.acquireNextImageKHR(device, *swapchain, foreverNs, presentIndex == j ? acquireSem : DE_NULL, DE_NULL, &acquiredIndices[j]));
2110 			}
2111 
2112 			// Construct a list of image indices to be released.  That is every index except the one being presented, if any.
2113 			std::vector<deUint32>			releaseIndices	= acquiredIndices;
2114 			if (doPresent)
2115 			{
2116 				releaseIndices.erase(releaseIndices.begin() + presentIndex);
2117 			}
2118 
2119 			// Randomize the indices to be released.
2120 			rng.shuffle(releaseIndices.begin(), releaseIndices.end());
2121 
2122 			if (doResize && testParams.resizeWindow == ResizeWindow::BeforePresent)
2123 			{
2124 				tcu::UVec2					windowSize		= native.windowSize;
2125 				windowSize.x()								= windowSize.x() - 20 + rng.getUint32() % 41;
2126 				windowSize.y()								= windowSize.y() - 20 + rng.getUint32() % 41;
2127 
2128 				native.windows[0]->resize(windowSize);
2129 			}
2130 
2131 			if (doPresent)
2132 			{
2133 				beginCommandBuffer(vkd, **commandBuffers[i], 0u);
2134 
2135 				VkImageMemoryBarrier barrier = {
2136 					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
2137 					DE_NULL,
2138 					0,
2139 					0,
2140 					VK_IMAGE_LAYOUT_UNDEFINED,
2141 					VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2142 					VK_QUEUE_FAMILY_IGNORED,
2143 					VK_QUEUE_FAMILY_IGNORED,
2144 					swapchainImages[acquiredIndices[presentIndex]],
2145 					range,
2146 				};
2147 
2148 				VkClearColorValue				clearValue;
2149 				clearValue.float32[0]			= static_cast<float>(i % 33) / 32.0f;
2150 				clearValue.float32[1]			= static_cast<float>((i + 7) % 33) / 32.0f;
2151 				clearValue.float32[2]			= static_cast<float>((i + 17) % 33) / 32.0f;
2152 				clearValue.float32[3]			= 1.0f;
2153 
2154 				vkd.cmdClearColorImage(**commandBuffers[i], swapchainImages[acquiredIndices[presentIndex]], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue, 1, &range);
2155 
2156 				barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2157 				barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2158 				barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
2159 
2160 				vkd.cmdPipelineBarrier(**commandBuffers[i],
2161 						VK_PIPELINE_STAGE_TRANSFER_BIT,
2162 						VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2163 						0u,
2164 						0, DE_NULL,
2165 						0, DE_NULL,
2166 						1, &barrier);
2167 
2168 				endCommandBuffer(vkd, **commandBuffers[i]);
2169 
2170 				// Submit the command buffer
2171 				VkPipelineStageFlags			waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
2172 				const VkSubmitInfo				submitInfo =
2173 				{
2174 					VK_STRUCTURE_TYPE_SUBMIT_INFO,
2175 					DE_NULL,
2176 					1,
2177 					&acquireSem,
2178 					&waitStage,
2179 					1u,
2180 					&**commandBuffers[i],
2181 					1u,
2182 					&presentSem,
2183 				};
2184 				VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, DE_NULL));
2185 			}
2186 
2187 			// If asked to release before present, do so now.
2188 			const VkReleaseSwapchainImagesInfoEXT	releaseInfo =
2189 			{
2190 				VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT,
2191 				DE_NULL,
2192 				*swapchain,
2193 				(deUint32)releaseIndices.size(),
2194 				releaseIndices.data(),
2195 			};
2196 
2197 			bool imagesReleased = false;
2198 			if (testParams.releaseBeforePresent)
2199 			{
2200 				VK_CHECK(vkd.releaseSwapchainImagesEXT(device, &releaseInfo));
2201 				imagesReleased = true;
2202 			}
2203 
2204 			// Present the frame
2205 			if (doPresent)
2206 			{
2207 				const VkSwapchainPresentFenceInfoEXT presentFenceInfo =
2208 				{
2209 					VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT,
2210 					DE_NULL,
2211 					1,
2212 					&**presentFence,
2213 				};
2214 
2215 				const VkPresentInfoKHR presentInfo =
2216 				{
2217 					VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
2218 					// Signal the present fence on the last present.
2219 					i + 1 == iterations ? &presentFenceInfo : nullptr,
2220 					1u,
2221 					&presentSem,
2222 					1,
2223 					&*swapchain,
2224 					&acquiredIndices[presentIndex],
2225 					&result,
2226 				};
2227 				VkResult aggregateResult = vkd.queuePresentKHR(devHelper.queue, &presentInfo);
2228 				if (aggregateResult == VK_ERROR_OUT_OF_DATE_KHR || result == VK_ERROR_OUT_OF_DATE_KHR)
2229 				{
2230 					// If OUT_OF_DATE is returned from present, recreate the swapchain and release images to the retired swapchain.
2231 					if (!imagesReleased && testParams.releaseBeforeRetire)
2232 					{
2233 						VK_CHECK(vkd.releaseSwapchainImagesEXT(device, &releaseInfo));
2234 						imagesReleased = true;
2235 					}
2236 
2237 					swapchainInfo.oldSwapchain				= *swapchain;
2238 					Move<VkSwapchainKHR>	newSwapchain	(createSwapchainKHR(vkd, device, &swapchainInfo));
2239 
2240 					if (!imagesReleased && !testParams.releaseBeforeRetire)
2241 					{
2242 						// Release the images to the retired swapchain before deleting it (as part of move assignment below)
2243 						VK_CHECK(vkd.releaseSwapchainImagesEXT(device, &releaseInfo));
2244 						imagesReleased = true;
2245 					}
2246 
2247 					// Must have released old swapchain's images before destruction
2248 					DE_ASSERT(imagesReleased);
2249 					swapchain								= std::move(newSwapchain);
2250 
2251 					const size_t previousImageCount			= swapchainImages.size();
2252 					swapchainImages							= getSwapchainImages(vkd, device, *swapchain);
2253 					if (previousImageCount != swapchainImages.size())
2254 						TCU_THROW(InternalError, "Unexpected change in number of swapchain images when recreated during window resize");
2255 				}
2256 				else
2257 				{
2258 					VK_CHECK_WSI(result);
2259 					VK_CHECK_WSI(result);
2260 				}
2261 			}
2262 
2263 			// If asked to release after present, do it now.
2264 			if (!imagesReleased)
2265 			{
2266 				VK_CHECK_WSI(vkd.releaseSwapchainImagesEXT(device, &releaseInfo));
2267 			}
2268 		}
2269 
2270 		// Wait for all presents before terminating the test (when semaphores are destroyed)
2271 		VK_CHECK(vkd.waitForFences(device, 1u, &**presentFence, VK_TRUE, kMaxFenceWaitTimeout));
2272 	}
2273 	catch (...)
2274 	{
2275 		// Make sure device is idle before destroying resources
2276 		vkd.deviceWaitIdle(device);
2277 		throw;
2278 	}
2279 
2280 	native.windows[0]->setVisible(false);
2281 
2282 	return tcu::TestStatus::pass("Tests ran successfully");
2283 }
2284 
populateReleaseImagesGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2285 void populateReleaseImagesGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
2286 {
2287 	const struct
2288 	{
2289 		VkPresentModeKHR	mode;
2290 		const char*			name;
2291 	} presentModes[] =
2292 	{
2293 		{ VK_PRESENT_MODE_IMMEDIATE_KHR,					"immediate"		},
2294 		{ VK_PRESENT_MODE_MAILBOX_KHR,						"mailbox"		},
2295 		{ VK_PRESENT_MODE_FIFO_KHR,							"fifo"			},
2296 		{ VK_PRESENT_MODE_FIFO_RELAXED_KHR,					"fifo_relaxed"	},
2297 		{ VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,		"demand"		},
2298 		{ VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,	"continuous"	},
2299 	};
2300 
2301 	const struct
2302 	{
2303 		VkPresentScalingFlagsEXT		scaling;
2304 		const char*						name;
2305 	} scalingFlags[] =
2306 	{
2307 		{ 0,												"no_scaling"		},
2308 		{ VK_PRESENT_SCALING_STRETCH_BIT_EXT,				"stretch"			},
2309 	};
2310 
2311 	for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
2312 	{
2313 		de::MovePtr<tcu::TestCaseGroup>	presentModeGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), presentModes[presentModeNdx].name, presentModes[presentModeNdx].name));
2314 
2315 		for (size_t scalingFlagNdx = 0; scalingFlagNdx < DE_LENGTH_OF_ARRAY(scalingFlags); scalingFlagNdx++)
2316 		{
2317 			de::MovePtr<tcu::TestCaseGroup>	scalingFlagGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), scalingFlags[scalingFlagNdx].name, scalingFlags[scalingFlagNdx].name));
2318 
2319 			ReleaseImagesTestConfig			config;
2320 			config.wsiType					= wsiType;
2321 			config.mode						= presentModes[presentModeNdx].mode;
2322 			config.scaling					= scalingFlags[scalingFlagNdx].scaling;
2323 			config.resizeWindow				= ResizeWindow::No;
2324 			config.releaseBeforePresent		= false;
2325 			config.releaseBeforeRetire		= false;
2326 
2327 			addFunctionCase(&*scalingFlagGroup, "basic", "Basic release acquired images test", releaseImagesTest, config);
2328 
2329 			config.releaseBeforePresent		= true;
2330 			addFunctionCase(&*scalingFlagGroup, "release_before_present", "Basic release acquired images test where release happens before presenting an image", releaseImagesTest, config);
2331 
2332 			config.releaseBeforePresent		= false;
2333 			config.resizeWindow				= ResizeWindow::BeforeAcquire;
2334 			addFunctionCase(&*scalingFlagGroup, "resize_window", "Release acquired images after a window resize before acquire", releaseImagesTest, config);
2335 
2336 			config.resizeWindow				= ResizeWindow::BeforePresent;
2337 			addFunctionCase(&*scalingFlagGroup, "resize_window_after_acquire", "Release acquired images after a window resize after acquire", releaseImagesTest, config);
2338 
2339 			config.releaseBeforeRetire		= true;
2340 			addFunctionCase(&*scalingFlagGroup, "resize_window_after_acquire_release_before_retire", "Release acquired images after a window resize after acquire, but release the images before retiring the swapchain", releaseImagesTest, config);
2341 
2342 			presentModeGroup->addChild(scalingFlagGroup.release());
2343 		}
2344 
2345 		testGroup->addChild(presentModeGroup.release());
2346 	}
2347 }
2348 
2349 } // anonymous
2350 
createMaintenance1Tests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)2351 void createMaintenance1Tests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
2352 {
2353 	addTestGroup(testGroup, "present_fence",			"Present fence",				populatePresentFenceGroup,	wsiType);
2354 	addTestGroup(testGroup, "present_modes",			"Change present modes",			populatePresentModesGroup,	wsiType);
2355 	addTestGroup(testGroup, "scaling",					"Scaling and gravity",			populateScalingGroup,		wsiType);
2356 	addTestGroup(testGroup, "deferred_alloc",			"Deferred allocation",			populateDeferredAllocGroup,	wsiType);
2357 	addTestGroup(testGroup, "release_images",			"Release acquired images",		populateReleaseImagesGroup,	wsiType);
2358 }
2359 
2360 } // wsi
2361 
2362 } // vkt
2363