summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2020-08-26 14:29:49 +0200
committerPaul Lemire <paul.lemire@kdab.com>2020-08-27 07:57:59 +0200
commit50c2e3a1f81b6e2ebdd956b481d756e035cd6c62 (patch)
tree0185479d32e164e3dd20a262e774b83528726c7c
parent8ef1bab575e5e999b4e200901f7407b3d442d96a (diff)
rhi: Add support for QRenderCapture
Change-Id: I498c8c83d447f688cd0d88c1a8ebcc4dcb2b68a7 Reviewed-by: Mike Krus <mike.krus@kdab.com>
-rw-r--r--src/plugins/renderers/rhi/graphicshelpers/submissioncontext.cpp3
-rw-r--r--src/plugins/renderers/rhi/renderer/renderer.cpp59
2 files changed, 58 insertions, 4 deletions
diff --git a/src/plugins/renderers/rhi/graphicshelpers/submissioncontext.cpp b/src/plugins/renderers/rhi/graphicshelpers/submissioncontext.cpp
index 0ebbb2558..0126dbe17 100644
--- a/src/plugins/renderers/rhi/graphicshelpers/submissioncontext.cpp
+++ b/src/plugins/renderers/rhi/graphicshelpers/submissioncontext.cpp
@@ -1159,7 +1159,8 @@ SubmissionContext::SwapChainInfo *SubmissionContext::swapChainForSurface(QSurfac
const int samples = format().samples();
swapChain->setWindow(window);
- swapChain->setFlags(QRhiSwapChain::Flags {});
+ // Allow to read back from swap chain for RenderCapture to work
+ swapChain->setFlags(QRhiSwapChain::Flags { QRhiSwapChain::UsedAsTransferSource });
swapChain->setSampleCount(samples);
QRhiRenderBuffer *renderBuffer =
diff --git a/src/plugins/renderers/rhi/renderer/renderer.cpp b/src/plugins/renderers/rhi/renderer/renderer.cpp
index fd8b5c1e9..ccf2a0584 100644
--- a/src/plugins/renderers/rhi/renderer/renderer.cpp
+++ b/src/plugins/renderers/rhi/renderer/renderer.cpp
@@ -51,6 +51,7 @@
#include <Qt3DRender/qtechnique.h>
#include <Qt3DRender/qrenderaspect.h>
#include <Qt3DRender/qeffect.h>
+#include <Qt3DRender/qrendercapture.h>
#include <Qt3DRender/private/qsceneimporter_p.h>
#include <Qt3DRender/private/renderstates_p.h>
@@ -1186,8 +1187,10 @@ void Renderer::createRenderTarget(RenderTarget *target)
if (tex && tex->getRhiTexture()) {
auto rhiTex = tex->getRhiTexture();
- if (!rhiTex->flags().testFlag(QRhiTexture::RenderTarget)) {
- rhiTex->setFlags(rhiTex->flags() | QRhiTexture::RenderTarget);
+ if (!rhiTex->flags().testFlag(QRhiTexture::RenderTarget) ||
+ !rhiTex->flags().testFlag(QRhiTexture::UsedAsTransferSource)) {
+ // UsedAsTransferSource is required if we ever want to read back from the texture
+ rhiTex->setFlags(rhiTex->flags() | QRhiTexture::RenderTarget|QRhiTexture::UsedAsTransferSource);
rhiTex->create();
}
switch (rhiTex->format()) {
@@ -2813,6 +2816,7 @@ bool Renderer::executeCommandsSubmission(const RHIPassInfo &passInfo)
// All the RVs in the current passinfo target the same RenderTarget
// A single beginPass should take place, unless Computes RVs are intermingled
+ QRhiResourceUpdateBatch *inPassUpdates = nullptr;
// Per Pass Global States
for (RenderView *rv : renderViews) {
@@ -2851,11 +2855,60 @@ bool Renderer::executeCommandsSubmission(const RHIPassInfo &passInfo)
}
executeDrawRenderView(rv);
+
+ const Qt3DCore::QNodeId renderCaptureId = rv->renderCaptureNodeId();
+ if (!renderCaptureId.isNull()) {
+ const QRenderCaptureRequest request = rv->renderCaptureRequest();
+ QRhiRenderTarget *rhiTarget = nullptr;
+ RHIRenderTarget *target = nullptr;
+
+ if (rv->renderTargetId()) {
+ RHIRenderTargetManager *targetManager = m_RHIResourceManagers->rhiRenderTargetManager();
+ target = targetManager->lookupResource(rv->renderTargetId());
+ if (target != nullptr)
+ rhiTarget = target->renderTarget;
+ }
+ // Use FBO size if RV has one
+ const QSize size = rhiTarget ? rhiTarget->pixelSize() : rv->surfaceSize();
+
+ QRect rect(QPoint(0, 0), size);
+ if (!request.rect.isEmpty())
+ rect = rect.intersected(request.rect);
+ QImage image;
+ if (!rect.isEmpty()) {
+ // Bind fbo as read framebuffer
+ QRhiReadbackResult *readBackResult = new QRhiReadbackResult;
+ readBackResult->completed = [this, readBackResult, renderCaptureId, request] () {
+ const QImage::Format fmt = QImage::Format_RGBA8888_Premultiplied; // fits QRhiTexture::RGBA8
+ const uchar *p = reinterpret_cast<const uchar *>(readBackResult->data.constData());
+ const QImage image(p, readBackResult->pixelSize.width(), readBackResult->pixelSize.height(), fmt);
+
+ Render::RenderCapture *renderCapture = static_cast<Render::RenderCapture*>(m_nodesManager->frameGraphManager()->lookupNode(renderCaptureId));
+ renderCapture->addRenderCapture(request.captureId, image);
+ if (!Qt3DCore::contains(m_pendingRenderCaptureSendRequests, renderCaptureId))
+ m_pendingRenderCaptureSendRequests.push_back(renderCaptureId);
+ delete readBackResult;
+ };
+
+ QRhiReadbackDescription readbackDesc;
+ if (rhiTarget) {
+ // First texture should be Attachment 0
+ QRhiTextureRenderTarget *textureRenderTarget = static_cast<QRhiTextureRenderTarget *>(rhiTarget);
+ const QRhiTextureRenderTargetDescription &desc = textureRenderTarget->description();
+ const QRhiColorAttachment *color0Att = desc.colorAttachmentAt(0);
+ readbackDesc.setTexture(color0Att->texture());
+ }
+ inPassUpdates = m_submissionContext->rhi()->nextResourceUpdateBatch();
+ inPassUpdates->readBackTexture(readbackDesc, readBackResult);
+ } else {
+ qCWarning(Backend) << "Requested capture rectangle is outside framebuffer";
+ }
+ }
}
}
if (Q_LIKELY(inDraw))
- cb->endPass();
+ cb->endPass(inPassUpdates);
else if (inCompute)
cb->endComputePass();