• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 0
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", "metal", "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_EXT_metal_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_EXT_metal_surface
128         {
129             PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE | PlatformProperties::FEATURE_RESIZE_WINDOW,
130             PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_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, nullptr));
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, nullptr));
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, nullptr));
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         nullptr,                                           // 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, nullptr,
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, nullptr,
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, nullptr,
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, nullptr,
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, nullptr,
290                                                         (VkWin32SurfaceCreateFlagsKHR)0, win32Display.getNative(),
291                                                         win32Window.getNative()};
292 
293         return vki.createWin32SurfaceKHR(instance, &createInfo, pAllocator, pSurface);
294     }
295 
296     case TYPE_METAL:
297     {
298         const MetalWindowInterface &metalWindow      = dynamic_cast<const MetalWindowInterface &>(nativeWindow);
299         const VkMetalSurfaceCreateInfoEXT createInfo = {
300             VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT, nullptr, (VkMetalSurfaceCreateFlagsEXT)0,
301             // pt::CAMetalLayer is defined as a pointer, but the struct def uses a pointer to this pointer type.
302             // *sigh*...
303             reinterpret_cast<pt::CAMetalLayer *>(metalWindow.getNative().internal)};
304 
305         return vki.createMetalSurfaceEXT(instance, &createInfo, pAllocator, pSurface);
306     }
307 
308     case TYPE_HEADLESS:
309     {
310         const VkHeadlessSurfaceCreateInfoEXT createInfo = {VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT, nullptr,
311                                                            (VkHeadlessSurfaceCreateFlagsEXT)0};
312 
313         return vki.createHeadlessSurfaceEXT(instance, &createInfo, pAllocator, pSurface);
314     }
315 
316     case TYPE_DIRECT_DRM:
317     {
318         DirectDrmDisplayInterface &drmDisplay =
319             dynamic_cast<DirectDrmDisplayInterface &>(const_cast<Display &>(nativeDisplay));
320         drmDisplay.initializeDisplay(vki, instance, cmdLine);
321         return createDisplaySurface(vki, instance, drmDisplay.getNative(), cmdLine, pAllocator, pSurface);
322     }
323 
324     default:
325         DE_FATAL("Unknown WSI type");
326         return VK_ERROR_SURFACE_LOST_KHR;
327     }
328 #endif // CTS_USES_VULKANSC
329     return VK_ERROR_SURFACE_LOST_KHR;
330 }
331 
createSurface(const InstanceInterface & vki,VkInstance instance,Type wsiType,const Display & nativeDisplay,const Window & nativeWindow,const tcu::CommandLine & cmdLine,const VkAllocationCallbacks * pAllocator)332 Move<VkSurfaceKHR> createSurface(const InstanceInterface &vki, VkInstance instance, Type wsiType,
333                                  const Display &nativeDisplay, const Window &nativeWindow,
334                                  const tcu::CommandLine &cmdLine, const VkAllocationCallbacks *pAllocator)
335 {
336     VkSurfaceKHR object = VK_NULL_HANDLE;
337     VK_CHECK(createSurface(vki, instance, wsiType, nativeDisplay, nativeWindow, cmdLine, pAllocator, &object));
338     return Move<VkSurfaceKHR>(check<VkSurfaceKHR>(object), Deleter<VkSurfaceKHR>(vki, instance, pAllocator));
339 }
340 
getPhysicalDeviceSurfaceSupport(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,uint32_t queueFamilyIndex,VkSurfaceKHR surface)341 VkBool32 getPhysicalDeviceSurfaceSupport(const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
342                                          uint32_t queueFamilyIndex, VkSurfaceKHR surface)
343 {
344     VkBool32 result = 0;
345 
346     VK_CHECK(vki.getPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, &result));
347 
348     return result;
349 }
350 
getPhysicalDevicePresentationSupport(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,uint32_t queueFamilyIndex,Type wsiType,const Display & nativeDisplay)351 VkBool32 getPhysicalDevicePresentationSupport(const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
352                                               uint32_t queueFamilyIndex, Type wsiType, const Display &nativeDisplay)
353 {
354 #ifdef CTS_USES_VULKANSC
355     DE_UNREF(vki);
356     DE_UNREF(physicalDevice);
357     DE_UNREF(queueFamilyIndex);
358     DE_UNREF(wsiType);
359     DE_UNREF(nativeDisplay);
360     TCU_THROW(NotSupportedError, "Vulkan SC does not support getPhysicalDevicePresentationSupport");
361 #else // CTS_USES_VULKANSC
362     switch (wsiType)
363     {
364     case TYPE_XLIB:
365     {
366         const XlibDisplayInterface &xlibDisplay = dynamic_cast<const XlibDisplayInterface &>(nativeDisplay);
367         pt::XlibVisualID visualID(0U);
368 #if defined(DEQP_SUPPORT_X11)
369         ::Display *displayPtr = (::Display *)(xlibDisplay.getNative().internal);
370         visualID.internal     = (uint32_t)(::XDefaultVisual(displayPtr, 0)->visualid);
371 #endif
372         return vki.getPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex,
373                                                                xlibDisplay.getNative(), visualID);
374     }
375     case TYPE_XCB:
376     {
377         const XcbDisplayInterface &xcbDisplay = dynamic_cast<const XcbDisplayInterface &>(nativeDisplay);
378         pt::XcbVisualid visualID(0U);
379 #if defined(DEQP_SUPPORT_XCB)
380         xcb_connection_t *connPtr = (xcb_connection_t *)(xcbDisplay.getNative().internal);
381         xcb_screen_t *screen      = xcb_setup_roots_iterator(xcb_get_setup(connPtr)).data;
382         visualID.internal         = (uint32_t)(screen->root_visual);
383 #endif
384         return vki.getPhysicalDeviceXcbPresentationSupportKHR(physicalDevice, queueFamilyIndex, xcbDisplay.getNative(),
385                                                               visualID);
386     }
387     case TYPE_WAYLAND:
388     {
389         const WaylandDisplayInterface &waylandDisplay = dynamic_cast<const WaylandDisplayInterface &>(nativeDisplay);
390         return vki.getPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex,
391                                                                   waylandDisplay.getNative());
392     }
393     case TYPE_WIN32:
394     {
395         return vki.getPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
396     }
397     case TYPE_HEADLESS:
398     case TYPE_ANDROID:
399     case TYPE_METAL:
400     case TYPE_DIRECT_DRM:
401     {
402         return 1;
403     }
404     default:
405         DE_FATAL("Unknown WSI type");
406         return 0;
407     }
408 #endif // CTS_USES_VULKANSC
409     return 1;
410 }
411 
getPhysicalDeviceSurfaceCapabilities(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)412 VkSurfaceCapabilitiesKHR getPhysicalDeviceSurfaceCapabilities(const InstanceInterface &vki,
413                                                               VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
414 {
415     VkSurfaceCapabilitiesKHR capabilities;
416 
417     deMemset(&capabilities, 0, sizeof(capabilities));
418 
419     VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities));
420 
421     return capabilities;
422 }
423 
getPhysicalDeviceSurfaceCapabilities2EXT(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)424 VkSurfaceCapabilities2EXT getPhysicalDeviceSurfaceCapabilities2EXT(const InstanceInterface &vki,
425                                                                    VkPhysicalDevice physicalDevice,
426                                                                    VkSurfaceKHR surface)
427 {
428     VkSurfaceCapabilities2EXT capabilities;
429 
430     deMemset(&capabilities, 0, sizeof(capabilities));
431     capabilities.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT;
432 
433     VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2EXT(physicalDevice, surface, &capabilities));
434 
435     return capabilities;
436 }
437 
sameSurfaceCapabilities(const VkSurfaceCapabilitiesKHR & khr,const VkSurfaceCapabilities2EXT & ext)438 bool sameSurfaceCapabilities(const VkSurfaceCapabilitiesKHR &khr, const VkSurfaceCapabilities2EXT &ext)
439 {
440     return (
441         khr.minImageCount == ext.minImageCount && khr.maxImageCount == ext.maxImageCount &&
442         khr.currentExtent.width == ext.currentExtent.width && khr.currentExtent.height == ext.currentExtent.height &&
443         khr.minImageExtent.width == ext.minImageExtent.width &&
444         khr.minImageExtent.height == ext.minImageExtent.height &&
445         khr.maxImageExtent.width == ext.maxImageExtent.width &&
446         khr.maxImageExtent.height == ext.maxImageExtent.height && khr.maxImageArrayLayers == ext.maxImageArrayLayers &&
447         khr.supportedTransforms == ext.supportedTransforms && khr.currentTransform == ext.currentTransform &&
448         khr.supportedCompositeAlpha == ext.supportedCompositeAlpha &&
449         khr.supportedUsageFlags == ext.supportedUsageFlags);
450 }
451 
getPhysicalDeviceSurfaceFormats(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)452 std::vector<VkSurfaceFormatKHR> getPhysicalDeviceSurfaceFormats(const InstanceInterface &vki,
453                                                                 VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
454 {
455     uint32_t numFormats = 0;
456 
457     VK_CHECK(vki.getPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &numFormats, nullptr));
458 
459     if (numFormats > 0)
460     {
461         std::vector<VkSurfaceFormatKHR> formats(numFormats);
462 
463         VK_CHECK(vki.getPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &numFormats, &formats[0]));
464 
465         return formats;
466     }
467     else
468         return std::vector<VkSurfaceFormatKHR>();
469 }
470 
getPhysicalDeviceSurfacePresentModes(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)471 std::vector<VkPresentModeKHR> getPhysicalDeviceSurfacePresentModes(const InstanceInterface &vki,
472                                                                    VkPhysicalDevice physicalDevice,
473                                                                    VkSurfaceKHR surface)
474 {
475     uint32_t numModes = 0;
476 
477     VK_CHECK(vki.getPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numModes, nullptr));
478 
479     if (numModes > 0)
480     {
481         std::vector<VkPresentModeKHR> modes(numModes);
482 
483         VK_CHECK(vki.getPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numModes, &modes[0]));
484 
485         return modes;
486     }
487     else
488         return std::vector<VkPresentModeKHR>();
489 }
490 
getSwapchainImages(const DeviceInterface & vkd,VkDevice device,VkSwapchainKHR swapchain)491 std::vector<VkImage> getSwapchainImages(const DeviceInterface &vkd, VkDevice device, VkSwapchainKHR swapchain)
492 {
493     uint32_t numImages = 0;
494 
495     VK_CHECK(vkd.getSwapchainImagesKHR(device, swapchain, &numImages, nullptr));
496 
497     if (numImages > 0)
498     {
499         std::vector<VkImage> images(numImages);
500 
501         VK_CHECK(vkd.getSwapchainImagesKHR(device, swapchain, &numImages, &images[0]));
502 
503         return images;
504     }
505     else
506         return std::vector<VkImage>();
507 }
508 
509 namespace
510 {
511 
getSupportedQueueFamilyIndices(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)512 std::vector<uint32_t> getSupportedQueueFamilyIndices(const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
513                                                      VkSurfaceKHR surface)
514 {
515     uint32_t numTotalFamilyIndices;
516     vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numTotalFamilyIndices, nullptr);
517 
518     std::vector<VkQueueFamilyProperties> queueFamilyProperties(numTotalFamilyIndices);
519     vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numTotalFamilyIndices, &queueFamilyProperties[0]);
520 
521     std::vector<uint32_t> supportedFamilyIndices;
522     for (uint32_t queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
523     {
524         if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
525             supportedFamilyIndices.push_back(queueFamilyNdx);
526     }
527 
528     return supportedFamilyIndices;
529 }
530 
getSortedSupportedQueueFamilyIndices(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface)531 std::vector<uint32_t> getSortedSupportedQueueFamilyIndices(const vk::InstanceInterface &vki,
532                                                            vk::VkPhysicalDevice physicalDevice,
533                                                            vk::VkSurfaceKHR surface)
534 {
535     std::vector<uint32_t> indices = getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
536     std::sort(begin(indices), end(indices));
537     return indices;
538 }
539 
540 } // namespace
541 
chooseQueueFamilyIndex(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,const std::vector<vk::VkSurfaceKHR> & surfaces)542 uint32_t chooseQueueFamilyIndex(const vk::InstanceInterface &vki, vk::VkPhysicalDevice physicalDevice,
543                                 const std::vector<vk::VkSurfaceKHR> &surfaces)
544 {
545     auto indices = getCompatibleQueueFamilyIndices(vki, physicalDevice, surfaces);
546 
547     if (indices.empty())
548         TCU_THROW(NotSupportedError, "Device does not support presentation to the given surfaces");
549 
550     return indices[0];
551 }
552 
chooseQueueFamilyIndex(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface)553 uint32_t chooseQueueFamilyIndex(const vk::InstanceInterface &vki, vk::VkPhysicalDevice physicalDevice,
554                                 vk::VkSurfaceKHR surface)
555 {
556     return chooseQueueFamilyIndex(vki, physicalDevice, std::vector<vk::VkSurfaceKHR>(1u, surface));
557 }
558 
getCompatibleQueueFamilyIndices(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const std::vector<VkSurfaceKHR> & surfaces)559 std::vector<uint32_t> getCompatibleQueueFamilyIndices(const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
560                                                       const std::vector<VkSurfaceKHR> &surfaces)
561 {
562     DE_ASSERT(!surfaces.empty());
563 
564     auto indices = getSortedSupportedQueueFamilyIndices(vki, physicalDevice, surfaces[0]);
565 
566     for (size_t i = 1; i < surfaces.size(); ++i)
567     {
568         auto newIndices = getSortedSupportedQueueFamilyIndices(vki, physicalDevice, surfaces[i]);
569 
570         // Set intersection and overwrite.
571         decltype(indices) intersection;
572         std::set_intersection(begin(indices), end(indices), begin(newIndices), end(newIndices),
573                               std::back_inserter(intersection));
574         indices = std::move(intersection);
575     }
576 
577     return indices;
578 }
579 
getFullScreenSize(const vk::wsi::Type wsiType,const vk::wsi::Display & display,const tcu::UVec2 & fallbackSize)580 tcu::UVec2 getFullScreenSize(const vk::wsi::Type wsiType, const vk::wsi::Display &display,
581                              const tcu::UVec2 &fallbackSize)
582 {
583     tcu::UVec2 result = fallbackSize;
584 
585     switch (wsiType)
586     {
587     case TYPE_XLIB:
588     {
589 #if defined(DEQP_SUPPORT_X11)
590         const XlibDisplayInterface &xlibDisplay = dynamic_cast<const XlibDisplayInterface &>(display);
591         ::Display *displayPtr                   = (::Display *)(xlibDisplay.getNative().internal);
592         const Screen *screen                    = ScreenOfDisplay(displayPtr, 0);
593         result.x()                              = uint32_t(screen->width);
594         result.y()                              = uint32_t(screen->height);
595 #endif
596         break;
597     }
598     case TYPE_XCB:
599     {
600 #if defined(DEQP_SUPPORT_XCB)
601 // const XcbDisplayInterface& xcbDisplay = dynamic_cast<const XcbDisplayInterface&>(display);
602 // xcb_connection_t* connPtr = (xcb_connection_t*)(xcbDisplay.getNative().internal);
603 // xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(connPtr)).data;
604 // result.x() = uint32_t(screen->width_in_pixels);
605 // result.y() = uint32_t(screen->height_in_pixels);
606 #endif
607         break;
608     }
609     case TYPE_WAYLAND:
610     {
611 #if defined(DEQP_SUPPORT_WAYLAND)
612 #endif
613         break;
614     }
615     case TYPE_ANDROID:
616     {
617 #if (DE_OS == DE_OS_ANDROID)
618 #endif
619         break;
620     }
621     case TYPE_WIN32:
622     {
623 #if (DE_OS == DE_OS_WIN32)
624         de::MovePtr<Window> nullWindow(display.createWindow(tcu::Nothing));
625         const Win32WindowInterface &win32Window = dynamic_cast<const Win32WindowInterface &>(*nullWindow);
626         HMONITOR hMonitor =
627             (HMONITOR)MonitorFromWindow((HWND)win32Window.getNative().internal, MONITOR_DEFAULTTONEAREST);
628         MONITORINFO monitorInfo;
629         monitorInfo.cbSize = sizeof(MONITORINFO);
630         GetMonitorInfo(hMonitor, &monitorInfo);
631         result.x() = uint32_t(abs(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left));
632         result.y() = uint32_t(abs(monitorInfo.rcMonitor.top - monitorInfo.rcMonitor.bottom));
633 #endif
634         break;
635     }
636 
637     case TYPE_METAL:
638     {
639 #if (DE_OS == DE_OS_OSX)
640 #endif
641         break;
642     }
643 
644     default:
645         DE_FATAL("Unknown WSI type");
646         break;
647     }
648 
649     DE_UNREF(display);
650     return result;
651 }
652 
isDisplaySurface(Type wsiType)653 VkBool32 isDisplaySurface(Type wsiType)
654 {
655     switch (wsiType)
656     {
657     case TYPE_XLIB:
658     case TYPE_XCB:
659     case TYPE_WAYLAND:
660     case TYPE_ANDROID:
661     case TYPE_WIN32:
662     case TYPE_METAL:
663     case TYPE_HEADLESS:
664         return 0;
665     case TYPE_DIRECT_DRM:
666         return 1;
667     default:
668         DE_FATAL("Unknown WSI type");
669         return 0;
670     }
671 }
672 
createRenderPass(const DeviceInterface & vkd,const VkDevice device,const VkFormat colorAttachmentFormat,const bool explicitLayoutTransitions)673 Move<VkRenderPass> WsiTriangleRenderer::createRenderPass(const DeviceInterface &vkd, const VkDevice device,
674                                                          const VkFormat colorAttachmentFormat,
675                                                          const bool explicitLayoutTransitions)
676 {
677     const VkAttachmentDescription colorAttDesc = {
678         (VkAttachmentDescriptionFlags)0,
679         colorAttachmentFormat,
680         VK_SAMPLE_COUNT_1_BIT,
681         VK_ATTACHMENT_LOAD_OP_CLEAR,
682         VK_ATTACHMENT_STORE_OP_STORE,
683         VK_ATTACHMENT_LOAD_OP_DONT_CARE,
684         VK_ATTACHMENT_STORE_OP_DONT_CARE,
685         (explicitLayoutTransitions) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED,
686         (explicitLayoutTransitions) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
687     };
688     const VkAttachmentReference colorAttRef = {
689         0u,
690         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
691     };
692     const VkSubpassDescription subpassDesc = {
693         (VkSubpassDescriptionFlags)0u,
694         VK_PIPELINE_BIND_POINT_GRAPHICS,
695         0u,           // inputAttachmentCount
696         nullptr,      // pInputAttachments
697         1u,           // colorAttachmentCount
698         &colorAttRef, // pColorAttachments
699         nullptr,      // pResolveAttachments
700         nullptr,      // depthStencilAttachment
701         0u,           // preserveAttachmentCount
702         nullptr,      // pPreserveAttachments
703     };
704     const VkSubpassDependency dependencies[] = {
705         {VK_SUBPASS_EXTERNAL, // srcSubpass
706          0u,                  // dstSubpass
707          VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_MEMORY_READ_BIT,
708          (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), VK_DEPENDENCY_BY_REGION_BIT},
709         {0u,                  // srcSubpass
710          VK_SUBPASS_EXTERNAL, // dstSubpass
711          VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
712          (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), VK_ACCESS_MEMORY_READ_BIT,
713          VK_DEPENDENCY_BY_REGION_BIT},
714     };
715     const VkRenderPassCreateInfo renderPassParams = {
716         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
717         nullptr,
718         (VkRenderPassCreateFlags)0,
719         1u,
720         &colorAttDesc,
721         1u,
722         &subpassDesc,
723         DE_LENGTH_OF_ARRAY(dependencies),
724         dependencies,
725     };
726 
727     return vk::createRenderPass(vkd, device, &renderPassParams);
728 }
729 
createPipelineLayout(const DeviceInterface & vkd,const VkDevice device)730 Move<VkPipelineLayout> WsiTriangleRenderer::createPipelineLayout(const DeviceInterface &vkd, const VkDevice device)
731 {
732     const VkPushConstantRange pushConstantRange = {
733         VK_SHADER_STAGE_VERTEX_BIT,
734         0u,                         // offset
735         (uint32_t)sizeof(uint32_t), // size
736     };
737     const VkPipelineLayoutCreateInfo pipelineLayoutParams = {
738         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
739         nullptr,
740         (vk::VkPipelineLayoutCreateFlags)0,
741         0u,      // setLayoutCount
742         nullptr, // pSetLayouts
743         1u,
744         &pushConstantRange,
745     };
746 
747     return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
748 }
749 
createPipeline(const DeviceInterface & vkd,const VkDevice device,const VkRenderPass renderPass,const VkPipelineLayout pipelineLayout,const BinaryCollection & binaryCollection,const tcu::UVec2 & renderSize)750 Move<VkPipeline> WsiTriangleRenderer::createPipeline(const DeviceInterface &vkd, const VkDevice device,
751                                                      const VkRenderPass renderPass,
752                                                      const VkPipelineLayout pipelineLayout,
753                                                      const BinaryCollection &binaryCollection,
754                                                      const tcu::UVec2 &renderSize)
755 {
756     // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
757     //         and can be deleted immediately following that call.
758     const Unique<VkShaderModule> vertShaderModule(createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
759     const Unique<VkShaderModule> fragShaderModule(createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
760     const std::vector<VkViewport> viewports(1, makeViewport(renderSize));
761     const std::vector<VkRect2D> scissors(1, makeRect2D(renderSize));
762 
763     return vk::makeGraphicsPipeline(vkd,               // const DeviceInterface&            vk
764                                     device,            // const VkDevice                    device
765                                     pipelineLayout,    // const VkPipelineLayout            pipelineLayout
766                                     *vertShaderModule, // const VkShaderModule              vertexShaderModule
767                                     VK_NULL_HANDLE, // const VkShaderModule              tessellationControlShaderModule
768                                     VK_NULL_HANDLE, // const VkShaderModule              tessellationEvalShaderModule
769                                     VK_NULL_HANDLE, // const VkShaderModule              geometryShaderModule
770                                     *fragShaderModule, // const VkShaderModule              fragmentShaderModule
771                                     renderPass,        // const VkRenderPass                renderPass
772                                     viewports,         // const std::vector<VkViewport>&    viewports
773                                     scissors);         // const std::vector<VkRect2D>&      scissors
774 }
775 
createAttachmentView(const DeviceInterface & vkd,const VkDevice device,const VkImage image,const VkFormat format)776 Move<VkImageView> WsiTriangleRenderer::createAttachmentView(const DeviceInterface &vkd, const VkDevice device,
777                                                             const VkImage image, const VkFormat format)
778 {
779     const VkImageViewCreateInfo viewParams = {
780         VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
781         nullptr,
782         (VkImageViewCreateFlags)0,
783         image,
784         VK_IMAGE_VIEW_TYPE_2D,
785         format,
786         vk::makeComponentMappingRGBA(),
787         {
788             VK_IMAGE_ASPECT_COLOR_BIT,
789             0u, // baseMipLevel
790             1u, // levelCount
791             0u, // baseArrayLayer
792             1u, // layerCount
793         },
794     };
795 
796     return vk::createImageView(vkd, device, &viewParams);
797 }
798 
createFramebuffer(const DeviceInterface & vkd,const VkDevice device,const VkRenderPass renderPass,const VkImageView colorAttachment,const tcu::UVec2 & renderSize)799 Move<VkFramebuffer> WsiTriangleRenderer::createFramebuffer(const DeviceInterface &vkd, const VkDevice device,
800                                                            const VkRenderPass renderPass,
801                                                            const VkImageView colorAttachment,
802                                                            const tcu::UVec2 &renderSize)
803 {
804     const VkFramebufferCreateInfo framebufferParams = {
805         VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
806         nullptr,
807         (VkFramebufferCreateFlags)0,
808         renderPass,
809         1u,
810         &colorAttachment,
811         renderSize.x(),
812         renderSize.y(),
813         1u, // layers
814     };
815 
816     return vk::createFramebuffer(vkd, device, &framebufferParams);
817 }
818 
createBuffer(const DeviceInterface & vkd,VkDevice device,VkDeviceSize size,VkBufferUsageFlags usage)819 Move<VkBuffer> WsiTriangleRenderer::createBuffer(const DeviceInterface &vkd, VkDevice device, VkDeviceSize size,
820                                                  VkBufferUsageFlags usage)
821 {
822     const VkBufferCreateInfo bufferParams = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
823                                              nullptr,
824                                              (VkBufferCreateFlags)0,
825                                              size,
826                                              usage,
827                                              VK_SHARING_MODE_EXCLUSIVE,
828                                              0,
829                                              nullptr};
830 
831     return vk::createBuffer(vkd, device, &bufferParams);
832 }
833 
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)834 WsiTriangleRenderer::WsiTriangleRenderer(const DeviceInterface &vkd, const VkDevice device, Allocator &allocator,
835                                          const BinaryCollection &binaryRegistry, bool explicitLayoutTransitions,
836                                          const vector<VkImage> swapchainImages, const vector<VkImage> aliasImages,
837                                          const VkFormat framebufferFormat, const tcu::UVec2 &renderSize)
838     : m_vkd(vkd)
839     , m_explicitLayoutTransitions(explicitLayoutTransitions)
840     , m_swapchainImages(swapchainImages)
841     , m_aliasImages(aliasImages)
842     , m_renderSize(renderSize)
843     , m_renderPass(createRenderPass(vkd, device, framebufferFormat, m_explicitLayoutTransitions))
844     , m_pipelineLayout(createPipelineLayout(vkd, device))
845     , m_pipeline(createPipeline(vkd, device, *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
846     , m_vertexBuffer(
847           createBuffer(vkd, device, (VkDeviceSize)(sizeof(float) * 4 * 3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
848     , m_vertexBufferMemory(
849           allocator.allocate(getBufferMemoryRequirements(vkd, device, *m_vertexBuffer), MemoryRequirement::HostVisible))
850 {
851     m_attachmentViews.resize(swapchainImages.size());
852     m_attachmentLayouts.resize(swapchainImages.size());
853     m_framebuffers.resize(swapchainImages.size());
854 
855     for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
856     {
857         m_attachmentViews[imageNdx] = ImageViewSp(
858             new Unique<VkImageView>(createAttachmentView(vkd, device, swapchainImages[imageNdx], framebufferFormat)));
859         m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_UNDEFINED;
860         m_framebuffers[imageNdx]      = FramebufferSp(new Unique<VkFramebuffer>(
861             createFramebuffer(vkd, device, *m_renderPass, **m_attachmentViews[imageNdx], renderSize)));
862     }
863 
864     VK_CHECK(vkd.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(),
865                                   m_vertexBufferMemory->getOffset()));
866 
867     {
868         const VkMappedMemoryRange memRange = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, nullptr,
869                                               m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset(),
870                                               VK_WHOLE_SIZE};
871         const tcu::Vec4 vertices[]         = {tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f), tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
872                                               tcu::Vec4(0.0f, +0.5f, 0.0f, 1.0f)};
873         DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float) * 4 * 3);
874 
875         deMemcpy(m_vertexBufferMemory->getHostPtr(), &vertices[0], sizeof(vertices));
876         VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &memRange));
877     }
878 }
879 
WsiTriangleRenderer(WsiTriangleRenderer && other)880 WsiTriangleRenderer::WsiTriangleRenderer(WsiTriangleRenderer &&other)
881     : m_vkd(other.m_vkd)
882     , m_explicitLayoutTransitions(other.m_explicitLayoutTransitions)
883     , m_swapchainImages(other.m_swapchainImages)
884     , m_aliasImages(other.m_aliasImages)
885     , m_renderSize(other.m_renderSize)
886     , m_renderPass(other.m_renderPass)
887     , m_pipelineLayout(other.m_pipelineLayout)
888     , m_pipeline(other.m_pipeline)
889     , m_vertexBuffer(other.m_vertexBuffer)
890     , m_vertexBufferMemory(other.m_vertexBufferMemory)
891     , m_attachmentViews(other.m_attachmentViews)
892     , m_attachmentLayouts(other.m_attachmentLayouts)
893     , m_framebuffers(other.m_framebuffers)
894 {
895 }
896 
~WsiTriangleRenderer(void)897 WsiTriangleRenderer::~WsiTriangleRenderer(void)
898 {
899 }
900 
recordFrame(VkCommandBuffer cmdBuffer,uint32_t imageNdx,uint32_t frameNdx) const901 void WsiTriangleRenderer::recordFrame(VkCommandBuffer cmdBuffer, uint32_t imageNdx, uint32_t frameNdx) const
902 {
903     const VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
904 
905     beginCommandBuffer(m_vkd, cmdBuffer, 0u);
906 
907     if (m_explicitLayoutTransitions || m_attachmentLayouts[imageNdx] == VK_IMAGE_LAYOUT_UNDEFINED)
908     {
909         const auto range = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
910         const auto newLayout =
911             (m_explicitLayoutTransitions ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
912         const auto srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
913         const auto srcMask  = 0u;
914         const auto dstStage = (m_explicitLayoutTransitions ? VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT :
915                                                              VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
916         const auto dstMask  = (m_explicitLayoutTransitions ? VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT : 0);
917 
918         const auto barrier = makeImageMemoryBarrier(srcMask, dstMask, m_attachmentLayouts[imageNdx], newLayout,
919                                                     m_aliasImages[imageNdx], range);
920         m_vkd.cmdPipelineBarrier(cmdBuffer, srcStage, dstStage, 0u, 0u, nullptr, 0u, nullptr, 1u, &barrier);
921 
922         m_attachmentLayouts[imageNdx] = newLayout;
923     }
924 
925     beginRenderPass(m_vkd, cmdBuffer, *m_renderPass, curFramebuffer,
926                     makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
927 
928     m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
929 
930     {
931         const VkDeviceSize bindingOffset = 0;
932         m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
933     }
934 
935     m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (uint32_t)sizeof(uint32_t),
936                            &frameNdx);
937     m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
938     endRenderPass(m_vkd, cmdBuffer);
939 
940     if (m_explicitLayoutTransitions)
941     {
942         VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
943         const VkImageMemoryBarrier barrier =
944             makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0, m_attachmentLayouts[imageNdx],
945                                    VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, m_aliasImages[imageNdx], range);
946         m_vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
947                                  VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &barrier);
948         m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
949     }
950 
951     endCommandBuffer(m_vkd, cmdBuffer);
952 }
953 
recordDeviceGroupFrame(VkCommandBuffer cmdBuffer,uint32_t firstDeviceID,uint32_t secondDeviceID,uint32_t devicesCount,uint32_t imageNdx,uint32_t frameNdx) const954 void WsiTriangleRenderer::recordDeviceGroupFrame(VkCommandBuffer cmdBuffer, uint32_t firstDeviceID,
955                                                  uint32_t secondDeviceID, uint32_t devicesCount, uint32_t imageNdx,
956                                                  uint32_t frameNdx) const
957 {
958     const VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
959 
960     beginCommandBuffer(m_vkd, cmdBuffer, 0u);
961 
962     if (m_explicitLayoutTransitions || m_attachmentLayouts[imageNdx] == VK_IMAGE_LAYOUT_UNDEFINED)
963     {
964         const auto range = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
965         const auto newLayout =
966             (m_explicitLayoutTransitions ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
967         const auto srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
968         const auto srcMask  = 0u;
969         const auto dstStage = (m_explicitLayoutTransitions ? VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT :
970                                                              VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
971         const auto dstMask  = (m_explicitLayoutTransitions ? VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT : 0);
972 
973         const auto barrier = makeImageMemoryBarrier(srcMask, dstMask, m_attachmentLayouts[imageNdx], newLayout,
974                                                     m_aliasImages[imageNdx], range);
975         m_vkd.cmdPipelineBarrier(cmdBuffer, srcStage, dstStage, 0u, 0u, nullptr, 0u, nullptr, 1u, &barrier);
976 
977         m_attachmentLayouts[imageNdx] = newLayout;
978     }
979 
980     // begin renderpass
981     {
982         const VkClearValue clearValue = makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
983 
984         VkRect2D zeroRect = {{
985                                  0,
986                                  0,
987                              },
988                              {
989                                  0,
990                                  0,
991                              }};
992         vector<VkRect2D> renderAreas;
993         for (uint32_t i = 0; i < devicesCount; i++)
994             renderAreas.push_back(zeroRect);
995 
996         // Render completely if there is only 1 device
997         if (devicesCount == 1u)
998         {
999             renderAreas[0].extent.width  = (int32_t)m_renderSize.x();
1000             renderAreas[0].extent.height = (int32_t)m_renderSize.y();
1001         }
1002         else
1003         {
1004             // Split into 2 vertical halves
1005             renderAreas[firstDeviceID].extent.width  = (int32_t)m_renderSize.x() / 2;
1006             renderAreas[firstDeviceID].extent.height = (int32_t)m_renderSize.y();
1007             renderAreas[secondDeviceID]              = renderAreas[firstDeviceID];
1008             renderAreas[secondDeviceID].offset.x     = (int32_t)m_renderSize.x() / 2;
1009         }
1010 
1011         const VkDeviceGroupRenderPassBeginInfo deviceGroupRPBeginInfo = {
1012             VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO, nullptr, (uint32_t)((1 << devicesCount) - 1),
1013             devicesCount, &renderAreas[0]};
1014 
1015         const VkRenderPassBeginInfo passBeginParams = {
1016             VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,       // sType
1017             &deviceGroupRPBeginInfo,                        // pNext
1018             *m_renderPass,                                  // renderPass
1019             curFramebuffer,                                 // framebuffer
1020             {{0, 0}, {m_renderSize.x(), m_renderSize.y()}}, // renderArea
1021             1u,                                             // clearValueCount
1022             &clearValue,                                    // pClearValues
1023         };
1024         m_vkd.cmdBeginRenderPass(cmdBuffer, &passBeginParams, VK_SUBPASS_CONTENTS_INLINE);
1025     }
1026 
1027     m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1028 
1029     {
1030         const VkDeviceSize bindingOffset = 0;
1031         m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
1032     }
1033 
1034     m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (uint32_t)sizeof(uint32_t),
1035                            &frameNdx);
1036     m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1037     endRenderPass(m_vkd, cmdBuffer);
1038 
1039     if (m_explicitLayoutTransitions)
1040     {
1041         VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
1042         const VkImageMemoryBarrier barrier =
1043             makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0, m_attachmentLayouts[imageNdx],
1044                                    VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, m_aliasImages[imageNdx], range);
1045         m_vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1046                                  VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &barrier);
1047         m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1048     }
1049 
1050     endCommandBuffer(m_vkd, cmdBuffer);
1051 }
1052 
getPrograms(SourceCollections & dst)1053 void WsiTriangleRenderer::getPrograms(SourceCollections &dst)
1054 {
1055     dst.glslSources.add("tri-vert") << glu::VertexSource("#version 310 es\n"
1056                                                          "layout(location = 0) in highp vec4 a_position;\n"
1057                                                          "layout(push_constant) uniform FrameData\n"
1058                                                          "{\n"
1059                                                          "    highp uint frameNdx;\n"
1060                                                          "} frameData;\n"
1061                                                          "void main (void)\n"
1062                                                          "{\n"
1063                                                          "    highp float angle = float(frameData.frameNdx) / 100.0;\n"
1064                                                          "    highp float c     = cos(angle);\n"
1065                                                          "    highp float s     = sin(angle);\n"
1066                                                          "    highp mat4  t     = mat4( c, -s,  0,  0,\n"
1067                                                          "                              s,  c,  0,  0,\n"
1068                                                          "                              0,  0,  1,  0,\n"
1069                                                          "                              0,  0,  0,  1);\n"
1070                                                          "    gl_Position = t * a_position;\n"
1071                                                          "}\n");
1072     dst.glslSources.add("tri-frag") << glu::FragmentSource(
1073         "#version 310 es\n"
1074         "layout(location = 0) out lowp vec4 o_color;\n"
1075         "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1076 }
1077 
1078 } // namespace wsi
1079 } // namespace vk
1080