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
118 // Pick the first display and the first mode, unless specified via env.vars.
119 uint32_t wantedDisplayIndex = 0;
120 uint32_t wantedModeIndex = 0;
121 if (qEnvironmentVariableIsSet("QT_VK_DISPLAY_INDEX"))
122 wantedDisplayIndex = uint32_t(qEnvironmentVariableIntValue("QT_VK_DISPLAY_INDEX"));
123 if (qEnvironmentVariableIsSet("QT_VK_MODE_INDEX"))
124 wantedModeIndex = uint32_t(qEnvironmentVariableIntValue("QT_VK_MODE_INDEX"));
125
126 for (uint32_t i = 0; i < displayCount; ++i) {
127 const VkDisplayPropertiesKHR &disp(displayProps[i]);
128 qCDebug(qLcVkKhrDisplay,
129 "Display #%u:\n display: %p\n name: %s\n dimensions: %ux%u\n resolution: %ux%u",
130 i, (void *) disp.display, disp.displayName,
131 disp.physicalDimensions.width, disp.physicalDimensions.height,
132 disp.physicalResolution.width, disp.physicalResolution.height);
133
134 if (i == wantedDisplayIndex)
135 m_display = disp.display;
136
137 uint32_t modeCount = 0;
138 if (m_getDisplayModePropertiesKHR(m_physDev, disp.display, &modeCount, nullptr) != VK_SUCCESS) {
139 qWarning("Failed to get modes for display");
140 continue;
141 }
142 QVarLengthArray<VkDisplayModePropertiesKHR, 16> modeProps(modeCount);
143 m_getDisplayModePropertiesKHR(m_physDev, disp.display, &modeCount, modeProps.data());
144 for (uint32_t j = 0; j < modeCount; ++j) {
145 const VkDisplayModePropertiesKHR &mode(modeProps[j]);
146 qCDebug(qLcVkKhrDisplay,
147 " Mode #%u:\n mode: %p\n visibleRegion: %ux%u\n refreshRate: %u",
148 j, (void *) mode.displayMode,
149 mode.parameters.visibleRegion.width, mode.parameters.visibleRegion.height,
150 mode.parameters.refreshRate);
151 if (j == wantedModeIndex && i == wantedDisplayIndex) {
152 m_displayMode = mode.displayMode;
153 m_width = mode.parameters.visibleRegion.width;
154 m_height = mode.parameters.visibleRegion.height;
155 }
156 }
157 }
158
159 if (m_display == VK_NULL_HANDLE || m_displayMode == VK_NULL_HANDLE) {
160 qWarning("Failed to choose display and mode");
161 return false;
162 }
163
164 qCDebug(qLcVkKhrDisplay, "Using display #%u with mode #%u",
165 wantedDisplayIndex, wantedModeIndex);
166
167 uint32_t planeCount = 0;
168 err = m_getPhysicalDeviceDisplayPlanePropertiesKHR(m_physDev, &planeCount, nullptr);
169 if (err != VK_SUCCESS) {
170 qWarning("Failed to get plane properties: %d", err);
171 return false;
172 }
173
174 qCDebug(qLcVkKhrDisplay, "Plane count: %u", planeCount);
175
176 QVarLengthArray<VkDisplayPlanePropertiesKHR, 4> planeProps(planeCount);
177 m_getPhysicalDeviceDisplayPlanePropertiesKHR(m_physDev, &planeCount, planeProps.data());
178
179 m_planeIndex = UINT_MAX;
180 for (uint32_t i = 0; i < planeCount; ++i) {
181 uint32_t supportedDisplayCount = 0;
182 err = m_getDisplayPlaneSupportedDisplaysKHR(m_physDev, i, &supportedDisplayCount, nullptr);
183 if (err != VK_SUCCESS) {
184 qWarning("Failed to query supported displays for plane: %d", err);
185 return false;
186 }
187
188 QVarLengthArray<VkDisplayKHR, 4> supportedDisplays(supportedDisplayCount);
189 m_getDisplayPlaneSupportedDisplaysKHR(m_physDev, i, &supportedDisplayCount, supportedDisplays.data());
190 qCDebug(qLcVkKhrDisplay, "Plane #%u supports %u displays, currently bound to display %p",
191 i, supportedDisplayCount, (void *) planeProps[i].currentDisplay);
192
193 VkDisplayPlaneCapabilitiesKHR caps;
194 err = m_getDisplayPlaneCapabilitiesKHR(m_physDev, m_displayMode, i, &caps);
195 if (err != VK_SUCCESS) {
196 qWarning("Failed to query plane capabilities: %d", err);
197 return false;
198 }
199
200 qCDebug(qLcVkKhrDisplay,
201 " supportedAlpha: %d (1=no, 2=global, 4=per pixel, 8=per pixel premul)\n"
202 " minSrc=%d, %d %ux%u\n"
203 " maxSrc=%d, %d %ux%u\n"
204 " minDst=%d, %d %ux%u\n"
205 " maxDst=%d, %d %ux%u",
206 int(caps.supportedAlpha),
207 caps.minSrcPosition.x, caps.minSrcPosition.y,
208 caps.minSrcExtent.width, caps.minSrcExtent.height,
209 caps.maxSrcPosition.x, caps.maxSrcPosition.y,
210 caps.maxSrcExtent.width, caps.maxSrcExtent.height,
211 caps.minDstPosition.x, caps.minDstPosition.y,
212 caps.minDstExtent.width, caps.minDstExtent.height,
213 caps.maxDstPosition.x, caps.maxDstPosition.y,
214 caps.maxDstExtent.width, caps.maxDstExtent.height);
215
216 // if the plane is not in use and supports our chosen display, use that plane
217 if (m_planeIndex == UINT_MAX && supportedDisplays.contains(m_display)
218 && (planeProps[i].currentDisplay == VK_NULL_HANDLE || planeProps[i].currentDisplay == m_display))
219 {
220 m_planeIndex = i;
221 m_planeStackIndex = planeProps[i].currentStackIndex;
222 }
223 }
224
225 if (m_planeIndex == UINT_MAX) {
226 qWarning("Failed to find a suitable plane");
227 return false;
228 }
229
230 qCDebug(qLcVkKhrDisplay, "Using plane #%u", m_planeIndex);
231 return true;
232#else
233 return false;
234#endif
235}
236
238{
239#if VK_KHR_display
240 qCDebug(qLcVkKhrDisplay, "Creating VkSurfaceKHR via VK_KHR_display for window %p",
241 (void *) window);
242
243 if (!m_physDev) {
244 qWarning("No physical device, cannot create surface");
245 return VK_NULL_HANDLE;
246 }
247 if (!m_display || !m_displayMode) {
248 qWarning("No display mode chosen, cannot create surface");
249 return VK_NULL_HANDLE;
250 }
251
252 VkDisplaySurfaceCreateInfoKHR surfaceCreateInfo = {};
253 surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
254 surfaceCreateInfo.displayMode = m_displayMode;
255 surfaceCreateInfo.planeIndex = m_planeIndex;
256 surfaceCreateInfo.planeStackIndex = m_planeStackIndex;
257 surfaceCreateInfo.transform = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
258 surfaceCreateInfo.globalAlpha = 1.0f;
259 surfaceCreateInfo.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
260 surfaceCreateInfo.imageExtent = { m_width, m_height };
261
262 VkSurfaceKHR surface = VK_NULL_HANDLE;
263 VkResult err = m_createDisplayPlaneSurfaceKHR(m_vkInst, &surfaceCreateInfo, nullptr, &surface);
264 if (err != VK_SUCCESS || surface == VK_NULL_HANDLE) {
265 qWarning("Failed to create surface: %d", err);
266 return VK_NULL_HANDLE;
267 }
268
269 qCDebug(qLcVkKhrDisplay, "Created surface %p", (void *) surface);
270
271 return surface;
272#else
273 Q_UNUSED(window);
274 return VK_NULL_HANDLE;
275#endif
276}
277
279{
280 Q_UNUSED(window);
281}
282
283QT_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.