diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/GrClipStackClip.cpp | 384 | ||||
-rw-r--r-- | src/gpu/GrClipStackClip.h | 17 | ||||
-rw-r--r-- | src/gpu/GrContext.cpp | 22 | ||||
-rw-r--r-- | src/gpu/GrContextPriv.h | 2 | ||||
-rw-r--r-- | src/gpu/GrReducedClip.cpp | 323 | ||||
-rw-r--r-- | src/gpu/GrReducedClip.h | 6 | ||||
-rw-r--r-- | src/gpu/GrStencilAttachment.h | 10 |
7 files changed, 378 insertions, 386 deletions
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp index 23c2b42a92..003b4a5d43 100644 --- a/src/gpu/GrClipStackClip.cpp +++ b/src/gpu/GrClipStackClip.cpp @@ -8,6 +8,7 @@ #include "GrClipStackClip.h" #include "GrAppliedClip.h" +#include "GrContextPriv.h" #include "GrDrawingManager.h" #include "GrDrawContextPriv.h" #include "GrFixedClip.h" @@ -150,7 +151,8 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context, canDrawArgs.fIsStencilBufferMSAA = drawContext->isStencilBufferMultisampled(); // the 'false' parameter disallows use of the SW path renderer - GrPathRenderer* pr = context->drawingManager()->getPathRenderer(canDrawArgs, false, type); + GrPathRenderer* pr = + context->contextPriv().drawingManager()->getPathRenderer(canDrawArgs, false, type); if (prOut) { *prOut = pr; } @@ -166,17 +168,17 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context, bool GrClipStackClip::UseSWOnlyPath(GrContext* context, bool hasUserStencilSettings, const GrDrawContext* drawContext, - const SkVector& clipToMaskOffset, - const ElementList& elements) { + const GrReducedClip& reducedClip) { // 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. // Set the matrix so that rendered clip elements are transformed to mask space from clip // space. - const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMaskOffset.fY); + SkMatrix translate; + translate.setTranslate(SkIntToScalar(-reducedClip.left()), SkIntToScalar(-reducedClip.top())); - for (ElementList::Iter iter(elements); iter.get(); iter.next()) { + for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()) { const Element* element = iter.get(); SkRegion::Op op = element->getOp(); @@ -351,21 +353,12 @@ bool GrClipStackClip::apply(GrContext* context, GrDrawContext* drawContext, bool // If the stencil buffer is multisampled we can use it to do everything. 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(-reducedClip.left()), - SkIntToScalar(-reducedClip.top()) - }; - - if (UseSWOnlyPath(context, hasUserStencilSettings, drawContext, - clipToMaskOffset, reducedClip.elements())) { + if (UseSWOnlyPath(context, hasUserStencilSettings, drawContext, reducedClip)) { // The clip geometry is complex enough that it will be more efficient to create it // entirely in software - result = CreateSoftwareClipMask(context->textureProvider(), reducedClip, - clipToMaskOffset); + result = CreateSoftwareClipMask(context->textureProvider(), reducedClip); } else { - result = CreateAlphaClipMask(context, reducedClip, clipToMaskOffset); + result = CreateAlphaClipMask(context, reducedClip); // If createAlphaClipMask fails it means UseSWOnlyPath has a bug SkASSERT(result); } @@ -382,73 +375,22 @@ bool GrClipStackClip::apply(GrContext* context, GrDrawContext* drawContext, bool } // use the stencil clip if we can't represent the clip as a rectangle. - SkIPoint clipSpaceToStencilSpaceOffset = -fOrigin; - CreateStencilClipMask(context, drawContext, reducedClip, clipSpaceToStencilSpaceOffset); - out->addStencilClip(); - return true; -} - -static bool stencil_element(GrDrawContext* dc, - const GrFixedClip& clip, - const GrUserStencilSettings* ss, - const SkMatrix& viewMatrix, - const SkClipStack::Element* element) { - - // TODO: Draw rrects directly here. - switch (element->getType()) { - case Element::kEmpty_Type: - SkDEBUGFAIL("Should never get here with an empty element."); - break; - case Element::kRect_Type: - return dc->drawContextPriv().drawAndStencilRect(clip, ss, - element->getOp(), - element->isInverseFilled(), - element->isAA(), - viewMatrix, element->getRect()); - break; - default: { - SkPath path; - element->asPath(&path); - if (path.isInverseFillType()) { - path.toggleInverseFillType(); - } - - return dc->drawContextPriv().drawAndStencilPath(clip, ss, - element->getOp(), - element->isInverseFilled(), - element->isAA(), viewMatrix, path); - break; - } + // TODO: these need to be swapped over to using a StencilAttachmentProxy + GrStencilAttachment* stencilAttachment = + context->resourceProvider()->attachStencilAttachment(drawContext->accessRenderTarget()); + if (nullptr == stencilAttachment) { + SkDebugf("WARNING: failed to attach stencil buffer for clip mask. Clip will be ignored.\n"); + return true; } - return false; -} - -static void draw_element(GrDrawContext* dc, - const GrClip& clip, // TODO: can this just always be WideOpen? - const GrPaint &paint, - const SkMatrix& viewMatrix, - const SkClipStack::Element* element) { - - // TODO: Draw rrects directly here. - switch (element->getType()) { - case Element::kEmpty_Type: - SkDEBUGFAIL("Should never get here with an empty element."); - break; - case Element::kRect_Type: - dc->drawRect(clip, paint, viewMatrix, element->getRect()); - break; - default: { - SkPath path; - element->asPath(&path); - if (path.isInverseFillType()) { - path.toggleInverseFillType(); - } - - dc->drawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill()); - break; - } + if (stencilAttachment->mustRenderClip(reducedClip.elementsGenID(), reducedClip.ibounds(), + fOrigin)) { + reducedClip.drawStencilClipMask(context, drawContext, fOrigin); + stencilAttachment->setLastClip(reducedClip.elementsGenID(), reducedClip.ibounds(), + fOrigin); } + out->addStencilClip(); + return true; } //////////////////////////////////////////////////////////////////////////////// @@ -463,8 +405,7 @@ static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey } sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context, - const GrReducedClip& reducedClip, - const SkVector& clipToMaskOffset) { + const GrReducedClip& reducedClip) { GrResourceProvider* resourceProvider = context->resourceProvider(); GrUniqueKey key; GetClipMaskKey(reducedClip.elementsGenID(), reducedClip.ibounds(), &key); @@ -485,72 +426,9 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context, if (!dc) { return nullptr; } - - // 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(reducedClip.width(), reducedClip.height()); - GrFixedClip clip(maskSpaceIBounds); - - // The scratch texture that we are drawing into can be substantially larger than the mask. Only - // clear the part that we care about. - GrColor initialCoverage = InitialState::kAllIn == reducedClip.initialState() ? -1 : 0; - dc->drawContextPriv().clear(clip, initialCoverage, true); - - // Set the matrix so that rendered clip elements are transformed to mask space from clip - // space. - const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMaskOffset.fY); - - // It is important that we use maskSpaceIBounds as the stencil rect in the below loop. - // The second pass that zeros the stencil buffer renders the rect maskSpaceIBounds so the first - // pass must not set values outside of this bounds or stencil values outside the rect won't be - // cleared. - - // walk through each clip element and perform its set op - for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()) { - const Element* element = iter.get(); - SkRegion::Op op = element->getOp(); - bool invert = element->isInverseFilled(); - if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) { - // draw directly into the result with the stencil set to make the pixels affected - // by the clip shape be non-zero. - static constexpr GrUserStencilSettings kStencilInElement( - GrUserStencilSettings::StaticInit< - 0xffff, - GrUserStencilTest::kAlways, - 0xffff, - GrUserStencilOp::kReplace, - GrUserStencilOp::kReplace, - 0xffff>() - ); - if (!stencil_element(dc.get(), clip, &kStencilInElement, - translate, element)) { - return nullptr; - } - - // Draw to the exterior pixels (those with a zero stencil value). - static constexpr GrUserStencilSettings kDrawOutsideElement( - GrUserStencilSettings::StaticInit< - 0x0000, - GrUserStencilTest::kEqual, - 0xffff, - GrUserStencilOp::kZero, - GrUserStencilOp::kZero, - 0xffff>() - ); - if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideElement, - op, !invert, false, - translate, - SkRect::Make(reducedClip.ibounds()))) { - return nullptr; - } - } else { - // all the remaining ops can just be directly draw into the accumulation buffer - GrPaint paint; - paint.setAntiAlias(element->isAA()); - paint.setCoverageSetOpXPFactory(op, false); - draw_element(dc.get(), clip, paint, translate, element); - } + if (!reducedClip.drawAlphaClipMask(dc.get())) { + return nullptr; } sk_sp<GrTexture> texture(dc->asTexture()); @@ -559,214 +437,8 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context, return texture; } -//////////////////////////////////////////////////////////////////////////////// -// Create a 1-bit clip mask in the stencil buffer. - -class StencilClip final : public GrClip { -public: - StencilClip(const SkIRect& scissorRect) : fFixedClip(scissorRect) {} - const GrFixedClip& fixedClip() const { return fFixedClip; } - -private: - bool quickContains(const SkRect&) const final { - return false; - } - void getConservativeBounds(int width, int height, SkIRect* devResult, bool* iior) const final { - fFixedClip.getConservativeBounds(width, height, devResult, iior); - } - bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const final { - return false; - } - bool apply(GrContext* context, GrDrawContext* drawContext, bool useHWAA, - bool hasUserStencilSettings, GrAppliedClip* out) const final { - if (!fFixedClip.apply(context, drawContext, useHWAA, hasUserStencilSettings, out)) { - return false; - } - out->addStencilClip(); - return true; - } - - GrFixedClip fFixedClip; - - typedef GrClip INHERITED; -}; - -bool GrClipStackClip::CreateStencilClipMask(GrContext* context, - GrDrawContext* drawContext, - const GrReducedClip& reducedClip, - const SkIPoint& clipSpaceToStencilOffset) { - SkASSERT(drawContext); - - GrStencilAttachment* stencilAttachment = context->resourceProvider()->attachStencilAttachment( - drawContext->accessRenderTarget()); - if (nullptr == stencilAttachment) { - return false; - } - - // TODO: these need to be swapped over to using a StencilAttachmentProxy - if (stencilAttachment->mustRenderClip(reducedClip.elementsGenID(), reducedClip.ibounds(), - clipSpaceToStencilOffset)) { - stencilAttachment->setLastClip(reducedClip.elementsGenID(), reducedClip.ibounds(), - clipSpaceToStencilOffset); - // Set the matrix so that rendered clip elements are transformed from clip to stencil space. - SkVector translate = { - SkIntToScalar(clipSpaceToStencilOffset.fX), - SkIntToScalar(clipSpaceToStencilOffset.fY) - }; - SkMatrix viewMatrix; - viewMatrix.setTranslate(translate); - - // We set the current clip to the bounds so that our recursive draws are scissored to them. - SkIRect stencilSpaceIBounds(reducedClip.ibounds()); - stencilSpaceIBounds.offset(clipSpaceToStencilOffset); - StencilClip stencilClip(stencilSpaceIBounds); - - bool initialState = InitialState::kAllIn == reducedClip.initialState(); - drawContext->drawContextPriv().clearStencilClip(stencilClip.fixedClip(), initialState); - - // walk through each clip element and perform its set op - // with the existing clip. - for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()) { - const Element* element = iter.get(); - bool useHWAA = element->isAA() && drawContext->isStencilBufferMultisampled(); - - bool fillInverted = false; - - // This will be used to determine whether the clip shape can be rendered into the - // stencil with arbitrary stencil settings. - GrPathRenderer::StencilSupport stencilSupport; - - SkRegion::Op op = element->getOp(); - - GrPathRenderer* pr = nullptr; - SkPath clipPath; - if (Element::kRect_Type == element->getType()) { - stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; - fillInverted = false; - } else { - element->asPath(&clipPath); - fillInverted = clipPath.isInverseFillType(); - if (fillInverted) { - clipPath.toggleInverseFillType(); - } - - GrShape shape(clipPath, GrStyle::SimpleFill()); - GrPathRenderer::CanDrawPathArgs canDrawArgs; - canDrawArgs.fShaderCaps = context->caps()->shaderCaps(); - canDrawArgs.fViewMatrix = &viewMatrix; - canDrawArgs.fShape = &shape; - canDrawArgs.fAntiAlias = false; - canDrawArgs.fHasUserStencilSettings = false; - canDrawArgs.fIsStencilBufferMSAA = drawContext->isStencilBufferMultisampled(); - - GrDrawingManager* dm = context->drawingManager(); - pr = dm->getPathRenderer(canDrawArgs, false, - GrPathRendererChain::kStencilOnly_DrawType, - &stencilSupport); - if (!pr) { - return false; - } - } - - bool canRenderDirectToStencil = - GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport; - bool drawDirectToClip; // Given the renderer, the element, - // fill rule, and set operation should - // we render the element directly to - // stencil bit used for clipping. - GrUserStencilSettings const* const* stencilPasses = - GrStencilSettings::GetClipPasses(op, canRenderDirectToStencil, fillInverted, - &drawDirectToClip); - - // draw the element to the client stencil bits if necessary - if (!drawDirectToClip) { - static constexpr GrUserStencilSettings kDrawToStencil( - GrUserStencilSettings::StaticInit< - 0x0000, - GrUserStencilTest::kAlways, - 0xffff, - GrUserStencilOp::kIncMaybeClamp, - GrUserStencilOp::kIncMaybeClamp, - 0xffff>() - ); - if (Element::kRect_Type == element->getType()) { - drawContext->drawContextPriv().stencilRect(stencilClip.fixedClip(), - &kDrawToStencil, useHWAA, - viewMatrix, element->getRect()); - } else { - if (!clipPath.isEmpty()) { - GrShape shape(clipPath, GrStyle::SimpleFill()); - if (canRenderDirectToStencil) { - GrPaint paint; - paint.setXPFactory(GrDisableColorXPFactory::Make()); - paint.setAntiAlias(element->isAA()); - - GrPathRenderer::DrawPathArgs args; - args.fResourceProvider = context->resourceProvider(); - args.fPaint = &paint; - args.fUserStencilSettings = &kDrawToStencil; - args.fDrawContext = drawContext; - args.fClip = &stencilClip.fixedClip(); - args.fViewMatrix = &viewMatrix; - args.fShape = &shape; - args.fAntiAlias = false; - args.fGammaCorrect = false; - pr->drawPath(args); - } else { - GrPathRenderer::StencilPathArgs args; - args.fResourceProvider = context->resourceProvider(); - args.fDrawContext = drawContext; - args.fClip = &stencilClip.fixedClip(); - args.fViewMatrix = &viewMatrix; - args.fIsAA = element->isAA(); - args.fShape = &shape; - pr->stencilPath(args); - } - } - } - } - - // now we modify the clip bit by rendering either the clip - // element directly or a bounding rect of the entire clip. - for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) { - if (drawDirectToClip) { - if (Element::kRect_Type == element->getType()) { - drawContext->drawContextPriv().stencilRect(stencilClip, *pass, useHWAA, - viewMatrix, element->getRect()); - } else { - GrShape shape(clipPath, GrStyle::SimpleFill()); - GrPaint paint; - paint.setXPFactory(GrDisableColorXPFactory::Make()); - paint.setAntiAlias(element->isAA()); - GrPathRenderer::DrawPathArgs args; - args.fResourceProvider = context->resourceProvider(); - args.fPaint = &paint; - args.fUserStencilSettings = *pass; - args.fDrawContext = drawContext; - args.fClip = &stencilClip; - args.fViewMatrix = &viewMatrix; - args.fShape = &shape; - args.fAntiAlias = false; - args.fGammaCorrect = false; - pr->drawPath(args); - } - } else { - // The view matrix is setup to do clip space -> stencil space translation, so - // draw rect in clip space. - drawContext->drawContextPriv().stencilRect(stencilClip, *pass, - false, viewMatrix, - SkRect::Make(reducedClip.ibounds())); - } - } - } - } - return true; -} - -//////////////////////////////////////////////////////////////////////////////// sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texProvider, - const GrReducedClip& reducedClip, - const SkVector& clipToMaskOffset) { + const GrReducedClip& reducedClip) { GrUniqueKey key; GetClipMaskKey(reducedClip.elementsGenID(), reducedClip.ibounds(), &key); if (GrTexture* texture = texProvider->findAndRefTextureByUniqueKey(key)) { @@ -782,7 +454,7 @@ sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texP // Set the matrix so that rendered clip elements are transformed to mask space from clip // space. SkMatrix translate; - translate.setTranslate(clipToMaskOffset); + translate.setTranslate(SkIntToScalar(-reducedClip.left()), SkIntToScalar(-reducedClip.top())); helper.init(maskSpaceIBounds, &translate); helper.clear(InitialState::kAllIn == reducedClip.initialState() ? 0xFF : 0x00); diff --git a/src/gpu/GrClipStackClip.h b/src/gpu/GrClipStackClip.h index ad143d6969..075d1d857d 100644 --- a/src/gpu/GrClipStackClip.h +++ b/src/gpu/GrClipStackClip.h @@ -49,28 +49,17 @@ private: GrPathRenderer** prOut, bool needsStencil); - // Draws the clip into the stencil buffer - static bool CreateStencilClipMask(GrContext*, - GrDrawContext*, - 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*, - const GrReducedClip&, - const SkVector& clipToMaskOffset); + static sk_sp<GrTexture> CreateAlphaClipMask(GrContext*, const GrReducedClip&); // Similar to createAlphaClipMask but it rasterizes in SW and uploads to the result texture. - static sk_sp<GrTexture> CreateSoftwareClipMask(GrTextureProvider*, - const GrReducedClip&, - const SkVector& clipToMaskOffset); + static sk_sp<GrTexture> CreateSoftwareClipMask(GrTextureProvider*, const GrReducedClip&); static bool UseSWOnlyPath(GrContext*, bool hasUserStencilSettings, const GrDrawContext*, - const SkVector& clipToMaskOffset, - const GrReducedClip::ElementList& elements); + const GrReducedClip&); static GrTexture* CreateCachedMask(int width, int height, const GrUniqueKey& key, bool renderTarget); diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 6221fea3c6..0157760990 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -627,9 +627,9 @@ sk_sp<GrDrawContext> GrContextPriv::makeWrappedDrawContext(sk_sp<GrRenderTarget> sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* surfaceProps) { ASSERT_SINGLE_OWNER_PRIV - return fContext->drawingManager()->makeDrawContext(std::move(rt), - std::move(colorSpace), - surfaceProps); + return this->drawingManager()->makeDrawContext(std::move(rt), + std::move(colorSpace), + surfaceProps); } sk_sp<GrDrawContext> GrContextPriv::makeBackendTextureDrawContext(const GrBackendTextureDesc& desc, @@ -644,8 +644,8 @@ sk_sp<GrDrawContext> GrContextPriv::makeBackendTextureDrawContext(const GrBacken return nullptr; } - return fContext->drawingManager()->makeDrawContext(sk_ref_sp(surface->asRenderTarget()), - std::move(colorSpace), props); + return this->drawingManager()->makeDrawContext(sk_ref_sp(surface->asRenderTarget()), + std::move(colorSpace), props); } sk_sp<GrDrawContext> GrContextPriv::makeBackendRenderTargetDrawContext( @@ -659,9 +659,9 @@ sk_sp<GrDrawContext> GrContextPriv::makeBackendRenderTargetDrawContext( return nullptr; } - return fContext->drawingManager()->makeDrawContext(std::move(rt), - std::move(colorSpace), - surfaceProps); + return this->drawingManager()->makeDrawContext(std::move(rt), + std::move(colorSpace), + surfaceProps); } sk_sp<GrDrawContext> GrContextPriv::makeBackendTextureAsRenderTargetDrawContext( @@ -676,9 +676,9 @@ sk_sp<GrDrawContext> GrContextPriv::makeBackendTextureAsRenderTargetDrawContext( return nullptr; } - return fContext->drawingManager()->makeDrawContext(sk_ref_sp(surface->asRenderTarget()), - std::move(colorSpace), - surfaceProps); + return this->drawingManager()->makeDrawContext(sk_ref_sp(surface->asRenderTarget()), + std::move(colorSpace), + surfaceProps); } sk_sp<GrDrawContext> GrContext::makeDrawContext(SkBackingFit fit, diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h index 8646e25d49..29eb151b6c 100644 --- a/src/gpu/GrContextPriv.h +++ b/src/gpu/GrContextPriv.h @@ -15,6 +15,8 @@ data members or virtual methods. */ class GrContextPriv { public: + GrDrawingManager* drawingManager() { return fContext->fDrawingManager; } + // Create a drawContext that wraps an existing renderTarget sk_sp<GrDrawContext> makeWrappedDrawContext(sk_sp<GrRenderTarget> rt, sk_sp<SkColorSpace> colorSpace, diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp index 237ea221e1..dfc0a2651b 100644 --- a/src/gpu/GrReducedClip.cpp +++ b/src/gpu/GrReducedClip.cpp @@ -7,7 +7,17 @@ #include "GrReducedClip.h" +#include "GrAppliedClip.h" #include "GrClip.h" +#include "GrColor.h" +#include "GrContextPriv.h" +#include "GrDrawContext.h" +#include "GrDrawContextPriv.h" +#include "GrDrawingManager.h" +#include "GrFixedClip.h" +#include "GrPathRenderer.h" +#include "GrStyle.h" +#include "GrUserStencilSettings.h" typedef SkClipStack::Element Element; @@ -421,3 +431,316 @@ inline bool GrReducedClip::intersectIBounds(const SkIRect& irect) { } return true; } + +//////////////////////////////////////////////////////////////////////////////// +// Create a 8-bit clip mask in alpha + +static bool stencil_element(GrDrawContext* dc, + const GrFixedClip& clip, + const GrUserStencilSettings* ss, + const SkMatrix& viewMatrix, + const SkClipStack::Element* element) { + + // TODO: Draw rrects directly here. + switch (element->getType()) { + case Element::kEmpty_Type: + SkDEBUGFAIL("Should never get here with an empty element."); + break; + case Element::kRect_Type: + return dc->drawContextPriv().drawAndStencilRect(clip, ss, + element->getOp(), + element->isInverseFilled(), + element->isAA(), + viewMatrix, element->getRect()); + break; + default: { + SkPath path; + element->asPath(&path); + if (path.isInverseFillType()) { + path.toggleInverseFillType(); + } + + return dc->drawContextPriv().drawAndStencilPath(clip, ss, + element->getOp(), + element->isInverseFilled(), + element->isAA(), viewMatrix, path); + break; + } + } + + return false; +} + +static void draw_element(GrDrawContext* dc, + const GrClip& clip, // TODO: can this just always be WideOpen? + const GrPaint &paint, + const SkMatrix& viewMatrix, + const SkClipStack::Element* element) { + + // TODO: Draw rrects directly here. + switch (element->getType()) { + case Element::kEmpty_Type: + SkDEBUGFAIL("Should never get here with an empty element."); + break; + case Element::kRect_Type: + dc->drawRect(clip, paint, viewMatrix, element->getRect()); + break; + default: { + SkPath path; + element->asPath(&path); + if (path.isInverseFillType()) { + path.toggleInverseFillType(); + } + + dc->drawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill()); + break; + } + } +} + +bool GrReducedClip::drawAlphaClipMask(GrDrawContext* dc) const { + // The texture may be larger than necessary, this rect represents the part of the texture + // we populate with a rasterization of the clip. + GrFixedClip clip(SkIRect::MakeWH(fIBounds.width(), fIBounds.height())); + + // The scratch texture that we are drawing into can be substantially larger than the mask. Only + // clear the part that we care about. + GrColor initialCoverage = InitialState::kAllIn == this->initialState() ? -1 : 0; + dc->drawContextPriv().clear(clip, initialCoverage, true); + + // Set the matrix so that rendered clip elements are transformed to mask space from clip space. + SkMatrix translate; + translate.setTranslate(SkIntToScalar(-fIBounds.left()), SkIntToScalar(-fIBounds.top())); + + // walk through each clip element and perform its set op + for (ElementList::Iter iter(fElements); iter.get(); iter.next()) { + const Element* element = iter.get(); + SkRegion::Op op = element->getOp(); + bool invert = element->isInverseFilled(); + if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) { + // draw directly into the result with the stencil set to make the pixels affected + // by the clip shape be non-zero. + static constexpr GrUserStencilSettings kStencilInElement( + GrUserStencilSettings::StaticInit< + 0xffff, + GrUserStencilTest::kAlways, + 0xffff, + GrUserStencilOp::kReplace, + GrUserStencilOp::kReplace, + 0xffff>() + ); + if (!stencil_element(dc, clip, &kStencilInElement, translate, element)) { + return false; + } + + // Draw to the exterior pixels (those with a zero stencil value). + static constexpr GrUserStencilSettings kDrawOutsideElement( + GrUserStencilSettings::StaticInit< + 0x0000, + GrUserStencilTest::kEqual, + 0xffff, + GrUserStencilOp::kZero, + GrUserStencilOp::kZero, + 0xffff>() + ); + if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideElement, + op, !invert, false, + translate, + SkRect::Make(fIBounds))) { + return false; + } + } else { + // all the remaining ops can just be directly draw into the accumulation buffer + GrPaint paint; + paint.setAntiAlias(element->isAA()); + paint.setCoverageSetOpXPFactory(op, false); + + draw_element(dc, clip, paint, translate, element); + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// Create a 1-bit clip mask in the stencil buffer. + +class StencilClip final : public GrClip { +public: + StencilClip(const SkIRect& scissorRect) : fFixedClip(scissorRect) {} + const GrFixedClip& fixedClip() const { return fFixedClip; } + +private: + bool quickContains(const SkRect&) const final { + return false; + } + void getConservativeBounds(int width, int height, SkIRect* devResult, bool* iior) const final { + fFixedClip.getConservativeBounds(width, height, devResult, iior); + } + bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const final { + return false; + } + bool apply(GrContext* context, GrDrawContext* drawContext, bool useHWAA, + bool hasUserStencilSettings, GrAppliedClip* out) const final { + if (!fFixedClip.apply(context, drawContext, useHWAA, hasUserStencilSettings, out)) { + return false; + } + out->addStencilClip(); + return true; + } + + GrFixedClip fFixedClip; + + typedef GrClip INHERITED; +}; + +bool GrReducedClip::drawStencilClipMask(GrContext* context, + GrDrawContext* drawContext, + const SkIPoint& clipOrigin) const { + // We set the current clip to the bounds so that our recursive draws are scissored to them. + StencilClip stencilClip(fIBounds.makeOffset(-clipOrigin.x(), -clipOrigin.y())); + + bool initialState = InitialState::kAllIn == this->initialState(); + drawContext->drawContextPriv().clearStencilClip(stencilClip.fixedClip(), initialState); + + // Set the matrix so that rendered clip elements are transformed from clip to stencil space. + SkMatrix viewMatrix; + viewMatrix.setTranslate(SkIntToScalar(-clipOrigin.x()), SkIntToScalar(-clipOrigin.y())); + + // walk through each clip element and perform its set op + // with the existing clip. + for (ElementList::Iter iter(fElements); iter.get(); iter.next()) { + const Element* element = iter.get(); + bool useHWAA = element->isAA() && drawContext->isStencilBufferMultisampled(); + + bool fillInverted = false; + + // This will be used to determine whether the clip shape can be rendered into the + // stencil with arbitrary stencil settings. + GrPathRenderer::StencilSupport stencilSupport; + + SkRegion::Op op = element->getOp(); + + GrPathRenderer* pr = nullptr; + SkPath clipPath; + if (Element::kRect_Type == element->getType()) { + stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; + fillInverted = false; + } else { + element->asPath(&clipPath); + fillInverted = clipPath.isInverseFillType(); + if (fillInverted) { + clipPath.toggleInverseFillType(); + } + + GrShape shape(clipPath, GrStyle::SimpleFill()); + GrPathRenderer::CanDrawPathArgs canDrawArgs; + canDrawArgs.fShaderCaps = context->caps()->shaderCaps(); + canDrawArgs.fViewMatrix = &viewMatrix; + canDrawArgs.fShape = &shape; + canDrawArgs.fAntiAlias = false; + canDrawArgs.fHasUserStencilSettings = false; + canDrawArgs.fIsStencilBufferMSAA = drawContext->isStencilBufferMultisampled(); + + GrDrawingManager* dm = context->contextPriv().drawingManager(); + pr = dm->getPathRenderer(canDrawArgs, false, + GrPathRendererChain::kStencilOnly_DrawType, + &stencilSupport); + if (!pr) { + return false; + } + } + + bool canRenderDirectToStencil = + GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport; + bool drawDirectToClip; // Given the renderer, the element, + // fill rule, and set operation should + // we render the element directly to + // stencil bit used for clipping. + GrUserStencilSettings const* const* stencilPasses = + GrStencilSettings::GetClipPasses(op, canRenderDirectToStencil, fillInverted, + &drawDirectToClip); + + // draw the element to the client stencil bits if necessary + if (!drawDirectToClip) { + static constexpr GrUserStencilSettings kDrawToStencil( + GrUserStencilSettings::StaticInit< + 0x0000, + GrUserStencilTest::kAlways, + 0xffff, + GrUserStencilOp::kIncMaybeClamp, + GrUserStencilOp::kIncMaybeClamp, + 0xffff>() + ); + if (Element::kRect_Type == element->getType()) { + drawContext->drawContextPriv().stencilRect(stencilClip.fixedClip(), + &kDrawToStencil, useHWAA, + viewMatrix, element->getRect()); + } else { + if (!clipPath.isEmpty()) { + GrShape shape(clipPath, GrStyle::SimpleFill()); + if (canRenderDirectToStencil) { + GrPaint paint; + paint.setXPFactory(GrDisableColorXPFactory::Make()); + paint.setAntiAlias(element->isAA()); + + GrPathRenderer::DrawPathArgs args; + args.fResourceProvider = context->resourceProvider(); + args.fPaint = &paint; + args.fUserStencilSettings = &kDrawToStencil; + args.fDrawContext = drawContext; + args.fClip = &stencilClip.fixedClip(); + args.fViewMatrix = &viewMatrix; + args.fShape = &shape; + args.fAntiAlias = false; + args.fGammaCorrect = false; + pr->drawPath(args); + } else { + GrPathRenderer::StencilPathArgs args; + args.fResourceProvider = context->resourceProvider(); + args.fDrawContext = drawContext; + args.fClip = &stencilClip.fixedClip(); + args.fViewMatrix = &viewMatrix; + args.fIsAA = element->isAA(); + args.fShape = &shape; + pr->stencilPath(args); + } + } + } + } + + // now we modify the clip bit by rendering either the clip + // element directly or a bounding rect of the entire clip. + for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) { + if (drawDirectToClip) { + if (Element::kRect_Type == element->getType()) { + drawContext->drawContextPriv().stencilRect(stencilClip, *pass, useHWAA, + viewMatrix, element->getRect()); + } else { + GrShape shape(clipPath, GrStyle::SimpleFill()); + GrPaint paint; + paint.setXPFactory(GrDisableColorXPFactory::Make()); + paint.setAntiAlias(element->isAA()); + GrPathRenderer::DrawPathArgs args; + args.fResourceProvider = context->resourceProvider(); + args.fPaint = &paint; + args.fUserStencilSettings = *pass; + args.fDrawContext = drawContext; + args.fClip = &stencilClip; + args.fViewMatrix = &viewMatrix; + args.fShape = &shape; + args.fAntiAlias = false; + args.fGammaCorrect = false; + pr->drawPath(args); + } + } else { + // The view matrix is setup to do clip space -> stencil space translation, so + // draw rect in clip space. + drawContext->drawContextPriv().stencilRect(stencilClip, *pass, + false, viewMatrix, + SkRect::Make(fIBounds)); + } + } + } + return true; +} diff --git a/src/gpu/GrReducedClip.h b/src/gpu/GrReducedClip.h index c3f94a0dff..731d58f61c 100644 --- a/src/gpu/GrReducedClip.h +++ b/src/gpu/GrReducedClip.h @@ -11,6 +11,9 @@ #include "SkClipStack.h" #include "SkTLList.h" +class GrContext; +class GrDrawContext; + /** * 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. @@ -60,6 +63,9 @@ public: InitialState initialState() const { return fInitialState; } + bool drawAlphaClipMask(GrDrawContext*) const; + bool drawStencilClipMask(GrContext*, GrDrawContext*, const SkIPoint& clipOrigin) const; + private: void walkStack(const SkClipStack&, const SkRect& queryBounds); bool intersectIBounds(const SkIRect&); diff --git a/src/gpu/GrStencilAttachment.h b/src/gpu/GrStencilAttachment.h index 8f41b57e21..0ed3c8b27c 100644 --- a/src/gpu/GrStencilAttachment.h +++ b/src/gpu/GrStencilAttachment.h @@ -31,18 +31,18 @@ public: // called to note the last clip drawn to this buffer. void setLastClip(int32_t clipStackGenID, const SkIRect& clipSpaceRect, - const SkIPoint clipSpaceToStencilOffset) { + const SkIPoint clipOrigin) { fLastClipStackGenID = clipStackGenID; fLastClipStackRect = clipSpaceRect; - fLastClipSpaceOffset = clipSpaceToStencilOffset; + fLastClipOrigin = clipOrigin; } // called to determine if we have to render the clip into SB. bool mustRenderClip(int32_t clipStackGenID, const SkIRect& clipSpaceRect, - const SkIPoint clipSpaceToStencilOffset) const { + const SkIPoint& clipOrigin) const { return fLastClipStackGenID != clipStackGenID || - fLastClipSpaceOffset != clipSpaceToStencilOffset || + fLastClipOrigin != clipOrigin || !fLastClipStackRect.contains(clipSpaceRect); } @@ -71,7 +71,7 @@ private: int32_t fLastClipStackGenID; SkIRect fLastClipStackRect; - SkIPoint fLastClipSpaceOffset; + SkIPoint fLastClipOrigin; typedef GrGpuResource INHERITED; }; |