GrTexture can now create its own cache key

http://codereview.appspot.com/6269047/



git-svn-id: http://skia.googlecode.com/svn/trunk@4148 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index b7ada61..072bc47 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -163,17 +163,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-enum {
-    // flags for textures
-    kNPOTBit            = 0x1,
-    kFilterBit          = 0x2,
-    kScratchBit         = 0x4,
-
-    // resource type
-    kTextureBit         = 0x8,
-    kStencilBufferBit   = 0x10
-};
-
 GrTexture* GrContext::TextureCacheEntry::texture() const {
     if (NULL == fEntry) {
         return NULL; 
@@ -183,50 +172,6 @@
 }
 
 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,
-                            int sampleCnt,
-                            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->getCaps().fMaxTextureSize <= SK_MaxU16);
-    v[0] = clientKey & 0xffffffffUL;
-    v[1] = (clientKey >> 32) & 0xffffffffUL;
-    v[2] = width | (height << 16);
-
-    v[3] = (sampleCnt << 24);
-    GrAssert(sampleCnt >= 0 && sampleCnt < 256);
-
-    if (!gpu->getCaps().fNPOTTextureTileSupport) {
-        bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
-
-        bool tiled = NULL != sampler &&
-                     ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
-                      (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
-
-        if (tiled && !isPow2) {
-            v[3] |= kNPOTBit;
-            if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
-                v[3] |= kFilterBit;
-            }
-        }
-    }
-
-    if (scratch) {
-        v[3] |= kScratchBit;
-    }
-
-    v[3] |= kTextureBit;
-
-    return v[3] & kNPOTBit;
-}
 
 // we should never have more than one stencil buffer with same combo of
 // (width,height,samplecount)
@@ -235,7 +180,7 @@
     v[0] = width;
     v[1] = height;
     v[2] = sampleCnt;
-    v[3] = kStencilBufferBit;
+    v[3] = GrResourceKey::kStencilBuffer_TypeBit;
 }
 
 void gen_stencil_key_values(const GrStencilBuffer* sb,
@@ -307,24 +252,18 @@
 }
 
 GrContext::TextureCacheEntry GrContext::findAndLockTexture(
-        TextureKey key,
-        int width,
-        int height,
+        GrTexture::TextureKey key,
+        const GrTextureDesc& desc,
         const GrSamplerState* sampler) {
-    uint32_t v[4];
-    gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
-    GrResourceKey resourceKey(v);
+    GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, sampler, key, desc, false);
     return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
                                             GrResourceCache::kNested_LockType));
 }
 
-bool GrContext::isTextureInCache(TextureKey key,
-                                 int width,
-                                 int height,
+bool GrContext::isTextureInCache(GrTexture::TextureKey key,
+                                 const GrTextureDesc& desc,
                                  const GrSamplerState* sampler) const {
-    uint32_t v[4];
-    gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
-    GrResourceKey resourceKey(v);
+    GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, sampler, key, desc, false);
     return fTextureCache->hasKey(resourceKey);
 }
 
