rhi: vulkan: metal: Ensure ms color data is written out on PreserveColor

Fixes: QTBUG-123211
Pick-to: 6.7 6.6
Change-Id: Id037f8c5a69c2b0ec18d92fe8bb5a34a0a2b0ea0
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Laszlo Agocs 2024-03-13 11:47:14 +01:00
parent bc61d6fcfa
commit 1b374fc4c1
3 changed files with 28 additions and 7 deletions

View File

@ -2545,9 +2545,10 @@ QRhiColorAttachment::QRhiColorAttachment(QRhiRenderBuffer *renderBuffer)
\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
purposes) 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.
on some GPU architectures at all. See
\l{QRhiTextureRenderTarget::Flag}{PreserveColorContents} for more details.
\note When using setDepthTexture(), not setDepthStencilBuffer(), and the
depth (stencil) data is not of interest afterwards, set the
@ -5063,7 +5064,19 @@ QRhiResource::Type QRhiSwapChainRenderTarget::resourceType() const
\value PreserveColorContents Indicates that the contents of the color
attachments is to be loaded when starting a render pass, instead of
clearing. This is potentially more expensive, especially on mobile (tiled)
GPUs, but allows preserving the existing contents between passes.
GPUs, but allows preserving the existing contents between passes. When doing
multisample rendering with a resolve texture set, setting this flag also
requests the multisample color data to be stored (written out) to the
multisample texture or render buffer. (for non-multisample rendering the
color data is always stored, but for MSAA storing the multisample data
decreases efficiency for certain GPU architectures, hence defaulting to not
writing it out) Note however that this is non-portable: in some cases there
is no intermediate multisample texture on the graphics API level, e.g. when
using OpenGL ES's \c{GL_EXT_multisampled_render_to_texture} as it is all
implicit, handled by the OpenGL ES implementation. In that case,
PreserveColorContents will likely have no effect. Therefore, avoid relying
on this flag when using multisample rendering and the color attachment is
using a multisample QRhiTexture (not QRhiRenderBuffer).
\value PreserveDepthStencilContents Indicates that the contents of the
depth texture is to be loaded when starting a render pass, instead

View File

@ -365,6 +365,8 @@ struct QMetalRenderTargetData
id<MTLTexture> dsTex = nil;
bool hasStencil = false;
bool depthNeedsStore = false;
bool preserveColor = false;
bool preserveDs = false;
} fb;
QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
@ -2952,11 +2954,11 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QMetalTexture, QMetalRenderBuffer>(rtTex->description(), rtD->currentResIdList))
rtTex->create();
cbD->d->currentPassRpDesc = d->createDefaultRenderPass(rtD->dsAttCount, colorClearValue, depthStencilClearValue, rtD->colorAttCount);
if (rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents)) {
if (rtD->fb.preserveColor) {
for (uint i = 0; i < uint(rtD->colorAttCount); ++i)
cbD->d->currentPassRpDesc.colorAttachments[i].loadAction = MTLLoadActionLoad;
}
if (rtD->dsAttCount && rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents)) {
if (rtD->dsAttCount && rtD->fb.preserveDs) {
cbD->d->currentPassRpDesc.depthAttachment.loadAction = MTLLoadActionLoad;
cbD->d->currentPassRpDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
}
@ -2990,7 +2992,8 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
cbD->d->currentPassRpDesc.colorAttachments[i].depthPlane = NSUInteger(rtD->fb.colorAtt[i].slice);
cbD->d->currentPassRpDesc.colorAttachments[i].level = NSUInteger(rtD->fb.colorAtt[i].level);
if (rtD->fb.colorAtt[i].resolveTex) {
cbD->d->currentPassRpDesc.colorAttachments[i].storeAction = MTLStoreActionMultisampleResolve;
cbD->d->currentPassRpDesc.colorAttachments[i].storeAction = rtD->fb.preserveColor ? MTLStoreActionStoreAndMultisampleResolve
: MTLStoreActionMultisampleResolve;
cbD->d->currentPassRpDesc.colorAttachments[i].resolveTexture = rtD->fb.colorAtt[i].resolveTex;
cbD->d->currentPassRpDesc.colorAttachments[i].resolveSlice = NSUInteger(rtD->fb.colorAtt[i].resolveLayer);
cbD->d->currentPassRpDesc.colorAttachments[i].resolveLevel = NSUInteger(rtD->fb.colorAtt[i].resolveLevel);
@ -4227,6 +4230,7 @@ bool QMetalTextureRenderTarget::create()
d->fb.dsTex = depthTexD->d->tex;
d->fb.hasStencil = rhiD->isStencilSupportingFormat(depthTexD->format());
d->fb.depthNeedsStore = !m_flags.testFlag(DoNotStoreDepthStencilContents);
d->fb.preserveDs = m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
if (d->colorAttCount == 0) {
d->pixelSize = depthTexD->pixelSize();
d->sampleCount = depthTexD->samples;
@ -4236,6 +4240,7 @@ bool QMetalTextureRenderTarget::create()
d->fb.dsTex = depthRbD->d->tex;
d->fb.hasStencil = true;
d->fb.depthNeedsStore = false;
d->fb.preserveDs = false;
if (d->colorAttCount == 0) {
d->pixelSize = depthRbD->pixelSize();
d->sampleCount = depthRbD->samples;
@ -4246,6 +4251,9 @@ bool QMetalTextureRenderTarget::create()
d->dsAttCount = 0;
}
if (d->colorAttCount > 0)
d->fb.preserveColor = m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
QRhiRenderTargetAttachmentTracker::updateResIdList<QMetalTexture, QMetalRenderBuffer>(m_desc, &d->currentResIdList);
rhiD->registerResource(this, false);

View File

@ -1457,7 +1457,7 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
attDesc.format = vkformat;
attDesc.samples = samples;
attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
attDesc.storeOp = it->resolveTexture() ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
// this has to interact correctly with activateTextureRenderTarget(), hence leaving in COLOR_ATT