diff options
-rw-r--r-- | src/quick/items/qquickrendertarget.cpp | 338 | ||||
-rw-r--r-- | src/quick/items/qquickrendertarget.h | 4 | ||||
-rw-r--r-- | src/quick/items/qquickrendertarget_p.h | 9 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 2 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 1 | ||||
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgmaterial.cpp | 13 |
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 */ |