diff options
-rw-r--r-- | bench/AAClipBench.cpp | 91 | ||||
-rw-r--r-- | src/gpu/GrClipMaskManager.cpp | 57 | ||||
-rw-r--r-- | src/gpu/GrClipMaskManager.h | 51 |
3 files changed, 184 insertions, 15 deletions
diff --git a/bench/AAClipBench.cpp b/bench/AAClipBench.cpp index 39088c1a78..ea4f6da5ac 100644 --- a/bench/AAClipBench.cpp +++ b/bench/AAClipBench.cpp @@ -10,7 +10,84 @@ #include "SkPath.h" #include "SkRegion.h" #include "SkString.h" +#include "SkCanvas.h" + +//////////////////////////////////////////////////////////////////////////////// +// This bench tests out AA/BW clipping via canvas' clipPath and clipRect calls +class AAClipBench : public SkBenchmark { + SkString fName; + SkPath fClipPath; + SkRect fClipRect; + SkRect fDrawRect; + bool fDoPath; + bool fDoAA; + + enum { + N = SkBENCHLOOP(200), + }; + +public: + AAClipBench(void* param, bool doPath, bool doAA) + : INHERITED(param) { + fDoPath = doPath; + fDoAA = doAA; + + fName.printf("aaclip_%s_%s", + doPath ? "path" : "rect", + doAA ? "AA" : "BW"); + + fClipRect.set(SkFloatToScalar(10.5), SkFloatToScalar(10.5), + SkFloatToScalar(50.5), SkFloatToScalar(50.5)); + fClipPath.addRoundRect(fClipRect, SkIntToScalar(10), SkIntToScalar(10)); + fDrawRect.set(SkIntToScalar(0), SkIntToScalar(0), + SkIntToScalar(100), SkIntToScalar(100)); + + SkASSERT(fClipPath.isConvex()); + } + +protected: + virtual const char* onGetName() { return fName.c_str(); } + virtual void onDraw(SkCanvas* canvas) { + + SkPaint paint; + this->setupPaint(&paint); + + for (int i = 0; i < N; ++i) { + // jostle the clip regions each time to prevent caching + fClipRect.offset((i % 2) == 0 ? SkIntToScalar(10) : SkIntToScalar(-10), 0); + fClipPath.reset(); + fClipPath.addRoundRect(fClipRect, + SkIntToScalar(5), SkIntToScalar(5)); + SkASSERT(fClipPath.isConvex()); + + canvas->save(); +#if 1 + if (fDoPath) { + canvas->clipPath(fClipPath, SkRegion::kReplace_Op, fDoAA); + } else { + canvas->clipRect(fClipRect, SkRegion::kReplace_Op, fDoAA); + } + + canvas->drawRect(fDrawRect, paint); +#else + // this path tests out directly draw the clip primitive + // use it to comparing just drawing the clip vs. drawing using + // the clip + if (fDoPath) { + canvas->drawPath(fClipPath, paint); + } else { + canvas->drawRect(fClipRect, paint); + } +#endif + canvas->restore(); + } + } +private: + typedef SkBenchmark INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// class AAClipBuilderBench : public SkBenchmark { SkString fName; SkPath fPath; @@ -56,6 +133,7 @@ private: typedef SkBenchmark INHERITED; }; +//////////////////////////////////////////////////////////////////////////////// class AAClipRegionBench : public SkBenchmark { public: AAClipRegionBench(void* param) : INHERITED(param) { @@ -88,7 +166,7 @@ private: typedef SkBenchmark INHERITED; }; -/////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// static SkBenchmark* Fact0(void* p) { return SkNEW_ARGS(AAClipBuilderBench, (p, false, false)); } static SkBenchmark* Fact1(void* p) { return SkNEW_ARGS(AAClipBuilderBench, (p, false, true)); } @@ -102,3 +180,14 @@ static BenchRegistry gReg3(Fact3); static SkBenchmark* Fact01(void* p) { return SkNEW_ARGS(AAClipRegionBench, (p)); } static BenchRegistry gReg01(Fact01); + +static SkBenchmark* Fact000(void* p) { return SkNEW_ARGS(AAClipBench, (p, false, false)); } +static SkBenchmark* Fact001(void* p) { return SkNEW_ARGS(AAClipBench, (p, false, true)); } +static SkBenchmark* Fact002(void* p) { return SkNEW_ARGS(AAClipBench, (p, true, false)); } +static SkBenchmark* Fact003(void* p) { return SkNEW_ARGS(AAClipBench, (p, true, true)); } + +static BenchRegistry gReg000(Fact000); +static BenchRegistry gReg001(Fact001); +static BenchRegistry gReg002(Fact002); +static BenchRegistry gReg003(Fact003); + diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index f4b0721404..1a892d80dc 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -340,7 +340,6 @@ namespace { void clear(GrGpu* gpu, GrTexture* target, - const GrRect& bounds, GrColor color) { GrDrawState* drawState = gpu->drawState(); GrAssert(NULL != drawState); @@ -350,6 +349,36 @@ void clear(GrGpu* gpu, gpu->clear(NULL, color); } +// get a texture to act as a temporary buffer for AA clip boolean operations +// TODO: given the expense of createTexture we may want to just cache this too +void needTemp(GrGpu *gpu, const GrTextureDesc& desc, GrTexture** temp) { + if (NULL != *temp) { + // we've already allocated the temp texture + return; + } + + *temp = gpu->createTexture(desc, NULL, 0); +} + +} + +void GrClipMaskManager::getAccum(GrGpu* gpu, + const GrTextureDesc& desc, + GrTexture** accum) { + GrAssert(NULL == *accum); + + // since we are getting an accumulator we know our cache is shot. See + // if we can reuse the texture stored in the cache + if (fAACache.getLastMaskWidth() >= desc.fWidth && + fAACache.getLastMaskHeight() >= desc.fHeight) { + // we can just reuse the existing texture + *accum = fAACache.detachLastMask(); + fAACache.reset(); + } else { + *accum = gpu->createTexture(desc, NULL, 0); + } + + GrAssert(1 == (*accum)->getRefCnt()); } //////////////////////////////////////////////////////////////////////////////// @@ -403,7 +432,7 @@ bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, GrAssert(SkScalarIsInt(bounds.width())); GrAssert(SkScalarIsInt(bounds.height())); - GrTextureDesc desc = { + const GrTextureDesc desc = { kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit, SkScalarCeilToInt(bounds.width()), SkScalarCeilToInt(bounds.height()), @@ -414,12 +443,12 @@ bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, GrRect newRTBounds; newRTBounds.setLTRB(0, 0, bounds.width(), bounds.height()); - GrTexture* accum = gpu->createTexture(desc, NULL, 0); - GrTexture* temp = gpu->createTexture(desc, NULL, 0); - if (NULL == accum || NULL == temp) { + GrTexture* accum = NULL, *temp = NULL; + + getAccum(gpu, desc, &accum); + if (NULL == accum) { fClipMaskInAlpha = false; SkSafeUnref(accum); - SkSafeUnref(temp); return false; } @@ -437,7 +466,7 @@ bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, m.setTranslate(-bounds.fLeft, -bounds.fTop); - drawState->preConcatViewMatrix(m); + drawState->setViewMatrix(m); } bool clearToInside; @@ -447,7 +476,7 @@ bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, &clearToInside, &startOp); - clear(gpu, accum, newRTBounds, clearToInside ? 0xffffffff : 0x00000000); + clear(gpu, accum, clearToInside ? 0xffffffff : 0x00000000); // walk through each clip element and perform its set op for (int c = start; c < count; ++c) { @@ -460,7 +489,7 @@ bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, // replace ops and alter GrClip to allow them through // clear the accumulator and draw the new object directly into it - clear(gpu, accum, newRTBounds, 0x00000000); + clear(gpu, accum, 0x00000000); setUpBooleanBlendCoeffs(drawState, op); this->drawClipShape(gpu, accum, clipIn, c); @@ -474,8 +503,15 @@ bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, continue; } + needTemp(gpu, desc, &temp); + if (NULL == temp) { + fClipMaskInAlpha = false; + SkSafeUnref(accum); + return false; + } + // clear the temp target & draw into it - clear(gpu, temp, newRTBounds, 0x00000000); + clear(gpu, temp, 0x00000000); setUpBooleanBlendCoeffs(drawState, SkRegion::kReplace_Op); this->drawClipShape(gpu, temp, clipIn, c); @@ -517,6 +553,7 @@ bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, *resultBounds = bounds; SkSafeUnref(accum); // fAACache still has a ref to accum SkSafeUnref(temp); + return true; } diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h index 516ec95e30..f827948202 100644 --- a/src/gpu/GrClipMaskManager.h +++ b/src/gpu/GrClipMaskManager.h @@ -14,6 +14,7 @@ #include "GrNoncopyable.h" #include "GrClip.h" #include "SkRefCnt.h" +#include "GrTexture.h" class GrGpu; class GrPathRenderer; @@ -41,9 +42,15 @@ struct ScissoringSettings { */ class GrClipMaskCache : public GrNoncopyable { public: - GrClipMaskCache() - : fLastWidth(-1) - , fLastHeight(-1) { + GrClipMaskCache() { + reset(); + } + + void reset () { + fLastWidth = -1; + fLastHeight = -1; + fLastClip.setEmpty(); + fLastMask.reset(NULL); fLastBound.MakeEmpty(); } @@ -68,10 +75,42 @@ public: fLastBound = bound; } - GrTexture* getLastMask() { + int getLastWidth() const { + return fLastWidth; + } + + int getLastHeight() const { + return fLastHeight; + } + + const GrClip& getLastClip() const { + return fLastClip; + } + + GrTexture* getLastMask() { return fLastMask.get(); } + GrTexture* detachLastMask() { + return fLastMask.detach(); + } + + int getLastMaskWidth() const { + if (NULL == fLastMask.get()) { + return -1; + } + + return fLastMask.get()->width(); + } + + int getLastMaskHeight() const { + if (NULL == fLastMask.get()) { + return -1; + } + + return fLastMask.get()->height(); + } + const GrRect& getLastBound() const { return fLastBound; } @@ -150,6 +189,10 @@ private: const GrRect& rect, GrTexture* texture); + void getAccum(GrGpu* gpu, + const GrTextureDesc& desc, + GrTexture** accum); + // determines the path renderer used to draw a clip path element. GrPathRenderer* getClipPathRenderer(GrGpu* gpu, const SkPath& path, |