aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrClipStackClip.cpp
diff options
context:
space:
mode:
authorGravatar Chris Dalton <csmartdalton@google.com>2017-10-31 17:50:41 -0600
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-11-01 16:25:00 +0000
commit1af37b758bc3c285effb7b96bd27faf4481d90d0 (patch)
tree0263f28275e9c39c6cf2d613846d9d6623fd1cd8 /src/gpu/GrClipStackClip.cpp
parentd4685403e25efe85eca108f7b9db5b7cfb8ffcd8 (diff)
Fold analytic clip FPs into GrReducedClip
Perf result on Pixel phone (sorted by impact): GEOMEAN 6.73 -> 6.49 ms [96% ] top25desk_pinterest.skp 0.45 -> 0.49 ms [107%] desk_pokemonwiki.skp 14.6 -> 15.9 ms [106%] keymobi_pinterest.skp 0.47 -> 0.49 ms [104%] ... keymobi_androidpolice_com_2012_.skp 3.69 -> 3.09 ms [83% ] keymobi_shop_mobileweb_ebay_com.skp 2.90 -> 2.29 ms [78% ] keymobi_boingboing_net.skp 2.95 -> 2.29 ms [76% ] desk_jsfiddlebigcar.skp 1.79 -> 1.29 ms [71% ] keymobi_m_youtube_com_watch_v_9.skp 12.9 -> 9.09 ms [70% ] keymobi_blogger.skp 3.80 -> 2.69 ms [70% ] keymobi_sfgate_com_.skp 8.16 -> 5.69 ms [69% ] 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: I070148258d04284def535134a72a4584c5d6f7c7 Reviewed-on: https://skia-review.googlesource.com/65460 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Chris Dalton <csmartdalton@google.com>
Diffstat (limited to 'src/gpu/GrClipStackClip.cpp')
-rw-r--r--src/gpu/GrClipStackClip.cpp159
1 files changed, 42 insertions, 117 deletions
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index aa2b9fdd29..b18cb16c44 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -30,7 +30,15 @@ typedef SkClipStack::Element Element;
typedef GrReducedClip::InitialState InitialState;
typedef GrReducedClip::ElementList ElementList;
+// 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.
static const int kMaxAnalyticElements = 4;
+
const char GrClipStackClip::kMaskTestTag[] = "clip_mask";
bool GrClipStackClip::quickContains(const SkRect& rect) const {
@@ -176,80 +184,6 @@ 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) {
- GrPrimitiveEdgeType edgeType;
- if (iter.get()->isAA()) {
- if (abortIfAA) {
- return false;
- }
- edgeType =
- invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProcessorEdgeType;
- } else {
- edgeType =
- invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProcessorEdgeType;
- }
-
- 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
@@ -265,8 +199,19 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
return true;
}
- const GrReducedClip reducedClip(*fStack, devBounds,
- renderTargetContext->priv().maxWindowRectangles());
+ int maxAnalyticFPs = kMaxAnalyticElements;
+ 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);
if (reducedClip.hasScissor() && !GrClip::IsInsideClip(reducedClip.scissor(), devBounds)) {
out->addScissor(reducedClip.scissor(), bounds);
@@ -277,6 +222,10 @@ 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();
}
@@ -289,41 +238,9 @@ 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()) ||
- avoidStencilBuffers) {
+ 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
@@ -343,7 +260,8 @@ 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;
}
}
@@ -353,11 +271,14 @@ 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())) {
+ if (renderTargetContext->priv().mustRenderClip(reducedClip.maskGenID(), reducedClip.scissor(),
+ reducedClip.numAnalyticFPs())) {
reducedClip.drawStencilClipMask(context, renderTargetContext);
- renderTargetContext->priv().setLastClip(reducedClip.maskGenID(), reducedClip.scissor());
+ renderTargetContext->priv().setLastClip(reducedClip.maskGenID(), reducedClip.scissor(),
+ reducedClip.numAnalyticFPs());
}
+ // GrAppliedClip doesn't need to figure numAnalyticFPs into its key (used by operator==) because
+ // it verifies the FPs are also equal.
out->addStencilClip(reducedClip.maskGenID());
return true;
}
@@ -365,14 +286,16 @@ 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, GrUniqueKey* key) {
+static void create_clip_mask_key(uint32_t clipGenID, const SkIRect& bounds, int numAnalyticFPs,
+ GrUniqueKey* key) {
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
- GrUniqueKey::Builder builder(key, kDomain, 3, GrClipStackClip::kMaskTestTag);
+ GrUniqueKey::Builder builder(key, kDomain, 4, 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,
@@ -393,7 +316,8 @@ 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(), &key);
+ create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(),
+ reducedClip.numAnalyticFPs(), &key);
sk_sp<GrTextureProxy> proxy(resourceProvider->findOrCreateProxyByUniqueKey(
key, kBottomLeft_GrSurfaceOrigin));
@@ -505,7 +429,8 @@ sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask(
GrContext* context, const GrReducedClip& reducedClip,
GrRenderTargetContext* renderTargetContext) const {
GrUniqueKey key;
- create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(), &key);
+ create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(),
+ reducedClip.numAnalyticFPs(), &key);
sk_sp<GrTextureProxy> proxy(context->resourceProvider()->findOrCreateProxyByUniqueKey(
key, kTopLeft_GrSurfaceOrigin));