@@ -384,7 +323,7 @@
 }
 
 GrContext::TextureCacheEntry GrContext::createAndLockTexture(
-        TextureKey key,
+        GrTexture::TextureKey key,
         const GrSamplerState* sampler,
         const GrTextureDesc& desc,
         void* srcData,
@@ -396,17 +335,16 @@
 #endif
 
     TextureCacheEntry entry;
-    uint32_t v[4];
-    bool special = gen_texture_key_values(fGpu, sampler, key,
-                                          desc.fWidth, desc.fHeight,
-                                          desc.fSampleCnt, false, v);
-    GrResourceKey resourceKey(v);
 
-    if (special) {
+    GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, sampler, key,
+                                                      desc, false);
+
+    if (GrTexture::NeedsResizing(resourceKey)) {
+        // The desired texture is NPOT and tiled but that isn't supported by 
+        // the current hardware. Resize the texture to be a POT
         GrAssert(NULL != sampler);
         TextureCacheEntry clampEntry = this->findAndLockTexture(key,
-                                                                desc.fWidth,
-                                                                desc.fHeight,
+                                                                desc,
                                                                 NULL);
 
         if (NULL == clampEntry.texture()) {
@@ -437,10 +375,10 @@
             // if filtering is not desired then we want to ensure all
             // texels in the resampled image are copies of texels from
             // the original.
-            if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
-                filter = GrSamplerState::kNearest_Filter;
-            } else {
+            if (GrTexture::NeedsFiltering(resourceKey)) {
                 filter = GrSamplerState::kBilinear_Filter;
+            } else {
+                filter = GrSamplerState::kNearest_Filter;
             }
             drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
                                          filter);
@@ -497,21 +435,6 @@
     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.fFlags << 8) |
-                                    ((uint64_t) desc.fConfig << 32);
-    // this code path isn't friendly to tiling with NPOT restricitons
-    // We just pass ClampNoFilter()
-    gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
-                           desc.fHeight, desc.fSampleCnt, true, v);
-}
-}
-
 GrContext::TextureCacheEntry GrContext::lockScratchTexture(
                                                 const GrTextureDesc& inDesc,
                                                 ScratchTexMatch match) {
@@ -531,9 +454,7 @@
     bool doubledH = false;
 
     do {
-        uint32_t v[4];
-        gen_scratch_tex_key_values(fGpu, desc, v);
-        GrResourceKey key(v);
+        GrResourceKey key = GrTexture::ComputeKey(fGpu, NULL, 0, desc, true);
         entry = fTextureCache->findAndLock(key,
                                            GrResourceCache::kNested_LockType);
         // if we miss, relax the fit of the flags...
@@ -566,9 +487,9 @@
         desc.fHeight = origHeight;
         GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
         if (NULL != texture) {
-            uint32_t v[4];
-            gen_scratch_tex_key_values(fGpu, desc, v);
-            GrResourceKey key(v);
+            GrResourceKey key = GrTexture::ComputeKey(fGpu, NULL, 0,
+                                                      texture->desc(),
+                                                      true);
             entry = fTextureCache->createAndLock(key, texture);
         }
     }
@@ -587,7 +508,7 @@
     // 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)) {
+    if (GrTexture::IsScratchTexture(entry.cacheEntry()->key())) {
         fTextureCache->reattachAndUnlock(entry.cacheEntry());
     } else {
         fTextureCache->unlock(entry.cacheEntry());
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h
index f86fcd2..b83e8ec 100644
--- a/src/gpu/GrResourceCache.h
+++ b/src/gpu/GrResourceCache.h
@@ -41,6 +41,16 @@
         kHashMask   = kHashCount - 1
     };
 
+    enum TypeBits {
+        // resource types
+        kTexture_TypeBit         = 0x01,
+        kStencilBuffer_TypeBit   = 0x02,
+
+        // Derived classes may add additional bits
+        kDummy_TypeBit,
+        kLastPublic_TypeBit = kDummy_TypeBit-1,
+    };
+
     GrResourceKey(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3) {
         fP[0] = p0;
         fP[1] = p1;
diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp
index 00ae8d0..e05b62b 100644
--- a/src/gpu/GrTexture.cpp
+++ b/src/gpu/GrTexture.cpp
@@ -12,6 +12,7 @@
 #include "GrContext.h"
 #include "GrGpu.h"
 #include "GrRenderTarget.h"
+#include "GrResourceCache.h"
 
 bool GrTexture::readPixels(int left, int top, int width, int height,
                            GrPixelConfig config, void* buffer,
@@ -80,3 +81,97 @@
         GrAssert(0 == fDesc.fSampleCnt);
     }
 }
+
+enum TextureBits {
+    kFirst_TextureBit = (GrResourceKey::kLastPublic_TypeBit << 1),
+
+    /*
+     * The kNPOT bit is set when the texture is NPOT and is being repeated
+     * but the hardware doesn't support that feature. 
+     */
+    kNPOT_TextureBit            = kFirst_TextureBit,
+    /*
+     * The kFilter bit can only be set when the kNPOT flag is set and indicates
+     * whether the resizing of the texture should use filtering. This is
+     * to handle cases where the original texture is indexed to disable
+     * filtering.
+     */
+    kFilter_TextureBit          = kNPOT_TextureBit << 1,
+    /*
+     * The kScratch bit is set if the texture is being used as a scratch
+     * texture.
+     */
+    kScratch_TextureBit         = kFilter_TextureBit << 1,
+};
+
+namespace {
+void gen_texture_key_values(const GrGpu* gpu,
+                            const GrSamplerState* sampler,
+                            GrTexture::TextureKey clientKey,
+                            const GrTextureDesc& desc,
+                            bool scratch,
+                            uint32_t v[4]) {
+    GR_STATIC_ASSERT(sizeof(GrTexture::TextureKey) == sizeof(uint64_t));
+
+    if (scratch) {
+        // Instead of a client-provided key of the texture contents
+        // we create a key of from the descriptor.
+        GrAssert(0 == clientKey);
+        clientKey = (desc.fFlags << 8) | ((uint64_t) desc.fConfig << 32);
+    }
+
+    // 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->getCaps().fMaxTextureSize <= SK_MaxU16);
+    v[0] = clientKey & 0xffffffffUL;
+    v[1] = (clientKey >> 32) & 0xffffffffUL;
+    v[2] = desc.fWidth | (desc.fHeight << 16);
+
+    v[3] = (desc.fSampleCnt << 24);
+    GrAssert(desc.fSampleCnt >= 0 && desc.fSampleCnt < 256);
+
+    if (!gpu->getCaps().fNPOTTextureTileSupport) {
+        bool isPow2 = GrIsPow2(desc.fWidth) && GrIsPow2(desc.fHeight);
+
+        bool tiled = NULL != sampler &&
+                   ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
+                    (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
+
+        if (tiled && !isPow2) {
+            v[3] |= kNPOT_TextureBit;
+            if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
+                v[3] |= kFilter_TextureBit;
+            }
+        }
+    }
+
+    if (scratch) {
+        v[3] |= kScratch_TextureBit;
+    }
+
+    v[3] |= GrResourceKey::kTexture_TypeBit;
+}
+}
+
+GrResourceKey GrTexture::ComputeKey(const GrGpu* gpu,
+                                    const GrSamplerState* sampler,
+                                    TextureKey clientKey,
+                                    const GrTextureDesc& desc,
+                                    bool scratch) {
+    uint32_t v[4];
+    gen_texture_key_values(gpu, sampler, clientKey, desc, scratch, v);
+    return GrResourceKey(v);
+}
+
+bool GrTexture::NeedsResizing(const GrResourceKey& key) {
+    return 0 != (key.getValue32(3) & kNPOT_TextureBit);
+}
+
+bool GrTexture::IsScratchTexture(const GrResourceKey& key) {
+    return 0 != (key.getValue32(3) & kScratch_TextureBit);
+}
+
+bool GrTexture::NeedsFiltering(const GrResourceKey& key) {
+    return 0 != (key.getValue32(3) & kFilter_TextureBit);
+}
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 056c5d8..d9d2349 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -230,7 +230,7 @@
         kRenderTarget_GrTextureFlagBit,
         width,
         height,
-        SkGr::Bitmap2PixelConfig(bm),
+        SkGr::BitmapConfig2PixelConfig(bm.config()),
         0 // samples
     };
 
