| Index: src/gpu/GrClipMaskManager.cpp
|
| diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
|
| index 3168424cf8715a998b0f0aec94655d9021143b43..70c65ed70585c8b30a5e12e9b49237f26b14bbc1 100644
|
| --- a/src/gpu/GrClipMaskManager.cpp
|
| +++ b/src/gpu/GrClipMaskManager.cpp
|
| @@ -8,7 +8,7 @@
|
| #include "GrClipMaskManager.h"
|
| #include "GrCaps.h"
|
| #include "GrDrawingManager.h"
|
| -#include "GrDrawContext.h"
|
| +#include "GrDrawContextPriv.h"
|
| #include "GrDrawTarget.h"
|
| #include "GrGpuResourcePriv.h"
|
| #include "GrPaint.h"
|
| @@ -159,7 +159,8 @@ GrResourceProvider* GrClipMaskManager::resourceProvider() {
|
| * will be used on any element. If so, it returns true to indicate that the
|
| * entire clip should be rendered in SW and then uploaded en masse to the gpu.
|
| */
|
| -bool GrClipMaskManager::useSWOnlyPath(const GrPipelineBuilder& pipelineBuilder,
|
| +bool GrClipMaskManager::UseSWOnlyPath(GrContext* context,
|
| + const GrPipelineBuilder& pipelineBuilder,
|
| const GrRenderTarget* rt,
|
| const SkVector& clipToMaskOffset,
|
| const GrReducedClip::ElementList& elements) {
|
| @@ -179,7 +180,7 @@ bool GrClipMaskManager::useSWOnlyPath(const GrPipelineBuilder& pipelineBuilder,
|
| bool needsStencil = invert ||
|
| SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op;
|
|
|
| - if (PathNeedsSWRenderer(this->getContext(), pipelineBuilder.getStencil().isDisabled(),
|
| + if (PathNeedsSWRenderer(context, pipelineBuilder.getStencil().isDisabled(),
|
| rt, translate, element, nullptr, needsStencil)) {
|
| return true;
|
| }
|
| @@ -316,6 +317,42 @@ static void add_rect_to_clip(const GrClip& clip, const SkRect& devRect, GrClip*
|
| }
|
| }
|
|
|
| +bool GrClipMaskManager::setupScissorClip(const GrPipelineBuilder& pipelineBuilder,
|
| + GrPipelineBuilder::AutoRestoreStencil* ars,
|
| + const SkIRect& clipScissor,
|
| + const SkRect* devBounds,
|
| + GrAppliedClip* out) {
|
| + if (kRespectClip_StencilClipMode == fClipMode) {
|
| + fClipMode = kIgnoreClip_StencilClipMode;
|
| + }
|
| +
|
| + GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
|
| +
|
| + SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height());
|
| + SkIRect devBoundsScissor;
|
| + const SkIRect* scissor = &clipScissor;
|
| + bool doDevBoundsClip = fDebugClipBatchToBounds && devBounds;
|
| + if (doDevBoundsClip) {
|
| + devBounds->roundOut(&devBoundsScissor);
|
| + if (devBoundsScissor.intersect(clipScissor)) {
|
| + scissor = &devBoundsScissor;
|
| + }
|
| + }
|
| +
|
| + if (scissor->contains(clipSpaceRTIBounds)) {
|
| + // This counts as wide open
|
| + this->setPipelineBuilderStencil(pipelineBuilder, ars);
|
| + return true;
|
| + }
|
| +
|
| + if (clipSpaceRTIBounds.intersect(*scissor)) {
|
| + out->fScissorState.set(clipSpaceRTIBounds);
|
| + this->setPipelineBuilderStencil(pipelineBuilder, ars);
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| ////////////////////////////////////////////////////////////////////////////////
|
| // sort out what kind of clip mask needs to be created: alpha, stencil,
|
| // scissor, or entirely software
|
| @@ -439,21 +476,23 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
| SkIntToScalar(-clipSpaceIBounds.fTop)
|
| };
|
|
|
| - if (this->useSWOnlyPath(pipelineBuilder, rt, clipToMaskOffset, elements)) {
|
| + if (UseSWOnlyPath(this->getContext(), pipelineBuilder, rt, clipToMaskOffset, elements)) {
|
| // The clip geometry is complex enough that it will be more efficient to create it
|
| // entirely in software
|
| - result.reset(this->createSoftwareClipMask(genID,
|
| - initialState,
|
| - elements,
|
| - clipToMaskOffset,
|
| - clipSpaceIBounds));
|
| + result.reset(CreateSoftwareClipMask(this->getContext(),
|
| + genID,
|
| + initialState,
|
| + elements,
|
| + clipToMaskOffset,
|
| + clipSpaceIBounds));
|
| } else {
|
| - result.reset(this->createAlphaClipMask(genID,
|
| - initialState,
|
| - elements,
|
| - clipToMaskOffset,
|
| - clipSpaceIBounds));
|
| - // If createAlphaClipMask fails it means useSWOnlyPath has a bug
|
| + result.reset(CreateAlphaClipMask(this->getContext(),
|
| + genID,
|
| + initialState,
|
| + elements,
|
| + clipToMaskOffset,
|
| + clipSpaceIBounds));
|
| + // If createAlphaClipMask fails it means UseSWOnlyPath has a bug
|
| SkASSERT(result);
|
| }
|
|
|
| @@ -488,93 +527,67 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
| return true;
|
| }
|
|
|
| -namespace {
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// Set a coverage drawing XPF on the pipelineBuilder for the given op and invertCoverage mode
|
| -void set_coverage_drawing_xpf(SkRegion::Op op, bool invertCoverage,
|
| - GrPipelineBuilder* pipelineBuilder) {
|
| - SkASSERT(op <= SkRegion::kLastOp);
|
| - pipelineBuilder->setCoverageSetOpXPFactory(op, invertCoverage);
|
| -}
|
| -}
|
| +static bool stencil_element(GrDrawContext* dc,
|
| + const SkIRect* scissorRect,
|
| + const GrStencilSettings& ss,
|
| + const SkMatrix& viewMatrix,
|
| + const SkClipStack::Element* element) {
|
|
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -bool GrClipMaskManager::drawElement(GrPipelineBuilder* pipelineBuilder,
|
| - const SkMatrix& viewMatrix,
|
| - GrTexture* target,
|
| - const SkClipStack::Element* element,
|
| - GrPathRenderer* pr) {
|
| + // 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(scissorRect, 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(scissorRect, ss,
|
| + element->getOp(),
|
| + element->isInverseFilled(),
|
| + element->isAA(), viewMatrix, path);
|
| + break;
|
| + }
|
| + }
|
|
|
| - GrRenderTarget* rt = target->asRenderTarget();
|
| - pipelineBuilder->setRenderTarget(rt);
|
| + return false;
|
| +}
|
|
|
| - // The color we use to draw does not matter since we will always be using a GrCoverageSetOpXP
|
| - // which ignores color.
|
| - GrColor color = GrColor_WHITE;
|
| +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: {
|
| - // TODO: Do rects directly to the accumulator using a aa-rect GrProcessor that covers
|
| - // the entire mask bounds and writes 0 outside the rect.
|
| - if (element->isAA()) {
|
| - SkRect devRect = element->getRect();
|
| - viewMatrix.mapRect(&devRect);
|
| -
|
| - SkAutoTUnref<GrDrawBatch> batch(
|
| - GrRectBatchFactory::CreateAAFill(color, viewMatrix, element->getRect(),
|
| - devRect));
|
| -
|
| - fDrawTarget->drawBatch(*pipelineBuilder, batch);
|
| - } else {
|
| - draw_non_aa_rect(fDrawTarget, *pipelineBuilder, color, viewMatrix,
|
| - element->getRect());
|
| - }
|
| - return true;
|
| - }
|
| + case Element::kRect_Type:
|
| + dc->drawRect(clip, paint, viewMatrix, element->getRect());
|
| + break;
|
| default: {
|
| SkPath path;
|
| element->asPath(&path);
|
| if (path.isInverseFillType()) {
|
| path.toggleInverseFillType();
|
| }
|
| - GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
|
| - if (nullptr == pr) {
|
| - GrPathRendererChain::DrawType type;
|
| - type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_DrawType :
|
| - GrPathRendererChain::kColor_DrawType;
|
|
|
| - GrPathRenderer::CanDrawPathArgs canDrawArgs;
|
| - canDrawArgs.fShaderCaps = this->getContext()->caps()->shaderCaps();
|
| - canDrawArgs.fViewMatrix = &viewMatrix;
|
| - canDrawArgs.fPath = &path;
|
| - canDrawArgs.fStroke = &stroke;
|
| - canDrawArgs.fAntiAlias = element->isAA();;
|
| - canDrawArgs.fIsStencilDisabled = pipelineBuilder->getStencil().isDisabled();
|
| - canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled();
|
| -
|
| - pr = this->getContext()->drawingManager()->getPathRenderer(canDrawArgs, false, type);
|
| - }
|
| - if (nullptr == pr) {
|
| - return false;
|
| - }
|
| - GrPathRenderer::DrawPathArgs args;
|
| - args.fTarget = fDrawTarget;
|
| - args.fResourceProvider = this->getContext()->resourceProvider();
|
| - args.fPipelineBuilder = pipelineBuilder;
|
| - args.fColor = color;
|
| - args.fViewMatrix = &viewMatrix;
|
| - args.fPath = &path;
|
| - args.fStroke = &stroke;
|
| - args.fAntiAlias = element->isAA();
|
| - pr->drawPath(args);
|
| + dc->drawPath(clip, paint, viewMatrix, path, GrStrokeInfo::FillInfo());
|
| break;
|
| }
|
| }
|
| - return true;
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| @@ -588,32 +601,13 @@ static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
|
| builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16);
|
| }
|
|
|
| -GrTexture* GrClipMaskManager::createCachedMask(int width, int height, const GrUniqueKey& key,
|
| - bool renderTarget) {
|
| - GrSurfaceDesc desc;
|
| - desc.fWidth = width;
|
| - desc.fHeight = height;
|
| - desc.fFlags = renderTarget ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
|
| - if (!renderTarget || this->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
|
| - desc.fConfig = kAlpha_8_GrPixelConfig;
|
| - } else {
|
| - desc.fConfig = kRGBA_8888_GrPixelConfig;
|
| - }
|
| -
|
| - GrTexture* texture = this->resourceProvider()->createApproxTexture(desc, 0);
|
| - if (!texture) {
|
| - return nullptr;
|
| - }
|
| - texture->resourcePriv().setUniqueKey(key);
|
| - return texture;
|
| -}
|
| -
|
| -GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
| +GrTexture* GrClipMaskManager::CreateAlphaClipMask(GrContext* context,
|
| + int32_t elementsGenID,
|
| GrReducedClip::InitialState initialState,
|
| const GrReducedClip::ElementList& elements,
|
| const SkVector& clipToMaskOffset,
|
| const SkIRect& clipSpaceIBounds) {
|
| - GrResourceProvider* resourceProvider = this->resourceProvider();
|
| + GrResourceProvider* resourceProvider = context->resourceProvider();
|
| GrUniqueKey key;
|
| GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key);
|
| if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) {
|
| @@ -621,15 +615,27 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
| }
|
|
|
| // There's no texture in the cache. Let's try to allocate it then.
|
| - SkAutoTUnref<GrTexture> texture(this->createCachedMask(
|
| - clipSpaceIBounds.width(), clipSpaceIBounds.height(), key, true));
|
| + GrSurfaceDesc desc;
|
| + desc.fWidth = clipSpaceIBounds.width();
|
| + desc.fHeight = clipSpaceIBounds.height();
|
| + desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
| + if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
|
| + desc.fConfig = kAlpha_8_GrPixelConfig;
|
| + } else {
|
| + desc.fConfig = kRGBA_8888_GrPixelConfig;
|
| + }
|
| +
|
| + SkAutoTUnref<GrTexture> texture(resourceProvider->createApproxTexture(desc, 0));
|
| if (!texture) {
|
| return nullptr;
|
| }
|
|
|
| - // 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);
|
| + texture->resourcePriv().setUniqueKey(key);
|
| +
|
| + SkAutoTUnref<GrDrawContext> dc(context->drawContext(texture->asRenderTarget()));
|
| + 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.
|
| @@ -637,16 +643,18 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
|
|
| // The scratch texture that we are drawing into can be substantially larger than the mask. Only
|
| // clear the part that we care about.
|
| - fDrawTarget->clear(&maskSpaceIBounds,
|
| - GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000,
|
| - true,
|
| - texture->asRenderTarget());
|
| + dc->clear(&maskSpaceIBounds,
|
| + GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000,
|
| + true);
|
|
|
| - // When we use the stencil in the below loop it is important to have this clip installed.
|
| + // 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.
|
| - const GrClip clip(maskSpaceIBounds);
|
|
|
| // walk through each clip element and perform its set op
|
| for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get(); iter.next()) {
|
| @@ -654,68 +662,54 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
| SkRegion::Op op = element->getOp();
|
| bool invert = element->isInverseFilled();
|
| if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) {
|
| -
|
| - GrPathRenderer* pr = GetPathRenderer(this->getContext(),
|
| +#ifdef SK_DEBUG
|
| + GrPathRenderer* pr = GetPathRenderer(context,
|
| texture, translate, element);
|
| if (Element::kRect_Type != element->getType() && !pr) {
|
| - // useSWOnlyPath should now filter out all cases where gpu-side mask merging would
|
| - // be performed (i.e., pr would be NULL for a non-rect path). See https://bug.skia.org/4519
|
| - // for rationale and details.
|
| + // UseSWOnlyPath should now filter out all cases where gpu-side mask merging would
|
| + // be performed (i.e., pr would be NULL for a non-rect path).
|
| + // See https://bug.skia.org/4519 for rationale and details.
|
| SkASSERT(0);
|
| - continue;
|
| }
|
| -
|
| - {
|
| - GrPipelineBuilder pipelineBuilder;
|
| -
|
| - pipelineBuilder.setClip(clip);
|
| - pipelineBuilder.setRenderTarget(texture->asRenderTarget());
|
| - SkASSERT(pipelineBuilder.getStencil().isDisabled());
|
| -
|
| - // draw directly into the result with the stencil set to make the pixels affected
|
| - // by the clip shape be non-zero.
|
| - GR_STATIC_CONST_SAME_STENCIL(kStencilInElement,
|
| - kReplace_StencilOp,
|
| - kReplace_StencilOp,
|
| - kAlways_StencilFunc,
|
| - 0xffff,
|
| - 0xffff,
|
| - 0xffff);
|
| - pipelineBuilder.setStencil(kStencilInElement);
|
| - set_coverage_drawing_xpf(op, invert, &pipelineBuilder);
|
| -
|
| - if (!this->drawElement(&pipelineBuilder, translate, texture, element, pr)) {
|
| - texture->resourcePriv().removeUniqueKey();
|
| - return nullptr;
|
| - }
|
| +#endif
|
| +
|
| + // draw directly into the result with the stencil set to make the pixels affected
|
| + // by the clip shape be non-zero.
|
| + GR_STATIC_CONST_SAME_STENCIL(kStencilInElement,
|
| + kReplace_StencilOp,
|
| + kReplace_StencilOp,
|
| + kAlways_StencilFunc,
|
| + 0xffff,
|
| + 0xffff,
|
| + 0xffff)
|
| + if (!stencil_element(dc, &maskSpaceIBounds, kStencilInElement,
|
| + translate, element)) {
|
| + texture->resourcePriv().removeUniqueKey();
|
| + return nullptr;
|
| }
|
|
|
| - {
|
| - GrPipelineBuilder backgroundPipelineBuilder;
|
| - backgroundPipelineBuilder.setRenderTarget(texture->asRenderTarget());
|
| -
|
| - set_coverage_drawing_xpf(op, !invert, &backgroundPipelineBuilder);
|
| - // Draw to the exterior pixels (those with a zero stencil value).
|
| - GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement,
|
| - kZero_StencilOp,
|
| - kZero_StencilOp,
|
| - kEqual_StencilFunc,
|
| - 0xffff,
|
| - 0x0000,
|
| - 0xffff);
|
| - backgroundPipelineBuilder.setStencil(kDrawOutsideElement);
|
| -
|
| - // The color passed in here does not matter since the coverageSetOpXP won't read it.
|
| - draw_non_aa_rect(fDrawTarget, backgroundPipelineBuilder, GrColor_WHITE, translate,
|
| - SkRect::Make(clipSpaceIBounds));
|
| + // Draw to the exterior pixels (those with a zero stencil value).
|
| + GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement,
|
| + kZero_StencilOp,
|
| + kZero_StencilOp,
|
| + kEqual_StencilFunc,
|
| + 0xffff,
|
| + 0x0000,
|
| + 0xffff);
|
| + if (!dc->drawContextPriv().drawAndStencilRect(&maskSpaceIBounds, kDrawOutsideElement,
|
| + op, !invert, false,
|
| + translate,
|
| + SkRect::Make(clipSpaceIBounds))) {
|
| + texture->resourcePriv().removeUniqueKey();
|
| + return nullptr;
|
| }
|
| } else {
|
| - GrPipelineBuilder pipelineBuilder;
|
| -
|
| // all the remaining ops can just be directly draw into the accumulation buffer
|
| - set_coverage_drawing_xpf(op, false, &pipelineBuilder);
|
| - // The color passed in here does not matter since the coverageSetOpXP won't read it.
|
| - this->drawElement(&pipelineBuilder, translate, texture, element);
|
| + GrPaint paint;
|
| + paint.setAntiAlias(element->isAA());
|
| + paint.setCoverageSetOpXPFactory(op, false);
|
| +
|
| + draw_element(dc, GrClip::WideOpen(), paint, translate, element);
|
| }
|
| }
|
|
|
| @@ -1081,14 +1075,15 @@ void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings,
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| -GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID,
|
| +GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context,
|
| + int32_t elementsGenID,
|
| GrReducedClip::InitialState initialState,
|
| const GrReducedClip::ElementList& elements,
|
| const SkVector& clipToMaskOffset,
|
| const SkIRect& clipSpaceIBounds) {
|
| GrUniqueKey key;
|
| GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key);
|
| - GrResourceProvider* resourceProvider = this->resourceProvider();
|
| + GrResourceProvider* resourceProvider = context->resourceProvider();
|
| if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) {
|
| return texture;
|
| }
|
| @@ -1097,7 +1092,7 @@ GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID,
|
| // the top left corner of the resulting rect to the top left of the texture.
|
| SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height());
|
|
|
| - GrSWMaskHelper helper(this->getContext());
|
| + GrSWMaskHelper helper(context);
|
|
|
| // Set the matrix so that rendered clip elements are transformed to mask space from clip
|
| // space.
|
| @@ -1141,11 +1136,17 @@ GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID,
|
| }
|
|
|
| // Allocate clip mask texture
|
| - GrTexture* result = this->createCachedMask(clipSpaceIBounds.width(), clipSpaceIBounds.height(),
|
| - key, false);
|
| - if (nullptr == result) {
|
| + GrSurfaceDesc desc;
|
| + desc.fWidth = clipSpaceIBounds.width();
|
| + desc.fHeight = clipSpaceIBounds.height();
|
| + desc.fConfig = kAlpha_8_GrPixelConfig;
|
| +
|
| + GrTexture* result = context->resourceProvider()->createApproxTexture(desc, 0);
|
| + if (!result) {
|
| return nullptr;
|
| }
|
| + result->resourcePriv().setUniqueKey(key);
|
| +
|
| helper.toTexture(result);
|
|
|
| return result;
|
|
|