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:
parent
4c49e0fde4
commit
bc61d6fcfa
@ -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.
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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()))
|
||||
{
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user