diff --git a/include/gpu/GrGpuResource.h b/include/gpu/GrGpuResource.h
index c5b8ca5fbb..806a45aa11 100644
--- a/include/gpu/GrGpuResource.h
+++ b/include/gpu/GrGpuResource.h
@@ -191,7 +191,7 @@ protected:
         backend API calls should be made. */
     virtual void onAbandon() { }
 
-    bool isWrapped() const { return kWrapped_FlagBit & fFlags; }
+    bool isWrapped() const { return SkToBool(kWrapped_Flag & fFlags); }
 
     /**
      * This entry point should be called whenever gpuMemorySize() should report a different size.
@@ -221,7 +221,7 @@ private:
 
     // See comments in CacheAccess.
     bool setContentKey(const GrResourceKey& contentKey);
-
+    void setBudgeted(bool countsAgainstBudget);
     void notifyIsPurgable() const;
 
 #ifdef SK_DEBUG
@@ -233,31 +233,39 @@ private:
     // We're in an internal doubly linked list owned by GrResourceCache2
     SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrGpuResource);
 
-    // This is not ref'ed but abandon() or release() will be called before the GrGpu object
-    // is destroyed. Those calls set will this to NULL.
-    GrGpu* fGpu;
-
-    enum Flags {
-        /**
-         * This object wraps a GPU object given to us by the user.
-         * Lifetime management is left up to the user (i.e., we will not
-         * free it).
-         */
-        kWrapped_FlagBit         = 0x1,
-    };
 
     static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
+    enum Flags {
+        /**
+         * The resource counts against the resource cache's budget.
+         */
+        kBudgeted_Flag      = 0x1,
 
-    uint32_t                fFlags;
+        /**
+         * This object wraps a GPU object given to us by Skia's client. Skia will not free the
+         * underlying backend API GPU resources when the GrGpuResource is destroyed. This also
+         * implies that kBudgeted_Flag is not set.
+         */
+        kWrapped_Flag       = 0x2,
 
-    mutable size_t          fGpuMemorySize;
-    const uint32_t          fUniqueID;
+        /**
+         * If set then fContentKey is valid and the resource is cached based on its content.
+         */
+        kContentKeySet_Flag = 0x4,
+    };
 
     // TODO(bsalomon): Remove GrResourceKey and use different simpler types for content and scratch
     // keys.
     GrResourceKey           fScratchKey;
     GrResourceKey           fContentKey;
-    bool                    fContentKeySet;
+
+    // This is not ref'ed but abandon() or release() will be called before the GrGpu object
+    // is destroyed. Those calls set will this to NULL.
+    GrGpu*                  fGpu;
+    mutable size_t          fGpuMemorySize;
+
+    uint32_t                fFlags;
+    const uint32_t          fUniqueID;
 
     typedef GrIORef<GrGpuResource> INHERITED;
     friend class GrIORef<GrGpuResource>; // to access notifyIsPurgable.
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 7012988ab8..e7449da23b 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -490,7 +490,13 @@ GrTexture* GrContext::createUncachedTexture(const GrSurfaceDesc& descIn,
                                             void* srcData,
                                             size_t rowBytes) {
     GrSurfaceDesc descCopy = descIn;
-    return fGpu->createTexture(descCopy, srcData, rowBytes);
+    GrTexture* texture = fGpu->createTexture(descCopy, srcData, rowBytes);
+    if (texture) {
+        // TODO: It'd be nice to be able to do this before creation so we don't boot something
+        // out of the cache. We could temporarily boost the cache budget.
+        texture->cacheAccess().setBudgeted(false);
+    }
+    return texture;
 }
 
 void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
diff --git a/src/gpu/GrGpuResource.cpp b/src/gpu/GrGpuResource.cpp
index ea3756b8dd..8dbbd83ef5 100644
--- a/src/gpu/GrGpuResource.cpp
+++ b/src/gpu/GrGpuResource.cpp
@@ -19,15 +19,15 @@ static inline GrResourceCache2* get_resource_cache2(GrGpu* gpu) {
 }
 
 GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped)
