aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar csmartdalton <csmartdalton@google.com>2016-08-15 11:17:19 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-15 11:17:19 -0700
commitd211e7875d9d564f075f664d9f402e1fed6dd90c (patch)
treee6ea3720badcff1e5b4eb1af613cd5928d189d2d
parent3fe0327585f32ea2b9334965d8c90d9d699c584e (diff)
Convert GrAppliedClip interface to builder style
GrAppliedClip was about at its limit for how many "make" functions it could have. Window rectangles would push it over the edge. This change makes it so GrDrawTarget supplies the original draw bounds to the constructor, and then GrClip adds the various required clipping techniques. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2246113002 Review-Url: https://codereview.chromium.org/2246113002
-rw-r--r--include/gpu/GrClip.h125
-rw-r--r--include/gpu/GrTypesPriv.h7
-rw-r--r--src/gpu/GrClip.cpp30
-rw-r--r--src/gpu/GrClipStackClip.cpp90
-rw-r--r--src/gpu/GrClipStackClip.h6
-rw-r--r--src/gpu/GrDrawTarget.cpp60
-rw-r--r--src/gpu/GrReducedClip.cpp13
-rw-r--r--src/gpu/GrReducedClip.h24
-rw-r--r--tests/ClipStackTest.cpp32
9 files changed, 139 insertions, 248 deletions
diff --git a/include/gpu/GrClip.h b/include/gpu/GrClip.h
index 5f0a881653..9db76f0942 100644
--- a/include/gpu/GrClip.h
+++ b/include/gpu/GrClip.h
@@ -19,78 +19,43 @@ class GrDrawContext;
*/
class GrAppliedClip : public SkNoncopyable {
public:
- GrAppliedClip() : fHasStencilClip(false), fDeviceBounds(SkRect::MakeLargest()) {}
- GrFragmentProcessor* getClipCoverageFragmentProcessor() const {
- return fClipCoverageFP.get();
+ GrAppliedClip(const SkRect& drawBounds)
+ : fHasStencilClip(false)
+ , fClippedDrawBounds(drawBounds) {
}
+
const GrScissorState& scissorState() const { return fScissorState; }
+ GrFragmentProcessor* clipCoverageFragmentProcessor() const { return fClipCoverageFP.get(); }
bool hasStencilClip() const { return fHasStencilClip; }
- void makeStencil(bool hasStencil, const SkRect& deviceBounds) {
- fClipCoverageFP = nullptr;
- fScissorState.setDisabled();
- fHasStencilClip = hasStencil;
- fDeviceBounds = deviceBounds;
- }
-
/**
- * The device bounds of the clip defaults to the scissor rect, but a tighter bounds (based
- * on the known effect of the stencil values) can be provided.
+ * Intersects the applied clip with the provided rect. Returns false if the draw became empty.
*/
- void makeScissoredStencil(const SkIRect& scissor, const SkRect* deviceBounds = nullptr) {
- fClipCoverageFP = nullptr;
- fScissorState.set(scissor);
- fHasStencilClip = true;
- if (deviceBounds) {
- fDeviceBounds = *deviceBounds;
- SkASSERT(scissor.contains(*deviceBounds));
- } else {
- fDeviceBounds = SkRect::Make(scissor);
- }
+ bool addScissor(const SkIRect& irect) {
+ return fScissorState.intersect(irect) && fClippedDrawBounds.intersect(SkRect::Make(irect));
}
- void makeFPBased(sk_sp<GrFragmentProcessor> fp, const SkRect& deviceBounds) {
+ void addCoverageFP(sk_sp<GrFragmentProcessor> fp) {
+ SkASSERT(!fClipCoverageFP);
fClipCoverageFP = fp;
- fScissorState.setDisabled();
- fHasStencilClip = false;
- fDeviceBounds = deviceBounds;
}
- void makeScissored(SkIRect& scissor) {
- fClipCoverageFP.reset();
- fScissorState.set(scissor);
- fHasStencilClip = false;
- fDeviceBounds = SkRect::Make(scissor);
- }
-
- /**
- * The device bounds of the clip defaults to the scissor rect, but a tighter bounds (based
- * on the known effect of the fragment processor) can be provided.
- */
- void makeScissoredFPBased(sk_sp<GrFragmentProcessor> fp, const SkIRect& scissor,
- const SkRect* deviceBounds = nullptr) {
- fClipCoverageFP = fp;
- fScissorState.set(scissor);
- fHasStencilClip = false;
- if (deviceBounds) {
- fDeviceBounds = *deviceBounds;
- SkASSERT(scissor.contains(*deviceBounds));
- } else {
- fDeviceBounds = SkRect::Make(scissor);
- }
+ void addStencilClip() {
+ SkASSERT(!fHasStencilClip);
+ fHasStencilClip = true;
}
/**
- * Returns the device bounds of the applied clip. Ideally this considers the combined effect of
- * all clipping techniques in play (scissor, stencil, and/or coverage fp).
+ * Returns the device bounds of the draw after clip has been applied. TODO: Ideally this would
+ * consider the combined effect of all clipping techniques in play (scissor, stencil, fp, etc.).
*/
- const SkRect& deviceBounds() const { return fDeviceBounds; }
+ const SkRect& clippedDrawBounds() const { return fClippedDrawBounds; }
private:
- sk_sp<GrFragmentProcessor> fClipCoverageFP;
GrScissorState fScissorState;
+ sk_sp<GrFragmentProcessor> fClipCoverageFP;
bool fHasStencilClip;
- SkRect fDeviceBounds;
+ SkRect fClippedDrawBounds;
typedef SkNoncopyable INHERITED;
};
@@ -103,11 +68,7 @@ public:
virtual bool quickContains(const SkRect&) const = 0;
virtual void getConservativeBounds(int width, int height, SkIRect* devResult,
bool* isIntersectionOfRects = nullptr) const = 0;
- virtual bool apply(GrContext*,
- GrDrawContext*,
- const SkRect* devBounds,
- bool useHWAA,
- bool hasUserStencilSettings,
+ virtual bool apply(GrContext*, GrDrawContext*, bool useHWAA, bool hasUserStencilSettings,
GrAppliedClip* out) const = 0;
virtual ~GrClip() {}
@@ -192,12 +153,7 @@ private:
bool quickContains(const SkRect&) const final { return true; }
void getConservativeBounds(int width, int height, SkIRect* devResult,
bool* isIntersectionOfRects) const final;
- bool apply(GrContext*,
- GrDrawContext*,
- const SkRect* /* devBounds */,
- bool /* useHWAA */,
- bool /* hasUserStencilSettings */,
- GrAppliedClip* /* out */) const final { return true; }
+ bool apply(GrContext*, GrDrawContext*, bool, bool, GrAppliedClip*) const final { return true; }
};
/**
@@ -206,66 +162,33 @@ private:
*/
class GrFixedClip final : public GrClip {
public:
- GrFixedClip() : fDeviceBounds(SkRect::MakeLargest()), fHasStencilClip(false) {}
+ GrFixedClip() : fHasStencilClip(false) {}
GrFixedClip(const SkIRect& scissorRect)
: fScissorState(scissorRect)
- , fDeviceBounds(SkRect::Make(scissorRect))
, fHasStencilClip(false) {}
void reset() {
fScissorState.setDisabled();
- fDeviceBounds.setLargest();
fHasStencilClip = false;
}
void reset(const SkIRect& scissorRect) {
fScissorState.set(scissorRect);
- fDeviceBounds = SkRect::Make(scissorRect);
fHasStencilClip = false;
}
- /**
- * Enables stenciling. The stencil bounds is the device space bounds where the stencil test
- * may pass.
- */
- void enableStencilClip(const SkRect& stencilBounds) {
- fHasStencilClip = true;
- fDeviceBounds = stencilBounds;
- if (fScissorState.enabled()) {
- const SkIRect& s = fScissorState.rect();
- fDeviceBounds.fLeft = SkTMax(fDeviceBounds.fLeft, SkIntToScalar(s.fLeft));
- fDeviceBounds.fTop = SkTMax(fDeviceBounds.fTop, SkIntToScalar(s.fTop));
- fDeviceBounds.fRight = SkTMin(fDeviceBounds.fRight, SkIntToScalar(s.fRight));
- fDeviceBounds.fBottom = SkTMin(fDeviceBounds.fBottom, SkIntToScalar(s.fBottom));
- }
- }
-
- void disableStencilClip() {
- fHasStencilClip = false;
- if (fScissorState.enabled()) {
- fDeviceBounds = SkRect::Make(fScissorState.rect());
- } else {
- fDeviceBounds.setLargest();
- }
- }
-
- const GrScissorState& scissorState() const { return fScissorState; }
- bool hasStencilClip() const { return fHasStencilClip; }
+ void enableStencilClip() { fHasStencilClip = true; }
+ void disableStencilClip() { fHasStencilClip = false; }
bool quickContains(const SkRect&) const final;
void getConservativeBounds(int width, int height, SkIRect* devResult,
bool* isIntersectionOfRects) const final;
private:
- bool apply(GrContext*,
- GrDrawContext*,
- const SkRect* devBounds,
- bool useHWAA,
- bool hasUserStencilSettings,
+ bool apply(GrContext*, GrDrawContext*, bool useHWAA, bool hasUserStencilSettings,
GrAppliedClip* out) const final;
GrScissorState fScissorState;
- SkRect fDeviceBounds;
bool fHasStencilClip;
};
diff --git a/include/gpu/GrTypesPriv.h b/include/gpu/GrTypesPriv.h
index abbfdfca06..8c42d648d0 100644
--- a/include/gpu/GrTypesPriv.h
+++ b/include/gpu/GrTypesPriv.h
@@ -425,6 +425,13 @@ struct GrScissorState {
GrScissorState(const SkIRect& rect) : fEnabled(true), fRect(rect) {}
void setDisabled() { fEnabled = false; }
void set(const SkIRect& rect) { fRect = rect; fEnabled = true; }
+ bool SK_WARN_UNUSED_RESULT intersect(const SkIRect& rect) {
+ if (!fEnabled) {
+ this->set(rect);
+ return true;
+ }
+ return fRect.intersect(rect);
+ }
bool operator==(const GrScissorState& other) const {
return fEnabled == other.fEnabled &&
(false == fEnabled || fRect == other.fRect);
diff --git a/src/gpu/GrClip.cpp b/src/gpu/GrClip.cpp
index 3eccd801b5..ef9c9cdfa6 100644
--- a/src/gpu/GrClip.cpp
+++ b/src/gpu/GrClip.cpp
@@ -21,10 +21,7 @@ bool GrFixedClip::quickContains(const SkRect& rect) const {
if (fHasStencilClip) {
return false;
}
- if (!fScissorState.enabled()) {
- return true;
- }
- return fScissorState.rect().contains(rect);
+ return !fScissorState.enabled() || GrClip::IsInsideClip(fScissorState.rect(), rect);
}
void GrFixedClip::getConservativeBounds(int width, int height, SkIRect* devResult,
@@ -40,32 +37,25 @@ void GrFixedClip::getConservativeBounds(int width, int height, SkIRect* devResul
}
}
-bool GrFixedClip::apply(GrContext*,
- GrDrawContext* drawContext,
- const SkRect* devBounds,
- bool isHWAntiAlias,
- bool hasUserStencilSettings,
- GrAppliedClip* out) const {
- SkASSERT(!fDeviceBounds.isLargest());
+bool GrFixedClip::apply(GrContext*, GrDrawContext* drawContext, bool isHWAntiAlias,
+ bool hasUserStencilSettings, GrAppliedClip* out) const {
if (fScissorState.enabled()) {
SkIRect tightScissor;
if (!tightScissor.intersect(fScissorState.rect(),
SkIRect::MakeWH(drawContext->width(), drawContext->height()))) {
return false;
}
- if (devBounds && IsOutsideClip(tightScissor, *devBounds)) {
+ if (IsOutsideClip(tightScissor, out->clippedDrawBounds())) {
return false;
}
- if (!devBounds || !IsInsideClip(fScissorState.rect(), *devBounds)) {
- if (fHasStencilClip) {
- out->makeScissoredStencil(tightScissor, &fDeviceBounds);
- } else {
- out->makeScissored(tightScissor);
- }
- return true;
+ if (!IsInsideClip(fScissorState.rect(), out->clippedDrawBounds())) {
+ out->addScissor(tightScissor);
}
}
- out->makeStencil(fHasStencilClip, fDeviceBounds);
+ if (fHasStencilClip) {
+ out->addStencilClip();
+ }
+
return true;
}
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index e117144eb9..6cb216ee0c 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -242,18 +242,14 @@ static bool get_analytic_clip_processor(const ElementList& elements,
////////////////////////////////////////////////////////////////////////////////
// sort out what kind of clip mask needs to be created: alpha, stencil,
// scissor, or entirely software
-bool GrClipStackClip::apply(GrContext* context,
- GrDrawContext* drawContext,
- const SkRect* origDevBounds,
- bool useHWAA,
- bool hasUserStencilSettings,
- GrAppliedClip* out) const {
+bool GrClipStackClip::apply(GrContext* context, GrDrawContext* drawContext, bool useHWAA,
+ bool hasUserStencilSettings, GrAppliedClip* out) const {
if (!fStack || fStack->isWideOpen()) {
return true;
}
SkRect devBounds = SkRect::MakeIWH(drawContext->width(), drawContext->height());
- if (origDevBounds && !devBounds.intersect(*origDevBounds)) {
+ if (!devBounds.intersect(out->clippedDrawBounds())) {
return false;
}
@@ -263,18 +259,19 @@ bool GrClipStackClip::apply(GrContext* context,
SkRect clipSpaceDevBounds = devBounds.makeOffset(clipX, clipY);
const GrReducedClip reducedClip(*fStack, clipSpaceDevBounds);
+ if (reducedClip.hasIBounds() &&
+ !GrClip::IsInsideClip(reducedClip.ibounds(), clipSpaceDevBounds)) {
+ SkIRect scissorSpaceIBounds(reducedClip.ibounds());
+ scissorSpaceIBounds.offset(-fOrigin);
+ out->addScissor(scissorSpaceIBounds);
+ }
+
if (reducedClip.elements().isEmpty()) {
- if (GrReducedClip::InitialState::kAllOut == reducedClip.initialState()) {
- return false;
- }
- if (!GrClip::IsInsideClip(reducedClip.iBounds(), clipSpaceDevBounds)) {
- SkIRect scissorSpaceIBounds(reducedClip.iBounds());
- scissorSpaceIBounds.offset(-fOrigin);
- out->makeScissored(scissorSpaceIBounds);
- }
- return true;
+ return InitialState::kAllIn == reducedClip.initialState();
}
+ SkASSERT(reducedClip.hasIBounds());
+
// An element count of 4 was chosen because of the common pattern in Blink of:
// isect RR
// diff RR
@@ -297,13 +294,7 @@ bool GrClipStackClip::apply(GrContext* context,
if (reducedClip.requiresAA() &&
get_analytic_clip_processor(reducedClip.elements(), disallowAnalyticAA,
{-clipX, -clipY}, devBounds, &clipFP)) {
- SkIRect scissorSpaceIBounds(reducedClip.iBounds());
- scissorSpaceIBounds.offset(-fOrigin);
- if (GrClip::IsInsideClip(scissorSpaceIBounds, devBounds)) {
- out->makeFPBased(std::move(clipFP), SkRect::Make(scissorSpaceIBounds));
- } else {
- out->makeScissoredFPBased(std::move(clipFP), scissorSpaceIBounds);
- }
+ out->addCoverageFP(std::move(clipFP));
return true;
}
}
@@ -333,10 +324,9 @@ bool GrClipStackClip::apply(GrContext* context,
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 = reducedClip.iBounds();
+ SkIRect rtSpaceMaskBounds = reducedClip.ibounds();
rtSpaceMaskBounds.offset(-fOrigin);
- out->makeFPBased(create_fp_for_mask(result.get(), rtSpaceMaskBounds),
- SkRect::Make(rtSpaceMaskBounds));
+ out->addCoverageFP(create_fp_for_mask(result.get(), rtSpaceMaskBounds));
return true;
}
// if alpha clip mask creation fails fall through to the non-AA code paths
@@ -345,17 +335,7 @@ bool GrClipStackClip::apply(GrContext* context,
// use the stencil clip if we can't represent the clip as a rectangle.
SkIPoint clipSpaceToStencilSpaceOffset = -fOrigin;
CreateStencilClipMask(context, drawContext, reducedClip, 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.
- if (GrClip::IsInsideClip(reducedClip.iBounds(), clipSpaceDevBounds)) {
- out->makeStencil(true, devBounds);
- } else {
- SkIRect scissorSpaceIBounds(reducedClip.iBounds());
- scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset);
- out->makeScissoredStencil(scissorSpaceIBounds);
- }
+ out->addStencilClip();
return true;
}
@@ -438,7 +418,7 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
const SkVector& clipToMaskOffset) {
GrResourceProvider* resourceProvider = context->resourceProvider();
GrUniqueKey key;
- GetClipMaskKey(reducedClip.genID(), reducedClip.iBounds(), &key);
+ GetClipMaskKey(reducedClip.genID(), reducedClip.ibounds(), &key);
if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) {
return sk_sp<GrTexture>(texture);
}
@@ -463,9 +443,7 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
// The scratch texture that we are drawing into can be substantially larger than the mask. Only
// clear the part that we care about.
- dc->clear(&maskSpaceIBounds,
- GrReducedClip::InitialState::kAllIn == reducedClip.initialState() ? -1 : 0,
- true);
+ dc->clear(&maskSpaceIBounds, InitialState::kAllIn == reducedClip.initialState() ? -1 : 0, true);
// Set the matrix so that rendered clip elements are transformed to mask space from clip
// space.
@@ -513,7 +491,7 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideElement,
op, !invert, false,
translate,
- SkRect::Make(reducedClip.iBounds()))) {
+ SkRect::Make(reducedClip.ibounds()))) {
return nullptr;
}
} else {
@@ -548,9 +526,9 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
}
// TODO: these need to be swapped over to using a StencilAttachmentProxy
- if (stencilAttachment->mustRenderClip(reducedClip.genID(), reducedClip.iBounds(),
+ if (stencilAttachment->mustRenderClip(reducedClip.genID(), reducedClip.ibounds(),
clipSpaceToStencilOffset)) {
- stencilAttachment->setLastClip(reducedClip.genID(), reducedClip.iBounds(),
+ stencilAttachment->setLastClip(reducedClip.genID(), reducedClip.ibounds(),
clipSpaceToStencilOffset);
// Set the matrix so that rendered clip elements are transformed from clip to stencil space.
SkVector translate = {
@@ -561,11 +539,11 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
viewMatrix.setTranslate(translate);
// We set the current clip to the bounds so that our recursive draws are scissored to them.
- SkIRect stencilSpaceIBounds(reducedClip.iBounds());
+ SkIRect stencilSpaceIBounds(reducedClip.ibounds());
stencilSpaceIBounds.offset(clipSpaceToStencilOffset);
GrFixedClip clip(stencilSpaceIBounds);
- bool insideClip = GrReducedClip::InitialState::kAllIn == reducedClip.initialState();
+ bool insideClip = InitialState::kAllIn == reducedClip.initialState();
drawContext->drawContextPriv().clearStencilClip(stencilSpaceIBounds, insideClip);
// walk through each clip element and perform its set op
@@ -671,22 +649,19 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
}
}
+ // Just enable stencil clip. The passes choose whether or not they will actually use it.
+ clip.enableStencilClip();
+
// now we modify the clip bit by rendering either the clip
// element directly or a bounding rect of the entire clip.
for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) {
-
if (drawDirectToClip) {
if (Element::kRect_Type == element->getType()) {
- clip.enableStencilClip(element->getRect().makeOffset(translate.fX,
- translate.fY));
drawContext->drawContextPriv().stencilRect(clip, *pass, useHWAA, viewMatrix,
element->getRect());
} else {
GrShape shape(clipPath, GrStyle::SimpleFill());
GrPaint paint;
- SkRect bounds = clipPath.getBounds();
- bounds.offset(translate.fX, translate.fY);
- clip.enableStencilClip(bounds);
paint.setXPFactory(GrDisableColorXPFactory::Make());
paint.setAntiAlias(element->isAA());
GrPathRenderer::DrawPathArgs args;
@@ -704,11 +679,8 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
} else {
// The view matrix is setup to do clip space -> stencil space translation, so
// draw rect in clip space.
- SkRect bounds = SkRect::Make(reducedClip.iBounds());
- bounds.offset(translate.fX, translate.fY);
- clip.enableStencilClip(bounds);
drawContext->drawContextPriv().stencilRect(clip, *pass, false, viewMatrix,
- SkRect::Make(reducedClip.iBounds()));
+ SkRect::Make(reducedClip.ibounds()));
}
}
}
@@ -721,7 +693,7 @@ sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texP
const GrReducedClip& reducedClip,
const SkVector& clipToMaskOffset) {
GrUniqueKey key;
- GetClipMaskKey(reducedClip.genID(), reducedClip.iBounds(), &key);
+ GetClipMaskKey(reducedClip.genID(), reducedClip.ibounds(), &key);
if (GrTexture* texture = texProvider->findAndRefTextureByUniqueKey(key)) {
return sk_sp<GrTexture>(texture);
}
@@ -738,7 +710,7 @@ sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texP
translate.setTranslate(clipToMaskOffset);
helper.init(maskSpaceIBounds, &translate);
- helper.clear(GrReducedClip::InitialState::kAllIn == reducedClip.initialState() ? 0xFF : 0x00);
+ helper.clear(InitialState::kAllIn == reducedClip.initialState() ? 0xFF : 0x00);
for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()) {
const Element* element = iter.get();
@@ -750,7 +722,7 @@ sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texP
// but leave the pixels inside the geometry alone. For reverse difference we invert all
// the pixels before clearing the ones outside the geometry.
if (SkRegion::kReverseDifference_Op == op) {
- SkRect temp = SkRect::Make(reducedClip.iBounds());
+ SkRect temp = SkRect::Make(reducedClip.ibounds());
// invert the entire scene
helper.drawRect(temp, SkRegion::kXOR_Op, false, 0xFF);
}
diff --git a/src/gpu/GrClipStackClip.h b/src/gpu/GrClipStackClip.h
index aaa2f90e3a..98675e62ac 100644
--- a/src/gpu/GrClipStackClip.h
+++ b/src/gpu/GrClipStackClip.h
@@ -33,11 +33,7 @@ public:
bool quickContains(const SkRect&) const final;
void getConservativeBounds(int width, int height, SkIRect* devResult,
bool* isIntersectionOfRects) const final;
- bool apply(GrContext*,
- GrDrawContext*,
- const SkRect* devBounds,
- bool useHWAA,
- bool hasUserStencilSettings,
+ bool apply(GrContext*, GrDrawContext*, bool useHWAA, bool hasUserStencilSettings,
GrAppliedClip* out) const final;
private:
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index e143f90291..b4142eb40b 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -321,51 +321,38 @@ static void batch_bounds(SkRect* bounds, const GrBatch* batch) {
}
}
-static inline bool intersect(SkRect* out, const SkRect& a, const SkRect& b) {
- SkASSERT(a.fLeft <= a.fRight && a.fTop <= a.fBottom);
- SkASSERT(b.fLeft <= b.fRight && b.fTop <= b.fBottom);
- out->fLeft = SkTMax(a.fLeft, b.fLeft);
- out->fTop = SkTMax(a.fTop, b.fTop);
- out->fRight = SkTMin(a.fRight, b.fRight);
- out->fBottom = SkTMin(a.fBottom, b.fBottom);
- return (out->fLeft <= out->fRight && out->fTop <= out->fBottom);
-}
-
void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
GrDrawContext* drawContext,
const GrClip& clip,
GrDrawBatch* batch) {
// Setup clip
- GrAppliedClip appliedClip;
SkRect bounds;
batch_bounds(&bounds, batch);
- if (!clip.apply(fContext, drawContext, &bounds,
- pipelineBuilder.isHWAntialias(), pipelineBuilder.hasUserStencilSettings(),
- &appliedClip)) {
+ GrAppliedClip appliedClip(bounds);
+ if (!clip.apply(fContext, drawContext, pipelineBuilder.isHWAntialias(),
+ pipelineBuilder.hasUserStencilSettings(), &appliedClip)) {
return;
}
// TODO: this is the only remaining usage of the AutoRestoreFragmentProcessorState - remove it
GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
- if (appliedClip.getClipCoverageFragmentProcessor()) {
+ if (appliedClip.clipCoverageFragmentProcessor()) {
arfps.set(&pipelineBuilder);
- arfps.addCoverageFragmentProcessor(sk_ref_sp(appliedClip.getClipCoverageFragmentProcessor()));
+ arfps.addCoverageFragmentProcessor(sk_ref_sp(appliedClip.clipCoverageFragmentProcessor()));
}
- GrPipeline::CreateArgs args;
- args.fPipelineBuilder = &pipelineBuilder;
- args.fDrawContext = drawContext;
- args.fCaps = this->caps();
- args.fScissor = &appliedClip.scissorState();
- args.fHasStencilClip = appliedClip.hasStencilClip();
if (pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip()) {
if (!fResourceProvider->attachStencilAttachment(drawContext->accessRenderTarget())) {
SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
return;
}
}
+
+ GrPipeline::CreateArgs args;
+ args.fPipelineBuilder = &pipelineBuilder;
+ args.fDrawContext = drawContext;
+ args.fCaps = this->caps();
batch->getPipelineOptimizations(&args.fOpts);
- GrScissorState finalScissor;
if (args.fOpts.fOverrides.fUsePLSDstRead || fClipBatchToBounds) {
GrGLIRect viewport;
viewport.fLeft = 0;
@@ -381,14 +368,9 @@ void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
viewport.fWidth);
ibounds.fBottom = SkTPin(SkScalarCeilToInt(batch->bounds().fBottom), viewport.fBottom,
viewport.fHeight);
- if (appliedClip.scissorState().enabled()) {
- const SkIRect& scissorRect = appliedClip.scissorState().rect();
- if (!ibounds.intersect(scissorRect)) {
- return;
- }
+ if (!appliedClip.addScissor(ibounds)) {
+ return;
}
- finalScissor.set(ibounds);
- args.fScissor = &finalScissor;
}
args.fOpts.fColorPOI.completeCalculations(
sk_sp_address_as_pointer_address(pipelineBuilder.fColorFragmentProcessors.begin()),
@@ -396,6 +378,8 @@ void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
args.fOpts.fCoveragePOI.completeCalculations(
sk_sp_address_as_pointer_address(pipelineBuilder.fCoverageFragmentProcessors.begin()),
pipelineBuilder.numCoverageFragmentProcessors());
+ args.fScissor = &appliedClip.scissorState();
+ args.fHasStencilClip = appliedClip.hasStencilClip();
if (!this->setupDstReadIfNecessary(pipelineBuilder, drawContext->accessRenderTarget(),
clip, args.fOpts,
&args.fDstTexture, batch->bounds())) {
@@ -410,9 +394,7 @@ void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
SkASSERT(fRenderTarget);
batch->pipeline()->addDependenciesTo(fRenderTarget);
#endif
- SkRect clippedBounds;
- SkAssertResult(intersect(&clippedBounds, bounds, appliedClip.deviceBounds()));
- this->recordBatch(batch, clippedBounds);
+ this->recordBatch(batch, appliedClip.clippedDrawBounds());
}
void GrDrawTarget::stencilPath(GrDrawContext* drawContext,
@@ -424,16 +406,20 @@ void GrDrawTarget::stencilPath(GrDrawContext* drawContext,
SkASSERT(path);
SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
+ // FIXME: Use path bounds instead of this WAR once
+ // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
+ SkRect bounds = SkRect::MakeIWH(drawContext->width(), drawContext->height());
+
// Setup clip
- GrAppliedClip appliedClip;
- if (!clip.apply(fContext, drawContext, nullptr, useHWAA, true, &appliedClip)) {
+ GrAppliedClip appliedClip(bounds);
+ if (!clip.apply(fContext, drawContext, useHWAA, true, &appliedClip)) {
return;
}
// TODO: respect fClipBatchToBounds if we ever start computing bounds here.
// Coverage AA does not make sense when rendering to the stencil buffer. The caller should never
// attempt this in a situation that would require coverage AA.
- SkASSERT(!appliedClip.getClipCoverageFragmentProcessor());
+ SkASSERT(!appliedClip.clipCoverageFragmentProcessor());
GrStencilAttachment* stencilAttachment = fResourceProvider->attachStencilAttachment(
drawContext->accessRenderTarget());
@@ -450,7 +436,7 @@ void GrDrawTarget::stencilPath(GrDrawContext* drawContext,
appliedClip.scissorState(),
drawContext->accessRenderTarget(),
path);
- this->recordBatch(batch, appliedClip.deviceBounds());
+ this->recordBatch(batch, appliedClip.clippedDrawBounds());
batch->unref();
}
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp
index f7bac4aa58..132936c64e 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -343,9 +343,7 @@ GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds
// generation id. When we make early returns, we do not know what was the generation
// id that lead to the state. Make a conservative guess.
fGenID = stack.getTopmostGenID();
-
- // TODO: instead devise a way of telling the caller to disregard some or all of the clip bounds.
- fIBounds = GrClip::GetPixelIBounds(queryBounds);
+ fHasIBounds = false;
if (stack.isWideOpen()) {
fInitialState = InitialState::kAllIn;
@@ -372,6 +370,7 @@ GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds
// The clip is a non-aa rect. This is the one spot where we can actually implement the
// clip (using fIBounds) rather than just telling the caller what it should be.
stackBounds.round(&fIBounds);
+ fHasIBounds = true;
fInitialState = fIBounds.isEmpty() ? InitialState::kAllOut : InitialState::kAllIn;
return;
}
@@ -380,8 +379,11 @@ GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds
return;
}
- SkAssertResult(fIBounds.intersect(GrClip::GetPixelIBounds(stackBounds)));
+ SkRect tightBounds;
+ SkAssertResult(tightBounds.intersect(stackBounds, queryBounds));
+ fIBounds = GrClip::GetPixelIBounds(tightBounds);
SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOutsideClip above.
+ fHasIBounds = true;
// Implement the clip with an AA rect element.
fElements.addToHead(stackBounds, SkRegion::kReplace_Op, true/*doAA*/);
@@ -396,10 +398,11 @@ GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds
// Tighten the query by introducing a new clip at the stack's pixel boundaries. (This new
// clip will be enforced by the scissor through fIBounds.)
SkAssertResult(tighterQuery.intersect(GrClip::GetPixelBounds(stackBounds)));
- fIBounds = GrClip::GetPixelIBounds(tighterQuery);
}
+ fIBounds = GrClip::GetPixelIBounds(tighterQuery);
SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOutsideClip above.
+ fHasIBounds = true;
// Now that we have determined the bounds to use and filtered out the trivial cases, call the
// helper that actually walks the stack.
diff --git a/src/gpu/GrReducedClip.h b/src/gpu/GrReducedClip.h
index 07e06694a1..d7b7ea8881 100644
--- a/src/gpu/GrReducedClip.h
+++ b/src/gpu/GrReducedClip.h
@@ -25,14 +25,20 @@ public:
int32_t genID() const { return fGenID; }
/**
- * Bounding box within which the reduced clip is valid. The caller must not draw any pixels
- * outside this box.
+ * If hasIBounds() is true, this is the bounding box within which the reduced clip is valid, and
+ * the caller must not modify any pixels outside this box. Undefined if hasIBounds() is false.
*/
- const SkIRect& iBounds() const { return fIBounds; }
- int left() const { return this->iBounds().left(); }
- int top() const { return this->iBounds().top(); }
- int width() const { return this->iBounds().width(); }
- int height() const { return this->iBounds().height(); }
+ const SkIRect& ibounds() const { SkASSERT(fHasIBounds); return fIBounds; }
+ int left() const { return this->ibounds().left(); }
+ int top() const { return this->ibounds().top(); }
+ int width() const { return this->ibounds().width(); }
+ int height() const { return this->ibounds().height(); }
+
+ /**
+ * Indicates whether ibounds() are defined. They will always be defined if the elements() are
+ * nonempty.
+ */
+ bool hasIBounds() const { return fHasIBounds; }
typedef SkTLList<SkClipStack::Element, 16> ElementList;
@@ -51,14 +57,12 @@ public:
kAllOut
};
- /**
- * The initial state of the clip within iBounds().
- */
InitialState initialState() const { return fInitialState; }
private:
int32_t fGenID;
SkIRect fIBounds;
+ bool fHasIBounds;
ElementList fElements;
bool fRequiresAA;
InitialState fInitialState;
diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp
index a6b636271a..5265ac2c67 100644
--- a/tests/ClipStackTest.cpp
+++ b/tests/ClipStackTest.cpp
@@ -916,7 +916,8 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
// they are equal.
// All the clip elements will be contained within these bounds.
- static const SkRect kBounds = SkRect::MakeWH(100, 100);
+ static const SkIRect kIBounds = SkIRect::MakeWH(100, 100);
+ static const SkRect kBounds = SkRect::Make(kIBounds);
enum {
kNumTests = 250,
@@ -1015,13 +1016,14 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
testCase.c_str());
if (!reduced.elements().isEmpty()) {
+ REPORTER_ASSERT_MESSAGE(reporter, reduced.hasIBounds(), testCase.c_str());
SkRect stackBounds;
SkClipStack::BoundsType stackBoundsType;
stack.getBounds(&stackBounds, &stackBoundsType);
if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
// Unless GrReducedClip starts doing some heroic tightening of the clip bounds, this
// will be true since the stack bounds are completely contained inside the query.
- REPORTER_ASSERT_MESSAGE(reporter, GrClip::IsInsideClip(reduced.iBounds(), stackBounds),
+ REPORTER_ASSERT_MESSAGE(reporter, GrClip::IsInsideClip(reduced.ibounds(), stackBounds),
testCase.c_str());
}
REPORTER_ASSERT_MESSAGE(reporter, reduced.requiresAA() == doAA, testCase.c_str());
@@ -1037,16 +1039,18 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
add_elem_to_stack(*iter.get(), &reducedStack);
}
+ SkIRect ibounds = reduced.hasIBounds() ? reduced.ibounds() : kIBounds;
+
// GrReducedClipStack assumes that the final result is clipped to the returned bounds
- reducedStack.clipDevRect(reduced.iBounds(), SkRegion::kIntersect_Op);
- stack.clipDevRect(reduced.iBounds(), SkRegion::kIntersect_Op);
+ reducedStack.clipDevRect(ibounds, SkRegion::kIntersect_Op);
+ stack.clipDevRect(ibounds, SkRegion::kIntersect_Op);
// convert both the original stack and reduced stack to SkRegions and see if they're equal
SkRegion region;
- set_region_to_stack(stack, reduced.iBounds(), &region);
+ set_region_to_stack(stack, ibounds, &region);
SkRegion reducedRegion;
- set_region_to_stack(reducedStack, reduced.iBounds(), &reducedRegion);
+ set_region_to_stack(reducedStack, ibounds, &reducedRegion);
REPORTER_ASSERT_MESSAGE(reporter, region == reducedRegion, testCase.c_str());
}
@@ -1151,8 +1155,10 @@ static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) {
SkASSERT(reduced.genID() == testCases[i].reducedGenID);
REPORTER_ASSERT(reporter, reduced.initialState() == testCases[i].initialState);
SkASSERT(reduced.initialState() == testCases[i].initialState);
- REPORTER_ASSERT(reporter, reduced.iBounds() == testCases[i].clipIRect);
- SkASSERT(reduced.iBounds() == testCases[i].clipIRect);
+ REPORTER_ASSERT(reporter, reduced.hasIBounds());
+ SkASSERT(reduced.hasIBounds());
+ REPORTER_ASSERT(reporter, reduced.ibounds() == testCases[i].clipIRect);
+ SkASSERT(reduced.ibounds() == testCases[i].clipIRect);
}
}
}
@@ -1197,7 +1203,9 @@ static void test_aa_query(skiatest::Reporter* reporter, const SkString& testName
return;
case ClipMethod::kIgnoreClip:
SkASSERT(0 == numExpectedElems);
- REPORTER_ASSERT_MESSAGE(reporter, GrClip::IsInsideClip(reduced.iBounds(), queryBounds),
+ REPORTER_ASSERT_MESSAGE(reporter,
+ !reduced.hasIBounds() ||
+ GrClip::IsInsideClip(reduced.ibounds(), queryBounds),
testName.c_str());
REPORTER_ASSERT_MESSAGE(reporter, reduced.elements().isEmpty(), testName.c_str());
REPORTER_ASSERT_MESSAGE(reporter,
@@ -1210,7 +1218,8 @@ static void test_aa_query(skiatest::Reporter* reporter, const SkString& testName
SkIRect expectedScissor;
stackBounds.round(&expectedScissor);
REPORTER_ASSERT_MESSAGE(reporter, reduced.elements().isEmpty(), testName.c_str());
- REPORTER_ASSERT_MESSAGE(reporter, expectedScissor == reduced.iBounds(),
+ REPORTER_ASSERT_MESSAGE(reporter, reduced.hasIBounds(), testName.c_str());
+ REPORTER_ASSERT_MESSAGE(reporter, expectedScissor == reduced.ibounds(),
testName.c_str());
REPORTER_ASSERT_MESSAGE(reporter,
GrReducedClip::InitialState::kAllIn == reduced.initialState(),
@@ -1224,7 +1233,8 @@ static void test_aa_query(skiatest::Reporter* reporter, const SkString& testName
}
REPORTER_ASSERT_MESSAGE(reporter, numExpectedElems == reduced.elements().count(),
testName.c_str());
- REPORTER_ASSERT_MESSAGE(reporter, expectedClipIBounds == reduced.iBounds(),
+ REPORTER_ASSERT_MESSAGE(reporter, reduced.hasIBounds(), testName.c_str());
+ REPORTER_ASSERT_MESSAGE(reporter, expectedClipIBounds == reduced.ibounds(),
testName.c_str());
REPORTER_ASSERT_MESSAGE(reporter, reduced.requiresAA() == !reduced.elements().isEmpty(),
testName.c_str());