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