Revision control
Copy as Markdown
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "qopenxrgraphics_opengles_p.h"
#include "qopenxrhelpers_p.h"
#include <QtGui/QOpenGLContext>
#include <QtQuick/private/qquickrendertarget_p.h>
#include <rhi/qrhi.h>
QT_BEGIN_NAMESPACE
#ifndef GL_DEPTH_COMPONENT32F
#define GL_DEPTH_COMPONENT32F 0x8CAC
#endif
QOpenXRGraphicsOpenGLES::QOpenXRGraphicsOpenGLES()
{
#ifdef XR_USE_PLATFORM_ANDROID
m_graphicsBinding.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR;
#endif
m_graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR;
}
bool QOpenXRGraphicsOpenGLES::initialize(const QVector<XrExtensionProperties> &extensions)
{
return hasExtension(extensions, XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME);
}
QVector<const char *> QOpenXRGraphicsOpenGLES::getRequiredExtensions() const
{
return { XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME };
}
const XrBaseInStructure *QOpenXRGraphicsOpenGLES::handle() const
{
return reinterpret_cast<const XrBaseInStructure*>(&m_graphicsBinding);
}
bool QOpenXRGraphicsOpenGLES::setupGraphics(const XrInstance &instance, XrSystemId &systemId, const QQuickGraphicsConfiguration &)
{
// Extension function must be loaded by name
PFN_xrGetOpenGLESGraphicsRequirementsKHR pfnGetOpenGLESGraphicsRequirementsKHR = nullptr;
OpenXRHelpers::checkXrResult(xrGetInstanceProcAddr(instance, "xrGetOpenGLESGraphicsRequirementsKHR",
reinterpret_cast<PFN_xrVoidFunction*>(&pfnGetOpenGLESGraphicsRequirementsKHR)),
instance);
if (!pfnGetOpenGLESGraphicsRequirementsKHR) {
qWarning("Could not resolve xrGetOpenGLESGraphicsRequirementsKHR; perhaps the OpenXR implementation does not support OpenGL ES?");
return false;
}
OpenXRHelpers::checkXrResult(pfnGetOpenGLESGraphicsRequirementsKHR(instance, systemId, &m_graphicsRequirements),
instance);
return true;
}
bool QOpenXRGraphicsOpenGLES::finializeGraphics(QRhi *rhi)
{
const QRhiGles2NativeHandles *openglRhi = static_cast<const QRhiGles2NativeHandles *>(rhi->nativeHandles());
auto context = openglRhi->context;
const XrVersion desiredApiVersion = XR_MAKE_VERSION(context->format().majorVersion(), context->format().minorVersion(), 0);
if (m_graphicsRequirements.minApiVersionSupported > desiredApiVersion) {
qWarning("Qt Quick 3D XR (Open GL ES): Runtime does not support desired graphics API and/or version");
return false;
}
#ifdef XR_USE_PLATFORM_ANDROID
auto nativeContext = context->nativeInterface<QNativeInterface::QEGLContext>();
if (nativeContext) {
m_graphicsBinding.display = nativeContext->display();
m_graphicsBinding.config = nativeContext->config();
m_graphicsBinding.context = nativeContext->nativeContext();
}
#endif
m_rhi = rhi;
return true;
}
int64_t QOpenXRGraphicsOpenGLES::colorSwapchainFormat(const QVector<int64_t> &swapchainFormats) const
{
// List of supported color swapchain formats.
constexpr int64_t supportedColorSwapchainFormats[] = {
GL_SRGB8_ALPHA8_EXT,
GL_RGBA8_SNORM
};
auto swapchainFormatIt = std::find_first_of(std::begin(supportedColorSwapchainFormats),
std::end(supportedColorSwapchainFormats),
swapchainFormats.begin(),
swapchainFormats.end());
return *swapchainFormatIt;
}
int64_t QOpenXRGraphicsOpenGLES::depthSwapchainFormat(const QVector<int64_t> &swapchainFormats) const
{
// in order of preference
constexpr int64_t supportedDepthSwapchainFormats[] = {
GL_DEPTH24_STENCIL8_OES,
GL_DEPTH_COMPONENT32F,
GL_DEPTH_COMPONENT24_OES,
GL_DEPTH_COMPONENT16_OES
};
return *std::find_first_of(std::begin(supportedDepthSwapchainFormats),
std::end(supportedDepthSwapchainFormats),
swapchainFormats.begin(),
swapchainFormats.end());
}
QVector<XrSwapchainImageBaseHeader*> QOpenXRGraphicsOpenGLES::allocateSwapchainImages(int count, XrSwapchain swapchain)
{
QVector<XrSwapchainImageBaseHeader*> swapchainImages;
QVector<XrSwapchainImageOpenGLESKHR> swapchainImageBuffer(count);
for (XrSwapchainImageOpenGLESKHR& image : swapchainImageBuffer) {
image.type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
swapchainImages.push_back(reinterpret_cast<XrSwapchainImageBaseHeader*>(&image));
}
m_swapchainImageBuffer.insert(swapchain, swapchainImageBuffer);
return swapchainImages;
}
QQuickRenderTarget QOpenXRGraphicsOpenGLES::renderTarget(const XrSwapchainSubImage &subImage,
const XrSwapchainImageBaseHeader *swapchainImage,
quint64 swapchainFormat,
int samples,
int arraySize,
const XrSwapchainImageBaseHeader *depthSwapchainImage,
quint64 depthSwapchainFormat) const
{
const uint32_t colorTexture = reinterpret_cast<const XrSwapchainImageOpenGLESKHR*>(swapchainImage)->image;
switch (swapchainFormat) {
case GL_SRGB8_ALPHA8_EXT:
swapchainFormat = GL_RGBA8_OES;
break;
default:
break;
}
QQuickRenderTarget::Flags flags;
if (samples > 1)
flags |= QQuickRenderTarget::Flag::MultisampleResolve;
const QSize pixelSize(subImage.imageRect.extent.width, subImage.imageRect.extent.height);
QQuickRenderTarget rt = QQuickRenderTarget::fromOpenGLTexture(colorTexture,
swapchainFormat,
pixelSize,
samples,
arraySize,
flags);
if (depthSwapchainImage) {
QRhiTexture::Format format = QRhiTexture::D24S8;
switch (depthSwapchainFormat) {
case GL_DEPTH_COMPONENT32F:
format = QRhiTexture::D32F;
break;
case GL_DEPTH_COMPONENT24_OES:
format = QRhiTexture::D24;
break;
case GL_DEPTH_COMPONENT16_OES:
format = QRhiTexture::D16;
break;
}
GLuint depthImage = reinterpret_cast<const XrSwapchainImageOpenGLESKHR*>(depthSwapchainImage)->image;
if (m_depthTexture && (m_depthTexture->format() != format || m_depthTexture->pixelSize() != pixelSize || m_depthTexture->arraySize() != arraySize)) {
delete m_depthTexture;
m_depthTexture = nullptr;
}
if (!m_depthTexture) {
// this is never multisample, QQuickRt takes care of resolving depth-stencil
if (arraySize > 1)
m_depthTexture = m_rhi->newTextureArray(format, arraySize, pixelSize, 1, QRhiTexture::RenderTarget);
else
m_depthTexture = m_rhi->newTexture(format, pixelSize, 1, QRhiTexture::RenderTarget);
}
m_depthTexture->createFrom({ depthImage, 0 });
rt.setDepthTexture(m_depthTexture);
}
return rt;
}
void QOpenXRGraphicsOpenGLES::releaseResources()
{
delete m_depthTexture;
m_depthTexture = nullptr;
}
QT_END_NAMESPACE