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