aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickwindow.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2024-02-22 10:28:49 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2024-02-22 17:10:23 +0100
commita15c3519209d4b2a4aae3a7621a1af6291b074ff (patch)
treebd1f96735d028c8e900e3d0d6cd6009a90d0256f /src/quick/items/qquickwindow.cpp
parent448a6ffe265915a3bcaa681aa3c21f0073a5868f (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.cpp89
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