-    : fGpu(gpu)
+    : fScratchKey(GrResourceKey::NullScratchKey())
+    , fGpu(gpu)
     , fGpuMemorySize(kInvalidGpuMemorySize)
-    , fUniqueID(CreateUniqueID())
-    , fScratchKey(GrResourceKey::NullScratchKey())
-    , fContentKeySet(false) {
+    , fUniqueID(CreateUniqueID()) {
     if (isWrapped) {
-        fFlags = kWrapped_FlagBit;
+        fFlags = kWrapped_Flag;
     } else {
-        fFlags = 0;
+        // By default all non-wrapped resources are budgeted.
+        fFlags = kBudgeted_Flag;
     }
 }
 
@@ -92,16 +92,16 @@ bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
     if (this->isWrapped()) {
         return false;
     }
-    
-    if (fContentKeySet || this->wasDestroyed()) {
+
+    if ((fFlags & kContentKeySet_Flag) || this->wasDestroyed()) {
         return false;
     }
 
     fContentKey = contentKey;
-    fContentKeySet = true;
+    fFlags |= kContentKeySet_Flag;
 
     if (!get_resource_cache2(fGpu)->resourceAccess().didSetContentKey(this)) {
-        fContentKeySet = false;
+         fFlags &= ~kContentKeySet_Flag;
         return false;
     }
     return true;
@@ -136,3 +136,21 @@ uint32_t GrGpuResource::CreateUniqueID() {
     } while (id == SK_InvalidUniqueID);
     return id;
 }
+
+void GrGpuResource::setBudgeted(bool countsAgainstBudget) {
+    // Wrapped resources never count against the budget, nothing to do. No point in changing the
+    // budgeting of destroyed resources.
+    if (this->isWrapped() || this->wasDestroyed()) {
+        return;
+    }
+
+    uint32_t oldFlags = fFlags;
+    if (countsAgainstBudget) {
+        fFlags |= kBudgeted_Flag;
+    } else {
+        fFlags &= ~kBudgeted_Flag;
+    }
+    if (fFlags != oldFlags) {
+        get_resource_cache2(fGpu)->resourceAccess().didChangeBudgetStatus(this);
+    }
+}
diff --git a/src/gpu/GrGpuResourceCacheAccess.h b/src/gpu/GrGpuResourceCacheAccess.h
index 7d20fff473..c55bb07774 100644
--- a/src/gpu/GrGpuResourceCacheAccess.h
+++ b/src/gpu/GrGpuResourceCacheAccess.h
@@ -28,6 +28,11 @@ public:
         return fResource->setContentKey(contentKey);
     }
 
