Adding a new SkSurface factory for generating surfaces from the scratch texture pool.

TEST=Surface unit test
BUG=crbug.com/351798
R=bsalomon@google.com, robertphillips@google.com, reed@google.com

Author: junov@chromium.org

Review URL: https://codereview.chromium.org/201153023

git-svn-id: http://skia.googlecode.com/svn/trunk@13864 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index c7e3433..c480a1f 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -220,6 +220,10 @@
   return fTextureCache->getCachedResourceBytes();
 }
 
+int GrContext::getGpuTextureCacheResourceCount() const {
+  return fTextureCache->getCachedResourceCount();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 GrTexture* GrContext::findAndRefTexture(const GrTextureDesc& desc,
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h
index 41c6b51..b595303 100644
--- a/src/gpu/GrResourceCache.h
+++ b/src/gpu/GrResourceCache.h
@@ -213,6 +213,11 @@
      */
     size_t getCachedResourceBytes() const { return fEntryBytes; }
 
+    /**
+     * Returns the number of cached resources.
+     */
+    int getCachedResourceCount() const { return fEntryCount; }
+
     // For a found or added resource to be completely exclusive to the caller
     // both the kNoOtherOwners and kHide flags need to be specified
     enum OwnershipFlags {
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index de01953..e9682d2 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -158,31 +158,31 @@
     return bitmap;
 }
 
-SkGpuDevice* SkGpuDevice::Create(GrSurface* surface) {
+SkGpuDevice* SkGpuDevice::Create(GrSurface* surface, unsigned flags) {
     SkASSERT(NULL != surface);
     if (NULL == surface->asRenderTarget() || NULL == surface->getContext()) {
         return NULL;
     }
     if (surface->asTexture()) {
-        return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asTexture()));
+        return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asTexture(), flags));
     } else {
-        return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asRenderTarget()));
+        return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asRenderTarget(), flags));
     }
 }
 
-SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
+SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture, unsigned flags)
     : SkBitmapDevice(make_bitmap(context, texture->asRenderTarget())) {
-    this->initFromRenderTarget(context, texture->asRenderTarget(), false);
+    this->initFromRenderTarget(context, texture->asRenderTarget(), flags);
 }
 
-SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
+SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget, unsigned flags)
     : SkBitmapDevice(make_bitmap(context, renderTarget)) {
-    this->initFromRenderTarget(context, renderTarget, false);
+    this->initFromRenderTarget(context, renderTarget, flags);
 }
 
 void SkGpuDevice::initFromRenderTarget(GrContext* context,
                                        GrRenderTarget* renderTarget,
-                                       bool cached) {
+                                       unsigned flags) {
     fDrawProcs = NULL;
 
     fContext = context;
@@ -192,7 +192,7 @@
     fFallbackTextContext = SkNEW_ARGS(GrBitmapTextContext, (fContext, fLeakyProperties));
 
     fRenderTarget = NULL;
-    fNeedClear = false;
+    fNeedClear = flags & kNeedClear_Flag;
 
     SkASSERT(NULL != renderTarget);
     fRenderTarget = renderTarget;
@@ -209,7 +209,7 @@
 
     SkImageInfo info;
     surface->asImageInfo(&info);
-    SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, surface, cached));
+    SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, surface, flags & kCached_Flag));
 
     this->setPixelRef(pr)->unref();
 }
@@ -1971,11 +1971,12 @@
 
     SkAutoTUnref<GrTexture> texture;
     // Skia's convention is to only clear a device if it is non-opaque.
-    bool needClear = !info.isOpaque();
+    unsigned flags = info.isOpaque() ? 0 : kNeedClear_Flag;
 
 #if CACHE_COMPATIBLE_DEVICE_TEXTURES
     // layers are never draw in repeat modes, so we can request an approx
     // match and ignore any padding.
+    flags |= kCached_Flag;
     const GrContext::ScratchTexMatch match = (kSaveLayer_Usage == usage) ?
                                                 GrContext::kApprox_ScratchTexMatch :
                                                 GrContext::kExact_ScratchTexMatch;
