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