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