diff options
Diffstat (limited to 'src/gpu/GrClipMaskManager.cpp')
-rw-r--r-- | src/gpu/GrClipMaskManager.cpp | 351 |
1 files changed, 176 insertions, 175 deletions
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index 3168424cf8..70c65ed705 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; |