aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrClipStackClip.cpp
diff options
context:
space:
mode:
authorGravatar Brian Osman <brianosman@google.com>2017-11-16 13:56:47 +0000
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-11-16 13:57:01 +0000
commit554c1f0508a95b5411036a95d1bb62c0d5fdeae8 (patch)
tree9a4308484386496d1ab2a30cc53893f0234b45c1 /src/gpu/GrClipStackClip.cpp
parent63d26849701fe8cc37e181d4e0f6978063f7d269 (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.cpp152
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));