Move clip mask generation into GrReducedClip
This is a temporary solution to facilitate window rectangles and make
clip mask generation more accessible for testing. The eventual goal is
to simplify clips and merge GrReducedClip into GrClipStackClip.
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2263343002
Review-Url: https://codereview.chromium.org/2263343002
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index 23c2b42..003b4a5 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 @@
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::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 @@
// 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,75 +375,24 @@
}
// use the stencil clip if we can't represent the clip as a rectangle.
- SkIPoint clipSpaceToStencilSpaceOffset = -fOrigin;
- CreateStencilClipMask(context, drawContext, reducedClip, clipSpaceToStencilSpaceOffset);
+ // 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;
+ }
+
+ if (stencilAttachment->mustRenderClip(reducedClip.elementsGenID(), reducedClip.ibounds(),
+ fOrigin)) {
+ reducedClip.drawStencilClipMask(context, drawContext, fOrigin);
+ stencilAttachment->setLastClip(reducedClip.elementsGenID(), reducedClip.ibounds(),
+ fOrigin);
+ }
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;
- }
- }
-
- 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;
- }
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
// Create a 8-bit clip mask in alpha
@@ -463,8 +405,7 @@
}
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 @@
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 @@
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 @@
// 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 ad143d6..075d1d8 100644
--- a/src/gpu/GrClipStackClip.h
+++ b/src/gpu/GrClipStackClip.h
@@ -49,28 +49,17 @@
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 6221fea..0157760 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -627,9 +627,9 @@
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 @@
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 @@
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 @@
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 8646e25..29eb151 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 237ea22..dfc0a26 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 @@
}
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 c3f94a0..731d58f 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 @@
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 8f41b57..0ed3c8b 100644
--- a/src/gpu/GrStencilAttachment.h
+++ b/src/gpu/GrStencilAttachment.h
@@ -31,18 +31,18 @@
// 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 @@
int32_t fLastClipStackGenID;
SkIRect fLastClipStackRect;
- SkIPoint fLastClipSpaceOffset;
+ SkIPoint fLastClipOrigin;
typedef GrGpuResource INHERITED;
};