diff options
author | Brian Salomon <bsalomon@google.com> | 2018-07-09 18:23:58 +0000 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-07-09 18:24:08 +0000 |
commit | c3833b4c152af3b6fa2a4c4ba7b1da02acd1af80 (patch) | |
tree | 87183da161e40d0b2fb86fdbe12a8570bfb54d40 /src | |
parent | d48897b576e9ee7df445606243d14bcb1d0b95df (diff) |
Revert "Add genIDs from all contributing elements to GrReducedClip's mask key."
This reverts commit 1354048c8fa885b83e414532c011d710590d6b46.
Reason for revert: tsan/valgrind failures
Original change's description:
> Add genIDs from all contributing elements to GrReducedClip's mask key.
>
> Change-Id: I3fed124ba3fefd1ef82acdb4ace9531d0c89ad8b
> Reviewed-on: https://skia-review.googlesource.com/138586
> Commit-Queue: Brian Salomon <bsalomon@google.com>
> Reviewed-by: Robert Phillips <robertphillips@google.com>
TBR=bsalomon@google.com,robertphillips@google.com,csmartdalton@google.com
Change-Id: Ia5bc098309cd02baf46f03d8ff17fabbd383481e
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://skia-review.googlesource.com/139920
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/GrAppliedClip.h | 17 | ||||
-rw-r--r-- | src/gpu/GrClipStackClip.cpp | 84 | ||||
-rw-r--r-- | src/gpu/GrClipStackClip.h | 3 | ||||
-rw-r--r-- | src/gpu/GrReducedClip.cpp | 200 | ||||
-rw-r--r-- | src/gpu/GrReducedClip.h | 42 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetContextPriv.h | 21 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetOpList.cpp | 3 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetOpList.h | 9 | ||||
-rw-r--r-- | src/gpu/GrStencilClip.h | 2 | ||||
-rw-r--r-- | src/gpu/ops/GrStencilAndCoverPathRenderer.cpp | 2 |
10 files changed, 174 insertions, 209 deletions
diff --git a/src/gpu/GrAppliedClip.h b/src/gpu/GrAppliedClip.h index eb136eaccb..bfe3383e16 100644 --- a/src/gpu/GrAppliedClip.h +++ b/src/gpu/GrAppliedClip.h @@ -27,7 +27,8 @@ public: const GrScissorState& scissorState() const { return fScissorState; } const GrWindowRectsState& windowRectsState() const { return fWindowRectsState; } - bool hasStencilClip() const { return fHasStencilClip; } + uint32_t stencilStackID() const { return fStencilStackID; } + bool hasStencilClip() const { return SkClipStack::kInvalidGenID != fStencilStackID; } /** * Intersects the applied clip with the provided rect. Returns false if the draw became empty. @@ -48,9 +49,9 @@ public: fWindowRectsState.set(windows, mode); } - void addStencilClip() { - SkASSERT(!fHasStencilClip); - fHasStencilClip = true; + void addStencilClip(uint32_t stencilStackID) { + SkASSERT(SkClipStack::kInvalidGenID == fStencilStackID); + fStencilStackID = stencilStackID; } bool doesClip() const { @@ -58,15 +59,16 @@ public: } bool operator==(const GrAppliedHardClip& that) const { - return fScissorState == that.fScissorState && fWindowRectsState == that.fWindowRectsState && - fHasStencilClip == that.fHasStencilClip; + return fScissorState == that.fScissorState && + fWindowRectsState == that.fWindowRectsState && + fStencilStackID == that.fStencilStackID; } bool operator!=(const GrAppliedHardClip& that) const { return !(*this == that); } private: GrScissorState fScissorState; GrWindowRectsState fWindowRectsState; - bool fHasStencilClip = false; + uint32_t fStencilStackID = SkClipStack::kInvalidGenID; }; /** @@ -80,6 +82,7 @@ public: const GrScissorState& scissorState() const { return fHardClip.scissorState(); } const GrWindowRectsState& windowRectsState() const { return fHardClip.windowRectsState(); } + uint32_t stencilStackID() const { return fHardClip.stencilStackID(); } bool hasStencilClip() const { return fHardClip.hasStencilClip(); } int numClipCoverageFragmentProcessors() const { return fClipCoverageFPs.count(); } const GrFragmentProcessor* clipCoverageFragmentProcessor(int i) const { diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp index dea60ff3b4..68c18be5e8 100644 --- a/src/gpu/GrClipStackClip.cpp +++ b/src/gpu/GrClipStackClip.cpp @@ -27,10 +27,11 @@ #include "effects/GrRRectEffect.h" #include "effects/GrTextureDomain.h" -using MaskElement = GrReducedClip::MaskElement; -using Element = SkClipStack::Element; -using InitialState = GrReducedClip::InitialState; -using ElementList = GrReducedClip::ElementList; +typedef SkClipStack::Element Element; +typedef GrReducedClip::InitialState InitialState; +typedef GrReducedClip::ElementList ElementList; + +const char GrClipStackClip::kMaskTestTag[] = "clip_mask"; bool GrClipStackClip::quickContains(const SkRect& rect) const { if (!fStack || fStack->isWideOpen()) { @@ -90,10 +91,10 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context, bool hasUserStencilSettings, const GrRenderTargetContext* renderTargetContext, const SkMatrix& viewMatrix, - const Element& element, + const Element* element, GrPathRenderer** prOut, bool needsStencil) { - if (Element::DeviceSpaceType::kRect == element.getDeviceSpaceType()) { + if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) { // rects can always be drawn directly w/o using the software path // TODO: skip rrects once we're drawing them directly. if (prOut) { @@ -102,11 +103,11 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context, return false; } else { // We shouldn't get here with an empty clip element. - SkASSERT(Element::DeviceSpaceType::kEmpty != element.getDeviceSpaceType()); + SkASSERT(Element::DeviceSpaceType::kEmpty != element->getDeviceSpaceType()); // the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer SkPath path; - element.asDeviceSpacePath(&path); + element->asDeviceSpacePath(&path); if (path.isInverseFillType()) { path.toggleInverseFillType(); } @@ -121,7 +122,7 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context, canDrawArgs.fClipConservativeBounds = &scissorRect; canDrawArgs.fViewMatrix = &viewMatrix; canDrawArgs.fShape = &shape; - canDrawArgs.fAAType = GrChooseAAType(GrAA(element.isAA()), + canDrawArgs.fAAType = GrChooseAAType(GrAA(element->isAA()), renderTargetContext->fsaaType(), GrAllowMixedSamples::kYes, *context->contextPriv().caps()); @@ -161,10 +162,10 @@ bool GrClipStackClip::UseSWOnlyPath(GrContext* context, translate.setTranslate(SkIntToScalar(-reducedClip.left()), SkIntToScalar(-reducedClip.top())); for (ElementList::Iter iter(reducedClip.maskElements()); iter.get(); iter.next()) { - const Element& element = iter.get()->fElement; + const Element* element = iter.get(); - SkClipOp op = element.getOp(); - bool invert = element.isInverseFilled(); + SkClipOp op = element->getOp(); + bool invert = element->isInverseFilled(); bool needsStencil = invert || kIntersect_SkClipOp == op || kReverseDifference_SkClipOp == op; @@ -280,25 +281,38 @@ bool GrClipStackClip::applyClipMask(GrContext* context, GrRenderTargetContext* r renderTargetContext->setNeedsStencil(); - if (!renderTargetContext->priv().lastStencilClipKey().isValid() || - !reducedClip.maskUniqueKey().isValid() || - renderTargetContext->priv().lastStencilClipKey() != reducedClip.maskUniqueKey()) { + // This relies on the property that a reduced sub-rect of the last clip will contain all the + // relevant window rectangles that were in the last clip. This subtle requirement will go away + // after clipping is overhauled. + if (renderTargetContext->priv().mustRenderClip(reducedClip.maskGenID(), reducedClip.scissor(), + reducedClip.numAnalyticFPs())) { reducedClip.drawStencilClipMask(context, renderTargetContext); - renderTargetContext->priv().setLastStencilClipKey(reducedClip.maskUniqueKey()); + renderTargetContext->priv().setLastClip(reducedClip.maskGenID(), reducedClip.scissor(), + reducedClip.numAnalyticFPs()); } - // The enables the stencil test against the clip bit in the applied clip. - out->hardClip().addStencilClip(); + // GrAppliedClip doesn't need to figure numAnalyticFPs into its key (used by operator==) because + // it verifies the FPs are also equal. + out->hardClip().addStencilClip(reducedClip.maskGenID()); return true; } //////////////////////////////////////////////////////////////////////////////// // Create a 8-bit clip mask in alpha +static void create_clip_mask_key(uint32_t clipGenID, const SkIRect& bounds, int numAnalyticFPs, + GrUniqueKey* key) { + static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); + GrUniqueKey::Builder builder(key, kDomain, 4, GrClipStackClip::kMaskTestTag); + builder[0] = clipGenID; + // SkToS16 because image filters outset layers to a size indicated by the filter, which can + // sometimes result in negative coordinates from device space. + builder[1] = SkToS16(bounds.fLeft) | (SkToS16(bounds.fRight) << 16); + builder[2] = SkToS16(bounds.fTop) | (SkToS16(bounds.fBottom) << 16); + builder[3] = numAnalyticFPs; +} + static void add_invalidate_on_pop_message(const SkClipStack& stack, uint32_t clipGenID, const GrUniqueKey& clipMaskKey) { - if (clipGenID == SK_InvalidGenID || !clipMaskKey.isValid()) { - return; - } SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); while (const Element* element = iter.prev()) { if (element->getGenID() == clipGenID) { @@ -314,7 +328,10 @@ static void add_invalidate_on_pop_message(const SkClipStack& stack, uint32_t cli sk_sp<GrTextureProxy> GrClipStackClip::createAlphaClipMask(GrContext* context, const GrReducedClip& reducedClip) const { GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); - const GrUniqueKey& key = reducedClip.maskUniqueKey(); + GrUniqueKey key; + create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(), + reducedClip.numAnalyticFPs(), &key); + sk_sp<GrTextureProxy> proxy(proxyProvider->findOrCreateProxyByUniqueKey( key, kTopLeft_GrSurfaceOrigin)); if (proxy) { @@ -345,7 +362,7 @@ sk_sp<GrTextureProxy> GrClipStackClip::createAlphaClipMask(GrContext* context, SkASSERT(result->origin() == kTopLeft_GrSurfaceOrigin); proxyProvider->assignUniqueKeyToProxy(key, result.get()); - add_invalidate_on_pop_message(*fStack, reducedClip.topMaskElementID(), key); + add_invalidate_on_pop_message(*fStack, reducedClip.maskGenID(), key); return result; } @@ -389,9 +406,9 @@ static void draw_clip_elements_to_mask_helper(GrSWMaskHelper& helper, const Elem helper.clear(InitialState::kAllIn == initialState ? 0xFF : 0x00); for (ElementList::Iter iter(elements); iter.get(); iter.next()) { - const Element& element = iter.get()->fElement; - SkClipOp op = element.getOp(); - GrAA aa = GrAA(element.isAA()); + const Element* element = iter.get(); + SkClipOp op = element->getOp(); + GrAA aa = GrAA(element->isAA()); if (kIntersect_SkClipOp == op || kReverseDifference_SkClipOp == op) { // Intersect and reverse difference require modifying pixels outside of the geometry @@ -404,7 +421,7 @@ static void draw_clip_elements_to_mask_helper(GrSWMaskHelper& helper, const Elem helper.drawRect(temp, translate, SkRegion::kXOR_Op, GrAA::kNo, 0xFF); } SkPath clipPath; - element.asDeviceSpacePath(&clipPath); + element->asDeviceSpacePath(&clipPath); clipPath.toggleInverseFillType(); GrShape shape(clipPath, GrStyle::SimpleFill()); helper.drawShape(shape, translate, SkRegion::kReplace_Op, aa, 0x00); @@ -413,11 +430,11 @@ static void draw_clip_elements_to_mask_helper(GrSWMaskHelper& helper, const Elem // The other ops (union, xor, diff) only affect pixels inside // the geometry so they can just be drawn normally - if (Element::DeviceSpaceType::kRect == element.getDeviceSpaceType()) { - helper.drawRect(element.getDeviceSpaceRect(), translate, (SkRegion::Op)op, aa, 0xFF); + if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) { + helper.drawRect(element->getDeviceSpaceRect(), translate, (SkRegion::Op)op, aa, 0xFF); } else { SkPath path; - element.asDeviceSpacePath(&path); + element->asDeviceSpacePath(&path); GrShape shape(path, GrStyle::SimpleFill()); helper.drawShape(shape, translate, (SkRegion::Op)op, aa, 0xFF); } @@ -427,7 +444,9 @@ static void draw_clip_elements_to_mask_helper(GrSWMaskHelper& helper, const Elem sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask( GrContext* context, const GrReducedClip& reducedClip, GrRenderTargetContext* renderTargetContext) const { - const GrUniqueKey& key = reducedClip.maskUniqueKey(); + GrUniqueKey key; + create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(), + reducedClip.numAnalyticFPs(), &key); GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); @@ -484,7 +503,6 @@ sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask( SkASSERT(proxy->origin() == kTopLeft_GrSurfaceOrigin); proxyProvider->assignUniqueKeyToProxy(key, proxy.get()); - add_invalidate_on_pop_message(*fStack, reducedClip.topMaskElementID(), key); - + add_invalidate_on_pop_message(*fStack, reducedClip.maskGenID(), key); return proxy; } diff --git a/src/gpu/GrClipStackClip.h b/src/gpu/GrClipStackClip.h index d4075af4c7..aeb983468c 100644 --- a/src/gpu/GrClipStackClip.h +++ b/src/gpu/GrClipStackClip.h @@ -34,6 +34,7 @@ public: bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA* aa) const override; sk_sp<GrTextureProxy> testingOnly_createClipMask(GrContext*) const; + static const char kMaskTestTag[]; private: static bool PathNeedsSWRenderer(GrContext* context, @@ -41,7 +42,7 @@ private: bool hasUserStencilSettings, const GrRenderTargetContext*, const SkMatrix& viewMatrix, - const SkClipStack::Element& element, + const SkClipStack::Element* element, GrPathRenderer** prOut, bool needsStencil); diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp index de3d27fb56..2377846153 100644 --- a/src/gpu/GrReducedClip.cpp +++ b/src/gpu/GrReducedClip.cpp @@ -26,8 +26,6 @@ #include "effects/GrConvexPolyEffect.h" #include "effects/GrRRectEffect.h" -constexpr char GrReducedClip::kMaskTestTag[]; - /** * There are plenty of optimizations that could be added here. Maybe flips could be folded into * earlier operations. Or would inserting flips and reversing earlier ops ever be a win? Perhaps @@ -91,6 +89,8 @@ GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds fHasScissor = true; fAAClipRect = stackBounds; + fAAClipRectGenID = stack.getTopmostGenID(); + SkASSERT(SK_InvalidGenID != fAAClipRectGenID); fInitialState = InitialState::kAllIn; } else { @@ -113,84 +113,18 @@ GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds this->walkStack(stack, tighterQuery); } - // Is there an AA clip rect? - if (SK_InvalidGenID != fAAClipRectGenID || iior) { - if (ClipResult::kNotClipped == this->addAnalyticFP(fAAClipRect, Invert::kNo, GrAA::kYes)) { - if (fMaskElements.isEmpty()) { - // Use a replace since it is faster than intersect. - fMaskElements.addToHead(fAAClipRect, kReplace_SkClipOp, true); - fInitialState = InitialState::kAllOut; - } else { - fMaskElements.addToTail(fAAClipRect, kIntersect_SkClipOp, true); - } - fMaskRequiresAA = true; + if (SK_InvalidGenID != fAAClipRectGenID && // Is there an AA clip rect? + ClipResult::kNotClipped == this->addAnalyticFP(fAAClipRect, Invert::kNo, GrAA::kYes)) { + if (fMaskElements.isEmpty()) { + // Use a replace since it is faster than intersect. + fMaskElements.addToHead(fAAClipRect, SkMatrix::I(), kReplace_SkClipOp, true /*doAA*/); + fInitialState = InitialState::kAllOut; } else { - // We didn't include the aa clip rect in the mask elements. Clear this so we don't - // include the rect in the mask key or report it as the top-most mask genID. - fAAClipRectGenID = SK_InvalidGenID; - } - } -} - -const GrUniqueKey& GrReducedClip::maskUniqueKey() const { - if (fMaskUniqueKey.isValid() || !fMaskElements.count()) { - SkASSERT(SkToBool(fMaskElements.count()) == fMaskUniqueKey.isValid()); - return fMaskUniqueKey; - } - int size = fMaskElements.count(); - if (fAAClipRectGenID != SK_InvalidGenID) { - // 4 for the rect edges, -1 for the rect element in fMaskElmeents which has genID 0. - size += 3; - } - size += 4; // scissor - - static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey::Builder builder(&fMaskUniqueKey, kDomain, size, kMaskTestTag); - int i = 0; - for (ElementList::Iter iter(fMaskElements); iter.get(); iter.next()) { - if (iter.get()->fOriginalGenID != SK_InvalidGenID) { - builder[i++] = iter.get()->fOriginalGenID; - } - } - if (fAAClipRectGenID != SK_InvalidGenID) { - GR_STATIC_ASSERT(sizeof(SkScalar) == sizeof(float)); - builder[i++] = static_cast<uint32_t>(SkFloat2Bits(fAAClipRect.fLeft)); - builder[i++] = static_cast<uint32_t>(SkFloat2Bits(fAAClipRect.fTop)); - builder[i++] = static_cast<uint32_t>(SkFloat2Bits(fAAClipRect.fRight)); - builder[i++] = static_cast<uint32_t>(SkFloat2Bits(fAAClipRect.fBottom)); - } - builder[i++] = static_cast<uint32_t>(fScissor.fLeft); - builder[i++] = static_cast<uint32_t>(fScissor.fTop); - builder[i++] = static_cast<uint32_t>(fScissor.fRight); - builder[i++] = static_cast<uint32_t>(fScissor.fBottom); - builder.finish(); - - return fMaskUniqueKey; -} - -uint32_t GrReducedClip::topMaskElementID() const { -#ifdef SK_DEBUG - // We expect all mask elements to have a valid gen ID with the exception of the - // unified AA rect (if present and part of the mask). - bool foundInvalidGenID = false; - for (ElementList::Iter iter(fMaskElements); iter.get(); iter.next()) { - if (iter.get()->fOriginalGenID == SK_InvalidGenID) { - SkASSERT(!foundInvalidGenID); - // In the intersection-of-rect cases we don't know or store the top-most gen ID that - // contributed to the AA rect. In that case there is only one element. - SkASSERT(fAAClipRectGenID != SK_InvalidGenID || fMaskElements.count() == 1); - foundInvalidGenID = true; + fMaskElements.addToTail(fAAClipRect, SkMatrix::I(), kIntersect_SkClipOp, true /*doAA*/); } + fMaskRequiresAA = true; + fMaskGenID = fAAClipRectGenID; } -#endif - if (!fMaskElements.count()) { - return SK_InvalidGenID; - } - auto topGenID = fMaskElements.tail()->fOriginalGenID; - if (topGenID == SK_InvalidGenID) { - return fAAClipRectGenID; - } - return topGenID; } void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBounds) { @@ -221,7 +155,7 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); int numAAElements = 0; while (InitialTriState::kUnknown == initialTriState) { - const SkClipStack::Element* element = iter.prev(); + const Element* element = iter.prev(); if (nullptr == element) { initialTriState = InitialTriState::kAllIn; break; @@ -428,14 +362,19 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound break; } if (!skippable) { + if (fMaskElements.isEmpty()) { + // This will be the last element. Record the stricter genID. + fMaskGenID = element->getGenID(); + } + // if it is a flip, change it to a bounds-filling rect if (isFlip) { SkASSERT(kXOR_SkClipOp == element->getOp() || kReverseDifference_SkClipOp == element->getOp()); - fMaskElements.addToHead(SkRect::Make(fScissor), kReverseDifference_SkClipOp, false, - element->getGenID()); + fMaskElements.addToHead(SkRect::Make(fScissor), SkMatrix::I(), + kReverseDifference_SkClipOp, false); } else { - SkClipStack::Element* newElement = &fMaskElements.addToHead(*element)->fElement; + Element* newElement = fMaskElements.addToHead(*element); if (newElement->isAA()) { ++numAAElements; } @@ -461,8 +400,8 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound fMaskElements.reset(); numAAElements = 0; } else { - SkClipStack::Element* element = &fMaskElements.headIter().get()->fElement; - while (true) { + Element* element = fMaskElements.headIter().get(); + while (element) { bool skippable = false; switch (element->getOp()) { case kDifference_SkClipOp: @@ -519,18 +458,14 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound SkDEBUGFAIL("Unexpected op."); break; } - if (skippable) { + if (!skippable) { + break; + } else { if (element->isAA()) { --numAAElements; } fMaskElements.popHead(); - if (fMaskElements.count()) { - element = &fMaskElements.headIter().get()->fElement; - } else { - break; - } - } else { - break; + element = fMaskElements.headIter().get(); } } } @@ -540,7 +475,7 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound fInitialState = static_cast<GrReducedClip::InitialState>(initialTriState); } -GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const SkClipStack::Element* element) { +GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const Element* element) { SkIRect elementIBounds; if (!element->isAA()) { element->getBounds().round(&elementIBounds); @@ -554,16 +489,21 @@ GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const SkClipStack::El } switch (element->getDeviceSpaceType()) { - case SkClipStack::Element::DeviceSpaceType::kEmpty: + case Element::DeviceSpaceType::kEmpty: return ClipResult::kMadeEmpty; - case SkClipStack::Element::DeviceSpaceType::kRect: + case Element::DeviceSpaceType::kRect: SkASSERT(element->getBounds() == element->getDeviceSpaceRect()); SkASSERT(!element->isInverseFilled()); if (element->isAA()) { - if (fAAClipRectGenID == SK_InvalidGenID) { // No AA clip rect yet? + if (SK_InvalidGenID == fAAClipRectGenID) { // No AA clip rect yet? fAAClipRect = element->getDeviceSpaceRect(); - fAAClipRectGenID = element->getGenID(); + // fAAClipRectGenID is the value we should use for fMaskGenID if we end up + // moving the AA clip rect into the mask. The mask GenID is simply the topmost + // element's GenID. And since we walk the stack backwards, this means it's just + // the first element we don't skip during our walk. + fAAClipRectGenID = fMaskElements.isEmpty() ? element->getGenID() : fMaskGenID; + SkASSERT(SK_InvalidGenID != fAAClipRectGenID); } else if (!fAAClipRect.intersect(element->getDeviceSpaceRect())) { this->makeEmpty(); return ClipResult::kMadeEmpty; @@ -571,12 +511,12 @@ GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const SkClipStack::El } return ClipResult::kClipped; - case SkClipStack::Element::DeviceSpaceType::kRRect: + case Element::DeviceSpaceType::kRRect: SkASSERT(!element->isInverseFilled()); return this->addAnalyticFP(element->getDeviceSpaceRRect(), Invert::kNo, GrAA(element->isAA())); - case SkClipStack::Element::DeviceSpaceType::kPath: + case Element::DeviceSpaceType::kPath: return this->addAnalyticFP(element->getDeviceSpacePath(), Invert(element->isInverseFilled()), GrAA(element->isAA())); } @@ -585,12 +525,12 @@ GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const SkClipStack::El return ClipResult::kNotClipped; } -GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const SkClipStack::Element* element) { +GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const Element* element) { switch (element->getDeviceSpaceType()) { - case SkClipStack::Element::DeviceSpaceType::kEmpty: + case Element::DeviceSpaceType::kEmpty: return ClipResult::kMadeEmpty; - case SkClipStack::Element::DeviceSpaceType::kRect: + case Element::DeviceSpaceType::kRect: SkASSERT(!element->isInverseFilled()); if (fWindowRects.count() < fMaxWindowRectangles) { // Clip out the inside of every rect. We won't be able to entirely skip the AA ones, @@ -603,7 +543,7 @@ GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const SkClipStack::E return this->addAnalyticFP(element->getDeviceSpaceRect(), Invert::kYes, GrAA(element->isAA())); - case SkClipStack::Element::DeviceSpaceType::kRRect: { + case Element::DeviceSpaceType::kRRect: { SkASSERT(!element->isInverseFilled()); const SkRRect& clipRRect = element->getDeviceSpaceRRect(); ClipResult clipResult = this->addAnalyticFP(clipRRect, Invert::kYes, @@ -643,7 +583,7 @@ GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const SkClipStack::E return clipResult; } - case SkClipStack::Element::DeviceSpaceType::kPath: + case Element::DeviceSpaceType::kPath: return this->addAnalyticFP(element->getDeviceSpacePath(), Invert(!element->isInverseFilled()), GrAA(element->isAA())); } @@ -741,26 +681,26 @@ static bool stencil_element(GrRenderTargetContext* rtc, const GrFixedClip& clip, const GrUserStencilSettings* ss, const SkMatrix& viewMatrix, - const SkClipStack::Element& element) { - GrAA aa = GrAA(element.isAA()); - switch (element.getDeviceSpaceType()) { + const SkClipStack::Element* element) { + GrAA aa = GrAA(element->isAA()); + switch (element->getDeviceSpaceType()) { case SkClipStack::Element::DeviceSpaceType::kEmpty: SkDEBUGFAIL("Should never get here with an empty element."); break; case SkClipStack::Element::DeviceSpaceType::kRect: - return rtc->priv().drawAndStencilRect(clip, ss, (SkRegion::Op)element.getOp(), - element.isInverseFilled(), aa, viewMatrix, - element.getDeviceSpaceRect()); + return rtc->priv().drawAndStencilRect(clip, ss, (SkRegion::Op)element->getOp(), + element->isInverseFilled(), aa, viewMatrix, + element->getDeviceSpaceRect()); break; default: { SkPath path; - element.asDeviceSpacePath(&path); + element->asDeviceSpacePath(&path); if (path.isInverseFillType()) { path.toggleInverseFillType(); } - return rtc->priv().drawAndStencilPath(clip, ss, (SkRegion::Op)element.getOp(), - element.isInverseFilled(), aa, viewMatrix, path); + return rtc->priv().drawAndStencilPath(clip, ss, (SkRegion::Op)element->getOp(), + element->isInverseFilled(), aa, viewMatrix, path); break; } } @@ -773,18 +713,18 @@ static void draw_element(GrRenderTargetContext* rtc, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, - const SkClipStack::Element& element) { + const SkClipStack::Element* element) { // TODO: Draw rrects directly here. - switch (element.getDeviceSpaceType()) { + switch (element->getDeviceSpaceType()) { case SkClipStack::Element::DeviceSpaceType::kEmpty: SkDEBUGFAIL("Should never get here with an empty element."); break; case SkClipStack::Element::DeviceSpaceType::kRect: - rtc->drawRect(clip, std::move(paint), aa, viewMatrix, element.getDeviceSpaceRect()); + rtc->drawRect(clip, std::move(paint), aa, viewMatrix, element->getDeviceSpaceRect()); break; default: { SkPath path; - element.asDeviceSpacePath(&path); + element->asDeviceSpacePath(&path); if (path.isInverseFillType()) { path.toggleInverseFillType(); } @@ -816,10 +756,10 @@ bool GrReducedClip::drawAlphaClipMask(GrRenderTargetContext* rtc) const { // walk through each clip element and perform its set op for (ElementList::Iter iter(fMaskElements); iter.get(); iter.next()) { - const SkClipStack::Element& element = iter.get()->fElement; - SkRegion::Op op = (SkRegion::Op)element.getOp(); - GrAA aa = GrAA(element.isAA()); - bool invert = element.isInverseFilled(); + const Element* element = iter.get(); + SkRegion::Op op = (SkRegion::Op)element->getOp(); + GrAA aa = GrAA(element->isAA()); + bool invert = element->isInverseFilled(); if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) { // draw directly into the result with the stencil set to make the pixels affected // by the clip shape be non-zero. @@ -868,7 +808,7 @@ bool GrReducedClip::drawAlphaClipMask(GrRenderTargetContext* rtc) const { bool GrReducedClip::drawStencilClipMask(GrContext* context, GrRenderTargetContext* renderTargetContext) const { // We set the current clip to the bounds so that our recursive draws are scissored to them. - GrStencilClip stencilClip(fScissor, /*enable stencil clip test*/ true); + GrStencilClip stencilClip(fScissor, this->maskGenID()); if (!fWindowRects.empty()) { stencilClip.fixedClip().setWindowRectangles(fWindowRects, @@ -880,9 +820,9 @@ bool GrReducedClip::drawStencilClipMask(GrContext* context, // walk through each clip element and perform its set op with the existing clip. for (ElementList::Iter iter(fMaskElements); iter.get(); iter.next()) { - const SkClipStack::Element& element = iter.get()->fElement; + const Element* element = iter.get(); GrAAType aaType = GrAAType::kNone; - if (element.isAA() && GrFSAAType::kNone != renderTargetContext->fsaaType()) { + if (element->isAA() && GrFSAAType::kNone != renderTargetContext->fsaaType()) { aaType = GrAAType::kMSAA; } @@ -892,15 +832,15 @@ bool GrReducedClip::drawStencilClipMask(GrContext* context, // stencil with arbitrary stencil settings. GrPathRenderer::StencilSupport stencilSupport; - SkRegion::Op op = (SkRegion::Op)element.getOp(); + SkRegion::Op op = (SkRegion::Op)element->getOp(); GrPathRenderer* pr = nullptr; SkPath clipPath; - if (SkClipStack::Element::DeviceSpaceType::kRect == element.getDeviceSpaceType()) { + if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) { stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; fillInverted = false; } else { - element.asDeviceSpacePath(&clipPath); + element->asDeviceSpacePath(&clipPath); fillInverted = clipPath.isInverseFillType(); if (fillInverted) { clipPath.toggleInverseFillType(); @@ -944,10 +884,10 @@ bool GrReducedClip::drawStencilClipMask(GrContext* context, GrUserStencilOp::kIncMaybeClamp, 0xffff>() ); - if (SkClipStack::Element::DeviceSpaceType::kRect == element.getDeviceSpaceType()) { + if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) { renderTargetContext->priv().stencilRect(stencilClip.fixedClip(), &kDrawToStencil, aaType, SkMatrix::I(), - element.getDeviceSpaceRect()); + element->getDeviceSpaceRect()); } else { if (!clipPath.isEmpty()) { GrShape shape(clipPath, GrStyle::SimpleFill()); @@ -985,10 +925,10 @@ bool GrReducedClip::drawStencilClipMask(GrContext* context, // element directly or a bounding rect of the entire clip. for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) { if (drawDirectToClip) { - if (SkClipStack::Element::DeviceSpaceType::kRect == element.getDeviceSpaceType()) { + if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) { renderTargetContext->priv().stencilRect(stencilClip, *pass, aaType, SkMatrix::I(), - element.getDeviceSpaceRect()); + element->getDeviceSpaceRect()); } else { GrShape shape(clipPath, GrStyle::SimpleFill()); GrPaint paint; diff --git a/src/gpu/GrReducedClip.h b/src/gpu/GrReducedClip.h index b8447555b0..fcdc66c843 100644 --- a/src/gpu/GrReducedClip.h +++ b/src/gpu/GrReducedClip.h @@ -23,22 +23,8 @@ class GrRenderTargetContext; */ class SK_API GrReducedClip { public: - /** - * Elements that contribute to the mask are not always directly copied from SkClipStack and - * may instead be synthesized by GrReducedClip. Therefore, we store the "original" gen ID of - * the element that corresponds to the MaskElement. If the MaskElement does not correspond to - * a single SkClipStack element then this ID will be SK_InvalidGenID. - */ - struct MaskElement { - MaskElement(const SkClipStack::Element& element) - : fElement(element), fOriginalGenID(element.getGenID()) {} - MaskElement(const SkRect& rect, SkClipOp op, bool doAA, uint32_t genID = SK_InvalidGenID) - : fElement(rect, SkMatrix::I(), op, doAA), fOriginalGenID(genID) {} - SkClipStack::Element fElement; - uint32_t fOriginalGenID; - }; - - using ElementList = SkTLList<MaskElement, 16>; + using Element = SkClipStack::Element; + using ElementList = SkTLList<SkClipStack::Element, 16>; GrReducedClip(const SkClipStack&, const SkRect& queryBounds, const GrCaps* caps, int maxWindowRectangles = 0, int maxAnalyticFPs = 0, int maxCCPRClipPaths = 0); @@ -79,13 +65,17 @@ public: */ const ElementList& maskElements() const { return fMaskElements; } - const GrUniqueKey& maskUniqueKey() const; - /** - * Returns the unique ID of the top most element that contributes to the mask. If this element - * is popped then any cached mask with maskUniqueKey() can be purged. + * If maskElements() are nonempty, uniquely identifies the region of the clip mask that falls + * inside of scissor(). + * + * NOTE: since clip elements might fall outside the query bounds, different regions of the same + * clip stack might have more or less restrictive IDs. + * + * FIXME: this prevents us from reusing a sub-rect of a perfectly good mask when that rect has + * been assigned a less restrictive ID. */ - uint32_t topMaskElementID() const; + uint32_t maskGenID() const { SkASSERT(!fMaskElements.isEmpty()); return fMaskGenID; } /** * Indicates whether antialiasing is required to process any of the mask elements. @@ -110,8 +100,6 @@ public: uint32_t opListID, int rtWidth, int rtHeight); - static constexpr char kMaskTestTag[] = "clip_mask"; - private: void walkStack(const SkClipStack&, const SkRect& queryBounds); @@ -123,11 +111,11 @@ private: // Intersects the clip with the element's interior, regardless of inverse fill type. // NOTE: do not call for elements followed by ops that can grow the clip. - ClipResult clipInsideElement(const SkClipStack::Element*); + ClipResult clipInsideElement(const Element*); // Intersects the clip with the element's exterior, regardless of inverse fill type. // NOTE: do not call for elements followed by ops that can grow the clip. - ClipResult clipOutsideElement(const SkClipStack::Element*); + ClipResult clipOutsideElement(const Element*); void addWindowRectangle(const SkRect& elementInteriorRect, bool elementIsAA); @@ -152,11 +140,11 @@ private: SkIRect fScissor; bool fHasScissor; SkRect fAAClipRect; - uint32_t fAAClipRectGenID; // top most GenID that contributed to fAAClipRect. + uint32_t fAAClipRectGenID; // GenID the mask will have if includes the AA clip rect. GrWindowRectangles fWindowRects; ElementList fMaskElements; + uint32_t fMaskGenID; bool fMaskRequiresAA; - mutable GrUniqueKey fMaskUniqueKey; SkSTArray<4, std::unique_ptr<GrFragmentProcessor>> fAnalyticFPs; SkSTArray<4, SkPath> fCCPRClipPaths; // Will convert to FPs once we have an opList ID for CCPR. }; diff --git a/src/gpu/GrRenderTargetContextPriv.h b/src/gpu/GrRenderTargetContextPriv.h index 94d52debcf..52f5497603 100644 --- a/src/gpu/GrRenderTargetContextPriv.h +++ b/src/gpu/GrRenderTargetContextPriv.h @@ -23,11 +23,24 @@ struct GrUserStencilSettings; additional data members or virtual methods. */ class GrRenderTargetContextPriv { public: - const GrUniqueKey& lastStencilClipKey() const { - return fRenderTargetContext->getRTOpList()->lastStencilClipKey(); + // called to note the last clip drawn to the stencil buffer. + // TODO: remove after clipping overhaul. + void setLastClip(uint32_t clipStackGenID, const SkIRect& devClipBounds, + int numClipAnalyticFPs) { + GrRenderTargetOpList* opList = fRenderTargetContext->getRTOpList(); + opList->fLastClipStackGenID = clipStackGenID; + opList->fLastDevClipBounds = devClipBounds; + opList->fLastClipNumAnalyticFPs = numClipAnalyticFPs; } - void setLastStencilClipKey(const GrUniqueKey& key) { - fRenderTargetContext->getRTOpList()->setLastStencilClipKey(key); + + // called to determine if we have to render the clip into SB. + // TODO: remove after clipping overhaul. + bool mustRenderClip(uint32_t clipStackGenID, const SkIRect& devClipBounds, + int numClipAnalyticFPs) const { + GrRenderTargetOpList* opList = fRenderTargetContext->getRTOpList(); + return opList->fLastClipStackGenID != clipStackGenID || + !opList->fLastDevClipBounds.contains(devClipBounds) || + opList->fLastClipNumAnalyticFPs != numClipAnalyticFPs; } using CanClearFullscreen = GrRenderTargetContext::CanClearFullscreen; diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp index b3f31874d9..423b71ca10 100644 --- a/src/gpu/GrRenderTargetOpList.cpp +++ b/src/gpu/GrRenderTargetOpList.cpp @@ -30,6 +30,7 @@ GrRenderTargetOpList::GrRenderTargetOpList(GrResourceProvider* resourceProvider, GrRenderTargetProxy* proxy, GrAuditTrail* auditTrail) : INHERITED(resourceProvider, std::move(opMemoryPool), proxy, auditTrail) + , fLastClipStackGenID(SK_InvalidUniqueID) SkDEBUGCODE(, fNumClips(0)) { } @@ -201,7 +202,7 @@ bool GrRenderTargetOpList::onExecute(GrOpFlushState* flushState) { } void GrRenderTargetOpList::endFlush() { - fLastStencilClipKey.reset(); + fLastClipStackGenID = SK_InvalidUniqueID; this->deleteOps(); fClipAllocator.reset(); INHERITED::endFlush(); diff --git a/src/gpu/GrRenderTargetOpList.h b/src/gpu/GrRenderTargetOpList.h index 0c7d983b29..8629a7cb1f 100644 --- a/src/gpu/GrRenderTargetOpList.h +++ b/src/gpu/GrRenderTargetOpList.h @@ -120,10 +120,9 @@ public: SkDEBUGCODE(int numClips() const override { return fNumClips; }) SkDEBUGCODE(void visitProxies_debugOnly(const GrOp::VisitProxyFunc&) const;) - const GrUniqueKey& lastStencilClipKey() const { return fLastStencilClipKey; } - void setLastStencilClipKey(const GrUniqueKey& key) { fLastStencilClipKey = key; } - private: + friend class GrRenderTargetContextPriv; // for stencil clip state. TODO: this is invasive + void deleteOps(); struct RecordedOp { @@ -173,7 +172,9 @@ private: bool combineIfPossible(const RecordedOp& a, GrOp* b, const GrAppliedClip* bClip, const DstProxy* bDstTexture, const GrCaps&); - GrUniqueKey fLastStencilClipKey; + uint32_t fLastClipStackGenID; + SkIRect fLastDevClipBounds; + int fLastClipNumAnalyticFPs; // For ops/opList we have mean: 5 stdDev: 28 SkSTArray<5, RecordedOp, true> fRecordedOps; diff --git a/src/gpu/GrStencilClip.h b/src/gpu/GrStencilClip.h index b0cd4e41ba..2bbf3b44de 100644 --- a/src/gpu/GrStencilClip.h +++ b/src/gpu/GrStencilClip.h @@ -44,7 +44,7 @@ public: return false; } if (this->hasStencilClip()) { - out->addStencilClip(); + out->addStencilClip(fStencilStackID); } return true; } diff --git a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp index 1f048a9883..f395927b63 100644 --- a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp +++ b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp @@ -108,7 +108,7 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { GrAATypeIsHW(args.fAAType), true, &appliedClip, &devBounds)) { return true; } - GrStencilClip stencilClip(true); + GrStencilClip stencilClip(appliedClip.stencilStackID()); if (appliedClip.scissorState().enabled()) { stencilClip.fixedClip().setScissor(appliedClip.scissorState().rect()); } |