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
qopenxrgraphics_opengl.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
8
9#include <QtGui/QOpenGLContext>
10#include <QtQuick/QQuickWindow>
11#include <QtQuick/private/qquickrendertarget_p.h>
12
13#include <rhi/qrhi.h>
14
15#if defined(XR_USE_PLATFORM_XLIB) || defined(XR_USE_PLATFORM_XCB)
16#include <GL/glx.h>
17#endif
18
19#include <qpa/qplatformnativeinterface.h>
20
22
23#ifndef GL_RGBA8
24#define GL_RGBA8 0x8058
25#endif
26
27#ifndef GL_SRGB8_ALPHA8_EXT
28#define GL_SRGB8_ALPHA8_EXT 0x8C43
29#endif
30
31#ifndef GL_DEPTH_COMPONENT16
32#define GL_DEPTH_COMPONENT16 0x81A5
33#endif
34
35#ifndef GL_DEPTH_COMPONENT24
36#define GL_DEPTH_COMPONENT24 0x81A6
37#endif
38
39#ifndef GL_DEPTH_COMPONENT32F
40#define GL_DEPTH_COMPONENT32F 0x8CAC
41#endif
42
43#ifndef GL_DEPTH24_STENCIL8
44#define GL_DEPTH24_STENCIL8 0x88F0
45#endif
46
47template<typename T>
48T *typed_calloc()
49{
50 return static_cast<T *>(calloc(1, sizeof(T)));
51}
52
54{
55 m_graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR;
56}
57
58bool QOpenXRGraphicsOpenGL::initialize(const QVector<XrExtensionProperties> &extensions)
59{
60
61#ifdef XR_USE_PLATFORM_EGL
62 if (hasExtension(extensions, XR_MNDX_EGL_ENABLE_EXTENSION_NAME)) {
63
64 // To choose XR_MNDX_egl_enable we need to be absolutely sure that
65 // we will get access to EGLContext later and at this point we have no window/rhi yet.
66 QOpenGLContext ctx;
67 if (ctx.create() && ctx.nativeInterface<QNativeInterface::QEGLContext>()) {
68 m_selectedPlatform = PLATFORM_EGL;
69 m_requiredExtensions = { XR_MNDX_EGL_ENABLE_EXTENSION_NAME };
70
71 // XR_MNDX_egl_enable does not require XR_KHR_opengl_enable
72 // However, some OpenXR runtimes still want it (old Monado/SteamVR)
73 if (hasExtension(extensions, XR_KHR_OPENGL_ENABLE_EXTENSION_NAME)) {
74 m_requiredExtensions.append(XR_KHR_OPENGL_ENABLE_EXTENSION_NAME);
75 }
76 return true;
77 }
78 }
79#endif
80
81 // Standard OpenGL platforms
82 if (hasExtension(extensions, XR_KHR_OPENGL_ENABLE_EXTENSION_NAME)) {
83
84#ifdef XR_USE_PLATFORM_WAYLAND
85 auto wlApp = qApp->nativeInterface<QNativeInterface::QWaylandApplication>();
86 if (wlApp && wlApp->display()) {
87 m_selectedPlatform = PLATFORM_WAYLAND;
88 m_requiredExtensions = { XR_KHR_OPENGL_ENABLE_EXTENSION_NAME };
89 return true;
90 }
91#endif
92
93#ifdef XR_USE_PLATFORM_XLIB
94 auto x11App = qApp->nativeInterface<QNativeInterface::QX11Application>();
95 if (x11App && x11App->display()) {
96 m_selectedPlatform = PLATFORM_XLIB;
97 m_requiredExtensions = { XR_KHR_OPENGL_ENABLE_EXTENSION_NAME };
98 return true;
99 }
100#endif
101#ifdef XR_USE_PLATFORM_WIN32
102 m_selectedPlatform = PLATFORM_WIN32;
103 m_requiredExtensions = { XR_KHR_OPENGL_ENABLE_EXTENSION_NAME };
104 return true;
105#endif
106 }
107
108 qWarning("Qt Quick 3D XR (OpenGL): no supported platforms");
109 return false;
110}
111
113{
114 return m_requiredExtensions;
115}
116
117
119{
120 return m_graphicsBinding.get();
121}
122
123
124bool QOpenXRGraphicsOpenGL::setupGraphics(const XrInstance &instance, XrSystemId &systemId, const QQuickGraphicsConfiguration &)
125{
126 // Extension function must be loaded by name
127 PFN_xrGetOpenGLGraphicsRequirementsKHR pfnGetOpenGLGraphicsRequirementsKHR = nullptr;
128 OpenXRHelpers::checkXrResult(xrGetInstanceProcAddr(instance, "xrGetOpenGLGraphicsRequirementsKHR",
129 reinterpret_cast<PFN_xrVoidFunction*>(&pfnGetOpenGLGraphicsRequirementsKHR)),
130 instance);
131 if (!pfnGetOpenGLGraphicsRequirementsKHR) {
132 qWarning("Could not resolve xrGetOpenGLGraphicsRequirementsKHR; perhaps the OpenXR implementation does not support OpenGL?");
133 return false;
134 }
135 OpenXRHelpers::checkXrResult(pfnGetOpenGLGraphicsRequirementsKHR(instance, systemId, &m_graphicsRequirements),
136 instance);
137 return true;
138}
139
140bool QOpenXRGraphicsOpenGL::finializeGraphics(QRhi *rhi)
141{
142 const QRhiGles2NativeHandles *openglRhi = static_cast<const QRhiGles2NativeHandles *>(rhi->nativeHandles());
143
144 QOpenGLContext *openGLContext = openglRhi->context;
145
146 const XrVersion desiredApiVersion = XR_MAKE_VERSION(openGLContext->format().majorVersion(),
147 openGLContext->format().minorVersion(),
148 0);
149 if (m_graphicsRequirements.minApiVersionSupported > desiredApiVersion) {
150 qWarning("Qt Quick 3D XR (OpenGL): Runtime does not support desired graphics API and/or version");
151 return false;
152 }
153
154 switch (m_selectedPlatform) {
155
156#ifdef XR_USE_PLATFORM_EGL
157 case PLATFORM_EGL: {
158 auto eglContext = openGLContext->nativeInterface<QNativeInterface::QEGLContext>();
159 if (!eglContext) {
160 qWarning("Qt Quick 3D XR (OpenGL): Failed to get QNativeInterface::QEGLContext");
161 return false;
162 }
163 auto binding = typed_calloc<XrGraphicsBindingEGLMNDX>();
164 binding->type = XR_TYPE_GRAPHICS_BINDING_EGL_MNDX;
165 binding->getProcAddress = &eglGetProcAddress;
166 binding->display = eglContext->display();
167 binding->config = eglContext->config();
168 binding->context = eglContext->nativeContext();
169 m_graphicsBinding.reset(reinterpret_cast<XrBaseInStructure *>(binding));
170 break;
171 }
172#endif
173
174#ifdef XR_USE_PLATFORM_WAYLAND
175 case PLATFORM_WAYLAND: {
176 auto wlApp = qApp->nativeInterface<QNativeInterface::QWaylandApplication>();
177 auto wlDisplay = wlApp->display();
178 auto binding = typed_calloc<XrGraphicsBindingOpenGLWaylandKHR>();
179 binding->type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR;
180 binding->display = wlDisplay;
181 m_graphicsBinding.reset(reinterpret_cast<XrBaseInStructure *>(binding));
182 break;
183 }
184#endif
185
186#ifdef XR_USE_PLATFORM_XLIB
187 case PLATFORM_XLIB: {
188 auto glxContext = openGLContext->nativeInterface<QNativeInterface::QGLXContext>();
189 if (!glxContext) {
190 qWarning("Qt Quick 3D XR (OpenGL): Failed to get QNativeInterface::QGLXContext");
191 return false;
192 }
193
194 auto x11App = qApp->nativeInterface<QNativeInterface::QX11Application>();
195 auto xDisplay = x11App->display();
196 auto glxDrawable = m_window->winId();
197
198 QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
199 auto glxFBConfig = static_cast<GLXFBConfig>(native->nativeResourceForContext("glxconfig", openGLContext));
200 if (!glxFBConfig) {
201 qWarning("Qt Quick 3D XR (OpenGL): Failed to get GLXFBConfig");
202 return false;
203 }
204
205 int visualId = 0;
206 if (glXGetFBConfigAttrib(xDisplay, glxFBConfig, GLX_VISUAL_ID, &visualId) != Success) {
207 qWarning("Qt Quick 3D XR (OpenGL): Failed to get visualId");
208 return false;
209 }
210
211 auto binding = typed_calloc<XrGraphicsBindingOpenGLXlibKHR>();
212 binding->type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
213 binding->xDisplay = xDisplay;
214 binding->visualid = visualId;
215 binding->glxFBConfig = glxFBConfig;
216 binding->glxDrawable = glxDrawable;
217 binding->glxContext = glxContext->nativeContext();
218 m_graphicsBinding.reset(reinterpret_cast<XrBaseInStructure *>(binding));
219 break;
220 }
221#endif
222
223#ifdef XR_USE_PLATFORM_WIN32
224 case PLATFORM_WIN32: {
225 auto wglContext = openGLContext->nativeInterface<QNativeInterface::QWGLContext>();
226 if (!wglContext) {
227 qWarning("Qt Quick 3D XR (OpenGL): Failed to get QNativeInterface::QWGLContext");
228 return false;
229 }
230 auto binding = typed_calloc<XrGraphicsBindingOpenGLWin32KHR>();
231 binding->type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR;
232 binding->hDC = GetDC(reinterpret_cast<HWND>(m_window->winId()));
233 binding->hGLRC = wglContext->nativeContext();
234 m_graphicsBinding.reset(reinterpret_cast<XrBaseInStructure *>(binding));
235 break;
236 }
237#endif
238
239 default:
240 return false;
241 break;
242 }
243
244 m_rhi = rhi;
245
246 return true;
247}
248
249
250int64_t QOpenXRGraphicsOpenGL::colorSwapchainFormat(const QVector<int64_t> &swapchainFormats) const
251{
252 // List of supported color swapchain formats.
253 constexpr int64_t supportedColorSwapchainFormats[] = { GL_SRGB8_ALPHA8_EXT, GL_RGBA8, GL_RGBA8_SNORM };
254
255 auto swapchainFormatIt = std::find_first_of(std::begin(supportedColorSwapchainFormats),
256 std::end(supportedColorSwapchainFormats),
257 swapchainFormats.begin(),
258 swapchainFormats.end());
259 return *swapchainFormatIt;
260}
261
262int64_t QOpenXRGraphicsOpenGL::depthSwapchainFormat(const QVector<int64_t> &swapchainFormats) const
263{
264 // in order of preference
265 constexpr int64_t supportedDepthSwapchainFormats[] = {
270 };
271
272 return *std::find_first_of(std::begin(supportedDepthSwapchainFormats),
273 std::end(supportedDepthSwapchainFormats),
274 swapchainFormats.begin(),
275 swapchainFormats.end());
276}
277
279{
280 QVector<XrSwapchainImageBaseHeader*> swapchainImages;
281 QVector<XrSwapchainImageOpenGLKHR> swapchainImageBuffer(count);
282 for (XrSwapchainImageOpenGLKHR& image : swapchainImageBuffer) {
283 image.type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR;
284 swapchainImages.push_back(reinterpret_cast<XrSwapchainImageBaseHeader*>(&image));
285 }
286 m_swapchainImageBuffer.insert(swapchain, swapchainImageBuffer);
287 return swapchainImages;
288}
289
290
291QQuickRenderTarget QOpenXRGraphicsOpenGL::renderTarget(const XrSwapchainSubImage &subImage,
292 const XrSwapchainImageBaseHeader *swapchainImage,
293 quint64 swapchainFormat,
294 int samples,
295 int arraySize,
296 const XrSwapchainImageBaseHeader *depthSwapchainImage,
297 quint64 depthSwapchainFormat) const
298{
299 const uint32_t colorTexture = reinterpret_cast<const XrSwapchainImageOpenGLKHR*>(swapchainImage)->image;
300
301 switch (swapchainFormat) {
303 swapchainFormat = GL_RGBA8;
304 break;
305 default:
306 break;
307 }
308
309 QQuickRenderTarget::Flags flags;
310 if (samples > 1)
311 flags |= QQuickRenderTarget::Flag::MultisampleResolve;
312
313 const QSize pixelSize(subImage.imageRect.extent.width, subImage.imageRect.extent.height);
314 QQuickRenderTarget rt = QQuickRenderTarget::fromOpenGLTexture(colorTexture,
315 swapchainFormat,
316 pixelSize,
317 samples,
318 arraySize,
319 flags);
320 if (depthSwapchainImage) {
321 QRhiTexture::Format format = QRhiTexture::D24S8;
322 switch (depthSwapchainFormat) {
324 format = QRhiTexture::D32F;
325 break;
327 format = QRhiTexture::D24;
328 break;
330 format = QRhiTexture::D16;
331 break;
332 }
333 GLuint depthImage = reinterpret_cast<const XrSwapchainImageOpenGLKHR*>(depthSwapchainImage)->image;
334 if (m_depthTexture && (m_depthTexture->format() != format || m_depthTexture->pixelSize() != pixelSize || m_depthTexture->arraySize() != arraySize)) {
335 delete m_depthTexture;
336 m_depthTexture = nullptr;
337 }
338 if (!m_depthTexture) {
339 // this is never multisample, QQuickRt takes care of resolving depth-stencil
340 if (arraySize > 1)
341 m_depthTexture = m_rhi->newTextureArray(format, arraySize, pixelSize, 1, QRhiTexture::RenderTarget);
342 else
343 m_depthTexture = m_rhi->newTexture(format, pixelSize, 1, QRhiTexture::RenderTarget);
344 }
345 m_depthTexture->createFrom({ depthImage, 0 });
346 rt.setDepthTexture(m_depthTexture);
347 }
348 return rt;
349}
350
351void QOpenXRGraphicsOpenGL::setupWindow(QQuickWindow *window)
352{
353 m_window = window;
354}
355
357{
358 delete m_depthTexture;
359 m_depthTexture = nullptr;
360}
361
362QT_END_NAMESPACE
const XrBaseInStructure * handle() const override
QVector< const char * > getRequiredExtensions() const override
int64_t colorSwapchainFormat(const QVector< int64_t > &swapchainFormats) const override
bool setupGraphics(const XrInstance &instance, XrSystemId &systemId, const QQuickGraphicsConfiguration &quickConfig) override
QQuickRenderTarget renderTarget(const XrSwapchainSubImage &subImage, const XrSwapchainImageBaseHeader *swapchainImage, quint64 swapchainFormat, int samples, int arraySize, const XrSwapchainImageBaseHeader *depthSwapchainImage, quint64 depthSwapchainFormat) const override
void setupWindow(QQuickWindow *window) override
bool initialize(const QVector< XrExtensionProperties > &extensions) override
int64_t depthSwapchainFormat(const QVector< int64_t > &swapchainFormats) const override
QVector< XrSwapchainImageBaseHeader * > allocateSwapchainImages(int count, XrSwapchain swapchain) override
Combined button and popup list for selecting options.
#define GL_SRGB8_ALPHA8_EXT
#define GL_DEPTH_COMPONENT32F
Definition qopenglext.h:994
#define GL_DEPTH24_STENCIL8
#define GL_DEPTH_COMPONENT16
Definition qopenglext.h:328
#define GL_DEPTH_COMPONENT24
Definition qopenglext.h:329
#define GL_RGBA8