| Index: src/gpu/GrClipStackClip.cpp
|
| diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipStackClip.cpp
|
| similarity index 91%
|
| rename from src/gpu/GrClipMaskManager.cpp
|
| rename to src/gpu/GrClipStackClip.cpp
|
| index c591bf11826babd6fdfe9861994a1a8bc8da9e7b..84519f1a5eaa21c7d9ce8619ef4250dffdfe5737 100644
|
| --- a/src/gpu/GrClipMaskManager.cpp
|
| +++ b/src/gpu/GrClipStackClip.cpp
|
| @@ -5,7 +5,7 @@
|
| * found in the LICENSE file.
|
| */
|
|
|
| -#include "GrClipMaskManager.h"
|
| +#include "GrClipStackClip.h"
|
| #include "GrCaps.h"
|
| #include "GrDrawingManager.h"
|
| #include "GrDrawContextPriv.h"
|
| @@ -27,6 +27,29 @@
|
|
|
| typedef SkClipStack::Element Element;
|
|
|
| +bool GrClipStackClip::quickContains(const SkRect& rect) const {
|
| + if (!fStack) {
|
| + return true;
|
| + }
|
| + return fStack->quickContains(rect.makeOffset(SkIntToScalar(fOrigin.x()),
|
| + SkIntToScalar(fOrigin.y())));
|
| +}
|
| +
|
| +void GrClipStackClip::getConservativeBounds(int width, int height, SkIRect* devResult,
|
| + bool* isIntersectionOfRects) const {
|
| + if (!fStack) {
|
| + devResult->setXYWH(0, 0, width, height);
|
| + if (isIntersectionOfRects) {
|
| + *isIntersectionOfRects = true;
|
| + }
|
| + return;
|
| + }
|
| + SkRect devBounds;
|
| + fStack->getConservativeBounds(-fOrigin.x(), -fOrigin.y(), width, height, &devBounds,
|
| + isIntersectionOfRects);
|
| + devBounds.roundOut(devResult);
|
| +}
|
| +
|
| static const int kMaxAnalyticElements = 4;
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| @@ -54,7 +77,7 @@ static sk_sp<GrFragmentProcessor> create_fp_for_mask(GrTexture* result,
|
| // 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 GrClipMaskManager::PathNeedsSWRenderer(GrContext* context,
|
| +bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context,
|
| bool hasUserStencilSettings,
|
| const GrDrawContext* drawContext,
|
| const SkMatrix& viewMatrix,
|
| @@ -114,11 +137,11 @@ bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context,
|
| * 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 GrClipMaskManager::UseSWOnlyPath(GrContext* context,
|
| - const GrPipelineBuilder& pipelineBuilder,
|
| - const GrDrawContext* drawContext,
|
| - const SkVector& clipToMaskOffset,
|
| - const GrReducedClip::ElementList& elements) {
|
| +bool GrClipStackClip::UseSWOnlyPath(GrContext* context,
|
| + const GrPipelineBuilder& pipelineBuilder,
|
| + const GrDrawContext* drawContext,
|
| + const SkVector& clipToMaskOffset,
|
| + const GrReducedClip::ElementList& elements) {
|
| // 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.
|
| @@ -222,157 +245,6 @@ static bool get_analytic_clip_processor(const GrReducedClip::ElementList& elemen
|
| return true;
|
| }
|
|
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// sort out what kind of clip mask needs to be created: alpha, stencil,
|
| -// scissor, or entirely software
|
| -bool GrClipMaskManager::SetupClipping(GrContext* context,
|
| - const GrPipelineBuilder& pipelineBuilder,
|
| - GrDrawContext* drawContext,
|
| - const GrClipStackClip& clip,
|
| - const SkRect* origDevBounds,
|
| - GrAppliedClip* out) {
|
| - if (!clip.clipStack() || clip.clipStack()->isWideOpen()) {
|
| - return true;
|
| - }
|
| -
|
| - GrReducedClip::ElementList elements;
|
| - int32_t genID = 0;
|
| - GrReducedClip::InitialState initialState = GrReducedClip::kAllIn_InitialState;
|
| - SkIRect clipSpaceIBounds;
|
| - bool requiresAA = false;
|
| -
|
| - SkIRect clipSpaceReduceQueryBounds;
|
| - SkRect devBounds;
|
| - if (origDevBounds) {
|
| - if (!devBounds.intersect(SkRect::MakeIWH(drawContext->width(), drawContext->height()),
|
| - *origDevBounds)) {
|
| - return false;
|
| - }
|
| - devBounds.roundOut(&clipSpaceReduceQueryBounds);
|
| - clipSpaceReduceQueryBounds.offset(clip.origin());
|
| - } else {
|
| - devBounds = SkRect::MakeIWH(drawContext->width(), drawContext->height());
|
| - clipSpaceReduceQueryBounds.setXYWH(0, 0, drawContext->width(), drawContext->height());
|
| - clipSpaceReduceQueryBounds.offset(clip.origin());
|
| - }
|
| - GrReducedClip::ReduceClipStack(*clip.clipStack(),
|
| - clipSpaceReduceQueryBounds,
|
| - &elements,
|
| - &genID,
|
| - &initialState,
|
| - &clipSpaceIBounds,
|
| - &requiresAA);
|
| - if (elements.isEmpty()) {
|
| - if (GrReducedClip::kAllOut_InitialState == initialState) {
|
| - return false;
|
| - } else {
|
| - SkIRect scissorSpaceIBounds(clipSpaceIBounds);
|
| - scissorSpaceIBounds.offset(-clip.origin());
|
| - if (!SkRect::Make(scissorSpaceIBounds).contains(devBounds)) {
|
| - out->makeScissored(scissorSpaceIBounds);
|
| - }
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - // 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 (elements.count() <= kMaxAnalyticElements) {
|
| - SkVector clipToRTOffset = { SkIntToScalar(-clip.origin().fX),
|
| - SkIntToScalar(-clip.origin().fY) };
|
| - // When there are multiple samples we want to do per-sample clipping, not compute a
|
| - // fractional pixel coverage.
|
| - bool disallowAnalyticAA = drawContext->isStencilBufferMultisampled();
|
| - if (disallowAnalyticAA && !drawContext->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 = pipelineBuilder.isHWAntialias() ||
|
| - pipelineBuilder.hasUserStencilSettings();
|
| - }
|
| - sk_sp<GrFragmentProcessor> clipFP;
|
| - if (requiresAA &&
|
| - get_analytic_clip_processor(elements, disallowAnalyticAA, clipToRTOffset, devBounds,
|
| - &clipFP)) {
|
| - SkIRect scissorSpaceIBounds(clipSpaceIBounds);
|
| - scissorSpaceIBounds.offset(-clip.origin());
|
| - if (!SkRect::Make(scissorSpaceIBounds).contains(devBounds)) {
|
| - out->makeScissoredFPBased(std::move(clipFP), scissorSpaceIBounds);
|
| - return true;
|
| - }
|
| - out->makeFPBased(std::move(clipFP), SkRect::Make(scissorSpaceIBounds));
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - // If the stencil buffer is multisampled we can use it to do everything.
|
| - if (!drawContext->isStencilBufferMultisampled() && requiresAA) {
|
| - sk_sp<GrTexture> result;
|
| -
|
| - // The top-left of the mask corresponds to the top-left corner of the bounds.
|
| - SkVector clipToMaskOffset = {
|
| - SkIntToScalar(-clipSpaceIBounds.fLeft),
|
| - SkIntToScalar(-clipSpaceIBounds.fTop)
|
| - };
|
| -
|
| - if (UseSWOnlyPath(context, pipelineBuilder, drawContext,
|
| - clipToMaskOffset, elements)) {
|
| - // The clip geometry is complex enough that it will be more efficient to create it
|
| - // entirely in software
|
| - result = CreateSoftwareClipMask(context->textureProvider(),
|
| - genID,
|
| - initialState,
|
| - elements,
|
| - clipToMaskOffset,
|
| - clipSpaceIBounds);
|
| - } else {
|
| - result = CreateAlphaClipMask(context,
|
| - genID,
|
| - initialState,
|
| - elements,
|
| - clipToMaskOffset,
|
| - clipSpaceIBounds);
|
| - // If createAlphaClipMask fails it means UseSWOnlyPath has a bug
|
| - SkASSERT(result);
|
| - }
|
| -
|
| - if (result) {
|
| - // The mask's top left coord should be pinned to the rounded-out top left corner of
|
| - // clipSpace bounds. We determine the mask's position WRT to the render target here.
|
| - SkIRect rtSpaceMaskBounds = clipSpaceIBounds;
|
| - rtSpaceMaskBounds.offset(-clip.origin());
|
| - out->makeFPBased(create_fp_for_mask(result.get(), rtSpaceMaskBounds),
|
| - SkRect::Make(rtSpaceMaskBounds));
|
| - return true;
|
| - }
|
| - // if alpha clip mask creation fails fall through to the non-AA code paths
|
| - }
|
| -
|
| - // use the stencil clip if we can't represent the clip as a rectangle.
|
| - SkIPoint clipSpaceToStencilSpaceOffset = -clip.origin();
|
| - CreateStencilClipMask(context,
|
| - drawContext,
|
| - genID,
|
| - initialState,
|
| - elements,
|
| - clipSpaceIBounds,
|
| - clipSpaceToStencilSpaceOffset);
|
| -
|
| - // This must occur after createStencilClipMask. That function may change the scissor. Also, it
|
| - // only guarantees that the stencil mask is correct within the bounds it was passed, so we must
|
| - // use both stencil and scissor test to the bounds for the final draw.
|
| - SkIRect scissorSpaceIBounds(clipSpaceIBounds);
|
| - scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset);
|
| - out->makeScissoredStencil(scissorSpaceIBounds);
|
| - return true;
|
| -}
|
| -
|
| static bool stencil_element(GrDrawContext* dc,
|
| const GrFixedClip& clip,
|
| const GrUserStencilSettings* ss,
|
| @@ -447,7 +319,7 @@ static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
|
| builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16);
|
| }
|
|
|
| -sk_sp<GrTexture> GrClipMaskManager::CreateAlphaClipMask(GrContext* context,
|
| +sk_sp<GrTexture> CreateAlphaClipMask(GrContext* context,
|
| int32_t elementsGenID,
|
| GrReducedClip::InitialState initialState,
|
| const GrReducedClip::ElementList& elements,
|
| @@ -552,13 +424,13 @@ sk_sp<GrTexture> GrClipMaskManager::CreateAlphaClipMask(GrContext* context,
|
| ////////////////////////////////////////////////////////////////////////////////
|
| // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device
|
| // (as opposed to canvas) coordinates
|
| -bool GrClipMaskManager::CreateStencilClipMask(GrContext* context,
|
| - GrDrawContext* drawContext,
|
| - int32_t elementsGenID,
|
| - GrReducedClip::InitialState initialState,
|
| - const GrReducedClip::ElementList& elements,
|
| - const SkIRect& clipSpaceIBounds,
|
| - const SkIPoint& clipSpaceToStencilOffset) {
|
| +bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
|
| + GrDrawContext* drawContext,
|
| + int32_t elementsGenID,
|
| + GrReducedClip::InitialState initialState,
|
| + const GrReducedClip::ElementList& elements,
|
| + const SkIRect& clipSpaceIBounds,
|
| + const SkIPoint& clipSpaceToStencilOffset) {
|
| SkASSERT(drawContext);
|
|
|
| GrStencilAttachment* stencilAttachment = context->resourceProvider()->attachStencilAttachment(
|
| @@ -735,7 +607,7 @@ bool GrClipMaskManager::CreateStencilClipMask(GrContext* context,
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| -sk_sp<GrTexture> GrClipMaskManager::CreateSoftwareClipMask(
|
| +sk_sp<GrTexture> CreateSoftwareClipMask(
|
| GrTextureProvider* texProvider,
|
| int32_t elementsGenID,
|
| GrReducedClip::InitialState initialState,
|
| @@ -812,3 +684,148 @@ sk_sp<GrTexture> GrClipMaskManager::CreateSoftwareClipMask(
|
|
|
| return result;
|
| }
|
| +
|
| +bool GrClipStackClip::apply(GrContext* context,
|
| + const GrPipelineBuilder& pipelineBuilder, GrDrawContext* drawContext,
|
| + const SkRect* origDevBounds, GrAppliedClip* out) const {
|
| + ////////////////////////////////////////////////////////////////////////////////
|
| + // sort out what kind of clip mask needs to be created: alpha, stencil,
|
| + // scissor, or entirely software
|
| +
|
| + GrReducedClip::ElementList elements;
|
| + int32_t genID = 0;
|
| + GrReducedClip::InitialState initialState = GrReducedClip::kAllIn_InitialState;
|
| + SkIRect clipSpaceIBounds;
|
| + bool requiresAA = false;
|
| +
|
| + SkIRect clipSpaceReduceQueryBounds;
|
| + SkRect devBounds;
|
| + if (origDevBounds) {
|
| + if (!devBounds.intersect(SkRect::MakeIWH(drawContext->width(), drawContext->height()),
|
| + *origDevBounds)) {
|
| + return false;
|
| + }
|
| + devBounds.roundOut(&clipSpaceReduceQueryBounds);
|
| + clipSpaceReduceQueryBounds.offset(this->origin());
|
| + } else {
|
| + devBounds = SkRect::MakeIWH(drawContext->width(), drawContext->height());
|
| + clipSpaceReduceQueryBounds.setXYWH(0, 0, drawContext->width(), drawContext->height());
|
| + clipSpaceReduceQueryBounds.offset(this->origin());
|
| + }
|
| + GrReducedClip::ReduceClipStack(*this->clipStack(),
|
| + clipSpaceReduceQueryBounds,
|
| + &elements,
|
| + &genID,
|
| + &initialState,
|
| + &clipSpaceIBounds,
|
| + &requiresAA);
|
| + if (elements.isEmpty()) {
|
| + if (GrReducedClip::kAllOut_InitialState == initialState) {
|
| + return false;
|
| + } else {
|
| + SkIRect scissorSpaceIBounds(clipSpaceIBounds);
|
| + scissorSpaceIBounds.offset(-this->origin());
|
| + if (!SkRect::Make(scissorSpaceIBounds).contains(devBounds)) {
|
| + out->makeScissored(scissorSpaceIBounds);
|
| + }
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + // 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 (elements.count() <= kMaxAnalyticElements) {
|
| + SkVector clipToRTOffset = { SkIntToScalar(-this->origin().fX),
|
| + SkIntToScalar(-this->origin().fY) };
|
| + // When there are multiple samples we want to do per-sample clipping, not compute a
|
| + // fractional pixel coverage.
|
| + bool disallowAnalyticAA = drawContext->isStencilBufferMultisampled();
|
| + if (disallowAnalyticAA && !drawContext->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 = pipelineBuilder.isHWAntialias() ||
|
| + pipelineBuilder.hasUserStencilSettings();
|
| + }
|
| + sk_sp<GrFragmentProcessor> clipFP;
|
| + if (requiresAA &&
|
| + get_analytic_clip_processor(elements, disallowAnalyticAA, clipToRTOffset, devBounds,
|
| + &clipFP)) {
|
| + SkIRect scissorSpaceIBounds(clipSpaceIBounds);
|
| + scissorSpaceIBounds.offset(-this->origin());
|
| + if (!SkRect::Make(scissorSpaceIBounds).contains(devBounds)) {
|
| + out->makeScissoredFPBased(std::move(clipFP), scissorSpaceIBounds);
|
| + return true;
|
| + }
|
| + out->makeFPBased(std::move(clipFP), SkRect::Make(scissorSpaceIBounds));
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + // If the stencil buffer is multisampled we can use it to do everything.
|
| + if (!drawContext->isStencilBufferMultisampled() && requiresAA) {
|
| + sk_sp<GrTexture> result;
|
| +
|
| + // The top-left of the mask corresponds to the top-left corner of the bounds.
|
| + SkVector clipToMaskOffset = {
|
| + SkIntToScalar(-clipSpaceIBounds.fLeft),
|
| + SkIntToScalar(-clipSpaceIBounds.fTop)
|
| + };
|
| +
|
| + if (UseSWOnlyPath(context, pipelineBuilder, drawContext,
|
| + clipToMaskOffset, elements)) {
|
| + // The clip geometry is complex enough that it will be more efficient to create it
|
| + // entirely in software
|
| + result = CreateSoftwareClipMask(context->textureProvider(),
|
| + genID,
|
| + initialState,
|
| + elements,
|
| + clipToMaskOffset,
|
| + clipSpaceIBounds);
|
| + } else {
|
| + result = CreateAlphaClipMask(context,
|
| + genID,
|
| + initialState,
|
| + elements,
|
| + clipToMaskOffset,
|
| + clipSpaceIBounds);
|
| + // If createAlphaClipMask fails it means UseSWOnlyPath has a bug
|
| + SkASSERT(result);
|
| + }
|
| +
|
| + if (result) {
|
| + // The mask's top left coord should be pinned to the rounded-out top left corner of
|
| + // clipSpace bounds. We determine the mask's position WRT to the render target here.
|
| + SkIRect rtSpaceMaskBounds = clipSpaceIBounds;
|
| + rtSpaceMaskBounds.offset(-this->origin());
|
| + out->makeFPBased(create_fp_for_mask(result.get(), rtSpaceMaskBounds),
|
| + SkRect::Make(rtSpaceMaskBounds));
|
| + return true;
|
| + }
|
| + // if alpha clip mask creation fails fall through to the non-AA code paths
|
| + }
|
| +
|
| + // use the stencil clip if we can't represent the clip as a rectangle.
|
| + SkIPoint clipSpaceToStencilSpaceOffset = -this->origin();
|
| + CreateStencilClipMask(context,
|
| + drawContext,
|
| + genID,
|
| + initialState,
|
| + elements,
|
| + clipSpaceIBounds,
|
| + clipSpaceToStencilSpaceOffset);
|
| +
|
| + // This must occur after createStencilClipMask. That function may change the scissor. Also, it
|
| + // only guarantees that the stencil mask is correct within the bounds it was passed, so we must
|
| + // use both stencil and scissor test to the bounds for the final draw.
|
| + SkIRect scissorSpaceIBounds(clipSpaceIBounds);
|
| + scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset);
|
| + out->makeScissoredStencil(scissorSpaceIBounds);
|
| + return true;
|
| +}
|
|
|