aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickrendertarget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickrendertarget.cpp')
-rw-r--r--src/quick/items/qquickrendertarget.cpp1777
1 files changed, 1777 insertions, 0 deletions
diff --git a/src/quick/items/qquickrendertarget.cpp b/src/quick/items/qquickrendertarget.cpp
new file mode 100644
index 0000000000..55bbf22eee
--- /dev/null
+++ b/src/quick/items/qquickrendertarget.cpp
@@ -0,0 +1,1777 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquickrendertarget_p.h"
+#include <rhi/qrhi.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickwindow_p.h>
+#include <QtQuick/private/qsgrhisupport_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QQuickRenderTarget
+ \since 6.0
+ \inmodule QtQuick
+
+ \brief The QQuickRenderTarget class provides an opaque container for native
+ graphics resources specifying a render target, and associated metadata.
+
+ \sa QQuickWindow::setRenderTarget(), QQuickGraphicsDevice
+*/
+
+QQuickRenderTargetPrivate::QQuickRenderTargetPrivate()
+ : ref(1)
+{
+}
+
+QQuickRenderTargetPrivate::QQuickRenderTargetPrivate(const QQuickRenderTargetPrivate &other)
+ : ref(1),
+ type(other.type),
+ pixelSize(other.pixelSize),
+ devicePixelRatio(other.devicePixelRatio),
+ sampleCount(other.sampleCount),
+ u(other.u),
+ customDepthTexture(other.customDepthTexture),
+ mirrorVertically(other.mirrorVertically),
+ multisampleResolve(other.multisampleResolve)
+{
+}
+
+/*!
+ Constructs a default QQuickRenderTarget that does not reference any native
+ objects.
+ */
+QQuickRenderTarget::QQuickRenderTarget()
+ : d(new QQuickRenderTargetPrivate)
+{
+}
+
+/*!
+ \internal
+ */
+void QQuickRenderTarget::detach()
+{
+ qAtomicDetach(d);
+}
+
+/*!
+ \internal
+ */
+QQuickRenderTarget::QQuickRenderTarget(const QQuickRenderTarget &other)
+ : d(other.d)
+{
+ d->ref.ref();
+}
+
+/*!
+ \internal
+ */
+QQuickRenderTarget &QQuickRenderTarget::operator=(const QQuickRenderTarget &other)
+{
+ qAtomicAssign(d, other.d);
+ return *this;
+}
+
+/*!
+ Destructor.
+ */
+QQuickRenderTarget::~QQuickRenderTarget()
+{
+ if (!d->ref.deref())
+ delete d;
+}
+
+/*!
+ \return true if this QQuickRenderTarget is default constructed, referencing
+ no native objects.
+ */
+bool QQuickRenderTarget::isNull() const
+{
+ return d->type == QQuickRenderTargetPrivate::Type::Null;
+}
+
+/*!
+ \return the device pixel ratio for the render target. This is the ratio
+ between \e{device pixels} and \e{device independent pixels}.
+
+ The default device pixel ratio is 1.0.
+
+ \since 6.3
+
+ \sa setDevicePixelRatio()
+*/
+qreal QQuickRenderTarget::devicePixelRatio() const
+{
+ return d->devicePixelRatio;
+}
+
+/*!
+ Sets the device pixel ratio for this render target to \a ratio. This is
+ the ratio between \e{device pixels} and \e{device independent pixels}.
+
+ Note that the specified device pixel ratio value will be ignored if
+ QQuickRenderControl::renderWindow() is re-implemented to return a valid
+ QWindow.
+
+ \since 6.3
+
+ \sa devicePixelRatio()
+*/
+void QQuickRenderTarget::setDevicePixelRatio(qreal ratio)
+{
+ if (d->devicePixelRatio == ratio)
+ return;
+
+ detach();
+ d->devicePixelRatio = ratio;
+}
+
+/*!
+ \return Returns whether the render target is mirrored vertically.
+
+ The default value is \c {false}.
+
+ \since 6.4
+
+ \sa setMirrorVertically()
+*/
+bool QQuickRenderTarget::mirrorVertically() const
+{
+ return d->mirrorVertically;
+}
+
+
+/*!
+ Sets the size of the render target contents should be mirrored vertically to
+ \a enable when drawing. This allows easy integration of third-party rendering
+ code that does not follow the standard expectations.
+
+ \note This function should not be used when using the \c software backend.
+
+ \since 6.4
+
+ \sa mirrorVertically()
+ */
+void QQuickRenderTarget::setMirrorVertically(bool enable)
+{
+ if (d->mirrorVertically == enable)
+ return;
+
+ detach();
+ d->mirrorVertically = enable;
+}
+
+/*!
+ \return the currently set depth texture or, in most cases, \nullptr.
+
+ The value is only non-null when setDepthTexture() was called.
+
+ \since 6.8
+ */
+QRhiTexture *QQuickRenderTarget::depthTexture() const
+{
+ return d->customDepthTexture;
+}
+
+/*!
+ Requests using the given \a texture as the depth or depth-stencil buffer.
+ Ownership of \a texture is not taken.
+
+ The request is only taken into account when relevant. For example, calling
+ this function has no effect with fromRhiRenderTarget(), fromPaintDevice(),
+ or fromOpenGLRenderBuffer().
+
+ Normally a depth-stencil buffer is created automatically, transparently to
+ the user of QQuickRenderTarget. Therefore, there is no need to call this
+ function in most cases when working with QQuickRenderTarget. In special
+ circumstances, it can however become essential to be able to provide a
+ texture to render depth (or depth and stencil) data into, instead of letting
+ Qt Quick create its own intermediate textures or buffers. An example of this
+ is \l{https://www.khronos.org/openxr/}{OpenXR} and its extensions such as
+ \l{https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_KHR_composition_layer_depth}{XR_KHR_composition_layer_depth}.
+ In order to "submit the depth buffer" to the XR compositor, one has to, in
+ practice, retrieve an already created depth (depth-stencil) texture from
+ OpenXR (from the XrSwapchain) and use that texture as the render target for
+ depth data. That would not be possible without this function.
+
+ \note The \a texture is always expected to be a non-multisample 2D texture
+ or texture array (for multiview). If MSAA is involved, the samples are
+ resolved into \a texture at the end of the render pass, regardless of having
+ the MultisampleResolve flag set or not. MSAA is only supported for depth
+ (depth-stencil) textures when the underlying 3D API supports this, and this
+ support is not universally available. See \l{QRhi::ResolveDepthStencil}{the
+ relevant QRhi feature flag} for details. When this is not supported and
+ multisampling is requested in combination with a custom depth texture, \a
+ texture is not going to be touched during rendering and a warning is
+ printed.
+
+ \since 6.8
+
+ \note When it comes to OpenGL and OpenGL ES, using depth textures is not
+ functional on OpenGL ES 2.0 and requires at least OpenGL ES 3.0. Multisample
+ (MSAA) support is not available without at least OpenGL ES 3.1, or OpenGL
+ 3.0 on desktop.
+ */
+void QQuickRenderTarget::setDepthTexture(QRhiTexture *texture)
+{
+ if (d->customDepthTexture == texture)
+ return;
+
+ detach();
+ d->customDepthTexture = texture;
+}
+
+/*!
+ \enum QQuickRenderTarget::Flag
+ Flags for the static QQuickRenderTarget constructor functions.
+
+ \value MultisampleResolve Indicates that the \c sampleCount argument is not
+ the number of samples for the provided texture (and that the texture is
+ still a non-multisample texture), but rather the desired samples for
+ multisample antialiasing. Triggers automatically creating and managing an
+ intermediate multisample texture (or texture array) as the color buffer,
+ transparently to the application. The samples are resolved into the provided
+ texture at the end of the render pass automatically. When this flag is not
+ set, and the \c sampleCount argument is greater than 1, it implies the
+ provided texture is multisample. The flag has no effect is the
+ \c sampleCount is 1 (indicating that multisampling is not involved).
+
+ \since 6.8
+*/
+
+/*!
+ \return a new QQuickRenderTarget referencing an OpenGL texture object
+ specified by \a textureId.
+
+ \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. Currently only 2D
+ textures are supported.
+
+ \a sampleCount specifies 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 buffer, if applicable, is
+ created and used automatically.
+
+ The OpenGL object name \a textureId must be a valid name in the rendering
+ context used by the Qt Quick scenegraph.
+
+ \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.4
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+ */
+#if QT_CONFIG(opengl) || defined(Q_QDOC)
+QQuickRenderTarget QQuickRenderTarget::fromOpenGLTexture(uint textureId, uint format,
+ const QSize &pixelSize, int sampleCount)
+{
+ 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;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+
+ QRhiTexture::Flags formatFlags;
+ QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromGL(format, &formatFlags);
+ d->u.nativeTexture = { textureId, 0, uint(rhiFormat), uint(formatFlags), uint(rhiFormat), uint(formatFlags) };
+
+ 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).
+
+ \a pixelSize specifies the size of the image, in pixels. Currently
+ only 2D textures are supported.
+
+ \a sampleCount specifies 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 buffer, if applicable, is
+ created and used automatically.
+
+ The OpenGL object name \a textureId must be a valid name in the rendering
+ context used by the Qt Quick scenegraph.
+
+ \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.
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+*/
+QQuickRenderTarget QQuickRenderTarget::fromOpenGLTexture(uint textureId, const QSize &pixelSize, int sampleCount)
+{
+ return fromOpenGLTexture(textureId, 0, pixelSize, sampleCount);
+}
+
+/*!
+ \overload
+
+ \return a new QQuickRenderTarget referencing an OpenGL 2D texture or texture
+ array object specified by \a textureId.
+
+ \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. Currently only 2D
+ textures and 2D texture arrays are supported.
+
+ \a sampleCount specifies 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, except when \a flags contains \l MultisampleResolve. In
+ that case, \a textureId is assumed to be a non-multisample 2D texture or 2D
+ texture array, and \a sampleCount defines the number of samples desired. The
+ resulting QQuickRenderTarget will use an intermediate, automatically created
+ multisample texture (or texture array) as its color attachment, and will
+ resolve the samples into \a textureId. This is the recommended approach to
+ perform MSAA when the native OpenGL texture is not already multisample.
+
+ When \a arraySize is greater than 1, it implies multiview rendering
+ (\l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview.txt}{GL_OVR_multiview},
+ \l QRhiColorAttachment::setMultiViewCount()), which can be relevant with
+ VR/AR especially. In this case \a arraySize is the number of views,
+ typically \c 2. See \l QSGMaterial::viewCount() for details on enabling
+ multiview rendering within the Qt Quick scenegraph.
+
+ A depth-stencil buffer, if applicable, is created and used automatically.
+ When the color buffer is multisample, the depth-stencil buffer will
+ automatically be multisample too. For multiview rendering, the depth-stencil
+ texture will automatically be made an array with a matching \a arraySize.
+
+ The OpenGL object name \a textureId must be a valid 2D texture name in the
+ rendering context used by the Qt Quick scenegraph. When \a arraySize is
+ greater than 1, \a textureId must be a valid 2D texture array name.
+
+ \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
+
+ \note The implementation of this overload is not compatible with OpenGL ES
+ 2.0 or 3.0, and requires OpenGL ES 3.1 at minimum. (or OpenGL 3.0 on
+ desktop)
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl, fromOpenGLTexture()
+ */
+QQuickRenderTarget QQuickRenderTarget::fromOpenGLTexture(uint textureId, uint format, const QSize &pixelSize, int sampleCount, int arraySize, Flags flags)
+{
+ 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;
+ }
+
+ QRhiTexture::Flags formatFlags;
+ QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromGL(format, &formatFlags);
+
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+ d->multisampleResolve = flags.testFlag(Flag::MultisampleResolve);
+
+ if (arraySize <= 1) {
+ d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
+ d->u.nativeTexture = { textureId, 0, uint(rhiFormat), uint(formatFlags), uint(rhiFormat), uint(formatFlags) };
+ } else {
+ d->type = QQuickRenderTargetPrivate::Type::NativeTextureArray;
+ d->u.nativeTextureArray = { textureId, 0, arraySize, uint(rhiFormat), uint(formatFlags), uint(rhiFormat), uint(formatFlags) };
+ }
+
+ return rt;
+}
+
+/*!
+ \return a new QQuickRenderTarget referencing an OpenGL renderbuffer object
+ specified by \a renderbufferId.
+
+ The renderbuffer will be used as the color attachment for the internal
+ framebuffer object. This function is provided to allow targeting
+ renderbuffers that are created by the application with some external buffer
+ underneath, such as an EGLImageKHR. Once the application has called
+ \l{https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image.txt}{glEGLImageTargetRenderbufferStorageOES},
+ the renderbuffer can be passed to this function.
+
+ \a pixelSize specifies the size of the image, in pixels.
+
+ \a sampleCount specifies 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 renderbuffer.
+
+ \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.2
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+ */
+QQuickRenderTarget QQuickRenderTarget::fromOpenGLRenderBuffer(uint renderbufferId, const QSize &pixelSize, int sampleCount)
+{
+ QQuickRenderTarget rt;
+ QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
+
+ if (!renderbufferId) {
+ qWarning("QQuickRenderTarget: renderbufferId is invalid");
+ return rt;
+ }
+
+ if (pixelSize.isEmpty()) {
+ qWarning("QQuickRenderTarget: Cannot create with empty size");
+ return rt;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::NativeRenderbuffer;
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+ d->u.nativeRenderbufferObject = renderbufferId;
+
+ return rt;
+}
+#endif
+
+/*!
+ \return a new QQuickRenderTarget referencing a D3D11 texture object
+ specified by \a texture.
+
+ \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 specifies 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 buffer, if applicable, 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.4
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+ */
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
+QQuickRenderTarget QQuickRenderTarget::fromD3D11Texture(void *texture, uint format,
+ const QSize &pixelSize, int sampleCount)
+{
+ 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;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+
+ QRhiTexture::Flags formatFlags;
+ QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(format, &formatFlags);
+ d->u.nativeTexture = { quint64(texture), 0, uint(rhiFormat), uint(formatFlags), uint(rhiFormat), uint(formatFlags) };
+
+ return rt;
+}
+
+/*!
+ \overload
+
+ \return a new QQuickRenderTarget referencing a D3D11 texture
+ object specified by \a texture. The texture is assumed to have a
+ format of DXGI_FORMAT_R8G8B8A8_UNORM.
+
+ \a pixelSize specifies the size of the image, in pixels. Currently only 2D
+ textures are supported.
+
+ \a sampleCount specifies 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 buffer, if applicable, 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.
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+*/
+QQuickRenderTarget QQuickRenderTarget::fromD3D11Texture(void *texture, const QSize &pixelSize, int sampleCount)
+{
+ return fromD3D11Texture(texture, 0 /* DXGI_FORMAT_UNKNOWN */, pixelSize, sampleCount);
+}
+
+/*!
+ \overload
+
+ \return a new QQuickRenderTarget referencing a D3D11 texture object
+ specified by \a texture.
+
+ \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 specifies 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, except when \a flags contains \l MultisampleResolve. In
+ that case, \a texture is assumed to be a non-multisample 2D texture and \a
+ sampleCount defines the number of samples desired. The resulting
+ QQuickRenderTarget will use an intermediate, automatically created
+ multisample texture as its color attachment, and will resolve the samples
+ into \a texture. This is the recommended approach to perform MSAA when the
+ native texture is not already multisample.
+
+ The texture is used as the first color attachment of the render target used
+ by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
+ created and used automatically. When the color buffer is multisample, the
+ depth-stencil buffer will automatically be multisample too.
+
+ \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, fromD3D11Texture()
+ */
+QQuickRenderTarget QQuickRenderTarget::fromD3D11Texture(void *texture, uint format, const QSize &pixelSize, int sampleCount, Flags flags)
+{
+ QQuickRenderTarget rt = fromD3D11Texture(texture, format, pixelSize, sampleCount);
+ QQuickRenderTargetPrivate::get(&rt)->multisampleResolve = flags.testFlag(Flag::MultisampleResolve);
+ return rt;
+}
+
+/*!
+ \return a new QQuickRenderTarget referencing a D3D12 texture object
+ specified by \a texture.
+
+ \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 specifies 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 buffer, if applicable, 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.6
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+ */
+QQuickRenderTarget QQuickRenderTarget::fromD3D12Texture(void *texture,
+ int resourceState,
+ uint format,
+ const QSize &pixelSize,
+ int sampleCount)
+{
+ 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;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+
+ QRhiTexture::Flags formatFlags;
+ QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(format, &formatFlags);
+ d->u.nativeTexture = { quint64(texture), resourceState, uint(rhiFormat), uint(formatFlags), uint(rhiFormat), uint(formatFlags) };
+
+ return rt;
+}
+
+/*!
+ \overload
+
+ \return a new QQuickRenderTarget referencing a D3D12 2D texture or 2D
+ texture array object specified by \a texture.
+
+ \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 viewFormat is the DXGI_FORMAT used for the render target view (RTV).
+ Often the same as \a format. Functional only when
+ \l{https://microsoft.github.io/DirectX-Specs/d3d/RelaxedCasting.html}{relaxed
+ format casting} is supported by the driver, the argument is ignored otherwise.
+ In practice support is expected to be always available on Windows 10 1703
+ and newer.
+
+ \a pixelSize specifies the size of the image, in pixels. Currently only 2D
+ textures and 2D texture arrays are supported.
+
+ \a sampleCount specifies 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, except when \a flags contains \l MultisampleResolve. In
+ that case, \a texture is assumed to be a non-multisample 2D texture or 2D
+ texture array, and \a sampleCount defines the number of samples desired. The
+ resulting QQuickRenderTarget will use an intermediate, automatically created
+ multisample texture (or texture array) as its color attachment, and will
+ resolve the samples into \a texture. This is the recommended approach to
+ perform MSAA when the native D3D12 texture is not already multisample.
+
+ The number of array elements (layers) is given in \a arraySize. When greater
+ than 1, it implies multiview rendering
+ (\l{https://microsoft.github.io/DirectX-Specs/d3d/ViewInstancing.html}{view
+ instancing}), which can be relevant with VR/AR especially. \a arraySize is
+ the number of views, typically \c 2. See \l QSGMaterial::viewCount() for
+ details on enabling multiview rendering within the Qt Quick scenegraph.
+
+ The texture is used as the first color attachment of the render target used
+ by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
+ created and used automatically. When the color buffer is multisample, the
+ depth-stencil buffer will automatically be multisample too. For multiview
+ rendering, the depth-stencil texture will automatically be made an array
+ with a matching \a arraySize.
+
+ \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::fromD3D12Texture(void *texture,
+ int resourceState,
+ uint format,
+ uint viewFormat,
+ const QSize &pixelSize,
+ int sampleCount,
+ int arraySize,
+ Flags flags)
+{
+ 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;
+ }
+
+ QRhiTexture::Flags formatFlags;
+ QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(format, &formatFlags);
+ QRhiTexture::Flags viewFormatFlags;
+ QRhiTexture::Format rhiViewFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(viewFormat, &viewFormatFlags);
+
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+ d->multisampleResolve = flags.testFlag(Flag::MultisampleResolve);
+
+ if (arraySize <= 1) {
+ d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
+ d->u.nativeTexture = { quint64(texture), resourceState, uint(rhiFormat), uint(formatFlags), uint(rhiViewFormat), uint(viewFormatFlags) };
+ } else {
+ d->type = QQuickRenderTargetPrivate::Type::NativeTextureArray;
+ d->u.nativeTextureArray = { quint64(texture), resourceState, arraySize, uint(rhiFormat), uint(formatFlags), uint(rhiViewFormat), uint(viewFormatFlags) };
+ }
+
+ return rt;
+}
+
+#endif // Q_OS_WIN
+
+/*!
+ \return a new QQuickRenderTarget referencing a Metal texture object
+ specified by \a texture.
+
+ \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 specifies 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 buffer, if applicable, 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.4
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+ */
+#if QT_CONFIG(metal) || defined(Q_QDOC)
+QQuickRenderTarget QQuickRenderTarget::fromMetalTexture(MTLTexture *texture, uint format,
+ const QSize &pixelSize, int sampleCount)
+{
+ 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;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+
+ QRhiTexture::Flags formatFlags;
+ QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromMetal(format, &formatFlags);
+ d->u.nativeTexture = { quint64(texture), 0, uint(rhiFormat), uint(formatFlags), uint(rhiFormat), uint(formatFlags) };
+
+ 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.
+
+ \a pixelSize specifies the size of the image, in pixels. Currently only 2D
+ textures are supported.
+
+ \a sampleCount specifies 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 buffer, if applicable, 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.
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+*/
+QQuickRenderTarget QQuickRenderTarget::fromMetalTexture(MTLTexture *texture, const QSize &pixelSize, int sampleCount)
+{
+ return fromMetalTexture(texture, 0 /* MTLPixelFormatInvalid */, pixelSize, sampleCount);
+}
+
+/*!
+ \overload
+
+ \return a new QQuickRenderTarget referencing a Metal 2D texture or 2D
+ texture array given in \a texture.
+
+ \a format specifies the MTLPixelFormat of the texture. Only texture formats
+ that are supported by Qt's rendering infrastructure should be used.
+
+ \a viewFormat is usually set to the same value as \a format. In some cases,
+ such as when rendering into a texture with a \c{_SRGB} format and the
+ implicit linear->sRGB conversion on shader writes is not wanted, the value
+ can be different. Note however that the value may be ignored by Qt, when at
+ run time QRhi reports that the \l{QRhi::TextureViewFormat} feature is
+ unsupported.
+
+ \a pixelSize specifies the size of the image, in pixels. Currently only 2D
+ textures and 2D texture arrays are supported.
+
+ \a sampleCount specifies 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, except when \a flags contains \l MultisampleResolve. In
+ that case, \a texture is assumed to be a non-multisample 2D texture or 2D
+ texture array, and \a sampleCount defines the number of samples desired. The
+ resulting QQuickRenderTarget will use an intermediate, automatically created
+ multisample texture (or texture array) as its color attachment, and will
+ resolve the samples into \a texture. This is the recommended approach to
+ perform MSAA when the native Metal texture is not already multisample.
+
+ The number of array elements (layers) is given in \a arraySize. When greater
+ than 1, it implies multiview rendering, which can be relevant with VR/AR
+ especially. \a arraySize is the number of views, typically \c 2. See
+ \l QSGMaterial::viewCount() for details on enabling multiview rendering within
+ the Qt Quick scenegraph.
+
+ The texture is used as the first color attachment of the render target used
+ by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
+ created and used automatically. When the color buffer is multisample, the
+ depth-stencil buffer will automatically be multisample too. For multiview
+ rendering, the depth-stencil texture will automatically be made an array
+ with a matching \a arraySize.
+
+ \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::fromMetalTexture(MTLTexture *texture, uint format, uint viewFormat,
+ const QSize &pixelSize, int sampleCount, int arraySize, Flags flags)
+{
+ 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;
+ }
+
+ QRhiTexture::Flags formatFlags;
+ QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromMetal(format, &formatFlags);
+ QRhiTexture::Flags viewFormatFlags;
+ QRhiTexture::Format rhiViewFormat = QSGRhiSupport::toRhiTextureFormatFromMetal(viewFormat, &viewFormatFlags);
+
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+ d->multisampleResolve = flags.testFlag(Flag::MultisampleResolve);
+
+ if (arraySize <= 1) {
+ d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
+ d->u.nativeTexture = { quint64(texture), 0, uint(rhiFormat), uint(formatFlags), uint(rhiViewFormat), uint(viewFormatFlags) };
+ } else {
+ d->type = QQuickRenderTargetPrivate::Type::NativeTextureArray;
+ d->u.nativeTextureArray = { quint64(texture), 0, arraySize, uint(rhiFormat), uint(formatFlags), uint(rhiViewFormat), uint(viewFormatFlags) };
+ }
+
+ return rt;
+}
+
+#endif
+
+/*!
+ \return a new QQuickRenderTarget referencing a Vulkan image object
+ specified by \a image. The current \a layout of the image must be provided
+ as well.
+
+ \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 specifies 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 buffer, if applicable, 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.4
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+ */
+#if QT_CONFIG(vulkan) || defined(Q_QDOC)
+QQuickRenderTarget QQuickRenderTarget::fromVulkanImage(VkImage image, VkImageLayout layout, VkFormat format, const QSize &pixelSize, int sampleCount)
+{
+ 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;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+
+ QRhiTexture::Flags formatFlags;
+ QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromVulkan(format, &formatFlags);
+ d->u.nativeTexture = { quint64(image), layout, uint(rhiFormat), uint(formatFlags), uint(rhiFormat), uint(formatFlags) };
+
+ 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.
+
+ \a pixelSize specifies the size of the image, in pixels. Currently only 2D
+ textures are supported.
+
+ \a sampleCount specifies 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 buffer, if applicable, 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.
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+*/
+QQuickRenderTarget QQuickRenderTarget::fromVulkanImage(VkImage image, VkImageLayout layout, const QSize &pixelSize, int sampleCount)
+{
+ return fromVulkanImage(image, layout, VK_FORMAT_UNDEFINED, pixelSize, sampleCount);
+}
+
+/*!
+ \overload
+
+ \return a new QQuickRenderTarget referencing a Vulkan image object
+ specified by \a image. The current \a layout of the image must be provided
+ as well. The image must be either a 2D texture or 2D texture array.
+
+ \a format specifies the VkFormat of the image. Only image formats that are
+ supported by Qt's rendering infrastructure should be used.
+
+ \a viewFormat is usually set to the same value as \a format. In some cases,
+ such as when rendering into a texture with a \c{_SRGB} format and the
+ implicit linear->sRGB conversion on shader writes is not wanted, the value
+ can be different. (for example, a \a format of \c VK_FORMAT_R8G8B8A8_SRGB
+ and \a viewFormat of \c VK_FORMAT_R8G8B8A8_UNORM).
+
+ \a pixelSize specifies the size of the image, in pixels. Currently only 2D
+ textures are supported.
+
+ \a sampleCount specifies 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, except when \a flags contains \l MultisampleResolve. In
+ that case, \a image is assumed to be a non-multisample 2D texture or 2D
+ texture array, and \a sampleCount defines the number of samples desired. The
+ resulting QQuickRenderTarget will use an intermediate, automatically created
+ multisample texture (or texture array) as its color attachment, and will
+ resolve the samples into \a image. This is the recommended approach to
+ perform MSAA when the native Vulkan image is not already multisample.
+
+ The number of array elements (layers) is given in \a arraySize. When greater
+ than 1, it implies multiview rendering
+ (\l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_multiview.html}{VK_KHR_multiview}),
+ which can be relevant with VR/AR especially. \a arraySize is the number of
+ views, typically \c 2. See \l QSGMaterial::viewCount() for details on
+ enabling multiview rendering within the Qt Quick scenegraph.
+
+ The texture is used as the first color attachment of the render target used
+ by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
+ created and used automatically. When the color buffer is multisample, the
+ depth-stencil buffer will automatically be multisample too. For multiview
+ rendering, the depth-stencil texture will automatically be made an array
+ with a matching \a arraySize.
+
+ \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::fromVulkanImage(VkImage image, VkImageLayout layout, VkFormat format, VkFormat viewFormat,
+ const QSize &pixelSize, int sampleCount, int arraySize, Flags flags)
+{
+ 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;
+ }
+
+ QRhiTexture::Flags formatFlags;
+ QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromVulkan(format, &formatFlags);
+ QRhiTexture::Flags viewFormatFlags;
+ QRhiTexture::Format rhiViewFormat = QSGRhiSupport::toRhiTextureFormatFromVulkan(viewFormat, &viewFormatFlags);
+
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+ d->multisampleResolve = flags.testFlag(Flag::MultisampleResolve);
+
+ if (arraySize <= 1) {
+ d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
+ d->u.nativeTexture = { quint64(image), layout, uint(rhiFormat), uint(formatFlags), uint(rhiViewFormat), uint(viewFormatFlags) };
+ } else {
+ d->type = QQuickRenderTargetPrivate::Type::NativeTextureArray;
+ d->u.nativeTextureArray = { quint64(image), layout, arraySize, uint(rhiFormat), uint(formatFlags), uint(rhiViewFormat), uint(viewFormatFlags) };
+ }
+
+ return rt;
+}
+
+#endif // Vulkan
+
+/*!
+ \return a new QQuickRenderTarget referencing an existing \a renderTarget.
+
+ \a renderTarget will in most cases be a QRhiTextureRenderTarget, which
+ allows directing the Qt Quick scene's rendering into a QRhiTexture.
+
+ \note the resulting QQuickRenderTarget does not own \a renderTarget and any
+ underlying 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 referenced resources exists as long as
+ necessary.
+
+ \since 6.6
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+*/
+QQuickRenderTarget QQuickRenderTarget::fromRhiRenderTarget(QRhiRenderTarget *renderTarget)
+{
+ QQuickRenderTarget rt;
+ QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
+
+ if (!renderTarget) {
+ qWarning("QQuickRenderTarget: Needs a valid QRhiRenderTarget");
+ return rt;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::RhiRenderTarget;
+ d->pixelSize = renderTarget->pixelSize();
+ d->sampleCount = renderTarget->sampleCount();
+ d->u.rhiRt = renderTarget;
+
+ return rt;
+}
+
+/*!
+ \return a new QQuickRenderTarget referencing a paint device object
+ specified by \a device.
+
+ This option of redirecting rendering to a QPaintDevice is available only
+ when running with the \c software backend of Qt Quick.
+
+ \note The QQuickRenderTarget does not take ownship of \a device, it is the
+ caller's responsibility to ensure the object exists as long as necessary.
+
+ \since 6.4
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+ */
+QQuickRenderTarget QQuickRenderTarget::fromPaintDevice(QPaintDevice *device)
+{
+ QQuickRenderTarget rt;
+ QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
+
+ d->type = QQuickRenderTargetPrivate::Type::PaintDevice;
+ d->pixelSize = QSize(device->width(), device->height());
+ d->u.paintDevice = device;
+
+ return rt;
+}
+
+/*!
+ \fn bool QQuickRenderTarget::operator==(const QQuickRenderTarget &a, const QQuickRenderTarget &b) noexcept
+ \return true if \a a and \a b refer to the same set of native objects and
+ have matching associated data (size, sample count).
+*/
+/*!
+ \fn bool QQuickRenderTarget::operator!=(const QQuickRenderTarget &a, const QQuickRenderTarget &b) noexcept
+
+ \return true if \a a and \a b refer to a different set of native objects,
+ or the associated data (size, sample count) does not match.
+*/
+
+/*!
+ \internal
+*/
+bool QQuickRenderTarget::isEqual(const QQuickRenderTarget &other) const noexcept
+{
+ if (d->type != other.d->type
+ || d->pixelSize != other.d->pixelSize
+ || d->devicePixelRatio != other.d->devicePixelRatio
+ || d->sampleCount != other.d->sampleCount
+ || d->mirrorVertically != other.d->mirrorVertically
+ || d->multisampleResolve != other.d->multisampleResolve)
+ {
+ return false;
+ }
+
+ switch (d->type) {
+ case QQuickRenderTargetPrivate::Type::Null:
+ break;
+ case QQuickRenderTargetPrivate::Type::NativeTexture:
+ if (d->u.nativeTexture.object != other.d->u.nativeTexture.object
+ || d->u.nativeTexture.layoutOrState != other.d->u.nativeTexture.layoutOrState
+ || d->u.nativeTexture.rhiFormat != other.d->u.nativeTexture.rhiFormat
+ || d->u.nativeTexture.rhiFormatFlags != other.d->u.nativeTexture.rhiFormatFlags
+ || d->u.nativeTexture.rhiViewFormat != other.d->u.nativeTexture.rhiViewFormat
+ || d->u.nativeTexture.rhiViewFormatFlags != other.d->u.nativeTexture.rhiViewFormatFlags)
+ 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.rhiFormatFlags != other.d->u.nativeTextureArray.rhiFormatFlags
+ || d->u.nativeTextureArray.rhiViewFormat != other.d->u.nativeTextureArray.rhiViewFormat
+ || d->u.nativeTextureArray.rhiViewFormatFlags != other.d->u.nativeTextureArray.rhiViewFormatFlags)
+ return false;
+ break;
+ case QQuickRenderTargetPrivate::Type::NativeRenderbuffer:
+ if (d->u.nativeRenderbufferObject != other.d->u.nativeRenderbufferObject)
+ return false;
+ break;
+ case QQuickRenderTargetPrivate::Type::RhiRenderTarget:
+ if (d->u.rhiRt != other.d->u.rhiRt)
+ return false;
+ break;
+ case QQuickRenderTargetPrivate::Type::PaintDevice:
+ if (d->u.paintDevice != other.d->u.paintDevice)
+ return false;
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static bool createRhiRenderTargetWithRenderBuffer(QRhiRenderBuffer *renderBuffer,
+ const QSize &pixelSize,
+ int sampleCount,
+ QRhi *rhi,
+ QQuickWindowRenderTarget *dst)
+{
+ sampleCount = QSGRhiSupport::chooseSampleCount(sampleCount, rhi);
+
+ std::unique_ptr<QRhiRenderBuffer> depthStencil;
+ if (dst->implicitBuffers.depthStencil) {
+ if (dst->implicitBuffers.depthStencil->pixelSize() == pixelSize
+ && dst->implicitBuffers.depthStencil->sampleCount() == sampleCount)
+ {
+ depthStencil.reset(dst->implicitBuffers.depthStencil);
+ dst->implicitBuffers.depthStencil = nullptr;
+ }
+ }
+ dst->implicitBuffers.reset(rhi);
+
+ if (!depthStencil) {
+ depthStencil.reset(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, pixelSize, sampleCount));
+ depthStencil->setName(QByteArrayLiteral("Depth-stencil buffer for QQuickRenderTarget"));
+ if (!depthStencil->create()) {
+ qWarning("Failed to build depth-stencil buffer for QQuickRenderTarget");
+ return false;
+ }
+ }
+
+ QRhiColorAttachment colorAttachment(renderBuffer);
+ QRhiTextureRenderTargetDescription rtDesc(colorAttachment);
+ rtDesc.setDepthStencilBuffer(depthStencil.get());
+ std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
+ rt->setName(QByteArrayLiteral("RT for QQuickRenderTarget with renderbuffer"));
+ std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rp.get());
+
+ if (!rt->create()) {
+ qWarning("Failed to build renderbuffer-based render target for QQuickRenderTarget");
+ return false;
+ }
+
+ dst->rt.renderTarget = rt.release();
+ dst->rt.owns = true;
+ dst->res.rpDesc = rp.release();
+ dst->implicitBuffers.depthStencil = depthStencil.release();
+
+ return true;
+}
+
+static bool createRhiRenderTarget(QRhiTexture *texture,
+ const QSize &pixelSize,
+ int sampleCount,
+ bool multisampleResolve,
+ QRhi *rhi,
+ QQuickWindowRenderTarget *dst)
+{
+ // Simple path: no user-supplied depth texture. So create our own
+ // depth-stencil buffer, using renderbuffers (so this is still GLES 2.0
+ // compatible), with MSAA support being GLES 3.0 compatible.
+
+ sampleCount = QSGRhiSupport::chooseSampleCount(sampleCount, rhi);
+ if (sampleCount <= 1)
+ multisampleResolve = false;
+
+ std::unique_ptr<QRhiRenderBuffer> depthStencil;
+ if (dst->implicitBuffers.depthStencil) {
+ if (dst->implicitBuffers.depthStencil->pixelSize() == pixelSize
+ && dst->implicitBuffers.depthStencil->sampleCount() == sampleCount)
+ {
+ depthStencil.reset(dst->implicitBuffers.depthStencil);
+ dst->implicitBuffers.depthStencil = nullptr;
+ }
+ }
+
+ std::unique_ptr<QRhiTexture> colorBuffer;
+ QRhiTexture::Flags multisampleTextureFlags;
+ QRhiTexture::Format multisampleTextureFormat = texture->format();
+ if (multisampleResolve) {
+ multisampleTextureFlags = QRhiTexture::RenderTarget;
+ if (texture->flags().testFlag(QRhiTexture::sRGB))
+ multisampleTextureFlags |= QRhiTexture::sRGB;
+
+ if (dst->implicitBuffers.multisampleTexture) {
+ if (dst->implicitBuffers.multisampleTexture->pixelSize() == pixelSize
+ && dst->implicitBuffers.multisampleTexture->format() == multisampleTextureFormat
+ && dst->implicitBuffers.multisampleTexture->sampleCount() == sampleCount
+ && dst->implicitBuffers.multisampleTexture->flags().testFlags(multisampleTextureFlags))
+ {
+ colorBuffer.reset(dst->implicitBuffers.multisampleTexture);
+ dst->implicitBuffers.multisampleTexture = nullptr;
+ }
+ }
+ }
+
+ dst->implicitBuffers.reset(rhi);
+
+ if (!depthStencil) {
+ depthStencil.reset(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, pixelSize, sampleCount));
+ depthStencil->setName(QByteArrayLiteral("Depth-stencil buffer for QQuickRenderTarget"));
+ if (!depthStencil->create()) {
+ qWarning("Failed to build depth-stencil buffer for QQuickRenderTarget");
+ return false;
+ }
+ }
+
+ if (multisampleResolve && !colorBuffer) {
+ colorBuffer.reset(rhi->newTexture(multisampleTextureFormat, pixelSize, sampleCount, multisampleTextureFlags));
+ colorBuffer->setName(QByteArrayLiteral("Multisample color buffer for QQuickRenderTarget"));
+ colorBuffer->setWriteViewFormat(texture->writeViewFormat());
+ if (!colorBuffer->create()) {
+ qWarning("Failed to build multisample color buffer for QQuickRenderTarget");
+ return false;
+ }
+ }
+
+ QRhiColorAttachment colorAttachment;
+ if (multisampleResolve) {
+ colorAttachment.setTexture(colorBuffer.get());
+ colorAttachment.setResolveTexture(texture);
+ } else {
+ colorAttachment.setTexture(texture);
+ }
+ QRhiTextureRenderTargetDescription rtDesc(colorAttachment);
+ rtDesc.setDepthStencilBuffer(depthStencil.get());
+ std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
+ rt->setName(QByteArrayLiteral("RT for QQuickRenderTarget"));
+ std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rp.get());
+
+ if (!rt->create()) {
+ qWarning("Failed to build texture render target for QQuickRenderTarget");
+ return false;
+ }
+
+ dst->rt.renderTarget = rt.release();
+ dst->rt.owns = true;
+ dst->res.rpDesc = rp.release();
+ dst->implicitBuffers.depthStencil = depthStencil.release();
+ if (multisampleResolve)
+ dst->implicitBuffers.multisampleTexture = colorBuffer.release();
+
+ return true;
+}
+
+static bool createRhiRenderTargetWithDepthTexture(QRhiTexture *texture,
+ QRhiTexture *depthTexture,
+ const QSize &pixelSize,
+ int sampleCount,
+ bool multisampleResolve,
+ QRhi *rhi,
+ QQuickWindowRenderTarget *dst)
+{
+ // This version takes a user-supplied depthTexture. That texture is always
+ // non-multisample. If sample count is > 1, we still need our own
+ // multisample depth-stencil buffer, and the depth(stencil) data is expected
+ // to be resolved (and written out) to depthTexture, _if_ the underlying API
+ // supports it (see QRhi's ResolveDepthStencil feature). The intermediate,
+ // multisample depth-stencil buffer must be a texture here (not
+ // renderbuffer), specifically for OpenGL ES and its related multisample
+ // extensions.
+
+ sampleCount = QSGRhiSupport::chooseSampleCount(sampleCount, rhi);
+ if (sampleCount <= 1)
+ multisampleResolve = false;
+
+ std::unique_ptr<QRhiTexture> depthStencil;
+ if (dst->implicitBuffers.depthStencilTexture) {
+ if (dst->implicitBuffers.depthStencilTexture->pixelSize() == pixelSize
+ && dst->implicitBuffers.depthStencilTexture->sampleCount() == sampleCount)
+ {
+ depthStencil.reset(dst->implicitBuffers.depthStencilTexture);
+ dst->implicitBuffers.depthStencilTexture = nullptr;
+ }
+ }
+
+ std::unique_ptr<QRhiTexture> colorBuffer;
+ QRhiTexture::Flags multisampleTextureFlags;
+ QRhiTexture::Format multisampleTextureFormat = texture->format();
+ if (multisampleResolve) {
+ multisampleTextureFlags = QRhiTexture::RenderTarget;
+ if (texture->flags().testFlag(QRhiTexture::sRGB))
+ multisampleTextureFlags |= QRhiTexture::sRGB;
+
+ if (dst->implicitBuffers.multisampleTexture) {
+ if (dst->implicitBuffers.multisampleTexture->pixelSize() == pixelSize
+ && dst->implicitBuffers.multisampleTexture->format() == multisampleTextureFormat
+ && dst->implicitBuffers.multisampleTexture->sampleCount() == sampleCount
+ && dst->implicitBuffers.multisampleTexture->flags().testFlags(multisampleTextureFlags))
+ {
+ colorBuffer.reset(dst->implicitBuffers.multisampleTexture);
+ dst->implicitBuffers.multisampleTexture = nullptr;
+ }
+ }
+ }
+
+ dst->implicitBuffers.reset(rhi);
+
+ bool needsDepthStencilBuffer = true;
+ if (sampleCount <= 1) {
+ depthStencil.reset();
+ needsDepthStencilBuffer = false;
+ }
+ if (depthTexture->pixelSize() != pixelSize) {
+ qWarning("Custom depth texture size (%dx%d) does not match the QQuickRenderTarget (%dx%d)",
+ depthTexture->pixelSize().width(),
+ depthTexture->pixelSize().height(),
+ pixelSize.width(),
+ pixelSize.height());
+ return false;
+ }
+ if (depthTexture->sampleCount() > 1) {
+ qWarning("Custom depth texture cannot be multisample");
+ return false;
+ }
+ if (needsDepthStencilBuffer && !depthStencil) {
+ QRhiTexture::Format multisampleDepthTextureFormat = depthTexture->format();
+ depthStencil.reset(rhi->newTexture(multisampleDepthTextureFormat, pixelSize, sampleCount, QRhiTexture::RenderTarget));
+ depthStencil->setName(QByteArrayLiteral("Depth-stencil texture for QQuickRenderTarget"));
+ if (!depthStencil->create()) {
+ qWarning("Failed to build depth-stencil buffer for QQuickRenderTarget");
+ return false;
+ }
+ }
+
+ if (multisampleResolve && !colorBuffer) {
+ colorBuffer.reset(rhi->newTexture(multisampleTextureFormat, pixelSize, sampleCount, multisampleTextureFlags));
+ colorBuffer->setName(QByteArrayLiteral("Multisample color buffer for QQuickRenderTarget"));
+ colorBuffer->setWriteViewFormat(texture->writeViewFormat());
+ if (!colorBuffer->create()) {
+ qWarning("Failed to build multisample color buffer for QQuickRenderTarget");
+ return false;
+ }
+ }
+
+ QRhiColorAttachment colorAttachment;
+ if (multisampleResolve) {
+ colorAttachment.setTexture(colorBuffer.get());
+ colorAttachment.setResolveTexture(texture);
+ } else {
+ colorAttachment.setTexture(texture);
+ }
+
+ QRhiTextureRenderTargetDescription rtDesc(colorAttachment);
+ if (sampleCount > 1) {
+ rtDesc.setDepthTexture(depthStencil.get());
+ if (rhi->isFeatureSupported(QRhi::ResolveDepthStencil))
+ rtDesc.setDepthResolveTexture(depthTexture);
+ else
+ qWarning("Depth-stencil resolve is not supported by the underlying 3D API, depth contents will not be resolved");
+ } else {
+ rtDesc.setDepthTexture(depthTexture);
+ }
+
+ std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
+ rt->setName(QByteArrayLiteral("RT for QQuickRenderTarget"));
+ std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rp.get());
+
+ if (!rt->create()) {
+ qWarning("Failed to build texture render target for QQuickRenderTarget");
+ return false;
+ }
+
+ dst->rt.renderTarget = rt.release();
+ dst->rt.owns = true;
+ dst->res.rpDesc = rp.release();
+ if (depthStencil)
+ dst->implicitBuffers.depthStencilTexture = depthStencil.release();
+ if (multisampleResolve)
+ dst->implicitBuffers.multisampleTexture = colorBuffer.release();
+
+ return true;
+}
+
+static bool createRhiRenderTargetMultiView(QRhiTexture *texture,
+ QRhiTexture *maybeCustomDepthTexture,
+ const QSize &pixelSize,
+ int arraySize,
+ int sampleCount,
+ bool multisampleResolve,
+ QRhi *rhi,
+ QQuickWindowRenderTarget *dst)
+{
+ // Multiview path, working with texture arrays. Optionally with a
+ // user-supplied, non-multisample depth texture (array). (same semantics
+ // then as with createRhiRenderTargetWithDepthTexture, but everything is a
+ // 2D texture array here)
+
+ sampleCount = QSGRhiSupport::chooseSampleCount(sampleCount, rhi);
+ if (sampleCount <= 1)
+ multisampleResolve = false;
+
+ std::unique_ptr<QRhiTexture> depthStencil;
+ if (dst->implicitBuffers.depthStencilTexture) {
+ if (dst->implicitBuffers.depthStencilTexture->pixelSize() == pixelSize
+ && dst->implicitBuffers.depthStencilTexture->sampleCount() == sampleCount
+ && dst->implicitBuffers.depthStencilTexture->arraySize() == arraySize)
+ {
+ depthStencil.reset(dst->implicitBuffers.depthStencilTexture);
+ dst->implicitBuffers.depthStencilTexture = nullptr;
+ }
+ }
+
+ std::unique_ptr<QRhiTexture> colorBuffer;
+ QRhiTexture::Flags multisampleTextureFlags;
+ QRhiTexture::Format multisampleTextureFormat = texture->format();
+ if (multisampleResolve) {
+ multisampleTextureFlags = QRhiTexture::RenderTarget;
+ if (texture->flags().testFlag(QRhiTexture::sRGB))
+ multisampleTextureFlags |= QRhiTexture::sRGB;
+
+ if (dst->implicitBuffers.multisampleTexture) {
+ if (dst->implicitBuffers.multisampleTexture->pixelSize() == pixelSize
+ && dst->implicitBuffers.multisampleTexture->format() == multisampleTextureFormat
+ && dst->implicitBuffers.multisampleTexture->sampleCount() == sampleCount
+ && dst->implicitBuffers.multisampleTexture->arraySize() == arraySize
+ && dst->implicitBuffers.multisampleTexture->flags().testFlags(multisampleTextureFlags))
+ {
+ colorBuffer.reset(dst->implicitBuffers.multisampleTexture);
+ dst->implicitBuffers.multisampleTexture = nullptr;
+ }
+ }
+ }
+
+ dst->implicitBuffers.reset(rhi);
+
+ bool needsDepthStencilBuffer = true;
+ if (maybeCustomDepthTexture) {
+ if (sampleCount <= 1) {
+ depthStencil.reset();
+ needsDepthStencilBuffer = false;
+ }
+ if (maybeCustomDepthTexture->arraySize() != arraySize) {
+ qWarning("Custom depth texture array size (%d) does not match QQuickRenderTarget (%d)",
+ maybeCustomDepthTexture->arraySize(), arraySize);
+ return false;
+ }
+ if (maybeCustomDepthTexture->pixelSize() != pixelSize) {
+ qWarning("Custom depth texture size (%dx%d) does not match the QQuickRenderTarget (%dx%d)",
+ maybeCustomDepthTexture->pixelSize().width(),
+ maybeCustomDepthTexture->pixelSize().height(),
+ pixelSize.width(),
+ pixelSize.height());
+ return false;
+ }
+ if (maybeCustomDepthTexture->sampleCount() > 1) {
+ qWarning("Custom depth texture cannot be multisample");
+ return false;
+ }
+ }
+ if (needsDepthStencilBuffer && !depthStencil) {
+ depthStencil.reset(rhi->newTextureArray(QRhiTexture::D24S8, arraySize, pixelSize, sampleCount, QRhiTexture::RenderTarget));
+ depthStencil->setName(QByteArrayLiteral("Depth-stencil buffer (multiview) for QQuickRenderTarget"));
+ if (!depthStencil->create()) {
+ qWarning("Failed to build depth-stencil texture array for QQuickRenderTarget");
+ return false;
+ }
+ }
+
+ if (multisampleResolve && !colorBuffer) {
+ colorBuffer.reset(rhi->newTextureArray(multisampleTextureFormat, arraySize, pixelSize, sampleCount, multisampleTextureFlags));
+ colorBuffer->setName(QByteArrayLiteral("Multisample color buffer (multiview) for QQuickRenderTarget"));
+ colorBuffer->setWriteViewFormat(texture->writeViewFormat());
+ if (!colorBuffer->create()) {
+ qWarning("Failed to build multisample texture array for QQuickRenderTarget");
+ return false;
+ }
+ }
+
+ QRhiColorAttachment colorAttachment;
+ colorAttachment.setMultiViewCount(arraySize);
+ if (multisampleResolve) {
+ colorAttachment.setTexture(colorBuffer.get());
+ colorAttachment.setResolveTexture(texture);
+ } else {
+ colorAttachment.setTexture(texture);
+ }
+
+ QRhiTextureRenderTargetDescription rtDesc(colorAttachment);
+ if (sampleCount > 1) {
+ rtDesc.setDepthTexture(depthStencil.get());
+ if (maybeCustomDepthTexture) {
+ if (rhi->isFeatureSupported(QRhi::ResolveDepthStencil))
+ rtDesc.setDepthResolveTexture(maybeCustomDepthTexture);
+ else
+ qWarning("Depth-stencil resolve is not supported by the underlying 3D API, depth contents will not be resolved");
+ }
+ } else {
+ if (depthStencil)
+ rtDesc.setDepthTexture(depthStencil.get());
+ else if (maybeCustomDepthTexture)
+ rtDesc.setDepthTexture(maybeCustomDepthTexture);
+ }
+
+ QRhiTextureRenderTarget::Flags rtFlags;
+ if (!maybeCustomDepthTexture)
+ rtFlags |= QRhiTextureRenderTarget::DoNotStoreDepthStencilContents;
+
+ std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc, rtFlags));
+ rt->setName(QByteArrayLiteral("RT for multiview QQuickRenderTarget"));
+ 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->rt.renderTarget = rt.release();
+ dst->rt.owns = true;
+ dst->res.rpDesc = rp.release();
+ if (depthStencil)
+ dst->implicitBuffers.depthStencilTexture = depthStencil.release();
+ if (multisampleResolve)
+ dst->implicitBuffers.multisampleTexture = colorBuffer.release();
+
+ dst->rt.multiViewCount = arraySize;
+
+ return true;
+}
+
+bool QQuickRenderTargetPrivate::resolve(QRhi *rhi, QQuickWindowRenderTarget *dst)
+{
+ // dst->implicitBuffers may contain valid objects. If so, and their
+ // properties are suitable, they are expected to be reused. Once taken what
+ // we can reuse, it needs to be reset().
+
+ switch (type) {
+ case Type::Null:
+ dst->implicitBuffers.reset(rhi);
+ return true;
+
+ case Type::NativeTexture:
+ {
+ QRhiTexture::Format format = u.nativeTexture.rhiFormat == QRhiTexture::UnknownFormat ? QRhiTexture::RGBA8
+ : QRhiTexture::Format(u.nativeTexture.rhiFormat);
+ QRhiTexture::Format viewFormat = u.nativeTexture.rhiViewFormat == QRhiTexture::UnknownFormat ? QRhiTexture::RGBA8
+ : QRhiTexture::Format(u.nativeTexture.rhiViewFormat);
+ const auto flags = QRhiTexture::RenderTarget | QRhiTexture::Flags(u.nativeTexture.rhiFormatFlags);
+ std::unique_ptr<QRhiTexture> texture(rhi->newTexture(format, pixelSize, multisampleResolve ? 1 : sampleCount, flags));
+ const bool textureIsSrgb = flags.testFlag(QRhiTexture::sRGB);
+ const bool viewIsSrgb = QRhiTexture::Flags(u.nativeTexture.rhiViewFormatFlags).testFlag(QRhiTexture::sRGB);
+ if (viewFormat != format || viewIsSrgb != textureIsSrgb)
+ texture->setWriteViewFormat({ viewFormat, viewIsSrgb });
+ if (!texture->createFrom({ u.nativeTexture.object, u.nativeTexture.layoutOrState })) {
+ qWarning("Failed to build wrapper texture for QQuickRenderTarget");
+ return false;
+ }
+ if (customDepthTexture) {
+ if (!createRhiRenderTargetWithDepthTexture(texture.get(), customDepthTexture, pixelSize, sampleCount, multisampleResolve, rhi, dst))
+ return false;
+ } else {
+ if (!createRhiRenderTarget(texture.get(), pixelSize, sampleCount, multisampleResolve, rhi, dst))
+ return false;
+ }
+ dst->res.texture = texture.release();
+ }
+ return true;
+
+ case Type::NativeTextureArray:
+ {
+ QRhiTexture::Format format = u.nativeTextureArray.rhiFormat == QRhiTexture::UnknownFormat ? QRhiTexture::RGBA8
+ : QRhiTexture::Format(u.nativeTextureArray.rhiFormat);
+ QRhiTexture::Format viewFormat = u.nativeTextureArray.rhiViewFormat == QRhiTexture::UnknownFormat ? QRhiTexture::RGBA8
+ : QRhiTexture::Format(u.nativeTextureArray.rhiViewFormat);
+ const auto flags = QRhiTexture::RenderTarget | QRhiTexture::Flags(u.nativeTextureArray.rhiFormatFlags);
+ const int arraySize = u.nativeTextureArray.arraySize;
+ std::unique_ptr<QRhiTexture> texture(rhi->newTextureArray(format, arraySize, pixelSize, multisampleResolve ? 1 : sampleCount, flags));
+ const bool textureIsSrgb = flags.testFlag(QRhiTexture::sRGB);
+ const bool viewIsSrgb = QRhiTexture::Flags(u.nativeTextureArray.rhiViewFormatFlags).testFlag(QRhiTexture::sRGB);
+ if (viewFormat != format || viewIsSrgb != textureIsSrgb)
+ texture->setWriteViewFormat({ viewFormat, viewIsSrgb });
+ if (!texture->createFrom({ u.nativeTextureArray.object, u.nativeTextureArray.layoutOrState })) {
+ qWarning("Failed to build wrapper texture array for QQuickRenderTarget");
+ return false;
+ }
+ if (!createRhiRenderTargetMultiView(texture.get(), customDepthTexture, pixelSize, arraySize, sampleCount, multisampleResolve, rhi, dst))
+ return false;
+ dst->res.texture = texture.release();
+ }
+ return true;
+
+ case Type::NativeRenderbuffer:
+ {
+ std::unique_ptr<QRhiRenderBuffer> renderbuffer(rhi->newRenderBuffer(QRhiRenderBuffer::Color, pixelSize, sampleCount));
+ if (!renderbuffer->createFrom({ u.nativeRenderbufferObject })) {
+ qWarning("Failed to build wrapper renderbuffer for QQuickRenderTarget");
+ return false;
+ }
+ if (customDepthTexture)
+ qWarning("Custom depth texture is not supported with renderbuffers in QQuickRenderTarget");
+ if (!createRhiRenderTargetWithRenderBuffer(renderbuffer.get(), pixelSize, sampleCount, rhi, dst))
+ return false;
+ dst->res.renderBuffer = renderbuffer.release();
+ }
+ return true;
+
+ case Type::RhiRenderTarget:
+ dst->implicitBuffers.reset(rhi);
+ dst->rt.renderTarget = u.rhiRt;
+ dst->rt.owns = false;
+ if (dst->rt.renderTarget->resourceType() == QRhiResource::TextureRenderTarget) {
+ auto texRt = static_cast<QRhiTextureRenderTarget *>(dst->rt.renderTarget);
+ const QRhiTextureRenderTargetDescription desc = texRt->description();
+ bool first = true;
+ for (auto it = desc.cbeginColorAttachments(), end = desc.cendColorAttachments(); it != end; ++it) {
+ if (it->multiViewCount() <= 1)
+ continue;
+ if (first || dst->rt.multiViewCount == it->multiViewCount()) {
+ first = false;
+ if (it->texture() && it->texture()->flags().testFlag(QRhiTexture::TextureArray)) {
+ if (it->texture()->arraySize() >= it->layer() + it->multiViewCount()) {
+ dst->rt.multiViewCount = it->multiViewCount();
+ } else {
+ qWarning("Invalid QQuickRenderTarget; needs at least %d elements in texture array, got %d",
+ it->layer() + it->multiViewCount(),
+ it->texture()->arraySize());
+ return false;
+ }
+ } else {
+ qWarning("Invalid QQuickRenderTarget; multiview requires a texture array");
+ return false;
+ }
+ } else {
+ qWarning("Inconsistent multiViewCount in QQuickRenderTarget (was %d, now found an attachment with %d)",
+ dst->rt.multiViewCount, it->multiViewCount());
+ return false;
+ }
+ }
+ }
+ if (customDepthTexture)
+ qWarning("Custom depth texture is not supported with QRhiRenderTarget in QQuickRenderTarget");
+ return true;
+
+ case Type::PaintDevice:
+ dst->implicitBuffers.reset(rhi);
+ dst->sw.paintDevice = u.paintDevice;
+ dst->sw.owns = false;
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+QT_END_NAMESPACE