Add GrResourceCache2.

Currently it just replaces GrGpu as the owner of the linked list of resources.

Committed: https://skia.googlesource.com/skia/+/94ce9ac8624dbb45656b8f5c992fad9c9ff3ee5f

R=mtklein@google.com, robertphillips@google.com

Author: bsalomon@google.com

Review URL: https://codereview.chromium.org/481443002
This commit is contained in:
bsalomon 2014-08-21 13:02:13 -07:00 committed by Commit bot
parent 78fc1dbed0
commit c8dc1f74b6
17 changed files with 166 additions and 117 deletions

View File

@ -114,6 +114,8 @@
'<(skia_src_path)/gpu/GrReducedClip.h',
'<(skia_src_path)/gpu/GrResourceCache.cpp',
'<(skia_src_path)/gpu/GrResourceCache.h',
'<(skia_src_path)/gpu/GrResourceCache2.cpp',
'<(skia_src_path)/gpu/GrResourceCache2.h',
'<(skia_src_path)/gpu/GrStencil.cpp',
'<(skia_src_path)/gpu/GrStencil.h',
'<(skia_src_path)/gpu/GrStencilAndCoverPathRenderer.cpp',

View File

@ -35,6 +35,7 @@ class GrPath;
class GrPathRenderer;
class GrResourceEntry;
class GrResourceCache;
class GrResourceCache2;
class GrStencilBuffer;
class GrTestTarget;
class GrTextContext;
@ -926,6 +927,7 @@ public:
GrDrawTarget* getTextTarget();
const GrIndexBuffer* getQuadIndexBuffer() const;
GrAARectRenderer* getAARectRenderer() { return fAARectRenderer; }
GrResourceCache2* getResourceCache2() { return fResourceCache2; }
// Called by tests that draw directly to the context via GrDrawTarget
void getTestTarget(GrTestTarget*);
@ -973,6 +975,7 @@ private:
GrDrawState* fDrawState;
GrResourceCache* fResourceCache;
GrResourceCache2* fResourceCache2;
GrFontCache* fFontCache;
SkAutoTDelete<GrLayerCache> fLayerCache;

View File

