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