diff options
author | 2017-11-16 13:56:47 +0000 | |
---|---|---|
committer | 2017-11-16 13:57:01 +0000 | |
commit | 554c1f0508a95b5411036a95d1bb62c0d5fdeae8 (patch) | |
tree | 9a4308484386496d1ab2a30cc53893f0234b45c1 /src/gpu/GrClipStackClip.cpp | |
parent | 63d26849701fe8cc37e181d4e0f6978063f7d269 (diff) |
Revert "Fold analytic clip FPs into GrReducedClip"
This reverts commit 4355b26b359d5f2597a10012e7eb11fb3a1f025b.
Reason for revert: Most likely CL for layout test failures on Chrome roll: https://bugs.chromium.org/p/chromium/issues/detail?id=785931
Original change's description:
> Fold analytic clip FPs into GrReducedClip
>
> Perf result on Pixel phone (sorted by impact):
>
> GEOMEAN 7.44 -> 6.92 ms [ 93%]
>
> keymobi_cnn_com.skp 3.55 -> 3.59 ms [101%]
> keymobi_theverge_com.skp 4.08 -> 4.13 ms [101%]
> desk_skbug6850autoscroll.skp 1.21 -> 1.22 ms [101%]
> ...
> top25desk_weather_com.skp 14.2 -> 11.5 ms [ 81%]
> keymobi_androidpolice_com_2012_.skp 3.84 -> 2.95 ms [ 77%]
> keymobi_shop_mobileweb_ebay_com.skp 2.94 -> 2.26 ms [ 77%]
> keymobi_boingboing_net.skp 3.08 -> 2.24 ms [ 73%]
> desk_jsfiddlebigcar.skp 1.90 -> 1.25 ms [ 66%]
> keymobi_m_youtube_com_watch_v_9.skp 13.5 -> 8.84 ms [ 65%]
> keymobi_sfgate_com_.skp 8.55 -> 5.55 ms [ 65%]
> keymobi_blogger.skp 4.01 -> 2.60 ms [ 65%]
>
> Cleaner code, improved skps, slightly better geometric mean time.
>
> Pixel C is mostly unaffected, presumably because it uses window
> rectangles.
>
> Bug: skia:7190
> Change-Id: Ia93f68b2f971ea66b3ab19dc73557ea602932a92
> Reviewed-on: https://skia-review.googlesource.com/67424
> Commit-Queue: Chris Dalton <csmartdalton@google.com>
> Reviewed-by: Brian Salomon <bsalomon@google.com>
TBR=bsalomon@google.com,robertphillips@google.com,csmartdalton@google.com
Change-Id: I86ff05196eaaeca4fb63836c9b449bbea76fe80b
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:7190
Reviewed-on: https://skia-review.googlesource.com/72480
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Diffstat (limited to 'src/gpu/GrClipStackClip.cpp')
-rw-r--r-- | src/gpu/GrClipStackClip.cpp | 152 |
1 files changed, 118 insertions, 34 deletions
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp index 52fab72476..c0fe10678b 100644 --- a/src/gpu/GrClipStackClip.cpp +++ b/src/gpu/GrClipStackClip.cpp @@ -30,6 +30,7 @@ typedef SkClipStack::Element Element; typedef GrReducedClip::InitialState InitialState; typedef GrReducedClip::ElementList ElementList; +static const int kMaxAnalyticElements = 4; const char GrClipStackClip::kMaskTestTag[] = "clip_mask"; bool GrClipStackClip::quickContains(const SkRect& rect) const { @@ -175,6 +176,80 @@ bool GrClipStackClip::UseSWOnlyPath(GrContext* context, return false; } +static bool get_analytic_clip_processor(const ElementList& elements, + bool abortIfAA, + const SkRect& drawDevBounds, + std::unique_ptr<GrFragmentProcessor>* resultFP) { + SkASSERT(elements.count() <= kMaxAnalyticElements); + SkSTArray<kMaxAnalyticElements, std::unique_ptr<GrFragmentProcessor>> fps; + ElementList::Iter iter(elements); + while (iter.get()) { + SkClipOp op = iter.get()->getOp(); + bool invert; + bool skip = false; + switch (op) { + case kReplace_SkClipOp: + SkASSERT(iter.get() == elements.head()); + // Fallthrough, handled same as intersect. + case kIntersect_SkClipOp: + invert = false; + if (iter.get()->contains(drawDevBounds)) { + skip = true; + } + break; + case kDifference_SkClipOp: + invert = true; + // We don't currently have a cheap test for whether a rect is fully outside an + // element's primitive, so don't attempt to set skip. + break; + default: + return false; + } + if (!skip) { + GrClipEdgeType edgeType; + if (iter.get()->isAA()) { + if (abortIfAA) { + return false; + } + edgeType = + invert ? GrClipEdgeType::kInverseFillAA : GrClipEdgeType::kFillAA; + } else { + edgeType = + invert ? GrClipEdgeType::kInverseFillBW : GrClipEdgeType::kFillBW; + } + + switch (iter.get()->getDeviceSpaceType()) { + case SkClipStack::Element::DeviceSpaceType::kPath: + fps.emplace_back( + GrConvexPolyEffect::Make(edgeType, iter.get()->getDeviceSpacePath())); + break; + case SkClipStack::Element::DeviceSpaceType::kRRect: { + fps.emplace_back( + GrRRectEffect::Make(edgeType, iter.get()->getDeviceSpaceRRect())); + break; + } + case SkClipStack::Element::DeviceSpaceType::kRect: { + fps.emplace_back( + GrConvexPolyEffect::Make(edgeType, iter.get()->getDeviceSpaceRect())); + break; + } + default: + break; + } + if (!fps.back()) { + return false; + } + } + iter.next(); + } + + *resultFP = nullptr; + if (fps.count()) { + *resultFP = GrFragmentProcessor::RunInSeries(fps.begin(), fps.count()); + } + return true; +} + //////////////////////////////////////////////////////////////////////////////// // sort out what kind of clip mask needs to be created: alpha, stencil, // scissor, or entirely software @@ -190,19 +265,8 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar return true; } - int maxAnalyticFPs = context->caps()->maxClipAnalyticFPs(); - if (GrFSAAType::kNone != renderTargetContext->fsaaType()) { - // With mixed samples (non-msaa color buffer), any coverage info is lost from color once it - // hits the color buffer anyway, so we may as well use coverage AA if nothing else in the - // pipe is multisampled. - if (renderTargetContext->numColorSamples() > 0 || useHWAA || hasUserStencilSettings) { - maxAnalyticFPs = 0; - } - SkASSERT(!context->caps()->avoidStencilBuffers()); // We disable MSAA when avoiding stencil. - } - - GrReducedClip reducedClip(*fStack, devBounds, renderTargetContext->priv().maxWindowRectangles(), - maxAnalyticFPs); + const GrReducedClip reducedClip(*fStack, devBounds, + renderTargetContext->priv().maxWindowRectangles()); if (reducedClip.hasScissor() && !GrClip::IsInsideClip(reducedClip.scissor(), devBounds)) { out->hardClip().addScissor(reducedClip.scissor(), bounds); @@ -213,10 +277,6 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar GrWindowRectsState::Mode::kExclusive); } - if (std::unique_ptr<GrFragmentProcessor> clipFPs = reducedClip.detachAnalyticFPs()) { - out->addCoverageFP(std::move(clipFPs)); - } - if (reducedClip.maskElements().isEmpty()) { return InitialState::kAllIn == reducedClip.initialState(); } @@ -229,9 +289,41 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar SkASSERT(rtIBounds.contains(scissor)); // Mask shouldn't be larger than the RT. #endif + bool avoidStencilBuffers = context->caps()->avoidStencilBuffers(); + + // An element count of 4 was chosen because of the common pattern in Blink of: + // isect RR + // diff RR + // isect convex_poly + // isect convex_poly + // when drawing rounded div borders. This could probably be tuned based on a + // configuration's relative costs of switching RTs to generate a mask vs + // longer shaders. + if (reducedClip.maskElements().count() <= kMaxAnalyticElements) { + // When there are multiple samples we want to do per-sample clipping, not compute a + // fractional pixel coverage. + bool disallowAnalyticAA = + GrFSAAType::kNone != renderTargetContext->fsaaType() && !avoidStencilBuffers; + if (disallowAnalyticAA && !renderTargetContext->numColorSamples()) { + // With a single color sample, any coverage info is lost from color once it hits the + // color buffer anyway, so we may as well use coverage AA if nothing else in the pipe + // is multisampled. + disallowAnalyticAA = useHWAA || hasUserStencilSettings; + } + std::unique_ptr<GrFragmentProcessor> clipFP; + if ((reducedClip.maskRequiresAA() || avoidStencilBuffers) && + get_analytic_clip_processor(reducedClip.maskElements(), disallowAnalyticAA, devBounds, + &clipFP)) { + if (clipFP) { + out->addCoverageFP(std::move(clipFP)); + } + return true; + } + } + // If the stencil buffer is multisampled we can use it to do everything. if ((GrFSAAType::kNone == renderTargetContext->fsaaType() && reducedClip.maskRequiresAA()) || - context->caps()->avoidStencilBuffers()) { + 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 @@ -251,8 +343,7 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar // If alpha or 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"); + SkDebugf("WARNING: Clip mask requires stencil, but stencil unavailable. Clip will be ignored.\n"); return false; } } @@ -262,14 +353,11 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar // This relies on the property that a reduced sub-rect of the last clip will contain all the // relevant window rectangles that were in the last clip. This subtle requirement will go away // after clipping is overhauled. - if (renderTargetContext->priv().mustRenderClip(reducedClip.maskGenID(), reducedClip.scissor(), - reducedClip.numAnalyticFPs())) { + if (renderTargetContext->priv().mustRenderClip(reducedClip.maskGenID(), + reducedClip.scissor())) { reducedClip.drawStencilClipMask(context, renderTargetContext); - renderTargetContext->priv().setLastClip(reducedClip.maskGenID(), reducedClip.scissor(), - reducedClip.numAnalyticFPs()); + renderTargetContext->priv().setLastClip(reducedClip.maskGenID(), reducedClip.scissor()); } - // GrAppliedClip doesn't need to figure numAnalyticFPs into its key (used by operator==) because - // it verifies the FPs are also equal. out->hardClip().addStencilClip(reducedClip.maskGenID()); return true; } @@ -277,16 +365,14 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar //////////////////////////////////////////////////////////////////////////////// // Create a 8-bit clip mask in alpha -static void create_clip_mask_key(uint32_t clipGenID, const SkIRect& bounds, int numAnalyticFPs, - GrUniqueKey* key) { +static void create_clip_mask_key(uint32_t clipGenID, const SkIRect& bounds, GrUniqueKey* key) { static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey::Builder builder(key, kDomain, 4, GrClipStackClip::kMaskTestTag); + GrUniqueKey::Builder builder(key, kDomain, 3, GrClipStackClip::kMaskTestTag); builder[0] = clipGenID; // SkToS16 because image filters outset layers to a size indicated by the filter, which can // sometimes result in negative coordinates from device space. builder[1] = SkToS16(bounds.fLeft) | (SkToS16(bounds.fRight) << 16); builder[2] = SkToS16(bounds.fTop) | (SkToS16(bounds.fBottom) << 16); - builder[3] = numAnalyticFPs; } static void add_invalidate_on_pop_message(const SkClipStack& stack, uint32_t clipGenID, @@ -307,8 +393,7 @@ sk_sp<GrTextureProxy> GrClipStackClip::createAlphaClipMask(GrContext* context, const GrReducedClip& reducedClip) const { GrResourceProvider* resourceProvider = context->resourceProvider(); GrUniqueKey key; - create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(), - reducedClip.numAnalyticFPs(), &key); + create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(), &key); sk_sp<GrTextureProxy> proxy(resourceProvider->findOrCreateProxyByUniqueKey( key, kBottomLeft_GrSurfaceOrigin)); @@ -420,8 +505,7 @@ sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask( GrContext* context, const GrReducedClip& reducedClip, GrRenderTargetContext* renderTargetContext) const { GrUniqueKey key; - create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(), - reducedClip.numAnalyticFPs(), &key); + create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(), &key); sk_sp<GrTextureProxy> proxy(context->resourceProvider()->findOrCreateProxyByUniqueKey( key, kTopLeft_GrSurfaceOrigin)); |