aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar Chris Dalton <csmartdalton@google.com>2018-03-27 15:11:59 -0600
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-28 15:01:04 +0000
commita466228a616b1b02ede2d4389fefcfc839a54a25 (patch)
treee5a48f35dc33b0c4d0aeef4327a5960c3b5992e9 /src/gpu
parent41964ed46e241c95cd6c91ac99271c2a232f1b65 (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.cpp168
-rw-r--r--src/gpu/GrClipStackClip.h21
-rw-r--r--src/gpu/GrReducedClip.cpp128
-rw-r--r--src/gpu/GrReducedClip.h1
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(); }