diff options
-rw-r--r-- | include/gpu/GrClip.h | 24 | ||||
-rw-r--r-- | src/gpu/GrClipStackClip.cpp | 153 | ||||
-rw-r--r-- | src/gpu/GrClipStackClip.h | 19 | ||||
-rw-r--r-- | src/gpu/GrReducedClip.cpp | 121 | ||||
-rw-r--r-- | src/gpu/GrReducedClip.h | 68 | ||||
-rw-r--r-- | src/utils/SkLua.cpp | 17 | ||||
-rw-r--r-- | tests/ClipStackTest.cpp | 168 |
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, ®ion); + set_region_to_stack(stack, reduced.iBounds(), ®ion); 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); |