diff options
author | 2016-05-11 05:21:56 -0700 | |
---|---|---|
committer | 2016-05-11 05:21:56 -0700 | |
commit | e19aecdd13d83b2235faf3e2601100a2fd980b7b (patch) | |
tree | 75f24881e08d8c287b53bc3d055c68b3406ae8bf /src/gpu/GrClipMaskManager.cpp | |
parent | 3e11da7fa9b7ab26df6d6197c3f6a71d0826c97e (diff) |
Revert of Separate user and raw stencil settings (patchset #8 id:140001 of https://codereview.chromium.org/1962243002/ )
Reason for revert:
This seems to be breaking nanobench on the Windows bots with:
Caught exception 3221225477 EXCEPTION_ACCESS_VIOLATION
GrDrawTarget::stencilPath +c7
GrStencilAndCoverPathRenderer::onDrawPath +fd
GrDrawContext::internalDrawPath +509
GrDrawContext::drawPath +223
GrBlurUtils::drawPathWithMaskFilter +250
SkGpuDevice::drawPath +2ea
SkCanvas::onDrawPath +2e3
SkRecordDraw +2e6
SkBigPicture::playback +e5
SkCanvas::onDrawPicture +12c
SkCanvas::drawPicture +145
SkRecordDraw +2e6
SkBigPicture::playback +e5
SkCanvas::onDrawPicture +12c
SkCanvas::drawPicture +145
SkRecordDraw +261
SkBigPicture::playback +e5
SkCanvas::onDrawPicture +12c
SkCanvas::drawPicture +145
SkMultiPictureDraw::draw +bf
SKPBench::drawMPDPicture +1e0
SKPBench::onDraw +34
Benchmark::draw +32
time +92
setup_gpu_bench +6e
nanobench_main +77b
Original issue's description:
> Separate user and raw stencil settings
>
> Adds a new GrUserStencilSettings class that describes in abstract terms
> how a draw will use the stencil (e.g. kAlwaysIfInClip, kSetClipBit,
> etc.). GrPipelineBuilder now only defines the GrUserStencilSettings.
> When the GrPipeline is finalized, the user stencil settings are then
> translated into concrete GrStencilSettings.
>
> At this point, GrClipMaskManager only needs to tell the GrAppliedClip
> whether or not there is a stencil clip. It does not need to modify
> stencil settings and GrPipelineBuilder does not need
> AutoRestoreStencil.
>
> This is one step of the stencil overhaul. In the future it will also
> allow us to clean up the special case handling for nvpr and the
> stateful fClipMode member of GrClipMaskManager.
>
> BUG=skia:
> GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1962243002
>
> Committed: https://skia.googlesource.com/skia/+/12dbb3947e1aaf205b4fcf13b40e54e50650eb37
TBR=bsalomon@google.com,cdalton@nvidia.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:
Review-Url: https://codereview.chromium.org/1969693003
Diffstat (limited to 'src/gpu/GrClipMaskManager.cpp')
-rw-r--r-- | src/gpu/GrClipMaskManager.cpp | 297 |
1 files changed, 238 insertions, 59 deletions
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index c7b88caa24..56c0ee641b 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -62,7 +62,7 @@ static void draw_non_aa_rect(GrDrawTarget* drawTarget, // 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 @@ bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context, 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 @@ GrPathRenderer* GrClipMaskManager::GetPathRenderer(GrContext* context, 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 GrClipMaskManager::UseSWOnlyPath(GrContext* context, 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 @@ static void add_rect_to_clip(const GrClip& clip, const SkRect& devRect, GrClip* } 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 @@ bool GrClipMaskManager::setupScissorClip(const GrPipelineBuilder& pipelineBuilde 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 @@ bool GrClipMaskManager::setupScissorClip(const GrPipelineBuilder& pipelineBuilde // 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 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, const GrClip& clip = doDevBoundsClip ? devBoundsClip : pipelineBuilder.clip(); if (clip.isWideOpen(clipSpaceRTIBounds)) { + this->setPipelineBuilderStencil(pipelineBuilder, ars); return true; } @@ -390,7 +396,7 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, 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 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, if (elements.isEmpty()) { if (GrReducedClip::kAllIn_InitialState == initialState) { if (clipSpaceIBounds == clipSpaceRTIBounds) { + this->setPipelineBuilderStencil(pipelineBuilder, ars); return true; } } else { @@ -427,8 +434,6 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, } 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 // diff RR @@ -448,7 +453,7 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, // 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 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { out->fScissorState.set(scissorSpaceIBounds); } + this->setPipelineBuilderStencil(pipelineBuilder, ars); out->fClipCoverageFP.reset(clipFP); return true; } @@ -502,6 +508,7 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, 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 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, 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 @@ GrTexture* GrClipMaskManager::CreateAlphaClipMask(GrContext* context, // 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))) { @@ -751,6 +753,10 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, 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 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, clipPath.toggleInverseFillType(); } - SkASSERT(!pipelineBuilder.hasUserStencilSettings()); + SkASSERT(pipelineBuilder.getStencil().isDisabled()); GrPathRenderer::CanDrawPathArgs canDrawArgs; canDrawArgs.fShaderCaps = this->getContext()->caps()->shaderCaps(); @@ -800,7 +806,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, 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 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, } } + 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 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, // 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); + for (int p = 0; p < passes; ++p) { + *pipelineBuilder.stencil() = stencilSettings[p]; - if (drawDirectToClip) { + if (canDrawDirectToClip) { if (Element::kRect_Type == element->getType()) { draw_non_aa_rect(fDrawTarget, pipelineBuilder, GrColor_WHITE, viewMatrix, element->getRect()); @@ -902,6 +912,165 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, 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 @@ GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context, return result; } + +//////////////////////////////////////////////////////////////////////////////// + +void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stencilAttachment, + GrStencilSettings* settings) { + if (stencilAttachment) { + int stencilBits = stencilAttachment->bits(); + this->adjustStencilParams(settings, fClipMode, stencilBits); + } +} |