Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qvkkhrdisplayvulkaninstance.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 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// Qt-Security score:significant reason:default
4
6#include <QVarLengthArray>
7
9
10Q_LOGGING_CATEGORY(qLcVkKhrDisplay, "qt.qpa.vkkhrdisplay")
11
12QVkKhrDisplayVulkanInstance::QVkKhrDisplayVulkanInstance(QVulkanInstance *instance)
13 : m_instance(instance)
14{
15 loadVulkanLibrary(QStringLiteral("vulkan"), 1);
16}
17
19{
20 qCDebug(qLcVkKhrDisplay, "Creating Vulkan instance for VK_KHR_display");
21
22 const QByteArray extName = QByteArrayLiteral("VK_KHR_display");
23 initInstance(m_instance, { extName });
24 if (!m_vkInst)
25 return;
26
27 if (!enabledExtensions().contains(extName)) {
28 qWarning("Failed to enable VK_KHR_display extension");
29 return;
30 }
31
32#if VK_KHR_display
33 m_getPhysicalDeviceDisplayPropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)
34 m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceDisplayPropertiesKHR");
35 m_getDisplayModePropertiesKHR = (PFN_vkGetDisplayModePropertiesKHR)
36 m_vkGetInstanceProcAddr(m_vkInst, "vkGetDisplayModePropertiesKHR");
37 m_getPhysicalDeviceDisplayPlanePropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)
38 m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
39
40 m_getDisplayPlaneSupportedDisplaysKHR = (PFN_vkGetDisplayPlaneSupportedDisplaysKHR)
41 m_vkGetInstanceProcAddr(m_vkInst, "vkGetDisplayPlaneSupportedDisplaysKHR");
42 m_getDisplayPlaneCapabilitiesKHR = (PFN_vkGetDisplayPlaneCapabilitiesKHR)
43 m_vkGetInstanceProcAddr(m_vkInst, "vkGetDisplayPlaneCapabilitiesKHR");
44
45 m_createDisplayPlaneSurfaceKHR = (PFN_vkCreateDisplayPlaneSurfaceKHR)
46 m_vkGetInstanceProcAddr(m_vkInst, "vkCreateDisplayPlaneSurfaceKHR");
47#endif
48
49 m_enumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)
50 m_vkGetInstanceProcAddr(m_vkInst, "vkEnumeratePhysicalDevices");
51
52 m_getPhysicalDeviceSurfaceSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>(
53 m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceSurfaceSupportKHR"));
54
55 // Use for first physical device, unless overridden by QT_VK_PHYSICAL_DEVICE_INDEX.
56 // This behavior matches what the Vulkan backend of QRhi would do.
57
58 uint32_t physDevCount = 0;
59 m_enumeratePhysicalDevices(m_vkInst, &physDevCount, nullptr);
60 if (!physDevCount) {
61 qWarning("No physical devices");
62 return;
63 }
64 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
65 VkResult err = m_enumeratePhysicalDevices(m_vkInst, &physDevCount, physDevs.data());
66 if (err != VK_SUCCESS || !physDevCount) {
67 qWarning("Failed to enumerate physical devices: %d", err);
68 return;
69 }
70
71 if (qEnvironmentVariableIsSet("QT_VK_PHYSICAL_DEVICE_INDEX")) {
72 int requestedPhysDevIndex = qEnvironmentVariableIntValue("QT_VK_PHYSICAL_DEVICE_INDEX");
73 if (requestedPhysDevIndex >= 0 && uint32_t(requestedPhysDevIndex) < physDevCount)
74 m_physDev = physDevs[requestedPhysDevIndex];
75 }
76
77 if (m_physDev == VK_NULL_HANDLE)
78 m_physDev = physDevs[0];
79
80 if (chooseDisplay()) {
81 if (m_createdCallback)
82 m_createdCallback(this, m_createdCallbackUserData);
83 }
84}
85
86bool QVkKhrDisplayVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice,
87 uint32_t queueFamilyIndex,
88 QWindow *window)
89{
90 if (!m_getPhysicalDeviceSurfaceSupportKHR)
91 return true;
92
93 VkSurfaceKHR surface = QVulkanInstance::surfaceForWindow(window);
94 VkBool32 supported = false;
95 m_getPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, &supported);
96
97 return supported;
98}
99
100bool QVkKhrDisplayVulkanInstance::chooseDisplay()
101{
102#if VK_KHR_display
103 uint32_t displayCount = 0;
104 VkResult err = m_getPhysicalDeviceDisplayPropertiesKHR(m_physDev, &displayCount, nullptr);
105 if (err != VK_SUCCESS) {
106 qWarning("Failed to get display properties: %d", err);
107 return false;
108 }
109
110 qCDebug(qLcVkKhrDisplay, "Display count: %u", displayCount);
111
112 QVarLengthArray<VkDisplayPropertiesKHR, 4> displayProps(displayCount);
113 m_getPhysicalDeviceDisplayPropertiesKHR(m_physDev, &displayCount, displayProps.data());
114
115 m_display = VK_NULL_HANDLE;
116 m_displayMode = VK_NULL_HANDLE;
117 m_displayName.clear();
118 m_physicalSize = QSizeF();
119
120 // Pick the first display and the first mode, unless specified via env.vars.
121 uint32_t wantedDisplayIndex = 0;
122 uint32_t wantedModeIndex = 0;
123 if (qEnvironmentVariableIsSet("QT_VK_DISPLAY_INDEX"))
124 wantedDisplayIndex = uint32_t(qEnvironmentVariableIntValue("QT_VK_DISPLAY_INDEX"));
125 if (qEnvironmentVariableIsSet("QT_VK_MODE_INDEX"))
126 wantedModeIndex = uint32_t(qEnvironmentVariableIntValue("QT_VK_MODE_INDEX"));
127
128 for (uint32_t i = 0; i < displayCount; ++i) {
129 const VkDisplayPropertiesKHR &disp(displayProps[i]);
130 qCDebug(qLcVkKhrDisplay,
131 "Display #%u:\n display: %p\n name: %s\n dimensions: %ux%u\n resolution: %ux%u",
132 i, (void *) disp.display, disp.displayName,
133 disp.physicalDimensions.width, disp.physicalDimensions.height,
134 disp.physicalResolution.width, disp.physicalResolution.height);
135
136 if (i == wantedDisplayIndex) {
137 m_display = disp.display;
138 m_displayName = QString::fromUtf8(disp.displayName);
139 m_physicalSize = QSizeF(disp.physicalDimensions.width, disp.physicalDimensions.height);
140 }
141
142 uint32_t modeCount = 0;
143 if (m_getDisplayModePropertiesKHR(m_physDev, disp.display, &modeCount, nullptr) != VK_SUCCESS) {
144 qWarning("Failed to get modes for display");
145 continue;
146 }
147 QVarLengthArray<VkDisplayModePropertiesKHR, 16> modeProps(modeCount);
148 m_getDisplayModePropertiesKHR(m_physDev, disp.display, &modeCount, modeProps.data());
149 for (uint32_t j = 0; j < modeCount; ++j) {
150 const VkDisplayModePropertiesKHR &mode(modeProps[j]);
151 qCDebug(qLcVkKhrDisplay,
152 " Mode #%u:\n mode: %p\n visibleRegion: %ux%u\n refreshRate: %u",
153 j, (void *) mode.displayMode,
154 mode.parameters.visibleRegion.width, mode.parameters.visibleRegion.height,
155 mode.parameters.refreshRate);
156 if (j == wantedModeIndex && i == wantedDisplayIndex) {
157 m_displayMode = mode.displayMode;
158 m_width = mode.parameters.visibleRegion.width;
159 m_height = mode.parameters.visibleRegion.height;
160 }
161 }
162 }
163
164 if (m_display == VK_NULL_HANDLE || m_displayMode == VK_NULL_HANDLE) {
165 qWarning("Failed to choose display and mode");
166 return false;
167 }
168
169 qCDebug(qLcVkKhrDisplay, "Using display #%u with mode #%u",
170 wantedDisplayIndex, wantedModeIndex);
171
172 uint32_t planeCount = 0;
173 err = m_getPhysicalDeviceDisplayPlanePropertiesKHR(m_physDev, &planeCount, nullptr);
174 if (err != VK_SUCCESS) {
175 qWarning("Failed to get plane properties: %d", err);
176 return false;
177 }
178
179 qCDebug(qLcVkKhrDisplay, "Plane count: %u", planeCount);
180
181 QVarLengthArray<VkDisplayPlanePropertiesKHR, 4> planeProps(planeCount);
182 m_getPhysicalDeviceDisplayPlanePropertiesKHR(m_physDev, &planeCount, planeProps.data());
183
184 m_planeIndex = UINT_MAX;
185 for (uint32_t i = 0; i < planeCount; ++i) {
186 uint32_t supportedDisplayCount = 0;
187 err = m_getDisplayPlaneSupportedDisplaysKHR(m_physDev, i, &supportedDisplayCount, nullptr);
188 if (err != VK_SUCCESS) {
189 qWarning("Failed to query supported displays for plane: %d", err);
190 return false;
191 }
192
193 QVarLengthArray<VkDisplayKHR, 4> supportedDisplays(supportedDisplayCount);
194 m_getDisplayPlaneSupportedDisplaysKHR(m_physDev, i, &supportedDisplayCount, supportedDisplays.data());
195 qCDebug(qLcVkKhrDisplay, "Plane #%u supports %u displays, currently bound to display %p",
196 i, supportedDisplayCount, (void *) planeProps[i].currentDisplay);
197
198 VkDisplayPlaneCapabilitiesKHR caps;
199 err = m_getDisplayPlaneCapabilitiesKHR(m_physDev, m_displayMode, i, &caps);
200 if (err != VK_SUCCESS) {
201 qWarning("Failed to query plane capabilities: %d", err);
202 return false;
203 }
204
205 qCDebug(qLcVkKhrDisplay,
206 " supportedAlpha: %d (1=no, 2=global, 4=per pixel, 8=per pixel premul)\n"
207 " minSrc=%d, %d %ux%u\n"
208 " maxSrc=%d, %d %ux%u\n"
209 " minDst=%d, %d %ux%u\n"
210 " maxDst=%d, %d %ux%u",
211 int(caps.supportedAlpha),
212 caps.minSrcPosition.x, caps.minSrcPosition.y,
213 caps.minSrcExtent.width, caps.minSrcExtent.height,
214 caps.maxSrcPosition.x, caps.maxSrcPosition.y,
215 caps.maxSrcExtent.width, caps.maxSrcExtent.height,
216 caps.minDstPosition.x, caps.minDstPosition.y,
217 caps.minDstExtent.width, caps.minDstExtent.height,
218 caps.maxDstPosition.x, caps.maxDstPosition.y,
219 caps.maxDstExtent.width, caps.maxDstExtent.height);
220
221 // if the plane is not in use and supports our chosen display, use that plane
222 if (m_planeIndex == UINT_MAX && supportedDisplays.contains(m_display)
223 && (planeProps[i].currentDisplay == VK_NULL_HANDLE || planeProps[i].currentDisplay == m_display))
224 {
225 m_planeIndex = i;
226 m_planeStackIndex = planeProps[i].currentStackIndex;
227 }
228 }
229
230 if (m_planeIndex == UINT_MAX) {
231 qWarning("Failed to find a suitable plane");
232 return false;
233 }
234
235 qCDebug(qLcVkKhrDisplay, "Using plane #%u", m_planeIndex);
236 return true;
237#else
238 return false;
239#endif
240}
241
243{
244#if VK_KHR_display
245 qCDebug(qLcVkKhrDisplay, "Creating VkSurfaceKHR via VK_KHR_display for window %p",
246 (void *) window);
247
248 if (!m_physDev) {
249 qWarning("No physical device, cannot create surface");
250 return VK_NULL_HANDLE;
251 }
252 if (!m_display || !m_displayMode) {
253 qWarning("No display mode chosen, cannot create surface");
254 return VK_NULL_HANDLE;
255 }
256
257 VkDisplaySurfaceCreateInfoKHR surfaceCreateInfo = {};
258 surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
259 surfaceCreateInfo.displayMode = m_displayMode;
260 surfaceCreateInfo.planeIndex = m_planeIndex;
261 surfaceCreateInfo.planeStackIndex = m_planeStackIndex;
262 surfaceCreateInfo.transform = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
263 surfaceCreateInfo.globalAlpha = 1.0f;
264 surfaceCreateInfo.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
265 surfaceCreateInfo.imageExtent = { m_width, m_height };
266
267 VkSurfaceKHR surface = VK_NULL_HANDLE;
268 VkResult err = m_createDisplayPlaneSurfaceKHR(m_vkInst, &surfaceCreateInfo, nullptr, &surface);
269 if (err != VK_SUCCESS || surface == VK_NULL_HANDLE) {
270 qWarning("Failed to create surface: %d", err);
271 return VK_NULL_HANDLE;
272 }
273
274 qCDebug(qLcVkKhrDisplay, "Created surface %p", (void *) surface);
275
276 return surface;
277#else
278 Q_UNUSED(window);
279 return VK_NULL_HANDLE;
280#endif
281}
282
284{
285 Q_UNUSED(window);
286}
287
288QT_END_NAMESPACE
VkSurfaceKHR createSurface(QWindow *window)
bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override
void presentAboutToBeQueued(QWindow *window) override
Combined button and popup list for selecting options.