+    /**
+     * Changes whether the resource counts against the resource cache budget.
+     */
+    void setBudgeted(bool countsAgainstBudget) { fResource->setBudgeted(countsAgainstBudget); }
+
     /**
      * Is the resource currently cached as scratch? This means it has a valid scratch key and does
      * not have a content key.
@@ -48,14 +53,26 @@ public:
      * If the resource is currently cached by a content key, the key is returned, otherwise NULL.
      */
     const GrResourceKey* getContentKey() const {
-        if (fResource->fContentKeySet) {
+        if (fResource->fFlags & GrGpuResource::kContentKeySet_Flag) {
             return &fResource->fContentKey;
         }
         return NULL;
     }
 
+    /**
+     * Is the resource object wrapping an externally allocated GPU resource?
+     */
     bool isWrapped() const { return fResource->isWrapped(); }
 
+    /**
+     * Does the resource count against the resource budget?
+     */
+    bool isBudgeted() const { 
+        bool ret = SkToBool(GrGpuResource::kBudgeted_Flag & fResource->fFlags);
+        SkASSERT(!(ret && fResource->isWrapped()));
+        return ret;
+    }
+
     /**
      * Called by the cache to delete the resource under normal circumstances.
      */
diff --git a/src/gpu/GrResourceCache2.cpp b/src/gpu/GrResourceCache2.cpp
index d5590d0e20..9764e62329 100644
--- a/src/gpu/GrResourceCache2.cpp
+++ b/src/gpu/GrResourceCache2.cpp
@@ -100,12 +100,12 @@ void GrResourceCache2::insertResource(GrGpuResource* resource) {
 
     size_t size = resource->gpuMemorySize();
     ++fCount;
-    fBytes += resource->gpuMemorySize();
+    fBytes += size;
 #if GR_CACHE_STATS
     fHighWaterCount = SkTMax(fCount, fHighWaterCount);
     fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
 #endif
-    if (!resource->cacheAccess().isWrapped()) {
+    if (resource->cacheAccess().isBudgeted()) {
         ++fBudgetedCount;
         fBudgetedBytes += size;
 #if GR_CACHE_STATS
@@ -114,8 +114,7 @@ void GrResourceCache2::insertResource(GrGpuResource* resource) {
 #endif
     }
     if (!resource->cacheAccess().getScratchKey().isNullScratch()) {
-        // TODO(bsalomon): Make this assertion possible.
-        // SkASSERT(!resource->isWrapped());
+        SkASSERT(!resource->cacheAccess().isWrapped());
         fScratchMap.insert(resource->cacheAccess().getScratchKey(), resource);
     }
     
@@ -130,7 +129,7 @@ void GrResourceCache2::removeResource(GrGpuResource* resource) {
     size_t size = resource->gpuMemorySize();
     --fCount;
     fBytes -= size;
-    if (!resource->cacheAccess().isWrapped()) {
+    if (resource->cacheAccess().isBudgeted()) {
         --fBudgetedCount;
         fBudgetedBytes -= size;
     }
@@ -187,7 +186,6 @@ public:
         if (resource->internalHasRef() || !resource->cacheAccess().isScratch()) {
             return false;
         }
-
         return !fRejectPendingIO || !resource->internalHasPendingIO();
     }
 
@@ -293,7 +291,7 @@ void GrResourceCache2::didChangeGpuMemorySize(const GrGpuResource* resource, siz
 #if GR_CACHE_STATS
     fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
 #endif
-    if (!resource->cacheAccess().isWrapped()) {
+    if (resource->cacheAccess().isBudgeted()) {
         fBudgetedBytes += delta;
 #if GR_CACHE_STATS
         fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
@@ -304,6 +302,26 @@ void GrResourceCache2::didChangeGpuMemorySize(const GrGpuResource* resource, siz
     this->validate();
 }
 
+void GrResourceCache2::didChangeBudgetStatus(GrGpuResource* resource) {
+    SkASSERT(!fPurging);
+    SkASSERT(resource);
+    SkASSERT(this->isInCache(resource));
+
+    size_t size = resource->gpuMemorySize();
+
+    if (resource->cacheAccess().isBudgeted()) {
+        ++fBudgetedCount;
+        fBudgetedBytes += size;
+        this->purgeAsNeeded();
+    } else {
+        --fBudgetedCount;
+        fBudgetedBytes -= size;
+    }
+
+    this->validate();
+}
+
+
 void GrResourceCache2::internalPurgeAsNeeded() {
     SkASSERT(!fPurging);
     SkASSERT(!fNewlyPurgableResourceWhilePurging);
@@ -410,7 +428,7 @@ void GrResourceCache2::validate() const {
             SkASSERT(!resource->cacheAccess().isWrapped());
         }
 
-        if (!resource->cacheAccess().isWrapped()) {
+        if (resource->cacheAccess().isBudgeted()) {
             ++budgetedCount;
             budgetedBytes += resource->gpuMemorySize();
         }
@@ -446,6 +464,8 @@ void GrResourceCache2::printStats() const {
 
     int locked = 0;
     int scratch = 0;
+    int wrapped = 0;
+    size_t unbudgetedSize = 0;
 
     ResourceList::Iter iter;
     GrGpuResource* resource = iter.init(fResources, ResourceList::Iter::kHead_IterStart);
@@ -457,17 +477,23 @@ void GrResourceCache2::printStats() const {
         if (resource->cacheAccess().isScratch()) {
             ++scratch;
         }
+        if (resource->cacheAccess().isWrapped()) {
+            ++wrapped;
+        }
+        if (!resource->cacheAccess().isBudgeted()) {
+            unbudgetedSize += resource->gpuMemorySize();
+        }
     }
 
     float countUtilization = (100.f * fBudgetedCount) / fMaxCount;
     float byteUtilization = (100.f * fBudgetedBytes) / fMaxBytes;
 
     SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes);
-    SkDebugf(
-        "\t\tEntry Count: current %d (%d budgeted, %d locked, %d scratch %.2g%% full), high %d\n",
-        fCount, fBudgetedCount, locked, scratch, countUtilization, fHighWaterCount);
-    SkDebugf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full) high %d\n",
-                fBytes, fBudgetedBytes, byteUtilization, fHighWaterBytes);
+    SkDebugf("\t\tEntry Count: current %d"
+             " (%d budgeted, %d wrapped, %d locked, %d scratch %.2g%% full), high %d\n",
+        fCount, fBudgetedCount, wrapped, locked, scratch, countUtilization, fHighWaterCount);
+    SkDebugf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full, %d unbudgeted) high %d\n",
+                fBytes, fBudgetedBytes, byteUtilization, unbudgetedSize, fHighWaterBytes);
 }
 
 #endif
diff --git a/src/gpu/GrResourceCache2.h b/src/gpu/GrResourceCache2.h
index b0394e3c63..9331e9dfd3 100644
--- a/src/gpu/GrResourceCache2.h
+++ b/src/gpu/GrResourceCache2.h
@@ -22,7 +22,7 @@
  * Resources may have optionally have two types of keys:
  *      1) A scratch key. This is for resources whose allocations are cached but not their contents.
  *         Multiple resources can share the same scratch key. This is so a caller can have two
- *         resource instances with the same properties (e.g. multipass rendering that ping pongs
+ *         resource instances with the same properties (e.g. multipass rendering that ping-pongs
  *         between two temporary surfaces. The scratch key is set at resource creation time and
  *         should never change. Resources need not have a scratch key.
  *      2) A content key. This key represents the contents of the resource rather than just its
@@ -161,6 +161,7 @@ private:
     void notifyPurgable(GrGpuResource*);
     void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize);
     bool didSetContentKey(GrGpuResource*);
+    void didChangeBudgetStatus(GrGpuResource*);
     void makeResourceMRU(GrGpuResource*);
     /// @}
 
@@ -276,6 +277,12 @@ private:
      */
     bool didSetContentKey(GrGpuResource* resource) { return fCache->didSetContentKey(resource); }
 
+
+    /**
+     * Called by GrGpuResources when they change from budgeted to unbudgeted or vice versa.
+     */
+    void didChangeBudgetStatus(GrGpuResource* resource) { fCache->didChangeBudgetStatus(resource); }
+
     // No taking addresses of this type.
     const ResourceAccess* operator&() const;
     ResourceAccess* operator&();
diff --git a/tests/ResourceCacheTest.cpp b/tests/ResourceCacheTest.cpp
index 5fef3d0e75..930bd1217c 100644
--- a/tests/ResourceCacheTest.cpp
+++ b/tests/ResourceCacheTest.cpp
@@ -173,7 +173,7 @@ static void test_no_key(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, 0 == cache2->getResourceBytes());
 }
 
-static void test_wrapped(skiatest::Reporter* reporter) {
+static void test_budgeting(skiatest::Reporter* reporter) {
     SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
     REPORTER_ASSERT(reporter, SkToBool(context));
     if (NULL == context) {
@@ -199,6 +199,9 @@ static void test_wrapped(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, content->cacheAccess().setContentKey(contentKey));
     TestResource* wrapped = new TestResource(context->getGpu(), true);
     scratch->setSize(12);
+    TestResource* unbudgeted = new TestResource(context->getGpu());
+    unbudgeted->setSize(13);
+    unbudgeted->cacheAccess().setBudgeted(false);
 
     // Make sure we can't add a content key to the wrapped resource
     keyData.fData8[0] = 1;
@@ -207,49 +210,60 @@ static void test_wrapped(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, NULL == cache2->findAndRefContentResource(contentKey2));
 
     // Make sure sizes are as we expect
-    REPORTER_ASSERT(reporter, 3 == cache2->getResourceCount());
+    REPORTER_ASSERT(reporter, 4 == cache2->getResourceCount());
     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + content->gpuMemorySize() +
-                              wrapped->gpuMemorySize() == cache2->getResourceBytes());
+                              wrapped->gpuMemorySize() + unbudgeted->gpuMemorySize() ==
+                              cache2->getResourceBytes());
     REPORTER_ASSERT(reporter, 2 == cache2->getBudgetedResourceCount());
     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + content->gpuMemorySize() ==
                               cache2->getBudgetedResourceBytes());
 
     // Our refs mean that the resources are non purgable.
     cache2->purgeAllUnlocked();
-    REPORTER_ASSERT(reporter, 3 == cache2->getResourceCount());
+    REPORTER_ASSERT(reporter, 4 == cache2->getResourceCount());
     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + content->gpuMemorySize() +
-                              wrapped->gpuMemorySize() == cache2->getResourceBytes());
+                              wrapped->gpuMemorySize() + unbudgeted->gpuMemorySize() ==
+                              cache2->getResourceBytes());
     REPORTER_ASSERT(reporter, 2 == cache2->getBudgetedResourceCount());
     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + content->gpuMemorySize() ==
                               cache2->getBudgetedResourceBytes());
 
     // Unreffing the wrapped resource should free it right away.
     wrapped->unref();
