rhi: Make it possible to discard depth/stencil even when using a texture

Also implement this for OpenGL ES since it can be relevant with tiled
architectures wrt performance.

Task-number: QTBUG-122669
Change-Id: I90dcfe4f5f9edbb8dfb51189d46b89ef2c7a7c06
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Laszlo Agocs 2024-03-12 14:54:13 +01:00
parent 4c49e0fde4
commit bc61d6fcfa
7 changed files with 63 additions and 5 deletions

View File

@ -2542,6 +2542,24 @@ QRhiColorAttachment::QRhiColorAttachment(QRhiRenderBuffer *renderBuffer)
QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ colorAtt, depthStencil });
\endcode
\note when multisample resolving is enabled, the multisample data may not be
written out at all. This means that the multisample texture in a color
attachment must not be used afterwards with shaders for sampling (or other
puroses) whenever a resolve texture is set, since the multisample color
buffer is merely an intermediate storage then that gets no data written back
on some GPU architectures at all.
\note When using setDepthTexture(), not setDepthStencilBuffer(), and the
depth (stencil) data is not of interest afterwards, set the
DoNotStoreDepthStencilContents flag on the QRhiTextureRenderTarget. This
allows indicating to the underlying 3D API that the depth/stencil data can
be discarded, leading potentially to better performance with tiled GPU
architectures. When the depth-stencil buffer is a QRhiRenderBuffer (and also
for the multisample color texture, see previous note) this is implicit, but
with a depth (stencil) QRhiTexture the intention needs to be declared
explicitly. By default QRhi assumes that the data is of interest (e.g., the
depth texture is sampled in a shader afterwards).
\note This is a RHI API with limited compatibility guarantees, see \l QRhi
for details.
@ -5053,6 +5071,12 @@ QRhiResource::Type QRhiSwapChainRenderTarget::resourceType() const
(QRhiTextureRenderTargetDescription::depthTexture() is set) because
depth/stencil renderbuffers may not have any physical backing and data may
not be written out in the first place.
\value DoNotStoreDepthStencilContents Indicates that the contents of the
depth texture does not need to be written out. Relevant only when a
QRhiTexture, not QRhiRenderBuffer, is used as the depth-stencil buffer,
because for QRhiRenderBuffer this is implicit. This enum value is introduced
in Qt 6.8.
*/
/*!

View File

@ -1181,7 +1181,8 @@ class Q_GUI_EXPORT QRhiTextureRenderTarget : public QRhiRenderTarget
public:
enum Flag {
PreserveColorContents = 1 << 0,
PreserveDepthStencilContents = 1 << 1
PreserveDepthStencilContents = 1 << 1,
DoNotStoreDepthStencilContents = 1 << 2
};
Q_DECLARE_FLAGS(Flags, Flag)

View File

@ -3679,6 +3679,13 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
if (caps.compute)
f->glMemoryBarrier(cmd.args.barrier.barriers);
break;
case QGles2CommandBuffer::Command::InvalidateFramebuffer:
if (caps.gles && caps.ctxMajor >= 3) {
f->glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER,
cmd.args.invalidateFramebuffer.attCount,
cmd.args.invalidateFramebuffer.att);
}
break;
default:
break;
}
@ -4506,7 +4513,10 @@ void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
const bool hasZ = resolveTexD->m_flags.testFlag(QRhiTexture::ThreeDimensional)
|| resolveTexD->m_flags.testFlag(QRhiTexture::TextureArray);
cmd.args.blitFromRenderbuffer.dstLayer = hasZ ? colorAtt.resolveLayer() : 0;
} else if (!caps.glesMultisampleRenderToTexture) {
} else if (caps.glesMultisampleRenderToTexture) {
// Nothing to do, resolving into colorAtt.resolveTexture() is automatic,
// colorAtt.texture() is in fact not used for anything.
} else {
Q_ASSERT(colorAtt.texture());
QGles2Texture *texD = QRHI_RES(QGles2Texture, colorAtt.texture());
if (texD->pixelSize() != size) {
@ -4542,6 +4552,21 @@ void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
}
}
}
const bool mayDiscardDepthStencil = rtTex->m_desc.depthStencilBuffer()
|| (rtTex->m_desc.depthTexture() && rtTex->m_flags.testFlag(QRhiTextureRenderTarget::DoNotStoreDepthStencilContents));
if (mayDiscardDepthStencil) {
QGles2CommandBuffer::Command &cmd(cbD->commands.get());
cmd.cmd = QGles2CommandBuffer::Command::InvalidateFramebuffer;
if (caps.needsDepthStencilCombinedAttach) {
cmd.args.invalidateFramebuffer.attCount = 1;
cmd.args.invalidateFramebuffer.att[0] = GL_DEPTH_STENCIL_ATTACHMENT;
} else {
cmd.args.invalidateFramebuffer.attCount = 2;
cmd.args.invalidateFramebuffer.att[0] = GL_DEPTH_ATTACHMENT;
cmd.args.invalidateFramebuffer.att[1] = GL_STENCIL_ATTACHMENT;
}
}
}
cbD->recordingPass = QGles2CommandBuffer::NoPass;

View File

@ -337,7 +337,8 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
BindComputePipeline,
Dispatch,
BarriersForPass,
Barrier
Barrier,
InvalidateFramebuffer
};
Cmd cmd;
@ -536,6 +537,10 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
struct {
GLbitfield barriers;
} barrier;
struct {
int attCount;
GLenum att[3];
} invalidateFramebuffer;
} args;
};

View File

@ -4226,7 +4226,7 @@ bool QMetalTextureRenderTarget::create()
QMetalTexture *depthTexD = QRHI_RES(QMetalTexture, m_desc.depthTexture());
d->fb.dsTex = depthTexD->d->tex;
d->fb.hasStencil = rhiD->isStencilSupportingFormat(depthTexD->format());
d->fb.depthNeedsStore = true;
d->fb.depthNeedsStore = !m_flags.testFlag(DoNotStoreDepthStencilContents);
if (d->colorAttCount == 0) {
d->pixelSize = depthTexD->pixelSize();
d->sampleCount = depthTexD->samples;

View File

@ -1439,6 +1439,7 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
const QRhiColorAttachment *lastColorAttachment,
bool preserveColor,
bool preserveDs,
bool storeDs,
QRhiRenderBuffer *depthStencilBuffer,
QRhiTexture *depthTexture)
{
@ -1486,7 +1487,7 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
const VkSampleCountFlagBits samples = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->samples
: QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
const VkAttachmentStoreOp storeOp = depthTexture ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
VkAttachmentDescription attDesc = {};
attDesc.format = dsFormat;
attDesc.samples = samples;
@ -6859,6 +6860,7 @@ QRhiRenderPassDescriptor *QVkTextureRenderTarget::newCompatibleRenderPassDescrip
m_desc.cendColorAttachments(),
m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents),
m_desc.depthStencilBuffer(),
m_desc.depthTexture()))
{

View File

@ -773,6 +773,7 @@ public:
const QRhiColorAttachment *lastColorAttachment,
bool preserveColor,
bool preserveDs,
bool storeDs,
QRhiRenderBuffer *depthStencilBuffer,
QRhiTexture *depthTexture);
bool ensurePipelineCache(const void *initialData = nullptr, size_t initialDataSize = 0);