@ -12,6 +12,7 @@
#include "SkTInternalLList.h"
class GrResourceCacheEntry;
class GrResourceCache2;
class GrGpu;
class GrContext;
@ -118,12 +119,13 @@ private:
static uint32_t CreateUniqueID();
// We're in an internal doubly linked list
// We're in an internal doubly linked list owned by GrResourceCache2
SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrGpuResource);
GrGpu* fGpu; // not reffed. The GrGpu can be deleted while there
// are still live GrGpuResources. It will call
// release() on all such objects in its destructor.
// This is not ref'ed but abandon() or release() will be called before the GrGpu object
// is destroyed. Those calls set will this to NULL.
GrGpu* fGpu;
enum Flags {
/**
* This object wraps a GPU object given to us by the user.

View File

@ -41,6 +41,7 @@ public:
// We could reuse the mask if bounds is a subset of last bounds. We'd have to communicate
// an offset to the caller.
if (back->fLastMask.texture() &&
!back->fLastMask.texture()->wasDestroyed() &&
back->fLastBound == bounds &&
back->fLastClipGenID == clipGenID) {
return true;
@ -179,8 +180,8 @@ public:
return fContext;
}
void releaseResources() {
// TODO: Remove this when we hold cache keys instead of refs to textures.
void purgeResources() {
SkDeque::F2BIter iter(fStack);
for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
frame != NULL;
@ -219,7 +220,8 @@ private:
int32_t fLastClipGenID;
// The mask's width & height values are used by GrClipMaskManager to correctly scale the
// texture coords for the geometry drawn with this mask.
// texture coords for the geometry drawn with this mask. TODO: This should be a cache key
// and not a hard ref to a texture.
GrAutoScratchTexture fLastMask;
// fLastBound stores the bounding box of the clip mask in clip-stack space. This rect is
// used by GrClipMaskManager to position a rect and compute texture coords for the mask.

View File

@ -1112,8 +1112,8 @@ GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID,
}
////////////////////////////////////////////////////////////////////////////////
void GrClipMaskManager::releaseResources() {
fAACache.releaseResources();
void GrClipMaskManager::purgeResources() {
fAACache.purgeResources();
}
void GrClipMaskManager::setGpu(GrGpu* gpu) {

View File

@ -53,7 +53,11 @@ public:
bool setupClipping(const GrClipData* clipDataIn, GrDrawState::AutoRestoreEffects*,
const SkRect* devBounds);
void releaseResources();
/**
* Purge resources to free up memory. TODO: This class shouldn't hold any long lived refs
* which will allow ResourceCache2 to automatically purge anything this class has created.
*/
void purgeResources();
bool isClipInStencil() const {
return kStencil_ClipMaskType == fCurrClipMaskType;

View File

@ -25,6 +25,7 @@
#include "GrPathRenderer.h"
#include "GrPathUtils.h"
#include "GrResourceCache.h"
#include "GrResourceCache2.h"
#include "GrSoftwarePathRenderer.h"
#include "GrStencilBuffer.h"
#include "GrStencilAndCoverTextContext.h"
@ -108,6 +109,7 @@ GrContext::GrContext(const Options& opts) : fOptions(opts) {
fPathRendererChain = NULL;
fSoftwarePathRenderer = NULL;
fResourceCache = NULL;
fResourceCache2 = NULL;
fFontCache = NULL;
fDrawBuffer = NULL;
fDrawBufferVBAllocPool = NULL;
@ -133,6 +135,7 @@ bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
fResourceCache = SkNEW_ARGS(GrResourceCache, (MAX_RESOURCE_CACHE_COUNT,
MAX_RESOURCE_CACHE_BYTES));
fResourceCache->setOverbudgetCallback(OverbudgetCB, this);
fResourceCache2 = SkNEW(GrResourceCache2);
fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
@ -161,10 +164,8 @@ GrContext::~GrContext() {
(*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
}
// Since the gpu can hold scratch textures, give it a chance to let go
// of them before freeing the texture cache
fGpu->purgeResources();
delete fResourceCache2;
fResourceCache2 = NULL;
delete fResourceCache;
fResourceCache = NULL;
delete fFontCache;
@ -184,7 +185,9 @@ GrContext::~GrContext() {
void GrContext::abandonContext() {
// abandon first to so destructors
// don't try to free the resources in the API.
fGpu->abandonResources();
fResourceCache2->abandonAll();
fGpu->contextAbandonded();
// a path renderer may be holding onto resources that
// are now unusable
@ -207,7 +210,6 @@ void GrContext::abandonContext() {
fFontCache->freeAll();
fLayerCache->freeAll();
fGpu->markContextDirty();
}
void GrContext::resetContext(uint32_t state) {
@ -218,6 +220,9 @@ void GrContext::freeGpuResources() {
this->flush();
fGpu->purgeResources();
if (NULL != fDrawBuffer) {
fDrawBuffer->purgeResources();
}
fAARectRenderer->reset();
fOvalRenderer->reset();
@ -540,6 +545,15 @@ void GrContext::addExistingTextureToCache(GrTexture* texture) {
}
void GrContext::unlockScratchTexture(GrTexture* texture) {
if (texture->wasDestroyed()) {
if (texture->getCacheEntry()->key().isScratch()) {
// This texture was detached from the cache but the cache still had a ref to it but
// not a pointer to it.
texture->unref();
}
return;
}
ASSERT_OWNED_RESOURCE(texture);
SkASSERT(NULL != texture->getCacheEntry());

View File

@ -50,18 +50,6 @@ GrGpu::GrGpu(GrContext* context)
}
GrGpu::~GrGpu() {
this->releaseResources();
}
void GrGpu::abandonResources() {
fClipMaskManager.releaseResources();
while (NULL != fObjectList.head()) {
fObjectList.head()->abandon();
}
SkASSERT(NULL == fQuadIndexBuffer || fQuadIndexBuffer->wasDestroyed());
SkSafeSetNull(fQuadIndexBuffer);
delete fVertexPool;
fVertexPool = NULL;
@ -69,42 +57,7 @@ void GrGpu::abandonResources() {
fIndexPool = NULL;
}
void GrGpu::releaseResources() {
fClipMaskManager.releaseResources();
while (NULL != fObjectList.head()) {
fObjectList.head()->release();
}
SkASSERT(NULL == fQuadIndexBuffer || fQuadIndexBuffer->wasDestroyed());
SkSafeSetNull(fQuadIndexBuffer);
delete fVertexPool;
fVertexPool = NULL;
delete fIndexPool;
fIndexPool = NULL;
}
void GrGpu::insertObject(GrGpuResource* object) {
SkASSERT(NULL != object);
SkASSERT(this == object->getGpu());
fObjectList.addToHead(object);
}
void GrGpu::removeObject(GrGpuResource* object) {
SkASSERT(NULL != object);
SkASSERT(this == object->getGpu());
fObjectList.remove(object);
}
void GrGpu::unimpl(const char msg[]) {
#ifdef SK_DEBUG
GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
#endif
}
void GrGpu::contextAbandonded() {}
////////////////////////////////////////////////////////////////////////////////
@ -318,7 +271,8 @@ static inline void fill_indices(uint16_t* indices, int quadCount) {
}
const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
if (NULL == fQuadIndexBuffer) {
if (NULL == fQuadIndexBuffer || fQuadIndexBuffer->wasDestroyed()) {
SkSafeUnref(fQuadIndexBuffer);
static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
GrGpu* me = const_cast<GrGpu*>(this);
fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);

View File

@ -59,6 +59,12 @@ public:
return fPathRendering.get();
}
// Called by GrContext when the underlying backend context has been destroyed.
// GrGpu should use this to ensure that no backend API calls will be made from
// here onward, including in its destructor. Subclasses should call
// INHERITED::contextAbandonded() if they override this.
virtual void contextAbandonded();
/**
* The GrGpu object normally assumes that no outsider is setting state
* within the underlying 3D API's context/device/whatever. This call informs
@ -253,30 +259,6 @@ public:
GrPixelConfig config, const void* buffer,
size_t rowBytes);
/**
* Called to tell GrGpu that all GrGpuResources have been lost and should
* be abandoned. Overrides must call INHERITED::abandonResources().
*/
virtual void abandonResources();
/**
* Called to tell GrGpu to release all GrGpuResources. Overrides must call
* INHERITED::releaseResources().
*/
void releaseResources();
/**
* Add object to list of objects. Should only be called by GrGpuResource.
* @param resource the resource to add.
*/
void insertObject(GrGpuResource* object);
/**
* Remove object from list of objects. Should only be called by GrGpuResource.
* @param resource the resource to remove.
*/
void removeObject(GrGpuResource* object);
// GrDrawTarget overrides
virtual void clear(const SkIRect* rect,
GrColor color,
@ -286,7 +268,7 @@ public:
virtual void purgeResources() SK_OVERRIDE {
// The clip mask manager can rebuild all its clip masks so just
// get rid of them all.
fClipMaskManager.releaseResources();
fClipMaskManager.purgeResources();
}
// After the client interacts directly with the 3D context state the GrGpu
@ -523,7 +505,6 @@ private:
enum {
kPreallocGeomPoolStateStackCnt = 4,
};
typedef SkTInternalLList<GrGpuResource> ObjectList;
SkSTArray<kPreallocGeomPoolStateStackCnt, GeometryPoolState, true> fGeomPoolStateStack;
ResetTimestamp fResetTimestamp;
uint32_t fResetBits;
@ -534,9 +515,6 @@ private:
int fIndexPoolUseCnt;
// these are mutable so they can be created on-demand
mutable GrIndexBuffer* fQuadIndexBuffer;
// Used to abandon/release all resources created by this GrGpu. TODO: Move this
// functionality to GrResourceCache.
ObjectList fObjectList;
typedef GrDrawTarget INHERITED;
};

View File

@ -8,19 +8,27 @@
#include "GrGpuResource.h"
#include "GrResourceCache2.h"
#include "GrGpu.h"
static inline GrResourceCache2* get_resource_cache2(GrGpu* gpu) {
SkASSERT(NULL != gpu);
SkASSERT(NULL != gpu->getContext());
SkASSERT(NULL != gpu->getContext()->getResourceCache2());
return gpu->getContext()->getResourceCache2();
}
GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped)
: fRefCnt(1)
: fGpu(gpu)
, fRefCnt(1)
, fCacheEntry(NULL)
, fUniqueID(CreateUniqueID()) {
fGpu = gpu;
if (isWrapped) {
fFlags = kWrapped_FlagBit;
} else {
fFlags = 0;
}
fGpu->insertObject(this);
get_resource_cache2(fGpu)->insertResource(this);
}
GrGpuResource::~GrGpuResource() {
@ -32,7 +40,7 @@ GrGpuResource::~GrGpuResource() {
void GrGpuResource::release() {
if (NULL != fGpu) {
this->onRelease();
fGpu->removeObject(this);
get_resource_cache2(fGpu)->removeResource(this);
fGpu = NULL;
}
}
@ -40,7 +48,7 @@ void GrGpuResource::release() {
void GrGpuResource::abandon() {
if (NULL != fGpu) {
this->onAbandon();
fGpu->removeObject(this);
get_resource_cache2(fGpu)->removeResource(this);
fGpu = NULL;
}
}

View File

@ -112,7 +112,7 @@ void GrLayerCache::freeAll() {
fAtlas.free();
// GrLayerCache always assumes an atlas exists so recreate it. The atlas
// lazily allocates a replacement texture so reallocating a new
// atlas here won't disrupt a GrContext::contextDestroyed or freeGpuResources.
// atlas here won't disrupt a GrContext::abandonContext or freeGpuResources.
// TODO: Make GrLayerCache lazily allocate the atlas manager?
this->initAtlas();
}

View File

@ -267,7 +267,7 @@ void GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) {
void GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) {
// If the resource went invalid while it was detached then purge it
// This can happen when a 3D context was lost,
// the client called GrContext::contextDestroyed() to notify Gr,
// the client called GrContext::abandonContext() to notify Gr,
// and then later an SkGpuDevice's destructor releases its backing
// texture (which was invalidated at contextDestroyed time).
// TODO: Safely delete the GrResourceCacheEntry as well.

View File

@ -0,0 +1,47 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrResourceCache2.h"
#include "GrGpuResource.h"
GrResourceCache2::~GrResourceCache2() {
this->releaseAll();
}
void GrResourceCache2::insertResource(GrGpuResource* resource) {
SkASSERT(NULL != resource);
SkASSERT(!resource->wasDestroyed());
fResources.addToHead(resource);
++fCount;
}
void GrResourceCache2::removeResource(GrGpuResource* resource) {
fResources.remove(resource);
--fCount;
}
void GrResourceCache2::abandonAll() {
while (GrGpuResource* head = fResources.head()) {
SkASSERT(!head->wasDestroyed());
head->abandon();
// abandon should have already removed this from the list.
SkASSERT(head != fResources.head());
}
SkASSERT(!fCount);
}
void GrResourceCache2::releaseAll() {
while (GrGpuResource* head = fResources.head()) {
SkASSERT(!head->wasDestroyed());
head->release();
// release should have already removed this from the list.
SkASSERT(head != fResources.head());
}
SkASSERT(!fCount);
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrResourceCache2_DEFINED
#define GrResourceCache2_DEFINED
#include "GrTypes.h"
#include "SkTInternalLList.h"
class GrGpuResource;
/**
* Eventual replacement for GrResourceCache. Currently it simply holds a list
* of all GrGpuResource objects for a GrContext. It is used to invalidate all
* the resources when necessary.
*/
class GrResourceCache2 {
public:
GrResourceCache2() : fCount(0) {};
~GrResourceCache2();
void insertResource(GrGpuResource* resource);
void removeResource(GrGpuResource* resource);
void abandonAll();
void releaseAll();
private:
int fCount;
SkTInternalLList<GrGpuResource> fResources;
};
#endif

View File

@ -164,9 +164,15 @@ GrGpuGL::~GrGpuGL() {
// This must be called by before the GrDrawTarget destructor
this->releaseGeometry();
// This subclass must do this before the base class destructor runs
// since we will unref the GrGLInterface.
this->releaseResources();
}
void GrGpuGL::contextAbandonded() {
INHERITED::contextAbandonded();
fProgramCache->abandon();
fHWProgramID = 0;
if (this->glCaps().pathRenderingSupport()) {
this->glPathRendering()->abandonGpuResources();
}
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -30,6 +30,8 @@ public:
GrGpuGL(const GrGLContext& ctx, GrContext* context);
virtual ~GrGpuGL();
virtual void contextAbandonded() SK_OVERRIDE;
const GrGLContext& glContext() const { return fGLContext; }
const GrGLInterface* glInterface() const { return fGLContext.interface(); }
@ -75,8 +77,6 @@ public:
virtual void initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) SK_OVERRIDE;
virtual void abandonResources() SK_OVERRIDE;
// These functions should be used to bind GL objects. They track the GL state and skip redundant
// bindings. Making the equivalent glBind calls directly will confuse the state tracking.
void bindVertexArray(GrGLuint id) {

View File

@ -199,17 +199,6 @@ GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgramDesc& desc,
////////////////////////////////////////////////////////////////////////////////
void GrGpuGL::abandonResources(){
INHERITED::abandonResources();
fProgramCache->abandon();
fHWProgramID = 0;
if (this->glCaps().pathRenderingSupport()) {
this->glPathRendering()->abandonGpuResources();
}
}
////////////////////////////////////////////////////////////////////////////////
#define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstCopy) {