1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Google Inc.
6  * Copyright (c) 2020 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_full_screen_exclusive extension Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktWsiFullScreenExclusiveTests.hpp"
26 
27 #include "vktTestCaseUtil.hpp"
28 #include "vktCustomInstancesDevices.hpp"
29 
30 #include "vkRefUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkDeviceUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkWsiPlatform.hpp"
36 #include "vkWsiUtil.hpp"
37 
38 #include "tcuTestLog.hpp"
39 #include "tcuPlatform.hpp"
40 #include "tcuCommandLine.hpp"
41 
42 #include <limits>
43 
44 #if ( DE_OS == DE_OS_WIN32 )
45 	#define NOMINMAX
46 	#define WIN32_LEAN_AND_MEAN
47 	#include <windows.h>
48 #endif
49 
50 namespace vkt
51 {
52 namespace wsi
53 {
54 
55 namespace
56 {
57 
58 using namespace vk;
59 using namespace vk::wsi;
60 
61 typedef std::vector<VkExtensionProperties> Extensions;
62 
63 struct TestParams
64 {
65 	vk::wsi::Type				wsiType;
66 	VkFullScreenExclusiveEXT	fseType;
67 };
68 
checkAllSupported(const Extensions& supportedExtensions, const std::vector<std::string>& requiredExtensions)69 void checkAllSupported (const Extensions& supportedExtensions,
70 						const std::vector<std::string>& requiredExtensions)
71 {
72 	for (std::vector<std::string>::const_iterator requiredExtName = requiredExtensions.begin();
73 		 requiredExtName != requiredExtensions.end();
74 		 ++requiredExtName)
75 	{
76 		if (!isExtensionStructSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
77 			TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
78 	}
79 }
80 
createInstanceWithWsi(Context& context, const Extensions& supportedExtensions, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)81 CustomInstance createInstanceWithWsi (Context&						context,
82 									  const Extensions&				supportedExtensions,
83 									  Type							wsiType,
84 									  const VkAllocationCallbacks*	pAllocator	= DE_NULL)
85 {
86 	std::vector<std::string>	extensions;
87 
88 	extensions.push_back("VK_KHR_surface");
89 	extensions.push_back(getExtensionName(wsiType));
90 	if (isDisplaySurface(wsiType))
91 		extensions.push_back("VK_KHR_display");
92 
93 	if (isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_KHR_get_surface_capabilities2")))
94 		extensions.push_back("VK_KHR_get_surface_capabilities2");
95 
96 	checkAllSupported(supportedExtensions, extensions);
97 
98 	return createCustomInstanceWithExtensions(context, extensions, pAllocator);
99 }
100 
getDeviceFeaturesForWsi(void)101 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
102 {
103 	VkPhysicalDeviceFeatures features;
104 	deMemset(&features, 0, sizeof(features));
105 	return features;
106 }
107 
createDeviceWithWsi(const vk::PlatformInterface& vkp, vk::VkInstance instance, const InstanceInterface& vki, VkPhysicalDevice physicalDevice, const Extensions& supportedExtensions, const deUint32 queueFamilyIndex, const VkAllocationCallbacks* pAllocator, bool validationEnabled)108 Move<VkDevice> createDeviceWithWsi (const vk::PlatformInterface&	vkp,
109 									vk::VkInstance					instance,
110 									const InstanceInterface&		vki,
111 									VkPhysicalDevice				physicalDevice,
112 									const Extensions&				supportedExtensions,
113 									const deUint32					queueFamilyIndex,
114 									const VkAllocationCallbacks*	pAllocator,
115 									bool							validationEnabled)
116 {
117 	const float						queuePriorities[]	= { 1.0f };
118 	const VkDeviceQueueCreateInfo	queueInfos[]		=
119 	{
120 		{
121 			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
122 			DE_NULL,
123 			(VkDeviceQueueCreateFlags)0,
124 			queueFamilyIndex,
125 			DE_LENGTH_OF_ARRAY(queuePriorities),
126 			&queuePriorities[0]
127 		}
128 	};
129 	const VkPhysicalDeviceFeatures	features		= getDeviceFeaturesForWsi();
130 	std::vector<const char*>		extensions;
131 
132 	if (!isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_KHR_swapchain")))
133 		TCU_THROW(NotSupportedError, "VK_KHR_swapchain is not supported");
134 	extensions.push_back("VK_KHR_swapchain");
135 
136 	if (isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_EXT_full_screen_exclusive")))
137 	{
138 		extensions.push_back("VK_EXT_full_screen_exclusive");
139 	}
140 
141 	VkDeviceCreateInfo		deviceParams	=
142 	{
143 		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
144 		DE_NULL,
145 		(VkDeviceCreateFlags)0,
146 		DE_LENGTH_OF_ARRAY(queueInfos),
147 		&queueInfos[0],
148 		0u,									// enabledLayerCount
149 		DE_NULL,							// ppEnabledLayerNames
150 		(deUint32)extensions.size(),
151 		extensions.empty() ? DE_NULL : &extensions[0],
152 		&features
153 	};
154 
155 	return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
156 }
157 
158 struct InstanceHelper
159 {
160 	const std::vector<VkExtensionProperties>	supportedExtensions;
161 	const CustomInstance				instance;
162 	const InstanceDriver&				vki;
163 
InstanceHelpervkt::wsi::__anon30128::InstanceHelper164 	InstanceHelper (Context& context,
165 					Type wsiType,
166 					const VkAllocationCallbacks* pAllocator = DE_NULL)
167 		: supportedExtensions	(enumerateInstanceExtensionProperties(context.getPlatformInterface(),
168 																	  DE_NULL))
169 		, instance				(createInstanceWithWsi(context,
170 													   supportedExtensions,
171 													   wsiType,
172 													   pAllocator))
173 		, vki					(instance.getDriver())
174 	{}
175 };
176 
177 struct DeviceHelper
178 {
179 	const VkPhysicalDevice	physicalDevice;
180 	const deUint32			queueFamilyIndex;
181 	const Unique<VkDevice>	device;
182 	const DeviceDriver		vkd;
183 	const VkQueue			queue;
184 
DeviceHelpervkt::wsi::__anon30128::DeviceHelper185 	DeviceHelper (Context&						context,
186 				  const InstanceInterface&		vki,
187 				  VkInstance					instance,
188 				  VkSurfaceKHR					surface,
189 				  const VkAllocationCallbacks*	pAllocator = DE_NULL)
190 		: physicalDevice	(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
191 		, queueFamilyIndex	(chooseQueueFamilyIndex(vki, physicalDevice, surface))
192 		, device			(createDeviceWithWsi(context.getPlatformInterface(),
193 												 instance,
194 												 vki,
195 												 physicalDevice,
196 												 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
197 												 queueFamilyIndex,
198 												 pAllocator,
199 												 context.getTestContext().getCommandLine().isValidationEnabled()))
200 		, vkd				(context.getPlatformInterface(), instance, *device)
201 		, queue				(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
202 	{
203 	}
204 };
205 
createDisplay(const vk::Platform& platform, const Extensions& supportedExtensions, Type wsiType)206 de::MovePtr<Display> createDisplay (const vk::Platform&	platform,
207 									const Extensions&	supportedExtensions,
208 									Type				wsiType)
209 {
210 	try
211 	{
212 		return de::MovePtr<Display>(platform.createWsiDisplay(wsiType));
213 	}
214 	catch (const tcu::NotSupportedError& e)
215 	{
216 		if (isExtensionStructSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))) &&
217 		    platform.hasDisplay(wsiType))
218 		{
219 			// If VK_KHR_{platform}_surface was supported, vk::Platform implementation
220 			// must support creating native display & window for that WSI type.
221 			throw tcu::TestError(e.getMessage());
222 		}
223 		else
224 			throw;
225 	}
226 }
227 
createWindow(const Display& display, const tcu::Maybe<tcu::UVec2>& initialSize)228 de::MovePtr<Window> createWindow (const Display& display,
229 								  const tcu::Maybe<tcu::UVec2>& initialSize)
230 {
231 	try
232 	{
233 		return de::MovePtr<Window>(display.createWindow(initialSize));
234 	}
235 	catch (const tcu::NotSupportedError& e)
236 	{
237 		// See createDisplay - assuming that wsi::Display was supported platform port
238 		// should also support creating a window.
239 		throw tcu::TestError(e.getMessage());
240 	}
241 }
242 
243 struct NativeObjectsFS
244 {
245 	const de::UniquePtr<Display>	display;
246 	tcu::UVec2						windowSize;
247 	const de::UniquePtr<Window>		window;
248 
NativeObjectsFSvkt::wsi::__anon30128::NativeObjectsFS249 	NativeObjectsFS	(Context&				context,
250 					 const Extensions&		supportedExtensions,
251 					 Type					wsiType)
252 		: display		(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
253 		, windowSize	(getFullScreenSize(wsiType, *display.get(), tcu::UVec2(256U, 256U)))
254 		, window		(createWindow(*display, windowSize))
255 	{}
256 };
257 
getBasicSwapchainParameters(Type wsiType, const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceFormatKHR surfaceFormat, const tcu::UVec2& desiredSize, deUint32 desiredImageCount)258 VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type						wsiType,
259 													  const InstanceInterface&	vki,
260 													  VkPhysicalDevice			physicalDevice,
261 													  VkSurfaceKHR				surface,
262 													  VkSurfaceFormatKHR		surfaceFormat,
263 													  const tcu::UVec2&			desiredSize,
264 													  deUint32					desiredImageCount)
265 {
266 	const VkSurfaceCapabilitiesKHR		capabilities		= getPhysicalDeviceSurfaceCapabilities(vki,
267 																								   physicalDevice,
268 																								   surface);
269 	const PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
270 	const VkSurfaceTransformFlagBitsKHR transform			= (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
271 	const VkSwapchainCreateInfoKHR		parameters			=
272 	{
273 		VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
274 		DE_NULL,
275 		(VkSwapchainCreateFlagsKHR)0,
276 		surface,
277 		de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
278 		surfaceFormat.format,
279 		surfaceFormat.colorSpace,
280 		(platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
281 			? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
282 		1u,									// imageArrayLayers
283 		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
284 		VK_SHARING_MODE_EXCLUSIVE,
285 		0u,
286 		(const deUint32*)DE_NULL,
287 		transform,
288 		VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
289 		VK_PRESENT_MODE_FIFO_KHR,
290 		VK_FALSE,							// clipped
291 		(VkSwapchainKHR)0					// oldSwapchain
292 	};
293 
294 	return parameters;
295 }
296 
297 typedef de::SharedPtr<Unique<VkCommandBuffer> >	CommandBufferSp;
298 typedef de::SharedPtr<Unique<VkFence> >			FenceSp;
299 typedef de::SharedPtr<Unique<VkSemaphore> >		SemaphoreSp;
300 
createFences(const DeviceInterface& vkd, const VkDevice device, size_t numFences)301 std::vector<FenceSp> createFences (const DeviceInterface&	vkd,
302 								   const VkDevice			device,
303 								   size_t					numFences)
304 {
305 	std::vector<FenceSp> fences(numFences);
306 
307 	for (size_t ndx = 0; ndx < numFences; ++ndx)
308 		fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
309 
310 	return fences;
311 }
312 
createSemaphores(const DeviceInterface& vkd, const VkDevice device, size_t numSemaphores)313 std::vector<SemaphoreSp> createSemaphores (const DeviceInterface&	vkd,
314 										   const VkDevice			device,
315 										   size_t					numSemaphores)
316 {
317 	std::vector<SemaphoreSp> semaphores(numSemaphores);
318 
319 	for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
320 		semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
321 
322 	return semaphores;
323 }
324 
allocateCommandBuffers(const DeviceInterface& vkd, const VkDevice device, const VkCommandPool commandPool, const VkCommandBufferLevel level, const size_t numCommandBuffers)325 std::vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface&		vkd,
326 													 const VkDevice				device,
327 													 const VkCommandPool		commandPool,
328 													 const VkCommandBufferLevel	level,
329 													 const size_t				numCommandBuffers)
330 {
331 	std::vector<CommandBufferSp>				buffers		(numCommandBuffers);
332 
333 	for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
334 		buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
335 
336 	return buffers;
337 }
338 
fullScreenExclusiveTest(Context& context, TestParams testParams)339 tcu::TestStatus fullScreenExclusiveTest(Context& context,
340 	TestParams testParams)
341 {
342 	if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_EXT_full_screen_exclusive"))
343 		TCU_THROW(NotSupportedError, "Extension VK_EXT_full_screen_exclusive not supported");
344 
345 	const InstanceHelper						instHelper(context, testParams.wsiType);
346 	const NativeObjectsFS						native(context, instHelper.supportedExtensions, testParams.wsiType);
347 	const Unique<VkSurfaceKHR>					surface(createSurface(instHelper.vki, instHelper.instance, testParams.wsiType, *native.display, *native.window, context.getTestContext().getCommandLine()));
348 	const DeviceHelper							devHelper(context, instHelper.vki, instHelper.instance, *surface);
349 	const std::vector<VkExtensionProperties>	deviceExtensions(enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL));
350 	if (!isExtensionStructSupported(deviceExtensions, RequiredExtension("VK_EXT_full_screen_exclusive")))
351 		TCU_THROW(NotSupportedError, "Extension VK_EXT_full_screen_exclusive not supported");
352 
353 	native.window->setVisible(true);
354 
355 	if (testParams.wsiType == TYPE_WIN32)
356 	{
357 		native.window->setForeground();
358 	}
359 
360 	// add information about full screen exclusive to VkSwapchainCreateInfoKHR
361 	VkSurfaceFullScreenExclusiveInfoEXT			fseInfo =
362 	{
363 		VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT,			// VkStructureType             sType;
364 		DE_NULL,															// void*                       pNext;
365 		testParams.fseType													// VkFullScreenExclusiveEXT    fullScreenExclusive;
366 	};
367 
368 	// for Win32 - create structure containing HMONITOR value
369 #if ( DE_OS == DE_OS_WIN32 )
370 	VkSurfaceFullScreenExclusiveWin32InfoEXT	fseWin32Info				= {
371 		VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT,		// VkStructureType    sType;
372 		DE_NULL,															// const void*        pNext;
373 		pt::Win32MonitorHandle(0)											// HMONITOR           hmonitor;
374 	};
375 	if (testParams.wsiType == TYPE_WIN32)
376 	{
377 		Win32WindowInterface*					windowInterface				= dynamic_cast<Win32WindowInterface*>(native.window.get());
378 		fseWin32Info.hmonitor												= (pt::Win32MonitorHandle)MonitorFromWindow((HWND)windowInterface->getNative().internal, MONITOR_DEFAULTTONEAREST);
379 	}
380 #endif
381 
382 	// check surface capabilities
383 	VkSurfaceCapabilitiesFullScreenExclusiveEXT	surfaceCapabilitiesFSE		= {
384 		VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT,	// VkStructureType    sType;
385 		DE_NULL,															// void*              pNext;
386 		DE_FALSE															// VkBool32           fullScreenExclusiveSupported;
387 	};
388 	VkSurfaceCapabilities2KHR					surfaceCapabilities2		= {
389 		VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,						// VkStructureType             sType;
390 		&surfaceCapabilitiesFSE,											// void*                       pNext;
391 		VkSurfaceCapabilitiesKHR {}											// VkSurfaceCapabilitiesKHR    surfaceCapabilities;
392 	};
393 	VkPhysicalDeviceSurfaceInfo2KHR				surfaceInfo					= {
394 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,				// VkStructureType    sType;
395 		DE_NULL,															// const void*        pNext;
396 		*surface															// VkSurfaceKHR       surface;
397 	};
398 
399 	surfaceInfo.pNext = &fseInfo;
400 
401 #if ( DE_OS == DE_OS_WIN32 )
402 	if (testParams.wsiType == TYPE_WIN32)
403 	{
404 		fseInfo.pNext = &fseWin32Info;
405 	}
406 #endif
407 
408 	instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(devHelper.physicalDevice, &surfaceInfo, &surfaceCapabilities2);
409 	if (surfaceCapabilitiesFSE.fullScreenExclusiveSupported == DE_FALSE)
410 		TCU_THROW(NotSupportedError, "VkSurfaceCapabilitiesFullScreenExclusiveEXT::fullScreenExclusiveSupported is set to false");
411 
412 	const DeviceInterface&						vkd							= devHelper.vkd;
413 	const VkDevice								device						= *devHelper.device;
414 	SimpleAllocator								allocator					(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
415 
416 	std::vector<VkSurfaceFormatKHR>				surfaceFormats				= vk::wsi::getPhysicalDeviceSurfaceFormats(instHelper.vki, devHelper.physicalDevice, *surface);
417 	if(surfaceFormats.empty())
418 		return tcu::TestStatus::fail("No VkSurfaceFormatKHR defined");
419 
420 	VkSwapchainCreateInfoKHR					swapchainInfo				= getBasicSwapchainParameters(testParams.wsiType, instHelper.vki, devHelper.physicalDevice, *surface, surfaceFormats[0], native.windowSize, 2);
421 
422 	swapchainInfo.pNext = &fseInfo;
423 
424 #if ( DE_OS == DE_OS_WIN32 )
425 	if (testParams.wsiType == TYPE_WIN32)
426 	{
427 		fseInfo.pNext = &fseWin32Info;
428 	}
429 #endif
430 
431 	Move<VkSwapchainKHR>						swapchain;
432 	{
433 		VkSwapchainKHR object = 0;
434 		VkResult result = vkd.createSwapchainKHR(device, &swapchainInfo, DE_NULL, &object);
435 		if (result == VK_ERROR_INITIALIZATION_FAILED && testParams.fseType == VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT)
436 		{
437 			// In some cases, swapchain creation may fail if exclusive full-screen mode is requested for application control,
438 			// but for some implementation-specific reason exclusive full-screen access is unavailable for the particular combination
439 			// of parameters provided. If this occurs, VK_ERROR_INITIALIZATION_FAILED will be returned.
440 			return  tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Failed to create swapchain with exclusive full-screen mode for application control.");
441 		}
442 		else
443 		{
444 			VK_CHECK(result);
445 		}
446 
447 		swapchain = Move<VkSwapchainKHR>(check<VkSwapchainKHR>(object), Deleter<VkSwapchainKHR>(vkd, device, DE_NULL));
448 	}
449 	const std::vector<VkImage>					swapchainImages				= getSwapchainImages(vkd, device, *swapchain);
450 
451 	const WsiTriangleRenderer					renderer					(vkd,
452 																			 device,
453 																			 allocator,
454 																			 context.getBinaryCollection(),
455 																			 true,
456 																			 swapchainImages,
457 																			 swapchainImages,
458 																			 swapchainInfo.imageFormat,
459 																			 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
460 
461 	const Unique<VkCommandPool>					commandPool					(createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
462 
463 	const size_t								maxQueuedFrames				= swapchainImages.size()*2;
464 
465 	// We need to keep hold of fences from vkAcquireNextImageKHR to actually
466 	// limit number of frames we allow to be queued.
467 	const std::vector<FenceSp>					imageReadyFences			(createFences(vkd, device, maxQueuedFrames));
468 
469 	// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
470 	// the semaphore in same time as the fence we use to meter rendering.
471 	const std::vector<SemaphoreSp>				imageReadySemaphores		(createSemaphores(vkd, device, maxQueuedFrames+1));
472 
473 	// For rest we simply need maxQueuedFrames as we will wait for image
474 	// from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
475 	// previous uses must have completed.
476 	const std::vector<SemaphoreSp>				renderingCompleteSemaphores	(createSemaphores(vkd, device, maxQueuedFrames));
477 	const std::vector<CommandBufferSp>			commandBuffers				(allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
478 
479 	bool										fullScreenAcquired			= (testParams.fseType != VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT);
480 
481 	bool										fullScreenLost				= false;
482 
483 	try
484 	{
485 		const deUint32	numFramesToRender					= 60;
486 
487 		for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
488 		{
489 			const VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
490 			const VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
491 			deUint32			imageNdx			= ~0u;
492 
493 			if (!fullScreenAcquired)
494 			{
495 				const VkResult acquireResult = vkd.acquireFullScreenExclusiveModeEXT(device, *swapchain);
496 
497 				switch (acquireResult)
498 				{
499 					case VK_SUCCESS:
500 					{
501 						fullScreenAcquired = true;
502 						break;
503 					}
504 					case VK_ERROR_INITIALIZATION_FAILED:
505 					{
506 						break;
507 					}
508 					case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
509 					{
510 						context.getTestContext().getLog() << tcu::TestLog::Message << "Got VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT at vkAcquireFullScreenExclusiveModeEXT. Frame " << frameNdx << tcu::TestLog::EndMessage;
511 						break;
512 					}
513 					default:
514 					{
515 						VK_CHECK(acquireResult);
516 						break;
517 					}
518 				}
519 			}
520 
521 			if (frameNdx >= maxQueuedFrames)
522 				VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
523 
524 			VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
525 
526 			VkResult	acquireResult;
527 
528 			{
529 				acquireResult	= vkd.acquireNextImageKHR(device,
530 														  *swapchain,
531 														  std::numeric_limits<deUint64>::max(),
532 														  imageReadySemaphore,
533 														  (vk::VkFence)0,
534 														  &imageNdx);
535 				if (acquireResult == VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
536 				{
537 					context.getTestContext().getLog() << tcu::TestLog::Message << "Got VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT at vkAcquireNextImageKHR" << tcu::TestLog::EndMessage;
538 
539 					fullScreenLost = true;
540 				}
541 				VK_CHECK_WSI(acquireResult);
542 			}
543 
544 			if (acquireResult != VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
545 			{
546 				TCU_CHECK((size_t)imageNdx < swapchainImages.size());
547 
548 				const VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
549 				const VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
550 				const VkPipelineStageFlags	waitDstStage				= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
551 				const VkSubmitInfo			submitInfo					=
552 				{
553 					VK_STRUCTURE_TYPE_SUBMIT_INFO,
554 					DE_NULL,
555 					1u,
556 					&imageReadySemaphore,
557 					&waitDstStage,
558 					1u,
559 					&commandBuffer,
560 					1u,
561 					&renderingCompleteSemaphore
562 				};
563 				const VkPresentInfoKHR		presentInfo					=
564 				{
565 					VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
566 					DE_NULL,
567 					1u,
568 					&renderingCompleteSemaphore,
569 					1u,
570 					&*swapchain,
571 					&imageNdx,
572 					(VkResult*)DE_NULL
573 				};
574 
575 				renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
576 				VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
577 				const VkResult presentResult = vkd.queuePresentKHR(devHelper.queue, &presentInfo);
578 				if (presentResult == VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
579 				{
580 					context.getTestContext().getLog() << tcu::TestLog::Message << "Got VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT at vkQueuePresentKHR" << tcu::TestLog::EndMessage;
581 
582 					fullScreenLost = true;
583 				}
584 				VK_CHECK_WSI(presentResult);
585 			}
586 			else
587 			{
588 				// image was not acquired, just roll the synchronization
589 				VK_CHECK(vkd.queueSubmit(devHelper.queue, 0u, DE_NULL, imageReadyFence));
590 			}
591 		}
592 
593 		VK_CHECK(vkd.deviceWaitIdle(device));
594 	}
595 	catch (...)
596 	{
597 		// Make sure device is idle before destroying resources
598 		vkd.deviceWaitIdle(device);
599 		throw;
600 	}
601 
602 	if (fullScreenAcquired && testParams.fseType == VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT)
603 	{
604 		const VkResult releaseResult = vkd.releaseFullScreenExclusiveModeEXT(device, *swapchain);
605 		if (releaseResult == VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
606 		{
607 			context.getTestContext().getLog() << tcu::TestLog::Message << "Got VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT at vkReleaseFullScreenExclusiveModeEXT" << tcu::TestLog::EndMessage;
608 
609 			fullScreenLost = true;
610 		}
611 		VK_CHECK_WSI(releaseResult);
612 	}
613 
614 	native.window->setVisible(false);
615 
616 	if (fullScreenAcquired && !fullScreenLost)
617 	{
618 		return tcu::TestStatus::pass("Rendering tests succeeded");
619 	}
620 	else
621 	{
622 		if (fullScreenLost)
623 		{
624 			return  tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Full screen exclusive was lost during test, but did not end with an error.");
625 		}
626 		else
627 		{
628 			return  tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Failed to acquire full screen exclusive, but did not end with an error.");
629 		}
630 	}
631 }
632 
getBasicRenderPrograms(SourceCollections& dst, TestParams)633 void getBasicRenderPrograms (SourceCollections& dst, TestParams)
634 {
635 	WsiTriangleRenderer::getPrograms(dst);
636 }
637 
638 } // anonymous
639 
createFullScreenExclusiveTests(tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)640 void createFullScreenExclusiveTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
641 {
642 	struct
643 	{
644 		VkFullScreenExclusiveEXT				testType;
645 		const char*								name;
646 	} fullScreenTestTypes[] =
647 	{
648 		{ VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT,					"default" },
649 		{ VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT,					"allowed" },
650 		{ VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT,				"disallowed" },
651 		{ VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT,	"application_controlled" },
652 	};
653 
654 	for (size_t fseNdx = 0; fseNdx < DE_LENGTH_OF_ARRAY(fullScreenTestTypes); ++fseNdx)
655 	{
656 		TestParams testParams
657 		{
658 			wsiType,
659 			fullScreenTestTypes[fseNdx].testType
660 		};
661 		addFunctionCaseWithPrograms(testGroup, fullScreenTestTypes[fseNdx].name, "", getBasicRenderPrograms, fullScreenExclusiveTest, testParams);
662 	}
663 }
664 
665 } // wsi
666 
667 } // vkt
668