aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2018-07-09 10:31:47 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-07-09 14:54:16 +0000
commit1354048c8fa885b83e414532c011d710590d6b46 (patch)
treee3fd906497340adbd73e5a1bbebc50c4f4ef4d15
parent373224c9ab3ae3f13c45f61521e01c282016fde0 (diff)
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>
-rw-r--r--src/gpu/GrAppliedClip.h17
-rw-r--r--src/gpu/GrClipStackClip.cpp84
-rw-r--r--src/gpu/GrClipStackClip.h3
-rw-r--r--src/gpu/GrReducedClip.cpp200
-rw-r--r--src/gpu/GrReducedClip.h42
-rw-r--r--src/gpu/GrRenderTargetContextPriv.h21
-rw-r--r--src/gpu/GrRenderTargetOpList.cpp3
-rw-r--r--src/gpu/GrRenderTargetOpList.h9
-rw-r--r--src/gpu/GrStencilClip.h2
-rw-r--r--src/gpu/ops/GrStencilAndCoverPathRenderer.cpp2
-rw-r--r--tests/ClipStackTest.cpp76
11 files changed, 244 insertions, 215 deletions
diff --git a/src/gpu/GrAppliedClip.h b/src/gpu/GrAppliedClip.h
index bfe3383e16..eb136eaccb 100644
--- a/src/gpu/GrAppliedClip.h
+++ b/src/gpu/GrAppliedClip.h
@@ -27,8 +27,7 @@ public:
const GrScissorState& scissorState() const { return fScissorState; }
const GrWindowRectsState& windowRectsState() const { return fWindowRectsState; }
- uint32_t stencilStackID() const { return fStencilStackID; }
- bool hasStencilClip() const { return SkClipStack::kInvalidGenID != fStencilStackID; }
+ bool hasStencilClip() const { return fHasStencilClip; }
/**
* Intersects the applied clip with the provided rect. Returns false if the draw became empty.
@@ -49,9 +48,9 @@ public:
fWindowRectsState.set(windows, mode);
}
- void addStencilClip(uint32_t stencilStackID) {
- SkASSERT(SkClipStack::kInvalidGenID == fStencilStackID);
- fStencilStackID = stencilStackID;
+ void addStencilClip() {
+ SkASSERT(!fHasStencilClip);
+ fHasStencilClip = true;
}
bool doesClip() const {
@@ -59,16 +58,15 @@ public:
}
bool operator==(const GrAppliedHardClip& that) const {
- return fScissorState == that.fScissorState &&
- fWindowRectsState == that.fWindowRectsState &&
- fStencilStackID == that.fStencilStackID;
+ return fScissorState == that.fScissorState && fWindowRectsState == that.fWindowRectsState &&
+ fHasStencilClip == that.fHasStencilClip;
}
bool operator!=(const GrAppliedHardClip& that) const { return !(*this == that); }
private:
GrScissorState fScissorState;
GrWindowRectsState fWindowRectsState;
- uint32_t fStencilStackID = SkClipStack::kInvalidGenID;
+ bool fHasStencilClip = false;
};
/**
@@ -82,7 +80,6 @@ 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 68c18be5e8..dea60ff3b4 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -27,11 +27,10 @@
#include "effects/GrRRectEffect.h"
#include "effects/GrTextureDomain.h"
-typedef SkClipStack::Element Element;
-typedef GrReducedClip::InitialState InitialState;
-typedef GrReducedClip::ElementList ElementList;
-
-const char GrClipStackClip::kMaskTestTag[] = "clip_mask";
+using MaskElement = GrReducedClip::MaskElement;
+using Element = SkClipStack::Element;
+using InitialState = GrReducedClip::InitialState;
+using ElementList = GrReducedClip::ElementList;
bool GrClipStackClip::quickContains(const SkRect& rect) const {
if (!fStack || fStack->isWideOpen()) {
@@ -91,10 +90,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) {
@@ -103,11 +102,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();
}
@@ -122,7 +121,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());
@@ -162,10 +161,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();
+ const Element& element = iter.get()->fElement;
- 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;
@@ -281,38 +280,25 @@ bool GrClipStackClip::applyClipMask(GrContext* context, GrRenderTargetContext* r
renderTargetContext->setNeedsStencil();
- // 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())) {
+ if (!renderTargetContext->priv().lastStencilClipKey().isValid() ||
+ !reducedClip.maskUniqueKey().isValid() ||
+ renderTargetContext->priv().lastStencilClipKey() != reducedClip.maskUniqueKey()) {
reducedClip.drawStencilClipMask(context, renderTargetContext);
- renderTargetContext->priv().setLastClip(reducedClip.maskGenID(), reducedClip.scissor(),
- reducedClip.numAnalyticFPs());
+ renderTargetContext->priv().setLastStencilClipKey(reducedClip.maskUniqueKey());
}
- // 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());
+ // The enables the stencil test against the clip bit in the applied clip.
+ out->hardClip().addStencilClip();
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) {
@@ -328,10 +314,7 @@ 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();
- GrUniqueKey key;
- create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(),
- reducedClip.numAnalyticFPs(), &key);
-
+ const GrUniqueKey& key = reducedClip.maskUniqueKey();
sk_sp<GrTextureProxy> proxy(proxyProvider->findOrCreateProxyByUniqueKey(
key, kTopLeft_GrSurfaceOrigin));
if (proxy) {
@@ -362,7 +345,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.maskGenID(), key);
+ add_invalidate_on_pop_message(*fStack, reducedClip.topMaskElementID(), key);
return result;
}
@@ -406,9 +389,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();
- SkClipOp op = element->getOp();
- GrAA aa = GrAA(element->isAA());
+ const Element& element = iter.get()->fElement;
+ 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
@@ -421,7 +404,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);
@@ -430,11 +413,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);
}
@@ -444,9 +427,7 @@ 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 {
- GrUniqueKey key;
- create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(),
- reducedClip.numAnalyticFPs(), &key);
+ const GrUniqueKey& key = reducedClip.maskUniqueKey();
GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
@@ -503,6 +484,7 @@ sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask(
SkASSERT(proxy->origin() == kTopLeft_GrSurfaceOrigin);
proxyProvider->assignUniqueKeyToProxy(key, proxy.get());
- add_invalidate_on_pop_message(*fStack, reducedClip.maskGenID(), key);
+ add_invalidate_on_pop_message(*fStack, reducedClip.topMaskElementID(), key);
+
return proxy;
}
diff --git a/src/gpu/GrClipStackClip.h b/src/gpu/GrClipStackClip.h
index aeb983468c..d4075af4c7 100644
--- a/src/gpu/GrClipStackClip.h
+++ b/src/gpu/GrClipStackClip.h
@@ -34,7 +34,6 @@ 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,
@@ -42,7 +41,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 2377846153..de3d27fb56 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -26,6 +26,8 @@
#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
@@ -89,8 +91,6 @@ GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds
fHasScissor = true;
fAAClipRect = stackBounds;
- fAAClipRectGenID = stack.getTopmostGenID();
- SkASSERT(SK_InvalidGenID != fAAClipRectGenID);
fInitialState = InitialState::kAllIn;
} else {
@@ -113,18 +113,84 @@ GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds
this->walkStack(stack, tighterQuery);
}
- 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;
+ // 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;
} else {
- fMaskElements.addToTail(fAAClipRect, SkMatrix::I(), kIntersect_SkClipOp, true /*doAA*/);
+ // 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;
}
- 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) {
@@ -155,7 +221,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 Element* element = iter.prev();
+ const SkClipStack::Element* element = iter.prev();
if (nullptr == element) {
initialTriState = InitialTriState::kAllIn;
break;
@@ -362,19 +428,14 @@ 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), SkMatrix::I(),
- kReverseDifference_SkClipOp, false);
+ fMaskElements.addToHead(SkRect::Make(fScissor), kReverseDifference_SkClipOp, false,
+ element->getGenID());
} else {
- Element* newElement = fMaskElements.addToHead(*element);
+ SkClipStack::Element* newElement = &fMaskElements.addToHead(*element)->fElement;
if (newElement->isAA()) {
++numAAElements;
}
@@ -400,8 +461,8 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound
fMaskElements.reset();
numAAElements = 0;
} else {
- Element* element = fMaskElements.headIter().get();
- while (element) {
+ SkClipStack::Element* element = &fMaskElements.headIter().get()->fElement;
+ while (true) {
bool skippable = false;
switch (element->getOp()) {
case kDifference_SkClipOp:
@@ -458,14 +519,18 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound
SkDEBUGFAIL("Unexpected op.");
break;
}
- if (!skippable) {
- break;
- } else {
+ if (skippable) {
if (element->isAA()) {
--numAAElements;
}
fMaskElements.popHead();
- element = fMaskElements.headIter().get();
+ if (fMaskElements.count()) {
+ element = &fMaskElements.headIter().get()->fElement;
+ } else {
+ break;
+ }
+ } else {
+ break;
}
}
}
@@ -475,7 +540,7 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound
fInitialState = static_cast<GrReducedClip::InitialState>(initialTriState);
}
-GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const Element* element) {
+GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const SkClipStack::Element* element) {
SkIRect elementIBounds;
if (!element->isAA()) {
element->getBounds().round(&elementIBounds);
@@ -489,21 +554,16 @@ GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const Element* elemen
}
switch (element->getDeviceSpaceType()) {
- case Element::DeviceSpaceType::kEmpty:
+ case SkClipStack::Element::DeviceSpaceType::kEmpty:
return ClipResult::kMadeEmpty;
- case Element::DeviceSpaceType::kRect:
+ case SkClipStack::Element::DeviceSpaceType::kRect:
SkASSERT(element->getBounds() == element->getDeviceSpaceRect());
SkASSERT(!element->isInverseFilled());
if (element->isAA()) {
- if (SK_InvalidGenID == fAAClipRectGenID) { // No AA clip rect yet?
+ if (fAAClipRectGenID == SK_InvalidGenID) { // No AA clip rect yet?
fAAClipRect = element->getDeviceSpaceRect();
- // 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);
+ fAAClipRectGenID = element->getGenID();
} else if (!fAAClipRect.intersect(element->getDeviceSpaceRect())) {
this->makeEmpty();
return ClipResult::kMadeEmpty;
@@ -511,12 +571,12 @@ GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const Element* elemen
}
return ClipResult::kClipped;
- case Element::DeviceSpaceType::kRRect:
+ case SkClipStack::Element::DeviceSpaceType::kRRect:
SkASSERT(!element->isInverseFilled());
return this->addAnalyticFP(element->getDeviceSpaceRRect(), Invert::kNo,
GrAA(element->isAA()));
- case Element::DeviceSpaceType::kPath:
+ case SkClipStack::Element::DeviceSpaceType::kPath:
return this->addAnalyticFP(element->getDeviceSpacePath(),
Invert(element->isInverseFilled()), GrAA(element->isAA()));
}
@@ -525,12 +585,12 @@ GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const Element* elemen
return ClipResult::kNotClipped;
}
-GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const Element* element) {
+GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const SkClipStack::Element* element) {
switch (element->getDeviceSpaceType()) {
- case Element::DeviceSpaceType::kEmpty:
+ case SkClipStack::Element::DeviceSpaceType::kEmpty:
return ClipResult::kMadeEmpty;
- case Element::DeviceSpaceType::kRect:
+ case SkClipStack::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,
@@ -543,7 +603,7 @@ GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const Element* eleme
return this->addAnalyticFP(element->getDeviceSpaceRect(), Invert::kYes,
GrAA(element->isAA()));
- case Element::DeviceSpaceType::kRRect: {
+ case SkClipStack::Element::DeviceSpaceType::kRRect: {
SkASSERT(!element->isInverseFilled());
const SkRRect& clipRRect = element->getDeviceSpaceRRect();
ClipResult clipResult = this->addAnalyticFP(clipRRect, Invert::kYes,
@@ -583,7 +643,7 @@ GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const Element* eleme
return clipResult;
}
- case Element::DeviceSpaceType::kPath:
+ case SkClipStack::Element::DeviceSpaceType::kPath:
return this->addAnalyticFP(element->getDeviceSpacePath(),
Invert(!element->isInverseFilled()), GrAA(element->isAA()));
}
@@ -681,26 +741,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;
}
}
@@ -713,18 +773,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();
}
@@ -756,10 +816,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 Element* element = iter.get();
- SkRegion::Op op = (SkRegion::Op)element->getOp();
- GrAA aa = GrAA(element->isAA());
- bool invert = element->isInverseFilled();
+ const SkClipStack::Element& element = iter.get()->fElement;
+ 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.
@@ -808,7 +868,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, this->maskGenID());
+ GrStencilClip stencilClip(fScissor, /*enable stencil clip test*/ true);
if (!fWindowRects.empty()) {
stencilClip.fixedClip().setWindowRectangles(fWindowRects,
@@ -820,9 +880,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 Element* element = iter.get();
+ const SkClipStack::Element& element = iter.get()->fElement;
GrAAType aaType = GrAAType::kNone;
- if (element->isAA() && GrFSAAType::kNone != renderTargetContext->fsaaType()) {
+ if (element.isAA() && GrFSAAType::kNone != renderTargetContext->fsaaType()) {
aaType = GrAAType::kMSAA;
}
@@ -832,15 +892,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 (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
+ if (SkClipStack::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();
@@ -884,10 +944,10 @@ bool GrReducedClip::drawStencilClipMask(GrContext* context,
GrUserStencilOp::kIncMaybeClamp,
0xffff>()
);
- if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
+ if (SkClipStack::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());
@@ -925,10 +985,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 (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
+ if (SkClipStack::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 fcdc66c843..b8447555b0 100644
--- a/src/gpu/GrReducedClip.h
+++ b/src/gpu/GrReducedClip.h
@@ -23,8 +23,22 @@ class GrRenderTargetContext;
*/
class SK_API GrReducedClip {
public:
- using Element = SkClipStack::Element;
- using ElementList = SkTLList<SkClipStack::Element, 16>;
+ /**
+ * 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>;
GrReducedClip(const SkClipStack&, const SkRect& queryBounds, const GrCaps* caps,
int maxWindowRectangles = 0, int maxAnalyticFPs = 0, int maxCCPRClipPaths = 0);
@@ -65,17 +79,13 @@ public:
*/
const ElementList& maskElements() const { return fMaskElements; }
+ const GrUniqueKey& maskUniqueKey() const;
+
/**
- * 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.
+ * 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.
*/
- uint32_t maskGenID() const { SkASSERT(!fMaskElements.isEmpty()); return fMaskGenID; }
+ uint32_t topMaskElementID() const;
/**
* Indicates whether antialiasing is required to process any of the mask elements.
@@ -100,6 +110,8 @@ public:
uint32_t opListID, int rtWidth,
int rtHeight);
+ static constexpr char kMaskTestTag[] = "clip_mask";
+
private:
void walkStack(const SkClipStack&, const SkRect& queryBounds);
@@ -111,11 +123,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 Element*);
+ ClipResult clipInsideElement(const SkClipStack::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 Element*);
+ ClipResult clipOutsideElement(const SkClipStack::Element*);
void addWindowRectangle(const SkRect& elementInteriorRect, bool elementIsAA);
@@ -140,11 +152,11 @@ private:
SkIRect fScissor;
bool fHasScissor;
SkRect fAAClipRect;
- uint32_t fAAClipRectGenID; // GenID the mask will have if includes the AA clip rect.
+ uint32_t fAAClipRectGenID; // top most GenID that contributed to fAAClipRect.
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 52f5497603..94d52debcf 100644
--- a/src/gpu/GrRenderTargetContextPriv.h
+++ b/src/gpu/GrRenderTargetContextPriv.h
@@ -23,24 +23,11 @@ struct GrUserStencilSettings;
additional data members or virtual methods. */
class GrRenderTargetContextPriv {
public:
- // 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;
+ const GrUniqueKey& lastStencilClipKey() const {
+ return fRenderTargetContext->getRTOpList()->lastStencilClipKey();
}
-
- // 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;
+ void setLastStencilClipKey(const GrUniqueKey& key) {
+ fRenderTargetContext->getRTOpList()->setLastStencilClipKey(key);
}
using CanClearFullscreen = GrRenderTargetContext::CanClearFullscreen;
diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp
index 423b71ca10..b3f31874d9 100644
--- a/src/gpu/GrRenderTargetOpList.cpp
+++ b/src/gpu/GrRenderTargetOpList.cpp
@@ -30,7 +30,6 @@ GrRenderTargetOpList::GrRenderTargetOpList(GrResourceProvider* resourceProvider,
GrRenderTargetProxy* proxy,
GrAuditTrail* auditTrail)
: INHERITED(resourceProvider, std::move(opMemoryPool), proxy, auditTrail)
- , fLastClipStackGenID(SK_InvalidUniqueID)
SkDEBUGCODE(, fNumClips(0)) {
}
@@ -202,7 +201,7 @@ bool GrRenderTargetOpList::onExecute(GrOpFlushState* flushState) {
}
void GrRenderTargetOpList::endFlush() {
- fLastClipStackGenID = SK_InvalidUniqueID;
+ fLastStencilClipKey.reset();
this->deleteOps();
fClipAllocator.reset();
INHERITED::endFlush();
diff --git a/src/gpu/GrRenderTargetOpList.h b/src/gpu/GrRenderTargetOpList.h
index 8629a7cb1f..0c7d983b29 100644
--- a/src/gpu/GrRenderTargetOpList.h
+++ b/src/gpu/GrRenderTargetOpList.h
@@ -120,9 +120,10 @@ public:
SkDEBUGCODE(int numClips() const override { return fNumClips; })
SkDEBUGCODE(void visitProxies_debugOnly(const GrOp::VisitProxyFunc&) const;)
-private:
- friend class GrRenderTargetContextPriv; // for stencil clip state. TODO: this is invasive
+ const GrUniqueKey& lastStencilClipKey() const { return fLastStencilClipKey; }
+ void setLastStencilClipKey(const GrUniqueKey& key) { fLastStencilClipKey = key; }
+private:
void deleteOps();
struct RecordedOp {
@@ -172,9 +173,7 @@ private:
bool combineIfPossible(const RecordedOp& a, GrOp* b, const GrAppliedClip* bClip,
const DstProxy* bDstTexture, const GrCaps&);
- uint32_t fLastClipStackGenID;
- SkIRect fLastDevClipBounds;
- int fLastClipNumAnalyticFPs;
+ GrUniqueKey fLastStencilClipKey;
// 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 2bbf3b44de..b0cd4e41ba 100644
--- a/src/gpu/GrStencilClip.h
+++ b/src/gpu/GrStencilClip.h
@@ -44,7 +44,7 @@ public:
return false;
}
if (this->hasStencilClip()) {
- out->addStencilClip(fStencilStackID);
+ out->addStencilClip();
}
return true;
}
diff --git a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
index f395927b63..1f048a9883 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(appliedClip.stencilStackID());
+ GrStencilClip stencilClip(true);
if (appliedClip.scissorState().enabled()) {
stencilClip.fixedClip().setScissor(appliedClip.scissorState().rect());
}
diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp
index 498e60d45a..60a8626c57 100644
--- a/tests/ClipStackTest.cpp
+++ b/tests/ClipStackTest.cpp
@@ -944,6 +944,18 @@ static void add_elem_to_stack(const SkClipStack::Element& element, SkClipStack*
}
}
+// When the entire clip is an intersection of rectangles we can wind up with a mask with one
+// AA rect element that doesn't have a known top-most contributing element.
+static bool mask_allowed_no_top_most_gen_id(const GrReducedClip& reduced) {
+ return 1 == reduced.maskElements().count() &&
+ reduced.maskElements().head()->fElement.getDeviceSpaceType() ==
+ SkClipStack::Element::DeviceSpaceType::kRect &&
+ reduced.maskElements().head()->fElement.isAA() &&
+ !reduced.maskElements().head()->fElement.isInverseFilled() &&
+ reduced.maskElements().head()->fElement.getOp() ==
+ static_cast<SkClipOp>(SkRegion::kReplace_Op);
+}
+
static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
// We construct random clip stacks, reduce them, and then rasterize both versions to verify that
// they are equal.
@@ -1043,41 +1055,35 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
auto context = GrContext::MakeMock(nullptr);
const GrCaps* caps = context->contextPriv().caps();
- // Zero the memory we will new the GrReducedClip into. This ensures the elements gen ID
- // will be kInvalidGenID if left uninitialized.
- SkAlignedSTStorage<1, GrReducedClip> storage;
- memset(storage.get(), 0, sizeof(GrReducedClip));
- GR_STATIC_ASSERT(0 == SkClipStack::kInvalidGenID);
-
// Get the reduced version of the stack.
SkRect queryBounds = kBounds;
queryBounds.outset(kBounds.width() / 2, kBounds.height() / 2);
- const GrReducedClip* reduced = new (storage.get()) GrReducedClip(stack, queryBounds, caps);
+ const GrReducedClip reduced(stack, queryBounds, caps);
- REPORTER_ASSERT(reporter,
- reduced->maskElements().isEmpty() ||
- SkClipStack::kInvalidGenID != reduced->maskGenID(),
- testCase.c_str());
+ if (!reduced.maskElements().isEmpty() && !mask_allowed_no_top_most_gen_id(reduced)) {
+ REPORTER_ASSERT(reporter, SK_InvalidGenID != reduced.topMaskElementID(),
+ testCase.c_str());
+ }
- if (!reduced->maskElements().isEmpty()) {
- REPORTER_ASSERT(reporter, reduced->hasScissor(), testCase.c_str());
+ if (!reduced.maskElements().isEmpty()) {
+ REPORTER_ASSERT(reporter, reduced.hasScissor(), testCase.c_str());
SkRect stackBounds;
SkClipStack::BoundsType stackBoundsType;
stack.getBounds(&stackBounds, &stackBoundsType);
- REPORTER_ASSERT(reporter, reduced->maskRequiresAA() == doAA, testCase.c_str());
+ REPORTER_ASSERT(reporter, reduced.maskRequiresAA() == doAA, testCase.c_str());
}
// Build a new clip stack based on the reduced clip elements
SkClipStack reducedStack;
- if (GrReducedClip::InitialState::kAllOut == reduced->initialState()) {
+ if (GrReducedClip::InitialState::kAllOut == reduced.initialState()) {
// whether the result is bounded or not, the whole plane should start outside the clip.
reducedStack.clipEmpty();
}
- for (ElementList::Iter iter(reduced->maskElements()); iter.get(); iter.next()) {
- add_elem_to_stack(*iter.get(), &reducedStack);
+ for (ElementList::Iter iter(reduced.maskElements()); iter.get(); iter.next()) {
+ add_elem_to_stack(iter.get()->fElement, &reducedStack);
}
- SkIRect scissor = reduced->hasScissor() ? reduced->scissor() : kIBounds;
+ SkIRect scissor = reduced.hasScissor() ? reduced.scissor() : kIBounds;
// GrReducedClipStack assumes that the final result is clipped to the returned bounds
reducedStack.clipDevRect(scissor, kIntersect_SkClipOp);
@@ -1091,8 +1097,6 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
set_region_to_stack(reducedStack, scissor, &reducedRegion);
REPORTER_ASSERT(reporter, region == reducedRegion, testCase.c_str());
-
- reduced->~GrReducedClip();
}
}
@@ -1102,7 +1106,7 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
#define SUPPRESS_VISIBILITY_WARNING __attribute__((visibility("hidden")))
#endif
-static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) {
+static void test_reduced_clip_stack_mask_key(skiatest::Reporter* reporter) {
{
SkClipStack stack;
stack.clipRect(SkRect::MakeXYWH(0, 0, 100, 100), SkMatrix::I(), kReplace_SkClipOp,
@@ -1114,16 +1118,9 @@ static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) {
auto context = GrContext::MakeMock(nullptr);
const GrCaps* caps = context->contextPriv().caps();
- SkAlignedSTStorage<1, GrReducedClip> storage;
- memset(storage.get(), 0, sizeof(GrReducedClip));
- GR_STATIC_ASSERT(0 == SkClipStack::kInvalidGenID);
- const GrReducedClip* reduced = new (storage.get()) GrReducedClip(stack, bounds, caps);
-
- REPORTER_ASSERT(reporter, reduced->maskElements().count() == 1);
- // Clips will be cached based on the generation id. Make sure the gen id is valid.
- REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID != reduced->maskGenID());
-
- reduced->~GrReducedClip();
+ GrReducedClip reduced(stack, bounds, caps);
+ REPORTER_ASSERT(reporter, reduced.maskElements().count() == 1);
+ REPORTER_ASSERT(reporter, reduced.maskUniqueKey().isValid());
}
{
SkClipStack stack;
@@ -1162,7 +1159,7 @@ static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) {
static const struct SUPPRESS_VISIBILITY_WARNING {
SkRect testBounds;
int reducedClipCount;
- uint32_t reducedGenID;
+ uint32_t topStackGenID;
InitialState initialState;
SkIRect clipIRect;
// parameter.
@@ -1207,17 +1204,14 @@ static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) {
const GrReducedClip reduced(stack, testCases[i].testBounds, caps);
REPORTER_ASSERT(reporter, reduced.maskElements().count() ==
testCases[i].reducedClipCount);
- SkASSERT(reduced.maskElements().count() == testCases[i].reducedClipCount);
- if (reduced.maskElements().count()) {
- REPORTER_ASSERT(reporter, reduced.maskGenID() == testCases[i].reducedGenID);
- SkASSERT(reduced.maskGenID() == testCases[i].reducedGenID);
+ if (reduced.maskElements().count() && !mask_allowed_no_top_most_gen_id(reduced)) {
+ REPORTER_ASSERT(reporter, reduced.topMaskElementID() == testCases[i].topStackGenID);
+ REPORTER_ASSERT(reporter, reduced.maskUniqueKey().isValid());
}
+
REPORTER_ASSERT(reporter, reduced.initialState() == testCases[i].initialState);
- SkASSERT(reduced.initialState() == testCases[i].initialState);
REPORTER_ASSERT(reporter, reduced.hasScissor());
- SkASSERT(reduced.hasScissor());
REPORTER_ASSERT(reporter, reduced.scissor() == testCases[i].clipIRect);
- SkASSERT(reduced.scissor() == testCases[i].clipIRect);
}
}
}
@@ -1474,7 +1468,7 @@ DEF_TEST(ClipStack, reporter) {
test_invfill_diff_bug(reporter);
test_reduced_clip_stack(reporter);
- test_reduced_clip_stack_genid(reporter);
+ test_reduced_clip_stack_mask_key(reporter);
test_reduced_clip_stack_no_aa_crash(reporter);
test_reduced_clip_stack_aa(reporter);
test_tiny_query_bounds_assertion_bug(reporter);
@@ -1499,7 +1493,7 @@ DEF_GPUTEST_FOR_ALL_CONTEXTS(ClipMaskCache, reporter, ctxInfo) {
path.addCircle(15, 15, 8);
path.setFillType(SkPath::kEvenOdd_FillType);
- static const char* kTag = GrClipStackClip::kMaskTestTag;
+ static const char* kTag = GrReducedClip::kMaskTestTag;
GrResourceCache* cache = context->contextPriv().getResourceCache();
static constexpr int kN = 5;