diff options
author | 2015-10-26 08:33:10 -0700 | |
---|---|---|
committer | 2015-10-26 08:33:10 -0700 | |
commit | 5c3ea4cd3921e8904d4f201bcdedfd5b8a726542 (patch) | |
tree | 6dd7ca7a1cf6ff120496d6fe6b26f6c8db0a7682 /src | |
parent | 950305ec77702639fe6ad1923f7b8d828ccef634 (diff) |
Fix ClipMaskManager's SW-fallback logic
'useSWOnlyPath' was not correctly toggling between stencil and color draws so there was a mismatch with the behavior in createAlphaClipMask (i.e., we were inadvertently rendering some of the elements in a clip using SW but using stenciling for others - precisely what 'useSWOnlyPath' was intended to prevent).
Review URL: https://codereview.chromium.org/1421533007
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/GrClipMaskManager.cpp | 133 | ||||
-rw-r--r-- | src/gpu/GrClipMaskManager.h | 8 | ||||
-rw-r--r-- | src/gpu/GrContext.cpp | 2 | ||||
-rw-r--r-- | src/gpu/GrDrawContext.cpp | 6 | ||||
-rw-r--r-- | src/gpu/GrPathRendererChain.cpp | 16 |
5 files changed, 89 insertions, 76 deletions
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index b57f3cc1bc..b87788b286 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -46,24 +46,71 @@ static const GrFragmentProcessor* create_fp_for_mask(GrTexture* result, const Sk kDevice_GrCoordSet); } +// Does the path in 'element' require SW rendering? If so, return true (and, +// optionally, set 'prOut' to NULL. If not, return false (and, optionally, set +// 'prOut' to the non-SW path renderer that will do the job). static bool path_needs_SW_renderer(GrContext* context, const GrPipelineBuilder& pipelineBuilder, const SkMatrix& viewMatrix, - const SkPath& origPath, - const GrStrokeInfo& stroke, - bool doAA) { - // the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer - SkTCopyOnFirstWrite<SkPath> path(origPath); - if (path->isInverseFillType()) { - path.writable()->toggleInverseFillType(); + const Element* element, + GrPathRenderer** prOut, + bool needsStencil) { + if (Element::kRect_Type == element->getType()) { + // rects can always be drawn directly w/o using the software path + // TODO: skip rrects once we're drawing them directly. + return false; + } else { + // We shouldn't get here with an empty clip element. + SkASSERT(Element::kEmpty_Type != element->getType()); + + // the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer + SkPath path; + element->asPath(&path); + if (path.isInverseFillType()) { + path.toggleInverseFillType(); + } + GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); + + GrPathRendererChain::DrawType type; + + if (needsStencil) { + type = element->isAA() + ? GrPathRendererChain::kStencilAndColorAntiAlias_DrawType + : GrPathRendererChain::kStencilAndColor_DrawType; + } else { + type = element->isAA() + ? GrPathRendererChain::kColorAntiAlias_DrawType + : GrPathRendererChain::kColor_DrawType; + } + + // the 'false' parameter disallows use of the SW path renderer + GrPathRenderer* pr = context->getPathRenderer(pipelineBuilder, viewMatrix, path, + stroke, false, type); + if (prOut) { + *prOut = pr; + } + return SkToBool(!pr); } - // last (false) parameter disallows use of the SW path renderer - GrPathRendererChain::DrawType type = doAA ? - GrPathRendererChain::kColorAntiAlias_DrawType : - GrPathRendererChain::kColor_DrawType; +} - return nullptr == context->getPathRenderer(&pipelineBuilder, viewMatrix, *path, stroke, - false, type); +// Determines whether it is possible to draw the element to both the stencil buffer and the +// alpha mask simultaneously. If so and the element is a path a compatible path renderer is +// also returned. +static bool can_stencil_and_draw_element(GrContext* context, + GrPipelineBuilder* pipelineBuilder, + GrTexture* texture, + const SkMatrix& viewMatrix, + const SkClipStack::Element* element, + GrPathRenderer** pr) { + pipelineBuilder->setRenderTarget(texture->asRenderTarget()); + + static const bool kNeedsStencil = true; + return !path_needs_SW_renderer(context, + *pipelineBuilder, + viewMatrix, + element, + pr, + kNeedsStencil); } GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget) @@ -84,24 +131,22 @@ bool GrClipMaskManager::useSWOnlyPath(const GrPipelineBuilder& pipelineBuilder, // 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. - GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); // Set the matrix so that rendered clip elements are transformed to mask space from clip // space. - SkMatrix translate; - translate.setTranslate(clipToMaskOffset); + const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMaskOffset.fY); for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) { const Element* element = iter.get(); - // rects can always be drawn directly w/o using the software path - // Skip rrects once we're drawing them directly. - if (Element::kRect_Type != element->getType()) { - SkPath path; - element->asPath(&path); - if (path_needs_SW_renderer(this->getContext(), pipelineBuilder, translate, - path, stroke, element->isAA())) { - return true; - } + + SkRegion::Op op = element->getOp(); + bool invert = element->isInverseFilled(); + bool needsStencil = invert || + SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op; + + if (path_needs_SW_renderer(this->getContext(), pipelineBuilder, translate, + element, nullptr, needsStencil)) { + return true; } } return false; @@ -412,7 +457,7 @@ bool GrClipMaskManager::drawElement(GrPipelineBuilder* pipelineBuilder, GrPathRendererChain::DrawType type; type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_DrawType : GrPathRendererChain::kColor_DrawType; - pr = this->getContext()->getPathRenderer(pipelineBuilder, viewMatrix, + pr = this->getContext()->getPathRenderer(*pipelineBuilder, viewMatrix, path, stroke, false, type); } if (nullptr == pr) { @@ -434,32 +479,6 @@ bool GrClipMaskManager::drawElement(GrPipelineBuilder* pipelineBuilder, return true; } -bool GrClipMaskManager::canStencilAndDrawElement(GrPipelineBuilder* pipelineBuilder, - GrTexture* target, - GrPathRenderer** pr, - const SkClipStack::Element* element) { - pipelineBuilder->setRenderTarget(target->asRenderTarget()); - - if (Element::kRect_Type == element->getType()) { - return true; - } else { - // We shouldn't get here with an empty clip element. - SkASSERT(Element::kEmpty_Type != element->getType()); - SkPath path; - element->asPath(&path); - if (path.isInverseFillType()) { - path.toggleInverseFillType(); - } - GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); - GrPathRendererChain::DrawType type = element->isAA() ? - GrPathRendererChain::kStencilAndColorAntiAlias_DrawType : - GrPathRendererChain::kStencilAndColor_DrawType; - *pr = this->getContext()->getPathRenderer(pipelineBuilder, SkMatrix::I(), path, - stroke, false, type); - return SkToBool(*pr); - } -} - void GrClipMaskManager::mergeMask(GrPipelineBuilder* pipelineBuilder, GrTexture* dstMask, GrTexture* srcMask, @@ -555,8 +574,7 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, // Set the matrix so that rendered clip elements are transformed to mask space from clip // space. - SkMatrix translate; - translate.setTranslate(clipToMaskOffset); + const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMaskOffset.fY); // The texture may be larger than necessary, this rect represents the part of the texture // we populate with a rasterization of the clip. @@ -586,7 +604,8 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, pipelineBuilder.setClip(clip); GrPathRenderer* pr = nullptr; - bool useTemp = !this->canStencilAndDrawElement(&pipelineBuilder, texture, &pr, element); + bool useTemp = !can_stencil_and_draw_element(this->getContext(), &pipelineBuilder, + texture, translate, element, &pr); GrTexture* dst; // This is the bounds of the clip element in the space of the alpha-mask. The temporary // mask buffer can be substantially larger than the actually clip stack element. We @@ -594,6 +613,8 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, // the accumulator. SkIRect maskSpaceElementIBounds; + SkASSERT(!useTemp); + if (useTemp) { if (invert) { maskSpaceElementIBounds = maskSpaceIBounds; @@ -759,7 +780,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, if (fillInverted) { clipPath.toggleInverseFillType(); } - pr = this->getContext()->getPathRenderer(&pipelineBuilder, + pr = this->getContext()->getPathRenderer(pipelineBuilder, viewMatrix, clipPath, stroke, diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h index 3ce3e72bf1..515f4b6583 100644 --- a/src/gpu/GrClipMaskManager.h +++ b/src/gpu/GrClipMaskManager.h @@ -133,14 +133,6 @@ private: const SkClipStack::Element*, GrPathRenderer* pr = nullptr); - // Determines whether it is possible to draw the element to both the stencil buffer and the - // alpha mask simultaneously. If so and the element is a path a compatible path renderer is - // also returned. - bool canStencilAndDrawElement(GrPipelineBuilder*, - GrTexture* target, - GrPathRenderer**, - const SkClipStack::Element*); - void mergeMask(GrPipelineBuilder*, GrTexture* dstMask, GrTexture* srcMask, diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 081bc0ac38..04e1b8d203 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -541,7 +541,7 @@ void GrContext::flushSurfaceWrites(GrSurface* surface) { * Due to its expense, the software path renderer has split out so it can * can be individually allowed/disallowed via the "allowSW" boolean. */ -GrPathRenderer* GrContext::getPathRenderer(const GrPipelineBuilder* pipelineBuilder, +GrPathRenderer* GrContext::getPathRenderer(const GrPipelineBuilder& pipelineBuilder, const SkMatrix& viewMatrix, const SkPath& path, const GrStrokeInfo& stroke, diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp index f52d7dcd15..d64273a828 100644 --- a/src/gpu/GrDrawContext.cpp +++ b/src/gpu/GrDrawContext.cpp @@ -691,7 +691,7 @@ void GrDrawContext::internalDrawPath(GrPipelineBuilder* pipelineBuilder, const GrStrokeInfo* strokeInfoPtr = &strokeInfo; // Try a 1st time without stroking the path and without allowing the SW renderer - GrPathRenderer* pr = fDrawingManager->getContext()->getPathRenderer(pipelineBuilder, + GrPathRenderer* pr = fDrawingManager->getContext()->getPathRenderer(*pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr, false, type); @@ -707,7 +707,7 @@ void GrDrawContext::internalDrawPath(GrPipelineBuilder* pipelineBuilder, return; } strokeInfoPtr = &dashlessStrokeInfo; - pr = fDrawingManager->getContext()->getPathRenderer(pipelineBuilder, viewMatrix, + pr = fDrawingManager->getContext()->getPathRenderer(*pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr, false, type); } @@ -732,7 +732,7 @@ void GrDrawContext::internalDrawPath(GrPipelineBuilder* pipelineBuilder, } // This time, allow SW renderer - pr = fDrawingManager->getContext()->getPathRenderer(pipelineBuilder, viewMatrix, + pr = fDrawingManager->getContext()->getPathRenderer(*pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr, true, type); } diff --git a/src/gpu/GrPathRendererChain.cpp b/src/gpu/GrPathRendererChain.cpp index b1eb3202bf..c846dee5b3 100644 --- a/src/gpu/GrPathRendererChain.cpp +++ b/src/gpu/GrPathRendererChain.cpp @@ -40,7 +40,7 @@ GrPathRenderer* GrPathRendererChain::addPathRenderer(GrPathRenderer* pr) { } GrPathRenderer* GrPathRendererChain::getPathRenderer(const GrShaderCaps* shaderCaps, - const GrPipelineBuilder* pipelineBuilder, + const GrPipelineBuilder& pipelineBuilder, const SkMatrix& viewMatrix, const SkPath& path, const GrStrokeInfo& stroke, @@ -66,15 +66,15 @@ GrPathRenderer* GrPathRendererChain::getPathRenderer(const GrShaderCaps* shaderC minStencilSupport = GrPathRenderer::kNoSupport_StencilSupport; } + GrPathRenderer::CanDrawPathArgs args; + args.fShaderCaps = shaderCaps; + args.fPipelineBuilder = &pipelineBuilder; + args.fViewMatrix = &viewMatrix; + args.fPath = &path; + args.fStroke = &stroke; + args.fAntiAlias = antiAlias; for (int i = 0; i < fChain.count(); ++i) { - GrPathRenderer::CanDrawPathArgs args; - args.fShaderCaps = shaderCaps; - args.fPipelineBuilder = pipelineBuilder; - args.fViewMatrix = &viewMatrix; - args.fPath = &path; - args.fStroke = &stroke; - args.fAntiAlias = antiAlias; if (fChain[i]->canDrawPath(args)) { if (GrPathRenderer::kNoSupport_StencilSupport != minStencilSupport) { GrPathRenderer::StencilSupport support = |