public:
SK_DECLARE_INST_COUNT(BenchResource);
BenchResource (GrGpu* gpu)
- : INHERITED(gpu, false) {
+ : INHERITED(gpu, kCached_LifeCycle) {
this->registerWithCache();
}
public:
SK_DECLARE_INST_COUNT(GrGpuResource)
+ enum LifeCycle {
+ /**
+ * The resource is cached and owned by Skia. Resources with this status may be kept alive
+ * by the cache as either scratch or content resources even when there are no refs to them.
+ * The cache may release them whenever there are no refs.
+ */
+ kCached_LifeCycle,
+ /**
+ * The resource is uncached. As soon as there are no more refs to it, it is released. Under
+ * the hood the cache may opaquely recycle it as a cached resource.
+ */
+ kUncached_LifeCycle,
+ /**
+ * Similar to uncached, but Skia does not manage the lifetime of the underlying backend
+ * 3D API object(s). The client is responsible for freeing those. Used to inject client-
+ * created GPU resources into Skia (e.g. to render to a client-created texture).
+ */
+ kWrapped_LifeCycle,
+ };
+
/**
* Tests whether a object has been abandoned or released. All objects will
* be in this state after their creating GrContext is destroyed or has
// initialized (i.e. not in a base class constructor).
void registerWithCache();
- GrGpuResource(GrGpu*, bool isWrapped);
+ GrGpuResource(GrGpu*, LifeCycle);
virtual ~GrGpuResource();
GrGpu* getGpu() const { return fGpu; }
backend API calls should be made. */
virtual void onAbandon() { }
- bool isWrapped() const { return SkToBool(kWrapped_Flag & fFlags); }
+ bool isWrapped() const { return kWrapped_LifeCycle == fLifeCycle; }
/**
* This entry point should be called whenever gpuMemorySize() should report a different size.
// See comments in CacheAccess.
bool setContentKey(const GrResourceKey& contentKey);
- void setBudgeted(bool countsAgainstBudget);
void notifyIsPurgable() const;
void removeScratchKey();
static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
enum Flags {
/**
- * The resource counts against the resource cache's budget.
- */
- kBudgeted_Flag = 0x1,
-
- /**
- * This object wraps a GPU object given to us by Skia's client. Skia will not free the
- * underlying backend API GPU resources when the GrGpuResource is destroyed. This also
- * implies that kBudgeted_Flag is not set.
- */
- kWrapped_Flag = 0x2,
-
- /**
* If set then fContentKey is valid and the resource is cached based on its content.
*/
- kContentKeySet_Flag = 0x4,
+ kContentKeySet_Flag = 0x1,
};
GrScratchKey fScratchKey;
mutable size_t fGpuMemorySize;
uint32_t fFlags;
+ LifeCycle fLifeCycle;
const uint32_t fUniqueID;
SkAutoTUnref<const SkData> fData;
void setStencilBuffer(GrStencilBuffer* stencilBuffer);
protected:
- GrRenderTarget(GrGpu* gpu,
- bool isWrapped,
- const GrSurfaceDesc& desc)
- : INHERITED(gpu, isWrapped, desc)
+ GrRenderTarget(GrGpu* gpu, LifeCycle lifeCycle, const GrSurfaceDesc& desc)
+ : INHERITED(gpu, lifeCycle, desc)
, fStencilBuffer(NULL) {
fResolveRect.setLargestInverted();
}
// Provides access to methods that should be public within Skia code.
friend class GrSurfacePriv;
- GrSurface(GrGpu* gpu, bool isWrapped, const GrSurfaceDesc& desc)
- : INHERITED(gpu, isWrapped)
- , fDesc(desc) {
+ GrSurface(GrGpu* gpu, LifeCycle lifeCycle, const GrSurfaceDesc& desc)
+ : INHERITED(gpu, lifeCycle)
+ , fDesc(desc) {
}
GrSurfaceDesc fDesc;
inline const GrTexturePriv texturePriv() const;
protected:
- GrTexture(GrGpu* gpu, bool isWrapped, const GrSurfaceDesc& desc);
+ GrTexture(GrGpu*, LifeCycle, const GrSurfaceDesc&);
void validateDesc() const;
desc.fHeight = fBackingTextureSize.height();
desc.fConfig = fPixelConfig;
- fTexture = fGpu->createTexture(desc, NULL, 0);
+ fTexture = fGpu->createTexture(desc, true, NULL, 0);
if (NULL == fTexture) {
return NULL;
}
rtDesc.fWidth = GrNextPow2(desc.fWidth);
rtDesc.fHeight = GrNextPow2(desc.fHeight);
- GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
+ GrTexture* texture = fGpu->createTexture(rtDesc, true, NULL, 0);
if (texture) {
GrDrawState drawState;
size_t stretchedRowBytes = rtDesc.fWidth * bpp;
- texture = fGpu->createTexture(rtDesc, stretchedPixels.get(), stretchedRowBytes);
+ texture = fGpu->createTexture(rtDesc, true, stretchedPixels.get(), stretchedRowBytes);
SkASSERT(texture);
}
srcData, rowBytes,
GrTexturePriv::NeedsBilerp(resourceKey));
} else {
- texture = fGpu->createTexture(desc, srcData, rowBytes);
+ texture = fGpu->createTexture(desc, true, srcData, rowBytes);
}
if (texture) {
desc.writable()->fFlags = origFlags;
}
- GrTexture* texture = fGpu->createTexture(*desc, NULL, 0);
+ GrTexture* texture = fGpu->createTexture(*desc, true, NULL, 0);
#ifdef SK_DEBUG
GrScratchKey key;
GrTexturePriv::ComputeScratchKey(*desc, &key);
}
-GrTexture* GrContext::createUncachedTexture(const GrSurfaceDesc& descIn,
+GrTexture* GrContext::createUncachedTexture(const GrSurfaceDesc& desc,
void* srcData,
size_t rowBytes) {
- GrSurfaceDesc descCopy = descIn;
- GrTexture* texture = fGpu->createTexture(descCopy, srcData, rowBytes);
- if (texture) {
- // TODO: It'd be nice to be able to do this before creation so we don't boot something
- // out of the cache. We could temporarily boost the cache budget.
- texture->cacheAccess().setBudgeted(false);
- }
- return texture;
+ return fGpu->createTexture(desc, false, srcData, rowBytes);
}
void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
desc.fHeight = height;
desc.fConfig = kAlpha_8_GrPixelConfig;
- *gammaTexture = context->getGpu()->createTexture(desc, NULL, 0);
+ *gammaTexture = context->getGpu()->createTexture(desc, true, NULL, 0);
if (NULL == *gammaTexture) {
return;
}
}
protected:
- GrGeometryBuffer(GrGpu* gpu, bool isWrapped, size_t gpuMemorySize, bool dynamic, bool cpuBacked)
- : INHERITED(gpu, isWrapped)
+ GrGeometryBuffer(GrGpu* gpu, size_t gpuMemorySize, bool dynamic, bool cpuBacked)
+ : INHERITED(gpu, kCached_LifeCycle)
, fMapPtr(NULL)
, fGpuMemorySize(gpuMemorySize)
, fDynamic(dynamic)
////////////////////////////////////////////////////////////////////////////////
-GrTexture* GrGpu::createTexture(const GrSurfaceDesc& desc,
+GrTexture* GrGpu::createTexture(const GrSurfaceDesc& desc, bool budgeted,
const void* srcData, size_t rowBytes) {
if (!this->caps()->isConfigTexturable(desc.fConfig)) {
return NULL;
}
this->handleDirtyContext();
- tex = this->onCreateCompressedTexture(desc, srcData);
+ tex = this->onCreateCompressedTexture(desc, budgeted, srcData);
} else {
this->handleDirtyContext();
- tex = this->onCreateTexture(desc, srcData, rowBytes);
+ tex = this->onCreateTexture(desc, budgeted, srcData, rowBytes);
if (tex &&
(kRenderTarget_GrSurfaceFlag & desc.fFlags) &&
!(kNoStencil_GrSurfaceFlag & desc.fFlags)) {
* or render targets can be checked using GrDrawTargetCaps.
*
* @param desc describes the texture to be created.
+ * @param budgeted does this texture count against the resource cache budget?
* @param srcData texel data to load texture. Begins with full-size
* palette data for paletted textures. For compressed
* formats it contains the compressed pixel data. Otherwise,
*
* @return The texture object if successful, otherwise NULL.
*/
- GrTexture* createTexture(const GrSurfaceDesc& desc, const void* srcData, size_t rowBytes);
+ GrTexture* createTexture(const GrSurfaceDesc& desc, bool budgeted,
+ const void* srcData, size_t rowBytes);
/**
* Implements GrContext::wrapBackendTexture
virtual void onResetContext(uint32_t resetBits) = 0;
// overridden by backend-specific derived class to create objects.
- virtual GrTexture* onCreateTexture(const GrSurfaceDesc& desc,
- const void* srcData,
- size_t rowBytes) = 0;
- virtual GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc,
+ virtual GrTexture* onCreateTexture(const GrSurfaceDesc& desc, bool budgeted,
+ const void* srcData, size_t rowBytes) = 0;
+ virtual GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc, bool budgeted,
const void* srcData) = 0;
virtual GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&) = 0;
virtual GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) = 0;
return gpu->getContext()->getResourceCache2();
}
-GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped)
+GrGpuResource::GrGpuResource(GrGpu* gpu, LifeCycle lifeCycle)
: fGpu(gpu)
, fGpuMemorySize(kInvalidGpuMemorySize)
+ , fFlags(0)
+ , fLifeCycle(lifeCycle)
, fUniqueID(CreateUniqueID()) {
- if (isWrapped) {
- fFlags = kWrapped_Flag;
- } else {
- // By default all non-wrapped resources are budgeted.
- fFlags = kBudgeted_Flag;
- }
}
void GrGpuResource::registerWithCache() {
} while (id == SK_InvalidUniqueID);
return id;
}
-
-void GrGpuResource::setBudgeted(bool countsAgainstBudget) {
- // Wrapped resources never count against the budget, nothing to do. No point in changing the
- // budgeting of destroyed resources.
- if (this->isWrapped() || this->wasDestroyed()) {
- return;
- }
-
- uint32_t oldFlags = fFlags;
- if (countsAgainstBudget) {
- fFlags |= kBudgeted_Flag;
- } else {
- fFlags &= ~kBudgeted_Flag;
- }
- if (fFlags != oldFlags) {
- get_resource_cache2(fGpu)->resourceAccess().didChangeBudgetStatus(this);
- }
-}
}
/**
- * Changes whether the resource counts against the resource cache budget.
- */
- void setBudgeted(bool countsAgainstBudget) { fResource->setBudgeted(countsAgainstBudget); }
-
- /**
* Is the resource currently cached as scratch? This means it has a valid scratch key and does
* not have a content key.
*/
/**
* Is the resource object wrapping an externally allocated GPU resource?
*/
- bool isWrapped() const { return fResource->isWrapped(); }
+ bool isWrapped() const { return GrGpuResource::kWrapped_LifeCycle == fResource->fLifeCycle; }
/**
* Does the resource count against the resource budget?
*/
- bool isBudgeted() const {
- bool ret = SkToBool(GrGpuResource::kBudgeted_Flag & fResource->fFlags);
- SkASSERT(!(ret && fResource->isWrapped()));
- return ret;
- }
+ bool isBudgeted() const { return GrGpuResource::kCached_LifeCycle == fResource->fLifeCycle; }
/**
* Called by the cache to delete the resource under normal circumstances.
return static_cast<int>(this->gpuMemorySize() / (sizeof(uint16_t) * 6));
}
protected:
- GrIndexBuffer(GrGpu* gpu, bool isWrapped, size_t gpuMemorySize, bool dynamic, bool cpuBacked)
- : INHERITED(gpu, isWrapped, gpuMemorySize, dynamic, cpuBacked) {}
+ GrIndexBuffer(GrGpu* gpu, size_t gpuMemorySize, bool dynamic, bool cpuBacked)
+ : INHERITED(gpu, gpuMemorySize, dynamic, cpuBacked) {}
private:
typedef GrGeometryBuffer INHERITED;
};
/**
* Initialize to a path with a fixed stroke. Stroke must not be hairline.
*/
- GrPath(GrGpu* gpu, bool isWrapped, const SkPath& skPath, const SkStrokeRec& stroke)
- : INHERITED(gpu, isWrapped),
+ GrPath(GrGpu* gpu, const SkPath& skPath, const SkStrokeRec& stroke)
+ : INHERITED(gpu, kCached_LifeCycle),
fSkPath(skPath),
fStroke(stroke),
fBounds(skPath.getBounds()) {
GrPathRange::GrPathRange(GrGpu* gpu,
PathGenerator* pathGenerator,
const SkStrokeRec& stroke)
- : INHERITED(gpu, kIsWrapped),
+ : INHERITED(gpu, kCached_LifeCycle),
fPathGenerator(SkRef(pathGenerator)),
fNumPaths(fPathGenerator->getNumPaths()),
fStroke(stroke) {
GrPathRange::GrPathRange(GrGpu* gpu,
int numPaths,
const SkStrokeRec& stroke)
- : INHERITED(gpu, kIsWrapped),
+ : INHERITED(gpu, kCached_LifeCycle),
fNumPaths(numPaths),
fStroke(stroke) {
}
public:
SK_DECLARE_INST_COUNT(GrPathRange);
- static const bool kIsWrapped = false;
-
enum PathIndexType {
kU8_PathIndexType, //!< uint8_t
kU16_PathIndexType, //!< uint16_t
bool noKey = !resource->cacheAccess().isScratch() &&
(NULL == resource->cacheAccess().getContentKey());
- // Wrapped resources should never have a key.
- SkASSERT(noKey || !resource->cacheAccess().isWrapped());
+ // Only cached resources should ever have a key.
+ SkASSERT(noKey || resource->cacheAccess().isBudgeted());
- // And purge if the resource is wrapped
if (overBudget || noKey) {
SkDEBUGCODE(int beforeCount = fCount;)
resource->cacheAccess().release();
this->validate();
}
-
void GrResourceCache2::internalPurgeAsNeeded() {
SkASSERT(!fPurging);
SkASSERT(!fNewlyPurgableResourceWhilePurging);
static void ComputeKey(int width, int height, int sampleCnt, GrScratchKey* key);
protected:
- GrStencilBuffer(GrGpu* gpu, bool isWrapped, int width, int height, int bits, int sampleCnt)
- : GrGpuResource(gpu, isWrapped)
+ GrStencilBuffer(GrGpu* gpu, int width, int height, int bits, int sampleCnt)
+ : GrGpuResource(gpu, kCached_LifeCycle)
, fWidth(width)
, fHeight(height)
, fBits(bits)
private:
void onResetContext(uint32_t resetBits) SK_OVERRIDE {}
- GrTexture* onCreateTexture(const GrSurfaceDesc& desc,
- const void* srcData,
+ GrTexture* onCreateTexture(const GrSurfaceDesc& desc, bool budgeted, const void* srcData,
size_t rowBytes) SK_OVERRIDE {
return NULL;
}
- GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc,
+ GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc, bool budgeted,
const void* srcData) SK_OVERRIDE {
return NULL;
}
}
//////////////////////////////////////////////////////////////////////////////
-GrTexture::GrTexture(GrGpu* gpu, bool isWrapped, const GrSurfaceDesc& desc)
- : INHERITED(gpu, isWrapped, desc)
+GrTexture::GrTexture(GrGpu* gpu, LifeCycle lifeCycle, const GrSurfaceDesc& desc)
+ : INHERITED(gpu, lifeCycle, desc)
, fMipMapsStatus(kNotAllocated_MipMapsStatus) {
- if (!isWrapped) {
+ if (kCached_LifeCycle == lifeCycle) {
GrScratchKey key;
GrTexturePriv::ComputeScratchKey(desc, &key);
this->setScratchKey(key);
class GrVertexBuffer : public GrGeometryBuffer {
protected:
- GrVertexBuffer(GrGpu* gpu, bool isWrapped, size_t gpuMemorySize, bool dynamic, bool cpuBacked)
- : INHERITED(gpu, isWrapped, gpuMemorySize, dynamic, cpuBacked) {}
+ GrVertexBuffer(GrGpu* gpu, size_t gpuMemorySize, bool dynamic, bool cpuBacked)
+ : INHERITED(gpu, gpuMemorySize, dynamic, cpuBacked) {}
private:
typedef GrGeometryBuffer INHERITED;
};
if (fCPUData) {
sk_free(fCPUData);
fCPUData = NULL;
- } else if (fDesc.fID && !fDesc.fIsWrapped) {
+ } else if (fDesc.fID) {
GL_CALL(gpu, DeleteBuffers(1, &fDesc.fID));
if (GR_GL_ARRAY_BUFFER == fBufferType) {
gpu->notifyVertexBufferDelete(fDesc.fID);
SkASSERT(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType);
// The following assert isn't valid when the buffer has been abandoned:
// SkASSERT((0 == fDesc.fID) == (fCPUData));
- SkASSERT(0 != fDesc.fID || !fDesc.fIsWrapped);
SkASSERT(NULL == fCPUData || 0 == fGLSizeInBytes);
SkASSERT(NULL == fMapPtr || fCPUData || fGLSizeInBytes == fDesc.fSizeInBytes);
SkASSERT(NULL == fCPUData || NULL == fMapPtr || fCPUData == fMapPtr);
class GrGLBufferImpl : SkNoncopyable {
public:
struct Desc {
- bool fIsWrapped;
GrGLuint fID; // set to 0 to indicate buffer is CPU-backed and not a VBO.
size_t fSizeInBytes;
bool fDynamic;
GrSurfaceDesc surfDesc;
idDesc.fTextureID = static_cast<GrGLuint>(desc.fTextureHandle);
- idDesc.fIsWrapped = true;
+ idDesc.fLifeCycle = GrGpuResource::kWrapped_LifeCycle;
// next line relies on GrBackendTextureDesc's flags matching GrTexture's
surfDesc.fFlags = (GrSurfaceFlags) desc.fFlags;
GrGLTexture* texture = NULL;
if (renderTarget) {
GrGLRenderTarget::IDDesc rtIDDesc;
- if (!this->createRenderTargetObjects(surfDesc, idDesc.fTextureID, &rtIDDesc)) {
+ if (!this->createRenderTargetObjects(surfDesc, false, idDesc.fTextureID, &rtIDDesc)) {
return NULL;
}
texture = SkNEW_ARGS(GrGLTextureRenderTarget, (this, surfDesc, idDesc, rtIDDesc));
idDesc.fRTFBOID = static_cast<GrGLuint>(wrapDesc.fRenderTargetHandle);
idDesc.fMSColorRenderbufferID = 0;
idDesc.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID;
- idDesc.fIsWrapped = true;
+ idDesc.fLifeCycle = GrGpuResource::kWrapped_LifeCycle;
GrSurfaceDesc desc;
desc.fConfig = wrapDesc.fConfig;
format.fPacked = false;
format.fStencilBits = wrapDesc.fStencilBits;
format.fTotalBits = wrapDesc.fStencilBits;
- static const bool kIsSBWrapped = false;
GrGLStencilBuffer* sb = SkNEW_ARGS(GrGLStencilBuffer,
(this,
- kIsSBWrapped,
0,
desc.fWidth,
desc.fHeight,
return (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(ctx.interface()));;
}
-bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, GrGLuint texID,
+bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, bool budgeted, GrGLuint texID,
GrGLRenderTarget::IDDesc* idDesc) {
idDesc->fMSColorRenderbufferID = 0;
idDesc->fRTFBOID = 0;
idDesc->fTexFBOID = 0;
- idDesc->fIsWrapped = false;
+ idDesc->fLifeCycle = budgeted ? GrGpuResource::kCached_LifeCycle :
+ GrGpuResource::kUncached_LifeCycle;
GrGLenum status;
}
#endif
-GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& origDesc,
- const void* srcData,
- size_t rowBytes) {
+GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& origDesc, bool budgeted,
+ const void* srcData, size_t rowBytes) {
GrSurfaceDesc desc = origDesc;
- GrGLRenderTarget::IDDesc rtIDDesc;
// Attempt to catch un- or wrongly initialized sample counts;
SkASSERT(desc.fSampleCnt >= 0 && desc.fSampleCnt <= 64);
desc.fSampleCnt = SkTMin(desc.fSampleCnt, this->caps()->maxSampleCount());
desc.fOrigin = resolve_origin(desc.fOrigin, renderTarget);
- rtIDDesc.fMSColorRenderbufferID = 0;
- rtIDDesc.fRTFBOID = 0;
- rtIDDesc.fTexFBOID = 0;
- rtIDDesc.fIsWrapped = false;
-
if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType() && desc.fSampleCnt) {
//SkDebugf("MSAA RT requested but not supported on this platform.");
return return_null_texture();
GrGLTexture::IDDesc idDesc;
GL_CALL(GenTextures(1, &idDesc.fTextureID));
- idDesc.fIsWrapped = false;
+ idDesc.fLifeCycle = budgeted ? GrGpuResource::kCached_LifeCycle :
+ GrGpuResource::kUncached_LifeCycle;
if (!idDesc.fTextureID) {
return return_null_texture();
if (renderTarget) {
// unbind the texture from the texture unit before binding it to the frame buffer
GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0));
+ GrGLRenderTarget::IDDesc rtIDDesc;
- if (!this->createRenderTargetObjects(desc, idDesc.fTextureID, &rtIDDesc)) {
+ if (!this->createRenderTargetObjects(desc, budgeted, idDesc.fTextureID, &rtIDDesc)) {
GL_CALL(DeleteTextures(1, &idDesc.fTextureID));
return return_null_texture();
}
return tex;
}
-GrTexture* GrGLGpu::onCreateCompressedTexture(const GrSurfaceDesc& origDesc, const void* srcData) {
+GrTexture* GrGLGpu::onCreateCompressedTexture(const GrSurfaceDesc& origDesc, bool budgeted,
+ const void* srcData) {
if(SkToBool(origDesc.fFlags & kRenderTarget_GrSurfaceFlag) || origDesc.fSampleCnt > 0) {
return return_null_texture();
GrGLTexture::IDDesc idDesc;
GL_CALL(GenTextures(1, &idDesc.fTextureID));
- idDesc.fIsWrapped = false;
+ idDesc.fLifeCycle = budgeted ? GrGpuResource::kCached_LifeCycle :
+ GrGpuResource::kUncached_LifeCycle;
if (!idDesc.fTextureID) {
return return_null_texture();
// whatever sizes GL gives us. In that case we query for the size.
GrGLStencilBuffer::Format format = sFmt;
get_stencil_rb_sizes(this->glInterface(), &format);
- static const bool kIsWrapped = false;
SkAutoTUnref<GrStencilBuffer> sb(SkNEW_ARGS(GrGLStencilBuffer,
- (this, kIsWrapped, sbID, width, height,
- samples, format)));
+ (this, sbID, width, height, samples, format)));
if (this->attachStencilBufferToRenderTarget(sb, rt)) {
fLastSuccessfulStencilFmtIdx = sIdx;
rt->setStencilBuffer(sb);
GrGLVertexBuffer::Desc desc;
desc.fDynamic = dynamic;
desc.fSizeInBytes = size;
- desc.fIsWrapped = false;
if (this->glCaps().useNonVBOVertexAndIndexDynamicData() && desc.fDynamic) {
desc.fID = 0;
GrGLIndexBuffer::Desc desc;
desc.fDynamic = dynamic;
desc.fSizeInBytes = size;
- desc.fIsWrapped = false;
if (this->glCaps().useNonVBOVertexAndIndexDynamicData() && desc.fDynamic) {
desc.fID = 0;
// GrGpu overrides
void onResetContext(uint32_t resetBits) SK_OVERRIDE;
- GrTexture* onCreateTexture(const GrSurfaceDesc& desc,
- const void* srcData,
+ GrTexture* onCreateTexture(const GrSurfaceDesc& desc, bool budgeted, const void* srcData,
size_t rowBytes) SK_OVERRIDE;
- GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc,
+ GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc, bool budgeted,
const void* srcData) SK_OVERRIDE;
GrVertexBuffer* onCreateVertexBuffer(size_t size, bool dynamic) SK_OVERRIDE;
GrIndexBuffer* onCreateIndexBuffer(size_t size, bool dynamic) SK_OVERRIDE;
int left = 0, int top = 0,
int width = -1, int height = -1);
- bool createRenderTargetObjects(const GrSurfaceDesc&, GrGLuint texID, GrGLRenderTarget::IDDesc*);
+ bool createRenderTargetObjects(const GrSurfaceDesc&, bool budgeted, GrGLuint texID,
+ GrGLRenderTarget::IDDesc*);
GrGLuint bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport);
#include "GrGLGpu.h"
GrGLIndexBuffer::GrGLIndexBuffer(GrGLGpu* gpu, const Desc& desc)
- : INHERITED(gpu, desc.fIsWrapped, desc.fSizeInBytes, desc.fDynamic, 0 == desc.fID)
+ : INHERITED(gpu, desc.fSizeInBytes, desc.fDynamic, 0 == desc.fID)
, fImpl(gpu, desc, GR_GL_ELEMENT_ARRAY_BUFFER) {
this->registerWithCache();
}
}
}
-static const bool kIsWrapped = false; // The constructor creates the GL path object.
-
void GrGLPath::InitPathObject(GrGLGpu* gpu,
GrGLuint pathID,
const SkPath& skPath,
}
GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& path, const SkStrokeRec& stroke)
- : INHERITED(gpu, kIsWrapped, path, stroke),
+ : INHERITED(gpu, path, stroke),
fPathID(gpu->glPathRendering()->genPaths(1)) {
InitPathObject(gpu, fPathID, fSkPath, stroke);
// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc)
- : GrSurface(gpu, idDesc.fIsWrapped, desc)
- , INHERITED(gpu, idDesc.fIsWrapped, desc) {
+ : GrSurface(gpu, idDesc.fLifeCycle, desc)
+ , INHERITED(gpu, idDesc.fLifeCycle, desc) {
this->init(desc, idDesc);
this->registerWithCache();
}
GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc,
Derived)
- : GrSurface(gpu, idDesc.fIsWrapped, desc)
- , INHERITED(gpu, idDesc.fIsWrapped, desc) {
+ : GrSurface(gpu, idDesc.fLifeCycle, desc)
+ , INHERITED(gpu, idDesc.fLifeCycle, desc) {
this->init(desc, idDesc);
}
fRTFBOID = idDesc.fRTFBOID;
fTexFBOID = idDesc.fTexFBOID;
fMSColorRenderbufferID = idDesc.fMSColorRenderbufferID;
- fIsWrapped = idDesc.fIsWrapped;
+ fIsWrapped = kWrapped_LifeCycle == idDesc.fLifeCycle;
fViewport.fLeft = 0;
fViewport.fBottom = 0;
enum { kUnresolvableFBOID = 0 };
struct IDDesc {
- GrGLuint fRTFBOID;
- GrGLuint fTexFBOID;
- GrGLuint fMSColorRenderbufferID;
- bool fIsWrapped;
+ GrGLuint fRTFBOID;
+ GrGLuint fTexFBOID;
+ GrGLuint fMSColorRenderbufferID;
+ GrGpuResource::LifeCycle fLifeCycle;
};
GrGLRenderTarget(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&);
};
GrGLStencilBuffer(GrGpu* gpu,
- bool isWrapped,
GrGLint rbid,
int width, int height,
int sampleCnt,
const Format& format)
- : GrStencilBuffer(gpu, isWrapped, width, height, format.fStencilBits, sampleCnt)
+ : GrStencilBuffer(gpu, width, height, format.fStencilBits, sampleCnt)
, fFormat(format)
, fRenderbufferID(rbid) {
this->registerWithCache();
// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrGLTexture::GrGLTexture(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc)
- : GrSurface(gpu, idDesc.fIsWrapped, desc)
- , INHERITED(gpu, idDesc.fIsWrapped, desc) {
+ : GrSurface(gpu, idDesc.fLifeCycle, desc)
+ , INHERITED(gpu, idDesc.fLifeCycle, desc) {
this->init(desc, idDesc);
this->registerWithCache();
}
GrGLTexture::GrGLTexture(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc, Derived)
- : GrSurface(gpu, idDesc.fIsWrapped, desc)
- , INHERITED(gpu, idDesc.fIsWrapped, desc) {
+ : GrSurface(gpu, idDesc.fLifeCycle, desc)
+ , INHERITED(gpu, idDesc.fLifeCycle, desc) {
this->init(desc, idDesc);
}
fTexParams.invalidate();
fTexParamsTimestamp = GrGpu::kExpiredTimestamp;
fTextureID = idDesc.fTextureID;
- fIsWrapped = idDesc.fIsWrapped;
+ fIsWrapped = kWrapped_LifeCycle == idDesc.fLifeCycle;
}
void GrGLTexture::onRelease() {
};
struct IDDesc {
- GrGLuint fTextureID;
- bool fIsWrapped;
+ GrGLuint fTextureID;
+ GrGpuResource::LifeCycle fLifeCycle;
};
GrGLTexture(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&);
const GrSurfaceDesc& desc,
const GrGLTexture::IDDesc& texIDDesc,
const GrGLRenderTarget::IDDesc& rtIDDesc)
- : GrSurface(gpu, texIDDesc.fIsWrapped, desc)
+ : GrSurface(gpu, texIDDesc.fLifeCycle, desc)
, GrGLTexture(gpu, desc, texIDDesc, GrGLTexture::kDerived)
, GrGLRenderTarget(gpu, desc, rtIDDesc, GrGLRenderTarget::kDerived) {
this->registerWithCache();
///////////////////////////////////////////////////////////////////////////////////////////////////
GrGLVertexArray::GrGLVertexArray(GrGLGpu* gpu, GrGLint id, int attribCount)
- : INHERITED(gpu, false)
+ : INHERITED(gpu, kCached_LifeCycle)
, fID(id)
, fAttribArrays(attribCount)
, fIndexBufferIDIsValid(false) {
#include "GrGLGpu.h"
GrGLVertexBuffer::GrGLVertexBuffer(GrGLGpu* gpu, const Desc& desc)
- : INHERITED(gpu, desc.fIsWrapped, desc.fSizeInBytes, desc.fDynamic, 0 == desc.fID)
+ : INHERITED(gpu, desc.fSizeInBytes, desc.fDynamic, 0 == desc.fID)
, fImpl(gpu, desc, GR_GL_ARRAY_BUFFER) {
this->registerWithCache();
}
dummyDesc.fConfig = kSkia8888_GrPixelConfig;
dummyDesc.fWidth = 34;
dummyDesc.fHeight = 18;
- SkAutoTUnref<GrTexture> dummyTexture1(gpu->createTexture(dummyDesc, NULL, 0));
+ SkAutoTUnref<GrTexture> dummyTexture1(gpu->createTexture(dummyDesc, false, NULL, 0));
dummyDesc.fFlags = kNone_GrSurfaceFlags;
dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
dummyDesc.fWidth = 16;
dummyDesc.fHeight = 22;
- SkAutoTUnref<GrTexture> dummyTexture2(gpu->createTexture(dummyDesc, NULL, 0));
+ SkAutoTUnref<GrTexture> dummyTexture2(gpu->createTexture(dummyDesc, false, NULL, 0));
if (!dummyTexture1 || ! dummyTexture2) {
SkDebugf("Could not allocate dummy textures");
public:
SK_DECLARE_INST_COUNT(TestResource);
- TestResource(GrGpu* gpu, bool isWrapped)
- : INHERITED(gpu, isWrapped)
+ TestResource(GrGpu* gpu, size_t size, GrGpuResource::LifeCycle lifeCycle)
+ : INHERITED(gpu, lifeCycle)
+ , fToDelete(NULL)
+ , fSize(size) {
+ ++fNumAlive;
+ this->registerWithCache();
+ }
+
+ TestResource(GrGpu* gpu, GrGpuResource::LifeCycle lifeCycle)
+ : INHERITED(gpu, lifeCycle)
, fToDelete(NULL)
, fSize(kDefaultSize) {
++fNumAlive;
}
TestResource(GrGpu* gpu)
- : INHERITED(gpu, false)
+ : INHERITED(gpu, kCached_LifeCycle)
, fToDelete(NULL)
, fSize(kDefaultSize) {
++fNumAlive;
}
TestResource(GrGpu* gpu, const GrScratchKey& scratchKey)
- : INHERITED(gpu, false)
+ : INHERITED(gpu, kCached_LifeCycle)
, fToDelete(NULL)
, fSize(kDefaultSize) {
this->setScratchKey(scratchKey);
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
// Create a bunch of resources with no keys
- TestResource* a = new TestResource(context->getGpu());
- TestResource* b = new TestResource(context->getGpu());
- TestResource* c = new TestResource(context->getGpu());
- TestResource* d = new TestResource(context->getGpu());
+ TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu()));
+ TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu()));
+ TestResource* c = SkNEW_ARGS(TestResource, (context->getGpu()));
+ TestResource* d = SkNEW_ARGS(TestResource, (context->getGpu()));
a->setSize(11);
b->setSize(12);
c->setSize(13);
GrResourceKey contentKey(GrCacheID(GrCacheID::GenerateDomain(), keyData), 0);
// Create a scratch, a content, and a wrapped resource
- TestResource* scratch = new TestResource(context->getGpu(), scratchKey);
+ TestResource* scratch = SkNEW_ARGS(TestResource, (context->getGpu(), scratchKey));
scratch->setSize(10);
- TestResource* content = new TestResource(context->getGpu());
- scratch->setSize(11);
+ TestResource* content = SkNEW_ARGS(TestResource, (context->getGpu()));
+ content->setSize(11);
REPORTER_ASSERT(reporter, content->cacheAccess().setContentKey(contentKey));
- TestResource* wrapped = new TestResource(context->getGpu(), true);
- scratch->setSize(12);
- TestResource* unbudgeted = new TestResource(context->getGpu());
+ TestResource* wrapped = SkNEW_ARGS(TestResource,
+ (context->getGpu(), GrGpuResource::kWrapped_LifeCycle));
+ wrapped->setSize(12);
+ TestResource* unbudgeted = SkNEW_ARGS(TestResource,
+ (context->getGpu(), GrGpuResource::kUncached_LifeCycle));
unbudgeted->setSize(13);
- unbudgeted->cacheAccess().setBudgeted(false);
// Make sure we can't add a content key to the wrapped resource
keyData.fData8[0] = 1;
unbudgeted->gpuMemorySize() == cache2->getResourceBytes());
// Now try freeing the budgeted resources first
- wrapped = new TestResource(context->getGpu(), true);
+ wrapped = SkNEW_ARGS(TestResource, (context->getGpu(), GrGpuResource::kWrapped_LifeCycle));
scratch->setSize(12);
content->unref();
cache2->purgeAllUnlocked();
REPORTER_ASSERT(reporter, 0 == cache2->getBudgetedResourceBytes());
}
+static void test_unbudgeted(skiatest::Reporter* reporter) {
+ SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
+ REPORTER_ASSERT(reporter, SkToBool(context));
+ if (NULL == context) {
+ return;
+ }
+ context->setResourceCacheLimits(10, 300);
+ GrResourceCache2* cache2 = context->getResourceCache2();
+ cache2->purgeAllUnlocked();
+ SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
+ SkASSERT(0 == cache2->getBudgetedResourceCount() && 0 == cache2->getBudgetedResourceBytes());
+
+ GrScratchKey scratchKey;
+ make_scratch_key(&scratchKey);
+
+ GrCacheID::Key keyData;
+ memset(&keyData, 0, sizeof(keyData));
+ GrResourceKey contentKey(GrCacheID(GrCacheID::GenerateDomain(), keyData), 0);
+
+ TestResource* scratch;
+ TestResource* content;
+ TestResource* wrapped;
+ TestResource* unbudgeted;
+
+ // A large uncached or wrapped resource shouldn't evict anything.
+ scratch = SkNEW_ARGS(TestResource, (context->getGpu(), scratchKey));
+ scratch->setSize(10);
+ scratch->unref();
+ REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
+ REPORTER_ASSERT(reporter, 10 == cache2->getResourceBytes());
+ REPORTER_ASSERT(reporter, 1 == cache2->getBudgetedResourceCount());
+ REPORTER_ASSERT(reporter, 10 == cache2->getBudgetedResourceBytes());
+
+ content = SkNEW_ARGS(TestResource, (context->getGpu()));
+ content->setSize(11);
+ REPORTER_ASSERT(reporter, content->cacheAccess().setContentKey(contentKey));
+ content->unref();
+ REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
+ REPORTER_ASSERT(reporter, 21 == cache2->getResourceBytes());
+ REPORTER_ASSERT(reporter, 2 == cache2->getBudgetedResourceCount());
+ REPORTER_ASSERT(reporter, 21 == cache2->getBudgetedResourceBytes());
+
+ size_t large = 2 * cache2->getResourceBytes();
+ unbudgeted = SkNEW_ARGS(TestResource,
+ (context->getGpu(), large, GrGpuResource::kUncached_LifeCycle));
+ REPORTER_ASSERT(reporter, 3 == cache2->getResourceCount());
+ REPORTER_ASSERT(reporter, 21 + large == cache2->getResourceBytes());
+ REPORTER_ASSERT(reporter, 2 == cache2->getBudgetedResourceCount());
+ REPORTER_ASSERT(reporter, 21 == cache2->getBudgetedResourceBytes());
+
+ unbudgeted->unref();
+ REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
+ REPORTER_ASSERT(reporter, 21 == cache2->getResourceBytes());
+ REPORTER_ASSERT(reporter, 2 == cache2->getBudgetedResourceCount());
+ REPORTER_ASSERT(reporter, 21 == cache2->getBudgetedResourceBytes());
+
+ wrapped = SkNEW_ARGS(TestResource,
+ (context->getGpu(), large, GrGpuResource::kWrapped_LifeCycle));
+ REPORTER_ASSERT(reporter, 3 == cache2->getResourceCount());
+ REPORTER_ASSERT(reporter, 21 + large == cache2->getResourceBytes());
+ REPORTER_ASSERT(reporter, 2 == cache2->getBudgetedResourceCount());
+ REPORTER_ASSERT(reporter, 21 == cache2->getBudgetedResourceBytes());
+
+ wrapped->unref();
+ REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
+ REPORTER_ASSERT(reporter, 21 == cache2->getResourceBytes());
+ REPORTER_ASSERT(reporter, 2 == cache2->getBudgetedResourceCount());
+ REPORTER_ASSERT(reporter, 21 == cache2->getBudgetedResourceBytes());
+
+ cache2->purgeAllUnlocked();
+ REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount());
+ REPORTER_ASSERT(reporter, 0 == cache2->getResourceBytes());
+ REPORTER_ASSERT(reporter, 0 == cache2->getBudgetedResourceCount());
+ REPORTER_ASSERT(reporter, 0 == cache2->getBudgetedResourceBytes());
+}
+
static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
REPORTER_ASSERT(reporter, SkToBool(context));
make_scratch_key(&scratchKey);
// Create two resources that have the same scratch key.
- TestResource* a = new TestResource(context->getGpu(), scratchKey);
- TestResource* b = new TestResource(context->getGpu(), scratchKey);
+ TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu(), scratchKey));
+ TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu(), scratchKey));
a->setSize(11);
b->setSize(12);
// Scratch resources are registered with GrResourceCache2 just by existing. There are 2.
make_scratch_key(&scratchKey);
// Create two resources that have the same scratch key.
- TestResource* a = new TestResource(context->getGpu(), scratchKey);
- TestResource* b = new TestResource(context->getGpu(), scratchKey);
+ TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu(), scratchKey));
+ TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu(), scratchKey));
a->unref();
b->unref();
GrResourceKey key(GrCacheID(domain, keyData), 0);
// Create two resources that we will attempt to register with the same content key.
- TestResource* a = new TestResource(context->getGpu());
- TestResource* b = new TestResource(context->getGpu());
+ TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu()));
+ TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu()));
a->setSize(11);
b->setSize(12);
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
// Add three resources to the cache.
- TestResource* a = new TestResource(context->getGpu());
- TestResource* b = new TestResource(context->getGpu());
- TestResource* c = new TestResource(context->getGpu());
+ TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu()));
+ TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu()));
+ TestResource* c = SkNEW_ARGS(TestResource, (context->getGpu()));
a->cacheAccess().setContentKey(key1);
b->cacheAccess().setContentKey(key2);
c->cacheAccess().setContentKey(key3);
cache2->purgeAllUnlocked();
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
- TestResource* a = new TestResource(context->getGpu());
- TestResource* b = new TestResource(context->getGpu());
+ TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu()));
+ TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu()));
a->cacheAccess().setContentKey(key1);
b->cacheAccess().setContentKey(key2);
cache2->purgeAllUnlocked();
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
- TestResource* a = new TestResource(context->getGpu());
+ TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu()));
a->cacheAccess().setContentKey(key1);
a->unref();
- TestResource* b = new TestResource(context->getGpu());
+ TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu()));
b->cacheAccess().setContentKey(key2);
b->unref();
cache2->purgeAllUnlocked();
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
- TestResource* a = new TestResource(context->getGpu());
+ TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu()));
a->setSize(100);
a->cacheAccess().setContentKey(key1);
a->unref();
- TestResource* b = new TestResource(context->getGpu());
+ TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu()));
b->setSize(100);
b->cacheAccess().setContentKey(key2);
b->unref();
// The below tests create their own mock contexts.
test_no_key(reporter);
test_budgeting(reporter);
+ test_unbudgeted(reporter);
test_duplicate_content_key(reporter);
test_duplicate_scratch_key(reporter);
test_remove_scratch_key(reporter);