xref: /aosp_15_r20/external/deqp/external/vulkancts/framework/vulkan/vkWsiUtil.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * Vulkan CTS Framework
3  * --------------------
4  *
5  * Copyright (c) 2016 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Windowing System Integration (WSI) Utilities.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vkDeviceUtil.hpp"
25 #include "vkRefUtil.hpp"
26 #include "vkTypeUtil.hpp"
27 #include "vkObjUtil.hpp"
28 #include "vkCmdUtil.hpp"
29 #include "vkQueryUtil.hpp"
30 #include "vkWsiUtil.hpp"
31 #include "vkBarrierUtil.hpp"
32 
33 #include "deArrayUtil.hpp"
34 #include "deMemory.h"
35 
36 #include <limits>
37 #include <vector>
38 
39 using std::vector;
40 
41 #if defined(DEQP_SUPPORT_X11)
42 #include <X11/Xlib.h>
43 #if defined(DEQP_SUPPORT_XCB)
44 #include <xcb/xcb.h>
45 #endif // DEQP_SUPPORT_XCB
46 #endif // DEQP_SUPPORT_X11
47 
48 #if defined(DEQP_SUPPORT_WAYLAND)
49 #include "tcuLnxWayland.hpp"
50 #define WAYLAND_DISPLAY DE_NULL
51 #endif // DEQP_SUPPORT_WAYLAND
52 
53 #if (DE_OS == DE_OS_WIN32)
54 #define NOMINMAX
55 #define WIN32_LEAN_AND_MEAN
56 #include <windows.h>
57 #endif
58 
59 namespace vk
60 {
61 namespace wsi
62 {
63 
64 //! Get canonical WSI name that should be used for example in test case and group names.
getName(Type wsiType)65 const char *getName(Type wsiType)
66 {
67     static const char *const s_names[] = {
68         "xlib", "xcb", "wayland", "android", "win32", "macos", "headless", "direct_drm",
69     };
70     return de::getSizedArrayElement<TYPE_LAST>(s_names, wsiType);
71 }
72 
getExtensionName(Type wsiType)73 const char *getExtensionName(Type wsiType)
74 {
75     static const char *const s_extNames[] = {
76         "VK_KHR_xlib_surface",  "VK_KHR_xcb_surface",   "VK_KHR_wayland_surface",  "VK_KHR_android_surface",
77         "VK_KHR_win32_surface", "VK_MVK_macos_surface", "VK_EXT_headless_surface", "VK_EXT_acquire_drm_display",
78     };
79     return de::getSizedArrayElement<TYPE_LAST>(s_extNames, wsiType);
80 }
81 
getPlatformProperties(Type wsiType)82 const PlatformProperties &getPlatformProperties(Type wsiType)
83 {
84     // \note These are declared here (rather than queried through vk::Platform for example)
85     //         on purpose. The behavior of a platform is partly defined by the platform spec,
86     //         and partly by WSI extensions, and platform ports should not need to override
87     //         that definition.
88 
89     const uint32_t noDisplayLimit = std::numeric_limits<uint32_t>::max();
90     const uint32_t noWindowLimit  = std::numeric_limits<uint32_t>::max();
91 
92     static const PlatformProperties s_properties[] = {
93         // VK_KHR_xlib_surface
94         {
95             PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE | PlatformProperties::FEATURE_RESIZE_WINDOW,
96             PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
97             noDisplayLimit,
98             noWindowLimit,
99         },
100         // VK_KHR_xcb_surface
101         {
102             PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE | PlatformProperties::FEATURE_RESIZE_WINDOW,
103             PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
104             noDisplayLimit,
105             noWindowLimit,
106         },
107         // VK_KHR_wayland_surface
108         {
109             0u,
110             PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE,
111             noDisplayLimit,
112             noWindowLimit,
113         },
114         // VK_KHR_android_surface
115         {
116             PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE, PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE,
117             1u,
118             1u, // Only one window available
119         },
120         // VK_KHR_win32_surface
121         {
122             PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE | PlatformProperties::FEATURE_RESIZE_WINDOW,
123             PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
124             noDisplayLimit,
125             noWindowLimit,
126         },
127         // VK_MVK_macos_surface
128         {
129             PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE | PlatformProperties::FEATURE_RESIZE_WINDOW,
130             PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
131             noDisplayLimit,
132             noWindowLimit,
133         },
134         // VK_EXT_headless_surface
135         {
136             0u,
137             PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE,
138             noDisplayLimit,
139             noWindowLimit,
140         },
141         // VK_EXT_acquire_drm_display
142         {
143             0u,
144             PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
145             1u,
146             1u,
147         },
148     };
149 
150     return de::getSizedArrayElement<TYPE_LAST>(s_properties, wsiType);
151 }
152 
153 #ifndef CTS_USES_VULKANSC
createDisplaySurface(const InstanceInterface & vki,VkInstance instance,VkDisplayKHR display,const tcu::CommandLine & cmdLine,const VkAllocationCallbacks * pAllocator,VkSurfaceKHR * pSurface)154 static VkResult createDisplaySurface(const InstanceInterface &vki, VkInstance instance, VkDisplayKHR display,
155                                      const tcu::CommandLine &cmdLine, const VkAllocationCallbacks *pAllocator,
156                                      VkSurfaceKHR *pSurface)
157 {
158     VkPhysicalDevice physDevice = chooseDevice(vki, instance, cmdLine);
159 
160     vector<VkDisplayPlanePropertiesKHR> planeProperties;
161     uint32_t planeCount = 0u;
162     uint32_t planeIndex = 0u;
163     bool planeFound     = false;
164     VK_CHECK_SUPPORTED(vki.getPhysicalDeviceDisplayPlanePropertiesKHR(physDevice, &planeCount, DE_NULL));
165 
166     planeProperties.resize(planeCount);
167     VK_CHECK_SUPPORTED(vki.getPhysicalDeviceDisplayPlanePropertiesKHR(physDevice, &planeCount, &planeProperties[0]));
168 
169     for (uint32_t i = 0; i < planeCount; ++i)
170     {
171         vector<VkDisplayKHR> supportedDisplays;
172         uint32_t supportedDisplayCount = 0u;
173         VK_CHECK_SUPPORTED(vki.getDisplayPlaneSupportedDisplaysKHR(physDevice, i, &supportedDisplayCount, DE_NULL));
174 
175         supportedDisplays.resize(supportedDisplayCount);
176         VK_CHECK_SUPPORTED(
177             vki.getDisplayPlaneSupportedDisplaysKHR(physDevice, i, &supportedDisplayCount, &supportedDisplays[0]));
178 
179         for (uint32_t j = 0; j < supportedDisplayCount; ++j)
180         {
181             if (display == supportedDisplays[i])
182             {
183                 planeIndex = i;
184                 planeFound = true;
185                 break;
186             }
187         }
188 
189         if (planeFound)
190             break;
191     }
192     if (!planeFound)
193         TCU_THROW(NotSupportedError, "No supported displays for planes.");
194 
195     vector<VkDisplayModePropertiesKHR> displayModeProperties;
196     uint32_t displayModeCount = 0u;
197     VK_CHECK_SUPPORTED(vki.getDisplayModePropertiesKHR(physDevice, display, &displayModeCount, DE_NULL));
198     if (displayModeCount < 1)
199         TCU_THROW(NotSupportedError, "No display modes defined.");
200 
201     displayModeProperties.resize(displayModeCount);
202     VK_CHECK_SUPPORTED(
203         vki.getDisplayModePropertiesKHR(physDevice, display, &displayModeCount, &displayModeProperties[0]));
204 
205     const VkDisplaySurfaceCreateInfoKHR createInfo = {
206         VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR, // VkStructureType                    sType
207         DE_NULL,                                           // const void*                        pNext
208         0,                                                 // VkDisplaySurfaceCreateFlagsKHR    flags
209         displayModeProperties[0].displayMode,              // VkDisplayModeKHR                    displayMode
210         planeIndex,                                        // uint32_t                            planeIndex
211         planeProperties[planeIndex].currentStackIndex,     // uint32_t                            planeStackIndex
212         VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,             // VkSurfaceTransformFlagBitsKHR    transform
213         1.0f,                                              // float                            globalAlpha
214         VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR,             // VkDisplayPlaneAlphaFlagBitsKHR    alphaMode
215         displayModeProperties[0].parameters.visibleRegion, // VkExtent2D                        imageExtent
216     };
217 
218     return vki.createDisplayPlaneSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
219 }
220 #endif // CTS_USES_VULKANSC
221 
createSurface(const InstanceInterface & vki,VkInstance instance,Type wsiType,const Display & nativeDisplay,const Window & nativeWindow,const tcu::CommandLine & cmdLine,const VkAllocationCallbacks * pAllocator,VkSurfaceKHR * pSurface)222 VkResult createSurface(const InstanceInterface &vki, VkInstance instance, Type wsiType, const Display &nativeDisplay,
223                        const Window &nativeWindow, const tcu::CommandLine &cmdLine,
224                        const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface)
225 {
226     // Update this function if you add more WSI implementations
227     DE_STATIC_ASSERT(TYPE_LAST == 8);
228 
229 #ifdef CTS_USES_VULKANSC
230     DE_UNREF(vki);
231     DE_UNREF(instance);
232     DE_UNREF(wsiType);
233     DE_UNREF(nativeDisplay);
234     DE_UNREF(nativeWindow);
235     DE_UNREF(cmdLine);
236     DE_UNREF(pAllocator);
237     DE_UNREF(pSurface);
238 
239     TCU_THROW(NotSupportedError, "Vulkan SC does not support createSurface");
240 #else  // CTS_USES_VULKANSC
241     switch (wsiType)
242     {
243     case TYPE_XLIB:
244     {
245         const XlibDisplayInterface &xlibDisplay     = dynamic_cast<const XlibDisplayInterface &>(nativeDisplay);
246         const XlibWindowInterface &xlibWindow       = dynamic_cast<const XlibWindowInterface &>(nativeWindow);
247         const VkXlibSurfaceCreateInfoKHR createInfo = {VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, DE_NULL,
248                                                        (VkXlibSurfaceCreateFlagsKHR)0, xlibDisplay.getNative(),
249                                                        xlibWindow.getNative()};
250 
251         return vki.createXlibSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
252     }
253 
254     case TYPE_XCB:
255     {
256         const XcbDisplayInterface &xcbDisplay      = dynamic_cast<const XcbDisplayInterface &>(nativeDisplay);
257         const XcbWindowInterface &xcbWindow        = dynamic_cast<const XcbWindowInterface &>(nativeWindow);
258         const VkXcbSurfaceCreateInfoKHR createInfo = {VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, DE_NULL,
259                                                       (VkXcbSurfaceCreateFlagsKHR)0, xcbDisplay.getNative(),
260                                                       xcbWindow.getNative()};
261 
262         return vki.createXcbSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
263     }
264 
265     case TYPE_WAYLAND:
266     {
267         const WaylandDisplayInterface &waylandDisplay  = dynamic_cast<const WaylandDisplayInterface &>(nativeDisplay);
268         const WaylandWindowInterface &waylandWindow    = dynamic_cast<const WaylandWindowInterface &>(nativeWindow);
269         const VkWaylandSurfaceCreateInfoKHR createInfo = {VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, DE_NULL,
270                                                           (VkWaylandSurfaceCreateFlagsKHR)0, waylandDisplay.getNative(),
271                                                           waylandWindow.getNative()};
272 
273         return vki.createWaylandSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
274     }
275 
276     case TYPE_ANDROID:
277     {
278         const AndroidWindowInterface &androidWindow    = dynamic_cast<const AndroidWindowInterface &>(nativeWindow);
279         const VkAndroidSurfaceCreateInfoKHR createInfo = {VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, DE_NULL,
280                                                           (VkAndroidSurfaceCreateFlagsKHR)0, androidWindow.getNative()};
281 
282         return vki.createAndroidSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
283     }
284 
285     case TYPE_WIN32:
286     {
287         const Win32DisplayInterface &win32Display    = dynamic_cast<const Win32DisplayInterface &>(nativeDisplay);
288         const Win32WindowInterface &win32Window      = dynamic_cast<const Win32WindowInterface &>(nativeWindow);
289         const VkWin32SurfaceCreateInfoKHR createInfo = {VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, DE_NULL,
290                                                         (VkWin32SurfaceCreateFlagsKHR)0, win32Display.getNative(),
291                                                         win32Window.getNative()};
292 
293         return vki.createWin32SurfaceKHR(instance, &createInfo, pAllocator, pSurface);
294     }
295 
296     case TYPE_MACOS:
297     {
298         const MacOSWindowInterface &macOSWindow      = dynamic_cast<const MacOSWindowInterface &>(nativeWindow);
299         const VkMacOSSurfaceCreateInfoMVK createInfo = {VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, DE_NULL,
300                                                         (VkMacOSSurfaceCreateFlagsMVK)0, macOSWindow.getNative()};
301 
302         return vki.createMacOSSurfaceMVK(instance, &createInfo, pAllocator, pSurface);
303     }
304 
305     case TYPE_HEADLESS:
306     {
307         const VkHeadlessSurfaceCreateInfoEXT createInfo = {VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT, DE_NULL,
308                                                            (VkHeadlessSurfaceCreateFlagsEXT)0};
309 
310         return vki.createHeadlessSurfaceEXT(instance, &createInfo, pAllocator, pSurface);
311     }
312 
313     case TYPE_DIRECT_DRM:
314     {
315         DirectDrmDisplayInterface &drmDisplay =
316             dynamic_cast<DirectDrmDisplayInterface &>(const_cast<Display &>(nativeDisplay));
317         drmDisplay.initializeDisplay(vki, instance, cmdLine);
318         return createDisplaySurface(vki, instance, drmDisplay.getNative(), cmdLine, pAllocator, pSurface);
319     }
320 
321     default:
322         DE_FATAL("Unknown WSI type");
323         return VK_ERROR_SURFACE_LOST_KHR;
324     }
325 #endif // CTS_USES_VULKANSC
326     return VK_ERROR_SURFACE_LOST_KHR;
327 }
328 
createSurface(const InstanceInterface & vki,VkInstance instance,Type wsiType,const Display & nativeDisplay,const Window & nativeWindow,const tcu::CommandLine & cmdLine,const VkAllocationCallbacks * pAllocator)329 Move<VkSurfaceKHR> createSurface(const InstanceInterface &vki, VkInstance instance, Type wsiType,
330                                  const Display &nativeDisplay, const Window &nativeWindow,
331                                  const tcu::CommandLine &cmdLine, const VkAllocationCallbacks *pAllocator)
332 {
333     VkSurfaceKHR object = 0;
334     VK_CHECK(createSurface(vki, instance, wsiType, nativeDisplay, nativeWindow, cmdLine, pAllocator, &object));
335     return Move<VkSurfaceKHR>(check<VkSurfaceKHR>(object), Deleter<VkSurfaceKHR>(vki, instance, pAllocator));
336 }
337 
getPhysicalDeviceSurfaceSupport(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,uint32_t queueFamilyIndex,VkSurfaceKHR surface)338 VkBool32 getPhysicalDeviceSurfaceSupport(const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
339                                          uint32_t queueFamilyIndex, VkSurfaceKHR surface)
340 {
341     VkBool32 result = 0;
342 
343     VK_CHECK(vki.getPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, &result));
344 
345     return result;
346 }
347 
getPhysicalDevicePresentationSupport(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,uint32_t queueFamilyIndex,Type wsiType,const Display & nativeDisplay)348 VkBool32 getPhysicalDevicePresentationSupport(const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
349                                               uint32_t queueFamilyIndex, Type wsiType, const Display &nativeDisplay)
350 {
351 #ifdef CTS_USES_VULKANSC
352     DE_UNREF(vki);
353     DE_UNREF(physicalDevice);
354     DE_UNREF(queueFamilyIndex);
355     DE_UNREF(wsiType);
356     DE_UNREF(nativeDisplay);
357     TCU_THROW(NotSupportedError, "Vulkan SC does not support getPhysicalDevicePresentationSupport");
358 #else // CTS_USES_VULKANSC
359     switch (wsiType)
360     {
361     case TYPE_XLIB:
362     {
363         const XlibDisplayInterface &xlibDisplay = dynamic_cast<const XlibDisplayInterface &>(nativeDisplay);
364         pt::XlibVisualID visualID(0U);
365 #if defined(DEQP_SUPPORT_X11)
366         ::Display *displayPtr = (::Display *)(xlibDisplay.getNative().internal);
367         visualID.internal     = (uint32_t)(::XDefaultVisual(displayPtr, 0)->visualid);
368 #endif
369         return vki.getPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex,
370                                                                xlibDisplay.getNative(), visualID);
371     }
372     case TYPE_XCB:
373     {
374         const XcbDisplayInterface &xcbDisplay = dynamic_cast<const XcbDisplayInterface &>(nativeDisplay);
375         pt::XcbVisualid visualID(0U);
376 #if defined(DEQP_SUPPORT_XCB)
377         xcb_connection_t *connPtr = (xcb_connection_t *)(xcbDisplay.getNative().internal);
378         xcb_screen_t *screen      = xcb_setup_roots_iterator(xcb_get_setup(connPtr)).data;
379         visualID.internal         = (uint32_t)(screen->root_visual);
380 #endif
381         return vki.getPhysicalDeviceXcbPresentationSupportKHR(physicalDevice, queueFamilyIndex, xcbDisplay.getNative(),
382                                                               visualID);
383     }
384     case TYPE_WAYLAND:
385     {
386         const WaylandDisplayInterface &waylandDisplay = dynamic_cast<const WaylandDisplayInterface &>(nativeDisplay);
387         return vki.getPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex,
388                                                                   waylandDisplay.getNative());
389     }
390     case TYPE_WIN32:
391     {
392         return vki.getPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
393     }
394     case TYPE_HEADLESS:
395     case TYPE_ANDROID:
396     case TYPE_MACOS:
397     case TYPE_DIRECT_DRM:
398     {
399         return 1;
400     }
401     default:
402         DE_FATAL("Unknown WSI type");
403         return 0;
404     }
405 #endif // CTS_USES_VULKANSC
406     return 1;
407 }
408 
getPhysicalDeviceSurfaceCapabilities(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)409 VkSurfaceCapabilitiesKHR getPhysicalDeviceSurfaceCapabilities(const InstanceInterface &vki,
410                                                               VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
411 {
412     VkSurfaceCapabilitiesKHR capabilities;
413 
414     deMemset(&capabilities, 0, sizeof(capabilities));
415 
416     VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities));
417 
418     return capabilities;
419 }
420 
getPhysicalDeviceSurfaceCapabilities2EXT(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)421 VkSurfaceCapabilities2EXT getPhysicalDeviceSurfaceCapabilities2EXT(const InstanceInterface &vki,
422                                                                    VkPhysicalDevice physicalDevice,
423                                                                    VkSurfaceKHR surface)
424 {
425     VkSurfaceCapabilities2EXT capabilities;
426 
427     deMemset(&capabilities, 0, sizeof(capabilities));
428     capabilities.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT;
429 
430     VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2EXT(physicalDevice, surface, &capabilities));
431 
432     return capabilities;
433 }
434 
sameSurfaceCapabilities(const VkSurfaceCapabilitiesKHR & khr,const VkSurfaceCapabilities2EXT & ext)435 bool sameSurfaceCapabilities(const VkSurfaceCapabilitiesKHR &khr, const VkSurfaceCapabilities2EXT &ext)
436 {
437     return (
438         khr.minImageCount == ext.minImageCount && khr.maxImageCount == ext.maxImageCount &&
439         khr.currentExtent.width == ext.currentExtent.width && khr.currentExtent.height == ext.currentExtent.height &&
440         khr.minImageExtent.width == ext.minImageExtent.width &&
441         khr.minImageExtent.height == ext.minImageExtent.height &&
442         khr.maxImageExtent.width == ext.maxImageExtent.width &&
443         khr.maxImageExtent.height == ext.maxImageExtent.height && khr.maxImageArrayLayers == ext.maxImageArrayLayers &&
444         khr.supportedTransforms == ext.supportedTransforms && khr.currentTransform == ext.currentTransform &&
445         khr.supportedCompositeAlpha == ext.supportedCompositeAlpha &&
446         khr.supportedUsageFlags == ext.supportedUsageFlags);
447 }
448 
getPhysicalDeviceSurfaceFormats(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)449 std::vector<VkSurfaceFormatKHR> getPhysicalDeviceSurfaceFormats(const InstanceInterface &vki,
450                                                                 VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
451 {
452     uint32_t numFormats = 0;
453 
454     VK_CHECK(vki.getPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &numFormats, DE_NULL));
455 
456     if (numFormats > 0)
457     {
458         std::vector<VkSurfaceFormatKHR> formats(numFormats);
459 
460         VK_CHECK(vki.getPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &numFormats, &formats[0]));
461 
462         return formats;
463     }
464     else
465         return std::vector<VkSurfaceFormatKHR>();
466 }
467 
getPhysicalDeviceSurfacePresentModes(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)468 std::vector<VkPresentModeKHR> getPhysicalDeviceSurfacePresentModes(const InstanceInterface &vki,
469                                                                    VkPhysicalDevice physicalDevice,
470                                                                    VkSurfaceKHR surface)
471 {
472     uint32_t numModes = 0;
473 
474     VK_CHECK(vki.getPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numModes, DE_NULL));
475 
476     if (numModes > 0)
477     {
478         std::vector<VkPresentModeKHR> modes(numModes);
479 
480         VK_CHECK(vki.getPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numModes, &modes[0]));
481 
482         return modes;
483     }
484     else
485         return std::vector<VkPresentModeKHR>();
486 }
487 
getSwapchainImages(const DeviceInterface & vkd,VkDevice device,VkSwapchainKHR swapchain)488 std::vector<VkImage> getSwapchainImages(const DeviceInterface &vkd, VkDevice device, VkSwapchainKHR swapchain)
489 {
490     uint32_t numImages = 0;
491 
492     VK_CHECK(vkd.getSwapchainImagesKHR(device, swapchain, &numImages, DE_NULL));
493 
494     if (numImages > 0)
495     {
496         std::vector<VkImage> images(numImages);
497 
498         VK_CHECK(vkd.getSwapchainImagesKHR(device, swapchain, &numImages, &images[0]));
499 
500         return images;
501     }
502     else
503         return std::vector<VkImage>();
504 }
505 
506 namespace
507 {
508 
getSupportedQueueFamilyIndices(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)509 std::vector<uint32_t> getSupportedQueueFamilyIndices(const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
510                                                      VkSurfaceKHR surface)
511 {
512     uint32_t numTotalFamilyIndices;
513     vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numTotalFamilyIndices, DE_NULL);
514 
515     std::vector<VkQueueFamilyProperties> queueFamilyProperties(numTotalFamilyIndices);
516     vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numTotalFamilyIndices, &queueFamilyProperties[0]);
517 
518     std::vector<uint32_t> supportedFamilyIndices;
519     for (uint32_t queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
520     {
521         if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
522             supportedFamilyIndices.push_back(queueFamilyNdx);
523     }
524 
525     return supportedFamilyIndices;
526 }
527 
getSortedSupportedQueueFamilyIndices(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface)528 std::vector<uint32_t> getSortedSupportedQueueFamilyIndices(const vk::InstanceInterface &vki,
529                                                            vk::VkPhysicalDevice physicalDevice,
530                                                            vk::VkSurfaceKHR surface)
531 {
532     std::vector<uint32_t> indices = getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
533     std::sort(begin(indices), end(indices));
534     return indices;
535 }
536 
537 } // namespace
538 
chooseQueueFamilyIndex(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,const std::vector<vk::VkSurfaceKHR> & surfaces)539 uint32_t chooseQueueFamilyIndex(const vk::InstanceInterface &vki, vk::VkPhysicalDevice physicalDevice,
540                                 const std::vector<vk::VkSurfaceKHR> &surfaces)
541 {
542     auto indices = getCompatibleQueueFamilyIndices(vki, physicalDevice, surfaces);
543 
544     if (indices.empty())
545         TCU_THROW(NotSupportedError, "Device does not support presentation to the given surfaces");
546 
547     return indices[0];
548 }
549 
chooseQueueFamilyIndex(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface)550 uint32_t chooseQueueFamilyIndex(const vk::InstanceInterface &vki, vk::VkPhysicalDevice physicalDevice,
551                                 vk::VkSurfaceKHR surface)
552 {
553     return chooseQueueFamilyIndex(vki, physicalDevice, std::vector<vk::VkSurfaceKHR>(1u, surface));
554 }
555 
getCompatibleQueueFamilyIndices(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const std::vector<VkSurfaceKHR> & surfaces)556 std::vector<uint32_t> getCompatibleQueueFamilyIndices(const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
557                                                       const std::vector<VkSurfaceKHR> &surfaces)
558 {
559     DE_ASSERT(!surfaces.empty());
560 
561     auto indices = getSortedSupportedQueueFamilyIndices(vki, physicalDevice, surfaces[0]);
562 
563     for (size_t i = 1; i < surfaces.size(); ++i)
564     {
565         auto newIndices = getSortedSupportedQueueFamilyIndices(vki, physicalDevice, surfaces[i]);
566 
567         // Set intersection and overwrite.
568         decltype(indices) intersection;
569         std::set_intersection(begin(indices), end(indices), begin(newIndices), end(newIndices),
570                               std::back_inserter(intersection));
571         indices = std::move(intersection);
572     }
573 
574     return indices;
575 }
576 
getFullScreenSize(const vk::wsi::Type wsiType,const vk::wsi::Display & display,const tcu::UVec2 & fallbackSize)577 tcu::UVec2 getFullScreenSize(const vk::wsi::Type wsiType, const vk::wsi::Display &display,
578                              const tcu::UVec2 &fallbackSize)
579 {
580     tcu::UVec2 result = fallbackSize;
581 
582     switch (wsiType)
583     {
584     case TYPE_XLIB:
585     {
586 #if defined(DEQP_SUPPORT_X11)
587         const XlibDisplayInterface &xlibDisplay = dynamic_cast<const XlibDisplayInterface &>(display);
588         ::Display *displayPtr                   = (::Display *)(xlibDisplay.getNative().internal);
589         const Screen *screen                    = ScreenOfDisplay(displayPtr, 0);
590         result.x()                              = uint32_t(screen->width);
591         result.y()                              = uint32_t(screen->height);
592 #endif
593         break;
594     }
595     case TYPE_XCB:
596     {
597 #if defined(DEQP_SUPPORT_XCB)
598 // const XcbDisplayInterface& xcbDisplay = dynamic_cast<const XcbDisplayInterface&>(display);
599 // xcb_connection_t* connPtr = (xcb_connection_t*)(xcbDisplay.getNative().internal);
600 // xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(connPtr)).data;
601 // result.x() = uint32_t(screen->width_in_pixels);
602 // result.y() = uint32_t(screen->height_in_pixels);
603 #endif
604         break;
605     }
606     case TYPE_WAYLAND:
607     {
608 #if defined(DEQP_SUPPORT_WAYLAND)
609 #endif
610         break;
611     }
612     case TYPE_ANDROID:
613     {
614 #if (DE_OS == DE_OS_ANDROID)
615 #endif
616         break;
617     }
618     case TYPE_WIN32:
619     {
620 #if (DE_OS == DE_OS_WIN32)
621         de::MovePtr<Window> nullWindow(display.createWindow(tcu::Nothing));
622         const Win32WindowInterface &win32Window = dynamic_cast<const Win32WindowInterface &>(*nullWindow);
623         HMONITOR hMonitor =
624             (HMONITOR)MonitorFromWindow((HWND)win32Window.getNative().internal, MONITOR_DEFAULTTONEAREST);
625         MONITORINFO monitorInfo;
626         monitorInfo.cbSize = sizeof(MONITORINFO);
627         GetMonitorInfo(hMonitor, &monitorInfo);
628         result.x() = uint32_t(abs(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left));
629         result.y() = uint32_t(abs(monitorInfo.rcMonitor.top - monitorInfo.rcMonitor.bottom));
630 #endif
631         break;
632     }
633 
634     case TYPE_MACOS:
635     {
636 #if (DE_OS == DE_OS_OSX)
637 #endif
638         break;
639     }
640 
641     default:
642         DE_FATAL("Unknown WSI type");
643         break;
644     }
645 
646     DE_UNREF(display);
647     return result;
648 }
649 
isDisplaySurface(Type wsiType)650 VkBool32 isDisplaySurface(Type wsiType)
651 {
652     switch (wsiType)
653     {
654     case TYPE_XLIB:
655     case TYPE_XCB:
656     case TYPE_WAYLAND:
657     case TYPE_ANDROID:
658     case TYPE_WIN32:
659     case TYPE_MACOS:
660     case TYPE_HEADLESS:
661         return 0;
662     case TYPE_DIRECT_DRM:
663         return 1;
664     default:
665         DE_FATAL("Unknown WSI type");
666         return 0;
667     }
668 }
669 
createRenderPass(const DeviceInterface & vkd,const VkDevice device,const VkFormat colorAttachmentFormat,const bool explicitLayoutTransitions)670 Move<VkRenderPass> WsiTriangleRenderer::createRenderPass(const DeviceInterface &vkd, const VkDevice device,
671                                                          const VkFormat colorAttachmentFormat,
672                                                          const bool explicitLayoutTransitions)
673 {
674     const VkAttachmentDescription colorAttDesc = {
675         (VkAttachmentDescriptionFlags)0,
676         colorAttachmentFormat,
677         VK_SAMPLE_COUNT_1_BIT,
678         VK_ATTACHMENT_LOAD_OP_CLEAR,
679         VK_ATTACHMENT_STORE_OP_STORE,
680         VK_ATTACHMENT_LOAD_OP_DONT_CARE,
681         VK_ATTACHMENT_STORE_OP_DONT_CARE,
682         (explicitLayoutTransitions) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED,
683         (explicitLayoutTransitions) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
684     };
685     const VkAttachmentReference colorAttRef = {
686         0u,
687         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
688     };
689     const VkSubpassDescription subpassDesc = {
690         (VkSubpassDescriptionFlags)0u,
691         VK_PIPELINE_BIND_POINT_GRAPHICS,
692         0u,           // inputAttachmentCount
693         DE_NULL,      // pInputAttachments
694         1u,           // colorAttachmentCount
695         &colorAttRef, // pColorAttachments
696         DE_NULL,      // pResolveAttachments
697         DE_NULL,      // depthStencilAttachment
698         0u,           // preserveAttachmentCount
699         DE_NULL,      // pPreserveAttachments
700     };
701     const VkSubpassDependency dependencies[] = {
702         {VK_SUBPASS_EXTERNAL, // srcSubpass
703          0u,                  // dstSubpass
704          VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_MEMORY_READ_BIT,
705          (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), VK_DEPENDENCY_BY_REGION_BIT},
706         {0u,                  // srcSubpass
707          VK_SUBPASS_EXTERNAL, // dstSubpass
708          VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
709          (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), VK_ACCESS_MEMORY_READ_BIT,
710          VK_DEPENDENCY_BY_REGION_BIT},
711     };
712     const VkRenderPassCreateInfo renderPassParams = {
713         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
714         DE_NULL,
715         (VkRenderPassCreateFlags)0,
716         1u,
717         &colorAttDesc,
718         1u,
719         &subpassDesc,
720         DE_LENGTH_OF_ARRAY(dependencies),
721         dependencies,
722     };
723 
724     return vk::createRenderPass(vkd, device, &renderPassParams);
725 }
726 
createPipelineLayout(const DeviceInterface & vkd,const VkDevice device)727 Move<VkPipelineLayout> WsiTriangleRenderer::createPipelineLayout(const DeviceInterface &vkd, const VkDevice device)
728 {
729     const VkPushConstantRange pushConstantRange = {
730         VK_SHADER_STAGE_VERTEX_BIT,
731         0u,                         // offset
732         (uint32_t)sizeof(uint32_t), // size
733     };
734     const VkPipelineLayoutCreateInfo pipelineLayoutParams = {
735         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
736         DE_NULL,
737         (vk::VkPipelineLayoutCreateFlags)0,
738         0u,      // setLayoutCount
739         DE_NULL, // pSetLayouts
740         1u,
741         &pushConstantRange,
742     };
743 
744     return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
745 }
746 
createPipeline(const DeviceInterface & vkd,const VkDevice device,const VkRenderPass renderPass,const VkPipelineLayout pipelineLayout,const BinaryCollection & binaryCollection,const tcu::UVec2 & renderSize)747 Move<VkPipeline> WsiTriangleRenderer::createPipeline(const DeviceInterface &vkd, const VkDevice device,
748                                                      const VkRenderPass renderPass,
749                                                      const VkPipelineLayout pipelineLayout,
750                                                      const BinaryCollection &binaryCollection,
751                                                      const tcu::UVec2 &renderSize)
752 {
753     // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
754     //         and can be deleted immediately following that call.
755     const Unique<VkShaderModule> vertShaderModule(createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
756     const Unique<VkShaderModule> fragShaderModule(createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
757     const std::vector<VkViewport> viewports(1, makeViewport(renderSize));
758     const std::vector<VkRect2D> scissors(1, makeRect2D(renderSize));
759 
760     return vk::makeGraphicsPipeline(vkd,               // const DeviceInterface&            vk
761                                     device,            // const VkDevice                    device
762                                     pipelineLayout,    // const VkPipelineLayout            pipelineLayout
763                                     *vertShaderModule, // const VkShaderModule              vertexShaderModule
764                                     DE_NULL, // const VkShaderModule              tessellationControlShaderModule
765                                     DE_NULL, // const VkShaderModule              tessellationEvalShaderModule
766                                     DE_NULL, // const VkShaderModule              geometryShaderModule
767                                     *fragShaderModule, // const VkShaderModule              fragmentShaderModule
768                                     renderPass,        // const VkRenderPass                renderPass
769                                     viewports,         // const std::vector<VkViewport>&    viewports
770                                     scissors);         // const std::vector<VkRect2D>&      scissors
771 }
772 
createAttachmentView(const DeviceInterface & vkd,const VkDevice device,const VkImage image,const VkFormat format)773 Move<VkImageView> WsiTriangleRenderer::createAttachmentView(const DeviceInterface &vkd, const VkDevice device,
774                                                             const VkImage image, const VkFormat format)
775 {
776     const VkImageViewCreateInfo viewParams = {
777         VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
778         DE_NULL,
779         (VkImageViewCreateFlags)0,
780         image,
781         VK_IMAGE_VIEW_TYPE_2D,
782         format,
783         vk::makeComponentMappingRGBA(),
784         {
785             VK_IMAGE_ASPECT_COLOR_BIT,
786             0u, // baseMipLevel
787             1u, // levelCount
788             0u, // baseArrayLayer
789             1u, // layerCount
790         },
791     };
792 
793     return vk::createImageView(vkd, device, &viewParams);
794 }
795 
createFramebuffer(const DeviceInterface & vkd,const VkDevice device,const VkRenderPass renderPass,const VkImageView colorAttachment,const tcu::UVec2 & renderSize)796 Move<VkFramebuffer> WsiTriangleRenderer::createFramebuffer(const DeviceInterface &vkd, const VkDevice device,
797                                                            const VkRenderPass renderPass,
798                                                            const VkImageView colorAttachment,
799                                                            const tcu::UVec2 &renderSize)
800 {
801     const VkFramebufferCreateInfo framebufferParams = {
802         VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
803         DE_NULL,
804         (VkFramebufferCreateFlags)0,
805         renderPass,
806         1u,
807         &colorAttachment,
808         renderSize.x(),
809         renderSize.y(),
810         1u, // layers
811     };
812 
813     return vk::createFramebuffer(vkd, device, &framebufferParams);
814 }
815 
createBuffer(const DeviceInterface & vkd,VkDevice device,VkDeviceSize size,VkBufferUsageFlags usage)816 Move<VkBuffer> WsiTriangleRenderer::createBuffer(const DeviceInterface &vkd, VkDevice device, VkDeviceSize size,
817                                                  VkBufferUsageFlags usage)
818 {
819     const VkBufferCreateInfo bufferParams = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
820                                              DE_NULL,
821                                              (VkBufferCreateFlags)0,
822                                              size,
823                                              usage,
824                                              VK_SHARING_MODE_EXCLUSIVE,
825                                              0,
826                                              DE_NULL};
827 
828     return vk::createBuffer(vkd, device, &bufferParams);
829 }
830 
WsiTriangleRenderer(const DeviceInterface & vkd,const VkDevice device,Allocator & allocator,const BinaryCollection & binaryRegistry,bool explicitLayoutTransitions,const vector<VkImage> swapchainImages,const vector<VkImage> aliasImages,const VkFormat framebufferFormat,const tcu::UVec2 & renderSize)831 WsiTriangleRenderer::WsiTriangleRenderer(const DeviceInterface &vkd, const VkDevice device, Allocator &allocator,
832                                          const BinaryCollection &binaryRegistry, bool explicitLayoutTransitions,
833                                          const vector<VkImage> swapchainImages, const vector<VkImage> aliasImages,
834                                          const VkFormat framebufferFormat, const tcu::UVec2 &renderSize)
835     : m_vkd(vkd)
836     , m_explicitLayoutTransitions(explicitLayoutTransitions)
837     , m_swapchainImages(swapchainImages)
838     , m_aliasImages(aliasImages)
839     , m_renderSize(renderSize)
840     , m_renderPass(createRenderPass(vkd, device, framebufferFormat, m_explicitLayoutTransitions))
841     , m_pipelineLayout(createPipelineLayout(vkd, device))
842     , m_pipeline(createPipeline(vkd, device, *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
843     , m_vertexBuffer(
844           createBuffer(vkd, device, (VkDeviceSize)(sizeof(float) * 4 * 3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
845     , m_vertexBufferMemory(
846           allocator.allocate(getBufferMemoryRequirements(vkd, device, *m_vertexBuffer), MemoryRequirement::HostVisible))
847 {
848     m_attachmentViews.resize(swapchainImages.size());
849     m_attachmentLayouts.resize(swapchainImages.size());
850     m_framebuffers.resize(swapchainImages.size());
851 
852     for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
853     {
854         m_attachmentViews[imageNdx] = ImageViewSp(
855             new Unique<VkImageView>(createAttachmentView(vkd, device, swapchainImages[imageNdx], framebufferFormat)));
856         m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_UNDEFINED;
857         m_framebuffers[imageNdx]      = FramebufferSp(new Unique<VkFramebuffer>(
858             createFramebuffer(vkd, device, *m_renderPass, **m_attachmentViews[imageNdx], renderSize)));
859     }
860 
861     VK_CHECK(vkd.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(),
862                                   m_vertexBufferMemory->getOffset()));
863 
864     {
865         const VkMappedMemoryRange memRange = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, DE_NULL,
866                                               m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset(),
867                                               VK_WHOLE_SIZE};
868         const tcu::Vec4 vertices[]         = {tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f), tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
869                                               tcu::Vec4(0.0f, +0.5f, 0.0f, 1.0f)};
870         DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float) * 4 * 3);
871 
872         deMemcpy(m_vertexBufferMemory->getHostPtr(), &vertices[0], sizeof(vertices));
873         VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &memRange));
874     }
875 }
876 
WsiTriangleRenderer(WsiTriangleRenderer && other)877 WsiTriangleRenderer::WsiTriangleRenderer(WsiTriangleRenderer &&other)
878     : m_vkd(other.m_vkd)
879     , m_explicitLayoutTransitions(other.m_explicitLayoutTransitions)
880     , m_swapchainImages(other.m_swapchainImages)
881     , m_aliasImages(other.m_aliasImages)
882     , m_renderSize(other.m_renderSize)
883     , m_renderPass(other.m_renderPass)
884     , m_pipelineLayout(other.m_pipelineLayout)
885     , m_pipeline(other.m_pipeline)
886     , m_vertexBuffer(other.m_vertexBuffer)
887     , m_vertexBufferMemory(other.m_vertexBufferMemory)
888     , m_attachmentViews(other.m_attachmentViews)
889     , m_attachmentLayouts(other.m_attachmentLayouts)
890     , m_framebuffers(other.m_framebuffers)
891 {
892 }
893 
~WsiTriangleRenderer(void)894 WsiTriangleRenderer::~WsiTriangleRenderer(void)
895 {
896 }
897 
recordFrame(VkCommandBuffer cmdBuffer,uint32_t imageNdx,uint32_t frameNdx) const898 void WsiTriangleRenderer::recordFrame(VkCommandBuffer cmdBuffer, uint32_t imageNdx, uint32_t frameNdx) const
899 {
900     const VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
901 
902     beginCommandBuffer(m_vkd, cmdBuffer, 0u);
903 
904     if (m_explicitLayoutTransitions || m_attachmentLayouts[imageNdx] == VK_IMAGE_LAYOUT_UNDEFINED)
905     {
906         const auto range = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
907         const auto newLayout =
908             (m_explicitLayoutTransitions ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
909         const auto srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
910         const auto srcMask  = 0u;
911         const auto dstStage = (m_explicitLayoutTransitions ? VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT :
912                                                              VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
913         const auto dstMask  = (m_explicitLayoutTransitions ? VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT : 0);
914 
915         const auto barrier = makeImageMemoryBarrier(srcMask, dstMask, m_attachmentLayouts[imageNdx], newLayout,
916                                                     m_aliasImages[imageNdx], range);
917         m_vkd.cmdPipelineBarrier(cmdBuffer, srcStage, dstStage, 0u, 0u, nullptr, 0u, nullptr, 1u, &barrier);
918 
919         m_attachmentLayouts[imageNdx] = newLayout;
920     }
921 
922     beginRenderPass(m_vkd, cmdBuffer, *m_renderPass, curFramebuffer,
923                     makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
924 
925     m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
926 
927     {
928         const VkDeviceSize bindingOffset = 0;
929         m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
930     }
931 
932     m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (uint32_t)sizeof(uint32_t),
933                            &frameNdx);
934     m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
935     endRenderPass(m_vkd, cmdBuffer);
936 
937     if (m_explicitLayoutTransitions)
938     {
939         VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
940         const VkImageMemoryBarrier barrier =
941             makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0, m_attachmentLayouts[imageNdx],
942                                    VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, m_aliasImages[imageNdx], range);
943         m_vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
944                                  VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
945         m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
946     }
947 
948     endCommandBuffer(m_vkd, cmdBuffer);
949 }
950 
recordDeviceGroupFrame(VkCommandBuffer cmdBuffer,uint32_t firstDeviceID,uint32_t secondDeviceID,uint32_t devicesCount,uint32_t imageNdx,uint32_t frameNdx) const951 void WsiTriangleRenderer::recordDeviceGroupFrame(VkCommandBuffer cmdBuffer, uint32_t firstDeviceID,
952                                                  uint32_t secondDeviceID, uint32_t devicesCount, uint32_t imageNdx,
953                                                  uint32_t frameNdx) const
954 {
955     const VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
956 
957     beginCommandBuffer(m_vkd, cmdBuffer, 0u);
958 
959     if (m_explicitLayoutTransitions || m_attachmentLayouts[imageNdx] == VK_IMAGE_LAYOUT_UNDEFINED)
960     {
961         const auto range = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
962         const auto newLayout =
963             (m_explicitLayoutTransitions ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
964         const auto srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
965         const auto srcMask  = 0u;
966         const auto dstStage = (m_explicitLayoutTransitions ? VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT :
967                                                              VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
968         const auto dstMask  = (m_explicitLayoutTransitions ? VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT : 0);
969 
970         const auto barrier = makeImageMemoryBarrier(srcMask, dstMask, m_attachmentLayouts[imageNdx], newLayout,
971                                                     m_aliasImages[imageNdx], range);
972         m_vkd.cmdPipelineBarrier(cmdBuffer, srcStage, dstStage, 0u, 0u, nullptr, 0u, nullptr, 1u, &barrier);
973 
974         m_attachmentLayouts[imageNdx] = newLayout;
975     }
976 
977     // begin renderpass
978     {
979         const VkClearValue clearValue = makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
980 
981         VkRect2D zeroRect = {{
982                                  0,
983                                  0,
984                              },
985                              {
986                                  0,
987                                  0,
988                              }};
989         vector<VkRect2D> renderAreas;
990         for (uint32_t i = 0; i < devicesCount; i++)
991             renderAreas.push_back(zeroRect);
992 
993         // Render completely if there is only 1 device
994         if (devicesCount == 1u)
995         {
996             renderAreas[0].extent.width  = (int32_t)m_renderSize.x();
997             renderAreas[0].extent.height = (int32_t)m_renderSize.y();
998         }
999         else
1000         {
1001             // Split into 2 vertical halves
1002             renderAreas[firstDeviceID].extent.width  = (int32_t)m_renderSize.x() / 2;
1003             renderAreas[firstDeviceID].extent.height = (int32_t)m_renderSize.y();
1004             renderAreas[secondDeviceID]              = renderAreas[firstDeviceID];
1005             renderAreas[secondDeviceID].offset.x     = (int32_t)m_renderSize.x() / 2;
1006         }
1007 
1008         const VkDeviceGroupRenderPassBeginInfo deviceGroupRPBeginInfo = {
1009             VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO, DE_NULL, (uint32_t)((1 << devicesCount) - 1),
1010             devicesCount, &renderAreas[0]};
1011 
1012         const VkRenderPassBeginInfo passBeginParams = {
1013             VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,       // sType
1014             &deviceGroupRPBeginInfo,                        // pNext
1015             *m_renderPass,                                  // renderPass
1016             curFramebuffer,                                 // framebuffer
1017             {{0, 0}, {m_renderSize.x(), m_renderSize.y()}}, // renderArea
1018             1u,                                             // clearValueCount
1019             &clearValue,                                    // pClearValues
1020         };
1021         m_vkd.cmdBeginRenderPass(cmdBuffer, &passBeginParams, VK_SUBPASS_CONTENTS_INLINE);
1022     }
1023 
1024     m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1025 
1026     {
1027         const VkDeviceSize bindingOffset = 0;
1028         m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
1029     }
1030 
1031     m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (uint32_t)sizeof(uint32_t),
1032                            &frameNdx);
1033     m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1034     endRenderPass(m_vkd, cmdBuffer);
1035 
1036     if (m_explicitLayoutTransitions)
1037     {
1038         VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
1039         const VkImageMemoryBarrier barrier =
1040             makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0, m_attachmentLayouts[imageNdx],
1041                                    VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, m_aliasImages[imageNdx], range);
1042         m_vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1043                                  VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
1044         m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1045     }
1046 
1047     endCommandBuffer(m_vkd, cmdBuffer);
1048 }
1049 
getPrograms(SourceCollections & dst)1050 void WsiTriangleRenderer::getPrograms(SourceCollections &dst)
1051 {
1052     dst.glslSources.add("tri-vert") << glu::VertexSource("#version 310 es\n"
1053                                                          "layout(location = 0) in highp vec4 a_position;\n"
1054                                                          "layout(push_constant) uniform FrameData\n"
1055                                                          "{\n"
1056                                                          "    highp uint frameNdx;\n"
1057                                                          "} frameData;\n"
1058                                                          "void main (void)\n"
1059                                                          "{\n"
1060                                                          "    highp float angle = float(frameData.frameNdx) / 100.0;\n"
1061                                                          "    highp float c     = cos(angle);\n"
1062                                                          "    highp float s     = sin(angle);\n"
1063                                                          "    highp mat4  t     = mat4( c, -s,  0,  0,\n"
1064                                                          "                              s,  c,  0,  0,\n"
1065                                                          "                              0,  0,  1,  0,\n"
1066                                                          "                              0,  0,  0,  1);\n"
1067                                                          "    gl_Position = t * a_position;\n"
1068                                                          "}\n");
1069     dst.glslSources.add("tri-frag") << glu::FragmentSource(
1070         "#version 310 es\n"
1071         "layout(location = 0) out lowp vec4 o_color;\n"
1072         "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1073 }
1074 
1075 } // namespace wsi
1076 } // namespace vk
1077