| 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);
|
| + }
|
| +}
|
|
|