aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2023-12-07 20:20:06 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2024-01-15 21:25:12 +0100
commit7295ece36399f25e3a3226b3222261e803140c94 (patch)
tree2342c8cbf21af204a016f343fcec83a81bded297
parentb5a05e4e7e97f8ef5c4cc65fee0cfcfd9e4c5cc4 (diff)
Allow QQuickRt adopt a native texture array for multiview rendering
Limiting multiview to fromRhiRenderTarget() is quite limiting, since in practice it often involves duplicating the convenience logic that is built into Qt Quick for fromVulkanImage() and similar. We should also support passing in a texture array object to from fromOpenGLTexture, fromVulkanImage, etc. The array size then implies the view count. We are also required to use a texture array for depth/stencil as well in this case. Add the necessary plumbing so that clients, such as an OpenXR integration, can continue to use fromXxxxx(), just the *MultiView variants, instead of forcing them to create a QRhiTextureRenderTarget themselves upfront. Task-number: QTBUG-119850 Task-number: QTBUG-114871 Change-Id: I79978e5ff5f154c8914afbe2478d002291219aaf Reviewed-by: Andy Nichols <andy.nichols@qt.io>
-rw-r--r--src/quick/items/qquickrendertarget.cpp338
-rw-r--r--src/quick/items/qquickrendertarget.h4
-rw-r--r--src/quick/items/qquickrendertarget_p.h9
-rw-r--r--src/quick/items/qquickwindow.cpp2
-rw-r--r--src/quick/items/qquickwindow_p.h1
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp13
6 files changed, 361 insertions, 6 deletions
diff --git a/src/quick/items/qquickrendertarget.cpp b/src/quick/items/qquickrendertarget.cpp
index 60454455d6..9c4f02b5ae 100644
--- a/src/quick/items/qquickrendertarget.cpp
+++ b/src/quick/items/qquickrendertarget.cpp
@@ -221,6 +221,71 @@ QQuickRenderTarget QQuickRenderTarget::fromOpenGLTexture(uint textureId, uint fo
/*!
\overload
+ \return a new QQuickRenderTarget referencing a 2D texture array with the
+ specified \a arraySize and OpenGL \a textureId.
+
+ \note This implies multiview rendering (GL_OVR_multiview etc.), which can be
+ relevant with VR/AR especially. \a arraySize is the number of views,
+ typically \c 2. This overload should not be used other cases.
+ See \l QSGMaterial::viewCount() for details on enabling multiview rendering
+ within the Qt Quick scenegraph.
+
+ \a format specifies the native internal format of the texture. Only texture
+ formats that are supported by Qt's rendering infrastructure should be used.
+
+ \a pixelSize specifies the size of the image, in pixels.
+
+ \a sampleCount specific the number of samples. 0 or 1 means no
+ multisampling, while a value like 4 or 8 states that the native object is a
+ multisample texture.
+
+ The texture is used as the first color attachment of the render target used
+ by the Qt Quick scenegraph. A depth-stencil texture array with a matching
+ number of layers, sample count, and a format of \c D24S8 is created and used
+ automatically.
+
+ \note the resulting QQuickRenderTarget does not own any native resources, it
+ merely contains references and the associated metadata of the size and
+ sample count. It is the caller's responsibility to ensure that the native
+ resource exists as long as necessary.
+
+ \since 6.8
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+ */
+QQuickRenderTarget QQuickRenderTarget::fromOpenGLTextureMultiView(uint textureId, uint format, const QSize &pixelSize, int sampleCount, int arraySize)
+{
+ QQuickRenderTarget rt;
+ QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
+
+ if (!textureId) {
+ qWarning("QQuickRenderTarget: textureId is invalid");
+ return rt;
+ }
+
+ if (pixelSize.isEmpty()) {
+ qWarning("QQuickRenderTarget: Cannot create with empty size");
+ return rt;
+ }
+
+ if (arraySize < 1) {
+ qWarning("QQuickRenderTarget: Texture array must have at least one element");
+ return rt;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::NativeTextureArray;
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+
+ auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromGL(format);
+ d->u.nativeTextureArray = { textureId, 0, arraySize, uint(rhiFormat), 0 };
+
+ return rt;
+}
+
+/*!
+ \overload
+
\return a new QQuickRenderTarget referencing an OpenGL texture
object specified by \a textureId. The texture is assumed to have a
format of GL_RGBA (GL_RGBA8).
@@ -445,6 +510,82 @@ QQuickRenderTarget QQuickRenderTarget::fromD3D12Texture(void *texture,
return rt;
}
+
+/*!
+ \overload
+
+ \return a new QQuickRenderTarget referencing a D3D12 texture array object
+ specified by \a texture. The number of array elements (layers) is given in
+ \a arraySize.
+
+ \note This implies multiview rendering (GL_OVR_multiview etc.), which can be
+ relevant with VR/AR especially. \a arraySize is the number of views,
+ typically \c 2. This overload should not be used other cases.
+ See \l QSGMaterial::viewCount() for details on enabling multiview rendering
+ within the Qt Quick scenegraph.
+
+ \a resourceState must a valid bitmask with bits from D3D12_RESOURCE_STATES,
+ specifying the resource's current state.
+
+ \a format specifies the DXGI_FORMAT of the texture. Only texture formats
+ that are supported by Qt's rendering infrastructure should be used.
+
+ \a pixelSize specifies the size of the image, in pixels. Currently only 2D
+ textures are supported.
+
+ \a sampleCount specific the number of samples. 0 or 1 means no
+ multisampling, while a value like 4 or 8 states that the native object is a
+ multisample texture.
+
+ The texture is used as the first color attachment of the render target used
+ by the Qt Quick scenegraph. A depth-stencil texture array with a matching
+ number of layers, sample count, and a format of \l{QRhiTexture::}{D24S8} is
+ created and used automatically.
+
+ \note the resulting QQuickRenderTarget does not own any native resources, it
+ merely contains references and the associated metadata of the size and
+ sample count. It is the caller's responsibility to ensure that the native
+ resource exists as long as necessary.
+
+ \since 6.8
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+ */
+QQuickRenderTarget QQuickRenderTarget::fromD3D12TextureMultiView(void *texture,
+ int resourceState,
+ uint format,
+ const QSize &pixelSize,
+ int sampleCount,
+ int arraySize)
+{
+ QQuickRenderTarget rt;
+ QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
+
+ if (!texture) {
+ qWarning("QQuickRenderTarget: texture is null");
+ return rt;
+ }
+
+ if (pixelSize.isEmpty()) {
+ qWarning("QQuickRenderTarget: Cannot create with empty size");
+ return rt;
+ }
+
+ if (arraySize < 1) {
+ qWarning("QQuickRenderTarget: Texture array must have at least one element");
+ return rt;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::NativeTextureArray;
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+
+ QRhiTexture::Flags flags;
+ auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(format, &flags);
+ d->u.nativeTextureArray = { quint64(texture), resourceState, arraySize, uint(rhiFormat), uint(flags) };
+
+ return rt;
+}
#endif
/*!
@@ -505,6 +646,74 @@ QQuickRenderTarget QQuickRenderTarget::fromMetalTexture(MTLTexture *texture, uin
/*!
\overload
+ \return a new QQuickRenderTarget referencing a Metal texture array object
+ with \a arraySize elements specified by \a texture.
+
+ \note This implies multiview rendering (GL_OVR_multiview etc.), which can be
+ relevant with VR/AR especially. \a arraySize is the number of views,
+ typically \c 2. This overload should not be used other cases.
+ See \l QSGMaterial::viewCount() for details on enabling multiview rendering
+ within the Qt Quick scenegraph.
+
+ \a format specifies the MTLPixelFormat of the texture. Only texture formats
+ that are supported by Qt's rendering infrastructure should be used.
+
+ \a pixelSize specifies the size of the image, in pixels. Currently only 2D
+ textures are supported.
+
+ \a sampleCount specific the number of samples. 0 or 1 means no
+ multisampling, while a value like 4 or 8 states that the native object is a
+ multisample texture.
+
+ The texture is used as the first color attachment of the render target used
+ by the Qt Quick scenegraph. A depth-stencil texture array with a matching
+ number of layers, sample count, and a format of \c D24S8 is created and used
+ automatically.
+
+ \note the resulting QQuickRenderTarget does not own any native resources, it
+ merely contains references and the associated metadata of the size and
+ sample count. It is the caller's responsibility to ensure that the native
+ resource exists as long as necessary.
+
+ \since 6.8
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+ */
+QQuickRenderTarget QQuickRenderTarget::fromMetalTextureMultiView(MTLTexture *texture, uint format,
+ const QSize &pixelSize, int sampleCount, int arraySize)
+{
+ QQuickRenderTarget rt;
+ QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
+
+ if (!texture) {
+ qWarning("QQuickRenderTarget: texture is null");
+ return rt;
+ }
+
+ if (pixelSize.isEmpty()) {
+ qWarning("QQuickRenderTarget: Cannot create with empty size");
+ return rt;
+ }
+
+ if (arraySize < 1) {
+ qWarning("QQuickRenderTarget: Texture array must have at least one element");
+ return rt;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::NativeTextureArray;
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+
+ QRhiTexture::Flags flags;
+ auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromMetal(format, &flags);
+ d->u.nativeTextureArray = { quint64(texture), 0, arraySize, uint(rhiFormat), uint(flags) };
+
+ return rt;
+}
+
+/*!
+ \overload
+
\return a new QQuickRenderTarget referencing a Metal texture object
specified by \a texture. The texture is assumed to have a format of
MTLPixelFormatRGBA8Unorm.
@@ -592,6 +801,75 @@ QQuickRenderTarget QQuickRenderTarget::fromVulkanImage(VkImage image, VkImageLay
/*!
\overload
+ \return a new QQuickRenderTarget referencing a Vulkan image object with
+ \a arraySize layers specified by \a image. The current \a layout of the image
+ must be provided as well.
+
+ \note This implies multiview rendering (GL_OVR_multiview etc.), which can be
+ relevant with VR/AR especially. \a arraySize is the number of views,
+ typically \c 2. This overload should not be used other cases.
+ See \l QSGMaterial::viewCount() for details on enabling multiview rendering
+ within the Qt Quick scenegraph.
+
+ \a format specifies the VkFormat of the image. Only image formats that are
+ supported by Qt's rendering infrastructure should be used.
+
+ \a pixelSize specifies the size of the image, in pixels. Currently only 2D
+ textures are supported.
+
+ \a sampleCount specific the number of samples. 0 or 1 means no
+ multisampling, while a value like 4 or 8 states that the native object is a
+ multisample texture.
+
+ The image is used as the first color attachment of the render target used by
+ the Qt Quick scenegraph. A depth-stencil texture array with a matching
+ number of layers, sample count, and a format of \c D24S8 is created and used
+ automatically.
+
+ \note the resulting QQuickRenderTarget does not own any native resources, it
+ merely contains references and the associated metadata of the size and
+ sample count. It is the caller's responsibility to ensure that the native
+ resource exists as long as necessary.
+
+ \since 6.8
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+ */
+QQuickRenderTarget QQuickRenderTarget::fromVulkanImageMultiView(VkImage image, VkImageLayout layout, VkFormat format,
+ const QSize &pixelSize, int sampleCount, int arraySize)
+{
+ QQuickRenderTarget rt;
+ QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
+
+ if (image == VK_NULL_HANDLE) {
+ qWarning("QQuickRenderTarget: image is invalid");
+ return rt;
+ }
+
+ if (pixelSize.isEmpty()) {
+ qWarning("QQuickRenderTarget: Cannot create with empty size");
+ return rt;
+ }
+
+ if (arraySize < 1) {
+ qWarning("QQuickRenderTarget: Texture array must have at least one element");
+ return rt;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::NativeTextureArray;
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+
+ QRhiTexture::Flags flags;
+ auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromVulkan(format, &flags);
+ d->u.nativeTextureArray = { quint64(image), layout, arraySize, uint(rhiFormat), uint(flags) };
+
+ return rt;
+}
+
+/*!
+ \overload
+
\return a new QQuickRenderTarget referencing a Vulkan image object specified
by \a image. The image is assumed to have a format of
VK_FORMAT_R8G8B8A8_UNORM.
@@ -716,6 +994,14 @@ bool QQuickRenderTarget::isEqual(const QQuickRenderTarget &other) const noexcept
|| d->u.nativeTexture.rhiFlags != other.d->u.nativeTexture.rhiFlags)
return false;
break;
+ case QQuickRenderTargetPrivate::Type::NativeTextureArray:
+ if (d->u.nativeTextureArray.object != other.d->u.nativeTextureArray.object
+ || d->u.nativeTextureArray.layoutOrState != other.d->u.nativeTextureArray.layoutOrState
+ || d->u.nativeTextureArray.arraySize != other.d->u.nativeTextureArray.arraySize
+ || d->u.nativeTextureArray.rhiFormat != other.d->u.nativeTextureArray.rhiFormat
+ || d->u.nativeTextureArray.rhiFlags != other.d->u.nativeTextureArray.rhiFlags)
+ return false;
+ break;
case QQuickRenderTargetPrivate::Type::NativeRenderbuffer:
if (d->u.nativeRenderbufferObject != other.d->u.nativeRenderbufferObject)
return false;
@@ -766,6 +1052,39 @@ static bool createRhiRenderTarget(const QRhiColorAttachment &colorAttachment,
return true;
}
+static bool createRhiRenderTargetMultiView(const QRhiColorAttachment &colorAttachment,
+ const QSize &pixelSize,
+ int arraySize,
+ int sampleCount,
+ QRhi *rhi,
+ QQuickWindowRenderTarget *dst)
+{
+ std::unique_ptr<QRhiTexture> depthStencil(rhi->newTextureArray(QRhiTexture::D24S8, arraySize, pixelSize, sampleCount, QRhiTexture::RenderTarget));
+ if (!depthStencil->create()) {
+ qWarning("Failed to build depth-stencil texture array for QQuickRenderTarget");
+ return false;
+ }
+
+ QRhiTextureRenderTargetDescription rtDesc(colorAttachment);
+ rtDesc.setDepthTexture(depthStencil.get());
+ std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
+ std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rp.get());
+
+ if (!rt->create()) {
+ qWarning("Failed to build multiview texture render target for QQuickRenderTarget");
+ return false;
+ }
+
+ dst->renderTarget = rt.release();
+ dst->rpDesc = rp.release();
+ dst->depthStencilTexture = depthStencil.release();
+ dst->multiViewCount = arraySize;
+ dst->owns = true; // ownership of the native resource itself is not transferred but the QRhi objects are on us now
+
+ return true;
+}
+
bool QQuickRenderTargetPrivate::resolve(QRhi *rhi, QQuickWindowRenderTarget *dst)
{
switch (type) {
@@ -792,6 +1111,25 @@ bool QQuickRenderTargetPrivate::resolve(QRhi *rhi, QQuickWindowRenderTarget *dst
}
return true;
+ case Type::NativeTextureArray:
+ {
+ const auto format = u.nativeTextureArray.rhiFormat == QRhiTexture::UnknownFormat ? QRhiTexture::RGBA8
+ : QRhiTexture::Format(u.nativeTextureArray.rhiFormat);
+ const auto flags = QRhiTexture::RenderTarget | QRhiTexture::Flags(u.nativeTextureArray.rhiFlags);
+ const int arraySize = u.nativeTextureArray.arraySize;
+ std::unique_ptr<QRhiTexture> texture(rhi->newTextureArray(format, arraySize, pixelSize, sampleCount, flags));
+ if (!texture->createFrom({ u.nativeTextureArray.object, u.nativeTextureArray.layoutOrState })) {
+ qWarning("Failed to build wrapper texture array for QQuickRenderTarget");
+ return false;
+ }
+ QRhiColorAttachment att(texture.get());
+ att.setMultiViewCount(arraySize);
+ if (!createRhiRenderTargetMultiView(att, pixelSize, arraySize, sampleCount, rhi, dst))
+ return false;
+ dst->texture = texture.release();
+ }
+ return true;
+
case Type::NativeRenderbuffer:
{
std::unique_ptr<QRhiRenderBuffer> renderbuffer(rhi->newRenderBuffer(QRhiRenderBuffer::Color, pixelSize, sampleCount));
diff --git a/src/quick/items/qquickrendertarget.h b/src/quick/items/qquickrendertarget.h
index 646bdd9813..1a181185ca 100644
--- a/src/quick/items/qquickrendertarget.h
+++ b/src/quick/items/qquickrendertarget.h
@@ -40,6 +40,7 @@ public:
#if QT_CONFIG(opengl) || defined(Q_QDOC)
static QQuickRenderTarget fromOpenGLTexture(uint textureId, uint format, const QSize &pixelSize, int sampleCount = 1);
static QQuickRenderTarget fromOpenGLTexture(uint textureId, const QSize &pixelSize, int sampleCount = 1);
+ static QQuickRenderTarget fromOpenGLTextureMultiView(uint textureId, uint format, const QSize &pixelSize, int sampleCount, int arraySize);
static QQuickRenderTarget fromOpenGLRenderBuffer(uint renderbufferId, const QSize &pixelSize, int sampleCount = 1);
#endif
@@ -47,16 +48,19 @@ public:
static QQuickRenderTarget fromD3D11Texture(void *texture, uint format, const QSize &pixelSize, int sampleCount = 1);
static QQuickRenderTarget fromD3D11Texture(void *texture, const QSize &pixelSize, int sampleCount = 1);
static QQuickRenderTarget fromD3D12Texture(void *texture, int resourceState, uint format, const QSize &pixelSize, int sampleCount = 1);
+ static QQuickRenderTarget fromD3D12TextureMultiView(void *texture, int resourceState, uint format, const QSize &pixelSize, int sampleCount, int arraySize);
#endif
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) || defined(Q_QDOC)
static QQuickRenderTarget fromMetalTexture(MTLTexture *texture, uint format, const QSize &pixelSize, int sampleCount = 1);
static QQuickRenderTarget fromMetalTexture(MTLTexture *texture, const QSize &pixelSize, int sampleCount = 1);
+ static QQuickRenderTarget fromMetalTextureMultiView(MTLTexture *texture, uint format, const QSize &pixelSize, int sampleCount, int arraySize);
#endif
#if QT_CONFIG(vulkan) || defined(Q_QDOC)
static QQuickRenderTarget fromVulkanImage(VkImage image, VkImageLayout layout, VkFormat format, const QSize &pixelSize, int sampleCount = 1);
static QQuickRenderTarget fromVulkanImage(VkImage image, VkImageLayout layout, const QSize &pixelSize, int sampleCount = 1);
+ static QQuickRenderTarget fromVulkanImageMultiView(VkImage image, VkImageLayout layout, VkFormat format, const QSize &pixelSize, int sampleCount, int arraySize);
#endif
static QQuickRenderTarget fromRhiRenderTarget(QRhiRenderTarget *renderTarget);
diff --git a/src/quick/items/qquickrendertarget_p.h b/src/quick/items/qquickrendertarget_p.h
index fd1fb2afd8..7f3190947e 100644
--- a/src/quick/items/qquickrendertarget_p.h
+++ b/src/quick/items/qquickrendertarget_p.h
@@ -36,6 +36,7 @@ public:
enum class Type {
Null,
NativeTexture,
+ NativeTextureArray,
NativeRenderbuffer,
RhiRenderTarget,
PaintDevice
@@ -52,8 +53,16 @@ public:
uint rhiFormat;
uint rhiFlags;
};
+ struct NativeTextureArray {
+ quint64 object;
+ int layoutOrState;
+ int arraySize;
+ uint rhiFormat;
+ uint rhiFlags;
+ };
union {
NativeTexture nativeTexture;
+ NativeTextureArray nativeTextureArray;
quint64 nativeRenderbufferObject;
QRhiRenderTarget *rhiRt;
QPaintDevice *paintDevice;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 1893c269cb..36bfc52aeb 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -484,6 +484,7 @@ void QQuickWindowRenderTarget::reset(QRhi *rhi)
delete texture;
delete renderBuffer;
delete depthStencil;
+ delete depthStencilTexture;
}
delete paintDevice;
@@ -494,6 +495,7 @@ void QQuickWindowRenderTarget::reset(QRhi *rhi)
texture = nullptr;
renderBuffer = nullptr;
depthStencil = nullptr;
+ depthStencilTexture = nullptr;
paintDevice = nullptr;
owns = false;
multiViewCount = 1;
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index cfec6991da..9c45ccb9ca 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -81,6 +81,7 @@ public:
QRhiTexture *texture = nullptr;
QRhiRenderBuffer *renderBuffer = nullptr;
QRhiRenderBuffer *depthStencil = nullptr;
+ QRhiTexture *depthStencilTexture = nullptr; // for multiview
QPaintDevice *paintDevice = nullptr;
bool owns = false;
int multiViewCount = 1;
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index bdbc6ee73c..99c70a6c38 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -407,12 +407,13 @@ int QSGMaterial::compare(const QSGMaterial *other) const
)
\endcode
- See \l QRhi::MultiView, \l QRhiColorAttachment::setMultiViewCount(), and \l
- QRhiGraphicsPipeline::setMultiViewCount() for further, lower-level details
- on multiview support in Qt. The Qt Quick scene graph renderer is prepared
- to recognize multiview render targets, when specified via
- \l QQuickRenderTarget::fromRhiRenderTarget(), and propagate the view count to
- graphics pipelines and the materials.
+ See \l QRhi::MultiView, \l QRhiColorAttachment::setMultiViewCount(), and
+ \l QRhiGraphicsPipeline::setMultiViewCount() for further, lower-level details
+ on multiview support in Qt. The Qt Quick scene graph renderer is prepared to
+ recognize multiview render targets, when specified via
+ \l QQuickRenderTarget::fromRhiRenderTarget() or the \c MultiView
+ functions such as \l{QQuickRenderTarget::}{fromVulkanImageMultiView()}, and
+ propagate the view count to graphics pipelines and the materials.
\since 6.8
*/