Index: src/gpu/GrClipMaskManager.cpp |
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp |
index c7b88caa244cef3abf9ae59abab5097f919af3a3..56c0ee641b6613d1946cf32ebfff91b2c8e381f7 100644 |
--- a/src/gpu/GrClipMaskManager.cpp |
+++ b/src/gpu/GrClipMaskManager.cpp |
@@ -62,7 +62,7 @@ |
// optionally, set 'prOut' to NULL. If not, return false (and, optionally, set |
// 'prOut' to the non-SW path renderer that will do the job). |
bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context, |
- bool hasUserStencilSettings, |
+ bool isStencilDisabled, |
const GrRenderTarget* rt, |
const SkMatrix& viewMatrix, |
const Element* element, |
@@ -104,7 +104,7 @@ |
canDrawArgs.fPath = &path; |
canDrawArgs.fStyle = &GrStyle::SimpleFill(); |
canDrawArgs.fAntiAlias = element->isAA(); |
- canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings; |
+ canDrawArgs.fIsStencilDisabled = isStencilDisabled; |
canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled(); |
// the 'false' parameter disallows use of the SW path renderer |
@@ -124,10 +124,10 @@ |
const SkMatrix& viewMatrix, |
const SkClipStack::Element* element) { |
GrPathRenderer* pr; |
- constexpr bool kNeedsStencil = true; |
- constexpr bool kHasUserStencilSettings = false; |
+ static const bool kNeedsStencil = true; |
+ static const bool kStencilIsDisabled = true; |
PathNeedsSWRenderer(context, |
- kHasUserStencilSettings, |
+ kStencilIsDisabled, |
texture->asRenderTarget(), |
viewMatrix, |
element, |
@@ -179,7 +179,7 @@ |
bool needsStencil = invert || |
SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op; |
- if (PathNeedsSWRenderer(context, pipelineBuilder.hasUserStencilSettings(), |
+ if (PathNeedsSWRenderer(context, pipelineBuilder.getStencil().isDisabled(), |
rt, translate, element, nullptr, needsStencil)) { |
return true; |
} |
@@ -317,11 +317,13 @@ |
} |
bool GrClipMaskManager::setupScissorClip(const GrPipelineBuilder& pipelineBuilder, |
+ GrPipelineBuilder::AutoRestoreStencil* ars, |
const SkIRect& clipScissor, |
const SkRect* devBounds, |
GrAppliedClip* out) { |
- SkASSERT(kModifyClip_StencilClipMode != fClipMode); // TODO: Remove fClipMode. |
- fClipMode = kIgnoreClip_StencilClipMode; |
+ if (kRespectClip_StencilClipMode == fClipMode) { |
+ fClipMode = kIgnoreClip_StencilClipMode; |
+ } |
GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); |
@@ -338,11 +340,13 @@ |
if (scissor->contains(clipSpaceRTIBounds)) { |
// This counts as wide open |
+ this->setPipelineBuilderStencil(pipelineBuilder, ars); |
return true; |
} |
if (clipSpaceRTIBounds.intersect(*scissor)) { |
out->fScissorState.set(clipSpaceRTIBounds); |
+ this->setPipelineBuilderStencil(pipelineBuilder, ars); |
return true; |
} |
return false; |
@@ -352,6 +356,7 @@ |
// sort out what kind of clip mask needs to be created: alpha, stencil, |
// scissor, or entirely software |
bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, |
+ GrPipelineBuilder::AutoRestoreStencil* ars, |
const SkRect* devBounds, |
GrAppliedClip* out) { |
if (kRespectClip_StencilClipMode == fClipMode) { |
@@ -377,6 +382,7 @@ |
const GrClip& clip = doDevBoundsClip ? devBoundsClip : pipelineBuilder.clip(); |
if (clip.isWideOpen(clipSpaceRTIBounds)) { |
+ this->setPipelineBuilderStencil(pipelineBuilder, ars); |
return true; |
} |
@@ -390,7 +396,7 @@ |
SkIRect scissor = clip.irect(); |
if (scissor.intersect(clipSpaceRTIBounds)) { |
out->fScissorState.set(scissor); |
- out->fHasStencilClip = kIgnoreClip_StencilClipMode != fClipMode; |
+ this->setPipelineBuilderStencil(pipelineBuilder, ars); |
return true; |
} |
return false; |
@@ -418,6 +424,7 @@ |
if (elements.isEmpty()) { |
if (GrReducedClip::kAllIn_InitialState == initialState) { |
if (clipSpaceIBounds == clipSpaceRTIBounds) { |
+ this->setPipelineBuilderStencil(pipelineBuilder, ars); |
return true; |
} |
} else { |
@@ -426,8 +433,6 @@ |
} |
} break; |
} |
- |
- SkASSERT(kIgnoreClip_StencilClipMode == fClipMode); // TODO: Remove fClipMode. |
// An element count of 4 was chosen because of the common pattern in Blink of: |
// isect RR |
@@ -448,7 +453,7 @@ |
// color buffer anyway, so we may as well use coverage AA if nothing else in the pipe |
// is multisampled. |
disallowAnalyticAA = pipelineBuilder.isHWAntialias() || |
- pipelineBuilder.hasUserStencilSettings(); |
+ !pipelineBuilder.getStencil().isDisabled(); |
} |
const GrFragmentProcessor* clipFP = nullptr; |
if (elements.isEmpty() || |
@@ -461,6 +466,7 @@ |
!SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { |
out->fScissorState.set(scissorSpaceIBounds); |
} |
+ this->setPipelineBuilderStencil(pipelineBuilder, ars); |
out->fClipCoverageFP.reset(clipFP); |
return true; |
} |
@@ -502,6 +508,7 @@ |
SkIRect rtSpaceMaskBounds = clipSpaceIBounds; |
rtSpaceMaskBounds.offset(-clip.origin()); |
out->fClipCoverageFP.reset(create_fp_for_mask(result, rtSpaceMaskBounds)); |
+ this->setPipelineBuilderStencil(pipelineBuilder, ars); |
return true; |
} |
// if alpha clip mask creation fails fall through to the non-AA code paths |
@@ -522,14 +529,13 @@ |
SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); |
out->fScissorState.set(scissorSpaceIBounds); |
- SkASSERT(kRespectClip_StencilClipMode == fClipMode); // TODO: Remove fClipMode. |
- out->fHasStencilClip = true; |
+ this->setPipelineBuilderStencil(pipelineBuilder, ars); |
return true; |
} |
static bool stencil_element(GrDrawContext* dc, |
const SkIRect* scissorRect, |
- const GrUserStencilSettings* ss, |
+ const GrStencilSettings& ss, |
const SkMatrix& viewMatrix, |
const SkClipStack::Element* element) { |
@@ -675,32 +681,28 @@ |
// draw directly into the result with the stencil set to make the pixels affected |
// by the clip shape be non-zero. |
- static constexpr GrUserStencilSettings kStencilInElement( |
- GrUserStencilSettings::StaticInit< |
- 0xffff, |
- GrUserStencilTest::kAlways, |
- 0xffff, |
- GrUserStencilOp::kReplace, |
- GrUserStencilOp::kReplace, |
- 0xffff>() |
- ); |
- if (!stencil_element(dc.get(), &maskSpaceIBounds, &kStencilInElement, |
+ static constexpr GrStencilSettings kStencilInElement( |
+ kReplace_StencilOp, |
+ kReplace_StencilOp, |
+ kAlways_StencilFunc, |
+ 0xffff, |
+ 0xffff, |
+ 0xffff); |
+ if (!stencil_element(dc.get(), &maskSpaceIBounds, kStencilInElement, |
translate, element)) { |
texture->resourcePriv().removeUniqueKey(); |
return nullptr; |
} |
// Draw to the exterior pixels (those with a zero stencil value). |
- static constexpr GrUserStencilSettings kDrawOutsideElement( |
- GrUserStencilSettings::StaticInit< |
- 0x0000, |
- GrUserStencilTest::kEqual, |
- 0xffff, |
- GrUserStencilOp::kZero, |
- GrUserStencilOp::kZero, |
- 0xffff>() |
- ); |
- if (!dc->drawContextPriv().drawAndStencilRect(&maskSpaceIBounds, &kDrawOutsideElement, |
+ static constexpr GrStencilSettings kDrawOutsideElement( |
+ kZero_StencilOp, |
+ kZero_StencilOp, |
+ kEqual_StencilFunc, |
+ 0xffff, |
+ 0x0000, |
+ 0xffff); |
+ if (!dc->drawContextPriv().drawAndStencilRect(&maskSpaceIBounds, kDrawOutsideElement, |
op, !invert, false, |
translate, |
SkRect::Make(clipSpaceIBounds))) { |
@@ -750,6 +752,10 @@ |
SkIRect stencilSpaceIBounds(clipSpaceIBounds); |
stencilSpaceIBounds.offset(clipSpaceToStencilOffset); |
GrClip clip(stencilSpaceIBounds); |
+ |
+ int clipBit = stencilAttachment->bits(); |
+ SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers"); |
+ clipBit = (1 << (clipBit-1)); |
fDrawTarget->cmmAccess().clearStencilClip(stencilSpaceIBounds, |
GrReducedClip::kAllIn_InitialState == initialState, rt); |
@@ -792,7 +798,7 @@ |
clipPath.toggleInverseFillType(); |
} |
- SkASSERT(!pipelineBuilder.hasUserStencilSettings()); |
+ SkASSERT(pipelineBuilder.getStencil().isDisabled()); |
GrPathRenderer::CanDrawPathArgs canDrawArgs; |
canDrawArgs.fShaderCaps = this->getContext()->caps()->shaderCaps(); |
@@ -800,7 +806,7 @@ |
canDrawArgs.fPath = &clipPath; |
canDrawArgs.fStyle = &GrStyle::SimpleFill(); |
canDrawArgs.fAntiAlias = false; |
- canDrawArgs.fHasUserStencilSettings = pipelineBuilder.hasUserStencilSettings(); |
+ canDrawArgs.fIsStencilDisabled = pipelineBuilder.getStencil().isDisabled(); |
canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled(); |
pr = this->getContext()->drawingManager()->getPathRenderer(canDrawArgs, false, |
@@ -811,36 +817,40 @@ |
} |
} |
+ int passes; |
+ GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses]; |
+ |
bool canRenderDirectToStencil = |
GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport; |
- bool drawDirectToClip; // Given the renderer, the element, |
- // fill rule, and set operation should |
- // we render the element directly to |
- // stencil bit used for clipping. |
- GrUserStencilSettings const* const* stencilPasses = |
- GrStencilSettings::GetClipPasses(op, canRenderDirectToStencil, fillInverted, |
- &drawDirectToClip); |
+ bool canDrawDirectToClip; // Given the renderer, the element, |
+ // fill rule, and set operation can |
+ // we render the element directly to |
+ // stencil bit used for clipping. |
+ canDrawDirectToClip = GrStencilSettings::GetClipPasses(op, |
+ canRenderDirectToStencil, |
+ clipBit, |
+ fillInverted, |
+ &passes, |
+ stencilSettings); |
// draw the element to the client stencil bits if necessary |
- if (!drawDirectToClip) { |
- static constexpr GrUserStencilSettings kDrawToStencil( |
- GrUserStencilSettings::StaticInit< |
- 0x0000, |
- GrUserStencilTest::kAlways, |
- 0xffff, |
- GrUserStencilOp::kIncMaybeClamp, |
- GrUserStencilOp::kIncMaybeClamp, |
- 0xffff>() |
- ); |
+ if (!canDrawDirectToClip) { |
+ static constexpr GrStencilSettings kDrawToStencil( |
+ kIncClamp_StencilOp, |
+ kIncClamp_StencilOp, |
+ kAlways_StencilFunc, |
+ 0xffff, |
+ 0x0000, |
+ 0xffff); |
if (Element::kRect_Type == element->getType()) { |
- pipelineBuilder.setUserStencil(&kDrawToStencil); |
+ *pipelineBuilder.stencil() = kDrawToStencil; |
draw_non_aa_rect(fDrawTarget, pipelineBuilder, GrColor_WHITE, viewMatrix, |
element->getRect()); |
} else { |
if (!clipPath.isEmpty()) { |
if (canRenderDirectToStencil) { |
- pipelineBuilder.setUserStencil(&kDrawToStencil); |
+ *pipelineBuilder.stencil() = kDrawToStencil; |
GrPathRenderer::DrawPathArgs args; |
args.fTarget = fDrawTarget; |
@@ -869,10 +879,10 @@ |
// now we modify the clip bit by rendering either the clip |
// element directly or a bounding rect of the entire clip. |
fClipMode = kModifyClip_StencilClipMode; |
- for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) { |
- pipelineBuilder.setUserStencil(*pass); |
- |
- if (drawDirectToClip) { |
+ for (int p = 0; p < passes; ++p) { |
+ *pipelineBuilder.stencil() = stencilSettings[p]; |
+ |
+ if (canDrawDirectToClip) { |
if (Element::kRect_Type == element->getType()) { |
draw_non_aa_rect(fDrawTarget, pipelineBuilder, GrColor_WHITE, viewMatrix, |
element->getRect()); |
@@ -902,6 +912,165 @@ |
return true; |
} |
+// mapping of clip-respecting stencil funcs to normal stencil funcs |
+// mapping depends on whether stencil-clipping is in effect. |
+static const GrStencilFunc |
+ gSpecialToBasicStencilFunc[2][kClipStencilFuncCnt] = { |
+ {// Stencil-Clipping is DISABLED, we are effectively always inside the clip |
+ // In the Clip Funcs |
+ kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc |
+ kEqual_StencilFunc, // kEqualIfInClip_StencilFunc |
+ kLess_StencilFunc, // kLessIfInClip_StencilFunc |
+ kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc |
+ // Special in the clip func that forces user's ref to be 0. |
+ kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc |
+ // make ref 0 and do normal nequal. |
+ }, |
+ {// Stencil-Clipping is ENABLED |
+ // In the Clip Funcs |
+ kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc |
+ // eq stencil clip bit, mask |
+ // out user bits. |
+ |
+ kEqual_StencilFunc, // kEqualIfInClip_StencilFunc |
+ // add stencil bit to mask and ref |
+ |
+ kLess_StencilFunc, // kLessIfInClip_StencilFunc |
+ kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc |
+ // for both of these we can add |
+ // the clip bit to the mask and |
+ // ref and compare as normal |
+ // Special in the clip func that forces user's ref to be 0. |
+ kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc |
+ // make ref have only the clip bit set |
+ // and make comparison be less |
+ // 10..0 < 1..user_bits.. |
+ } |
+}; |
+ |
+void GrClipMaskManager::setPipelineBuilderStencil(const GrPipelineBuilder& pipelineBuilder, |
+ GrPipelineBuilder::AutoRestoreStencil* ars) { |
+ // We make two copies of the StencilSettings here (except in the early |
+ // exit scenario. One copy from draw state to the stack var. Then another |
+ // from the stack var to the gpu. We could make this class hold a ptr to |
+ // GrGpu's fStencilSettings and eliminate the stack copy here. |
+ |
+ // use stencil for clipping if clipping is enabled and the clip |
+ // has been written into the stencil. |
+ GrStencilSettings settings; |
+ |
+ // The GrGpu client may not be using the stencil buffer but we may need to |
+ // enable it in order to respect a stencil clip. |
+ if (pipelineBuilder.getStencil().isDisabled()) { |
+ if (GrClipMaskManager::kRespectClip_StencilClipMode == fClipMode) { |
+ static constexpr GrStencilSettings kBasicApplyClipSettings( |
+ kKeep_StencilOp, |
+ kKeep_StencilOp, |
+ kAlwaysIfInClip_StencilFunc, |
+ 0x0000, |
+ 0x0000, |
+ 0x0000); |
+ settings = kBasicApplyClipSettings; |
+ } else { |
+ return; |
+ } |
+ } else { |
+ settings = pipelineBuilder.getStencil(); |
+ } |
+ |
+ int stencilBits = 0; |
+ GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); |
+ GrStencilAttachment* stencilAttachment = this->resourceProvider()->attachStencilAttachment(rt); |
+ if (stencilAttachment) { |
+ stencilBits = stencilAttachment->bits(); |
+ } |
+ |
+ SkASSERT(this->caps()->stencilWrapOpsSupport() || !settings.usesWrapOp()); |
+ SkASSERT(this->caps()->twoSidedStencilSupport() || !settings.isTwoSided()); |
+ this->adjustStencilParams(&settings, fClipMode, stencilBits); |
+ ars->set(&pipelineBuilder); |
+ ars->setStencil(settings); |
+} |
+ |
+void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings, |
+ StencilClipMode mode, |
+ int stencilBitCnt) { |
+ SkASSERT(stencilBitCnt > 0); |
+ |
+ if (kModifyClip_StencilClipMode == mode) { |
+ // We assume that this clip manager itself is drawing to the GrGpu and |
+ // has already setup the correct values. |
+ return; |
+ } |
+ |
+ unsigned int clipBit = (1 << (stencilBitCnt - 1)); |
+ unsigned int userBits = clipBit - 1; |
+ |
+ GrStencilSettings::Face face = GrStencilSettings::kFront_Face; |
+ bool twoSided = this->caps()->twoSidedStencilSupport(); |
+ |
+ bool finished = false; |
+ while (!finished) { |
+ GrStencilFunc func = settings->func(face); |
+ uint16_t writeMask = settings->writeMask(face); |
+ uint16_t funcMask = settings->funcMask(face); |
+ uint16_t funcRef = settings->funcRef(face); |
+ |
+ SkASSERT((unsigned) func < kStencilFuncCnt); |
+ |
+ writeMask &= userBits; |
+ |
+ if (func >= kBasicStencilFuncCnt) { |
+ int respectClip = kRespectClip_StencilClipMode == mode; |
+ if (respectClip) { |
+ switch (func) { |
+ case kAlwaysIfInClip_StencilFunc: |
+ funcMask = clipBit; |
+ funcRef = clipBit; |
+ break; |
+ case kEqualIfInClip_StencilFunc: |
+ case kLessIfInClip_StencilFunc: |
+ case kLEqualIfInClip_StencilFunc: |
+ funcMask = (funcMask & userBits) | clipBit; |
+ funcRef = (funcRef & userBits) | clipBit; |
+ break; |
+ case kNonZeroIfInClip_StencilFunc: |
+ funcMask = (funcMask & userBits) | clipBit; |
+ funcRef = clipBit; |
+ break; |
+ default: |
+ SkFAIL("Unknown stencil func"); |
+ } |
+ } else { |
+ funcMask &= userBits; |
+ funcRef &= userBits; |
+ } |
+ const GrStencilFunc* table = |
+ gSpecialToBasicStencilFunc[respectClip]; |
+ func = table[func - kBasicStencilFuncCnt]; |
+ SkASSERT(func >= 0 && func < kBasicStencilFuncCnt); |
+ } else { |
+ funcMask &= userBits; |
+ funcRef &= userBits; |
+ } |
+ |
+ settings->setFunc(face, func); |
+ settings->setWriteMask(face, writeMask); |
+ settings->setFuncMask(face, funcMask); |
+ settings->setFuncRef(face, funcRef); |
+ |
+ if (GrStencilSettings::kFront_Face == face) { |
+ face = GrStencilSettings::kBack_Face; |
+ finished = !twoSided; |
+ } else { |
+ finished = true; |
+ } |
+ } |
+ if (!twoSided) { |
+ settings->copyFrontSettingsToBack(); |
+ } |
+} |
+ |
//////////////////////////////////////////////////////////////////////////////// |
GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context, |
int32_t elementsGenID, |
@@ -979,3 +1148,13 @@ |
return result; |
} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+ |
+void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stencilAttachment, |
+ GrStencilSettings* settings) { |
+ if (stencilAttachment) { |
+ int stencilBits = stencilAttachment->bits(); |
+ this->adjustStencilParams(settings, fClipMode, stencilBits); |
+ } |
+} |