Make GrTextureCache into a generic GrResource cache. Also some GrContext texture interface cleanup.

http://codereview.appspot.com/4815055/


git-svn-id: http://skia.googlecode.com/svn/trunk@1965 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2011-07-26 20:45:30 +00:00
parent f131694617
commit 50398bf7f1
10 changed files with 472 additions and 407 deletions

View File

@ -18,16 +18,18 @@
#define GrContext_DEFINED #define GrContext_DEFINED
#include "GrClip.h" #include "GrClip.h"
#include "GrTextureCache.h"
#include "GrPaint.h" #include "GrPaint.h"
#include "GrPathRenderer.h" #include "GrPathRenderer.h"
class GrFontCache; class GrFontCache;
class GrGpu; class GrGpu;
struct GrGpuStats; struct GrGpuStats;
class GrVertexBufferAllocPool;
class GrIndexBufferAllocPool; class GrIndexBufferAllocPool;
class GrInOrderDrawBuffer; class GrInOrderDrawBuffer;
class GrResourceEntry;
class GrResourceCache;
class GrVertexBufferAllocPool;
class GR_API GrContext : public GrRefCnt { class GR_API GrContext : public GrRefCnt {
public: public:
@ -82,54 +84,92 @@ public:
// Textures // Textures
/** /**
* Search for an entry with the same Key. If found, "lock" it and return it. * Token that refers to an entry in the texture cache. Returned by
* If not found, return null. * functions that lock textures. Passed to unlockTexture.
*/ */
GrTextureEntry* findAndLockTexture(GrTextureKey*, class TextureCacheEntry {
const GrSamplerState&); public:
TextureCacheEntry() : fEntry(NULL) {}
TextureCacheEntry(const TextureCacheEntry& e) : fEntry(e.fEntry) {}
TextureCacheEntry& operator= (const TextureCacheEntry& e) {
fEntry = e.fEntry;
return *this;
}
GrTexture* texture() const;
void reset() { fEntry = NULL; }
private:
explicit TextureCacheEntry(GrResourceEntry* entry) { fEntry = entry; }
void set(GrResourceEntry* entry) { fEntry = entry; }
GrResourceEntry* cacheEntry() { return fEntry; }
GrResourceEntry* fEntry;
friend class GrContext;
};
/**
* Key generated by client. Should be a unique key on the texture data.
* Does not need to consider that width and height of the texture. Two
* textures with the same TextureKey but different bounds will not collide.
*/
typedef uint64_t TextureKey;
/**
* Search for an entry based on key and dimensions. If found, "lock" it and
* return it. The entry's texture() function will return NULL if not found.
* Must call be balanced with an unlockTexture() call.
*/
TextureCacheEntry findAndLockTexture(TextureKey key,
int width,
int height,
const GrSamplerState&);
/** /**
* Create a new entry, based on the specified key and texture, and return * Create a new entry, based on the specified key and texture, and return
* its "locked" entry. * its "locked" entry. Must call be balanced with an unlockTexture() call.
*
* Ownership of the texture is transferred to the Entry, which will unref()
* it when we are purged or deleted.
*/ */
GrTextureEntry* createAndLockTexture(GrTextureKey* key, TextureCacheEntry createAndLockTexture(TextureKey key,
const GrSamplerState&, const GrSamplerState&,
const GrTextureDesc&, const GrTextureDesc&,
void* srcData, size_t rowBytes); void* srcData, size_t rowBytes);
/**
* Enum that determines how closely a returned scratch texture must match
* a provided GrTextureDesc.
*/
enum ScratchTexMatch {
/**
* Finds a texture that exactly matches the descriptor.
*/
kExact_ScratchTexMatch,
/**
* Finds a texture that approximately matches the descriptor. Will be
* at least as large in width and height as desc specifies. If desc
* specifies that texture is a render target then result will be a
* render target. If desc specifies a render target and doesn't set the
* no stencil flag then result will have a stencil. Format and aa level
* will always match.
*/
kApprox_ScratchTexMatch
};
/** /**
* Returns a texture matching the desc. It's contents are unknown. Subsequent * Returns a texture matching the desc. It's contents are unknown. Subsequent
* requests with the same descriptor are not guaranteed to return the same * requests with the same descriptor are not guaranteed to return the same
* texture. The same texture is guaranteed not be returned again until it is * texture. The same texture is guaranteed not be returned again until it is
* unlocked. * unlocked. Must call be balanced with an unlockTexture() call.
* *
* Textures created by createAndLockTexture() hide the complications of * Textures created by createAndLockTexture() hide the complications of
* tiling non-power-of-two textures on APIs that don't support this (e.g. * tiling non-power-of-two textures on APIs that don't support this (e.g.
* unextended GLES2). Tiling a npot texture created by lockKeylessTexture on * unextended GLES2). Tiling a npot texture created by lockScratchTexture on
* such an API will create gaps in the tiling pattern. This includes clamp * such an API will create gaps in the tiling pattern. This includes clamp
* mode. (This may be addressed in a future update.) * mode. (This may be addressed in a future update.)
*/ */
GrTextureEntry* lockKeylessTexture(const GrTextureDesc& desc); TextureCacheEntry lockScratchTexture(const GrTextureDesc& desc, ScratchTexMatch match);
/**
* Finds a texture that approximately matches the descriptor. Will be
* at least as large in width and height as desc specifies. If desc
* specifies that texture is a render target then result will be a
* render target. If desc specifies a render target and doesn't set the
* no stencil flag then result will have a stencil. Format and aa level
* will always match.
*/
GrTextureEntry* findApproximateKeylessTexture(const GrTextureDesc& desc);
/** /**
* When done with an entry, call unlockTexture(entry) on it, which returns * When done with an entry, call unlockTexture(entry) on it, which returns
* it to the cache, where it may be purged. * it to the cache, where it may be purged.
*/ */
void unlockTexture(GrTextureEntry* entry); void unlockTexture(TextureCacheEntry entry);
/** /**
* Creates a texture that is outside the cache. Does not count against * Creates a texture that is outside the cache. Does not count against
@ -195,9 +235,6 @@ public:
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Platform Surfaces // Platform Surfaces
// GrContext provides an interface for wrapping externally created textures
// and rendertargets in their Gr-equivalents.
/** /**
* Wraps an existing 3D API surface in a GrObject. desc.fFlags determines * Wraps an existing 3D API surface in a GrObject. desc.fFlags determines
* the type of object returned. If kIsTexture is set the returned object * the type of object returned. If kIsTexture is set the returned object
@ -213,6 +250,7 @@ public:
* on failure. * on failure.
*/ */
GrResource* createPlatformSurface(const GrPlatformSurfaceDesc& desc); GrResource* createPlatformSurface(const GrPlatformSurfaceDesc& desc);
/** /**
* Reads the current target object (e.g. FBO or IDirect3DSurface9*) and * Reads the current target object (e.g. FBO or IDirect3DSurface9*) and
* viewport state from the underlying 3D API and wraps it in a * viewport state from the underlying 3D API and wraps it in a
@ -559,9 +597,9 @@ private:
}; };
DrawCategory fLastDrawCategory; DrawCategory fLastDrawCategory;
GrGpu* fGpu; GrGpu* fGpu;
GrTextureCache* fTextureCache; GrResourceCache* fTextureCache;
GrFontCache* fFontCache; GrFontCache* fFontCache;
GrPathRenderer* fCustomPathRenderer; GrPathRenderer* fCustomPathRenderer;
GrDefaultPathRenderer fDefaultPathRenderer; GrDefaultPathRenderer fDefaultPathRenderer;
@ -597,10 +635,6 @@ private:
static void SetPaint(const GrPaint& paint, GrDrawTarget* target); static void SetPaint(const GrPaint& paint, GrDrawTarget* target);
bool finalizeTextureKey(GrTextureKey*,
const GrSamplerState&,
bool keyless) const;
GrDrawTarget* prepareToDraw(const GrPaint& paint, DrawCategory drawType); GrDrawTarget* prepareToDraw(const GrPaint& paint, DrawCategory drawType);
void drawClipIntoStencil(); void drawClipIntoStencil();
@ -680,24 +714,54 @@ private:
}; };
/** /**
* Unlocks a texture entry when this goes out of scope. Entry may be NULL. * Gets and locks a scratch texture from a descriptor using
* either exact or approximate criteria. Unlocks texture in
* the destructor.
*/ */
class GrAutoUnlockTextureEntry : ::GrNoncopyable { class GrAutoScratchTexture : ::GrNoncopyable {
public: public:
GrAutoUnlockTextureEntry(GrContext* context, GrTextureEntry* entry) GrAutoScratchTexture()
: fContext(context) : fContext(NULL) {
, fEntry(entry) {
} }
~GrAutoUnlockTextureEntry() {
if (fContext && fEntry) { GrAutoScratchTexture(GrContext* context,
const GrTextureDesc& desc,
GrContext::ScratchTexMatch match =
GrContext::kApprox_ScratchTexMatch)
: fContext(NULL) {
this->set(context, desc, match);
}
~GrAutoScratchTexture() {
if (NULL != fContext) {
fContext->unlockTexture(fEntry); fContext->unlockTexture(fEntry);
} }
} }
GrTexture* texture() { return fEntry->texture(); } GrTexture* set(GrContext* context,
const GrTextureDesc& desc,
GrContext::ScratchTexMatch match =
GrContext::kApprox_ScratchTexMatch) {
if (NULL != fContext) {
fContext->unlockTexture(fEntry);
}
fContext = context;
if (NULL != fContext) {
fEntry = fContext->lockScratchTexture(desc, match);
GrTexture* ret = fEntry.texture();
if (NULL == ret) {
fContext = NULL;
}
return ret;
} else {
return NULL;
}
}
GrTexture* texture() { return fEntry.texture(); }
private: private:
GrContext* fContext; GrContext* fContext;
GrTextureEntry* fEntry; GrContext::TextureCacheEntry fEntry;
}; };
#endif #endif

View File

@ -22,7 +22,7 @@
#include "GrInOrderDrawBuffer.h" #include "GrInOrderDrawBuffer.h"
#include "GrPathRenderer.h" #include "GrPathRenderer.h"
#include "GrPathUtils.h" #include "GrPathUtils.h"
#include "GrTextureCache.h" #include "GrResourceCache.h"
#include "GrTextStrike.h" #include "GrTextStrike.h"
#include "SkTrace.h" #include "SkTrace.h"
@ -135,41 +135,66 @@ int GrContext::PaintStageVertexLayoutBits(
enum { enum {
kNPOTBit = 0x1, kNPOTBit = 0x1,
kFilterBit = 0x2, kFilterBit = 0x2,
kKeylessBit = 0x4, kScratchBit = 0x4,
}; };
bool GrContext::finalizeTextureKey(GrTextureKey* key, GrTexture* GrContext::TextureCacheEntry::texture() const {
const GrSamplerState& sampler, if (NULL == fEntry) {
bool keyless) const { return NULL;
uint32_t bits = 0; } else {
uint16_t width = key->width(); return (GrTexture*) fEntry->resource();
uint16_t height = key->height(); }
}
if (!fGpu->npotTextureTileSupport()) { namespace {
// returns true if this is a "special" texture because of gpu NPOT limitations
bool gen_texture_key_values(const GrGpu* gpu,
const GrSamplerState& sampler,
GrContext::TextureKey clientKey,
int width,
int height,
bool scratch,
uint32_t v[4]) {
GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
// we assume we only need 16 bits of width and height
// assert that texture creation will fail anyway if this assumption
// would cause key collisions.
GrAssert(gpu->maxTextureSize() <= SK_MaxU16);
v[0] = clientKey & 0xffffffffUL;
v[1] = (clientKey >> 32) & 0xffffffffUL;
v[2] = width | (height << 16);
v[3] = 0;
if (!gpu->npotTextureTileSupport()) {
bool isPow2 = GrIsPow2(width) && GrIsPow2(height); bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) || bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
(sampler.getWrapY() != GrSamplerState::kClamp_WrapMode); (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
if (tiled && !isPow2) { if (tiled && !isPow2) {
bits |= kNPOTBit; v[3] |= kNPOTBit;
if (GrSamplerState::kNearest_Filter != sampler.getFilter()) { if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bits |= kFilterBit; v[3] |= kFilterBit;
} }
} }
} }
if (keyless) { if (scratch) {
bits |= kKeylessBit; v[3] |= kScratchBit;
} }
key->finalize(bits);
return 0 != bits; return v[3] & kNPOTBit;
}
} }
GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key, GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
const GrSamplerState& sampler) { int width,
finalizeTextureKey(key, sampler, false); int height,
return fTextureCache->findAndLock(*key); const GrSamplerState& sampler) {
uint32_t v[4];
gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
GrResourceKey resourceKey(v);
return TextureCacheEntry(fTextureCache->findAndLock(resourceKey));
} }
static void stretchImage(void* dst, static void stretchImage(void* dst,
@ -199,32 +224,34 @@ static void stretchImage(void* dst,
} }
} }
GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
const GrSamplerState& sampler, const GrSamplerState& sampler,
const GrTextureDesc& desc, const GrTextureDesc& desc,
void* srcData, size_t rowBytes) { void* srcData, size_t rowBytes) {
SK_TRACE_EVENT0("GrContext::createAndLockTexture"); SK_TRACE_EVENT0("GrContext::createAndLockTexture");
GrAssert(key->width() == desc.fWidth);
GrAssert(key->height() == desc.fHeight);
#if GR_DUMP_TEXTURE_UPLOAD #if GR_DUMP_TEXTURE_UPLOAD
GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight); GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
#endif #endif
GrTextureEntry* entry = NULL; TextureCacheEntry entry;
bool special = finalizeTextureKey(key, sampler, false); uint32_t v[4];
if (special) { bool special = gen_texture_key_values(fGpu, sampler, key,
GrTextureEntry* clampEntry; desc.fWidth, desc.fHeight, false, v);
GrTextureKey clampKey(*key); GrResourceKey resourceKey(v);
clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
if (NULL == clampEntry) { if (special) {
clampEntry = createAndLockTexture(&clampKey, TextureCacheEntry clampEntry =
findAndLockTexture(key, desc.fWidth, desc.fHeight,
GrSamplerState::ClampNoFilter());
if (NULL == clampEntry.texture()) {
clampEntry = createAndLockTexture(key,
GrSamplerState::ClampNoFilter(), GrSamplerState::ClampNoFilter(),
desc, srcData, rowBytes); desc, srcData, rowBytes);
GrAssert(NULL != clampEntry); GrAssert(NULL != clampEntry.texture());
if (NULL == clampEntry) { if (NULL == clampEntry.texture()) {
return NULL; return entry;
} }
} }
GrTextureDesc rtDesc = desc; GrTextureDesc rtDesc = desc;
@ -241,7 +268,7 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
if (NULL != texture) { if (NULL != texture) {
GrDrawTarget::AutoStateRestore asr(fGpu); GrDrawTarget::AutoStateRestore asr(fGpu);
fGpu->setRenderTarget(texture->asRenderTarget()); fGpu->setRenderTarget(texture->asRenderTarget());
fGpu->setTexture(0, clampEntry->texture()); fGpu->setTexture(0, clampEntry.texture());
fGpu->disableStencil(); fGpu->disableStencil();
fGpu->setViewMatrix(GrMatrix::I()); fGpu->setViewMatrix(GrMatrix::I());
fGpu->setAlpha(0xff); fGpu->setAlpha(0xff);
@ -276,7 +303,7 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint)); verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
0, 4); 0, 4);
entry = fTextureCache->createAndLock(*key, texture); entry.set(fTextureCache->createAndLock(resourceKey, texture));
} }
texture->releaseRenderTarget(); texture->releaseRenderTarget();
} else { } else {
@ -302,69 +329,64 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
stretchedPixels.get(), stretchedPixels.get(),
stretchedRowBytes); stretchedRowBytes);
GrAssert(NULL != texture); GrAssert(NULL != texture);
entry = fTextureCache->createAndLock(*key, texture); entry.set(fTextureCache->createAndLock(resourceKey, texture));
} }
fTextureCache->unlock(clampEntry); fTextureCache->unlock(clampEntry.cacheEntry());
} else { } else {
GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes); GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
if (NULL != texture) { if (NULL != texture) {
entry = fTextureCache->createAndLock(*key, texture); entry.set(fTextureCache->createAndLock(resourceKey, texture));
} else {
entry = NULL;
} }
} }
return entry; return entry;
} }
GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) { namespace {
uint32_t p0 = desc.fFormat; inline void gen_scratch_tex_key_values(const GrGpu* gpu,
uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags; const GrTextureDesc& desc,
GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight); uint32_t v[4]) {
this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true); // Instead of a client-provided key of the texture contents
// we create a key of from the descriptor.
GrTextureEntry* entry = fTextureCache->findAndLock(key); GrContext::TextureKey descKey = desc.fAALevel |
if (NULL == entry) { (desc.fFlags << 8) |
GrTexture* texture = fGpu->createTexture(desc, NULL, 0); ((uint64_t) desc.fFormat << 32);
if (NULL != texture) { // this code path isn't friendly to tiling with NPOT restricitons
entry = fTextureCache->createAndLock(key, texture); // We just pass ClampNoFilter()
} gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
} desc.fWidth, desc.fHeight, true, v);
// If the caller gives us the same desc/sampler twice we don't want }
// to return the same texture the second time (unless it was previously
// released). So we detach the entry from the cache and reattach at release.
if (NULL != entry) {
fTextureCache->detach(entry);
}
return entry;
} }
GrTextureEntry* GrContext::findApproximateKeylessTexture( GrContext::TextureCacheEntry GrContext::lockScratchTexture(
const GrTextureDesc& inDesc) { const GrTextureDesc& inDesc,
ScratchTexMatch match) {
GrTextureDesc desc = inDesc; GrTextureDesc desc = inDesc;
// bin by pow2 with a reasonable min if (kExact_ScratchTexMatch != match) {
static const int MIN_SIZE = 256; // bin by pow2 with a reasonable min
desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth)); static const int MIN_SIZE = 256;
desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight)); desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
}
uint32_t p0 = desc.fFormat; uint32_t p0 = desc.fFormat;
uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags; uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
GrTextureEntry* entry; GrResourceEntry* entry;
bool keepTrying = true;
int origWidth = desc.fWidth; int origWidth = desc.fWidth;
int origHeight = desc.fHeight; int origHeight = desc.fHeight;
bool doubledW = false; bool doubledW = false;
bool doubledH = false; bool doubledH = false;
do { do {
GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight); uint32_t v[4];
this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true); gen_scratch_tex_key_values(fGpu, desc, v);
GrResourceKey key(v);
entry = fTextureCache->findAndLock(key); entry = fTextureCache->findAndLock(key);
// if we miss, relax the fit of the flags... // if we miss, relax the fit of the flags...
// then try doubling width... then height. // then try doubling width... then height.
if (NULL != entry) { if (NULL != entry || kExact_ScratchTexMatch == match) {
break; break;
} }
if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) { if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
@ -392,9 +414,9 @@ GrTextureEntry* GrContext::findApproximateKeylessTexture(
desc.fHeight = origHeight; desc.fHeight = origHeight;
GrTexture* texture = fGpu->createTexture(desc, NULL, 0); GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
if (NULL != texture) { if (NULL != texture) {
GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight); uint32_t v[4];
this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), gen_scratch_tex_key_values(fGpu, desc, v);
true); GrResourceKey key(v);
entry = fTextureCache->createAndLock(key, texture); entry = fTextureCache->createAndLock(key, texture);
} }
} }
@ -405,14 +427,17 @@ GrTextureEntry* GrContext::findApproximateKeylessTexture(
if (NULL != entry) { if (NULL != entry) {
fTextureCache->detach(entry); fTextureCache->detach(entry);
} }
return entry; return TextureCacheEntry(entry);
} }
void GrContext::unlockTexture(GrTextureEntry* entry) { void GrContext::unlockTexture(TextureCacheEntry entry) {
if (kKeylessBit & entry->key().getPrivateBits()) { // If this is a scratch texture we detached it from the cache
fTextureCache->reattachAndUnlock(entry); // while it was locked (to avoid two callers simultaneously getting
// the same texture).
if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
fTextureCache->reattachAndUnlock(entry.cacheEntry());
} else { } else {
fTextureCache->unlock(entry); fTextureCache->unlock(entry.cacheEntry());
} }
} }
@ -529,9 +554,6 @@ void GrContext::drawPaint(const GrPaint& paint) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
struct GrContext::OffscreenRecord { struct GrContext::OffscreenRecord {
OffscreenRecord() { fEntry0 = NULL; fEntry1 = NULL; }
~OffscreenRecord() { GrAssert(NULL == fEntry0 && NULL == fEntry1); }
enum Downsample { enum Downsample {
k4x4TwoPass_Downsample, k4x4TwoPass_Downsample,
k4x4SinglePass_Downsample, k4x4SinglePass_Downsample,
@ -542,8 +564,8 @@ struct GrContext::OffscreenRecord {
int fTileCountX; int fTileCountX;
int fTileCountY; int fTileCountY;
int fScale; int fScale;
GrTextureEntry* fEntry0; GrAutoScratchTexture fOffscreen0;
GrTextureEntry* fEntry1; GrAutoScratchTexture fOffscreen1;
GrDrawTarget::SavedDrawState fSavedState; GrDrawTarget::SavedDrawState fSavedState;
GrClip fClip; GrClip fClip;
}; };
@ -585,8 +607,8 @@ bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
GrAssert(GR_USE_OFFSCREEN_AA); GrAssert(GR_USE_OFFSCREEN_AA);
GrAssert(NULL == record->fEntry0); GrAssert(NULL == record->fOffscreen0.texture());
GrAssert(NULL == record->fEntry1); GrAssert(NULL == record->fOffscreen1.texture());
GrAssert(!boundRect.isEmpty()); GrAssert(!boundRect.isEmpty());
int boundW = boundRect.width(); int boundW = boundRect.width();
@ -627,31 +649,28 @@ bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
desc.fWidth *= record->fScale; desc.fWidth *= record->fScale;
desc.fHeight *= record->fScale; desc.fHeight *= record->fScale;
record->fOffscreen0.set(this, desc);
record->fEntry0 = this->findApproximateKeylessTexture(desc); if (NULL == record->fOffscreen0.texture()) {
if (NULL == record->fEntry0) {
return false; return false;
} }
// the approximate lookup might have given us some slop space, might as well // the approximate lookup might have given us some slop space, might as well
// use it when computing the tiles size. // use it when computing the tiles size.
// these are scale values, will adjust after considering // these are scale values, will adjust after considering
// the possible second offscreen. // the possible second offscreen.
record->fTileSizeX = record->fEntry0->texture()->width(); record->fTileSizeX = record->fOffscreen0.texture()->width();
record->fTileSizeY = record->fEntry0->texture()->height(); record->fTileSizeY = record->fOffscreen0.texture()->height();
if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
desc.fWidth /= 2; desc.fWidth /= 2;
desc.fHeight /= 2; desc.fHeight /= 2;
record->fEntry1 = this->findApproximateKeylessTexture(desc); record->fOffscreen1.set(this, desc);
if (NULL == record->fEntry1) { if (NULL == record->fOffscreen1.texture()) {
this->unlockTexture(record->fEntry0);
record->fEntry0 = NULL;
return false; return false;
} }
record->fTileSizeX = GrMin(record->fTileSizeX, record->fTileSizeX = GrMin(record->fTileSizeX,
2 * record->fEntry0->texture()->width()); 2 * record->fOffscreen0.texture()->width());
record->fTileSizeY = GrMin(record->fTileSizeY, record->fTileSizeY = GrMin(record->fTileSizeY,
2 * record->fEntry0->texture()->height()); 2 * record->fOffscreen0.texture()->height());
} }
record->fTileSizeX /= record->fScale; record->fTileSizeX /= record->fScale;
record->fTileSizeY /= record->fScale; record->fTileSizeY /= record->fScale;
@ -670,7 +689,7 @@ void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
int tileX, int tileY, int tileX, int tileY,
OffscreenRecord* record) { OffscreenRecord* record) {
GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget(); GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
GrAssert(NULL != offRT0); GrAssert(NULL != offRT0);
GrPaint tempPaint; GrPaint tempPaint;
@ -715,7 +734,7 @@ void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
int tileX, int tileY, int tileX, int tileY,
OffscreenRecord* record) { OffscreenRecord* record) {
SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2"); SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
GrAssert(NULL != record->fEntry0); GrAssert(NULL != record->fOffscreen0.texture());
GrDrawTarget::AutoGeometryPush agp(target); GrDrawTarget::AutoGeometryPush agp(target);
GrIRect tileRect; GrIRect tileRect;
tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX; tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
@ -738,7 +757,7 @@ void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
GrSamplerState::kClamp_WrapMode, filter); GrSamplerState::kClamp_WrapMode, filter);
GrTexture* src = record->fEntry0->texture(); GrTexture* src = record->fOffscreen0.texture();
int scale; int scale;
enum { enum {
@ -746,9 +765,9 @@ void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
}; };
if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
GrAssert(NULL != record->fEntry1); GrAssert(NULL != record->fOffscreen1.texture());
scale = 2; scale = 2;
GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget(); GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
// Do 2x2 downsample from first to second // Do 2x2 downsample from first to second
target->setTexture(kOffscreenStage, src); target->setTexture(kOffscreenStage, src);
@ -762,7 +781,7 @@ void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
scale * tileRect.height()); scale * tileRect.height());
target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage); target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
src = record->fEntry1->texture(); src = record->fOffscreen1.texture();
} else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) { } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
scale = 1; scale = 1;
GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height()); GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
@ -811,16 +830,10 @@ void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
void GrContext::cleanupOffscreenAA(GrDrawTarget* target, void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
GrPathRenderer* pr, GrPathRenderer* pr,
OffscreenRecord* record) { OffscreenRecord* record) {
this->unlockTexture(record->fEntry0);
record->fEntry0 = NULL;
if (pr) { if (pr) {
// Counterpart of scale() in prepareForOffscreenAA() // Counterpart of scale() in prepareForOffscreenAA()
//pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale))); //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
} }
if (NULL != record->fEntry1) {
this->unlockTexture(record->fEntry1);
record->fEntry1 = NULL;
}
target->restoreDrawState(record->fSavedState); target->restoreDrawState(record->fSavedState);
} }
@ -1471,9 +1484,8 @@ void GrContext::writePixels(int left, int top, int width, int height,
const GrTextureDesc desc = { const GrTextureDesc desc = {
kNone_GrTextureFlags, kNone_GrAALevel, width, height, config kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
}; };
GrAutoUnlockTextureEntry aute(this, GrAutoScratchTexture ast(this, desc);
this->findApproximateKeylessTexture(desc)); GrTexture* texture = ast.texture();
GrTexture* texture = aute.texture();
if (NULL == texture) { if (NULL == texture) {
return; return;
} }
@ -1630,8 +1642,8 @@ GrContext::GrContext(GrGpu* gpu) :
fCustomPathRenderer = GrPathRenderer::CreatePathRenderer(); fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
fGpu->setClipPathRenderer(fCustomPathRenderer); fGpu->setClipPathRenderer(fCustomPathRenderer);
fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT, fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
MAX_TEXTURE_CACHE_BYTES); MAX_TEXTURE_CACHE_BYTES);
fFontCache = new GrFontCache(fGpu); fFontCache = new GrFontCache(fGpu);
fLastDrawCategory = kUnbuffered_DrawCategory; fLastDrawCategory = kUnbuffered_DrawCategory;

