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; |
+} |