From f105b109264f71dfb0bfd9977e6a5dd0a5a12f57 Mon Sep 17 00:00:00 2001 From: "robertphillips@google.com" Date: Mon, 14 May 2012 12:18:26 +0000 Subject: [PATCH] Made clip mask cache use Scratch Texture system http://codereview.appspot.com/6210044/ git-svn-id: http://skia.googlecode.com/svn/trunk@3920 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/gpu/GrContext.h | 1 + src/gpu/GrClipMaskManager.cpp | 99 +++++++++++++++-------------------- src/gpu/GrClipMaskManager.h | 99 ++++++++++++++++++++++------------- src/gpu/GrGpu.cpp | 8 +-- src/gpu/GrGpu.h | 1 + tests/ClipCacheTest.cpp | 49 +++++++++++------ 6 files changed, 147 insertions(+), 110 deletions(-) diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h index b26d2b3aee..bb661c90b7 100644 --- a/include/gpu/GrContext.h +++ b/include/gpu/GrContext.h @@ -853,6 +853,7 @@ public: GrContext::kApprox_ScratchTexMatch) { if (NULL != fContext) { fContext->unlockTexture(fEntry); + fEntry.reset(); } fContext = context; if (NULL != fContext) { diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index 2e9a4b9bd4..43b27431ba 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -338,7 +338,6 @@ bool GrClipMaskManager::drawClipShape(GrGpu* gpu, void GrClipMaskManager::drawTexture(GrGpu* gpu, GrTexture* target, - const GrRect& rect, GrTexture* texture) { GrDrawState* drawState = gpu->drawState(); GrAssert(NULL != drawState); @@ -354,6 +353,9 @@ void GrClipMaskManager::drawTexture(GrGpu* gpu, GrSamplerState::kNearest_Filter, sampleM); + GrRect rect = GrRect::MakeWH(SkIntToScalar(target->width()), + SkIntToScalar(target->height())); + gpu->drawSimpleRect(rect, NULL, 1 << 0); drawState->setTexture(0, NULL); @@ -372,10 +374,13 @@ 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 get_temp(GrGpu *gpu, const GrRect& bounds, GrTexture** temp) { - if (NULL != *temp) { +void GrClipMaskManager::getTemp(const GrRect& bounds, + GrAutoScratchTexture* temp) { + if (NULL != temp->texture()) { // we've already allocated the temp texture return; } @@ -388,39 +393,27 @@ void get_temp(GrGpu *gpu, const GrRect& bounds, GrTexture** temp) { 0 // samples }; - *temp = gpu->createTexture(desc, NULL, 0); + temp->set(fAACache.getContext(), desc); } + +void GrClipMaskManager::setupCache(const GrClip& clipIn, + const GrRect& bounds) { + // Since we are setting up the cache we know the last lookup was a miss + // Free up the currently cached mask so it can be reused + fAACache.reset(); + + const GrTextureDesc desc = { + kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit, + SkScalarCeilToInt(bounds.width()), + SkScalarCeilToInt(bounds.height()), + kAlpha_8_GrPixelConfig, + 0 // samples + }; + + fAACache.acquireMask(clipIn, desc, bounds); } -void GrClipMaskManager::getAccum(GrGpu* gpu, - const GrRect& bounds, - 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() >= bounds.width() && - fAACache.getLastMaskHeight() >= bounds.height()) { - // we can just reuse the existing texture - *accum = fAACache.detachLastMask(); - fAACache.reset(); - } else { - const GrTextureDesc desc = { - kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit, - SkScalarCeilToInt(bounds.width()), - SkScalarCeilToInt(bounds.height()), - kAlpha_8_GrPixelConfig, - 0 // samples - }; - - *accum = gpu->createTexture(desc, NULL, 0); - } - - GrAssert(1 == (*accum)->getRefCnt()); -} - - //////////////////////////////////////////////////////////////////////////////// // Shared preamble between gpu and SW-only AA clip mask creation paths. // Handles caching, determination of clip mask bound & allocation (if needed) @@ -429,8 +422,7 @@ void GrClipMaskManager::getAccum(GrGpu* gpu, bool GrClipMaskManager::clipMaskPreamble(GrGpu* gpu, const GrClip& clipIn, GrTexture** result, - GrRect *resultBounds, - GrTexture** maskStorage) { + GrRect *resultBounds) { GrDrawState* origDrawState = gpu->drawState(); GrAssert(origDrawState->isClipState()); @@ -441,7 +433,6 @@ bool GrClipMaskManager::clipMaskPreamble(GrGpu* gpu, rtRect.setLTRB(0, 0, GrIntToScalar(rt->width()), GrIntToScalar(rt->height())); - // unlike the stencil path the alpha path is not bound to the size of the // render target - determine the minimum size required for the mask GrRect bounds; @@ -477,7 +468,8 @@ bool GrClipMaskManager::clipMaskPreamble(GrGpu* gpu, return true; } - this->getAccum(gpu, bounds, maskStorage); + this->setupCache(clipIn, bounds); + *resultBounds = bounds; return false; } @@ -489,19 +481,17 @@ bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, GrTexture** result, GrRect *resultBounds) { - GrTexture* accum = NULL; - if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds, &accum)) { + if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) { return true; } + GrTexture* accum = fAACache.getLastMask(); if (NULL == accum) { fClipMaskInAlpha = false; + fAACache.reset(); return false; } - GrRect newRTBounds; - newRTBounds.setLTRB(0, 0, resultBounds->width(), resultBounds->height()); - GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit); GrDrawState* drawState = gpu->drawState(); @@ -528,7 +518,7 @@ bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, clear(gpu, accum, clearToInside ? 0xffffffff : 0x00000000); - GrTexture* temp = NULL; + GrAutoScratchTexture temp; // walk through each clip element and perform its set op for (int c = start; c < count; ++c) { @@ -555,18 +545,18 @@ bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, continue; } - get_temp(gpu, *resultBounds, &temp); - if (NULL == temp) { + getTemp(*resultBounds, &temp); + if (NULL == temp.texture()) { fClipMaskInAlpha = false; - SkSafeUnref(accum); + fAACache.reset(); return false; } // clear the temp target & draw into it - clear(gpu, temp, 0x00000000); + clear(gpu, temp.texture(), 0x00000000); setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op); - this->drawClipShape(gpu, temp, clipIn, c); + this->drawClipShape(gpu, temp.texture(), clipIn, c); // TODO: rather than adding these two translations here // compute the bounding box needed to render the texture @@ -582,7 +572,7 @@ bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, // Now draw into the accumulator using the real operation // and the temp buffer as a texture setup_boolean_blendcoeffs(drawState, op); - this->drawTexture(gpu, accum, newRTBounds, temp); + this->drawTexture(gpu, accum, temp.texture()); if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) { GrMatrix m; @@ -600,10 +590,7 @@ bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu, } } - fAACache.set(clipIn, accum, *resultBounds); *result = accum; - SkSafeUnref(accum); // fAACache still has a ref to accum - SkSafeUnref(temp); return true; } @@ -784,13 +771,14 @@ bool GrClipMaskManager::createSoftwareClipMask(GrGpu* gpu, GrTexture** result, GrRect *resultBounds) { - GrTexture* accum = NULL; - if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds, &accum)) { + if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) { return true; } + GrTexture* accum = fAACache.getLastMask(); if (NULL == accum) { fClipMaskInAlpha = false; + fAACache.reset(); return false; } @@ -819,9 +807,7 @@ bool GrClipMaskManager::createSoftwareClipMask(GrGpu* gpu, // TODO: need to get pixels out of SkRasterClip & into the texture! #endif - fAACache.set(clipIn, accum, *resultBounds); *result = accum; - SkSafeUnref(accum); // fAACache still has a ref to accum return true; } @@ -841,7 +827,8 @@ GrPathRenderer* GrClipMaskManager::getClipPathRenderer(GrGpu* gpu, } //////////////////////////////////////////////////////////////////////////////// -void GrClipMaskManager::freeResources() { +void GrClipMaskManager::releaseResources() { // in case path renderer has any GrResources, start from scratch GrSafeSetNull(fPathRendererChain); + fAACache.releaseResources(); } diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h index 5ab189d50e..c87bb7c32a 100644 --- a/src/gpu/GrClipMaskManager.h +++ b/src/gpu/GrClipMaskManager.h @@ -16,6 +16,7 @@ #include "SkRefCnt.h" #include "GrTexture.h" #include "SkDeque.h" +#include "GrContext.h" class GrGpu; class GrPathRenderer; @@ -44,7 +45,8 @@ struct ScissoringSettings { class GrClipMaskCache : public GrNoncopyable { public: GrClipMaskCache() - : fStack(sizeof(GrClipStackFrame)) { + : fContext(NULL) + , fStack(sizeof(GrClipStackFrame)) { // We need an initial frame to capture the clip state prior to // any pushes new (fStack.push_back()) GrClipStackFrame(); @@ -68,9 +70,9 @@ public: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); - if (back->fLastMask && - back->fLastMask->width() >= width && - back->fLastMask->height() >= height && + if (back->fLastMask.texture() && + back->fLastMask.texture()->width() >= width && + back->fLastMask.texture()->height() >= height && clip == back->fLastClip) { return true; } @@ -78,21 +80,6 @@ public: return false; } - void set(const GrClip& clip, GrTexture* mask, const GrRect& bound) { - - if (fStack.empty()) { - GrAssert(false); - return; - } - - GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); - - back->fLastClip = clip; - SkSafeRef(mask); - back->fLastMask.reset(mask); - back->fLastBound = bound; - } - void reset() { if (fStack.empty()) { GrAssert(false); @@ -147,7 +134,7 @@ public: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); - return back->fLastMask.get(); + return back->fLastMask.texture(); } const GrTexture* getLastMask() const { @@ -159,19 +146,21 @@ public: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); - return back->fLastMask.get(); + return back->fLastMask.texture(); } - GrTexture* detachLastMask() { + void acquireMask(const GrClip& clip, + const GrTextureDesc& desc, + const GrRect& bound) { if (fStack.empty()) { GrAssert(false); - return NULL; + return; } GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); - return back->fLastMask.detach(); + back->acquireMask(fContext, clip, desc, bound); } int getLastMaskWidth() const { @@ -183,11 +172,11 @@ public: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); - if (NULL == back->fLastMask.get()) { + if (NULL == back->fLastMask.texture()) { return -1; } - return back->fLastMask.get()->width(); + return back->fLastMask.texture()->width(); } int getLastMaskHeight() const { @@ -199,11 +188,11 @@ public: GrClipStackFrame* back = (GrClipStackFrame*) fStack.back(); - if (NULL == back->fLastMask.get()) { + if (NULL == back->fLastMask.texture()) { return -1; } - return back->fLastMask.get()->height(); + return back->fLastMask.texture()->height(); } void getLastBound(GrRect* bound) const { @@ -219,6 +208,24 @@ public: *bound = back->fLastBound; } + void setContext(GrContext* context) { + fContext = context; + } + + GrContext* getContext() { + return fContext; + } + + void releaseResources() { + + SkDeque::F2BIter iter(fStack); + for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next(); + frame != NULL; + frame = (GrClipStackFrame*) iter.next()) { + frame->reset(); + } + } + protected: private: struct GrClipStackFrame { @@ -227,22 +234,39 @@ private: reset(); } + void acquireMask(GrContext* context, + const GrClip& clip, + const GrTextureDesc& desc, + const GrRect& bound) { + + fLastClip = clip; + + fLastMask.set(context, desc); + + fLastBound = bound; + } + void reset () { fLastClip.setEmpty(); - fLastMask.reset(NULL); + + const GrTextureDesc desc = { kNone_GrTextureFlags, 0, 0, + kUnknown_GrPixelConfig, 0 }; + + fLastMask.set(NULL, desc); fLastBound.setEmpty(); } GrClip fLastClip; // The mask's width & height values are used in setupDrawStateAAClip to // correctly scale the uvs for geometry drawn with this mask - SkAutoTUnref fLastMask; + GrAutoScratchTexture fLastMask; // fLastBound stores the bounding box of the clip mask in canvas // space. The left and top fields are used to offset the uvs for // geometry drawn with this mask (in setupDrawStateAAClip) GrRect fLastBound; }; + GrContext* fContext; SkDeque fStack; typedef GrNoncopyable INHERITED; @@ -268,7 +292,7 @@ public: const GrClip& clip, ScissoringSettings* scissorSettings); - void freeResources(); + void releaseResources(); bool isClipInStencil() const { return fClipMaskInStencil; } bool isClipInAlpha() const { return fClipMaskInAlpha; } @@ -277,6 +301,10 @@ public: fClipMaskInStencil = false; } + void setContext(GrContext* context) { + fAACache.setContext(context); + } + protected: private: bool fClipMaskInStencil; // is the clip mask in the stencil buffer? @@ -302,8 +330,7 @@ private: bool clipMaskPreamble(GrGpu* gpu, const GrClip& clipIn, GrTexture** result, - GrRect *resultBounds, - GrTexture** maskStorage); + GrRect *resultBounds); bool drawPath(GrGpu* gpu, const SkPath& path, @@ -317,10 +344,12 @@ private: void drawTexture(GrGpu* gpu, GrTexture* target, - const GrRect& rect, GrTexture* texture); - void getAccum(GrGpu* gpu, const GrRect& bounds, GrTexture** accum); + void getTemp(const GrRect& bounds, GrAutoScratchTexture* temp); + + void setupCache(const GrClip& clip, + const GrRect& bounds); // determines the path renderer used to draw a clip path element. GrPathRenderer* getClipPathRenderer(GrGpu* gpu, diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index a5c7284ce8..4839e4f045 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -66,6 +66,8 @@ GrGpu::~GrGpu() { void GrGpu::abandonResources() { + fClipMaskManager.releaseResources(); + while (NULL != fResourceHead) { fResourceHead->abandon(); } @@ -79,12 +81,12 @@ void GrGpu::abandonResources() { fVertexPool = NULL; delete fIndexPool; fIndexPool = NULL; - - fClipMaskManager.freeResources(); } void GrGpu::releaseResources() { + fClipMaskManager.releaseResources(); + while (NULL != fResourceHead) { fResourceHead->release(); } @@ -98,8 +100,6 @@ void GrGpu::releaseResources() { fVertexPool = NULL; delete fIndexPool; fIndexPool = NULL; - - fClipMaskManager.freeResources(); } void GrGpu::insertResource(GrResource* resource) { diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index de14935e7f..aeb51f829a 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -87,6 +87,7 @@ public: void setContext(GrContext* context) { GrAssert(NULL == fContext); fContext = context; + fClipMaskManager.setContext(context); } GrContext* getContext() { return fContext; } const GrContext* getContext() const { return fContext; } diff --git a/tests/ClipCacheTest.cpp b/tests/ClipCacheTest.cpp index 93c6aebee7..1fc5d45b8f 100644 --- a/tests/ClipCacheTest.cpp +++ b/tests/ClipCacheTest.cpp @@ -61,6 +61,8 @@ static void test_cache(skiatest::Reporter* reporter, GrContext* context) { GrClipMaskCache cache; + cache.setContext(context); + GrClip emptyClip; emptyClip.setEmpty(); @@ -77,25 +79,32 @@ static void test_cache(skiatest::Reporter* reporter, GrContext* context) { GrClip clip1; clip1.setFromRect(bound1); - SkAutoTUnref texture(createTexture(context)); - REPORTER_ASSERT(reporter, texture.get()); + const GrTextureDesc desc = { + kRenderTarget_GrTextureFlagBit, + X_SIZE, + Y_SIZE, + kSkia8888_PM_GrPixelConfig, + 0 + }; - if (NULL == texture.get()) { + cache.acquireMask(clip1, desc, bound1); + + GrTexture* texture1 = cache.getLastMask(); + REPORTER_ASSERT(reporter, texture1); + if (NULL == texture1) { return; } - cache.set(clip1, texture.get(), bound1); - // check that the set took - check_state(reporter, cache, clip1, texture.get(), bound1); - REPORTER_ASSERT(reporter, 2 == texture.get()->getRefCnt()); + check_state(reporter, cache, clip1, texture1, bound1); + REPORTER_ASSERT(reporter, 1 == texture1->getRefCnt()); // push the state cache.push(); // verify that the pushed state is initially empty check_state(reporter, cache, emptyClip, NULL, emptyBound); - REPORTER_ASSERT(reporter, 2 == texture.get()->getRefCnt()); + REPORTER_ASSERT(reporter, 1 == texture1->getRefCnt()); // modify the new state GrRect bound2; @@ -105,11 +114,18 @@ static void test_cache(skiatest::Reporter* reporter, GrContext* context) { clip2.setEmpty(); clip2.setFromRect(bound2); - cache.set(clip2, texture.get(), bound2); + cache.acquireMask(clip2, desc, bound2); + + GrTexture* texture2 = cache.getLastMask(); + REPORTER_ASSERT(reporter, texture2); + if (NULL == texture2) { + return; + } // check that the changes took - check_state(reporter, cache, clip2, texture.get(), bound2); - REPORTER_ASSERT(reporter, 3 == texture.get()->getRefCnt()); + check_state(reporter, cache, clip2, texture2, bound2); + REPORTER_ASSERT(reporter, 1 == texture1->getRefCnt()); + REPORTER_ASSERT(reporter, 1 == texture2->getRefCnt()); // check to make sure canReuse works REPORTER_ASSERT(reporter, cache.canReuse(clip2, 10, 10)); @@ -119,15 +135,17 @@ static void test_cache(skiatest::Reporter* reporter, GrContext* context) { cache.pop(); // verify that the old state is restored - check_state(reporter, cache, clip1, texture.get(), bound1); - REPORTER_ASSERT(reporter, 2 == texture.get()->getRefCnt()); + check_state(reporter, cache, clip1, texture1, bound1); + REPORTER_ASSERT(reporter, 1 == texture1->getRefCnt()); + REPORTER_ASSERT(reporter, 1 == texture2->getRefCnt()); // manually clear the state cache.reset(); // verify it is now empty check_state(reporter, cache, emptyClip, NULL, emptyBound); - REPORTER_ASSERT(reporter, 1 == texture.get()->getRefCnt()); + REPORTER_ASSERT(reporter, 1 == texture1->getRefCnt()); + REPORTER_ASSERT(reporter, 1 == texture2->getRefCnt()); // pop again - so there is no state cache.pop(); @@ -137,7 +155,8 @@ static void test_cache(skiatest::Reporter* reporter, GrContext* context) { // only do in release since it generates asserts in debug check_state(reporter, cache, emptyClip, NULL, emptyBound); #endif - REPORTER_ASSERT(reporter, 1 == texture.get()->getRefCnt()); + REPORTER_ASSERT(reporter, 1 == texture1->getRefCnt()); + REPORTER_ASSERT(reporter, 1 == texture2->getRefCnt()); } ////////////////////////////////////////////////////////////////////////////////