@@ -337,8 +337,7 @@
     if (SkBitmap::kARGB_8888_Config == bitmap.config()) {
         config = config8888_to_gr_config(config8888);
     } else {
-        config= SkGr::BitmapConfig2PixelConfig(bitmap.config(),
-                                               bitmap.isOpaque());
+        config= SkGr::BitmapConfig2PixelConfig(bitmap.config());
     }
 
     fRenderTarget->writePixels(x, y, bitmap.width(), bitmap.height(),
@@ -1831,11 +1830,18 @@
     GrContext* ctx = this->context();
 
     if (!bitmap.isVolatile()) {
-        GrContext::TextureKey key = bitmap.getGenerationID();
+        GrTexture::TextureKey key = bitmap.getGenerationID();
         key |= ((uint64_t) bitmap.pixelRefOffset()) << 32;
 
-        entry = ctx->findAndLockTexture(key, bitmap.width(),
-                                        bitmap.height(), sampler);
+        GrTextureDesc desc = {
+            kNone_GrTextureFlags,
+            bitmap.width(),
+            bitmap.height(),
+            SkGr::BitmapConfig2PixelConfig(bitmap.config()),
+            0 // samples
+        };
+
+        entry = ctx->findAndLockTexture(key, desc, sampler);
         if (NULL == entry.texture()) {
             entry = sk_gr_create_bitmap_texture(ctx, key, sampler,
                                                 bitmap);
@@ -1857,11 +1863,18 @@
 
 bool SkGpuDevice::isBitmapInTextureCache(const SkBitmap& bitmap,
                                          const GrSamplerState& sampler) const {
-    GrContext::TextureKey key = bitmap.getGenerationID();
+    GrTexture::TextureKey key = bitmap.getGenerationID();
     key |= ((uint64_t) bitmap.pixelRefOffset()) << 32;
-    return this->context()->isTextureInCache(key, bitmap.width(),
-                                             bitmap.height(), &sampler);
 
+    GrTextureDesc desc = {
+        kNone_GrTextureFlags,
+        bitmap.width(),
+        bitmap.height(),
+        SkGr::BitmapConfig2PixelConfig(bitmap.config()),
+        0 // samples
+    };
+
+    return this->context()->isTextureInCache(key, desc, &sampler);
 }
 
 
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 12967e2..92a3aff 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -57,7 +57,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 GrContext::TextureCacheEntry sk_gr_create_bitmap_texture(GrContext* ctx,
-                                                GrContext::TextureKey key,
+                                                GrTexture::TextureKey key,
                                                 const GrSamplerState* sampler,
                                                 const SkBitmap& origBitmap) {
     SkAutoLockPixels alp(origBitmap);
@@ -75,7 +75,7 @@
         kNone_GrTextureFlags,
         bitmap->width(),
         bitmap->height(),
-        SkGr::Bitmap2PixelConfig(*bitmap),
+        SkGr::BitmapConfig2PixelConfig(bitmap->config()),
         0 // samples
     };
 
@@ -112,7 +112,7 @@
         }
     }
 
-    desc.fConfig = SkGr::Bitmap2PixelConfig(*bitmap);
+    desc.fConfig = SkGr::BitmapConfig2PixelConfig(bitmap->config());
     if (gUNCACHED_KEY != key) {
         return ctx->createAndLockTexture(key, sampler, desc,
                                          bitmap->getPixels(),
@@ -194,8 +194,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-GrPixelConfig SkGr::BitmapConfig2PixelConfig(SkBitmap::Config config,
-                                                    bool isOpaque) {
+GrPixelConfig SkGr::BitmapConfig2PixelConfig(SkBitmap::Config config) {
     switch (config) {
         case SkBitmap::kA8_Config:
             return kAlpha_8_GrPixelConfig;
@@ -208,6 +207,7 @@
         case SkBitmap::kARGB_8888_Config:
             return kSkia8888_PM_GrPixelConfig;
         default:
+            // kNo_Config, kA1_Config missing, and kRLE_Index8_Config
             return kUnknown_GrPixelConfig;
     }
 }
diff --git a/src/gpu/SkGrTexturePixelRef.cpp b/src/gpu/SkGrTexturePixelRef.cpp
index c81e9c0..485d572 100644
--- a/src/gpu/SkGrTexturePixelRef.cpp
+++ b/src/gpu/SkGrTexturePixelRef.cpp
@@ -62,7 +62,7 @@
     desc.fWidth  = texture->width();
     desc.fHeight = texture->height();
     desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
-    desc.fConfig = SkGr::BitmapConfig2PixelConfig(dstConfig, false);
+    desc.fConfig = SkGr::BitmapConfig2PixelConfig(dstConfig);
     desc.fSampleCnt = 0;
 
     GrTexture* dst = context->createUncachedTexture(desc, NULL, 0);