Index: src/gpu/GrReducedClip.cpp |
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp |
index 237ea221e1a6c84cae087c503011a05134eb12a9..dfc0a2651bd45be8ff51a637f25523f6dd1633f2 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; |
+} |