Don't attempt to use stencil on wrapped, stencil-less targets
We can't attach stencil to a wrapped render target. If we find
ourselves rendering to one that doesn't have stencil already, don't
issue any ops that use stencil.
Bug: chromium:1196353
Bug: skia:11943
Change-Id: I9db93f31a4f8556103be72eb708755e4eaf78136
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/399839
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrClipStack.cpp b/src/gpu/GrClipStack.cpp
index 5461bcd..4058395 100644
--- a/src/gpu/GrClipStack.cpp
+++ b/src/gpu/GrClipStack.cpp
@@ -1352,8 +1352,8 @@
// Disable analytic clips when there are user stencil settings to ensure the clip is
// respected in the stencil buffer.
remainingAnalyticFPs = 0;
- // If we have user stencil settings, we shouldn't be avoiding the stencil buffer anyways.
- SkASSERT(!context->priv().caps()->avoidStencilBuffers());
+ // If we have user stencil settings, stencil needs to be supported.
+ SkASSERT(rtc->asRenderTargetProxy()->canUseStencil(*context->priv().caps()));
}
// If window rectangles are supported, we can use them to exclude inner bounds of difference ops
@@ -1469,8 +1469,8 @@
// Now rasterize any remaining elements, either to the stencil or a SW mask. All elements are
// flattened into a single mask.
if (!elementsForMask.empty()) {
- bool stencilUnavailable = context->priv().caps()->avoidStencilBuffers() ||
- rtc->wrapsVkSecondaryCB();
+ bool stencilUnavailable =
+ !rtc->asRenderTargetProxy()->canUseStencil(*context->priv().caps());
bool hasSWMask = false;
if ((rtc->numSamples() <= 1 && maskRequiresAA) || stencilUnavailable) {
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index 75f0daa..b7de846 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -127,8 +127,6 @@
canDrawArgs.fPaint = nullptr;
canDrawArgs.fSurfaceProps = &surfaceDrawContext->surfaceProps();
canDrawArgs.fAAType = aaType;
- SkASSERT(!surfaceDrawContext->wrapsVkSecondaryCB());
- canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
// the 'false' parameter disallows use of the SW path renderer
@@ -155,10 +153,8 @@
// a clip gets complex enough it can just be done in SW regardless
// of whether it would invoke the GrSoftwarePathRenderer.
- // If we're avoiding stencils, always use SW. This includes drawing into a wrapped vulkan
- // secondary command buffer which can't handle stencils.
- if (context->priv().caps()->avoidStencilBuffers() ||
- surfaceDrawContext->wrapsVkSecondaryCB()) {
+ // If stencil isn't supported, always use SW.
+ if (!surfaceDrawContext->asRenderTargetProxy()->canUseStencil(*context->priv().caps())) {
return true;
}
@@ -214,8 +210,8 @@
if (surfaceDrawContext->numSamples() > 1 || aa == GrAAType::kMSAA || hasUserStencilSettings) {
// Disable analytic clips when we have MSAA. In MSAA we never conflate coverage and opacity.
maxAnalyticElements = 0;
- // We disable MSAA when avoiding stencil.
- SkASSERT(!context->priv().caps()->avoidStencilBuffers());
+ // We disable MSAA when stencil isn't supported.
+ SkASSERT(surfaceDrawContext->asRenderTargetProxy()->canUseStencil(*context->priv().caps()));
}
auto* ccpr = context->priv().drawingManager()->getCoverageCountingPathRenderer();
@@ -274,8 +270,7 @@
#endif
if ((surfaceDrawContext->numSamples() <= 1 && reducedClip.maskRequiresAA()) ||
- context->priv().caps()->avoidStencilBuffers() ||
- surfaceDrawContext->wrapsVkSecondaryCB()) {
+ !surfaceDrawContext->asRenderTargetProxy()->canUseStencil(*context->priv().caps())) {
GrSurfaceProxyView result;
if (UseSWOnlyPath(context, hasUserStencilSettings, surfaceDrawContext, reducedClip)) {
// The clip geometry is complex enough that it will be more efficient to create it
@@ -295,8 +290,7 @@
// If alpha or software clip mask creation fails, fall through to the stencil code paths,
// unless stencils are disallowed.
- if (context->priv().caps()->avoidStencilBuffers() ||
- surfaceDrawContext->wrapsVkSecondaryCB()) {
+ if (!surfaceDrawContext->asRenderTargetProxy()->canUseStencil(*context->priv().caps())) {
SkDebugf("WARNING: Clip mask requires stencil, but stencil unavailable. "
"Clip will be ignored.\n");
return false;
diff --git a/src/gpu/GrOpsTask.cpp b/src/gpu/GrOpsTask.cpp
index 862f151..20f97cc 100644
--- a/src/gpu/GrOpsTask.cpp
+++ b/src/gpu/GrOpsTask.cpp
@@ -574,6 +574,7 @@
GrAttachment* stencil = nullptr;
if (proxy->needsStencil()) {
+ SkASSERT(proxy->canUseStencil(caps));
if (!flushState->resourceProvider()->attachStencilAttachment(renderTarget,
fUsesMSAASurface)) {
SkDebugf("WARNING: failed to attach a stencil buffer. Rendering will be skipped.\n");
diff --git a/src/gpu/GrPathRenderer.cpp b/src/gpu/GrPathRenderer.cpp
index f06089c..eaee4e2 100644
--- a/src/gpu/GrPathRenderer.cpp
+++ b/src/gpu/GrPathRenderer.cpp
@@ -53,7 +53,6 @@
canArgs.fPaint = &args.fPaint;
canArgs.fSurfaceProps = &args.fRenderTargetContext->surfaceProps();
canArgs.fAAType = args.fAAType;
- canArgs.fTargetIsWrappedVkSecondaryCB = args.fRenderTargetContext->wrapsVkSecondaryCB();
canArgs.validate();
canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused();
diff --git a/src/gpu/GrPathRenderer.h b/src/gpu/GrPathRenderer.h
index 248950e..873d8fc 100644
--- a/src/gpu/GrPathRenderer.h
+++ b/src/gpu/GrPathRenderer.h
@@ -86,7 +86,6 @@
const GrPaint* fPaint;
const SkSurfaceProps* fSurfaceProps;
GrAAType fAAType;
- bool fTargetIsWrappedVkSecondaryCB;
// This is only used by GrTessellationPathRenderer
bool fHasUserStencilSettings;
diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp
index fdbffad..48c395c 100644
--- a/src/gpu/GrRenderTargetProxy.cpp
+++ b/src/gpu/GrRenderTargetProxy.cpp
@@ -89,6 +89,33 @@
return true;
}
+bool GrRenderTargetProxy::canUseStencil(const GrCaps& caps) const {
+ if (caps.avoidStencilBuffers() || this->wrapsVkSecondaryCB()) {
+ return false;
+ }
+ if (!this->isInstantiated()) {
+ if (this->isLazy() && this->backendFormat().backend() == GrBackendApi::kOpenGL) {
+ // It's possible for wrapped GL render targets to not have stencil. We don't currently
+ // have an exact way of knowing whether the target will be able to use stencil, so we do
+ // the best we can: if a lazy GL proxy doesn't have a texture, then it might be a
+ // wrapped target without stencil, so we conservatively block stencil.
+ // FIXME: skbug.com/11943: SkSurfaceCharacterization needs a "canUseStencil" flag.
+ return SkToBool(this->asTextureProxy());
+ } else {
+ // Otherwise the target will definitely not be wrapped. Ganesh is free to attach
+ // stencils on internal render targets.
+ return true;
+ }
+ }
+ // Just ask the actual target if we can use stencil.
+ GrRenderTarget* rt = this->peekRenderTarget();
+ // The dmsaa attachment (if any) always supports stencil. The real question is whether the
+ // non-dmsaa attachment supports stencil.
+ bool useMSAASurface = rt->numSamples() > 1;
+ return rt->getStencilAttachment(useMSAASurface) ||
+ rt->canAttemptStencilAttachment(useMSAASurface);
+}
+
sk_sp<GrSurface> GrRenderTargetProxy::createSurface(GrResourceProvider* resourceProvider) const {
sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, fSampleCnt,
GrRenderable::kYes, GrMipmapped::kNo);
diff --git a/src/gpu/GrRenderTargetProxy.h b/src/gpu/GrRenderTargetProxy.h
index f869262..debeaea 100644
--- a/src/gpu/GrRenderTargetProxy.h
+++ b/src/gpu/GrRenderTargetProxy.h
@@ -54,6 +54,11 @@
// Actually instantiate the backing rendertarget, if necessary.
bool instantiate(GrResourceProvider*) override;
+ // Returns true if this proxy either has a stencil attachment already, or if we can attach one
+ // during flush. Wrapped render targets without stencil will return false, since we are unable
+ // to modify their attachments.
+ bool canUseStencil(const GrCaps& caps) const;
+
/*
* Indicate that a draw to this proxy requires stencil.
*/
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index f0e6f1c..92b5fca 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -504,6 +504,8 @@
bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt, bool useMSAASurface) {
SkASSERT(rt);
+ SkASSERT(!this->caps()->avoidStencilBuffers());
+
GrAttachment* stencil = rt->getStencilAttachment(useMSAASurface);
if (stencil) {
SkASSERT(stencil->numSamples() == num_stencil_samples(rt, useMSAASurface, *this->caps()));
diff --git a/src/gpu/GrStencilMaskHelper.cpp b/src/gpu/GrStencilMaskHelper.cpp
index 67e24ea..ecebf19 100644
--- a/src/gpu/GrStencilMaskHelper.cpp
+++ b/src/gpu/GrStencilMaskHelper.cpp
@@ -420,7 +420,6 @@
canDrawArgs.fSurfaceProps = &fRTC->surfaceProps();
canDrawArgs.fAAType = pathAAType;
canDrawArgs.fHasUserStencilSettings = false;
- canDrawArgs.fTargetIsWrappedVkSecondaryCB = fRTC->wrapsVkSecondaryCB();
GrPathRenderer* pr = fContext->priv().drawingManager()->getPathRenderer(
canDrawArgs, false, GrPathRendererChain::DrawType::kStencil, &stencilSupport);
diff --git a/src/gpu/GrSurfaceDrawContext.cpp b/src/gpu/GrSurfaceDrawContext.cpp
index 4d97d85..323e5e6 100644
--- a/src/gpu/GrSurfaceDrawContext.cpp
+++ b/src/gpu/GrSurfaceDrawContext.cpp
@@ -928,7 +928,6 @@
canDrawArgs.fSurfaceProps = &fSurfaceProps;
canDrawArgs.fAAType = (doStencilMSAA == GrAA::kYes) ? GrAAType::kMSAA : GrAAType::kNone;
canDrawArgs.fHasUserStencilSettings = false;
- canDrawArgs.fTargetIsWrappedVkSecondaryCB = this->wrapsVkSecondaryCB();
GrPathRenderer* pr = this->drawingManager()->getPathRenderer(
canDrawArgs, false, GrPathRendererChain::DrawType::kStencil);
if (!pr) {
@@ -1621,8 +1620,6 @@
canDrawArgs.fSurfaceProps = &fSurfaceProps;
canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
canDrawArgs.fAAType = aaType;
- SkASSERT(!this->wrapsVkSecondaryCB());
- canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
// Don't allow the SW renderer
@@ -1785,7 +1782,6 @@
canDrawArgs.fPaint = &paint;
canDrawArgs.fSurfaceProps = &fSurfaceProps;
canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
- canDrawArgs.fTargetIsWrappedVkSecondaryCB = this->wrapsVkSecondaryCB();
canDrawArgs.fHasUserStencilSettings = false;
canDrawArgs.fAAType = aaType;
diff --git a/src/gpu/gl/GrGLRenderTarget.cpp b/src/gpu/gl/GrGLRenderTarget.cpp
index 9151101..98657b4 100644
--- a/src/gpu/gl/GrGLRenderTarget.cpp
+++ b/src/gpu/gl/GrGLRenderTarget.cpp
@@ -252,10 +252,8 @@
}
bool GrGLRenderTarget::canAttemptStencilAttachment(bool useMultisampleFBO) const {
- if (this->getGpu()->getContext()->priv().caps()->avoidStencilBuffers()) {
- return false;
- }
-
+ // This cap should have been handled at a higher level.
+ SkASSERT(!this->getGpu()->getContext()->priv().caps()->avoidStencilBuffers());
// Only modify the FBO's attachments if we have created the FBO. Public APIs do not currently
// allow for borrowed FBO ownership, so we can safely assume that if an object is owned,
// Skia created it.
diff --git a/src/gpu/gl/GrGLTextureRenderTarget.cpp b/src/gpu/gl/GrGLTextureRenderTarget.cpp
index 75d642c..e3e8abf 100644
--- a/src/gpu/gl/GrGLTextureRenderTarget.cpp
+++ b/src/gpu/gl/GrGLTextureRenderTarget.cpp
@@ -54,9 +54,10 @@
}
bool GrGLTextureRenderTarget::canAttemptStencilAttachment(bool useMultisampleFBO) const {
- // The RT FBO of GrGLTextureRenderTarget is never created from a
- // wrapped FBO, so we only care about the flag.
- return !this->getGpu()->getContext()->priv().caps()->avoidStencilBuffers();
+ // This cap should have been handled at a higher level.
+ SkASSERT(!this->getGpu()->getContext()->priv().caps()->avoidStencilBuffers());
+ // The RT FBO of GrGLTextureRenderTarget is never created from a wrapped FBO.
+ return true;
}
sk_sp<GrGLTextureRenderTarget> GrGLTextureRenderTarget::MakeWrapped(
diff --git a/src/gpu/ops/GrDefaultPathRenderer.cpp b/src/gpu/ops/GrDefaultPathRenderer.cpp
index 5ca9e70..9d19886 100644
--- a/src/gpu/ops/GrDefaultPathRenderer.cpp
+++ b/src/gpu/ops/GrDefaultPathRenderer.cpp
@@ -700,7 +700,7 @@
args.fShape->style(), *args.fViewMatrix, nullptr);
// If we aren't a single_pass_shape or hairline, we require stencil buffers.
if (!(single_pass_shape(*args.fShape) || isHairline) &&
- (args.fCaps->avoidStencilBuffers() || args.fTargetIsWrappedVkSecondaryCB)) {
+ !args.fProxy->canUseStencil(*args.fCaps)) {
return CanDrawPath::kNo;
}
// If antialiasing is required, we only support MSAA.
diff --git a/src/gpu/tessellate/GrTessellationPathRenderer.cpp b/src/gpu/tessellate/GrTessellationPathRenderer.cpp
index 5eadbab..8804a4a 100644
--- a/src/gpu/tessellate/GrTessellationPathRenderer.cpp
+++ b/src/gpu/tessellate/GrTessellationPathRenderer.cpp
@@ -134,7 +134,7 @@
shape.style().strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style ||
shape.inverseFilled() ||
args.fHasUserStencilSettings ||
- args.fTargetIsWrappedVkSecondaryCB) {
+ !args.fProxy->canUseStencil(*args.fCaps)) {
return CanDrawPath::kNo;
}
// On platforms that don't have native support for indirect draws and/or hardware tessellation,