diff options
29 files changed, 249 insertions, 343 deletions
diff --git a/gm/texdata.cpp b/gm/texdata.cpp index 494a932cf1..01eedec633 100644 --- a/gm/texdata.cpp +++ b/gm/texdata.cpp @@ -82,7 +82,7 @@ DEF_SIMPLE_GM_BG(texdata, canvas, 2 * S, 2 * S, SK_ColorBLACK) { SkAutoTUnref<GrTexture> au(texture); // setup new clip - GrClip clip(SkRect::MakeWH(2*S, 2*S)); + GrFixedClip clip(SkIRect::MakeWH(2*S, 2*S)); GrPaint paint; paint.setPorterDuffXPFactory(SkXfermode::kSrcOver_Mode); diff --git a/include/gpu/GrClip.h b/include/gpu/GrClip.h index fd8b970e39..68a4eb9224 100644 --- a/include/gpu/GrClip.h +++ b/include/gpu/GrClip.h @@ -8,185 +8,125 @@ #ifndef GrClip_DEFINED #define GrClip_DEFINED +#include "GrFragmentProcessor.h" +#include "GrTypesPriv.h" #include "SkClipStack.h" -struct SkIRect; +class GrClipMaskManager; +class GrPipelineBuilder; /** - * GrClip encapsulates the information required to construct the clip - * masks. 'A GrClip is either wide open, just an IRect, just a Rect, or a full clipstack. - * If the clip is a clipstack than the origin is used to translate the stack with - * respect to device coordinates. This allows us to use a clip stack that is - * specified for a root device with a layer device that is restricted to a subset - * of the original canvas. For other clip types the origin will always be (0,0). - * - * NOTE: GrClip *must* point to a const clipstack + * Produced by GrClip. It provides a set of modifications to the drawing state that are used to + * create the final GrPipeline for a GrBatch. */ -class GrClip : SkNoncopyable { +class GrAppliedClip { public: - GrClip() : fClipType(kWideOpen_ClipType) { - fOrigin.setZero(); - } + GrAppliedClip() : fHasStencilClip(false) {} + const GrFragmentProcessor* clipCoverageFragmentProcessor() const { return fClipCoverageFP; } + const GrScissorState& scissorState() const { return fScissorState; } + bool hasStencilClip() const { return fHasStencilClip; } - GrClip(const SkIRect& rect) : fClipType(kIRect_ClipType) { - fOrigin.setZero(); - fClip.fIRect = rect; - } +private: + SkAutoTUnref<const GrFragmentProcessor> fClipCoverageFP; + GrScissorState fScissorState; + bool fHasStencilClip; - GrClip(const SkRect& rect) : fClipType(kIRect_ClipType) { - fOrigin.setZero(); - fClip.fIRect.fLeft = SkScalarRoundToInt(rect.fLeft); - fClip.fIRect.fTop = SkScalarRoundToInt(rect.fTop); - fClip.fIRect.fRight = SkScalarRoundToInt(rect.fRight); - fClip.fIRect.fBottom = SkScalarRoundToInt(rect.fBottom); - } + friend class GrFixedClip; + friend class GrClipMaskManager; - ~GrClip() { this->reset(); } - - const GrClip& operator=(const GrClip& other) { - this->reset(); - fClipType = other.fClipType; - switch (other.fClipType) { - case kWideOpen_ClipType: - fOrigin.setZero(); - break; - case kClipStack_ClipType: - fClip.fStack = SkRef(other.clipStack()); - fOrigin = other.origin(); - break; - case kIRect_ClipType: - fClip.fIRect = other.irect(); - fOrigin.setZero(); - break; - } - return *this; - } + typedef SkNoncopyable INHERITED; +}; - bool operator==(const GrClip& other) const { - if (this->clipType() != other.clipType()) { - return false; - } - - switch (fClipType) { - case kWideOpen_ClipType: - return true; - case kClipStack_ClipType: - if (this->origin() != other.origin()) { - return false; - } - - if (this->clipStack() && other.clipStack()) { - return *this->clipStack() == *other.clipStack(); - } else { - return this->clipStack() == other.clipStack(); - } - break; - case kIRect_ClipType: - return this->irect() == other.irect(); - break; - } - SkFAIL("This should not occur\n"); - return false; - } +/** + * GrClip is an abstract base class for applying a clip. It constructs a clip mask if necessary, and + * fills out a GrAppliedClip instructing the caller on how to set up the draw state. + */ +class GrClip { +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(GrClipMaskManager*, const GrPipelineBuilder&, const SkRect* devBounds, + GrAppliedClip*) const = 0; - bool operator!=(const GrClip& other) const { - return !(*this == other); - } + virtual ~GrClip() {} +}; - const SkClipStack* clipStack() const { - SkASSERT(kClipStack_ClipType == fClipType); - return fClip.fStack; - } +/** + * Specialized implementation for no clip. + */ +class GrNoClip final : public GrClip { +private: + bool quickContains(const SkRect&) const final { return true; } + void getConservativeBounds(int width, int height, SkIRect* devResult, + bool* isIntersectionOfRects) const final; + bool apply(GrClipMaskManager*, const GrPipelineBuilder&, + const SkRect*, GrAppliedClip*) const final { return true; } +}; - void setClipStack(const SkClipStack* clipStack, const SkIPoint* origin = NULL) { - this->reset(); - if (clipStack->isWideOpen()) { - fClipType = kWideOpen_ClipType; - fOrigin.setZero(); - } else { - fClipType = kClipStack_ClipType; - fClip.fStack = SkRef(clipStack); - if (origin) { - fOrigin = *origin; - } else { - fOrigin.setZero(); - } - } - } +/** + * GrFixedClip is a clip that can be represented by fixed-function hardware. It never modifies the + * stencil buffer itself, but can be configured to use whatever clip is already there. + */ +class GrFixedClip final : public GrClip { +public: + GrFixedClip() : fHasStencilClip(false) {} + GrFixedClip(const SkIRect& scissorRect) : fScissorState(scissorRect), fHasStencilClip(false) {} - void setIRect(const SkIRect& irect) { - this->reset(); - fClipType = kIRect_ClipType; - fOrigin.setZero(); - fClip.fIRect = irect; + void reset() { + fScissorState.setDisabled(); + fHasStencilClip = false; } - const SkIRect& irect() const { - SkASSERT(kIRect_ClipType == fClipType); - return fClip.fIRect; + void reset(const SkIRect& scissorRect) { + fScissorState.set(scissorRect); + fHasStencilClip = false; } - void reset() { - if (kClipStack_ClipType == fClipType) { - fClip.fStack->unref(); - fClip.fStack = NULL; - } - fClipType = kWideOpen_ClipType; - fOrigin.setZero(); - } + void enableStencilClip(bool enable) { fHasStencilClip = enable; } - // We support this for all cliptypes to simplify the logic a bit in clip mask manager. - // non clipstack clip types MUST have a (0,0) origin - const SkIPoint& origin() const { - SkASSERT(fClipType == kClipStack_ClipType || (fOrigin.fX == 0 && fOrigin.fY == 0)); - return fOrigin; - } + const GrScissorState& scissorState() const { return fScissorState; } + bool hasStencilClip() const { return fHasStencilClip; } - bool isWideOpen(const SkRect& rect) const { - return (kWideOpen_ClipType == fClipType) || - (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen()) || - (kIRect_ClipType == fClipType && this->irect().contains(rect)); - } + bool quickContains(const SkRect&) const final; + void getConservativeBounds(int width, int height, SkIRect* devResult, + bool* isIntersectionOfRects) const final; - bool isWideOpen(const SkIRect& rect) const { - return (kWideOpen_ClipType == fClipType) || - (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen()) || - (kIRect_ClipType == fClipType && this->irect().contains(rect)); - } +private: + bool apply(GrClipMaskManager*, const GrPipelineBuilder&, + const SkRect* devBounds, GrAppliedClip* out) const final; - bool isWideOpen() const { - return (kWideOpen_ClipType == fClipType) || - (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen()); - } + GrScissorState fScissorState; + bool fHasStencilClip; +}; - bool quickContains(const SkRect& rect) const { - return (kWideOpen_ClipType == fClipType) || - (kClipStack_ClipType == fClipType && this->clipStack()->quickContains(rect)) || - (kIRect_ClipType == fClipType && this->irect().contains(rect)); +/** + * GrClipStackClip can apply a generic SkClipStack to the draw state. It may generate clip masks or + * write to the stencil buffer during apply(). + */ +class GrClipStackClip final : public GrClip { +public: + GrClipStackClip(const SkClipStack* stack = nullptr, const SkIPoint* origin = nullptr) { + this->reset(stack, origin); } - void getConservativeBounds(int width, int height, - SkIRect* devResult, - bool* isIntersectionOfRects = NULL) const; - - static const GrClip& WideOpen(); + void reset(const SkClipStack* stack = nullptr, const SkIPoint* origin = nullptr) { + fOrigin = origin ? *origin : SkIPoint::Make(0, 0); + fStack.reset(SkSafeRef(stack)); + } - enum ClipType { - kClipStack_ClipType, - kWideOpen_ClipType, - kIRect_ClipType, - }; + const SkIPoint& origin() const { return fOrigin; } + const SkClipStack* clipStack() const { return fStack; } - ClipType clipType() const { return fClipType; } + bool quickContains(const SkRect&) const final; + void getConservativeBounds(int width, int height, SkIRect* devResult, + bool* isIntersectionOfRects) const final; + bool apply(GrClipMaskManager*, const GrPipelineBuilder&, + const SkRect* devBounds, GrAppliedClip*) const final; private: - union Clip { - const SkClipStack* fStack; - SkIRect fIRect; - } fClip; - - SkIPoint fOrigin; - ClipType fClipType; + SkIPoint fOrigin; + SkAutoTUnref<const SkClipStack> fStack; }; #endif diff --git a/include/gpu/GrTypesPriv.h b/include/gpu/GrTypesPriv.h index 18bc6449aa..6a6fd54c7b 100644 --- a/include/gpu/GrTypesPriv.h +++ b/include/gpu/GrTypesPriv.h @@ -401,6 +401,8 @@ enum GrIOType { struct GrScissorState { GrScissorState() : fEnabled(false) {} + GrScissorState(const SkIRect& rect) : fEnabled(true), fRect(rect) {} + void setDisabled() { fEnabled = false; } void set(const SkIRect& rect) { fRect = rect; fEnabled = true; } bool operator==(const GrScissorState& other) const { return fEnabled == other.fEnabled && diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp index 899083dbb4..c7a570121b 100644 --- a/src/core/SkImageFilter.cpp +++ b/src/core/SkImageFilter.cpp @@ -287,13 +287,13 @@ sk_sp<SkSpecialImage> SkImageFilter::DrawWithFP(GrContext* context, return nullptr; } + SkIRect dstIRect = SkIRect::MakeWH(bounds.width(), bounds.height()); SkRect srcRect = SkRect::Make(bounds); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); - GrClip clip(dstRect); + GrFixedClip clip(dstIRect); drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); - return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(bounds.width(), bounds.height()), - kNeedNewImageUniqueID_SpecialImage, + return SkSpecialImage::MakeFromGpu(dstIRect, kNeedNewImageUniqueID_SpecialImage, drawContext->asTexture()); } #endif diff --git a/src/effects/SkAlphaThresholdFilter.cpp b/src/effects/SkAlphaThresholdFilter.cpp index a4876c8008..b4848923ea 100644 --- a/src/effects/SkAlphaThresholdFilter.cpp +++ b/src/effects/SkAlphaThresholdFilter.cpp @@ -114,7 +114,7 @@ sk_sp<GrTexture> SkAlphaThresholdFilterImpl::createMaskTexture(GrContext* contex SkRegion::Iterator iter(fRegion); drawContext->clear(nullptr, 0x0, true); - GrClip clip(SkRect::Make(SkIRect::MakeWH(bounds.width(), bounds.height()))); + GrFixedClip clip(SkIRect::MakeWH(bounds.width(), bounds.height())); while (!iter.done()) { SkRect rect = SkRect::Make(iter.rect()); drawContext->drawRect(clip, grPaint, inMatrix, rect); diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index 7f076d6ca5..969afc12df 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -1278,7 +1278,7 @@ bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src, paint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); } - drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), SkRect::Make(clipRect)); + drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), SkRect::Make(clipRect)); } *result = drawContext->asTexture().release(); diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp index befda79332..541dbbd058 100644 --- a/src/effects/SkDisplacementMapEffect.cpp +++ b/src/effects/SkDisplacementMapEffect.cpp @@ -342,7 +342,7 @@ sk_sp<SkSpecialImage> SkDisplacementMapEffect::onFilterImage(SkSpecialImage* sou return nullptr; } - drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(colorBounds)); + drawContext->drawRect(GrNoClip(), paint, matrix, SkRect::Make(colorBounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); diff --git a/src/effects/SkGpuBlurUtils.cpp b/src/effects/SkGpuBlurUtils.cpp index de19d4372c..b377b417c5 100644 --- a/src/effects/SkGpuBlurUtils.cpp +++ b/src/effects/SkGpuBlurUtils.cpp @@ -212,7 +212,7 @@ sk_sp<GrDrawContext> GaussianBlur(GrContext* context, scale_irect(&srcRect, scaleFactorX, scaleFactorY); // setup new clip - GrClip clip(localDstBounds); + GrFixedClip clip(localDstBounds); sk_sp<GrTexture> srcTexture(sk_ref_sp(origSrc)); diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp index d9b29363ed..7f4dcfdf03 100644 --- a/src/effects/SkLightingImageFilter.cpp +++ b/src/effects/SkLightingImageFilter.cpp @@ -415,11 +415,11 @@ sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU(SkSpecialIma return nullptr; } - SkRect dstRect = SkRect::MakeWH(SkIntToScalar(offsetBounds.width()), - SkIntToScalar(offsetBounds.height())); + SkIRect dstIRect = SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height()); + SkRect dstRect = SkRect::Make(dstIRect); // setup new clip - GrClip clip(dstRect); + GrFixedClip clip(dstIRect); const SkIRect inputBounds = SkIRect::MakeWH(input->width(), input->height()); SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1); diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp index 121a7fdc01..bbd236ea72 100644 --- a/src/effects/SkMorphologyImageFilter.cpp +++ b/src/effects/SkMorphologyImageFilter.cpp @@ -478,8 +478,7 @@ static sk_sp<SkSpecialImage> apply_morphology(GrContext* context, SkASSERT(srcTexture); // setup new clip - const GrClip clip(SkRect::MakeWH(SkIntToScalar(srcTexture->width()), - SkIntToScalar(srcTexture->height()))); + const GrFixedClip clip(SkIRect::MakeWH(srcTexture->width(), srcTexture->height())); const SkIRect dstRect = SkIRect::MakeWH(rect.width(), rect.height()); SkIRect srcRect = rect; diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp index d4756e8e78..1921e00a1a 100644 --- a/src/effects/SkXfermodeImageFilter.cpp +++ b/src/effects/SkXfermodeImageFilter.cpp @@ -249,7 +249,7 @@ sk_sp<SkSpecialImage> SkXfermodeImageFilter::filterImageGPU(SkSpecialImage* sour SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); - drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(bounds)); + drawContext->drawRect(GrNoClip(), paint, matrix, SkRect::Make(bounds)); return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(bounds.width(), bounds.height()), kNeedNewImageUniqueID_SpecialImage, diff --git a/src/gpu/GrBlurUtils.cpp b/src/gpu/GrBlurUtils.cpp index 40bd6f973b..1e85b87dcf 100644 --- a/src/gpu/GrBlurUtils.cpp +++ b/src/gpu/GrBlurUtils.cpp @@ -125,8 +125,8 @@ static sk_sp<GrTexture> create_mask_GPU(GrContext* context, tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip - const SkRect clipRect = SkRect::MakeIWH(maskRect.width(), maskRect.height()); - GrClip clip(clipRect); + const SkIRect clipRect = SkIRect::MakeWH(maskRect.width(), maskRect.height()); + GrFixedClip clip(clipRect); // Draw the mask into maskTexture with the path's integerized top-left at // the origin using tempPaint. diff --git a/src/gpu/GrClip.cpp b/src/gpu/GrClip.cpp index 5c4a27ccad..15065aa484 100644 --- a/src/gpu/GrClip.cpp +++ b/src/gpu/GrClip.cpp @@ -7,47 +7,83 @@ #include "GrClip.h" -#include "GrSurface.h" -#include "SkRect.h" +#include "GrClipMaskManager.h" -/////////////////////////////////////////////////////////////////////////////// +void GrNoClip::getConservativeBounds(int width, int height, SkIRect* devResult, + bool* isIntersectionOfRects) const { + devResult->setXYWH(0, 0, width, height); + if (isIntersectionOfRects) { + *isIntersectionOfRects = true; + } +} -/** - * getConservativeBounds returns the conservative bounding box of the clip - * in device (as opposed to canvas) coordinates. If the bounding box is - * the result of purely intersections of rects (with an initial replace) - * isIntersectionOfRects will be set to true. - */ -void GrClip::getConservativeBounds(int width, int height, SkIRect* devResult, - bool* isIntersectionOfRects) const { - switch (fClipType) { - case kWideOpen_ClipType: { - devResult->setLTRB(0, 0, width, height); - if (isIntersectionOfRects) { - *isIntersectionOfRects = true; - } - } break; - case kIRect_ClipType: { - *devResult = this->irect(); - if (isIntersectionOfRects) { - *isIntersectionOfRects = true; - } - } break; - case kClipStack_ClipType: { - SkRect devBounds; - this->clipStack()->getConservativeBounds(-this->origin().fX, - -this->origin().fY, - width, - height, - &devBounds, - isIntersectionOfRects); - devBounds.roundOut(devResult); - } break; +bool GrFixedClip::quickContains(const SkRect& rect) const { + if (fHasStencilClip) { + return false; + } + if (!fScissorState.enabled()) { + return true; + } + return fScissorState.rect().contains(rect); +} + +void GrFixedClip::getConservativeBounds(int width, int height, SkIRect* devResult, + bool* isIntersectionOfRects) const { + devResult->setXYWH(0, 0, width, height); + if (fScissorState.enabled()) { + if (!devResult->intersect(fScissorState.rect())) { + devResult->setEmpty(); + } + } + if (isIntersectionOfRects) { + *isIntersectionOfRects = true; + } +} + +bool GrFixedClip::apply(GrClipMaskManager*, const GrPipelineBuilder& pipelineBuilder, + const SkRect* devBounds, GrAppliedClip* out) const { + if (fScissorState.enabled()) { + const GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); + SkIRect tightScissor; + if (!tightScissor.intersect(fScissorState.rect(), + SkIRect::MakeWH(rt->width(), rt->height()))) { + return false; + } + if (devBounds && !devBounds->intersects(SkRect::Make(tightScissor))) { + return false; + } + out->fScissorState.set(tightScissor); + } + out->fHasStencilClip = fHasStencilClip; + return true; +} + +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); } -const GrClip& GrClip::WideOpen() { - static const GrClip clip; - return clip; +bool GrClipStackClip::apply(GrClipMaskManager* clipMaskManager, + const GrPipelineBuilder& pipelineBuilder, const SkRect* devBounds, + GrAppliedClip* out) const { + // TODO: Collapse ClipMaskManager into this class.(?) + return clipMaskManager->setupClipping(pipelineBuilder, *this, devBounds, out); } diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index da128fb5c0..0d2d5b073e 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -137,11 +137,6 @@ GrPathRenderer* GrClipMaskManager::GetPathRenderer(GrContext* context, return pr; } -GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget) - : fDrawTarget(drawTarget) - , fClipMode(kIgnoreClip_StencilClipMode) { -} - GrContext* GrClipMaskManager::getContext() { return fDrawTarget->cmmAccess().context(); } @@ -288,11 +283,11 @@ bool GrClipMaskManager::getAnalyticClipProcessor(const GrReducedClip::ElementLis // sort out what kind of clip mask needs to be created: alpha, stencil, // scissor, or entirely software bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, - const GrClip& clip, + const GrClipStackClip& clip, const SkRect* devBounds, GrAppliedClip* out) { - if (kRespectClip_StencilClipMode == fClipMode) { - fClipMode = kIgnoreClip_StencilClipMode; + if (!clip.clipStack() || clip.clipStack()->isWideOpen()) { + return true; } GrReducedClip::ElementList elements; @@ -306,59 +301,36 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, SkASSERT(rt); SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height()); - if (clip.isWideOpen(clipSpaceRTIBounds)) { - return true; - } + clipSpaceRTIBounds.offset(clip.origin()); - // The clip mask manager always draws with a single IRect so we special case that logic here - // Image filters just use a rect, so we also special case that logic - switch (clip.clipType()) { - case GrClip::kWideOpen_ClipType: - SkFAIL("Should have caught this with clip.isWideOpen()"); - return true; - case GrClip::kIRect_ClipType: { - SkIRect scissor = clip.irect(); - if (scissor.intersect(clipSpaceRTIBounds)) { - out->fScissorState.set(scissor); - out->fHasStencilClip = kIgnoreClip_StencilClipMode != fClipMode; + SkIRect clipSpaceReduceQueryBounds; +#define DISABLE_DEV_BOUNDS_FOR_CLIP_REDUCTION 0 + if (devBounds && !DISABLE_DEV_BOUNDS_FOR_CLIP_REDUCTION) { + SkIRect devIBounds = devBounds->roundOut(); + devIBounds.offset(clip.origin()); + if (!clipSpaceReduceQueryBounds.intersect(clipSpaceRTIBounds, devIBounds)) { + return false; + } + } else { + clipSpaceReduceQueryBounds = clipSpaceRTIBounds; + } + GrReducedClip::ReduceClipStack(*clip.clipStack(), + clipSpaceReduceQueryBounds, + &elements, + &genID, + &initialState, + &clipSpaceIBounds, + &requiresAA); + if (elements.isEmpty()) { + if (GrReducedClip::kAllIn_InitialState == initialState) { + if (clipSpaceIBounds == clipSpaceRTIBounds) { return true; } + } else { return false; } - case GrClip::kClipStack_ClipType: { - clipSpaceRTIBounds.offset(clip.origin()); - SkIRect clipSpaceReduceQueryBounds; -#define DISABLE_DEV_BOUNDS_FOR_CLIP_REDUCTION 0 - if (devBounds && !DISABLE_DEV_BOUNDS_FOR_CLIP_REDUCTION) { - SkIRect devIBounds = devBounds->roundOut(); - devIBounds.offset(clip.origin()); - if (!clipSpaceReduceQueryBounds.intersect(clipSpaceRTIBounds, devIBounds)) { - return false; - } - } else { - clipSpaceReduceQueryBounds = clipSpaceRTIBounds; - } - GrReducedClip::ReduceClipStack(*clip.clipStack(), - clipSpaceReduceQueryBounds, - &elements, - &genID, - &initialState, - &clipSpaceIBounds, - &requiresAA); - if (elements.isEmpty()) { - if (GrReducedClip::kAllIn_InitialState == initialState) { - if (clipSpaceIBounds == clipSpaceRTIBounds) { - return true; - } - } else { - return false; - } - } - } break; } - SkASSERT(kIgnoreClip_StencilClipMode == fClipMode); // TODO: Remove fClipMode. - // An element count of 4 was chosen because of the common pattern in Blink of: // isect RR // diff RR @@ -452,13 +424,12 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, SkIRect scissorSpaceIBounds(clipSpaceIBounds); scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); out->fScissorState.set(scissorSpaceIBounds); - SkASSERT(kRespectClip_StencilClipMode == fClipMode); // TODO: Remove fClipMode. out->fHasStencilClip = true; return true; } static bool stencil_element(GrDrawContext* dc, - const GrClip& clip, + const GrFixedClip& clip, const GrUserStencilSettings* ss, const SkMatrix& viewMatrix, const SkClipStack::Element* element) { @@ -603,7 +574,7 @@ GrTexture* GrClipMaskManager::CreateAlphaClipMask(GrContext* context, } #endif - GrClip clip(maskSpaceIBounds); + GrFixedClip clip(maskSpaceIBounds); // draw directly into the result with the stencil set to make the pixels affected // by the clip shape be non-zero. @@ -645,7 +616,7 @@ GrTexture* GrClipMaskManager::CreateAlphaClipMask(GrContext* context, paint.setAntiAlias(element->isAA()); paint.setCoverageSetOpXPFactory(op, false); - draw_element(dc.get(), GrClip::WideOpen(), paint, translate, element); + draw_element(dc.get(), GrNoClip(), paint, translate, element); } } @@ -681,7 +652,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, // We set the current clip to the bounds so that our recursive draws are scissored to them. SkIRect stencilSpaceIBounds(clipSpaceIBounds); stencilSpaceIBounds.offset(clipSpaceToStencilOffset); - GrClip clip(stencilSpaceIBounds); + GrFixedClip clip(stencilSpaceIBounds); fDrawTarget->cmmAccess().clearStencilClip(stencilSpaceIBounds, GrReducedClip::kAllIn_InitialState == initialState, rt); @@ -703,7 +674,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, bool fillInverted = false; // enabled at bottom of loop - fClipMode = kIgnoreClip_StencilClipMode; + clip.enableStencilClip(false); // This will be used to determine whether the clip shape can be rendered into the // stencil with arbitrary stencil settings. @@ -801,7 +772,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, // now we modify the clip bit by rendering either the clip // element directly or a bounding rect of the entire clip. - fClipMode = kModifyClip_StencilClipMode; + clip.enableStencilClip(true); for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) { pipelineBuilder.setUserStencil(*pass); @@ -832,7 +803,6 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, } } } - fClipMode = kRespectClip_StencilClipMode; return true; } diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h index 2b70f02e38..ef5fbc14d0 100644 --- a/src/gpu/GrClipMaskManager.h +++ b/src/gpu/GrClipMaskManager.h @@ -17,7 +17,8 @@ #include "SkTLList.h" #include "SkTypes.h" -class GrClip; +class GrAppliedClip; +class GrClipStackClip; class GrDrawTarget; class GrPathRenderer; class GrPathRendererChain; @@ -26,28 +27,6 @@ class GrTexture; class SkPath; /** - * Produced by GrClipMaskManager. It provides a set of modifications to the drawing state that - * are used to create the final GrPipeline for a GrBatch. This is a work in progress. It will - * eventually encapsulate all mechanisms for modifying the scissor, shaders, and stencil state - * to implement clipping. - */ -class GrAppliedClip : public SkNoncopyable { -public: - GrAppliedClip() : fHasStencilClip(false) {} - const GrFragmentProcessor* clipCoverageFragmentProcessor() const { return fClipCoverageFP; } - const GrScissorState& scissorState() const { return fScissorState; } - bool hasStencilClip() const { return fHasStencilClip; } - -private: - SkAutoTUnref<const GrFragmentProcessor> fClipCoverageFP; - GrScissorState fScissorState; - bool fHasStencilClip; - friend class GrClipMaskManager; - - typedef SkNoncopyable INHERITED; -}; - -/** * The clip mask creator handles the generation of the clip mask. If anti * aliasing is requested it will (in the future) generate a single channel * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit @@ -57,7 +36,7 @@ private: */ class GrClipMaskManager : SkNoncopyable { public: - GrClipMaskManager(GrDrawTarget* owner); + GrClipMaskManager(GrDrawTarget* owner) : fDrawTarget(owner) {} /** * Creates a clip mask if necessary as a stencil buffer or alpha texture @@ -65,7 +44,7 @@ public: * then the draw can be skipped. devBounds is optional but can help optimize * clipping. */ - bool setupClipping(const GrPipelineBuilder&, const GrClip&, const SkRect* devBounds, + bool setupClipping(const GrPipelineBuilder&, const GrClipStackClip&, const SkRect* devBounds, GrAppliedClip*); private: @@ -85,20 +64,6 @@ private: const SkMatrix& viewMatrix, const SkClipStack::Element* element); - /** - * Informs the helper function adjustStencilParams() about how the stencil - * buffer clip is being used. - */ - enum StencilClipMode { - // Draw to the clip bit of the stencil buffer - kModifyClip_StencilClipMode, - // Clip against the existing representation of the clip in the high bit - // of the stencil buffer. - kRespectClip_StencilClipMode, - // Neither writing to nor clipping against the clip bit. - kIgnoreClip_StencilClipMode, - }; - // Attempts to install a series of coverage effects to implement the clip. Return indicates // whether the element list was successfully converted to processors. *fp may be nullptr even // when the function succeeds because all the elements were ignored. TODO: Make clip reduction @@ -146,7 +111,6 @@ private: static const int kMaxAnalyticElements = 4; GrDrawTarget* fDrawTarget; // This is our owning draw target. - StencilClipMode fClipMode; typedef SkNoncopyable INHERITED; }; diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 4235ae8552..39916b9728 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -373,7 +373,7 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, paint.addColorFragmentProcessor(fp); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); - drawContext->drawRect(GrClip::WideOpen(), paint, matrix, rect, nullptr); + drawContext->drawRect(GrNoClip(), paint, matrix, rect, nullptr); if (kFlushWrites_PixelOp & pixelOpsFlags) { this->flushSurfaceWrites(surface); @@ -487,7 +487,7 @@ bool GrContext::readSurfacePixels(GrSurface* src, SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); sk_sp<GrDrawContext> drawContext( this->drawContext(sk_ref_sp(temp->asRenderTarget()))); - drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, nullptr); + drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), rect, nullptr); surfaceToRead.reset(SkRef(temp.get())); left = 0; top = 0; @@ -559,7 +559,7 @@ bool GrContext::applyGamma(GrRenderTarget* dst, GrTexture* src, SkScalar gamma){ SkRect rect; src->getBoundsRect(&rect); - drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect); + drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), rect); this->flushSurfaceWrites(dst); return true; diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp index 3db04491e6..549e5ebf80 100644 --- a/src/gpu/GrDrawContext.cpp +++ b/src/gpu/GrDrawContext.cpp @@ -301,14 +301,8 @@ void GrDrawContext::drawRect(const GrClip& clip, if (width < 0) { SkRect rtRect; fRenderTarget->getBoundsRect(&rtRect); - SkRect clipSpaceRTRect = rtRect; - bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType(); - if (checkClip) { - clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX), - SkIntToScalar(clip.origin().fY)); - } // Does the clip contain the entire RT? - if (!checkClip || clip.quickContains(clipSpaceRTRect)) { + if (clip.quickContains(rtRect)) { SkMatrix invM; if (!viewMatrix.invert(&invM)) { return; @@ -374,7 +368,7 @@ void GrDrawContext::drawRect(const GrClip& clip, this->internalDrawPath(clip, paint, viewMatrix, path, *style); } -bool GrDrawContextPriv::drawAndStencilRect(const GrClip& clip, +bool GrDrawContextPriv::drawAndStencilRect(const GrFixedClip& clip, const GrUserStencilSettings* ss, SkRegion::Op op, bool invert, @@ -839,7 +833,7 @@ void GrDrawContext::drawPath(const GrClip& clip, this->internalDrawPath(clip, paint, viewMatrix, path, style); } -bool GrDrawContextPriv::drawAndStencilPath(const GrClip& clip, +bool GrDrawContextPriv::drawAndStencilPath(const GrFixedClip& clip, const GrUserStencilSettings* ss, SkRegion::Op op, bool invert, diff --git a/src/gpu/GrDrawContextPriv.h b/src/gpu/GrDrawContextPriv.h index 7f70f89582..2fb98ee51c 100644 --- a/src/gpu/GrDrawContextPriv.h +++ b/src/gpu/GrDrawContextPriv.h @@ -10,6 +10,7 @@ #include "GrDrawContext.h" +class GrFixedClip; struct GrUserStencilSettings; /** Class that adds methods to GrDrawContext that are only intended for use internal to Skia. @@ -17,7 +18,7 @@ struct GrUserStencilSettings; data members or virtual methods. */ class GrDrawContextPriv { public: - bool drawAndStencilRect(const GrClip&, + bool drawAndStencilRect(const GrFixedClip&, const GrUserStencilSettings*, SkRegion::Op op, bool invert, @@ -25,7 +26,7 @@ public: const SkMatrix& viewMatrix, const SkRect&); - bool drawAndStencilPath(const GrClip&, + bool drawAndStencilPath(const GrFixedClip&, const GrUserStencilSettings*, SkRegion::Op op, bool invert, diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp index 0db31f29de..7d92ef923c 100644 --- a/src/gpu/GrDrawTarget.cpp +++ b/src/gpu/GrDrawTarget.cpp @@ -239,7 +239,7 @@ void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder, GrDrawBatch* batch) { // Setup clip GrAppliedClip appliedClip; - if (!fClipMaskManager->setupClipping(pipelineBuilder, clip, &batch->bounds(), &appliedClip)) { + if (!clip.apply(fClipMaskManager, pipelineBuilder, &batch->bounds(), &appliedClip)) { return; } @@ -317,16 +317,14 @@ void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder, // Setup clip GrAppliedClip appliedClip; - if (!fClipMaskManager->setupClipping(pipelineBuilder, clip, nullptr, &appliedClip)) { + if (!clip.apply(fClipMaskManager, pipelineBuilder, nullptr, &appliedClip)) { return; } // TODO: respect fClipBatchToBounds if we ever start computing bounds here. - GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps; - if (appliedClip.clipCoverageFragmentProcessor()) { - arfps.set(&pipelineBuilder); - arfps.addCoverageFragmentProcessor(appliedClip.clipCoverageFragmentProcessor()); - } + // 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.clipCoverageFragmentProcessor()); GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); GrStencilAttachment* stencilAttachment = fResourceProvider->attachStencilAttachment(rt); @@ -378,7 +376,7 @@ void GrDrawTarget::clear(const SkIRect* rect, SkAutoTUnref<GrDrawBatch> batch( GrRectBatchFactory::CreateNonAAFill(color, SkMatrix::I(), scalarRect, nullptr, nullptr)); - this->drawBatch(pipelineBuilder, GrClip::WideOpen(), batch); + this->drawBatch(pipelineBuilder, GrNoClip(), batch); } else { GrBatch* batch = new GrClearBatch(*rect, color, renderTarget); this->recordBatch(batch); diff --git a/src/gpu/GrTextureParamsAdjuster.cpp b/src/gpu/GrTextureParamsAdjuster.cpp index 3c4769b96e..a91ba8a5e3 100644 --- a/src/gpu/GrTextureParamsAdjuster.cpp +++ b/src/gpu/GrTextureParamsAdjuster.cpp @@ -119,7 +119,7 @@ static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset, } SkRect dstRect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight)); - drawContext->fillRectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), dstRect, localRect); + drawContext->fillRectToRect(GrNoClip(), paint, SkMatrix::I(), dstRect, localRect); return copy.release(); } diff --git a/src/gpu/GrTextureToYUVPlanes.cpp b/src/gpu/GrTextureToYUVPlanes.cpp index 14ebf3c272..42156026a3 100644 --- a/src/gpu/GrTextureToYUVPlanes.cpp +++ b/src/gpu/GrTextureToYUVPlanes.cpp @@ -43,7 +43,7 @@ static bool convert_texture(GrTexture* src, GrDrawContext* dst, int dstW, int ds GrPaint paint; paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); paint.addColorFragmentProcessor(fp); - dst->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), SkRect::MakeIWH(dstW, dstH)); + dst->drawRect(GrNoClip(), paint, SkMatrix::I(), SkRect::MakeIWH(dstW, dstH)); return true; } diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp index 970644d0f4..a7281da27b 100644 --- a/src/gpu/GrYUVProvider.cpp +++ b/src/gpu/GrYUVProvider.cpp @@ -147,7 +147,7 @@ sk_sp<GrTexture> GrYUVProvider::refAsTexture(GrContext* ctx, const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth, yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); - drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), r); + drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), r); return drawContext->asTexture(); } diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index a0f81e7ed9..a5af472cbb 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -341,7 +341,7 @@ void SkGpuDevice::prepareDraw(const SkDraw& draw) { SkASSERT(draw.fClipStack && draw.fClipStack == fClipStack); - fClip.setClipStack(fClipStack, &this->getOrigin()); + fClip.reset(fClipStack, &this->getOrigin()); } GrRenderTarget* SkGpuDevice::accessRenderTarget() { diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h index 1e025670ef..e940159b22 100644 --- a/src/gpu/SkGpuDevice.h +++ b/src/gpu/SkGpuDevice.h @@ -153,7 +153,7 @@ private: SkAutoTUnref<const SkClipStack> fClipStack; SkIPoint fClipOrigin; - GrClip fClip;; + GrClipStackClip fClip; // remove when our clients don't rely on accessBitmap() SkBitmap fLegacyBitmap; bool fOpaque; diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp index 6b43606bb5..99a4884f0f 100644 --- a/src/gpu/effects/GrConfigConversionEffect.cpp +++ b/src/gpu/effects/GrConfigConversionEffect.cpp @@ -232,7 +232,7 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context break; } - readDrawContext->fillRectToRect(GrClip::WideOpen(), + readDrawContext->fillRectToRect(GrNoClip(), paint1, SkMatrix::I(), kDstRect, @@ -249,7 +249,7 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context failed = true; break; } - tempDrawContext->fillRectToRect(GrClip::WideOpen(), + tempDrawContext->fillRectToRect(GrNoClip(), paint2, SkMatrix::I(), kDstRect, @@ -264,7 +264,7 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context break; } - readDrawContext->fillRectToRect(GrClip::WideOpen(), + readDrawContext->fillRectToRect(GrNoClip(), paint3, SkMatrix::I(), kDstRect, diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp index 339dee7a5c..2c24058395 100644 --- a/src/image/SkImage_Gpu.cpp +++ b/src/image/SkImage_Gpu.cpp @@ -269,7 +269,7 @@ sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx , SkYUVColorSpace const SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); - drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect); + drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), rect); ctx->flushSurfaceWrites(drawContext->accessRenderTarget()); return sk_make_sp<SkImage_Gpu>(width, height, kNeedNewImageUniqueID, kOpaque_SkAlphaType, diff --git a/tests/ClipBoundsTest.cpp b/tests/ClipBoundsTest.cpp index 5660afdc27..246cf6e60c 100644 --- a/tests/ClipBoundsTest.cpp +++ b/tests/ClipBoundsTest.cpp @@ -40,8 +40,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrClipBounds, reporter, ctxInfo) { REPORTER_ASSERT(reporter, isIntersectionOfRects); // wrap the SkClipStack in a GrClip - GrClip clipData; - clipData.setClipStack(&stack); + GrClipStackClip clipData(&stack); SkIRect devGrClipBound; clipData.getConservativeBounds(kXSize, kYSize, diff --git a/tests/TessellatingPathRendererTests.cpp b/tests/TessellatingPathRendererTests.cpp index 62ad6e2c64..a3eb4893d3 100644 --- a/tests/TessellatingPathRendererTests.cpp +++ b/tests/TessellatingPathRendererTests.cpp @@ -239,11 +239,12 @@ static void test_path(GrDrawTarget* dt, GrRenderTarget* rt, GrResourceProvider* pipelineBuilder.setXPFactory( GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); pipelineBuilder.setRenderTarget(rt); + GrNoClip noClip; GrStyle style(SkStrokeRec::kFill_InitStyle); GrPathRenderer::DrawPathArgs args; args.fTarget = dt; args.fPipelineBuilder = &pipelineBuilder; - args.fClip = &GrClip::WideOpen(); + args.fClip = &noClip; args.fResourceProvider = rp; args.fColor = GrColor_WHITE; args.fViewMatrix = &SkMatrix::I(); diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp index 874567dc62..a301c747ca 100644 --- a/tools/gpu/GrTest.cpp +++ b/tools/gpu/GrTest.cpp @@ -168,8 +168,7 @@ void SkGpuDevice::drawTexture(GrTexture* tex, const SkRect& dst, const SkPaint& grPaint.addColorTextureProcessor(tex, textureMat); - GrClip clip; - fDrawContext->drawRect(clip, grPaint, mat, dst); + fDrawContext->drawRect(GrNoClip(), grPaint, mat, dst); } @@ -260,8 +259,11 @@ void GrDrawContextPriv::testingOnly_drawBatch(const GrPipelineBuilder& pipelineB SkDEBUGCODE(fDrawContext->validate();) GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContext::testingOnly_drawBatch"); - const GrClip& drawClip = clip ? *clip : GrClip::WideOpen(); - fDrawContext->getDrawTarget()->drawBatch(pipelineBuilder, drawClip, batch); + if (clip) { + fDrawContext->getDrawTarget()->drawBatch(pipelineBuilder, *clip, batch); + } else { + fDrawContext->getDrawTarget()->drawBatch(pipelineBuilder, GrNoClip(), batch); + } } #undef ASSERT_SINGLE_OWNER |