1 | // Copyright (C) 2019 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qwaylandvulkaninstance_p.h" |
5 | #include "qwaylandwindow_p.h" |
6 | #include "qwaylandscreen_p.h" |
7 | #include "qwaylanddisplay_p.h" |
8 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | namespace QtWaylandClient { |
12 | |
13 | QWaylandVulkanInstance::QWaylandVulkanInstance(QVulkanInstance *instance) |
14 | : m_instance(instance) |
15 | { |
16 | loadVulkanLibrary(QStringLiteral("vulkan" )); |
17 | } |
18 | |
19 | QWaylandVulkanInstance::~QWaylandVulkanInstance() = default; |
20 | |
21 | void QWaylandVulkanInstance::createOrAdoptInstance() |
22 | { |
23 | QByteArrayList ; |
24 | extraExtensions << QByteArrayLiteral("VK_KHR_wayland_surface" ); |
25 | initInstance(instance: m_instance, extraExts: extraExtensions); |
26 | |
27 | if (!m_vkInst) |
28 | return; |
29 | |
30 | m_getPhysDevPresSupport = reinterpret_cast<PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR>( |
31 | m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceWaylandPresentationSupportKHR" )); |
32 | if (!m_getPhysDevPresSupport) |
33 | qWarning() << "Failed to find vkGetPhysicalDeviceWaylandPresentationSupportKHR" ; |
34 | } |
35 | |
36 | bool QWaylandVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, |
37 | uint32_t queueFamilyIndex, |
38 | QWindow *window) |
39 | { |
40 | if (!m_getPhysDevPresSupport || !m_getPhysDevSurfaceSupport) |
41 | return true; |
42 | |
43 | auto *w = static_cast<QWaylandWindow *>(window->handle()); |
44 | if (!w) { |
45 | qWarning() << "Attempted to call supportsPresent() without a valid platform window" ; |
46 | return false; |
47 | } |
48 | wl_display *display = w->display()->wl_display(); |
49 | bool ok = m_getPhysDevPresSupport(physicalDevice, queueFamilyIndex, display); |
50 | |
51 | VkSurfaceKHR surface = QVulkanInstance::surfaceForWindow(window); |
52 | VkBool32 supported = false; |
53 | m_getPhysDevSurfaceSupport(physicalDevice, queueFamilyIndex, surface, &supported); |
54 | ok &= bool(supported); |
55 | |
56 | return ok; |
57 | } |
58 | |
59 | VkSurfaceKHR QWaylandVulkanInstance::createSurface(QWaylandWindow *window) |
60 | { |
61 | VkSurfaceKHR surface = VK_NULL_HANDLE; |
62 | |
63 | if (!m_createSurface) { |
64 | m_createSurface = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>( |
65 | m_vkGetInstanceProcAddr(m_vkInst, "vkCreateWaylandSurfaceKHR" )); |
66 | } |
67 | if (!m_createSurface) { |
68 | qWarning() << "Failed to find vkCreateWaylandSurfaceKHR" ; |
69 | return surface; |
70 | } |
71 | |
72 | VkWaylandSurfaceCreateInfoKHR surfaceInfo; |
73 | memset(s: &surfaceInfo, c: 0, n: sizeof(surfaceInfo)); |
74 | surfaceInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; |
75 | surfaceInfo.display = window->display()->wl_display(); |
76 | surfaceInfo.surface = window->wlSurface(); |
77 | VkResult err = m_createSurface(m_vkInst, &surfaceInfo, nullptr, &surface); |
78 | if (err != VK_SUCCESS) |
79 | qWarning(msg: "Failed to create Vulkan surface: %d" , err); |
80 | |
81 | return surface; |
82 | } |
83 | |
84 | void QWaylandVulkanInstance::presentAboutToBeQueued(QWindow *window) |
85 | { |
86 | auto *w = static_cast<QWaylandWindow *>(window->handle()); |
87 | if (!w) { |
88 | qWarning() << "Attempted to call presentAboutToBeQueued() without a valid platform window" ; |
89 | return; |
90 | } |
91 | |
92 | bool ok; |
93 | int frameCallbackTimeout = qEnvironmentVariableIntValue(varName: "QT_WAYLAND_FRAME_CALLBACK_TIMEOUT" , ok: &ok); |
94 | |
95 | if (ok) |
96 | mFrameCallbackTimeout = frameCallbackTimeout; |
97 | |
98 | if (w->format().swapInterval() > 0) |
99 | w->waitForFrameSync(timeout: mFrameCallbackTimeout); |
100 | |
101 | w->handleUpdate(); |
102 | } |
103 | |
104 | void QWaylandVulkanInstance::beginFrame(QWindow *window) |
105 | { |
106 | auto *w = static_cast<QWaylandWindow *>(window->handle()); |
107 | if (!w) { |
108 | qWarning() << "Attempted to call beginFrame() without a valid platform window" ; |
109 | return; |
110 | } |
111 | w->beginFrame(); |
112 | } |
113 | |
114 | void QWaylandVulkanInstance::endFrame(QWindow *window) |
115 | { |
116 | auto *w = static_cast<QWaylandWindow *>(window->handle()); |
117 | if (!w) { |
118 | qWarning() << "Attempted to call endFrame() without a valid platform window" ; |
119 | return; |
120 | } |
121 | w->endFrame(); |
122 | } |
123 | |
124 | } // namespace QtWaylandClient |
125 | |
126 | QT_END_NAMESPACE |
127 | |