diff options
author | Chris Dalton <csmartdalton@google.com> | 2018-03-27 15:11:59 -0600 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-03-28 15:01:04 +0000 |
commit | a466228a616b1b02ede2d4389fefcfc839a54a25 (patch) | |
tree | e5a48f35dc33b0c4d0aeef4327a5960c3b5992e9 /src/gpu | |
parent | 41964ed46e241c95cd6c91ac99271c2a232f1b65 (diff) |
Delete GPU alpha clip masks
The cost of switching render targets on each draw to make a custom
clip is enormous. There are virtually no circumstances where this will
outperform our cached, multi-threaded software mask generator. The
tried-and-true approach to clipping on-GPU is with analytic FPs. And
now that we support CCPR clip FPs, there ulitmately should be very few
clip stacks that even require a mask as long as they don't use
deprecated SkClipOps.
Bug: skia:
Change-Id: I79c5558c93c1b99179f1e933d029f69b14ad1ce3
Reviewed-on: https://skia-review.googlesource.com/116724
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrClipStackClip.cpp | 168 | ||||
-rw-r--r-- | src/gpu/GrClipStackClip.h | 21 | ||||
-rw-r--r-- | src/gpu/GrReducedClip.cpp | 128 | ||||
-rw-r--r-- | src/gpu/GrReducedClip.h | 1 |
4 files changed, 11 insertions, 307 deletions
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp index fe8d10095c..ed4a098c8d 100644 --- a/src/gpu/GrClipStackClip.cpp +++ b/src/gpu/GrClipStackClip.cpp @@ -73,111 +73,6 @@ void GrClipStackClip::getConservativeBounds(int width, int height, SkIRect* devR devBounds.roundOut(devResult); } -//////////////////////////////////////////////////////////////////////////////// -// set up the draw state to enable the aa clipping mask. -static std::unique_ptr<GrFragmentProcessor> create_fp_for_mask(sk_sp<GrTextureProxy> mask, - const SkIRect& devBound) { - SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); - return GrDeviceSpaceTextureDecalFragmentProcessor::Make(std::move(mask), domainTexels, - {devBound.fLeft, devBound.fTop}); -} - -// 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). -bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context, - const SkIRect& scissorRect, - bool hasUserStencilSettings, - const GrRenderTargetContext* renderTargetContext, - const SkMatrix& viewMatrix, - const Element* element, - GrPathRenderer** prOut, - bool needsStencil) { - if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) { - // rects can always be drawn directly w/o using the software path - // TODO: skip rrects once we're drawing them directly. - if (prOut) { - *prOut = nullptr; - } - return false; - } else { - // We shouldn't get here with an empty clip element. - SkASSERT(Element::DeviceSpaceType::kEmpty != element->getDeviceSpaceType()); - - // the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer - SkPath path; - element->asDeviceSpacePath(&path); - if (path.isInverseFillType()) { - path.toggleInverseFillType(); - } - - GrPathRendererChain::DrawType type = - needsStencil ? GrPathRendererChain::DrawType::kStencilAndColor - : GrPathRendererChain::DrawType::kColor; - - GrShape shape(path, GrStyle::SimpleFill()); - GrPathRenderer::CanDrawPathArgs canDrawArgs; - canDrawArgs.fCaps = context->caps(); - canDrawArgs.fClipConservativeBounds = &scissorRect; - canDrawArgs.fViewMatrix = &viewMatrix; - canDrawArgs.fShape = &shape; - canDrawArgs.fAAType = GrChooseAAType(GrAA(element->isAA()), - renderTargetContext->fsaaType(), - GrAllowMixedSamples::kYes, - *context->caps()); - canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings; - - // the 'false' parameter disallows use of the SW path renderer - GrPathRenderer* pr = - context->contextPriv().drawingManager()->getPathRenderer(canDrawArgs, false, type); - if (prOut) { - *prOut = pr; - } - return SkToBool(!pr); - } -} - -/* - * This method traverses the clip stack to see if the GrSoftwarePathRenderer - * 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 GrClipStackClip::UseSWOnlyPath(GrContext* context, - bool hasUserStencilSettings, - const GrRenderTargetContext* renderTargetContext, - 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. - - // If we're avoiding stencils, always use SW: - if (context->caps()->avoidStencilBuffers()) - return true; - - // Set the matrix so that rendered clip elements are transformed to mask space from clip - // space. - SkMatrix translate; - translate.setTranslate(SkIntToScalar(-reducedClip.left()), SkIntToScalar(-reducedClip.top())); - - for (ElementList::Iter iter(reducedClip.maskElements()); iter.get(); iter.next()) { - const Element* element = iter.get(); - - SkClipOp op = element->getOp(); - bool invert = element->isInverseFilled(); - bool needsStencil = invert || - kIntersect_SkClipOp == op || kReverseDifference_SkClipOp == op; - - if (PathNeedsSWRenderer(context, reducedClip.scissor(), hasUserStencilSettings, - renderTargetContext, translate, element, nullptr, needsStencil)) { - return true; - } - } - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// sort out what kind of clip mask needs to be created: alpha, stencil, -// scissor, or entirely software bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTargetContext, bool useHWAA, bool hasUserStencilSettings, GrAppliedClip* out, SkRect* bounds) const { @@ -253,24 +148,18 @@ bool GrClipStackClip::applyClipMask(GrContext* context, GrRenderTargetContext* r // If the stencil buffer is multisampled we can use it to do everything. if ((GrFSAAType::kNone == renderTargetContext->fsaaType() && reducedClip.maskRequiresAA()) || context->caps()->avoidStencilBuffers()) { - sk_sp<GrTextureProxy> result; - if (UseSWOnlyPath(context, hasUserStencilSettings, renderTargetContext, reducedClip)) { - // The clip geometry is complex enough that it will be more efficient to create it - // entirely in software - result = this->createSoftwareClipMask(context, reducedClip, renderTargetContext); - } else { - result = this->createAlphaClipMask(context, reducedClip); - } - - if (result) { - // The mask's top left coord should be pinned to the rounded-out top left corner of - // the clip's device space bounds. - out->addCoverageFP(create_fp_for_mask(std::move(result), reducedClip.scissor())); + if (auto mask = this->createSoftwareClipMask(context, reducedClip, renderTargetContext)) { + // The mask should fill the clip's scissor. + SkIRect domainTexels = SkIRect::MakeWH(reducedClip.width(), reducedClip.height()); + SkIPoint maskOffset = SkIPoint::Make(reducedClip.left(), reducedClip.top()); + out->addCoverageFP(GrDeviceSpaceTextureDecalFragmentProcessor::Make(std::move(mask), + domainTexels, + maskOffset)); return true; } - // If alpha or software clip mask creation fails, fall through to the stencil code paths, - // unless stencils are disallowed. + // If software clip mask creation fails, fall through to the stencil code paths, unless + // stencils are disallowed. if (context->caps()->avoidStencilBuffers()) { SkDebugf("WARNING: Clip mask requires stencil, but stencil unavailable. " "Clip will be ignored.\n"); @@ -324,45 +213,6 @@ static void add_invalidate_on_pop_message(const SkClipStack& stack, uint32_t cli SkDEBUGFAIL("Gen ID was not found in stack."); } -sk_sp<GrTextureProxy> GrClipStackClip::createAlphaClipMask(GrContext* context, - const GrReducedClip& reducedClip) const { - GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); - GrUniqueKey key; - create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(), - reducedClip.numAnalyticFPs(), &key); - - sk_sp<GrTextureProxy> proxy(proxyProvider->findOrCreateProxyByUniqueKey( - key, kBottomLeft_GrSurfaceOrigin)); - if (proxy) { - return proxy; - } - - sk_sp<GrRenderTargetContext> rtc( - context->contextPriv().makeDeferredRenderTargetContextWithFallback(SkBackingFit::kApprox, - reducedClip.width(), - reducedClip.height(), - kAlpha_8_GrPixelConfig, - nullptr)); - if (!rtc) { - return nullptr; - } - - if (!reducedClip.drawAlphaClipMask(rtc.get())) { - return nullptr; - } - - sk_sp<GrTextureProxy> result(rtc->asTextureProxyRef()); - if (!result) { - return nullptr; - } - - SkASSERT(result->origin() == kBottomLeft_GrSurfaceOrigin); - proxyProvider->assignUniqueKeyToProxy(key, result.get()); - add_invalidate_on_pop_message(*fStack, reducedClip.maskGenID(), key); - - return result; -} - namespace { /** diff --git a/src/gpu/GrClipStackClip.h b/src/gpu/GrClipStackClip.h index aeb983468c..05d9f18c88 100644 --- a/src/gpu/GrClipStackClip.h +++ b/src/gpu/GrClipStackClip.h @@ -37,31 +37,14 @@ public: static const char kMaskTestTag[]; private: - static bool PathNeedsSWRenderer(GrContext* context, - const SkIRect& scissorRect, - bool hasUserStencilSettings, - const GrRenderTargetContext*, - const SkMatrix& viewMatrix, - const SkClipStack::Element* element, - GrPathRenderer** prOut, - bool needsStencil); - bool applyClipMask(GrContext*, GrRenderTargetContext*, const GrReducedClip&, bool hasUserStencilSettings, GrAppliedClip*) const; - // Creates an alpha mask of the clip. The mask is a rasterization of elements through the - // rect specified by clipSpaceIBounds. - sk_sp<GrTextureProxy> createAlphaClipMask(GrContext*, const GrReducedClip&) const; - - // Similar to createAlphaClipMask but it rasterizes in SW and uploads to the result texture. + // Creates an alpha mask of the remaining reduced clip elements that could not be handled + // analytically on the GPU. The mask fills the reduced clip's scissor rect. sk_sp<GrTextureProxy> createSoftwareClipMask(GrContext*, const GrReducedClip&, GrRenderTargetContext*) const; - static bool UseSWOnlyPath(GrContext*, - bool hasUserStencilSettings, - const GrRenderTargetContext*, - const GrReducedClip&); - const SkClipStack* fStack; }; diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp index 9d27f7696e..2f60dad28f 100644 --- a/src/gpu/GrReducedClip.cpp +++ b/src/gpu/GrReducedClip.cpp @@ -673,134 +673,6 @@ void GrReducedClip::makeEmpty() { } //////////////////////////////////////////////////////////////////////////////// -// Create a 8-bit clip mask in alpha - -static bool stencil_element(GrRenderTargetContext* rtc, - const GrFixedClip& clip, - const GrUserStencilSettings* ss, - const SkMatrix& viewMatrix, - const SkClipStack::Element* element) { - GrAA aa = GrAA(element->isAA()); - switch (element->getDeviceSpaceType()) { - case SkClipStack::Element::DeviceSpaceType::kEmpty: - SkDEBUGFAIL("Should never get here with an empty element."); - break; - case SkClipStack::Element::DeviceSpaceType::kRect: - return rtc->priv().drawAndStencilRect(clip, ss, (SkRegion::Op)element->getOp(), - element->isInverseFilled(), aa, viewMatrix, - element->getDeviceSpaceRect()); - break; - default: { - SkPath path; - element->asDeviceSpacePath(&path); - if (path.isInverseFillType()) { - path.toggleInverseFillType(); - } - - return rtc->priv().drawAndStencilPath(clip, ss, (SkRegion::Op)element->getOp(), - element->isInverseFilled(), aa, viewMatrix, path); - break; - } - } - - return false; -} - -static void draw_element(GrRenderTargetContext* rtc, - const GrClip& clip, // TODO: can this just always be WideOpen? - GrPaint&& paint, - GrAA aa, - const SkMatrix& viewMatrix, - const SkClipStack::Element* element) { - // TODO: Draw rrects directly here. - switch (element->getDeviceSpaceType()) { - case SkClipStack::Element::DeviceSpaceType::kEmpty: - SkDEBUGFAIL("Should never get here with an empty element."); - break; - case SkClipStack::Element::DeviceSpaceType::kRect: - rtc->drawRect(clip, std::move(paint), aa, viewMatrix, element->getDeviceSpaceRect()); - break; - default: { - SkPath path; - element->asDeviceSpacePath(&path); - if (path.isInverseFillType()) { - path.toggleInverseFillType(); - } - - rtc->drawPath(clip, std::move(paint), aa, viewMatrix, path, GrStyle::SimpleFill()); - break; - } - } -} - -bool GrReducedClip::drawAlphaClipMask(GrRenderTargetContext* rtc) 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(fScissor.width(), fScissor.height())); - - if (!fWindowRects.empty()) { - clip.setWindowRectangles(fWindowRects.makeOffset(-fScissor.left(), -fScissor.top()), - GrWindowRectsState::Mode::kExclusive); - } - - // 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; - rtc->priv().clear(clip, initialCoverage, GrRenderTargetContext::CanClearFullscreen::kYes); - - // Set the matrix so that rendered clip elements are transformed to mask space from clip space. - SkMatrix translate; - translate.setTranslate(SkIntToScalar(-fScissor.left()), SkIntToScalar(-fScissor.top())); - - // walk through each clip element and perform its set op - for (ElementList::Iter iter(fMaskElements); iter.get(); iter.next()) { - const Element* element = iter.get(); - SkRegion::Op op = (SkRegion::Op)element->getOp(); - GrAA aa = GrAA(element->isAA()); - 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(rtc, 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 (!rtc->priv().drawAndStencilRect(clip, &kDrawOutsideElement, op, !invert, GrAA::kNo, - translate, SkRect::Make(fScissor))) { - return false; - } - } else { - // all the remaining ops can just be directly draw into the accumulation buffer - GrPaint paint; - paint.setCoverageSetOpXPFactory(op, false); - - draw_element(rtc, clip, std::move(paint), aa, translate, element); - } - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// // Create a 1-bit clip mask in the stencil buffer. bool GrReducedClip::drawStencilClipMask(GrContext* context, diff --git a/src/gpu/GrReducedClip.h b/src/gpu/GrReducedClip.h index c3838d8802..5447652137 100644 --- a/src/gpu/GrReducedClip.h +++ b/src/gpu/GrReducedClip.h @@ -83,7 +83,6 @@ public: */ bool maskRequiresAA() const { SkASSERT(!fMaskElements.isEmpty()); return fMaskRequiresAA; } - bool drawAlphaClipMask(GrRenderTargetContext*) const; bool drawStencilClipMask(GrContext*, GrRenderTargetContext*) const; int numAnalyticFPs() const { return fAnalyticFPs.count() + fCCPRClipPaths.count(); } |