xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/wsi/vktWsiDisplayControlTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \brief VK_EXT_display_control tests
21  *//*--------------------------------------------------------------------*/
22 
23 #include "vkRefUtil.hpp"
24 #include "vkWsiPlatform.hpp"
25 #include "vkWsiUtil.hpp"
26 #include "vkQueryUtil.hpp"
27 #include "vkDeviceUtil.hpp"
28 #include "vkPlatform.hpp"
29 #include "vkTypeUtil.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkWsiUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkObjUtil.hpp"
35 
36 #include "vktWsiDisplayControlTests.hpp"
37 #include "vktTestCaseUtil.hpp"
38 #include "vktTestGroupUtil.hpp"
39 #include "vktCustomInstancesDevices.hpp"
40 
41 #include "tcuPlatform.hpp"
42 #include "tcuResultCollector.hpp"
43 #include "tcuTestLog.hpp"
44 #include "tcuCommandLine.hpp"
45 
46 #include "deClock.h"
47 
48 #include <vector>
49 #include <string>
50 
51 using std::string;
52 using std::vector;
53 
54 using tcu::Maybe;
55 using tcu::TestLog;
56 using tcu::UVec2;
57 
58 namespace vkt
59 {
60 namespace wsi
61 {
62 namespace
63 {
64 
65 using namespace vk;
66 using namespace vk::wsi;
67 
68 typedef vector<VkExtensionProperties> Extensions;
69 
createInstance(Context & context)70 CustomInstance createInstance(Context &context)
71 {
72     vector<string> extensions = {
73         "VK_KHR_surface",
74         "VK_KHR_display",
75         "VK_EXT_display_surface_counter",
76     };
77 
78     return vkt::createCustomInstanceWithExtensions(context, extensions);
79 }
80 
chooseQueueFamilyIndex(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)81 uint32_t chooseQueueFamilyIndex(const InstanceInterface &vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
82 {
83     uint32_t numTotalFamilyIndices;
84     vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numTotalFamilyIndices, DE_NULL);
85 
86     for (uint32_t queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
87     {
88         if (wsi::getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) == VK_TRUE)
89             return queueFamilyNdx;
90     }
91 
92     TCU_THROW(NotSupportedError, "Device doesn't support presentation");
93     return 0;
94 }
95 
createTestDevice(const Context & context,const PlatformInterface & vkp,const VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const uint32_t queueFamilyIndex,const VkAllocationCallbacks * pAllocator=DE_NULL)96 Move<VkDevice> createTestDevice(const Context &context, const PlatformInterface &vkp, const VkInstance instance,
97                                 const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
98                                 const uint32_t queueFamilyIndex, const VkAllocationCallbacks *pAllocator = DE_NULL)
99 {
100     const float queuePriorities[] = {1.0f};
101     bool displayAvailable         = true;
102     bool validationEnabled        = context.getTestContext().getCommandLine().isValidationEnabled();
103     const vk::Platform &platform  = context.getTestContext().getPlatform().getVulkanPlatform();
104 
105     const VkDeviceQueueCreateInfo queueInfos[] = {{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, DE_NULL,
106                                                    (VkDeviceQueueCreateFlags)0, queueFamilyIndex,
107                                                    DE_LENGTH_OF_ARRAY(queuePriorities), &queuePriorities[0]}};
108 
109     VkPhysicalDeviceFeatures features;
110     deMemset(&features, 0, sizeof(features));
111 
112     const char *extensions[] = {"VK_KHR_swapchain", "VK_EXT_display_control"};
113 
114     const VkDeviceCreateInfo deviceParams = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
115                                              DE_NULL,
116                                              (VkDeviceCreateFlags)0,
117                                              DE_LENGTH_OF_ARRAY(queueInfos),
118                                              &queueInfos[0],
119                                              0u,
120                                              DE_NULL,
121                                              DE_LENGTH_OF_ARRAY(extensions),
122                                              &extensions[0],
123                                              &features};
124 
125     for (auto ext : extensions)
126     {
127         if (!context.isDeviceFunctionalitySupported(ext))
128             TCU_THROW(NotSupportedError, (string(ext) + " is not supported").c_str());
129     }
130 
131     for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
132     {
133         vk::wsi::Type wsiType = (vk::wsi::Type)typeNdx;
134         if (platform.hasDisplay(wsiType))
135         {
136             displayAvailable = false;
137             break;
138         }
139     }
140 
141     if (!displayAvailable)
142         TCU_THROW(NotSupportedError, "Display is unavailable as windowing system has access");
143 
144     return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
145 }
146 
getDisplayAndDisplayPlane(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,uint32_t * pPlaneIndex)147 VkDisplayKHR getDisplayAndDisplayPlane(const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
148                                        uint32_t *pPlaneIndex)
149 {
150     uint32_t countDisplays = 0;
151     VkResult result        = vki.getPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &countDisplays, DE_NULL);
152     if (result != VK_SUCCESS)
153         TCU_THROW(NotSupportedError, "vkGetPhysicalDeviceDisplayPropertiesKHR failed");
154 
155     if (countDisplays == 0)
156         TCU_THROW(NotSupportedError, "No displays available");
157 
158     uint32_t countDisplayPlanes = 0;
159     result = vki.getPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &countDisplayPlanes, DE_NULL);
160     if (result != VK_SUCCESS || !countDisplayPlanes)
161         TCU_FAIL("GetPhysicalDeviceDisplayPlanePropertiesKHR failed");
162 
163     for (uint32_t p = 0; p < countDisplayPlanes; p++)
164     {
165         uint32_t count = 0u;
166         result         = vki.getDisplayPlaneSupportedDisplaysKHR(physicalDevice, p, &count, DE_NULL);
167         if (result != VK_SUCCESS)
168             TCU_FAIL("GetDisplayPlaneSupportedDisplaysKHR failed");
169 
170         // No displays that can make use of this plane are available.
171         if (!count)
172             continue;
173 
174         std::vector<VkDisplayKHR> displays(count);
175         result = vki.getDisplayPlaneSupportedDisplaysKHR(physicalDevice, p, &count, &displays[0]);
176         if (result != VK_SUCCESS)
177             TCU_FAIL("GetDisplayPlaneSupportedDisplaysKHR failed");
178 
179         // return first plane with an available display
180         *pPlaneIndex = p;
181         return displays[0];
182     }
183 
184     TCU_FAIL("No intersection between displays and display planes");
185 
186     // Unreachable.
187     return DE_NULL;
188 }
189 
createSurface(const InstanceInterface & vki,VkInstance instance,VkPhysicalDevice physicalDevice,VkDisplayKHR display,uint32_t planeIndex)190 VkSurfaceKHR createSurface(const InstanceInterface &vki, VkInstance instance, VkPhysicalDevice physicalDevice,
191                            VkDisplayKHR display, uint32_t planeIndex)
192 {
193     // get number of display modes for this display
194     uint32_t displayModesCount = 0;
195     VkResult result            = vki.getDisplayModePropertiesKHR(physicalDevice, display, &displayModesCount, DE_NULL);
196     if (result != VK_SUCCESS)
197         TCU_FAIL("GetDisplayModePropertiesKHR failed");
198 
199     // get first display mode of this display
200     std::vector<vk::VkDisplayModePropertiesKHR> modeProperties(displayModesCount);
201     result = vki.getDisplayModePropertiesKHR(physicalDevice, display, &displayModesCount, &modeProperties[0]);
202     if (result != VK_SUCCESS)
203         TCU_FAIL("GetDisplayModePropertiesKHR failed");
204     VkDisplayModeKHR displayMode = modeProperties[0].displayMode;
205 
206     // get capabielieties for first plane of this display
207     VkDisplayPlaneCapabilitiesKHR planeCapabilities;
208     result = vki.getDisplayPlaneCapabilitiesKHR(physicalDevice, displayMode, planeIndex, &planeCapabilities);
209     if (result != VK_SUCCESS)
210         TCU_FAIL("GetDisplayPlaneCapabilitiesKHR failed");
211 
212     // get plane properties count
213     uint32_t planePropertiesCount = 0;
214     result = vki.getPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &planePropertiesCount, DE_NULL);
215     if (result != VK_SUCCESS || !planePropertiesCount)
216         TCU_FAIL("GetPhysicalDeviceDisplayPlanePropertiesKHR failed");
217 
218     // get plane properties
219     std::vector<VkDisplayPlanePropertiesKHR> planeProperties(planePropertiesCount);
220     result = vki.getPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &planePropertiesCount, &planeProperties[0]);
221     if (result != VK_SUCCESS)
222         TCU_FAIL("GetPhysicalDeviceDisplayPlanePropertiesKHR failed");
223 
224     // define surface create info
225     const VkDisplaySurfaceCreateInfoKHR createInfo = {
226         VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR, // VkStructureType                    sType
227         DE_NULL,                                           // const void*                        pNext
228         0,                                                 // VkDisplaySurfaceCreateFlagsKHR    flags
229         displayMode,                                       // VkDisplayModeKHR                    displayMode
230         planeIndex,                                        // uint32_t                            planeIndex
231         planeProperties[planeIndex].currentStackIndex,     // uint32_t                            planeStackIndex
232         VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,             // VkSurfaceTransformFlagBitsKHR    transform
233         1.0f,                                              // float                            globalAlpha
234         VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR,             // VkDisplayPlaneAlphaFlagBitsKHR    alphaMode
235         {                                                  // VkExtent2D                        imageExtent
236          planeCapabilities.minDstExtent.width, planeCapabilities.minDstExtent.height}};
237 
238     VkSurfaceKHR surface = DE_NULL;
239     result               = vki.createDisplayPlaneSurfaceKHR(instance, &createInfo, DE_NULL, &surface);
240     if (result != VK_SUCCESS)
241         TCU_FAIL("CreateDisplayPlaneSurfaceKHR failed");
242 
243     if (surface == DE_NULL)
244         TCU_FAIL("Invalid surface handle returned");
245 
246     return surface;
247 }
248 
initSemaphores(const DeviceInterface & vkd,VkDevice device,std::vector<VkSemaphore> & semaphores)249 void initSemaphores(const DeviceInterface &vkd, VkDevice device, std::vector<VkSemaphore> &semaphores)
250 {
251     for (VkSemaphore &semaphore : semaphores)
252         semaphore = createSemaphore(vkd, device).disown();
253 }
254 
deinitSemaphores(const DeviceInterface & vkd,VkDevice device,std::vector<VkSemaphore> & semaphores)255 void deinitSemaphores(const DeviceInterface &vkd, VkDevice device, std::vector<VkSemaphore> &semaphores)
256 {
257     for (VkSemaphore &semaphore : semaphores)
258     {
259         if (semaphore == (VkSemaphore)0)
260             continue;
261 
262         vkd.destroySemaphore(device, semaphore, DE_NULL);
263         semaphore = (VkSemaphore)0;
264     }
265 
266     semaphores.clear();
267 }
268 
initFences(const DeviceInterface & vkd,VkDevice device,std::vector<VkFence> & fences)269 void initFences(const DeviceInterface &vkd, VkDevice device, std::vector<VkFence> &fences)
270 {
271     for (VkFence &fence : fences)
272         fence = createFence(vkd, device).disown();
273 }
274 
deinitFences(const DeviceInterface & vkd,VkDevice device,std::vector<VkFence> & fences)275 void deinitFences(const DeviceInterface &vkd, VkDevice device, std::vector<VkFence> &fences)
276 {
277     for (VkFence &fence : fences)
278     {
279         if (fence == (VkFence)0)
280             continue;
281 
282         vkd.destroyFence(device, fence, DE_NULL);
283         fence = (VkFence)0;
284     }
285 
286     fences.clear();
287 }
288 
createCommandBuffer(const DeviceInterface & vkd,VkDevice device,VkCommandPool commandPool,VkRenderPass renderPass,VkImage image,VkFramebuffer framebuffer,VkPipeline pipeline,uint32_t imageWidth,uint32_t imageHeight)289 Move<VkCommandBuffer> createCommandBuffer(const DeviceInterface &vkd, VkDevice device, VkCommandPool commandPool,
290                                           VkRenderPass renderPass, VkImage image, VkFramebuffer framebuffer,
291                                           VkPipeline pipeline, uint32_t imageWidth, uint32_t imageHeight)
292 {
293     const VkCommandBufferAllocateInfo allocateInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, DE_NULL,
294 
295                                                       commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
296 
297     VkImageMemoryBarrier imageBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,   // VkStructureType sType;
298                                          DE_NULL,                                  // const void* pNext;
299                                          0u,                                       // VkAccessFlags srcAccessMask;
300                                          VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,     // VkAccessFlags dstAccessMask;
301                                          VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout oldLayout;
302                                          VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout;
303                                          VK_QUEUE_FAMILY_IGNORED,                  // uint32_t srcQueueFamilyIndex;
304                                          VK_QUEUE_FAMILY_IGNORED,                  // uint32_t dstQueueFamilyIndex;
305                                          image,                                    // VkImage image;
306                                          {
307                                              // VkImageSubresourceRange subresourceRange;
308                                              VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
309                                              0u,                        // uint32_t baseMipLevel;
310                                              1u,                        // uint32_t mipLevels;
311                                              0u,                        // uint32_t baseArraySlice;
312                                              1u                         // uint32_t arraySize;
313                                          }};
314 
315     Move<VkCommandBuffer> commandBuffer(allocateCommandBuffer(vkd, device, &allocateInfo));
316     beginCommandBuffer(vkd, *commandBuffer, 0u);
317 
318     vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
319                            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0, 0,
320                            (const VkMemoryBarrier *)DE_NULL, 0, (const VkBufferMemoryBarrier *)DE_NULL, 1,
321                            &imageBarrier);
322 
323     beginRenderPass(vkd, *commandBuffer, renderPass, framebuffer, makeRect2D(0, 0, imageWidth, imageHeight),
324                     tcu::Vec4(0.25f, 0.5f, 0.75f, 1.0f));
325 
326     vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
327     vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u);
328 
329     endRenderPass(vkd, *commandBuffer);
330 
331     endCommandBuffer(vkd, *commandBuffer);
332     return commandBuffer;
333 }
334 
deinitCommandBuffers(const DeviceInterface & vkd,VkDevice device,VkCommandPool commandPool,std::vector<VkCommandBuffer> & commandBuffers)335 void deinitCommandBuffers(const DeviceInterface &vkd, VkDevice device, VkCommandPool commandPool,
336                           std::vector<VkCommandBuffer> &commandBuffers)
337 {
338     for (size_t ndx = 0; ndx < commandBuffers.size(); ndx++)
339     {
340         if (commandBuffers[ndx] != (VkCommandBuffer)0)
341             vkd.freeCommandBuffers(device, commandPool, 1u, &commandBuffers[ndx]);
342 
343         commandBuffers[ndx] = (VkCommandBuffer)0;
344     }
345 
346     commandBuffers.clear();
347 }
348 
createCommandPool(const DeviceInterface & vkd,VkDevice device,uint32_t queueFamilyIndex)349 Move<VkCommandPool> createCommandPool(const DeviceInterface &vkd, VkDevice device, uint32_t queueFamilyIndex)
350 {
351     const VkCommandPoolCreateInfo createInfo = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, DE_NULL, 0u,
352                                                 queueFamilyIndex};
353 
354     return createCommandPool(vkd, device, &createInfo);
355 }
356 
initFramebuffers(const DeviceInterface & vkd,VkDevice device,VkRenderPass renderPass,std::vector<VkImageView> imageViews,uint32_t width,uint32_t height,std::vector<VkFramebuffer> & framebuffers)357 void initFramebuffers(const DeviceInterface &vkd, VkDevice device, VkRenderPass renderPass,
358                       std::vector<VkImageView> imageViews, uint32_t width, uint32_t height,
359                       std::vector<VkFramebuffer> &framebuffers)
360 {
361     DE_ASSERT(framebuffers.size() == imageViews.size());
362 
363     for (size_t ndx = 0; ndx < framebuffers.size(); ndx++)
364     {
365         const VkFramebufferCreateInfo createInfo = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
366                                                     DE_NULL,
367 
368                                                     0u,
369                                                     renderPass,
370                                                     1u,
371                                                     &imageViews[ndx],
372                                                     width,
373                                                     height,
374                                                     1u};
375 
376         framebuffers[ndx] = createFramebuffer(vkd, device, &createInfo).disown();
377     }
378 }
379 
deinitFramebuffers(const DeviceInterface & vkd,VkDevice device,std::vector<VkFramebuffer> & framebuffers)380 void deinitFramebuffers(const DeviceInterface &vkd, VkDevice device, std::vector<VkFramebuffer> &framebuffers)
381 {
382     for (size_t ndx = 0; ndx < framebuffers.size(); ndx++)
383     {
384         if (framebuffers[ndx] != (VkFramebuffer)0)
385             vkd.destroyFramebuffer(device, framebuffers[ndx], DE_NULL);
386 
387         framebuffers[ndx] = (VkFramebuffer)0;
388     }
389 
390     framebuffers.clear();
391 }
392 
createImageView(const DeviceInterface & vkd,VkDevice device,VkImage image,VkFormat format)393 Move<VkImageView> createImageView(const DeviceInterface &vkd, VkDevice device, VkImage image, VkFormat format)
394 {
395     const VkImageViewCreateInfo createInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
396                                               DE_NULL,
397 
398                                               0u,
399                                               image,
400                                               VK_IMAGE_VIEW_TYPE_2D,
401                                               format,
402                                               makeComponentMappingRGBA(),
403                                               {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}};
404 
405     return createImageView(vkd, device, &createInfo, DE_NULL);
406 }
407 
initImageViews(const DeviceInterface & vkd,VkDevice device,const std::vector<VkImage> & images,VkFormat format,std::vector<VkImageView> & imageViews)408 void initImageViews(const DeviceInterface &vkd, VkDevice device, const std::vector<VkImage> &images, VkFormat format,
409                     std::vector<VkImageView> &imageViews)
410 {
411     DE_ASSERT(images.size() == imageViews.size());
412 
413     for (size_t ndx = 0; ndx < imageViews.size(); ndx++)
414         imageViews[ndx] = createImageView(vkd, device, images[ndx], format).disown();
415 }
416 
deinitImageViews(const DeviceInterface & vkd,VkDevice device,std::vector<VkImageView> & imageViews)417 void deinitImageViews(const DeviceInterface &vkd, VkDevice device, std::vector<VkImageView> &imageViews)
418 {
419     for (size_t ndx = 0; ndx < imageViews.size(); ndx++)
420     {
421         if (imageViews[ndx] != (VkImageView)0)
422             vkd.destroyImageView(device, imageViews[ndx], DE_NULL);
423 
424         imageViews[ndx] = (VkImageView)0;
425     }
426 
427     imageViews.clear();
428 }
429 
createPipeline(const DeviceInterface & vkd,VkDevice device,VkRenderPass renderPass,VkPipelineLayout layout,VkShaderModule vertexShaderModule,VkShaderModule fragmentShaderModule,uint32_t width,uint32_t height)430 Move<VkPipeline> createPipeline(const DeviceInterface &vkd, VkDevice device, VkRenderPass renderPass,
431                                 VkPipelineLayout layout, VkShaderModule vertexShaderModule,
432                                 VkShaderModule fragmentShaderModule, uint32_t width, uint32_t height)
433 {
434     const VkPipelineVertexInputStateCreateInfo vertexInputState = {
435         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, DE_NULL, 0u, 0u, DE_NULL, 0u, DE_NULL};
436     const std::vector<VkViewport> viewports(1, makeViewport(tcu::UVec2(width, height)));
437     const std::vector<VkRect2D> scissors(1, makeRect2D(tcu::UVec2(width, height)));
438 
439     return makeGraphicsPipeline(
440         vkd,                  // const DeviceInterface&                        vk
441         device,               // const VkDevice                                device
442         layout,               // const VkPipelineLayout                        pipelineLayout
443         vertexShaderModule,   // const VkShaderModule                          vertexShaderModule
444         DE_NULL,              // const VkShaderModule                          tessellationControlShaderModule
445         DE_NULL,              // const VkShaderModule                          tessellationEvalShaderModule
446         DE_NULL,              // const VkShaderModule                          geometryShaderModule
447         fragmentShaderModule, // const VkShaderModule                          fragmentShaderModule
448         renderPass,           // const VkRenderPass                            renderPass
449         viewports,            // const std::vector<VkViewport>&                viewports
450         scissors,             // const std::vector<VkRect2D>&                  scissors
451         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology                     topology
452         0u,                                  // const uint32_t                                subpass
453         0u,                                  // const uint32_t                                patchControlPoints
454         &vertexInputState);                  // const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
455 }
456 
createPipelineLayout(const DeviceInterface & vkd,VkDevice device)457 Move<VkPipelineLayout> createPipelineLayout(const DeviceInterface &vkd, VkDevice device)
458 {
459     const VkPipelineLayoutCreateInfo createInfo = {
460         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, DE_NULL, 0u, 0u, DE_NULL, 0u, DE_NULL,
461     };
462 
463     return createPipelineLayout(vkd, device, &createInfo);
464 }
465 
createSwapchainCounterConfig()466 VkSwapchainCounterCreateInfoEXT createSwapchainCounterConfig()
467 {
468     const VkSwapchainCounterCreateInfoEXT swapchainCounterConfig = {VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT,
469                                                                     DE_NULL, VK_SURFACE_COUNTER_VBLANK_EXT};
470     return swapchainCounterConfig;
471 }
472 
createSwapchainConfig(VkSurfaceKHR surface,uint32_t queueFamilyIndex,const VkSurfaceCapabilities2EXT & properties,const vector<VkSurfaceFormatKHR> & formats,const vector<VkPresentModeKHR> & presentModes,VkPresentModeKHR presentMode,VkSwapchainCounterCreateInfoEXT * swapchainCounterInfo)473 VkSwapchainCreateInfoKHR createSwapchainConfig(VkSurfaceKHR surface, uint32_t queueFamilyIndex,
474                                                const VkSurfaceCapabilities2EXT &properties,
475                                                const vector<VkSurfaceFormatKHR> &formats,
476                                                const vector<VkPresentModeKHR> &presentModes,
477                                                VkPresentModeKHR presentMode,
478                                                VkSwapchainCounterCreateInfoEXT *swapchainCounterInfo)
479 {
480     if ((properties.supportedSurfaceCounters & VK_SURFACE_COUNTER_VBLANK_EXT) == 0)
481         TCU_THROW(NotSupportedError, "vblank counter not supported");
482 
483     const uint32_t imageLayers         = 1u;
484     const VkImageUsageFlags imageUsage = properties.supportedUsageFlags;
485     const VkBool32 clipped             = VK_FALSE;
486 
487     const uint32_t imageWidth =
488         (properties.currentExtent.width != 0xFFFFFFFFu) ?
489             properties.currentExtent.width :
490             de::min(1024u, properties.minImageExtent.width +
491                                ((properties.maxImageExtent.width - properties.minImageExtent.width) / 2));
492     const uint32_t imageHeight =
493         (properties.currentExtent.height != 0xFFFFFFFFu) ?
494             properties.currentExtent.height :
495             de::min(1024u, properties.minImageExtent.height +
496                                ((properties.maxImageExtent.height - properties.minImageExtent.height) / 2));
497     const VkExtent2D imageSize = {imageWidth, imageHeight};
498 
499     if (std::find(presentModes.begin(), presentModes.end(), presentMode) == presentModes.end())
500         TCU_THROW(NotSupportedError, "Present mode not supported");
501 
502     // Pick the first supported transform, alpha, and format:
503     VkSurfaceTransformFlagsKHR transform;
504     for (transform = 1u; transform <= properties.supportedTransforms; transform = transform << 1u)
505     {
506         if ((properties.supportedTransforms & transform) != 0)
507             break;
508     }
509 
510     VkCompositeAlphaFlagsKHR alpha;
511     for (alpha = 1u; alpha <= properties.supportedCompositeAlpha; alpha = alpha << 1u)
512     {
513         if ((alpha & properties.supportedCompositeAlpha) != 0)
514             break;
515     }
516 
517     {
518         const VkSurfaceTransformFlagBitsKHR preTransform = (VkSurfaceTransformFlagBitsKHR)transform;
519         const VkCompositeAlphaFlagBitsKHR compositeAlpha = (VkCompositeAlphaFlagBitsKHR)alpha;
520         const VkFormat imageFormat                       = formats[0].format;
521         const VkColorSpaceKHR imageColorSpace            = formats[0].colorSpace;
522         const VkSwapchainCreateInfoKHR createInfo        = {VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
523                                                             swapchainCounterInfo,
524                                                             0u,
525                                                             surface,
526                                                             properties.minImageCount,
527                                                             imageFormat,
528                                                             imageColorSpace,
529                                                             imageSize,
530                                                             imageLayers,
531                                                             imageUsage,
532                                                             VK_SHARING_MODE_EXCLUSIVE,
533                                                             1u,
534                                                             &queueFamilyIndex,
535                                                             preTransform,
536                                                             compositeAlpha,
537                                                             presentMode,
538                                                             clipped,
539                                                             (VkSwapchainKHR)0};
540 
541         return createInfo;
542     }
543 }
544 
545 class SwapchainCounterTestInstance : public TestInstance
546 {
547 public:
548     SwapchainCounterTestInstance(Context &context);
549     ~SwapchainCounterTestInstance(void);
550 
551     tcu::TestStatus iterate(void);
552 
553 private:
554     void initSwapchainResources(void);
555     void deinitSwapchainResources(void);
556     void render(void);
557 
558 private:
559     const PlatformInterface &m_vkp;
560     const CustomInstance m_instance;
561     const InstanceDriver &m_vki;
562     const VkPhysicalDevice m_physicalDevice;
563     uint32_t m_planeIndex;
564     const VkDisplayKHR m_display;
565     const VkSurfaceKHR m_surface;
566 
567     const uint32_t m_queueFamilyIndex;
568     const Unique<VkDevice> m_device;
569     const DeviceDriver m_vkd;
570     const VkQueue m_queue;
571 
572     const Unique<VkCommandPool> m_commandPool;
573     const Unique<VkShaderModule> m_vertexShaderModule;
574     const Unique<VkShaderModule> m_fragmentShaderModule;
575     const Unique<VkPipelineLayout> m_pipelineLayout;
576 
577     const VkSurfaceCapabilities2EXT m_surfaceProperties;
578     const vector<VkSurfaceFormatKHR> m_surfaceFormats;
579     const vector<VkPresentModeKHR> m_presentModes;
580 
581     tcu::ResultCollector m_resultCollector;
582 
583     Move<VkSwapchainKHR> m_swapchain;
584     std::vector<VkImage> m_swapchainImages;
585 
586     Move<VkRenderPass> m_renderPass;
587     Move<VkPipeline> m_pipeline;
588 
589     std::vector<VkImageView> m_swapchainImageViews;
590     std::vector<VkFramebuffer> m_framebuffers;
591     std::vector<VkCommandBuffer> m_commandBuffers;
592     std::vector<VkSemaphore> m_acquireSemaphores;
593     std::vector<VkSemaphore> m_renderSemaphores;
594     std::vector<VkFence> m_fences;
595 
596     VkSwapchainCounterCreateInfoEXT m_swapchainCounterConfig;
597     VkSwapchainCreateInfoKHR m_swapchainConfig;
598 
599     const size_t m_frameCount;
600     size_t m_frameNdx;
601 
602     const size_t m_maxOutOfDateCount;
603     size_t m_outOfDateCount;
604 };
605 
SwapchainCounterTestInstance(Context & context)606 SwapchainCounterTestInstance::SwapchainCounterTestInstance(Context &context)
607     : TestInstance(context)
608     , m_vkp(context.getPlatformInterface())
609     , m_instance(createInstance(context))
610     , m_vki(m_instance.getDriver())
611     , m_physicalDevice(chooseDevice(m_vki, m_instance, context.getTestContext().getCommandLine()))
612     , m_planeIndex(0)
613     , m_display(getDisplayAndDisplayPlane(m_vki, m_physicalDevice, &m_planeIndex))
614     , m_surface(createSurface(m_vki, m_instance, m_physicalDevice, m_display, m_planeIndex))
615 
616     , m_queueFamilyIndex(chooseQueueFamilyIndex(m_vki, m_physicalDevice, m_surface))
617     , m_device(createTestDevice(context, m_vkp, m_instance, m_vki, m_physicalDevice, m_queueFamilyIndex))
618     , m_vkd(m_vkp, m_instance, *m_device, context.getUsedApiVersion(), context.getTestContext().getCommandLine())
619     , m_queue(getDeviceQueue(m_vkd, *m_device, m_queueFamilyIndex, 0u))
620 
621     , m_commandPool(createCommandPool(m_vkd, *m_device, m_queueFamilyIndex))
622     , m_vertexShaderModule(createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-vert"), 0u))
623     , m_fragmentShaderModule(createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-frag"), 0u))
624     , m_pipelineLayout(createPipelineLayout(m_vkd, *m_device))
625 
626     , m_surfaceProperties(wsi::getPhysicalDeviceSurfaceCapabilities2EXT(m_vki, m_physicalDevice, m_surface))
627     , m_surfaceFormats(wsi::getPhysicalDeviceSurfaceFormats(m_vki, m_physicalDevice, m_surface))
628     , m_presentModes(wsi::getPhysicalDeviceSurfacePresentModes(m_vki, m_physicalDevice, m_surface))
629 
630     , m_swapchainCounterConfig(createSwapchainCounterConfig())
631     , m_swapchainConfig(createSwapchainConfig(m_surface, m_queueFamilyIndex, m_surfaceProperties, m_surfaceFormats,
632                                               m_presentModes, VK_PRESENT_MODE_FIFO_KHR, &m_swapchainCounterConfig))
633 
634     , m_frameCount(20u)
635     , m_frameNdx(0u)
636 
637     , m_maxOutOfDateCount(10u)
638     , m_outOfDateCount(0u)
639 {
640 }
641 
~SwapchainCounterTestInstance(void)642 SwapchainCounterTestInstance::~SwapchainCounterTestInstance(void)
643 {
644     deinitSwapchainResources();
645 
646     m_vki.destroySurfaceKHR(m_instance, m_surface, DE_NULL);
647 }
648 
initSwapchainResources(void)649 void SwapchainCounterTestInstance::initSwapchainResources(void)
650 {
651     const uint32_t imageWidth  = m_swapchainConfig.imageExtent.width;
652     const uint32_t imageHeight = m_swapchainConfig.imageExtent.height;
653     const VkFormat imageFormat = m_swapchainConfig.imageFormat;
654 
655     m_swapchain       = createSwapchainKHR(m_vkd, *m_device, &m_swapchainConfig);
656     m_swapchainImages = wsi::getSwapchainImages(m_vkd, *m_device, *m_swapchain);
657 
658     m_renderPass = makeRenderPass(m_vkd, *m_device, imageFormat, VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD,
659                                   VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
660     m_pipeline   = createPipeline(m_vkd, *m_device, *m_renderPass, *m_pipelineLayout, *m_vertexShaderModule,
661                                   *m_fragmentShaderModule, imageWidth, imageHeight);
662 
663     const size_t swapchainImagesCount = m_swapchainImages.size();
664     const size_t fenceCount           = swapchainImagesCount * 2;
665 
666     m_swapchainImageViews = std::vector<VkImageView>(swapchainImagesCount, (VkImageView)0);
667     m_framebuffers        = std::vector<VkFramebuffer>(swapchainImagesCount, (VkFramebuffer)0);
668     m_acquireSemaphores   = std::vector<VkSemaphore>(swapchainImagesCount + 1, (VkSemaphore)0);
669     m_renderSemaphores    = std::vector<VkSemaphore>(swapchainImagesCount + 1, (VkSemaphore)0);
670 
671     m_fences         = std::vector<VkFence>(fenceCount, (VkFence)0);
672     m_commandBuffers = std::vector<VkCommandBuffer>(fenceCount, (VkCommandBuffer)0);
673 
674     initImageViews(m_vkd, *m_device, m_swapchainImages, imageFormat, m_swapchainImageViews);
675     initFramebuffers(m_vkd, *m_device, *m_renderPass, m_swapchainImageViews, imageWidth, imageHeight, m_framebuffers);
676     initSemaphores(m_vkd, *m_device, m_acquireSemaphores);
677     initSemaphores(m_vkd, *m_device, m_renderSemaphores);
678 
679     initFences(m_vkd, *m_device, m_fences);
680 }
681 
deinitSwapchainResources(void)682 void SwapchainCounterTestInstance::deinitSwapchainResources(void)
683 {
684     VK_CHECK(m_vkd.queueWaitIdle(m_queue));
685 
686     deinitSemaphores(m_vkd, *m_device, m_acquireSemaphores);
687     deinitSemaphores(m_vkd, *m_device, m_renderSemaphores);
688     deinitFences(m_vkd, *m_device, m_fences);
689     deinitCommandBuffers(m_vkd, *m_device, *m_commandPool, m_commandBuffers);
690     deinitFramebuffers(m_vkd, *m_device, m_framebuffers);
691     deinitImageViews(m_vkd, *m_device, m_swapchainImageViews);
692 
693     m_swapchainImages.clear();
694 
695     m_swapchain  = Move<VkSwapchainKHR>();
696     m_renderPass = Move<VkRenderPass>();
697     m_pipeline   = Move<VkPipeline>();
698 }
699 
render(void)700 void SwapchainCounterTestInstance::render(void)
701 {
702     const uint64_t foreverNs       = ~0x0ull;
703     VkCommandBuffer &commandBuffer = m_commandBuffers[m_frameNdx % m_commandBuffers.size()];
704     const VkFence fence            = m_fences[m_frameNdx % m_fences.size()];
705     const uint32_t width           = m_swapchainConfig.imageExtent.width;
706     const uint32_t height          = m_swapchainConfig.imageExtent.height;
707 
708     if (m_frameNdx >= m_fences.size())
709         VK_CHECK(m_vkd.waitForFences(*m_device, 1u, &fence, VK_TRUE, foreverNs));
710     VK_CHECK(m_vkd.resetFences(*m_device, 1u, &fence));
711 
712     VkSemaphore currentAcquireSemaphore = m_acquireSemaphores[m_frameNdx % m_acquireSemaphores.size()];
713     VkSemaphore currentRenderSemaphore  = m_renderSemaphores[m_frameNdx % m_renderSemaphores.size()];
714 
715     // Acquire next image
716     uint32_t imageIndex;
717     VK_CHECK(m_vkd.acquireNextImageKHR(*m_device, *m_swapchain, foreverNs, currentAcquireSemaphore, (VkFence)0,
718                                        &imageIndex));
719 
720     // Create command buffer
721     commandBuffer = createCommandBuffer(m_vkd, *m_device, *m_commandPool, *m_renderPass, m_swapchainImages[imageIndex],
722                                         m_framebuffers[imageIndex], *m_pipeline, width, height)
723                         .disown();
724 
725     // Submit command buffer
726     {
727         const VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
728         const VkSubmitInfo submitInfo           = {
729             VK_STRUCTURE_TYPE_SUBMIT_INFO, DE_NULL, 1u, &currentAcquireSemaphore, &dstStageMask, 1u, &commandBuffer, 1u,
730             &currentRenderSemaphore};
731 
732         VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, fence));
733     }
734 
735     VkResult result;
736     const VkPresentInfoKHR presentInfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
737                                           DE_NULL,
738                                           1u,
739                                           &currentRenderSemaphore,
740                                           1u,
741                                           &*m_swapchain,
742                                           &imageIndex,
743                                           &result};
744 
745     VK_CHECK_WSI(m_vkd.queuePresentKHR(m_queue, &presentInfo));
746     VK_CHECK_WSI(result);
747 
748     // verify counter on last frame - we know that we must have presented as meny frames
749     // as we rendered minus the number of images in swapchain - that may not have been presented yet
750     if (m_frameNdx >= m_frameCount)
751     {
752         uint64_t counter = 0;
753         m_vkd.getSwapchainCounterEXT(*m_device, *m_swapchain, VK_SURFACE_COUNTER_VBLANK_EXT, &counter);
754         if ((counter < (m_frameCount - m_swapchainImages.size())) || (counter > m_frameCount))
755         {
756             deinitSwapchainResources();
757             m_resultCollector.fail("Invalid surface counter value");
758         }
759     }
760 }
761 
iterate(void)762 tcu::TestStatus SwapchainCounterTestInstance::iterate(void)
763 {
764     try
765     {
766         // Initialize swapchain specific resources
767         if (m_frameNdx == 0)
768             initSwapchainResources();
769 
770         // Render frame
771         render();
772     }
773     catch (const Error &error)
774     {
775         if (error.getError() == VK_ERROR_OUT_OF_DATE_KHR)
776         {
777             if (m_outOfDateCount < m_maxOutOfDateCount)
778             {
779                 m_context.getTestContext().getLog()
780                     << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date. Recreating resources."
781                     << TestLog::EndMessage;
782                 deinitSwapchainResources();
783                 m_outOfDateCount++;
784                 m_frameNdx = 0;
785 
786                 return tcu::TestStatus::incomplete();
787             }
788 
789             m_context.getTestContext().getLog()
790                 << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date." << TestLog::EndMessage;
791             return tcu::TestStatus::fail("Received too many VK_ERROR_OUT_OF_DATE_KHR errors.");
792         }
793 
794         deinitSwapchainResources();
795         return tcu::TestStatus::fail(error.what());
796     }
797 
798     m_frameNdx++;
799     if (m_frameNdx < m_frameCount)
800         return tcu::TestStatus::incomplete();
801 
802     deinitSwapchainResources();
803     return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
804 }
805 
806 class SwapchainCounterTestCase : public TestCase
807 {
808 public:
809     SwapchainCounterTestCase(tcu::TestContext &context, const char *name);
810     ~SwapchainCounterTestCase() = default;
811 
812     void initPrograms(SourceCollections &programCollection) const;
813     virtual TestInstance *createInstance(Context &context) const;
814     virtual void checkSupport(Context &context) const;
815 };
816 
SwapchainCounterTestCase(tcu::TestContext & context,const char * name)817 SwapchainCounterTestCase::SwapchainCounterTestCase(tcu::TestContext &context, const char *name)
818     : vkt::TestCase(context, name)
819 {
820 }
821 
initPrograms(SourceCollections & dst) const822 void SwapchainCounterTestCase::initPrograms(SourceCollections &dst) const
823 {
824     dst.glslSources.add("quad-vert") << glu::VertexSource(
825         "#version 450\n"
826         "out gl_PerVertex {\n"
827         "    vec4 gl_Position;\n"
828         "};\n"
829         "highp float;\n"
830         "void main (void) {\n"
831         "    gl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
832         "                       ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
833         "}\n");
834     dst.glslSources.add("quad-frag") << glu::FragmentSource("#version 450\n"
835                                                             "layout(location = 0) out highp vec4 o_color;\n"
836                                                             "void main (void)\n"
837                                                             "{\n"
838                                                             "    o_color = vec4(1.0, 0.5, 0.0, 1.0);\n"
839                                                             "}\n");
840 }
841 
createInstance(Context & context) const842 TestInstance *SwapchainCounterTestCase::createInstance(Context &context) const
843 {
844     return new SwapchainCounterTestInstance(context);
845 }
846 
checkSupport(Context & context) const847 void SwapchainCounterTestCase::checkSupport(Context &context) const
848 {
849     context.requireInstanceFunctionality("VK_KHR_display");
850     context.requireDeviceFunctionality("VK_EXT_display_control");
851 }
852 
getDisplays(Context & context,std::vector<VkDisplayKHR> & availableDisplays)853 void getDisplays(Context &context, std::vector<VkDisplayKHR> &availableDisplays)
854 {
855     // get number of displays
856     uint32_t countReported          = 0u;
857     VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
858     const InstanceInterface &vki    = context.getInstanceInterface();
859     const vk::Platform &platform    = context.getTestContext().getPlatform().getVulkanPlatform();
860 
861     VkResult result = vki.getPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &countReported, DE_NULL);
862     if (result != VK_SUCCESS)
863         TCU_THROW(NotSupportedError, "vkGetPhysicalDeviceDisplayPropertiesKHR failed");
864 
865     if (countReported == 0)
866         TCU_THROW(NotSupportedError, "No displays available");
867 
868     for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
869     {
870         vk::wsi::Type wsiType = (vk::wsi::Type)typeNdx;
871         if (platform.hasDisplay(wsiType))
872         {
873             TCU_THROW(NotSupportedError, "Display is unavailable as windowing system has access");
874         }
875     }
876 
877     // get display properties
878     std::vector<VkDisplayPropertiesKHR> displaysProperties(countReported);
879     result = vki.getPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &countReported, &displaysProperties[0]);
880 
881     if (result != VK_SUCCESS)
882         TCU_THROW(NotSupportedError, "vkGetPhysicalDeviceDisplayPropertiesKHR failed");
883 
884     availableDisplays.clear();
885     for (const auto &dp : displaysProperties)
886         availableDisplays.push_back(dp.display);
887 }
888 
testDisplayPowerControl(Context & context)889 tcu::TestStatus testDisplayPowerControl(Context &context)
890 {
891     // make sure VK_EXT_display_control is available
892     context.requireDeviceFunctionality("VK_EXT_display_control");
893 
894     // get all connected displays
895     std::vector<VkDisplayKHR> availableDisplays;
896     getDisplays(context, availableDisplays);
897 
898     struct PowerStateData
899     {
900         VkDisplayPowerStateEXT state;
901         uint32_t waitMs;
902     };
903     vector<PowerStateData> powerStateDataVect = {
904         {VK_DISPLAY_POWER_STATE_ON_EXT, 1000},
905         {VK_DISPLAY_POWER_STATE_SUSPEND_EXT, 1000},
906         {VK_DISPLAY_POWER_STATE_OFF_EXT, 1000},
907         {VK_DISPLAY_POWER_STATE_ON_EXT, 1000},
908     };
909 
910     // iterate over all displays
911     VkDevice device                = context.getDevice();
912     const vk::DeviceInterface &vkd = context.getDeviceInterface();
913     for (const auto &display : availableDisplays)
914     {
915         // iterate over tested sequence of power states
916         for (const auto &psd : powerStateDataVect)
917         {
918             VkDisplayPowerInfoEXT displayPowerInfo = {VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT, DE_NULL, psd.state};
919 
920             VkResult result = vkd.displayPowerControlEXT(device, display, &displayPowerInfo);
921             if (result != VK_SUCCESS)
922                 return tcu::TestStatus::fail(std::string("vkDisplayPowerControlEXT returned invalid result for ") +
923                                              de::toString(psd.state));
924 
925             deSleep(psd.waitMs);
926         }
927     }
928 
929     return tcu::TestStatus::pass("pass");
930 }
931 
testDisplayEvent(Context & context)932 tcu::TestStatus testDisplayEvent(Context &context)
933 {
934     // make sure VK_EXT_display_control is available
935     context.requireDeviceFunctionality("VK_EXT_display_control");
936 
937     // get all connected displays
938     std::vector<vk::VkDisplayKHR> availableDisplays;
939     getDisplays(context, availableDisplays);
940 
941     VkDevice device             = context.getDevice();
942     const DeviceInterface &vkd  = context.getDeviceInterface();
943     std::vector<VkFence> fences = std::vector<VkFence>(availableDisplays.size(), (VkFence)0);
944 
945     // iterate over all displays
946     for (size_t i = 0; i < availableDisplays.size(); ++i)
947     {
948         VkDisplayEventInfoEXT displayEventInfo = {VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT, DE_NULL,
949                                                   VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT};
950 
951         VkFence &fence        = fences[i];
952         VkDisplayKHR &display = availableDisplays[i];
953         VkResult result       = vkd.registerDisplayEventEXT(device, display, &displayEventInfo, DE_NULL, &fence);
954         if (result != VK_SUCCESS)
955             return tcu::TestStatus::fail(std::string("vkRegisterDisplayEventEXT returned invalid result"));
956     }
957 
958     // deinit fence
959     deinitFences(vkd, device, fences);
960 
961     return tcu::TestStatus::pass("pass");
962 }
963 
testDeviceEvent(Context & context)964 tcu::TestStatus testDeviceEvent(Context &context)
965 {
966     // make sure VK_EXT_display_control is available
967     context.requireDeviceFunctionality("VK_EXT_display_control");
968 
969     VkDevice device             = context.getDevice();
970     const DeviceInterface &vkd  = context.getDeviceInterface();
971     std::vector<VkFence> fences = std::vector<VkFence>(1, (VkFence)0);
972 
973     vk::VkDeviceEventInfoEXT deviceEventInfo = {VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT, DE_NULL,
974                                                 VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT};
975 
976     VkResult result = vkd.registerDeviceEventEXT(device, &deviceEventInfo, DE_NULL, &fences[0]);
977     if (result != VK_SUCCESS)
978         return tcu::TestStatus::fail(std::string("vkRegisterDeviceEventEXT returned invalid result"));
979 
980     // deinit fence
981     deinitFences(vkd, device, fences);
982 
983     return tcu::TestStatus::pass("pass");
984 }
985 
986 } // namespace
987 
createDisplayControlTests(tcu::TestCaseGroup * testGroup)988 void createDisplayControlTests(tcu::TestCaseGroup *testGroup)
989 {
990     testGroup->addChild(new SwapchainCounterTestCase(testGroup->getTestContext(), "swapchain_counter"));
991     addFunctionCase(testGroup, "display_power_control", testDisplayPowerControl);
992     addFunctionCase(testGroup, "register_display_event", testDisplayEvent);
993     addFunctionCase(testGroup, "register_device_event", testDeviceEvent);
994 }
995 
996 } // namespace wsi
997 } // namespace vkt
998