Metal: fix RenderCommandEncoder compatibility check.

The original compatibility check is based on the Metal Best Practices
Guide from Apple. However, that assumes that you will be merging two
potential encoders. In our case we have an existing encoder and want to
know if we can use it for the next renderpass, which involves some
additional checks comparing store actions.y

Bug: skia:12086
Change-Id: If0f1259a02b50ff98469f10a0d1513b4977f4426
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/443405
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
Jim Van Verth 2021-08-30 14:30:11 -04:00 committed by SkCQ
parent f89a8122a4
commit 2055cb2790

View File

@ -65,6 +65,7 @@ id<MTLBlitCommandEncoder> GrMtlCommandBuffer::getBlitCommandEncoder() {
static bool compatible(const MTLRenderPassAttachmentDescriptor* first,
const MTLRenderPassAttachmentDescriptor* second,
const GrMtlPipelineState* pipelineState) {
// From the Metal Best Practices Guide:
// Check to see if the previous descriptor is compatible with the new one.
// They are compatible if:
// * they share the same rendertargets
@ -82,13 +83,55 @@ static bool compatible(const MTLRenderPassAttachmentDescriptor* first,
(second.storeAction == MTLStoreActionStoreAndMultisampleResolve);
}
bool secondDoesntSampleFirst = (!pipelineState ||
pipelineState->doesntSampleAttachment(first)) &&
second.storeAction != MTLStoreActionMultisampleResolve &&
!secondStoreActionStoreAndMultisampleResolve;
pipelineState->doesntSampleAttachment(first));
// Since we are trying to use the same encoder rather than merging two,
// we have to check to see if both store actions are mutually compatible.
bool secondStoreValid = true;
if (second.storeAction == MTLStoreActionDontCare) {
secondStoreValid = (first.storeAction == MTLStoreActionDontCare);
// TODO: if first.storeAction is Store and second.loadAction is Load,
// we could reset the active RenderCommandEncoder's store action to DontCare
} else if (second.storeAction == MTLStoreActionStore) {
if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, *)) {
secondStoreValid = (first.storeAction == MTLStoreActionStore ||
first.storeAction == MTLStoreActionStoreAndMultisampleResolve);
} else {
secondStoreValid = (first.storeAction == MTLStoreActionStore);
}
// TODO: if the first store action is DontCare we could reset the active
// RenderCommandEncoder's store action to Store, but it's not clear if it's worth it.
} else if (second.storeAction == MTLStoreActionMultisampleResolve) {
if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, *)) {
secondStoreValid = (first.resolveTexture == second.resolveTexture) &&
(first.storeAction == MTLStoreActionMultisampleResolve ||
first.storeAction == MTLStoreActionStoreAndMultisampleResolve);
} else {
secondStoreValid = (first.resolveTexture == second.resolveTexture) &&
(first.storeAction == MTLStoreActionMultisampleResolve);
}
// When we first check whether store actions are valid we don't consider resolves,
// so we need to reset that here.
storeActionsValid = secondStoreValid;
} else {
if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, *)) {
if (second.storeAction == MTLStoreActionStoreAndMultisampleResolve) {
secondStoreValid = (first.resolveTexture == second.resolveTexture) &&
(first.storeAction == MTLStoreActionStoreAndMultisampleResolve);
// TODO: if the first store action is simply MultisampleResolve we could reset
// the active RenderCommandEncoder's store action to StoreAndMultisampleResolve,
// but it's not clear if it's worth it.
// When we first check whether store actions are valid we don't consider resolves,
// so we need to reset that here.
storeActionsValid = secondStoreValid;
}
}
}
return renderTargetsMatch &&
(nil == first.texture ||
(storeActionsValid && loadActionsValid && secondDoesntSampleFirst));
(storeActionsValid && loadActionsValid && secondDoesntSampleFirst && secondStoreValid));
}
GrMtlRenderCommandEncoder* GrMtlCommandBuffer::getRenderCommandEncoder(