@@ -1984,7 +1985,7 @@
     texture.reset(fContext->createUncachedTexture(desc, NULL, 0));
 #endif
     if (NULL != texture.get()) {
-        return SkNEW_ARGS(SkGpuDevice,(fContext, texture, needClear));
+        return SkGpuDevice::Create(texture, flags);
     } else {
         GrPrintf("---- failed to create compatible device texture [%d %d]\n",
                  info.width(), info.height());
@@ -1996,18 +1997,6 @@
     return SkSurface::NewRenderTarget(fContext, info, fRenderTarget->numSamples());
 }
 
-SkGpuDevice::SkGpuDevice(GrContext* context,
-                         GrTexture* texture,
-                         bool needClear)
-    : SkBitmapDevice(make_bitmap(context, texture->asRenderTarget())) {
-
-    SkASSERT(texture && texture->asRenderTarget());
-    // This constructor is called from onCreateDevice. It has locked the RT in the texture
-    // cache. We pass true for the third argument so that it will get unlocked.
-    this->initFromRenderTarget(context, texture->asRenderTarget(), true);
-    fNeedClear = needClear;
-}
-
 class GPUAccelData : public SkPicture::AccelData {
 public:
     GPUAccelData(Key key) : INHERITED(key) { }
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index ae05ea8..50d6606 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -14,7 +14,7 @@
 public:
     SK_DECLARE_INST_COUNT(SkSurface_Gpu)
 
-    SkSurface_Gpu(GrRenderTarget*);
+    SkSurface_Gpu(GrRenderTarget*, bool cached);
     virtual ~SkSurface_Gpu();
 
     virtual SkCanvas* onNewCanvas() SK_OVERRIDE;
@@ -32,9 +32,9 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkSurface_Gpu::SkSurface_Gpu(GrRenderTarget* renderTarget)
+SkSurface_Gpu::SkSurface_Gpu(GrRenderTarget* renderTarget, bool cached)
         : INHERITED(renderTarget->width(), renderTarget->height()) {
-    fDevice = SkNEW_ARGS(SkGpuDevice, (renderTarget->getContext(), renderTarget));
+    fDevice = SkGpuDevice::Create(renderTarget, cached ? SkGpuDevice::kCached_Flag : 0);
 
     if (kRGB_565_GrPixelConfig != renderTarget->config()) {
         fDevice->clear(0x0);
@@ -95,7 +95,7 @@
     if (NULL == target) {
         return NULL;
     }
-    return SkNEW_ARGS(SkSurface_Gpu, (target));
+    return SkNEW_ARGS(SkSurface_Gpu, (target, false));
 }
 
 SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, const SkImageInfo& info, int sampleCount) {
@@ -117,5 +117,28 @@
         return NULL;
     }
 
-    return SkNEW_ARGS(SkSurface_Gpu, (tex->asRenderTarget()));
+    return SkNEW_ARGS(SkSurface_Gpu, (tex->asRenderTarget(), false));
+}
+
+SkSurface* SkSurface::NewScratchRenderTarget(GrContext* ctx, const SkImageInfo& info, int sampleCount) {
+    if (NULL == ctx) {
+        return NULL;
+    }
+
+    SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
+
+    GrTextureDesc desc;
+    desc.fFlags = kRenderTarget_GrTextureFlagBit | kCheckAllocation_GrTextureFlagBit;
+    desc.fWidth = info.fWidth;
+    desc.fHeight = info.fHeight;
+    desc.fConfig = SkBitmapConfig2GrPixelConfig(config);
+    desc.fSampleCnt = sampleCount;
+
+    SkAutoTUnref<GrTexture> tex(ctx->lockAndRefScratchTexture(desc, GrContext::kExact_ScratchTexMatch));
+
+    if (NULL == tex) {
+        return NULL;
+    }
+
+    return SkNEW_ARGS(SkSurface_Gpu, (tex->asRenderTarget(), true));
 }