First pass at improving temporary tex/rt reuse
Review URL: http://codereview.appspot.com/4625043/




git-svn-id: http://skia.googlecode.com/svn/trunk@1616 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index ab5ac06..56ebb68 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -337,6 +337,75 @@
     return entry;
 }
 
+GrTextureEntry* GrContext::findApproximateKeylessTexture(
+                                                    const GrTextureDesc& inDesc) {
+    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));
+
+    uint32_t p0 = desc.fFormat;
+    uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
+    
+    GrTextureEntry* entry;
+    bool keepTrying = true;
+    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);
+        entry = fTextureCache->findAndLock(key);
+
+        // if we miss, relax the fit of the flags...
+        // then try doubling width... then height.
+        if (NULL != entry) {
+            break;
+        }
+        if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
+            desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
+        } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
+            desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
+        } else if (!doubledW) {
+            desc.fFlags = inDesc.fFlags;
+            desc.fWidth *= 2;
+            doubledW = true;
+        } else if (!doubledH) {
+            desc.fFlags = inDesc.fFlags;
+            desc.fWidth = origWidth;
+            desc.fHeight *= 2;
+            doubledH = true;
+        } else {
+            break;
+        }
+        
+    } while (true);
+
+    if (NULL == entry) {
+        desc.fFlags = inDesc.fFlags;
+        desc.fWidth = origWidth;
+        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);
+            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;
+}
+
 void GrContext::unlockTexture(GrTextureEntry* entry) {
     if (kKeylessBit & entry->key().getPrivateBits()) {
         fTextureCache->reattachAndUnlock(entry);
@@ -466,7 +535,8 @@
         k4x4SinglePass_Downsample,
         kFSAA_Downsample
     }                              fDownsample;
-    int                            fTileSize;
+    int                            fTileSizeX;
+    int                            fTileSizeY;
     int                            fTileCountX;
     int                            fTileCountY;
     int                            fScale;
@@ -518,14 +588,11 @@
     int boundW = boundRect.width();
     int boundH = boundRect.height();
 
-    record->fTileSize  = (int)GrNextPow2(GrMax(boundW, boundH));
-    record->fTileSize = GrMax(64, record->fTileSize);
-    record->fTileSize = GrMin(fMaxOffscreenAASize, record->fTileSize);
-
-    record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSize);
-    record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSize);
-
     GrTextureDesc desc;
+
+    desc.fWidth  = GrMin(fMaxOffscreenAASize, boundW);
+    desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
+
     if (requireStencil) {
         desc.fFlags = kRenderTarget_GrTextureFlagBit;
     } else {
@@ -548,26 +615,41 @@
         GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
         desc.fAALevel = kNone_GrAALevel;
     }
-    
-    desc.fWidth = record->fScale * record->fTileSize;
-    desc.fHeight = record->fScale * record->fTileSize;
 
-    record->fEntry0 = this->lockKeylessTexture(desc);
+    desc.fWidth *= record->fScale;
+    desc.fHeight *= record->fScale;
 
+    record->fEntry0 = this->findApproximateKeylessTexture(desc);
     if (NULL == record->fEntry0) {
         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();
 
     if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
         desc.fWidth /= 2;
         desc.fHeight /= 2;
-        record->fEntry1 = this->lockKeylessTexture(desc);
+        record->fEntry1 = this->findApproximateKeylessTexture(desc);
         if (NULL == record->fEntry1) {
             this->unlockTexture(record->fEntry0);
             record->fEntry0 = NULL;
             return false;
         }
+        record->fTileSizeX = GrMin(record->fTileSizeX, 
+                                   2 * record->fEntry0->texture()->width());
+        record->fTileSizeY = GrMin(record->fTileSizeY, 
+                                   2 * record->fEntry0->texture()->height());
     }
+    record->fTileSizeX /= record->fScale;
+    record->fTileSizeY /= record->fScale;
+
+    record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
+    record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
+
     target->saveCurrentDrawState(&record->fSavedState);
     return true;
 }
@@ -586,8 +668,8 @@
     target->setRenderTarget(offRT0);
 
     GrMatrix transM;
-    int left = boundRect.fLeft + tileX * record->fTileSize;
-    int top =  boundRect.fTop  + tileY * record->fTileSize;
+    int left = boundRect.fLeft + tileX * record->fTileSizeX;
+    int top =  boundRect.fTop  + tileY * record->fTileSizeY;
     transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
     target->postConcatViewMatrix(transM);
     GrMatrix scaleM;
@@ -598,9 +680,9 @@
     target->disableState(GrDrawTarget::kClip_StateBit);
 
     int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
-                                               record->fTileSize;
+                                               record->fTileSizeX;
     int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
-                                               record->fTileSize;
+                                               record->fTileSizeY;
     GrIRect clear = SkIRect::MakeWH(record->fScale * w, 
                                     record->fScale * h);
 #if 0
@@ -627,14 +709,14 @@
     GrAssert(NULL != record->fEntry0);
     
     GrIRect tileRect;
-    tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSize;
-    tileRect.fTop  = boundRect.fTop  + tileY * record->fTileSize,
+    tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
+    tileRect.fTop  = boundRect.fTop  + tileY * record->fTileSizeY,
     tileRect.fRight = (tileX == record->fTileCountX-1) ? 
                         boundRect.fRight :
-                        tileRect.fLeft + record->fTileSize;
+                        tileRect.fLeft + record->fTileSizeX;
     tileRect.fBottom = (tileY == record->fTileCountY-1) ? 
                         boundRect.fBottom :
-                        tileRect.fTop + record->fTileSize;
+                        tileRect.fTop + record->fTileSizeY;
 
     GrSamplerState::Filter filter;
     if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {