Make GrResourceCache2 responsible for calling release, abandon, and ~.
BUG=skia:2889 TBR=robertphillips@google.com NOTRY=true Review URL: https://codereview.chromium.org/729683002
This commit is contained in:
parent
85588344c3
commit
12299ab7a1
@ -33,8 +33,6 @@ public:
|
||||
this->registerWithCache();
|
||||
}
|
||||
|
||||
virtual ~StencilResource() { this->release(); }
|
||||
|
||||
static GrResourceKey ComputeKey(int width, int height, int sampleCnt) {
|
||||
return GrStencilBuffer::ComputeKey(width, height, sampleCnt);
|
||||
}
|
||||
@ -58,8 +56,6 @@ public:
|
||||
this->registerWithCache();
|
||||
}
|
||||
|
||||
virtual ~TextureResource() { this->release(); }
|
||||
|
||||
static GrResourceKey ComputeKey(const GrSurfaceDesc& desc) {
|
||||
GrCacheID::Key key;
|
||||
memset(&key, 0, sizeof(key));
|
||||
|
@ -56,21 +56,20 @@ public:
|
||||
this->didUnref();
|
||||
}
|
||||
|
||||
bool isPurgable() const { return this->reffedOnlyByCache() && !this->internalHasPendingIO(); }
|
||||
bool reffedOnlyByCache() const { return 1 == fRefCnt; }
|
||||
|
||||
void validate() const {
|
||||
#ifdef SK_DEBUG
|
||||
SkASSERT(fRefCnt >= 0);
|
||||
SkASSERT(fPendingReads >= 0);
|
||||
SkASSERT(fPendingWrites >= 0);
|
||||
SkASSERT(fRefCnt + fPendingReads + fPendingWrites > 0);
|
||||
SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { }
|
||||
|
||||
bool isPurgable() const { return !this->internalHasRef() && !this->internalHasPendingIO(); }
|
||||
|
||||
bool internalHasPendingRead() const { return SkToBool(fPendingReads); }
|
||||
bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); }
|
||||
bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); }
|
||||
@ -102,14 +101,8 @@ private:
|
||||
|
||||
private:
|
||||
void didUnref() const {
|
||||
if (0 == fPendingReads && 0 == fPendingWrites) {
|
||||
if (0 == fRefCnt) {
|
||||
// Must call derived destructor since this is not a virtual class.
|
||||
SkDELETE(static_cast<const DERIVED*>(this));
|
||||
} else if (1 == fRefCnt) {
|
||||
// The one ref is the cache's
|
||||
static_cast<const DERIVED*>(this)->notifyIsPurgable();
|
||||
}
|
||||
if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) {
|
||||
static_cast<const DERIVED*>(this)->notifyIsPurgable();
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,18 +124,6 @@ class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(GrGpuResource)
|
||||
|
||||
/**
|
||||
* Frees the object in the underlying 3D API. It must be safe to call this
|
||||
* when the object has been previously abandoned.
|
||||
*/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Removes references to objects in the underlying 3D API without freeing
|
||||
* them. Used when the API context has been torn down before the GrContext.
|
||||
*/
|
||||
void abandon();
|
||||
|
||||
/**
|
||||
* Tests whether a object has been abandoned or released. All objects will
|
||||
* be in this state after their creating GrContext is destroyed or has
|
||||
@ -203,10 +184,12 @@ protected:
|
||||
|
||||
GrGpu* getGpu() const { return fGpu; }
|
||||
|
||||
// Derived classes should always call their parent class' onRelease
|
||||
// and onAbandon methods in their overrides.
|
||||
virtual void onRelease() {};
|
||||
virtual void onAbandon() {};
|
||||
/** Overridden to free GPU resources in the backend API. */
|
||||
virtual void onRelease() { }
|
||||
/** Overridden to abandon any internal handles, ptrs, etc to backend API resources.
|
||||
This may be called when the underlying 3D context is no longer valid and so no
|
||||
backend API calls should be made. */
|
||||
virtual void onAbandon() { }
|
||||
|
||||
bool isWrapped() const { return kWrapped_FlagBit & fFlags; }
|
||||
|
||||
@ -223,6 +206,17 @@ protected:
|
||||
void setScratchKey(const GrResourceKey& scratchKey);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Frees the object in the underlying 3D API. Called by CacheAccess.
|
||||
*/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Removes references to objects in the underlying 3D API without freeing them.
|
||||
* Called by CacheAccess.
|
||||
*/
|
||||
void abandon();
|
||||
|
||||
virtual size_t onGpuMemorySize() const = 0;
|
||||
|
||||
// See comments in CacheAccess.
|
||||
|
@ -36,26 +36,24 @@ void GrGpuResource::registerWithCache() {
|
||||
}
|
||||
|
||||
GrGpuResource::~GrGpuResource() {
|
||||
// subclass should have released this.
|
||||
// The cache should have released or destroyed this resource.
|
||||
SkASSERT(this->wasDestroyed());
|
||||
}
|
||||
|
||||
void GrGpuResource::release() {
|
||||
if (fGpu) {
|
||||
this->onRelease();
|
||||
get_resource_cache2(fGpu)->resourceAccess().removeResource(this);
|
||||
fGpu = NULL;
|
||||
fGpuMemorySize = 0;
|
||||
}
|
||||
SkASSERT(fGpu);
|
||||
this->onRelease();
|
||||
get_resource_cache2(fGpu)->resourceAccess().removeResource(this);
|
||||
fGpu = NULL;
|
||||
fGpuMemorySize = 0;
|
||||
}
|
||||
|
||||
void GrGpuResource::abandon() {
|
||||
if (fGpu) {
|
||||
this->onAbandon();
|
||||
get_resource_cache2(fGpu)->resourceAccess().removeResource(this);
|
||||
fGpu = NULL;
|
||||
fGpuMemorySize = 0;
|
||||
}
|
||||
SkASSERT(fGpu);
|
||||
this->onAbandon();
|
||||
get_resource_cache2(fGpu)->resourceAccess().removeResource(this);
|
||||
fGpu = NULL;
|
||||
fGpuMemorySize = 0;
|
||||
}
|
||||
|
||||
const GrContext* GrGpuResource::getContext() const {
|
||||
@ -90,7 +88,7 @@ bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
|
||||
SkASSERT(!contentKey.isScratch());
|
||||
SkASSERT(this->internalHasRef());
|
||||
|
||||
if (fContentKeySet) {
|
||||
if (fContentKeySet || this->wasDestroyed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -105,8 +103,12 @@ bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
|
||||
}
|
||||
|
||||
void GrGpuResource::notifyIsPurgable() const {
|
||||
if (!this->wasDestroyed()) {
|
||||
get_resource_cache2(fGpu)->resourceAccess().notifyPurgable(this);
|
||||
if (this->wasDestroyed()) {
|
||||
// We've already been removed from the cache. Goodbye cruel world!
|
||||
SkDELETE(this);
|
||||
} else {
|
||||
GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
|
||||
get_resource_cache2(fGpu)->resourceAccess().notifyPurgable(mutableThis);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,26 @@ public:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the cache to delete the resource under normal circumstances.
|
||||
*/
|
||||
void release() {
|
||||
fResource->release();
|
||||
if (fResource->isPurgable()) {
|
||||
SkDELETE(fResource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the cache to delete the resource when the backend 3D context is no longer valid.
|
||||
*/
|
||||
void abandon() {
|
||||
fResource->abandon();
|
||||
if (fResource->isPurgable()) {
|
||||
SkDELETE(fResource);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CacheAccess(GrGpuResource* resource) : fResource(resource) { }
|
||||
CacheAccess(const CacheAccess& that) : fResource(that.fResource) { }
|
||||
|
@ -93,7 +93,6 @@ void GrResourceCache2::insertResource(GrGpuResource* resource) {
|
||||
SkASSERT(!this->isInCache(resource));
|
||||
SkASSERT(!fPurging);
|
||||
fResources.addToHead(resource);
|
||||
resource->ref();
|
||||
|
||||
++fCount;
|
||||
SkDEBUGCODE(fHighWaterCount = SkTMax(fCount, fHighWaterCount));
|
||||
@ -129,8 +128,7 @@ void GrResourceCache2::abandonAll() {
|
||||
SkASSERT(!fPurging);
|
||||
while (GrGpuResource* head = fResources.head()) {
|
||||
SkASSERT(!head->wasDestroyed());
|
||||
head->abandon();
|
||||
head->unref();
|
||||
head->cacheAccess().abandon();
|
||||
// abandon should have already removed this from the list.
|
||||
SkASSERT(head != fResources.head());
|
||||
}
|
||||
@ -145,8 +143,7 @@ void GrResourceCache2::releaseAll() {
|
||||
SkASSERT(!fPurging);
|
||||
while (GrGpuResource* head = fResources.head()) {
|
||||
SkASSERT(!head->wasDestroyed());
|
||||
head->release();
|
||||
head->unref();
|
||||
head->cacheAccess().release();
|
||||
// release should have already removed this from the list.
|
||||
SkASSERT(head != fResources.head());
|
||||
}
|
||||
@ -159,7 +156,7 @@ public:
|
||||
AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendingIO) { }
|
||||
|
||||
bool operator()(const GrGpuResource* resource) const {
|
||||
if (!resource->reffedOnlyByCache() || !resource->cacheAccess().isScratch()) {
|
||||
if (resource->internalHasRef() || !resource->cacheAccess().isScratch()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -224,7 +221,7 @@ void GrResourceCache2::makeResourceMRU(GrGpuResource* resource) {
|
||||
fResources.addToHead(resource);
|
||||
}
|
||||
|
||||
void GrResourceCache2::notifyPurgable(const GrGpuResource* resource) {
|
||||
void GrResourceCache2::notifyPurgable(GrGpuResource* resource) {
|
||||
SkASSERT(resource);
|
||||
SkASSERT(this->isInCache(resource));
|
||||
SkASSERT(resource->isPurgable());
|
||||
@ -239,25 +236,14 @@ void GrResourceCache2::notifyPurgable(const GrGpuResource* resource) {
|
||||
// Purge the resource if we're over budget
|
||||
bool overBudget = fCount > fMaxCount || fBytes > fMaxBytes;
|
||||
|
||||
// We should not be over budget here unless all resources are unpuragble.
|
||||
#ifdef SK_DEBUG
|
||||
if (overBudget) {
|
||||
ResourceList::Iter iter;
|
||||
GrGpuResource* r = iter.init(fResources, ResourceList::Iter::kHead_IterStart);
|
||||
for ( ; r; r = iter.next()) {
|
||||
SkASSERT(r == resource || !r->isPurgable());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Also purge if the resource has neither a valid scratch key nor a content key.
|
||||
bool noKey = !resource->cacheAccess().isScratch() &&
|
||||
(NULL == resource->cacheAccess().getContentKey());
|
||||
|
||||
if (overBudget || noKey) {
|
||||
SkDEBUGCODE(int beforeCount = fCount;)
|
||||
resource->unref();
|
||||
// We should at least have freed resource. It may have in turn freed other resources.
|
||||
resource->cacheAccess().release();
|
||||
// We should at least free this resource, perhaps dependent resources as well.
|
||||
SkASSERT(fCount < beforeCount);
|
||||
}
|
||||
|
||||
@ -295,7 +281,7 @@ void GrResourceCache2::internalPurgeAsNeeded() {
|
||||
while (resource) {
|
||||
GrGpuResource* prev = resourceIter.prev();
|
||||
if (resource->isPurgable()) {
|
||||
resource->unref();
|
||||
resource->cacheAccess().release();
|
||||
}
|
||||
resource = prev;
|
||||
if (fCount <= fMaxCount && fBytes <= fMaxBytes) {
|
||||
@ -331,8 +317,8 @@ void GrResourceCache2::purgeAllUnlocked() {
|
||||
while (resource) {
|
||||
GrGpuResource* prev = resourceIter.prev();
|
||||
if (resource->isPurgable()) {
|
||||
resource->unref();
|
||||
}
|
||||
resource->cacheAccess().release();
|
||||
}
|
||||
resource = prev;
|
||||
}
|
||||
|
||||
@ -387,8 +373,10 @@ void GrResourceCache2::validate() const {
|
||||
SkASSERT(content == fContentHash.count());
|
||||
SkASSERT(scratch + couldBeScratch == fScratchMap.count());
|
||||
|
||||
bool overBudget = bytes > fMaxBytes || count > fMaxCount;
|
||||
SkASSERT(!overBudget || locked == count || fPurging);
|
||||
// This assertion is not currently valid because we can be in recursive notifyIsPurgable()
|
||||
// calls. This will be fixed when subresource registration is explicit.
|
||||
// bool overBudget = bytes > fMaxBytes || count > fMaxCount;
|
||||
// SkASSERT(!overBudget || locked == count || fPurging);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -148,7 +148,7 @@ private:
|
||||
////
|
||||
void insertResource(GrGpuResource*);
|
||||
void removeResource(GrGpuResource*);
|
||||
void notifyPurgable(const GrGpuResource*);
|
||||
void notifyPurgable(GrGpuResource*);
|
||||
void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize);
|
||||
bool didSetContentKey(GrGpuResource*);
|
||||
void makeResourceMRU(GrGpuResource*);
|
||||
@ -241,7 +241,7 @@ private:
|
||||
/**
|
||||
* Called by GrGpuResources when they detects that they are newly purgable.
|
||||
*/
|
||||
void notifyPurgable(const GrGpuResource* resource) { fCache->notifyPurgable(resource); }
|
||||
void notifyPurgable(GrGpuResource* resource) { fCache->notifyPurgable(resource); }
|
||||
|
||||
/**
|
||||
* Called by GrGpuResources when their sizes change.
|
||||
|
@ -20,7 +20,6 @@ public:
|
||||
typedef GrGLBufferImpl::Desc Desc;
|
||||
|
||||
GrGLIndexBuffer(GrGpuGL* gpu, const Desc& desc);
|
||||
virtual ~GrGLIndexBuffer() { this->release(); }
|
||||
|
||||
GrGLuint bufferID() const { return fImpl.bufferID(); }
|
||||
size_t baseOffset() const { return fImpl.baseOffset(); }
|
||||
|
@ -143,10 +143,6 @@ GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path, const SkStrokeRec& stroke)
|
||||
this->registerWithCache();
|
||||
}
|
||||
|
||||
GrGLPath::~GrGLPath() {
|
||||
this->release();
|
||||
}
|
||||
|
||||
void GrGLPath::onRelease() {
|
||||
if (0 != fPathID && !this->isWrapped()) {
|
||||
static_cast<GrGpuGL*>(this->getGpu())->glPathRendering()->deletePaths(fPathID, 1);
|
||||
|
@ -28,7 +28,6 @@ public:
|
||||
const SkStrokeRec&);
|
||||
|
||||
GrGLPath(GrGpuGL* gpu, const SkPath& path, const SkStrokeRec& stroke);
|
||||
virtual ~GrGLPath();
|
||||
GrGLuint pathID() const { return fPathID; }
|
||||
|
||||
protected:
|
||||
|
@ -29,10 +29,6 @@ GrGLPathRange::GrGLPathRange(GrGpuGL* gpu,
|
||||
this->registerWithCache();
|
||||
}
|
||||
|
||||
GrGLPathRange::~GrGLPathRange() {
|
||||
this->release();
|
||||
}
|
||||
|
||||
void GrGLPathRange::onInitPath(int index, const SkPath& skPath) const {
|
||||
GrGpuGL* gpu = static_cast<GrGpuGL*>(this->getGpu());
|
||||
if (NULL == gpu) {
|
||||
|
@ -39,8 +39,6 @@ public:
|
||||
size_t gpuMemorySize,
|
||||
const SkStrokeRec&);
|
||||
|
||||
virtual ~GrGLPathRange();
|
||||
|
||||
GrGLuint basePathID() const { return fBasePathID; }
|
||||
|
||||
protected:
|
||||
|
@ -30,8 +30,6 @@ public:
|
||||
|
||||
GrGLRenderTarget(GrGpuGL*, const GrSurfaceDesc&, const IDDesc&);
|
||||
|
||||
virtual ~GrGLRenderTarget() { this->release(); }
|
||||
|
||||
void setViewport(const GrGLIRect& rect) { fViewport = rect; }
|
||||
const GrGLIRect& getViewport() const { return fViewport; }
|
||||
|
||||
|
@ -9,10 +9,6 @@
|
||||
#include "GrGLStencilBuffer.h"
|
||||
#include "GrGpuGL.h"
|
||||
|
||||
GrGLStencilBuffer::~GrGLStencilBuffer() {
|
||||
this->release();
|
||||
}
|
||||
|
||||
size_t GrGLStencilBuffer::onGpuMemorySize() const {
|
||||
uint64_t size = this->width();
|
||||
size *= this->height();
|
||||
|
@ -35,8 +35,6 @@ public:
|
||||
this->registerWithCache();
|
||||
}
|
||||
|
||||
virtual ~GrGLStencilBuffer();
|
||||
|
||||
GrGLuint renderbufferID() const {
|
||||
return fRenderbufferID;
|
||||
}
|
||||
|
@ -33,8 +33,6 @@ public:
|
||||
|
||||
GrGLTexture(GrGpuGL*, const GrSurfaceDesc&, const IDDesc&);
|
||||
|
||||
virtual ~GrGLTexture() { this->release(); }
|
||||
|
||||
virtual GrBackendObject getTextureHandle() const SK_OVERRIDE;
|
||||
|
||||
virtual void textureParamsModified() SK_OVERRIDE { fTexParams.invalidate(); }
|
||||
|
@ -34,8 +34,6 @@ public:
|
||||
this->registerWithCache();
|
||||
}
|
||||
|
||||
virtual ~GrGLTextureRenderTarget() { this->release(); }
|
||||
|
||||
protected:
|
||||
virtual void onAbandon() SK_OVERRIDE {
|
||||
GrGLRenderTarget::onAbandon();
|
||||
|
@ -20,7 +20,6 @@ public:
|
||||
typedef GrGLBufferImpl::Desc Desc;
|
||||
|
||||
GrGLVertexBuffer(GrGpuGL* gpu, const Desc& desc);
|
||||
virtual ~GrGLVertexBuffer() { this->release(); }
|
||||
|
||||
GrGLuint bufferID() const { return fImpl.bufferID(); }
|
||||
size_t baseOffset() const { return fImpl.baseOffset(); }
|
||||
|
@ -1131,21 +1131,22 @@ bool GrGpuGL::createStencilBufferForRenderTarget(GrRenderTarget* rt,
|
||||
SkASSERT(height >= rt->height());
|
||||
|
||||
int samples = rt->numSamples();
|
||||
GrGLuint sbID;
|
||||
GL_CALL(GenRenderbuffers(1, &sbID));
|
||||
if (!sbID) {
|
||||
return false;
|
||||
}
|
||||
GrGLuint sbID = 0;
|
||||
|
||||
int stencilFmtCnt = this->glCaps().stencilFormats().count();
|
||||
for (int i = 0; i < stencilFmtCnt; ++i) {
|
||||
if (!sbID) {
|
||||
GL_CALL(GenRenderbuffers(1, &sbID));
|
||||
}
|
||||
if (!sbID) {
|
||||
return false;
|
||||
}
|
||||
GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbID));
|
||||
// we start with the last stencil format that succeeded in hopes
|
||||
// that we won't go through this loop more than once after the
|
||||
// first (painful) stencil creation.
|
||||
int sIdx = (i + fLastSuccessfulStencilFmtIdx) % stencilFmtCnt;
|
||||
const GrGLCaps::StencilFormat& sFmt =
|
||||
this->glCaps().stencilFormats()[sIdx];
|
||||
const GrGLCaps::StencilFormat& sFmt = this->glCaps().stencilFormats()[sIdx];
|
||||
CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
|
||||
// we do this "if" so that we don't call the multisample
|
||||
// version on a GL that doesn't have an MSAA extension.
|
||||
@ -1156,12 +1157,10 @@ bool GrGpuGL::createStencilBufferForRenderTarget(GrRenderTarget* rt,
|
||||
sFmt.fInternalFormat,
|
||||
width, height);
|
||||
} else {
|
||||
GL_ALLOC_CALL(this->glInterface(),
|
||||
RenderbufferStorage(GR_GL_RENDERBUFFER,
|
||||
sFmt.fInternalFormat,
|
||||
width, height));
|
||||
created =
|
||||
(GR_GL_NO_ERROR == check_alloc_error(rt->desc(), this->glInterface()));
|
||||
GL_ALLOC_CALL(this->glInterface(), RenderbufferStorage(GR_GL_RENDERBUFFER,
|
||||
sFmt.fInternalFormat,
|
||||
width, height));
|
||||
created = (GR_GL_NO_ERROR == check_alloc_error(rt->desc(), this->glInterface()));
|
||||
}
|
||||
if (created) {
|
||||
// After sized formats we attempt an unsized format and take
|
||||
@ -1172,13 +1171,15 @@ bool GrGpuGL::createStencilBufferForRenderTarget(GrRenderTarget* rt,
|
||||
SkAutoTUnref<GrStencilBuffer> sb(SkNEW_ARGS(GrGLStencilBuffer,
|
||||
(this, kIsWrapped, sbID, width, height,
|
||||
samples, format)));
|
||||
// If we fail we have to create a new render buffer ID since we gave this one to the
|
||||
// GrGLStencilBuffer object.
|
||||
sbID = 0;
|
||||
if (this->attachStencilBufferToRenderTarget(sb, rt)) {
|
||||
fLastSuccessfulStencilFmtIdx = sIdx;
|
||||
sb->transferToCache();
|
||||
rt->setStencilBuffer(sb);
|
||||
return true;
|
||||
}
|
||||
sb->abandon(); // otherwise we lose sbID
|
||||
}
|
||||
}
|
||||
}
|
||||
GL_CALL(DeleteRenderbuffers(1, &sbID));
|
||||
|
@ -86,7 +86,6 @@ public:
|
||||
~TestResource() {
|
||||
--fNumAlive;
|
||||
SkSafeUnref(fToDelete);
|
||||
this->release();
|
||||
}
|
||||
|
||||
void setSize(size_t size) {
|
||||
|
Loading…
Reference in New Issue
Block a user