Fix DMSAA loads when framebuffer blits must be full
If the final MSAA resolve must contain the entire render target (as is the case in ANGLE ES2), then we also need to draw the entire proxy bounds into the DMSAA attachment during load. This is because we will have no other choice than to do a full size resolve at the end of the render pass, so the entire DMSAA attachment needs valid content. Bug: skia:12176 Bug: skia:12177 Bug: skia:12234 Bug: skia:12235 Change-Id: I106a8724de1c9cbf7106ed3720dabf37c0c17ab0 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/430256 Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
parent
65ec198696
commit
88dd356bf1
@ -3339,7 +3339,7 @@ bool GrGLCaps::canCopyAsBlit(GrGLFormat dstFormat, int dstSampleCnt,
|
||||
const GrTextureType* srcTypeIfTexture,
|
||||
const SkRect& srcBounds, bool srcBoundsExact,
|
||||
const SkIRect& srcRect, const SkIPoint& dstPoint) const {
|
||||
auto blitFramebufferFlags = this->blitFramebufferSupportFlags();
|
||||
auto blitFramebufferFlags = fBlitFramebufferFlags;
|
||||
if (!this->canFormatBeFBOColorAttachment(dstFormat) ||
|
||||
!this->canFormatBeFBOColorAttachment(srcFormat)) {
|
||||
return false;
|
||||
@ -3473,11 +3473,11 @@ GrCaps::DstCopyRestrictions GrGLCaps::getDstCopyRestrictions(const GrRenderTarge
|
||||
// creation. It isn't clear that avoiding temporary fbo creation is actually optimal.
|
||||
DstCopyRestrictions blitFramebufferRestrictions = {};
|
||||
if (src->numSamples() > 1 &&
|
||||
(this->blitFramebufferSupportFlags() & kResolveMustBeFull_BlitFrambufferFlag)) {
|
||||
(fBlitFramebufferFlags & kResolveMustBeFull_BlitFrambufferFlag)) {
|
||||
blitFramebufferRestrictions.fRectsMustMatch = GrSurfaceProxy::RectsMustMatch::kYes;
|
||||
blitFramebufferRestrictions.fMustCopyWholeSrc = true;
|
||||
// Mirroring causes rects to mismatch later, don't allow it.
|
||||
} else if (src->numSamples() > 1 && (this->blitFramebufferSupportFlags() &
|
||||
} else if (src->numSamples() > 1 && (fBlitFramebufferFlags &
|
||||
kRectsMustMatchForMSAASrc_BlitFramebufferFlag)) {
|
||||
blitFramebufferRestrictions.fRectsMustMatch = GrSurfaceProxy::RectsMustMatch::kYes;
|
||||
}
|
||||
|
@ -266,9 +266,22 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* What functionality is supported by glBlitFramebuffer.
|
||||
* Is it unsupported to only resolve a sub-rectangle of a framebuffer?
|
||||
*/
|
||||
uint32_t blitFramebufferSupportFlags() const { return fBlitFramebufferFlags; }
|
||||
bool framebufferResolvesMustBeFullSize() const {
|
||||
SkASSERT(fMSFBOType != kNone_MSFBOType);
|
||||
return fMSFBOType == kES_Apple_MSFBOType ||
|
||||
(fBlitFramebufferFlags & kResolveMustBeFull_BlitFrambufferFlag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can we resolve a single-sample framebuffer into an MSAA framebuffer?
|
||||
*/
|
||||
bool canResolveSingleToMSAA() const {
|
||||
SkASSERT(fMSFBOType != kNone_MSFBOType);
|
||||
return fMSFBOType != kES_Apple_MSFBOType &&
|
||||
!(fBlitFramebufferFlags & GrGLCaps::kNoMSAADst_BlitFramebufferFlag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the MSAA FBO extension one where the texture is multisampled when bound to an FBO and
|
||||
|
@ -2295,8 +2295,13 @@ GrGLenum GrGLGpu::prepareToDraw(GrPrimitiveType primitiveType) {
|
||||
}
|
||||
|
||||
void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect) {
|
||||
this->resolveRenderFBOs(static_cast<GrGLRenderTarget*>(target), resolveRect,
|
||||
ResolveDirection::kMSAAToSingle);
|
||||
auto glRT = static_cast<GrGLRenderTarget*>(target);
|
||||
if (this->glCaps().framebufferResolvesMustBeFullSize()) {
|
||||
this->resolveRenderFBOs(glRT, SkIRect::MakeSize(glRT->dimensions()),
|
||||
ResolveDirection::kMSAAToSingle);
|
||||
} else {
|
||||
this->resolveRenderFBOs(glRT, resolveRect, ResolveDirection::kMSAAToSingle);
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLGpu::resolveRenderFBOs(GrGLRenderTarget* rt, const SkIRect& resolveRect,
|
||||
@ -2315,13 +2320,7 @@ void GrGLGpu::resolveRenderFBOs(GrGLRenderTarget* rt, const SkIRect& resolveRect
|
||||
this->bindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, rt->singleSampleFBOID());
|
||||
} else {
|
||||
SkASSERT(resolveDirection == ResolveDirection::kSingleToMSAA);
|
||||
if (caps.msFBOType() == GrGLCaps::kES_Apple_MSFBOType ||
|
||||
(caps.blitFramebufferSupportFlags() & GrGLCaps::kNoMSAADst_BlitFramebufferFlag)) {
|
||||
// Blitting from single to multisample is not supported. Make a draw instead.
|
||||
this->copySurfaceAsDraw(rt, true/*drawToMultisampleFBO*/, rt, resolveRect,
|
||||
resolveRect.topLeft());
|
||||
return;
|
||||
}
|
||||
SkASSERT(this->glCaps().canResolveSingleToMSAA());
|
||||
this->bindFramebuffer(GR_GL_READ_FRAMEBUFFER, rt->singleSampleFBOID());
|
||||
this->bindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, rt->multisampleFBOID());
|
||||
}
|
||||
@ -2332,6 +2331,7 @@ void GrGLGpu::resolveRenderFBOs(GrGLRenderTarget* rt, const SkIRect& resolveRect
|
||||
if (GrGLCaps::kES_Apple_MSFBOType == caps.msFBOType()) {
|
||||
// The Apple extension doesn't support blitting from single to multisample.
|
||||
SkASSERT(resolveDirection != ResolveDirection::kSingleToMSAA);
|
||||
SkASSERT(resolveRect == SkIRect::MakeSize(rt->dimensions()));
|
||||
// Apple's extension uses the scissor as the blit bounds.
|
||||
// Passing in kTopLeft_GrSurfaceOrigin will make sure no transformation of the rect
|
||||
// happens inside flushScissor since resolveRect is already in native device coordinates.
|
||||
@ -2341,18 +2341,12 @@ void GrGLGpu::resolveRenderFBOs(GrGLRenderTarget* rt, const SkIRect& resolveRect
|
||||
this->disableWindowRectangles();
|
||||
GL_CALL(ResolveMultisampleFramebuffer());
|
||||
} else {
|
||||
int l, b, r, t;
|
||||
if (caps.blitFramebufferSupportFlags() & GrGLCaps::kResolveMustBeFull_BlitFrambufferFlag) {
|
||||
l = 0;
|
||||
b = 0;
|
||||
r = rt->width();
|
||||
t = rt->height();
|
||||
} else {
|
||||
l = resolveRect.x();
|
||||
b = resolveRect.y();
|
||||
r = resolveRect.x() + resolveRect.width();
|
||||
t = resolveRect.y() + resolveRect.height();
|
||||
}
|
||||
SkASSERT(!caps.framebufferResolvesMustBeFullSize() ||
|
||||
resolveRect == SkIRect::MakeSize(rt->dimensions()));
|
||||
int l = resolveRect.x();
|
||||
int b = resolveRect.y();
|
||||
int r = resolveRect.x() + resolveRect.width();
|
||||
int t = resolveRect.y() + resolveRect.height();
|
||||
|
||||
// BlitFrameBuffer respects the scissor, so disable it.
|
||||
this->flushScissorTest(GrScissorTest::kDisabled);
|
||||
|
@ -104,13 +104,26 @@ public:
|
||||
GrGLenum prepareToDraw(GrPrimitiveType primitiveType);
|
||||
|
||||
enum class ResolveDirection : bool {
|
||||
kSingleToMSAA,
|
||||
kSingleToMSAA, // glCaps.canResolveSingleToMSAA() must be true.
|
||||
kMSAAToSingle
|
||||
};
|
||||
|
||||
// Resolves the render target's single sample FBO into the MSAA, or vice versa.
|
||||
// If glCaps.framebufferResolvesMustBeFullSize() is true, resolveRect must be equal the render
|
||||
// target's bounds rect.
|
||||
// If blitting single to MSAA, glCaps.canResolveSingleToMSAA() must be true.
|
||||
void resolveRenderFBOs(GrGLRenderTarget*, const SkIRect& resolveRect, ResolveDirection,
|
||||
bool invalidateReadBufferAfterBlit = false);
|
||||
|
||||
// For loading a dynamic MSAA framebuffer when glCaps.canResolveSingleToMSAA() is false.
|
||||
// NOTE: If glCaps.framebufferResolvesMustBeFullSize() is also true, the drawBounds should be
|
||||
// equal to the proxy bounds. This is because the render pass will have to do a full size
|
||||
// resolve back into the single sample FBO when rendering is complete.
|
||||
void drawSingleIntoMSAAFBO(GrGLRenderTarget* rt, const SkIRect& drawBounds) {
|
||||
this->copySurfaceAsDraw(rt, true/*drawToMultisampleFBO*/, rt, drawBounds,
|
||||
drawBounds.topLeft());
|
||||
}
|
||||
|
||||
// The GrGLOpsRenderPass does not buffer up draws before submitting them to the gpu.
|
||||
// Thus this is the implementation of the clear call for the corresponding passthrough function
|
||||
// on GrGLOpsRenderPass.
|
||||
|
@ -31,15 +31,31 @@ void GrGLOpsRenderPass::set(GrRenderTarget* rt, bool useMSAASurface, const SkIRe
|
||||
fStencilLoadAndStoreInfo = stencilInfo;
|
||||
}
|
||||
|
||||
GrNativeRect GrGLOpsRenderPass::dmsaaLoadStoreBounds() const {
|
||||
if (fGpu->glCaps().framebufferResolvesMustBeFullSize()) {
|
||||
// If frambeffer resolves have to be full size, then resolve the entire render target during
|
||||
// load and store both, even if we will be doing so with a draw. We do this because we will
|
||||
// have no other choice than to do a full size resolve at the end of the render pass, so the
|
||||
// full DMSAA attachment needs to have valid content.
|
||||
return GrNativeRect::MakeRelativeTo(fOrigin, fRenderTarget->height(),
|
||||
SkIRect::MakeSize(fRenderTarget->dimensions()));
|
||||
} else {
|
||||
return GrNativeRect::MakeRelativeTo(fOrigin, fRenderTarget->height(), fContentBounds);
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLOpsRenderPass::onBegin() {
|
||||
auto glRT = static_cast<GrGLRenderTarget*>(fRenderTarget);
|
||||
if (fUseMultisampleFBO && fColorLoadAndStoreInfo.fLoadOp == GrLoadOp::kLoad &&
|
||||
if (fUseMultisampleFBO &&
|
||||
fColorLoadAndStoreInfo.fLoadOp == GrLoadOp::kLoad &&
|
||||
glRT->hasDynamicMSAAAttachment()) {
|
||||
// Blit the single sample fbo into the dmsaa attachment.
|
||||
auto nativeBounds = GrNativeRect::MakeRelativeTo(fOrigin, fRenderTarget->height(),
|
||||
fContentBounds);
|
||||
fGpu->resolveRenderFBOs(glRT, nativeBounds.asSkIRect(),
|
||||
GrGLGpu::ResolveDirection::kSingleToMSAA);
|
||||
// Load the single sample fbo into the dmsaa attachment.
|
||||
if (fGpu->glCaps().canResolveSingleToMSAA()) {
|
||||
fGpu->resolveRenderFBOs(glRT, this->dmsaaLoadStoreBounds().asSkIRect(),
|
||||
GrGLGpu::ResolveDirection::kSingleToMSAA);
|
||||
} else {
|
||||
fGpu->drawSingleIntoMSAAFBO(glRT, this->dmsaaLoadStoreBounds().asSkIRect());
|
||||
}
|
||||
}
|
||||
|
||||
fGpu->beginCommandBuffer(glRT, fUseMultisampleFBO, fContentBounds, fOrigin,
|
||||
@ -51,12 +67,11 @@ void GrGLOpsRenderPass::onEnd() {
|
||||
fGpu->endCommandBuffer(glRT, fUseMultisampleFBO, fColorLoadAndStoreInfo,
|
||||
fStencilLoadAndStoreInfo);
|
||||
|
||||
if (fUseMultisampleFBO && fColorLoadAndStoreInfo.fStoreOp == GrStoreOp::kStore &&
|
||||
if (fUseMultisampleFBO &&
|
||||
fColorLoadAndStoreInfo.fStoreOp == GrStoreOp::kStore &&
|
||||
glRT->hasDynamicMSAAAttachment()) {
|
||||
// Blit the msaa attachment into the single sample fbo.
|
||||
auto nativeBounds = GrNativeRect::MakeRelativeTo(fOrigin, fRenderTarget->height(),
|
||||
fContentBounds);
|
||||
fGpu->resolveRenderFBOs(glRT, nativeBounds.asSkIRect(),
|
||||
fGpu->resolveRenderFBOs(glRT, this->dmsaaLoadStoreBounds().asSkIRect(),
|
||||
GrGLGpu::ResolveDirection::kMSAAToSingle,
|
||||
true /*invalidateReadBufferAfterBlit*/);
|
||||
}
|
||||
|
@ -51,6 +51,12 @@ private:
|
||||
return fIndexPointer + baseIndex;
|
||||
}
|
||||
|
||||
// Ideally we load and store DMSAA only within the content bounds of our render pass, but if
|
||||
// the caps don't allow for partial framebuffer blits, we resolve the full target.
|
||||
// We resolve the same bounds during load and store both because if we have to do a full size
|
||||
// resolve at the end, the full DMSAA attachment needs to have valid content.
|
||||
GrNativeRect dmsaaLoadStoreBounds() const;
|
||||
|
||||
void onBegin() override;
|
||||
void onEnd() override;
|
||||
bool onBindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds) override;
|
||||
|
Loading…
Reference in New Issue
Block a user