diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2024-02-22 10:28:49 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2024-02-22 17:10:23 +0100 |
commit | a15c3519209d4b2a4aae3a7621a1af6291b074ff (patch) | |
tree | bd1f96735d028c8e900e3d0d6cd6009a90d0256f /src/quick/items/qquickwindow.cpp | |
parent | 448a6ffe265915a3bcaa681aa3c21f0073a5868f (diff) |
Optimize QQuickRt behavior with implicitly created buffers
Creating a new depth-stencil, or with the new auto-resolving variants,
a multisample color buffer on every setRenderTarget() is not ideal.
(e.g. Quick 3D XR at the moment uses the convenient fromVulkanImage(),
fromOpenGLTexture(), etc. constructors and then setRenderTarget(), on
every frame (multiview) - or per eye per frame (non-multiview) -
passing in the XrSwapchain-provided native image) As QQuickRenderTarget
is merely a value class referencing some resources plus contains
metadata, attempting to keep around QQuickRenderTarget instances
on the user side is not effective; from the renderer's point of view
every call to setRenderTarget() is effectively a full change, even
though we might have used that QQuickRenderTarget before.
At minimum, we should try keeping the already existing depth-stencil,
multisample, and other implicit (auto-created) buffers if they are
suitable for the new QQuickRenderTarget. (suitable = size matches,
format matches, other relevant properties match) This is implemented
in this patch.
That is then suitable to speed up the vast majority of common cases,
and will avoid creating new implicit buffers on every frame with
Quick 3D XR for example. Those who want to continuously render with
a different size is not helped by this, but it is not clear if there
is such a use case in practice to begin with. Introducing pools and
caches and such are not reasonable here, since keeping all sorts
of depth-stencil buffers with various sizes around causes
more problems than it solves. (who trims it, how much it can grow,
etc.) Power users should anyway resort to managing their own
QRhiRenderTarget objects and passing that in via
fromRhiRenderTarget(). (this is something to be considered for
Quick 3D XR as well later on; when using the API-specific
QQuickRt constructors the QRhiTextureRenderTarget is still
going to be remade after every setRenderTarget(), which is also
not entirely ideal, although the details depend on the
underlying 3D API as well)
Change-Id: I5754a4809038e9688cbd5618324383886cea7010
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src/quick/items/qquickwindow.cpp')
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 89 |
1 files changed, 51 insertions, 38 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 5e4b0d6c15..421b0479c9 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -475,32 +475,37 @@ void forceUpdate(QQuickItem *item) forceUpdate(items.at(i)); } -void QQuickWindowRenderTarget::reset(QRhi *rhi) +void QQuickWindowRenderTarget::reset(QRhi *rhi, ResetFlags flags) { - if (owns) { - if (rhi) { - delete renderTarget; - delete rpDesc; - delete texture; - delete renderBuffer; - delete depthStencil; - delete depthStencilTexture; - delete multisampleTexture; - } + if (rhi) { + if (rt.owns) + delete rt.renderTarget; - delete paintDevice; + delete res.texture; + delete res.renderBuffer; + delete res.rpDesc; } - renderTarget = nullptr; - rpDesc = nullptr; - texture = nullptr; - renderBuffer = nullptr; - depthStencil = nullptr; - depthStencilTexture = nullptr; - multisampleTexture = nullptr; - paintDevice = nullptr; - owns = false; - multiViewCount = 1; + rt = {}; + res = {}; + + if (!flags.testFlag(ResetFlag::KeepImplicitBuffers)) + implicitBuffers.reset(rhi); + + if (sw.owns) + delete sw.paintDevice; + + sw = {}; +} + +void QQuickWindowRenderTarget::ImplicitBuffers::reset(QRhi *rhi) +{ + if (rhi) { + delete depthStencil; + delete depthStencilTexture; + delete multisampleTexture; + } + *this = {}; } void QQuickWindowPrivate::invalidateFontData(QQuickItem *item) @@ -517,19 +522,18 @@ void QQuickWindowPrivate::invalidateFontData(QQuickItem *item) void QQuickWindowPrivate::ensureCustomRenderTarget() { // resolve() can be expensive when importing an existing native texture, so - // it is important to only do it when the QQuickRenderTarget* was really changed + // it is important to only do it when the QQuickRenderTarget was really changed. if (!redirect.renderTargetDirty) return; redirect.renderTargetDirty = false; - redirect.rt.reset(rhi); + redirect.rt.reset(rhi, QQuickWindowRenderTarget::ResetFlag::KeepImplicitBuffers); - // a default constructed QQuickRenderTarget means no redirection - if (customRenderTarget.isNull()) - return; - - QQuickRenderTargetPrivate::get(&customRenderTarget)->resolve(rhi, &redirect.rt); + if (!QQuickRenderTargetPrivate::get(&customRenderTarget)->resolve(rhi, &redirect.rt)) { + qWarning("Failed to set up render target redirection for QQuickWindow"); + redirect.rt.reset(rhi); + } } void QQuickWindowPrivate::setCustomCommandBuffer(QRhiCommandBuffer *cb) @@ -608,8 +612,8 @@ int QQuickWindowPrivate::multiViewCount() { if (rhi) { ensureCustomRenderTarget(); - if (redirect.rt.renderTarget) - return redirect.rt.multiViewCount; + if (redirect.rt.rt.renderTarget) + return redirect.rt.rt.multiViewCount; } // Note that on QRhi level 0 and 1 are often used interchangeably, as both mean @@ -619,6 +623,15 @@ int QQuickWindowPrivate::multiViewCount() return 1; } +QRhiRenderTarget *QQuickWindowPrivate::activeCustomRhiRenderTarget() +{ + if (rhi) { + ensureCustomRenderTarget(); + return redirect.rt.rt.renderTarget; + } + return nullptr; +} + void QQuickWindowPrivate::renderSceneGraph() { Q_Q(QQuickWindow); @@ -632,8 +645,8 @@ void QQuickWindowPrivate::renderSceneGraph() QRhiRenderTarget *rt; QRhiRenderPassDescriptor *rp; QRhiCommandBuffer *cb; - if (redirect.rt.renderTarget) { - rt = redirect.rt.renderTarget; + if (redirect.rt.rt.renderTarget) { + rt = redirect.rt.rt.renderTarget; rp = rt->renderPassDescriptor(); if (!rp) { qWarning("Custom render target is set but no renderpass descriptor has been provided."); @@ -656,7 +669,7 @@ void QQuickWindowPrivate::renderSceneGraph() sgRenderTarget = QSGRenderTarget(rt, rp, cb); sgRenderTarget.multiViewCount = multiViewCount(); } else { - sgRenderTarget = QSGRenderTarget(redirect.rt.paintDevice); + sgRenderTarget = QSGRenderTarget(redirect.rt.sw.paintDevice); } context->beginNextFrame(renderer, @@ -671,10 +684,10 @@ void QQuickWindowPrivate::renderSceneGraph() const qreal devicePixelRatio = q->effectiveDevicePixelRatio(); QSize pixelSize; - if (redirect.rt.renderTarget) - pixelSize = redirect.rt.renderTarget->pixelSize(); - else if (redirect.rt.paintDevice) - pixelSize = QSize(redirect.rt.paintDevice->width(), redirect.rt.paintDevice->height()); + if (redirect.rt.rt.renderTarget) + pixelSize = redirect.rt.rt.renderTarget->pixelSize(); + else if (redirect.rt.sw.paintDevice) + pixelSize = QSize(redirect.rt.sw.paintDevice->width(), redirect.rt.sw.paintDevice->height()); else if (rhi) pixelSize = swapchain->currentPixelSize(); else // software or other backend |