aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/gpu/GrClip.h24
-rw-r--r--src/gpu/GrClipStackClip.cpp153
-rw-r--r--src/gpu/GrClipStackClip.h19
-rw-r--r--src/gpu/GrReducedClip.cpp121
-rw-r--r--src/gpu/GrReducedClip.h68
-rw-r--r--src/utils/SkLua.cpp17
-rw-r--r--tests/ClipStackTest.cpp168
7 files changed, 248 insertions, 322 deletions
diff --git a/include/gpu/GrClip.h b/include/gpu/GrClip.h
index 03b9f65b9c..5f0a881653 100644
--- a/include/gpu/GrClip.h
+++ b/include/gpu/GrClip.h
@@ -129,12 +129,12 @@ public:
*/
template<typename TRect> constexpr static bool IsInsideClip(const TRect& innerClipBounds,
const SkRect& queryBounds) {
- return innerClipBounds.fRight - innerClipBounds.fLeft >= kBoundsTolerance &&
- innerClipBounds.fBottom - innerClipBounds.fTop >= kBoundsTolerance &&
- innerClipBounds.fLeft <= queryBounds.fLeft + kBoundsTolerance &&
- innerClipBounds.fTop <= queryBounds.fTop + kBoundsTolerance &&
- innerClipBounds.fRight >= queryBounds.fRight - kBoundsTolerance &&
- innerClipBounds.fBottom >= queryBounds.fBottom - kBoundsTolerance;
+ return innerClipBounds.fRight - innerClipBounds.fLeft > kBoundsTolerance &&
+ innerClipBounds.fBottom - innerClipBounds.fTop > kBoundsTolerance &&
+ innerClipBounds.fLeft < queryBounds.fLeft + kBoundsTolerance &&
+ innerClipBounds.fTop < queryBounds.fTop + kBoundsTolerance &&
+ innerClipBounds.fRight > queryBounds.fRight - kBoundsTolerance &&
+ innerClipBounds.fBottom > queryBounds.fBottom - kBoundsTolerance;
}
/**
@@ -145,12 +145,12 @@ public:
*/
template<typename TRect> constexpr static bool IsOutsideClip(const TRect& outerClipBounds,
const SkRect& queryBounds) {
- return outerClipBounds.fRight - outerClipBounds.fLeft < kBoundsTolerance ||
- outerClipBounds.fBottom - outerClipBounds.fTop < kBoundsTolerance ||
- outerClipBounds.fLeft > queryBounds.fRight - kBoundsTolerance ||
- outerClipBounds.fTop > queryBounds.fBottom - kBoundsTolerance ||
- outerClipBounds.fRight < queryBounds.fLeft + kBoundsTolerance ||
- outerClipBounds.fBottom < queryBounds.fTop + kBoundsTolerance;
+ return outerClipBounds.fRight - outerClipBounds.fLeft <= kBoundsTolerance ||
+ outerClipBounds.fBottom - outerClipBounds.fTop <= kBoundsTolerance ||
+ outerClipBounds.fLeft >= queryBounds.fRight - kBoundsTolerance ||
+ outerClipBounds.fTop >= queryBounds.fBottom - kBoundsTolerance ||
+ outerClipBounds.fRight <= queryBounds.fLeft + kBoundsTolerance ||
+ outerClipBounds.fBottom <= queryBounds.fTop + kBoundsTolerance;
}
/**
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index 4bd6d55134..e117144eb9 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -18,6 +18,7 @@
typedef SkClipStack::Element Element;
typedef GrReducedClip::InitialState InitialState;
+typedef GrReducedClip::ElementList ElementList;
static const int kMaxAnalyticElements = 4;
@@ -134,7 +135,7 @@ bool GrClipStackClip::UseSWOnlyPath(GrContext* context,
bool hasUserStencilSettings,
const GrDrawContext* drawContext,
const SkVector& clipToMaskOffset,
- const GrReducedClip::ElementList& elements) {
+ const ElementList& elements) {
// TODO: generalize this function so that when
// a clip gets complex enough it can just be done in SW regardless
// of whether it would invoke the GrSoftwarePathRenderer.
@@ -143,7 +144,7 @@ bool GrClipStackClip::UseSWOnlyPath(GrContext* context,
// space.
const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMaskOffset.fY);
- for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) {
+ for (ElementList::Iter iter(elements); iter.get(); iter.next()) {
const Element* element = iter.get();
SkRegion::Op op = element->getOp();
@@ -159,7 +160,7 @@ bool GrClipStackClip::UseSWOnlyPath(GrContext* context,
return false;
}
-static bool get_analytic_clip_processor(const GrReducedClip::ElementList& elements,
+static bool get_analytic_clip_processor(const ElementList& elements,
bool abortIfAA,
const SkVector& clipToRTOffset,
const SkRect& drawBounds,
@@ -168,7 +169,7 @@ static bool get_analytic_clip_processor(const GrReducedClip::ElementList& elemen
boundsInClipSpace = drawBounds.makeOffset(-clipToRTOffset.fX, -clipToRTOffset.fY);
SkASSERT(elements.count() <= kMaxAnalyticElements);
SkSTArray<kMaxAnalyticElements, sk_sp<GrFragmentProcessor>> fps;
- GrReducedClip::ElementList::Iter iter(elements);
+ ElementList::Iter iter(elements);
while (iter.get()) {
SkRegion::Op op = iter.get()->getOp();
bool invert;
@@ -259,28 +260,19 @@ bool GrClipStackClip::apply(GrContext* context,
const SkScalar clipX = SkIntToScalar(fOrigin.x()),
clipY = SkIntToScalar(fOrigin.y());
- GrReducedClip::ElementList elements;
- int32_t genID = 0;
- SkIRect clipSpaceIBounds;
- bool requiresAA = false;
-
- InitialState initialState = GrReducedClip::ReduceClipStack(*fStack,
- devBounds.makeOffset(clipX, clipY),
- &elements,
- &genID,
- &clipSpaceIBounds,
- &requiresAA);
- if (elements.isEmpty()) {
- if (GrReducedClip::kAllOut_InitialState == initialState || clipSpaceIBounds.isEmpty()) {
+ SkRect clipSpaceDevBounds = devBounds.makeOffset(clipX, clipY);
+ const GrReducedClip reducedClip(*fStack, clipSpaceDevBounds);
+
+ if (reducedClip.elements().isEmpty()) {
+ if (GrReducedClip::InitialState::kAllOut == reducedClip.initialState()) {
return false;
- } else {
- SkIRect scissorSpaceIBounds(clipSpaceIBounds);
+ }
+ if (!GrClip::IsInsideClip(reducedClip.iBounds(), clipSpaceDevBounds)) {
+ SkIRect scissorSpaceIBounds(reducedClip.iBounds());
scissorSpaceIBounds.offset(-fOrigin);
- if (!GrClip::IsInsideClip(scissorSpaceIBounds, devBounds)) {
- out->makeScissored(scissorSpaceIBounds);
- }
- return true;
+ out->makeScissored(scissorSpaceIBounds);
}
+ return true;
}
// An element count of 4 was chosen because of the common pattern in Blink of:
@@ -291,7 +283,7 @@ bool GrClipStackClip::apply(GrContext* context,
// when drawing rounded div borders. This could probably be tuned based on a
// configuration's relative costs of switching RTs to generate a mask vs
// longer shaders.
- if (elements.count() <= kMaxAnalyticElements) {
+ if (reducedClip.elements().count() <= kMaxAnalyticElements) {
// When there are multiple samples we want to do per-sample clipping, not compute a
// fractional pixel coverage.
bool disallowAnalyticAA = drawContext->isStencilBufferMultisampled();
@@ -302,10 +294,10 @@ bool GrClipStackClip::apply(GrContext* context,
disallowAnalyticAA = useHWAA || hasUserStencilSettings;
}
sk_sp<GrFragmentProcessor> clipFP;
- if (requiresAA &&
- get_analytic_clip_processor(elements, disallowAnalyticAA, {-clipX, -clipY}, devBounds,
- &clipFP)) {
- SkIRect scissorSpaceIBounds(clipSpaceIBounds);
+ if (reducedClip.requiresAA() &&
+ get_analytic_clip_processor(reducedClip.elements(), disallowAnalyticAA,
+ {-clipX, -clipY}, devBounds, &clipFP)) {
+ SkIRect scissorSpaceIBounds(reducedClip.iBounds());
scissorSpaceIBounds.offset(-fOrigin);
if (GrClip::IsInsideClip(scissorSpaceIBounds, devBounds)) {
out->makeFPBased(std::move(clipFP), SkRect::Make(scissorSpaceIBounds));
@@ -317,32 +309,23 @@ bool GrClipStackClip::apply(GrContext* context,
}
// If the stencil buffer is multisampled we can use it to do everything.
- if (!drawContext->isStencilBufferMultisampled() && requiresAA) {
+ if (!drawContext->isStencilBufferMultisampled() && reducedClip.requiresAA()) {
sk_sp<GrTexture> result;
// The top-left of the mask corresponds to the top-left corner of the bounds.
SkVector clipToMaskOffset = {
- SkIntToScalar(-clipSpaceIBounds.fLeft),
- SkIntToScalar(-clipSpaceIBounds.fTop)
+ SkIntToScalar(-reducedClip.left()),
+ SkIntToScalar(-reducedClip.top())
};
if (UseSWOnlyPath(context, hasUserStencilSettings, drawContext,
- clipToMaskOffset, elements)) {
+ clipToMaskOffset, reducedClip.elements())) {
// The clip geometry is complex enough that it will be more efficient to create it
// entirely in software
- result = CreateSoftwareClipMask(context->textureProvider(),
- genID,
- initialState,
- elements,
- clipToMaskOffset,
- clipSpaceIBounds);
+ result = CreateSoftwareClipMask(context->textureProvider(), reducedClip,
+ clipToMaskOffset);
} else {
- result = CreateAlphaClipMask(context,
- genID,
- initialState,
- elements,
- clipToMaskOffset,
- clipSpaceIBounds);
+ result = CreateAlphaClipMask(context, reducedClip, clipToMaskOffset);
// If createAlphaClipMask fails it means UseSWOnlyPath has a bug
SkASSERT(result);
}
@@ -350,7 +333,7 @@ bool GrClipStackClip::apply(GrContext* context,
if (result) {
// The mask's top left coord should be pinned to the rounded-out top left corner of
// clipSpace bounds. We determine the mask's position WRT to the render target here.
- SkIRect rtSpaceMaskBounds = clipSpaceIBounds;
+ SkIRect rtSpaceMaskBounds = reducedClip.iBounds();
rtSpaceMaskBounds.offset(-fOrigin);
out->makeFPBased(create_fp_for_mask(result.get(), rtSpaceMaskBounds),
SkRect::Make(rtSpaceMaskBounds));
@@ -361,22 +344,16 @@ bool GrClipStackClip::apply(GrContext* context,
// use the stencil clip if we can't represent the clip as a rectangle.
SkIPoint clipSpaceToStencilSpaceOffset = -fOrigin;
- CreateStencilClipMask(context,
- drawContext,
- genID,
- initialState,
- elements,
- clipSpaceIBounds,
- clipSpaceToStencilSpaceOffset);
+ CreateStencilClipMask(context, drawContext, reducedClip, clipSpaceToStencilSpaceOffset);
// This must occur after createStencilClipMask. That function may change the scissor. Also, it
// only guarantees that the stencil mask is correct within the bounds it was passed, so we must
// use both stencil and scissor test to the bounds for the final draw.
- SkIRect scissorSpaceIBounds(clipSpaceIBounds);
- scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset);
- if (GrClip::IsInsideClip(scissorSpaceIBounds, devBounds)) {
+ if (GrClip::IsInsideClip(reducedClip.iBounds(), clipSpaceDevBounds)) {
out->makeStencil(true, devBounds);
} else {
+ SkIRect scissorSpaceIBounds(reducedClip.iBounds());
+ scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset);
out->makeScissoredStencil(scissorSpaceIBounds);
}
return true;
@@ -457,14 +434,11 @@ static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
}
sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
- int32_t elementsGenID,
- GrReducedClip::InitialState initialState,
- const GrReducedClip::ElementList& elements,
- const SkVector& clipToMaskOffset,
- const SkIRect& clipSpaceIBounds) {
+ const GrReducedClip& reducedClip,
+ const SkVector& clipToMaskOffset) {
GrResourceProvider* resourceProvider = context->resourceProvider();
GrUniqueKey key;
- GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key);
+ GetClipMaskKey(reducedClip.genID(), reducedClip.iBounds(), &key);
if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) {
return sk_sp<GrTexture>(texture);
}
@@ -476,8 +450,8 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
}
sk_sp<GrDrawContext> dc(context->makeDrawContext(SkBackingFit::kApprox,
- clipSpaceIBounds.width(),
- clipSpaceIBounds.height(),
+ reducedClip.width(),
+ reducedClip.height(),
config, nullptr));
if (!dc) {
return nullptr;
@@ -485,12 +459,12 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
// The texture may be larger than necessary, this rect represents the part of the texture
// we populate with a rasterization of the clip.
- SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height());
+ SkIRect maskSpaceIBounds = SkIRect::MakeWH(reducedClip.width(), reducedClip.height());
// The scratch texture that we are drawing into can be substantially larger than the mask. Only
// clear the part that we care about.
dc->clear(&maskSpaceIBounds,
- GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000,
+ GrReducedClip::InitialState::kAllIn == reducedClip.initialState() ? -1 : 0,
true);
// Set the matrix so that rendered clip elements are transformed to mask space from clip
@@ -503,7 +477,7 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
// cleared.
// walk through each clip element and perform its set op
- for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get(); iter.next()) {
+ for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()) {
const Element* element = iter.get();
SkRegion::Op op = element->getOp();
bool invert = element->isInverseFilled();
@@ -539,7 +513,7 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideElement,
op, !invert, false,
translate,
- SkRect::Make(clipSpaceIBounds))) {
+ SkRect::Make(reducedClip.iBounds()))) {
return nullptr;
}
} else {
@@ -563,10 +537,7 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
// (as opposed to canvas) coordinates
bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
GrDrawContext* drawContext,
- int32_t elementsGenID,
- GrReducedClip::InitialState initialState,
- const GrReducedClip::ElementList& elements,
- const SkIRect& clipSpaceIBounds,
+ const GrReducedClip& reducedClip,
const SkIPoint& clipSpaceToStencilOffset) {
SkASSERT(drawContext);
@@ -577,8 +548,10 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
}
// TODO: these need to be swapped over to using a StencilAttachmentProxy
- if (stencilAttachment->mustRenderClip(elementsGenID, clipSpaceIBounds, clipSpaceToStencilOffset)) {
- stencilAttachment->setLastClip(elementsGenID, clipSpaceIBounds, clipSpaceToStencilOffset);
+ if (stencilAttachment->mustRenderClip(reducedClip.genID(), reducedClip.iBounds(),
+ clipSpaceToStencilOffset)) {
+ stencilAttachment->setLastClip(reducedClip.genID(), reducedClip.iBounds(),
+ clipSpaceToStencilOffset);
// Set the matrix so that rendered clip elements are transformed from clip to stencil space.
SkVector translate = {
SkIntToScalar(clipSpaceToStencilOffset.fX),
@@ -588,17 +561,16 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
viewMatrix.setTranslate(translate);
// We set the current clip to the bounds so that our recursive draws are scissored to them.
- SkIRect stencilSpaceIBounds(clipSpaceIBounds);
+ SkIRect stencilSpaceIBounds(reducedClip.iBounds());
stencilSpaceIBounds.offset(clipSpaceToStencilOffset);
GrFixedClip clip(stencilSpaceIBounds);
- drawContext->drawContextPriv().clearStencilClip(
- stencilSpaceIBounds,
- GrReducedClip::kAllIn_InitialState == initialState);
+ bool insideClip = GrReducedClip::InitialState::kAllIn == reducedClip.initialState();
+ drawContext->drawContextPriv().clearStencilClip(stencilSpaceIBounds, insideClip);
// walk through each clip element and perform its set op
// with the existing clip.
- for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) {
+ for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()) {
const Element* element = iter.get();
bool useHWAA = element->isAA() && drawContext->isStencilBufferMultisampled();
@@ -732,11 +704,11 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
} else {
// The view matrix is setup to do clip space -> stencil space translation, so
// draw rect in clip space.
- SkRect bounds = SkRect::Make(clipSpaceIBounds);
+ SkRect bounds = SkRect::Make(reducedClip.iBounds());
bounds.offset(translate.fX, translate.fY);
clip.enableStencilClip(bounds);
drawContext->drawContextPriv().stencilRect(clip, *pass, false, viewMatrix,
- SkRect::Make(clipSpaceIBounds));
+ SkRect::Make(reducedClip.iBounds()));
}
}
}
@@ -746,20 +718,17 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
////////////////////////////////////////////////////////////////////////////////
sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texProvider,
- int32_t elementsGenID,
- GrReducedClip::InitialState initialState,
- const GrReducedClip::ElementList& elements,
- const SkVector& clipToMaskOffset,
- const SkIRect& clipSpaceIBounds) {
+ const GrReducedClip& reducedClip,
+ const SkVector& clipToMaskOffset) {
GrUniqueKey key;
- GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key);
+ GetClipMaskKey(reducedClip.genID(), reducedClip.iBounds(), &key);
if (GrTexture* texture = texProvider->findAndRefTextureByUniqueKey(key)) {
return sk_sp<GrTexture>(texture);
}
// The mask texture may be larger than necessary. We round out the clip space bounds and pin
// the top left corner of the resulting rect to the top left of the texture.
- SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height());
+ SkIRect maskSpaceIBounds = SkIRect::MakeWH(reducedClip.width(), reducedClip.height());
GrSWMaskHelper helper(texProvider);
@@ -769,9 +738,9 @@ sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texP
translate.setTranslate(clipToMaskOffset);
helper.init(maskSpaceIBounds, &translate);
- helper.clear(GrReducedClip::kAllIn_InitialState == initialState ? 0xFF : 0x00);
+ helper.clear(GrReducedClip::InitialState::kAllIn == reducedClip.initialState() ? 0xFF : 0x00);
- for (GrReducedClip::ElementList::Iter iter(elements.headIter()) ; iter.get(); iter.next()) {
+ for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()) {
const Element* element = iter.get();
SkRegion::Op op = element->getOp();
@@ -781,7 +750,7 @@ sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texP
// but leave the pixels inside the geometry alone. For reverse difference we invert all
// the pixels before clearing the ones outside the geometry.
if (SkRegion::kReverseDifference_Op == op) {
- SkRect temp = SkRect::Make(clipSpaceIBounds);
+ SkRect temp = SkRect::Make(reducedClip.iBounds());
// invert the entire scene
helper.drawRect(temp, SkRegion::kXOR_Op, false, 0xFF);
}
@@ -807,8 +776,8 @@ sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texP
// Allocate clip mask texture
GrSurfaceDesc desc;
- desc.fWidth = clipSpaceIBounds.width();
- desc.fHeight = clipSpaceIBounds.height();
+ desc.fWidth = reducedClip.width();
+ desc.fHeight = reducedClip.height();
desc.fConfig = kAlpha_8_GrPixelConfig;
sk_sp<GrTexture> result(texProvider->createApproxTexture(desc));
diff --git a/src/gpu/GrClipStackClip.h b/src/gpu/GrClipStackClip.h
index 38f9e2d671..aaa2f90e3a 100644
--- a/src/gpu/GrClipStackClip.h
+++ b/src/gpu/GrClipStackClip.h
@@ -52,28 +52,19 @@ private:
// Draws the clip into the stencil buffer
static bool CreateStencilClipMask(GrContext*,
GrDrawContext*,
- int32_t elementsGenID,
- GrReducedClip::InitialState initialState,
- const GrReducedClip::ElementList& elements,
- const SkIRect& clipSpaceIBounds,
+ const GrReducedClip&,
const SkIPoint& clipSpaceToStencilOffset);
// Creates an alpha mask of the clip. The mask is a rasterization of elements through the
// rect specified by clipSpaceIBounds.
static sk_sp<GrTexture> CreateAlphaClipMask(GrContext*,
- int32_t elementsGenID,
- GrReducedClip::InitialState initialState,
- const GrReducedClip::ElementList& elements,
- const SkVector& clipToMaskOffset,
- const SkIRect& clipSpaceIBounds);
+ const GrReducedClip&,
+ const SkVector& clipToMaskOffset);
// Similar to createAlphaClipMask but it rasterizes in SW and uploads to the result texture.
static sk_sp<GrTexture> CreateSoftwareClipMask(GrTextureProvider*,
- int32_t elementsGenID,
- GrReducedClip::InitialState initialState,
- const GrReducedClip::ElementList& elements,
- const SkVector& clipToMaskOffset,
- const SkIRect& clipSpaceIBounds);
+ const GrReducedClip&,
+ const SkVector& clipToMaskOffset);
static bool UseSWOnlyPath(GrContext*,
bool hasUserStencilSettings,
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp
index 2940f6a682..f7bac4aa58 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Google Inc.
+ * Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
@@ -23,9 +23,11 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
// b) an operation that is known to make the bounds all inside/outside
// c) a replace operation
- static const GrReducedClip::InitialState kUnknown_InitialState =
- static_cast<GrReducedClip::InitialState>(-1);
- GrReducedClip::InitialState initialState = kUnknown_InitialState;
+ enum class InitialTriState {
+ kUnknown = -1,
+ kAllIn = (int)GrReducedClip::InitialState::kAllIn,
+ kAllOut = (int)GrReducedClip::InitialState::kAllOut
+ } initialState = InitialTriState::kUnknown;
// During our backwards walk, track whether we've seen ops that either grow or shrink the clip.
// TODO: track these per saved clip so that we can consider them on the forward pass.
@@ -39,18 +41,18 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
int numAAElements = 0;
- while (kUnknown_InitialState == initialState) {
+ while (InitialTriState::kUnknown == initialState) {
const Element* element = iter.prev();
if (nullptr == element) {
- initialState = GrReducedClip::kAllIn_InitialState;
+ initialState = InitialTriState::kAllIn;
break;
}
if (SkClipStack::kEmptyGenID == element->getGenID()) {
- initialState = GrReducedClip::kAllOut_InitialState;
+ initialState = InitialTriState::kAllOut;
break;
}
if (SkClipStack::kWideOpenGenID == element->getGenID()) {
- initialState = GrReducedClip::kAllIn_InitialState;
+ initialState = InitialTriState::kAllIn;
break;
}
@@ -65,12 +67,12 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
if (element->contains(relaxedQueryBounds)) {
skippable = true;
} else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- initialState = GrReducedClip::kAllOut_InitialState;
+ initialState = InitialTriState::kAllOut;
skippable = true;
}
} else {
if (element->contains(relaxedQueryBounds)) {
- initialState = GrReducedClip::kAllOut_InitialState;
+ initialState = InitialTriState::kAllOut;
skippable = true;
} else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
skippable = true;
@@ -86,7 +88,7 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
// empty.
if (element->isInverseFilled()) {
if (element->contains(relaxedQueryBounds)) {
- initialState = GrReducedClip::kAllOut_InitialState;
+ initialState = InitialTriState::kAllOut;
skippable = true;
} else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
skippable = true;
@@ -95,7 +97,7 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
if (element->contains(relaxedQueryBounds)) {
skippable = true;
} else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- initialState = GrReducedClip::kAllOut_InitialState;
+ initialState = InitialTriState::kAllOut;
skippable = true;
}
}
@@ -111,12 +113,12 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
if (element->contains(relaxedQueryBounds)) {
skippable = true;
} else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- initialState = GrReducedClip::kAllIn_InitialState;
+ initialState = InitialTriState::kAllIn;
skippable = true;
}
} else {
if (element->contains(relaxedQueryBounds)) {
- initialState = GrReducedClip::kAllIn_InitialState;
+ initialState = InitialTriState::kAllIn;
skippable = true;
} else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
skippable = true;
@@ -155,7 +157,7 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
// all outside the current clip.B
if (element->isInverseFilled()) {
if (element->contains(relaxedQueryBounds)) {
- initialState = GrReducedClip::kAllOut_InitialState;
+ initialState = InitialTriState::kAllOut;
skippable = true;
} else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
isFlip = true;
@@ -164,7 +166,7 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
if (element->contains(relaxedQueryBounds)) {
isFlip = true;
} else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- initialState = GrReducedClip::kAllOut_InitialState;
+ initialState = InitialTriState::kAllOut;
skippable = true;
}
}
@@ -180,23 +182,23 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
// setting the correct value for initialState.
if (element->isInverseFilled()) {
if (element->contains(relaxedQueryBounds)) {
- initialState = GrReducedClip::kAllOut_InitialState;
+ initialState = InitialTriState::kAllOut;
skippable = true;
} else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- initialState = GrReducedClip::kAllIn_InitialState;
+ initialState = InitialTriState::kAllIn;
skippable = true;
}
} else {
if (element->contains(relaxedQueryBounds)) {
- initialState = GrReducedClip::kAllIn_InitialState;
+ initialState = InitialTriState::kAllIn;
skippable = true;
} else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- initialState = GrReducedClip::kAllOut_InitialState;
+ initialState = InitialTriState::kAllOut;
skippable = true;
}
}
if (!skippable) {
- initialState = GrReducedClip::kAllOut_InitialState;
+ initialState = InitialTriState::kAllOut;
embiggens = emsmallens = true;
}
break;
@@ -230,16 +232,16 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
newElement->invertShapeFillType();
newElement->setOp(SkRegion::kDifference_Op);
if (isReplace) {
- SkASSERT(GrReducedClip::kAllOut_InitialState == initialState);
- initialState = GrReducedClip::kAllIn_InitialState;
+ SkASSERT(InitialTriState::kAllOut == initialState);
+ initialState = InitialTriState::kAllIn;
}
}
}
}
}
- if ((GrReducedClip::kAllOut_InitialState == initialState && !embiggens) ||
- (GrReducedClip::kAllIn_InitialState == initialState && !emsmallens)) {
+ if ((InitialTriState::kAllOut == initialState && !embiggens) ||
+ (InitialTriState::kAllIn == initialState && !emsmallens)) {
result->reset();
numAAElements = 0;
} else {
@@ -249,20 +251,20 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
switch (element->getOp()) {
case SkRegion::kDifference_Op:
// subtracting from the empty set yields the empty set.
- skippable = GrReducedClip::kAllOut_InitialState == initialState;
+ skippable = InitialTriState::kAllOut == initialState;
break;
case SkRegion::kIntersect_Op:
// intersecting with the empty set yields the empty set
- if (GrReducedClip::kAllOut_InitialState == initialState) {
+ if (InitialTriState::kAllOut == initialState) {
skippable = true;
} else {
// We can clear to zero and then simply draw the clip element.
- initialState = GrReducedClip::kAllOut_InitialState;
+ initialState = InitialTriState::kAllOut;
element->setOp(SkRegion::kReplace_Op);
}
break;
case SkRegion::kUnion_Op:
- if (GrReducedClip::kAllIn_InitialState == initialState) {
+ if (InitialTriState::kAllIn == initialState) {
// unioning the infinite plane with anything is a no-op.
skippable = true;
} else {
@@ -271,23 +273,23 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
}
break;
case SkRegion::kXOR_Op:
- if (GrReducedClip::kAllOut_InitialState == initialState) {
+ if (InitialTriState::kAllOut == initialState) {
// xor could be changed to diff in the kAllIn case, not sure it's a win.
element->setOp(SkRegion::kReplace_Op);
}
break;
case SkRegion::kReverseDifference_Op:
- if (GrReducedClip::kAllIn_InitialState == initialState) {
+ if (InitialTriState::kAllIn == initialState) {
// subtracting the whole plane will yield the empty set.
skippable = true;
- initialState = GrReducedClip::kAllOut_InitialState;
+ initialState = InitialTriState::kAllOut;
} else {
// this picks up flips inserted in the backwards pass.
skippable = element->isInverseFilled() ?
GrClip::IsOutsideClip(element->getBounds(), queryBounds) :
element->contains(relaxedQueryBounds);
if (skippable) {
- initialState = GrReducedClip::kAllIn_InitialState;
+ initialState = InitialTriState::kAllIn;
} else {
element->setOp(SkRegion::kReplace_Op);
}
@@ -315,7 +317,7 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
*requiresAA = numAAElements > 0;
if (0 == result->count()) {
- if (initialState == GrReducedClip::kAllIn_InitialState) {
+ if (initialState == InitialTriState::kAllIn) {
*resultGenID = SkClipStack::kWideOpenGenID;
} else {
*resultGenID = SkClipStack::kEmptyGenID;
@@ -323,7 +325,8 @@ static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
}
SkASSERT(SkClipStack::kInvalidGenID != *resultGenID);
- return initialState;
+ SkASSERT(InitialTriState::kUnknown != initialState);
+ return static_cast<GrReducedClip::InitialState>(initialState);
}
/*
@@ -333,25 +336,20 @@ for the case where the bounds are kInsideOut_BoundsType. We could restrict earli
based on later intersect operations, and perhaps remove intersect-rects. We could optionally
take a rect in case the caller knows a bound on what is to be drawn through this clip.
*/
-GrReducedClip::InitialState GrReducedClip::ReduceClipStack(const SkClipStack& stack,
- const SkRect& queryBounds,
- ElementList* result,
- int32_t* resultGenID,
- SkIRect* clipIBounds,
- bool* requiresAA) {
+GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds) {
SkASSERT(!queryBounds.isEmpty());
- result->reset();
// The clip established by the element list might be cached based on the last
// generation id. When we make early returns, we do not know what was the generation
// id that lead to the state. Make a conservative guess.
- *resultGenID = stack.getTopmostGenID();
+ fGenID = stack.getTopmostGenID();
// TODO: instead devise a way of telling the caller to disregard some or all of the clip bounds.
- *clipIBounds = GrClip::GetPixelIBounds(queryBounds);
+ fIBounds = GrClip::GetPixelIBounds(queryBounds);
if (stack.isWideOpen()) {
- return kAllIn_InitialState;
+ fInitialState = InitialState::kAllIn;
+ return;
}
SkClipStack::BoundsType stackBoundsType;
@@ -361,7 +359,8 @@ GrReducedClip::InitialState GrReducedClip::ReduceClipStack(const SkClipStack& st
if (stackBounds.isEmpty() || GrClip::IsOutsideClip(stackBounds, queryBounds)) {
bool insideOut = SkClipStack::kInsideOut_BoundsType == stackBoundsType;
- return insideOut ? kAllIn_InitialState : kAllOut_InitialState;
+ fInitialState = insideOut ? InitialState::kAllIn : InitialState::kAllOut;
+ return;
}
if (iior) {
@@ -371,31 +370,39 @@ GrReducedClip::InitialState GrReducedClip::ReduceClipStack(const SkClipStack& st
SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
if (!iter.prev()->isAA() || GrClip::IsPixelAligned(stackBounds)) {
// The clip is a non-aa rect. This is the one spot where we can actually implement the
- // clip (using clipIBounds) rather than just telling the caller what it should be.
- stackBounds.round(clipIBounds);
- return kAllIn_InitialState;
+ // clip (using fIBounds) rather than just telling the caller what it should be.
+ stackBounds.round(&fIBounds);
+ fInitialState = fIBounds.isEmpty() ? InitialState::kAllOut : InitialState::kAllIn;
+ return;
}
if (GrClip::IsInsideClip(stackBounds, queryBounds)) {
- return kAllIn_InitialState;
+ fInitialState = InitialState::kAllIn;
+ return;
}
+ SkAssertResult(fIBounds.intersect(GrClip::GetPixelIBounds(stackBounds)));
+ SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOutsideClip above.
+
// Implement the clip with an AA rect element.
- result->addToHead(stackBounds, SkRegion::kReplace_Op, true/*doAA*/);
- *requiresAA = true;
+ fElements.addToHead(stackBounds, SkRegion::kReplace_Op, true/*doAA*/);
+ fRequiresAA = true;
- SkAssertResult(clipIBounds->intersect(GrClip::GetPixelIBounds(stackBounds)));
- return kAllOut_InitialState;
+ fInitialState = InitialState::kAllOut;
+ return;
}
SkRect tighterQuery = queryBounds;
if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
// Tighten the query by introducing a new clip at the stack's pixel boundaries. (This new
- // clip will be enforced by the scissor through clipIBounds.)
+ // clip will be enforced by the scissor through fIBounds.)
SkAssertResult(tighterQuery.intersect(GrClip::GetPixelBounds(stackBounds)));
- *clipIBounds = GrClip::GetPixelIBounds(tighterQuery);
+ fIBounds = GrClip::GetPixelIBounds(tighterQuery);
}
+ SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOutsideClip above.
+
// Now that we have determined the bounds to use and filtered out the trivial cases, call the
// helper that actually walks the stack.
- return reduced_stack_walker(stack, tighterQuery, *clipIBounds, result, resultGenID, requiresAA);
+ fInitialState = reduced_stack_walker(stack, tighterQuery, fIBounds, &fElements, &fGenID,
+ &fRequiresAA);
}
diff --git a/src/gpu/GrReducedClip.h b/src/gpu/GrReducedClip.h
index 780f6f1ff5..07e06694a1 100644
--- a/src/gpu/GrReducedClip.h
+++ b/src/gpu/GrReducedClip.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Google Inc.
+ * Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
@@ -11,37 +11,57 @@
#include "SkClipStack.h"
#include "SkTLList.h"
+/**
+ * This class takes a clip stack and produces a reduced set of elements that are equivalent to
+ * applying that full stack within a specified query rectangle.
+ */
class SK_API GrReducedClip {
public:
+ GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds);
+
+ /**
+ * Uniquely identifies this reduced clip.
+ */
+ int32_t genID() const { return fGenID; }
+
+ /**
+ * Bounding box within which the reduced clip is valid. The caller must not draw any pixels
+ * outside this box.
+ */
+ const SkIRect& iBounds() const { return fIBounds; }
+ int left() const { return this->iBounds().left(); }
+ int top() const { return this->iBounds().top(); }
+ int width() const { return this->iBounds().width(); }
+ int height() const { return this->iBounds().height(); }
+
typedef SkTLList<SkClipStack::Element, 16> ElementList;
- enum InitialState {
- kAllIn_InitialState,
- kAllOut_InitialState,
+ /**
+ * Populated with a minimal list of elements that implement the clip.
+ */
+ const ElementList& elements() const { return fElements; }
+
+ /**
+ * Indicates whether antialiasing is required to process any of the clip elements.
+ */
+ bool requiresAA() const { return fRequiresAA; }
+
+ enum class InitialState : bool {
+ kAllIn,
+ kAllOut
};
/**
- * This function produces a reduced set of SkClipStack::Elements that are equivalent to applying
- * a full clip stack within a specified query rectangle.
- *
- * @param stack the clip stack to reduce.
- * @param queryBounds bounding box of geometry the stack will clip.
- * @param result populated with a minimal list of elements that implement the clip
- * within the provided query bounds.
- * @param resultGenID uniquely identifies the resulting reduced clip.
- * @param clipIBounds bounding box within which the reduced clip is valid. The caller must
- * not draw any pixels outside this box. NOTE: this box may be undefined
- * if no pixels are valid (e.g. empty result, "all out" initial state.)
- * @param requiresAA indicates whether anti-aliasing is required to process any of the
- * elements in the element list result. Undefined if the result is empty.
- * @return the initial clip state within clipIBounds ("all in" or "all out").
+ * The initial state of the clip within iBounds().
*/
- static InitialState ReduceClipStack(const SkClipStack& stack,
- const SkRect& queryBounds,
- ElementList* result,
- int32_t* resultGenID,
- SkIRect* clipIBounds,
- bool* requiresAA);
+ InitialState initialState() const { return fInitialState; }
+
+private:
+ int32_t fGenID;
+ SkIRect fIBounds;
+ ElementList fElements;
+ bool fRequiresAA;
+ InitialState fInitialState;
};
#endif
diff --git a/src/utils/SkLua.cpp b/src/utils/SkLua.cpp
index 3a335ad17c..8ea9eee5fc 100644
--- a/src/utils/SkLua.cpp
+++ b/src/utils/SkLua.cpp
@@ -644,22 +644,9 @@ int SkLua::lcanvas_getReducedClipStack(lua_State* L) {
#if SK_SUPPORT_GPU
const SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
SkRect queryBounds = SkRect::Make(canvas->getTopLayerBounds());
+ const GrReducedClip reducedClip(*canvas->getClipStack(), queryBounds);
- GrReducedClip::ElementList elements;
- int32_t genID;
- SkIRect resultBounds;
- bool requiresAA;
-
- const SkClipStack& stack = *canvas->getClipStack();
-
- GrReducedClip::ReduceClipStack(stack,
- queryBounds,
- &elements,
- &genID,
- &resultBounds,
- &requiresAA);
-
- GrReducedClip::ElementList::Iter iter(elements);
+ GrReducedClip::ElementList::Iter iter(reducedClip.elements());
int i = 0;
lua_newtable(L);
while(iter.get()) {
diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp
index f6edb8ce5b..a6b636271a 100644
--- a/tests/ClipStackTest.cpp
+++ b/tests/ClipStackTest.cpp
@@ -1006,57 +1006,47 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
}
}
+ // Get the reduced version of the stack.
SkRect queryBounds = kBounds;
queryBounds.outset(kBounds.width() / 2, kBounds.height() / 2);
+ const GrReducedClip reduced(stack, queryBounds);
- // Get the reduced version of the stack.
- ElementList reducedClips;
- int32_t reducedGenID;
- SkIRect clipIBounds;
- bool requiresAA;
- InitialState initial = GrReducedClip::ReduceClipStack(stack,
- queryBounds,
- &reducedClips,
- &reducedGenID,
- &clipIBounds,
- &requiresAA);
-
- REPORTER_ASSERT_MESSAGE(reporter, SkClipStack::kInvalidGenID != reducedGenID,
+ REPORTER_ASSERT_MESSAGE(reporter, SkClipStack::kInvalidGenID != reduced.genID(),
testCase.c_str());
- if (!reducedClips.isEmpty()) {
+ if (!reduced.elements().isEmpty()) {
SkRect stackBounds;
SkClipStack::BoundsType stackBoundsType;
stack.getBounds(&stackBounds, &stackBoundsType);
if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
// Unless GrReducedClip starts doing some heroic tightening of the clip bounds, this
// will be true since the stack bounds are completely contained inside the query.
- REPORTER_ASSERT_MESSAGE(reporter, GrClip::IsInsideClip(clipIBounds, stackBounds),
+ REPORTER_ASSERT_MESSAGE(reporter, GrClip::IsInsideClip(reduced.iBounds(), stackBounds),
testCase.c_str());
}
- REPORTER_ASSERT_MESSAGE(reporter, requiresAA == doAA, testCase.c_str());
+ REPORTER_ASSERT_MESSAGE(reporter, reduced.requiresAA() == doAA, testCase.c_str());
}
// Build a new clip stack based on the reduced clip elements
SkClipStack reducedStack;
- if (GrReducedClip::kAllOut_InitialState == initial) {
+ 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 = reducedClips.headIter(); iter.get(); iter.next()) {
+ for (ElementList::Iter iter(reduced.elements()); iter.get(); iter.next()) {
add_elem_to_stack(*iter.get(), &reducedStack);
}
// GrReducedClipStack assumes that the final result is clipped to the returned bounds
- reducedStack.clipDevRect(clipIBounds, SkRegion::kIntersect_Op);
- stack.clipDevRect(clipIBounds, SkRegion::kIntersect_Op);
+ reducedStack.clipDevRect(reduced.iBounds(), SkRegion::kIntersect_Op);
+ stack.clipDevRect(reduced.iBounds(), SkRegion::kIntersect_Op);
// convert both the original stack and reduced stack to SkRegions and see if they're equal
SkRegion region;
- set_region_to_stack(stack, clipIBounds, &region);
+ set_region_to_stack(stack, reduced.iBounds(), &region);
SkRegion reducedRegion;
- set_region_to_stack(reducedStack, clipIBounds, &reducedRegion);
+ set_region_to_stack(reducedStack, reduced.iBounds(), &reducedRegion);
REPORTER_ASSERT_MESSAGE(reporter, region == reducedRegion, testCase.c_str());
}
@@ -1075,21 +1065,11 @@ static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) {
stack.clipDevRect(SkRect::MakeXYWH(0, 0, SkScalar(50.3), SkScalar(50.3)), SkRegion::kReplace_Op, true);
SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
- ElementList reducedClips;
- int32_t reducedGenID;
- SkIRect tightBounds;
- bool requiresAA;
-
- GrReducedClip::ReduceClipStack(stack,
- bounds,
- &reducedClips,
- &reducedGenID,
- &tightBounds,
- &requiresAA);
+ const GrReducedClip reduced(stack, bounds);
- REPORTER_ASSERT(reporter, reducedClips.count() == 1);
+ REPORTER_ASSERT(reporter, reduced.elements().count() == 1);
// Clips will be cached based on the generation id. Make sure the gen id is valid.
- REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID != reducedGenID);
+ REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID != reduced.genID());
}
{
SkClipStack stack;
@@ -1129,60 +1109,50 @@ static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) {
SkIRect clipIRect;
// parameter.
} testCases[] = {
+
// Rect A.
- { XYWH(0, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, IXYWH(0, 0, 25, 25) },
- { XYWH(0.1f, 0.1f, 25.1f, 25.1f), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, IXYWH(0, 0, 26, 26) },
- { XYWH(0, 0, 27, 27), 1, genIDA, GrReducedClip::kAllOut_InitialState, IXYWH(0, 0, 27, 27)},
+ { XYWH(0, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::InitialState::kAllIn, IXYWH(0, 0, 25, 25) },
+ { XYWH(0.1f, 0.1f, 25.1f, 25.1f), 0, SkClipStack::kWideOpenGenID, GrReducedClip::InitialState::kAllIn, IXYWH(0, 0, 26, 26) },
+ { XYWH(0, 0, 27, 27), 1, genIDA, GrReducedClip::InitialState::kAllOut, IXYWH(0, 0, 27, 27)},
// Rect B.
- { XYWH(50, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, IXYWH(50, 0, 25, 25) },
- { XYWH(50, 0, 25.3f, 25.3f), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, IXYWH(50, 0, 26, 26) },
- { XYWH(50, 0, 27, 27), 1, genIDB, GrReducedClip::kAllOut_InitialState, IXYWH(50, 0, 26, 27) },
+ { XYWH(50, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::InitialState::kAllIn, IXYWH(50, 0, 25, 25) },
+ { XYWH(50, 0, 25.3f, 25.3f), 0, SkClipStack::kWideOpenGenID, GrReducedClip::InitialState::kAllIn, IXYWH(50, 0, 26, 26) },
+ { XYWH(50, 0, 27, 27), 1, genIDB, GrReducedClip::InitialState::kAllOut, IXYWH(50, 0, 26, 27) },
// Rect C.
- { XYWH(0, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, IXYWH(0, 50, 25, 25) },
- { XYWH(0.2f, 50.1f, 25.1f, 25.2f), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, IXYWH(0, 50, 26, 26) },
- { XYWH(0, 50, 27, 27), 1, genIDC, GrReducedClip::kAllOut_InitialState, IXYWH(0, 50, 27, 26) },
+ { XYWH(0, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::InitialState::kAllIn, IXYWH(0, 50, 25, 25) },
+ { XYWH(0.2f, 50.1f, 25.1f, 25.2f), 0, SkClipStack::kWideOpenGenID, GrReducedClip::InitialState::kAllIn, IXYWH(0, 50, 26, 26) },
+ { XYWH(0, 50, 27, 27), 1, genIDC, GrReducedClip::InitialState::kAllOut, IXYWH(0, 50, 27, 26) },
// Rect D.
- { XYWH(50, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, IXYWH(50, 50, 25, 25)},
- { XYWH(50.3f, 50.3f, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, IXYWH(50, 50, 26, 26)},
- { XYWH(50, 50, 27, 27), 1, genIDD, GrReducedClip::kAllOut_InitialState, IXYWH(50, 50, 26, 26)},
+ { XYWH(50, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::InitialState::kAllIn, IXYWH(50, 50, 25, 25)},
+ { XYWH(50.3f, 50.3f, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::InitialState::kAllIn, IXYWH(50, 50, 26, 26)},
+ { XYWH(50, 50, 27, 27), 1, genIDD, GrReducedClip::InitialState::kAllOut, IXYWH(50, 50, 26, 26)},
// Other tests:
- { XYWH(0, 0, 100, 100), 4, genIDD, GrReducedClip::kAllOut_InitialState, stackBounds },
+ { XYWH(0, 0, 100, 100), 4, genIDD, GrReducedClip::InitialState::kAllOut, stackBounds },
// Rect in the middle, touches none.
- { XYWH(26, 26, 24, 24), 0, SkClipStack::kEmptyGenID, GrReducedClip::kAllOut_InitialState, IXYWH(26, 26, 24, 24) },
+ { XYWH(26, 26, 24, 24), 0, SkClipStack::kEmptyGenID, GrReducedClip::InitialState::kAllOut, IXYWH(26, 26, 24, 24) },
// Rect in the middle, touches all the rects. GenID is the last rect.
- { XYWH(24, 24, 27, 27), 4, genIDD, GrReducedClip::kAllOut_InitialState, IXYWH(24, 24, 27, 27) },
+ { XYWH(24, 24, 27, 27), 4, genIDD, GrReducedClip::InitialState::kAllOut, IXYWH(24, 24, 27, 27) },
};
#undef XYWH
#undef IXYWH
for (size_t i = 0; i < SK_ARRAY_COUNT(testCases); ++i) {
- ElementList reducedClips;
- int32_t reducedGenID;
- SkIRect clipIRect;
- bool requiresAA;
-
- InitialState initial = GrReducedClip::ReduceClipStack(stack,
- testCases[i].testBounds,
- &reducedClips,
- &reducedGenID,
- &clipIRect,
- &requiresAA);
-
- REPORTER_ASSERT(reporter, reducedClips.count() == testCases[i].reducedClipCount);
- SkASSERT(reducedClips.count() == testCases[i].reducedClipCount);
- REPORTER_ASSERT(reporter, reducedGenID == testCases[i].reducedGenID);
- SkASSERT(reducedGenID == testCases[i].reducedGenID);
- REPORTER_ASSERT(reporter, initial == testCases[i].initialState);
- SkASSERT(initial == testCases[i].initialState);
- REPORTER_ASSERT(reporter, clipIRect == testCases[i].clipIRect);
- SkASSERT(clipIRect == testCases[i].clipIRect);
+ const GrReducedClip reduced(stack, testCases[i].testBounds);
+ REPORTER_ASSERT(reporter, reduced.elements().count() == testCases[i].reducedClipCount);
+ SkASSERT(reduced.elements().count() == testCases[i].reducedClipCount);
+ REPORTER_ASSERT(reporter, reduced.genID() == testCases[i].reducedGenID);
+ SkASSERT(reduced.genID() == testCases[i].reducedGenID);
+ REPORTER_ASSERT(reporter, reduced.initialState() == testCases[i].initialState);
+ SkASSERT(reduced.initialState() == testCases[i].initialState);
+ REPORTER_ASSERT(reporter, reduced.iBounds() == testCases[i].clipIRect);
+ SkASSERT(reduced.iBounds() == testCases[i].clipIRect);
}
}
}
@@ -1193,20 +1163,9 @@ static void test_reduced_clip_stack_no_aa_crash(skiatest::Reporter* reporter) {
stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 50, 50), SkRegion::kReplace_Op);
SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
- ElementList reducedClips;
- int32_t reducedGenID;
- SkIRect tightBounds;
- bool requiresAA;
-
// At the time, this would crash.
- GrReducedClip::ReduceClipStack(stack,
- bounds,
- &reducedClips,
- &reducedGenID,
- &tightBounds,
- &requiresAA);
-
- REPORTER_ASSERT(reporter, 0 == reducedClips.count());
+ const GrReducedClip reduced(stack, bounds);
+ REPORTER_ASSERT(reporter, reduced.elements().isEmpty());
}
enum class ClipMethod {
@@ -1220,20 +1179,9 @@ static void test_aa_query(skiatest::Reporter* reporter, const SkString& testName
const SkClipStack& stack, const SkMatrix& queryXform,
const SkRect& preXformQuery, ClipMethod expectedMethod,
int numExpectedElems = 0) {
- ElementList reducedElems;
- int32_t reducedGenID;
- SkIRect clipIBounds;
- bool requiresAA;
-
SkRect queryBounds;
queryXform.mapRect(&queryBounds, preXformQuery);
-
- InitialState initialState = GrReducedClip::ReduceClipStack(stack,
- queryBounds,
- &reducedElems,
- &reducedGenID,
- &clipIBounds,
- &requiresAA);
+ const GrReducedClip reduced(stack, queryBounds);
SkClipStack::BoundsType stackBoundsType;
SkRect stackBounds;
@@ -1242,16 +1190,18 @@ static void test_aa_query(skiatest::Reporter* reporter, const SkString& testName
switch (expectedMethod) {
case ClipMethod::kSkipDraw:
SkASSERT(0 == numExpectedElems);
- REPORTER_ASSERT_MESSAGE(reporter, reducedElems.isEmpty(), testName.c_str());
- REPORTER_ASSERT_MESSAGE(reporter, GrReducedClip::kAllOut_InitialState == initialState,
+ REPORTER_ASSERT_MESSAGE(reporter, reduced.elements().isEmpty(), testName.c_str());
+ REPORTER_ASSERT_MESSAGE(reporter,
+ GrReducedClip::InitialState::kAllOut == reduced.initialState(),
testName.c_str());
return;
case ClipMethod::kIgnoreClip:
SkASSERT(0 == numExpectedElems);
- REPORTER_ASSERT_MESSAGE(reporter, reducedElems.isEmpty(), testName.c_str());
- REPORTER_ASSERT_MESSAGE(reporter, GrClip::IsInsideClip(clipIBounds, queryBounds),
+ REPORTER_ASSERT_MESSAGE(reporter, GrClip::IsInsideClip(reduced.iBounds(), queryBounds),
testName.c_str());
- REPORTER_ASSERT_MESSAGE(reporter, GrReducedClip::kAllIn_InitialState == initialState,
+ REPORTER_ASSERT_MESSAGE(reporter, reduced.elements().isEmpty(), testName.c_str());
+ REPORTER_ASSERT_MESSAGE(reporter,
+ GrReducedClip::InitialState::kAllIn == reduced.initialState(),
testName.c_str());
return;
case ClipMethod::kScissor: {
@@ -1259,9 +1209,11 @@ static void test_aa_query(skiatest::Reporter* reporter, const SkString& testName
SkASSERT(0 == numExpectedElems);
SkIRect expectedScissor;
stackBounds.round(&expectedScissor);
- REPORTER_ASSERT_MESSAGE(reporter, reducedElems.isEmpty(), testName.c_str());
- REPORTER_ASSERT_MESSAGE(reporter, expectedScissor == clipIBounds, testName.c_str());
- REPORTER_ASSERT_MESSAGE(reporter, GrReducedClip::kAllIn_InitialState == initialState,
+ REPORTER_ASSERT_MESSAGE(reporter, reduced.elements().isEmpty(), testName.c_str());
+ REPORTER_ASSERT_MESSAGE(reporter, expectedScissor == reduced.iBounds(),
+ testName.c_str());
+ REPORTER_ASSERT_MESSAGE(reporter,
+ GrReducedClip::InitialState::kAllIn == reduced.initialState(),
testName.c_str());
return;
}
@@ -1270,10 +1222,11 @@ static void test_aa_query(skiatest::Reporter* reporter, const SkString& testName
if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
SkAssertResult(expectedClipIBounds.intersect(GrClip::GetPixelIBounds(stackBounds)));
}
- REPORTER_ASSERT_MESSAGE(reporter, numExpectedElems == reducedElems.count(),
+ REPORTER_ASSERT_MESSAGE(reporter, numExpectedElems == reduced.elements().count(),
+ testName.c_str());
+ REPORTER_ASSERT_MESSAGE(reporter, expectedClipIBounds == reduced.iBounds(),
testName.c_str());
- REPORTER_ASSERT_MESSAGE(reporter, expectedClipIBounds == clipIBounds, testName.c_str());
- REPORTER_ASSERT_MESSAGE(reporter, requiresAA == !reducedElems.isEmpty(),
+ REPORTER_ASSERT_MESSAGE(reporter, reduced.requiresAA() == !reduced.elements().isEmpty(),
testName.c_str());
break;
}
@@ -1306,8 +1259,7 @@ static void test_reduced_clip_stack_aa(skiatest::Reporter* reporter) {
stack.clipDevRect(alignedRect, SkRegion::kIntersect_Op, true);
test_aa_query(reporter, name, stack, m, {IL, IT, IR, IB}, ClipMethod::kIgnoreClip);
test_aa_query(reporter, name, stack, m, {IL, IT-1, IR, IT}, ClipMethod::kSkipDraw);
- test_aa_query(reporter, name, stack, m, {IL, IT, IR, IB}, ClipMethod::kScissor);
- test_aa_query(reporter, name, stack, m, {IL, IT+2, IR, IB-3}, ClipMethod::kScissor);
+ test_aa_query(reporter, name, stack, m, {IL, IT-2, IR, IB}, ClipMethod::kScissor);
// Rect (iior=true).
name.printf("Rect test, iter %i", i);