diff options
Diffstat (limited to 'src/gpu')
-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 |
4 files changed, 174 insertions, 187 deletions
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 |