-    REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + content->gpuMemorySize() ==
-                              cache2->getResourceBytes());
+    REPORTER_ASSERT(reporter, 3 == cache2->getResourceCount());
+    REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + content->gpuMemorySize() +
+                              unbudgeted->gpuMemorySize() == cache2->getResourceBytes());
 
-    // Now try freeing the other two resources first
+    // Now try freeing the budgeted resources first
     wrapped = new TestResource(context->getGpu(), true);
     scratch->setSize(12);
     content->unref();
     cache2->purgeAllUnlocked();
-    REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + wrapped->gpuMemorySize() ==
-                              cache2->getResourceBytes());
+    REPORTER_ASSERT(reporter, 3 == cache2->getResourceCount());
+    REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + wrapped->gpuMemorySize() +
+                              unbudgeted->gpuMemorySize() == cache2->getResourceBytes());
     REPORTER_ASSERT(reporter, 1 == cache2->getBudgetedResourceCount());
     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() == cache2->getBudgetedResourceBytes());
 
     scratch->unref();
     cache2->purgeAllUnlocked();
-    REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, wrapped->gpuMemorySize() == cache2->getResourceBytes());
+    REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
+    REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() + wrapped->gpuMemorySize() ==
+                              cache2->getResourceBytes());
     REPORTER_ASSERT(reporter, 0 == cache2->getBudgetedResourceCount());
     REPORTER_ASSERT(reporter, 0 == cache2->getBudgetedResourceBytes());
 
     wrapped->unref();
+    REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
+    REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() == cache2->getResourceBytes());
+    REPORTER_ASSERT(reporter, 0 == cache2->getBudgetedResourceCount());
+    REPORTER_ASSERT(reporter, 0 == cache2->getBudgetedResourceBytes());
+
+    unbudgeted->unref();
     REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount());
     REPORTER_ASSERT(reporter, 0 == cache2->getResourceBytes());
+    REPORTER_ASSERT(reporter, 0 == cache2->getBudgetedResourceCount());
+    REPORTER_ASSERT(reporter, 0 == cache2->getBudgetedResourceBytes());
 }
 
 static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
@@ -578,7 +592,7 @@ DEF_GPUTEST(ResourceCache, reporter, factory) {
 
     // The below tests create their own mock contexts.
     test_no_key(reporter);
-    test_wrapped(reporter);
+    test_budgeting(reporter);
     test_duplicate_content_key(reporter);
     test_duplicate_scratch_key(reporter);
     test_purge_invalidated(reporter);