| Index: src/gpu/GrClipStackClip.cpp
|
| diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
|
| index 23c2b42a9214e6bdfba9742495d1ddf1ce0a2dd9..003b4a5d439bb63782dd1370ea6bc7a0f94b4172 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);
|
|
|