View File

@ -16,7 +16,6 @@
#include "GrGpu.h" #include "GrGpu.h"
#include "GrTextStrike.h" #include "GrTextStrike.h"
#include "GrTextureCache.h"
#include "GrClipIterator.h" #include "GrClipIterator.h"
#include "GrIndexBuffer.h" #include "GrIndexBuffer.h"
#include "GrVertexBuffer.h" #include "GrVertexBuffer.h"

View File

@ -15,33 +15,33 @@
*/ */
#include "GrTextureCache.h" #include "GrResourceCache.h"
#include "GrTexture.h" #include "GrResource.h"
GrTextureEntry::GrTextureEntry(const GrTextureKey& key, GrTexture* texture) GrResourceEntry::GrResourceEntry(const GrResourceKey& key, GrResource* resource)
: fKey(key), fTexture(texture) { : fKey(key), fResource(resource) {
fLockCount = 0; fLockCount = 0;
fPrev = fNext = NULL; fPrev = fNext = NULL;
// we assume ownership of the texture, and will unref it when we die // we assume ownership of the resource, and will unref it when we die
GrAssert(texture); GrAssert(resource);
} }
GrTextureEntry::~GrTextureEntry() { GrResourceEntry::~GrResourceEntry() {
fTexture->unref(); fResource->unref();
} }
#if GR_DEBUG #if GR_DEBUG
void GrTextureEntry::validate() const { void GrResourceEntry::validate() const {
GrAssert(fLockCount >= 0); GrAssert(fLockCount >= 0);
GrAssert(fTexture); GrAssert(fResource);
fTexture->validate(); fResource->validate();
} }
#endif #endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
GrTextureCache::GrTextureCache(int maxCount, size_t maxBytes) : GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) :
fMaxCount(maxCount), fMaxCount(maxCount),
fMaxBytes(maxBytes) { fMaxBytes(maxBytes) {
fEntryCount = 0; fEntryCount = 0;
@ -52,36 +52,36 @@ GrTextureCache::GrTextureCache(int maxCount, size_t maxBytes) :
fHead = fTail = NULL; fHead = fTail = NULL;
} }
GrTextureCache::~GrTextureCache() { GrResourceCache::~GrResourceCache() {
GrAutoTextureCacheValidate atcv(this); GrAutoResourceCacheValidate atcv(this);
this->removeAll(); this->removeAll();
} }
void GrTextureCache::getLimits(int* maxTextures, size_t* maxTextureBytes) const{ void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) const{
if (maxTextures) { if (maxResources) {
*maxTextures = fMaxCount; *maxResources = fMaxCount;
} }
if (maxTextureBytes) { if (maxResourceBytes) {
*maxTextureBytes = fMaxBytes; *maxResourceBytes = fMaxBytes;
} }
} }
void GrTextureCache::setLimits(int maxTextures, size_t maxTextureBytes) { void GrResourceCache::setLimits(int maxResources, size_t maxResourceBytes) {
bool smaller = (maxTextures < fMaxCount) || (maxTextureBytes < fMaxBytes); bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes);
fMaxCount = maxTextures; fMaxCount = maxResources;
fMaxBytes = maxTextureBytes; fMaxBytes = maxResourceBytes;
if (smaller) { if (smaller) {
this->purgeAsNeeded(); this->purgeAsNeeded();
} }
} }
void GrTextureCache::internalDetach(GrTextureEntry* entry, void GrResourceCache::internalDetach(GrResourceEntry* entry,
bool clientDetach) { bool clientDetach) {
GrTextureEntry* prev = entry->fPrev; GrResourceEntry* prev = entry->fPrev;
GrTextureEntry* next = entry->fNext; GrResourceEntry* next = entry->fNext;
if (prev) { if (prev) {
prev->fNext = next; prev->fNext = next;
@ -97,14 +97,14 @@ void GrTextureCache::internalDetach(GrTextureEntry* entry,
// update our stats // update our stats
if (clientDetach) { if (clientDetach) {
fClientDetachedCount += 1; fClientDetachedCount += 1;
fClientDetachedBytes += entry->texture()->sizeInBytes(); fClientDetachedBytes += entry->resource()->sizeInBytes();
} else { } else {
fEntryCount -= 1; fEntryCount -= 1;
fEntryBytes -= entry->texture()->sizeInBytes(); fEntryBytes -= entry->resource()->sizeInBytes();
} }
} }
void GrTextureCache::attachToHead(GrTextureEntry* entry, void GrResourceCache::attachToHead(GrResourceEntry* entry,
bool clientReattach) { bool clientReattach) {
entry->fPrev = NULL; entry->fPrev = NULL;
entry->fNext = fHead; entry->fNext = fHead;
@ -119,19 +119,19 @@ void GrTextureCache::attachToHead(GrTextureEntry* entry,
// update our stats // update our stats
if (clientReattach) { if (clientReattach) {
fClientDetachedCount -= 1; fClientDetachedCount -= 1;
fClientDetachedBytes -= entry->texture()->sizeInBytes(); fClientDetachedBytes -= entry->resource()->sizeInBytes();
} else { } else {
fEntryCount += 1; fEntryCount += 1;
fEntryBytes += entry->texture()->sizeInBytes(); fEntryBytes += entry->resource()->sizeInBytes();
} }
} }
class GrTextureCache::Key { class GrResourceCache::Key {
typedef GrTextureEntry T; typedef GrResourceEntry T;
const GrTextureKey& fKey; const GrResourceKey& fKey;
public: public:
Key(const GrTextureKey& key) : fKey(key) {} Key(const GrResourceKey& key) : fKey(key) {}
uint32_t getHash() const { return fKey.hashIndex(); } uint32_t getHash() const { return fKey.hashIndex(); }
@ -154,10 +154,10 @@ public:
#endif #endif
}; };
GrTextureEntry* GrTextureCache::findAndLock(const GrTextureKey& key) { GrResourceEntry* GrResourceCache::findAndLock(const GrResourceKey& key) {
GrAutoTextureCacheValidate atcv(this); GrAutoResourceCacheValidate atcv(this);
GrTextureEntry* entry = fCache.find(key); GrResourceEntry* entry = fCache.find(key);
if (entry) { if (entry) {
this->internalDetach(entry, false); this->internalDetach(entry, false);
this->attachToHead(entry, false); this->attachToHead(entry, false);
@ -167,18 +167,18 @@ GrTextureEntry* GrTextureCache::findAndLock(const GrTextureKey& key) {
return entry; return entry;
} }
GrTextureEntry* GrTextureCache::createAndLock(const GrTextureKey& key, GrResourceEntry* GrResourceCache::createAndLock(const GrResourceKey& key,
GrTexture* texture) { GrResource* resource) {
GrAutoTextureCacheValidate atcv(this); GrAutoResourceCacheValidate atcv(this);
GrTextureEntry* entry = new GrTextureEntry(key, texture); GrResourceEntry* entry = new GrResourceEntry(key, resource);
this->attachToHead(entry, false); this->attachToHead(entry, false);
fCache.insert(key, entry); fCache.insert(key, entry);
#if GR_DUMP_TEXTURE_UPLOAD #if GR_DUMP_TEXTURE_UPLOAD
GrPrintf("--- add texture to cache %p, count=%d bytes= %d %d\n", GrPrintf("--- add resource to cache %p, count=%d bytes= %d %d\n",
entry, fEntryCount, texture->sizeInBytes(), fEntryBytes); entry, fEntryCount, resource->sizeInBytes(), fEntryBytes);
#endif #endif
// mark the entry as "busy" so it doesn't get purged // mark the entry as "busy" so it doesn't get purged
@ -187,19 +187,19 @@ GrTextureEntry* GrTextureCache::createAndLock(const GrTextureKey& key,
return entry; return entry;
} }
void GrTextureCache::detach(GrTextureEntry* entry) { void GrResourceCache::detach(GrResourceEntry* entry) {
internalDetach(entry, true); internalDetach(entry, true);
fCache.remove(entry->fKey, entry); fCache.remove(entry->fKey, entry);
} }
void GrTextureCache::reattachAndUnlock(GrTextureEntry* entry) { void GrResourceCache::reattachAndUnlock(GrResourceEntry* entry) {
attachToHead(entry, true); attachToHead(entry, true);
fCache.insert(entry->key(), entry); fCache.insert(entry->key(), entry);
unlock(entry); unlock(entry);
} }
void GrTextureCache::unlock(GrTextureEntry* entry) { void GrResourceCache::unlock(GrResourceEntry* entry) {
GrAutoTextureCacheValidate atcv(this); GrAutoResourceCacheValidate atcv(this);
GrAssert(entry); GrAssert(entry);
GrAssert(entry->isLocked()); GrAssert(entry->isLocked());
@ -209,16 +209,16 @@ void GrTextureCache::unlock(GrTextureEntry* entry) {
this->purgeAsNeeded(); this->purgeAsNeeded();
} }
void GrTextureCache::purgeAsNeeded() { void GrResourceCache::purgeAsNeeded() {
GrAutoTextureCacheValidate atcv(this); GrAutoResourceCacheValidate atcv(this);
GrTextureEntry* entry = fTail; GrResourceEntry* entry = fTail;
while (entry) { while (entry) {
if (fEntryCount <= fMaxCount && fEntryBytes <= fMaxBytes) { if (fEntryCount <= fMaxCount && fEntryBytes <= fMaxBytes) {
break; break;
} }
GrTextureEntry* prev = entry->fPrev; GrResourceEntry* prev = entry->fPrev;
if (!entry->isLocked()) { if (!entry->isLocked()) {
// remove from our cache // remove from our cache
fCache.remove(entry->fKey, entry); fCache.remove(entry->fKey, entry);
@ -227,9 +227,9 @@ void GrTextureCache::purgeAsNeeded() {
this->internalDetach(entry, false); this->internalDetach(entry, false);
#if GR_DUMP_TEXTURE_UPLOAD #if GR_DUMP_TEXTURE_UPLOAD
GrPrintf("--- ~texture from cache %p [%d %d]\n", entry->texture(), GrPrintf("--- ~resource from cache %p [%d %d]\n", entry->resource(),
entry->texture()->width(), entry->resource()->width(),
entry->texture()->height()); entry->resource()->height());
#endif #endif
delete entry; delete entry;
} }
@ -237,15 +237,15 @@ void GrTextureCache::purgeAsNeeded() {
} }
} }
void GrTextureCache::removeAll() { void GrResourceCache::removeAll() {
GrAssert(!fClientDetachedCount); GrAssert(!fClientDetachedCount);
GrAssert(!fClientDetachedBytes); GrAssert(!fClientDetachedBytes);
GrTextureEntry* entry = fHead; GrResourceEntry* entry = fHead;
while (entry) { while (entry) {
GrAssert(!entry->isLocked()); GrAssert(!entry->isLocked());
GrTextureEntry* next = entry->fNext; GrResourceEntry* next = entry->fNext;
delete entry; delete entry;
entry = next; entry = next;
} }
@ -259,8 +259,8 @@ void GrTextureCache::removeAll() {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#if GR_DEBUG #if GR_DEBUG
static int countMatches(const GrTextureEntry* head, const GrTextureEntry* target) { static int countMatches(const GrResourceEntry* head, const GrResourceEntry* target) {
const GrTextureEntry* entry = head; const GrResourceEntry* entry = head;
int count = 0; int count = 0;
while (entry) { while (entry) {
if (target == entry) { if (target == entry) {
@ -277,7 +277,7 @@ static bool both_zero_or_nonzero(int count, size_t bytes) {
} }
#endif #endif
void GrTextureCache::validate() const { void GrResourceCache::validate() const {
GrAssert(!fHead == !fTail); GrAssert(!fHead == !fTail);
GrAssert(both_zero_or_nonzero(fEntryCount, fEntryBytes)); GrAssert(both_zero_or_nonzero(fEntryCount, fEntryBytes));
GrAssert(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes)); GrAssert(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes));
@ -287,14 +287,14 @@ void GrTextureCache::validate() const {
fCache.validate(); fCache.validate();
GrTextureEntry* entry = fHead; GrResourceEntry* entry = fHead;
int count = 0; int count = 0;
size_t bytes = 0; size_t bytes = 0;
while (entry) { while (entry) {
entry->validate(); entry->validate();
GrAssert(fCache.find(entry->key())); GrAssert(fCache.find(entry->key()));
count += 1; count += 1;
bytes += entry->texture()->sizeInBytes(); bytes += entry->resource()->sizeInBytes();
entry = entry->fNext; entry = entry->fNext;
} }
GrAssert(count == fEntryCount - fClientDetachedCount); GrAssert(count == fEntryCount - fClientDetachedCount);

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2010 Google Inc. Copyright 2011 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -15,13 +15,13 @@
*/ */
#ifndef GrTextureCache_DEFINED #ifndef GrResourceCache_DEFINED
#define GrTextureCache_DEFINED #define GrResourceCache_DEFINED
#include "GrTypes.h" #include "GrTypes.h"
#include "GrTHashCache.h" #include "GrTHashCache.h"
class GrTexture; class GrResource;
// return true if a<b, or false if b<a // return true if a<b, or false if b<a
// //
@ -36,11 +36,11 @@ class GrTexture;
} while (0) } while (0)
/** /**
* Helper class for GrTextureCache, the Key is used to identify src data for * Helper class for GrResourceCache, the Key is used to identify src data for
* a texture. It is identified by 2 32bit data fields which can hold any * a resource. It is identified by 2 32bit data fields which can hold any
* data (uninterpreted by the cache) and a width/height. * data (uninterpreted by the cache) and a width/height.
*/ */
class GrTextureKey { class GrResourceKey {
public: public:
enum { enum {
kHashBits = 7, kHashBits = 7,
@ -48,51 +48,53 @@ public:
kHashMask = kHashCount - 1 kHashMask = kHashCount - 1
}; };
GrTextureKey(uint32_t p0, uint32_t p1, uint16_t width, uint16_t height) { GrResourceKey(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3) {
fP0 = p0; fP[0] = p0;
fP1 = p1; fP[1] = p1;
fP2 = width | (height << 16); fP[2] = p2;
GR_DEBUGCODE(fHashIndex = -1); fP[3] = p3;
this->computeHashIndex();
} }
GrTextureKey(const GrTextureKey& src) { GrResourceKey(uint32_t v[4]) {
fP0 = src.fP0; memcpy(fP, v, 4 * sizeof(uint32_t));
fP1 = src.fP1; this->computeHashIndex();
fP2 = src.fP2; }
finalize(src.fPrivateBits);
GrResourceKey(const GrResourceKey& src) {
memcpy(fP, src.fP, 4 * sizeof(uint32_t));
#if GR_DEBUG
this->computeHashIndex();
GrAssert(fHashIndex == src.fHashIndex);
#endif
fHashIndex = src.fHashIndex;
} }
//!< returns hash value [0..kHashMask] for the key //!< returns hash value [0..kHashMask] for the key
int hashIndex() const { return fHashIndex; } int hashIndex() const { return fHashIndex; }
friend bool operator==(const GrTextureKey& a, const GrTextureKey& b) { friend bool operator==(const GrResourceKey& a, const GrResourceKey& b) {
GR_DEBUGASSERT(-1 != a.fHashIndex && -1 != b.fHashIndex); GR_DEBUGASSERT(-1 != a.fHashIndex && -1 != b.fHashIndex);
return a.fP0 == b.fP0 && a.fP1 == b.fP1 && a.fP2 == b.fP2 && return 0 == memcmp(a.fP, b.fP, 4 * sizeof(uint32_t));
a.fPrivateBits == b.fPrivateBits;
} }
friend bool operator!=(const GrTextureKey& a, const GrTextureKey& b) { friend bool operator!=(const GrResourceKey& a, const GrResourceKey& b) {
GR_DEBUGASSERT(-1 != a.fHashIndex && -1 != b.fHashIndex); GR_DEBUGASSERT(-1 != a.fHashIndex && -1 != b.fHashIndex);
return !(a == b); return !(a == b);
} }
friend bool operator<(const GrTextureKey& a, const GrTextureKey& b) { friend bool operator<(const GrResourceKey& a, const GrResourceKey& b) {
RET_IF_LT_OR_GT(a.fP0, b.fP0); RET_IF_LT_OR_GT(a.fP[0], b.fP[0]);
RET_IF_LT_OR_GT(a.fP1, b.fP1); RET_IF_LT_OR_GT(a.fP[1], b.fP[1]);
RET_IF_LT_OR_GT(a.fP2, b.fP2); RET_IF_LT_OR_GT(a.fP[2], b.fP[2]);
return a.fPrivateBits < b.fPrivateBits; return a.fP[3] < b.fP[3];
} }
uint32_t getValue32(int i) const {
GrAssert(i >=0 && i < 4);
return fP[i];
}
private: private:
void finalize(uint32_t privateBits) {
fPrivateBits = privateBits;
this->computeHashIndex();
}
uint16_t width() const { return fP2 & 0xffff; }
uint16_t height() const { return (fP2 >> 16); }
uint32_t getPrivateBits() const { return fPrivateBits; }
static uint32_t rol(uint32_t x) { static uint32_t rol(uint32_t x) {
return (x >> 24) | (x << 8); return (x >> 24) | (x << 8);
@ -105,7 +107,7 @@ private:
} }
void computeHashIndex() { void computeHashIndex() {
uint32_t hash = fP0 ^ rol(fP1) ^ ror(fP2) ^ rohalf(fPrivateBits); uint32_t hash = fP[0] ^ rol(fP[1]) ^ ror(fP[2]) ^ rohalf(fP[3]);
// this way to mix and reduce hash to its index may have to change // this way to mix and reduce hash to its index may have to change
// depending on how many bits we allocate to the index // depending on how many bits we allocate to the index
hash ^= hash >> 16; hash ^= hash >> 16;
@ -113,10 +115,7 @@ private:
fHashIndex = hash & kHashMask; fHashIndex = hash & kHashMask;
} }
uint32_t fP0; uint32_t fP[4];
uint32_t fP1;
uint32_t fP2;
uint32_t fPrivateBits;
// this is computed from the fP... fields // this is computed from the fP... fields
int fHashIndex; int fHashIndex;
@ -126,14 +125,14 @@ private:
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
class GrTextureEntry { class GrResourceEntry {
public: public:
GrTexture* texture() const { return fTexture; } GrResource* resource() const { return fResource; }
const GrTextureKey& key() const { return fKey; } const GrResourceKey& key() const { return fKey; }
#if GR_DEBUG #if GR_DEBUG
GrTextureEntry* next() const { return fNext; } GrResourceEntry* next() const { return fNext; }
GrTextureEntry* prev() const { return fPrev; } GrResourceEntry* prev() const { return fPrev; }
#endif #endif
#if GR_DEBUG #if GR_DEBUG
@ -143,8 +142,8 @@ public:
#endif #endif
private: private:
GrTextureEntry(const GrTextureKey& key, GrTexture* texture); GrResourceEntry(const GrResourceKey& key, GrResource* resource);
~GrTextureEntry(); ~GrResourceEntry();
bool isLocked() const { return fLockCount != 0; } bool isLocked() const { return fLockCount != 0; }
void lock() { ++fLockCount; } void lock() { ++fLockCount; }
@ -153,18 +152,18 @@ private:
--fLockCount; --fLockCount;
} }
GrTextureKey fKey; GrResourceKey fKey;
GrTexture* fTexture; GrResource* fResource;
// track if we're in use, used when we need to purge // track if we're in use, used when we need to purge
// we only purge unlocked entries // we only purge unlocked entries
int fLockCount; int fLockCount;
// we're a dlinklist // we're a dlinklist
GrTextureEntry* fPrev; GrResourceEntry* fPrev;
GrTextureEntry* fNext; GrResourceEntry* fNext;
friend class GrTextureCache; friend class GrResourceCache;
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -172,17 +171,17 @@ private:
#include "GrTHashCache.h" #include "GrTHashCache.h"
/** /**
* Cache of GrTexture objects. * Cache of GrResource objects.
* *
* These have a corresponding GrTextureKey, built from 96bits identifying the * These have a corresponding GrResourceKey, built from 128bits identifying the
* texture/bitmap. * resource.
* *
* The cache stores the entries in a double-linked list, which is its LRU. * The cache stores the entries in a double-linked list, which is its LRU.
* When an entry is "locked" (i.e. given to the caller), it is moved to the * When an entry is "locked" (i.e. given to the caller), it is moved to the
* head of the list. If/when we must purge some of the entries, we walk the * head of the list. If/when we must purge some of the entries, we walk the
* list backwards from the tail, since those are the least recently used. * list backwards from the tail, since those are the least recently used.
* *
* For fast searches, we maintain a sorted array (based on the GrTextureKey) * For fast searches, we maintain a sorted array (based on the GrResourceKey)
* which we can bsearch. When a new entry is added, it is inserted into this * which we can bsearch. When a new entry is added, it is inserted into this
* array. * array.
* *
@ -190,46 +189,46 @@ private:
* a collision between two keys with the same hash, we fall back on the * a collision between two keys with the same hash, we fall back on the
* bsearch, and update the hash to reflect the most recent Key requested. * bsearch, and update the hash to reflect the most recent Key requested.
*/ */
class GrTextureCache { class GrResourceCache {
public: public:
GrTextureCache(int maxCount, size_t maxBytes); GrResourceCache(int maxCount, size_t maxBytes);
~GrTextureCache(); ~GrResourceCache();
/** /**
* Return the current texture cache limits. * Return the current resource cache limits.
* *
* @param maxTextures If non-null, returns maximum number of textures that * @param maxResource If non-null, returns maximum number of resources
* can be held in the cache. * that can be held in the cache.
* @param maxTextureBytes If non-null, returns maximum number of bytes of * @param maxBytes If non-null, returns maximum number of bytes of
* texture memory that can be held in the cache. * gpu memory that can be held in the cache.
*/ */
void getLimits(int* maxTextures, size_t* maxTextureBytes) const; void getLimits(int* maxResources, size_t* maxBytes) const;
/** /**
* Specify the texture cache limits. If the current cache exceeds either * Specify the resource cache limits. If the current cache exceeds either
* of these, it will be purged (LRU) to keep the cache within these limits. * of these, it will be purged (LRU) to keep the cache within these limits.
* *
* @param maxTextures The maximum number of textures that can be held in * @param maxResources The maximum number of resources that can be held in
* the cache. * the cache.
* @param maxTextureBytes The maximum number of bytes of texture memory * @param maxBytes The maximum number of bytes of resource memory that
* that can be held in the cache. * can be held in the cache.
*/ */
void setLimits(int maxTextures, size_t maxTextureBytes); void setLimits(int maxResource, size_t maxResourceBytes);
/** /**
* Search for an entry with the same Key. If found, "lock" it and return it. * Search for an entry with the same Key. If found, "lock" it and return it.
* If not found, return null. * If not found, return null.
*/ */
GrTextureEntry* findAndLock(const GrTextureKey&); GrResourceEntry* findAndLock(const GrResourceKey&);
/** /**
* Create a new entry, based on the specified key and texture, and return * Create a new entry, based on the specified key and resource, and return
* its "locked" entry. * its "locked" entry.
* *
* Ownership of the texture is transferred to the Entry, which will unref() * Ownership of the resource is transferred to the Entry, which will unref()
* it when we are purged or deleted. * it when we are purged or deleted.
*/ */
GrTextureEntry* createAndLock(const GrTextureKey&, GrTexture*); GrResourceEntry* createAndLock(const GrResourceKey&, GrResource*);
/** /**
* Detach removes an entry from the cache. This prevents the entry from * Detach removes an entry from the cache. This prevents the entry from
@ -237,20 +236,20 @@ public:
* entry still counts against the cache's budget and should be reattached * entry still counts against the cache's budget and should be reattached
* when exclusive access is no longer needed. * when exclusive access is no longer needed.
*/ */
void detach(GrTextureEntry*); void detach(GrResourceEntry*);
/** /**
* Reattaches a texture to the cache and unlocks it. Allows it to be found * Reattaches a resource to the cache and unlocks it. Allows it to be found
* by a subsequent findAndLock or be purged (provided its lock count is * by a subsequent findAndLock or be purged (provided its lock count is
* now 0.) * now 0.)
*/ */
void reattachAndUnlock(GrTextureEntry*); void reattachAndUnlock(GrResourceEntry*);
/** /**
* When done with an entry, call unlock(entry) on it, which returns it to * When done with an entry, call unlock(entry) on it, which returns it to
* a purgable state. * a purgable state.
*/ */
void unlock(GrTextureEntry*); void unlock(GrResourceEntry*);
void removeAll(); void removeAll();
@ -261,16 +260,16 @@ public:
#endif #endif
private: private:
void internalDetach(GrTextureEntry*, bool); void internalDetach(GrResourceEntry*, bool);
void attachToHead(GrTextureEntry*, bool); void attachToHead(GrResourceEntry*, bool);
void purgeAsNeeded(); // uses kFreeTexture_DeleteMode void purgeAsNeeded(); // uses kFreeResource_DeleteMode
class Key; class Key;
GrTHashTable<GrTextureEntry, Key, 8> fCache; GrTHashTable<GrResourceEntry, Key, 8> fCache;
// manage the dlink list // manage the dlink list
GrTextureEntry* fHead; GrResourceEntry* fHead;
GrTextureEntry* fTail; GrResourceEntry* fTail;
// our budget, used in purgeAsNeeded() // our budget, used in purgeAsNeeded()
int fMaxCount; int fMaxCount;
@ -286,21 +285,21 @@ private:
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#if GR_DEBUG #if GR_DEBUG
class GrAutoTextureCacheValidate { class GrAutoResourceCacheValidate {
public: public:
GrAutoTextureCacheValidate(GrTextureCache* cache) : fCache(cache) { GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
cache->validate(); cache->validate();
} }
~GrAutoTextureCacheValidate() { ~GrAutoResourceCacheValidate() {
fCache->validate(); fCache->validate();
} }
private: private:
GrTextureCache* fCache; GrResourceCache* fCache;
}; };
#else #else
class GrAutoTextureCacheValidate { class GrAutoResourceCacheValidate {
public: public:
GrAutoTextureCacheValidate(GrTextureCache*) {} GrAutoResourceCacheValidate(GrResourceCache*) {}
}; };
#endif #endif

View File

@ -132,7 +132,6 @@
'../gpu/include/GrTextContext.h', '../gpu/include/GrTextContext.h',
'../gpu/include/GrTextStrike.h', '../gpu/include/GrTextStrike.h',
'../gpu/include/GrTexture.h', '../gpu/include/GrTexture.h',
'../gpu/include/GrTextureCache.h',
'../gpu/include/GrTHashCache.h', '../gpu/include/GrTHashCache.h',
'../gpu/include/GrTLList.h', '../gpu/include/GrTLList.h',
'../gpu/include/GrTypes.h', '../gpu/include/GrTypes.h',
@ -173,13 +172,14 @@
'../gpu/src/GrRectanizer.cpp', '../gpu/src/GrRectanizer.cpp',
'../gpu/src/GrRedBlackTree.h', '../gpu/src/GrRedBlackTree.h',
'../gpu/src/GrResource.cpp', '../gpu/src/GrResource.cpp',
'../gpu/src/GrResourceCache.cpp',
'../gpu/src/GrResourceCache.h',
'../gpu/src/GrStencil.cpp', '../gpu/src/GrStencil.cpp',
'../gpu/src/GrTesselatedPathRenderer.cpp', '../gpu/src/GrTesselatedPathRenderer.cpp',
'../gpu/src/GrTextContext.cpp', '../gpu/src/GrTextContext.cpp',
'../gpu/src/GrTextStrike.cpp', '../gpu/src/GrTextStrike.cpp',
'../gpu/src/GrTextStrike_impl.h', '../gpu/src/GrTextStrike_impl.h',
'../gpu/src/GrTexture.cpp', '../gpu/src/GrTexture.cpp',
'../gpu/src/GrTextureCache.cpp',
'../gpu/src/gr_unittests.cpp', '../gpu/src/gr_unittests.cpp',
'../gpu/src/mac/GrGLDefaultInterface_mac.cpp', '../gpu/src/mac/GrGLDefaultInterface_mac.cpp',

View File

@ -22,6 +22,7 @@
#include "SkBitmap.h" #include "SkBitmap.h"
#include "SkDevice.h" #include "SkDevice.h"
#include "SkRegion.h" #include "SkRegion.h"
#include "GrContext.h"
struct SkDrawProcs; struct SkDrawProcs;
struct GrSkDrawProcs; struct GrSkDrawProcs;
@ -126,18 +127,16 @@ public:
virtual void makeRenderTargetCurrent(); virtual void makeRenderTargetCurrent();
protected: protected:
typedef GrContext::TextureCacheEntry TexCache;
class TexCache;
enum TexType { enum TexType {
kBitmap_TexType, kBitmap_TexType,
kDeviceRenderTarget_TexType, kDeviceRenderTarget_TexType,
kSaveLayerDeviceRenderTarget_TexType kSaveLayerDeviceRenderTarget_TexType
}; };
TexCache* lockCachedTexture(const SkBitmap& bitmap, TexCache lockCachedTexture(const SkBitmap& bitmap,
const GrSamplerState& sampler, const GrSamplerState& sampler,
GrTexture** texture, TexType type = kBitmap_TexType);
TexType type = kBitmap_TexType); void unlockCachedTexture(TexCache);
void unlockCachedTexture(TexCache*);
class SkAutoCachedTexture { class SkAutoCachedTexture {
public: public:
@ -152,7 +151,7 @@ protected:
private: private:
SkGpuDevice* fDevice; SkGpuDevice* fDevice;
TexCache* fTex; TexCache fTex;
}; };
friend class SkAutoTexCache; friend class SkAutoTexCache;
@ -162,11 +161,11 @@ private:
GrSkDrawProcs* fDrawProcs; GrSkDrawProcs* fDrawProcs;
// state for our offscreen render-target // state for our offscreen render-target
TexCache* fCache; TexCache fCache;
GrTexture* fTexture; GrTexture* fTexture;
GrRenderTarget* fRenderTarget; GrRenderTarget* fRenderTarget;
bool fNeedClear; bool fNeedClear;
bool fNeedPrepareRenderTarget; bool fNeedPrepareRenderTarget;
// called from rt and tex cons // called from rt and tex cons
void initFromRenderTarget(GrContext*, GrRenderTarget*); void initFromRenderTarget(GrContext*, GrRenderTarget*);

View File

@ -231,10 +231,11 @@ private:
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Helper functions // Helper functions
GrTextureEntry* sk_gr_create_bitmap_texture(GrContext* ctx, static const GrContext::TextureKey gUNCACHED_KEY = ~0;
GrTextureKey* key, GrContext::TextureCacheEntry sk_gr_create_bitmap_texture(GrContext* ctx,
const GrSamplerState& sampler, GrContext::TextureKey key,
const SkBitmap& bitmap); const GrSamplerState& sampler,
const SkBitmap& bitmap);
#endif #endif

View File

@ -67,34 +67,33 @@ SkGpuDevice::SkAutoCachedTexture::
const GrSamplerState& sampler, const GrSamplerState& sampler,
GrTexture** texture) { GrTexture** texture) {
GrAssert(texture); GrAssert(texture);
fTex = NULL;
*texture = this->set(device, bitmap, sampler); *texture = this->set(device, bitmap, sampler);
} }
SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() { SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
fTex = NULL;
} }
GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device, GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
const SkBitmap& bitmap, const SkBitmap& bitmap,
const GrSamplerState& sampler) { const GrSamplerState& sampler) {
if (fTex) { if (fTex.texture()) {
fDevice->unlockCachedTexture(fTex); fDevice->unlockCachedTexture(fTex);
} }
fDevice = device; fDevice = device;
GrTexture* texture = (GrTexture*)bitmap.getTexture(); GrTexture* texture = (GrTexture*)bitmap.getTexture();
if (texture) { if (texture) {
// return the native texture // return the native texture
fTex = NULL; fTex.reset();
} else { } else {
// look it up in our cache // look it up in our cache
fTex = device->lockCachedTexture(bitmap, sampler, &texture); fTex = device->lockCachedTexture(bitmap, sampler);
texture = fTex.texture();
} }
return texture; return texture;
} }
SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() { SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
if (fTex) { if (fTex.texture()) {
fDevice->unlockCachedTexture(fTex); fDevice->unlockCachedTexture(fTex);
} }
} }
@ -170,7 +169,6 @@ void SkGpuDevice::initFromRenderTarget(GrContext* context,
fContext = context; fContext = context;
fContext->ref(); fContext->ref();
fCache = NULL;
fTexture = NULL; fTexture = NULL;
fRenderTarget = NULL; fRenderTarget = NULL;
fNeedClear = false; fNeedClear = false;
@ -199,7 +197,6 @@ SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
fContext = context; fContext = context;
fContext->ref(); fContext->ref();
fCache = NULL;
fTexture = NULL; fTexture = NULL;
fRenderTarget = NULL; fRenderTarget = NULL;
fNeedClear = false; fNeedClear = false;
@ -214,10 +211,9 @@ SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
TexType type = (kSaveLayer_Usage == usage) ? TexType type = (kSaveLayer_Usage == usage) ?
kSaveLayerDeviceRenderTarget_TexType : kSaveLayerDeviceRenderTarget_TexType :
kDeviceRenderTarget_TexType; kDeviceRenderTarget_TexType;
fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(), fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(), type);
&fTexture, type); fTexture = fCache.texture();
if (fCache) { if (fTexture) {
SkASSERT(NULL != fTexture);
SkASSERT(NULL != fTexture->asRenderTarget()); SkASSERT(NULL != fTexture->asRenderTarget());
// hold a ref directly on fTexture (even though fCache has one) to match // hold a ref directly on fTexture (even though fCache has one) to match
// other constructor paths. Simplifies cleanup. // other constructor paths. Simplifies cleanup.
@ -260,10 +256,10 @@ SkGpuDevice::~SkGpuDevice() {
SkSafeUnref(fTexture); SkSafeUnref(fTexture);
SkSafeUnref(fRenderTarget); SkSafeUnref(fRenderTarget);
if (fCache) { if (fCache.texture()) {
GrAssert(NULL != fTexture); GrAssert(NULL != fTexture);
GrAssert(fRenderTarget == fTexture->asRenderTarget()); GrAssert(fRenderTarget == fTexture->asRenderTarget());
fContext->unlockTexture((GrTextureEntry*)fCache); fContext->unlockTexture(fCache);
} }
fContext->unref(); fContext->unref();
} }
@ -895,15 +891,13 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
kRGBA_8888_GrPixelConfig kRGBA_8888_GrPixelConfig
}; };
GrTextureEntry* srcEntry = context->findApproximateKeylessTexture(desc); GrAutoScratchTexture srcEntry(context, desc);
GrTextureEntry* dstEntry = context->findApproximateKeylessTexture(desc); GrAutoScratchTexture dstEntry(context, desc);
GrAutoUnlockTextureEntry srcLock(context, srcEntry), if (NULL == srcEntry.texture() || NULL == dstEntry.texture()) {
dstLock(context, dstEntry);
if (NULL == srcEntry || NULL == dstEntry) {
return false; return false;
} }
GrTexture* srcTexture = srcEntry->texture(); GrTexture* srcTexture = srcEntry.texture();
GrTexture* dstTexture = dstEntry->texture(); GrTexture* dstTexture = dstEntry.texture();
if (NULL == srcTexture || NULL == dstTexture) { if (NULL == srcTexture || NULL == dstTexture) {
return false; return false;
} }
@ -939,18 +933,18 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
paint.reset(); paint.reset();
paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter); paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
paint.getTextureSampler(0)->setMatrix(sampleM); paint.getTextureSampler(0)->setMatrix(sampleM);
GrTextureEntry* origEntry = NULL; GrAutoScratchTexture origEntry;
if (blurType != SkMaskFilter::kNormal_BlurType) { if (blurType != SkMaskFilter::kNormal_BlurType) {
// Stash away a copy of the unblurred image. // Stash away a copy of the unblurred image.
origEntry = context->findApproximateKeylessTexture(desc); origEntry.set(context, desc);
if (NULL == origEntry) { if (NULL == origEntry.texture()) {
return false; return false;
} }
context->setRenderTarget(origEntry->texture()->asRenderTarget()); context->setRenderTarget(origEntry.texture()->asRenderTarget());
paint.setTexture(0, srcTexture); paint.setTexture(0, srcTexture);
context->drawRect(paint, srcRect); context->drawRect(paint, srcRect);
} }
GrAutoUnlockTextureEntry origLock(context, origEntry);
for (int i = 1; i < scaleFactor; i *= 2) { for (int i = 1; i < scaleFactor; i *= 2) {
sampleM.setIDiv(srcTexture->width(), srcTexture->height()); sampleM.setIDiv(srcTexture->width(), srcTexture->height());
paint.getTextureSampler(0)->setMatrix(sampleM); paint.getTextureSampler(0)->setMatrix(sampleM);
@ -1011,7 +1005,7 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
} }
if (blurType != SkMaskFilter::kNormal_BlurType) { if (blurType != SkMaskFilter::kNormal_BlurType) {
GrTexture* origTexture = origEntry->texture(); GrTexture* origTexture = origEntry.texture();
paint.getTextureSampler(0)->setFilter(GrSamplerState::kNearest_Filter); paint.getTextureSampler(0)->setFilter(GrSamplerState::kNearest_Filter);
sampleM.setIDiv(origTexture->width(), origTexture->height()); sampleM.setIDiv(origTexture->width(), origTexture->height());
paint.getTextureSampler(0)->setMatrix(sampleM); paint.getTextureSampler(0)->setMatrix(sampleM);
@ -1102,9 +1096,8 @@ static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
kAlpha_8_GrPixelConfig kAlpha_8_GrPixelConfig
}; };
GrAutoUnlockTextureEntry aute(context, GrAutoScratchTexture ast(context, desc);
context->findApproximateKeylessTexture(desc)); GrTexture* texture = ast.texture();
GrTexture* texture = aute.texture();
if (NULL == texture) { if (NULL == texture) {
return false; return false;
@ -1723,12 +1716,10 @@ bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap, SkGpuDevice::TexCache SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
const GrSamplerState& sampler, const GrSamplerState& sampler,
GrTexture** texture, TexType type) {
TexType type) { GrContext::TextureCacheEntry entry;
GrTexture* newTexture = NULL;
GrTextureEntry* entry = NULL;
GrContext* ctx = this->context(); GrContext* ctx = this->context();
if (kBitmap_TexType != type) { if (kBitmap_TexType != type) {
@ -1739,46 +1730,41 @@ SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bitmap.height(), bitmap.height(),
SkGr::Bitmap2PixelConfig(bitmap) SkGr::Bitmap2PixelConfig(bitmap)
}; };
GrContext::ScratchTexMatch match;
if (kSaveLayerDeviceRenderTarget_TexType == type) { if (kSaveLayerDeviceRenderTarget_TexType == type) {
// we know layers will only be drawn through drawDevice. // we know layers will only be drawn through drawDevice.
// drawDevice has been made to work with content embedded in a // drawDevice has been made to work with content embedded in a
// larger texture so its okay to use the approximate version. // larger texture so its okay to use the approximate version.
entry = ctx->findApproximateKeylessTexture(desc); match = GrContext::kApprox_ScratchTexMatch;
} else { } else {
SkASSERT(kDeviceRenderTarget_TexType == type); SkASSERT(kDeviceRenderTarget_TexType == type);
entry = ctx->lockKeylessTexture(desc); match = GrContext::kExact_ScratchTexMatch;
} }
entry = ctx->lockScratchTexture(desc, match);
} else { } else {
if (!bitmap.isVolatile()) { if (!bitmap.isVolatile()) {
uint32_t p0, p1; GrContext::TextureKey key = bitmap.getGenerationID();
p0 = bitmap.getGenerationID(); key |= ((uint64_t) bitmap.pixelRefOffset()) << 32;
p1 = bitmap.pixelRefOffset();
GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
entry = ctx->findAndLockTexture(&key, sampler); entry = ctx->findAndLockTexture(key, bitmap.width(),
if (NULL == entry) bitmap.height(), sampler);
entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, if (NULL == entry.texture()) {
entry = sk_gr_create_bitmap_texture(ctx, key, sampler,
bitmap); bitmap);
}
} else { } else {
entry = sk_gr_create_bitmap_texture(ctx, NULL, sampler, bitmap); entry = sk_gr_create_bitmap_texture(ctx, gUNCACHED_KEY, sampler, bitmap);
} }
if (NULL == entry) { if (NULL == entry.texture()) {
GrPrintf("---- failed to create texture for cache [%d %d]\n", GrPrintf("---- failed to create texture for cache [%d %d]\n",
bitmap.width(), bitmap.height()); bitmap.width(), bitmap.height());
} }
} }
return entry;
if (NULL != entry) {
newTexture = entry->texture();
if (texture) {
*texture = newTexture;
}
}
return (TexCache*)entry;
} }
void SkGpuDevice::unlockCachedTexture(TexCache* cache) { void SkGpuDevice::unlockCachedTexture(TexCache cache) {
this->context()->unlockTexture((GrTextureEntry*)cache); this->context()->unlockTexture(cache);
} }
SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config, SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,

View File

@ -63,13 +63,15 @@ static void build_compressed_data(void* buffer, const SkBitmap& bitmap) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
GrTextureEntry* sk_gr_create_bitmap_texture(GrContext* ctx, GrContext::TextureCacheEntry sk_gr_create_bitmap_texture(GrContext* ctx,
GrTextureKey* key, GrContext::TextureKey key,
const GrSamplerState& sampler, const GrSamplerState& sampler,
const SkBitmap& origBitmap) { const SkBitmap& origBitmap) {
SkAutoLockPixels alp(origBitmap); SkAutoLockPixels alp(origBitmap);
GrContext::TextureCacheEntry entry;
if (!origBitmap.readyToDraw()) { if (!origBitmap.readyToDraw()) {
return NULL; return entry;
} }
SkBitmap tmpBitmap; SkBitmap tmpBitmap;
@ -98,12 +100,13 @@ GrTextureEntry* sk_gr_create_bitmap_texture(GrContext* ctx,
// our compressed data will be trimmed, so pass width() for its // our compressed data will be trimmed, so pass width() for its
// "rowBytes", since they are the same now. // "rowBytes", since they are the same now.
if (NULL != key) { if (gUNCACHED_KEY != key) {
return ctx->createAndLockTexture(key, sampler, desc, storage.get(), return ctx->createAndLockTexture(key, sampler, desc, storage.get(),
bitmap->width()); bitmap->width());
} else { } else {
GrTextureEntry* entry = ctx->lockKeylessTexture(desc); entry = ctx->lockScratchTexture(desc,
entry->texture()->uploadTextureData(0, 0, bitmap->width(), GrContext::kExact_ScratchTexMatch);
entry.texture()->uploadTextureData(0, 0, bitmap->width(),
bitmap->height(), storage.get(), 0); bitmap->height(), storage.get(), 0);
return entry; return entry;
} }
@ -116,12 +119,14 @@ GrTextureEntry* sk_gr_create_bitmap_texture(GrContext* ctx,
} }
desc.fFormat = SkGr::Bitmap2PixelConfig(*bitmap); desc.fFormat = SkGr::Bitmap2PixelConfig(*bitmap);
if (NULL != key) { if (gUNCACHED_KEY != key) {
return ctx->createAndLockTexture(key, sampler, desc, return ctx->createAndLockTexture(key, sampler, desc,
bitmap->getPixels(), bitmap->rowBytes()); bitmap->getPixels(),
bitmap->rowBytes());
} else { } else {
GrTextureEntry* entry = ctx->lockKeylessTexture(desc); entry = ctx->lockScratchTexture(desc,
entry->texture()->uploadTextureData(0, 0, bitmap->width(), GrContext::kExact_ScratchTexMatch);
entry.texture()->uploadTextureData(0, 0, bitmap->width(),
bitmap->height(), bitmap->getPixels(), bitmap->rowBytes()); bitmap->height(), bitmap->getPixels(), bitmap->rowBytes());
return entry; return entry;
} }