Defer flushes if kPreferNoIO is specified
authorrobertphillips <robertphillips@google.com>
Thu, 13 Aug 2015 12:19:14 +0000 (05:19 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 13 Aug 2015 12:19:14 +0000 (05:19 -0700)
Prior to this patch clients who were solely uploading to textures (e.g., SW Mask Mgr) would cause extra flushes b.c., even though kPreferNoIO was being specified, resources with pending IO would still be returned even though there was plenty of space in the resource cache.

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

include/gpu/GrSurface.h
src/gpu/GrAtlasTextContext.cpp
src/gpu/GrGpu.cpp
src/gpu/GrResourceCache.cpp
src/gpu/GrResourceCache.h
src/gpu/GrResourceProvider.cpp
src/gpu/GrSurface.cpp
src/gpu/GrTexture.cpp
src/gpu/GrTextureProvider.cpp
src/gpu/gl/GrGLRenderTarget.cpp
tests/ResourceCacheTest.cpp

index 3515a1a68f2c40cde51efd0bce2443675e912a80..28935009ce8caee78187405c3b50616d7d2e9aed 100644 (file)
@@ -133,6 +133,8 @@ public:
         fReleaseCtx = ctx;
     }
 
+    static size_t WorseCaseSize(const GrSurfaceDesc& desc);
+
 protected:
     // Methods made available via GrSurfacePriv
     SkImageInfo info(SkAlphaType) const;
index 4337d810eb9688dff656a52b3a01bb3312008443..e3149ad14a9bd12ab7fdd7663f1139617e662dda 100644 (file)
@@ -14,7 +14,6 @@
 #include "GrDrawContext.h"
 #include "GrDrawTarget.h"
 #include "GrFontScaler.h"
-#include "GrIndexBuffer.h"
 #include "GrResourceProvider.h"
 #include "GrStrokeInfo.h"
 #include "GrTextBlobCache.h"
index 9c468e7f427366a4afd482e1e91409da06eb2a1c..8c58321eb637cc30fb07ec3c25980bb8a3c6d393 100644 (file)
@@ -79,7 +79,7 @@ GrTexture* GrGpu::createTexture(const GrSurfaceDesc& origDesc, bool budgeted,
         return NULL;
     }
 
-    // We currently not support multisampled textures
+    // We currently do not support multisampled textures
     if (!isRT && desc.fSampleCnt > 0) {
         return NULL;
     }
index 88128ac5000fdfb651b21d0ca2f39751f6738be1..7efe62365bf432f112e12e5a01d9b97fa4f7ec98 100644 (file)
@@ -246,6 +246,7 @@ private:
 };
 
 GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& scratchKey,
+                                                          size_t resourceSize,
                                                           uint32_t flags) {
     SkASSERT(scratchKey.isValid());
 
@@ -259,8 +260,11 @@ GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& sc
         } else if (flags & kRequireNoPendingIO_ScratchFlag) {
             return NULL;
         }
-        // TODO: fail here when kPrefer is specified, we didn't find a resource without pending io,
-        // but there is still space in our budget for the resource.
+        if (this->wouldFit(resourceSize)) {
+            // kPrefer is specified, we didn't find a resource without pending io,
+            // but there is still space in our budget for the resource.
+            return NULL;
+        }
     }
     resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
     if (resource) {
index 5483e1900c9add6512be7d406c0a8bf27e2a5f63..809c4f491e0ae3ba857cfc6668036dc61966d453 100644 (file)
@@ -126,7 +126,9 @@ public:
     /**
      * Find a resource that matches a scratch key.
      */
-    GrGpuResource* findAndRefScratchResource(const GrScratchKey& scratchKey, uint32_t flags = 0);
+    GrGpuResource* findAndRefScratchResource(const GrScratchKey& scratchKey,
+                                             size_t resourceSize,
+                                             uint32_t flags);
     
 #ifdef SK_DEBUG
     // This is not particularly fast and only used for validation, so debug only.
@@ -206,6 +208,10 @@ private:
     void removeFromNonpurgeableArray(GrGpuResource*);
     bool overBudget() const { return fBudgetedBytes > fMaxBytes || fBudgetedCount > fMaxCount; }
 
+    bool wouldFit(size_t bytes) {
+        return fBudgetedBytes+bytes <= fMaxBytes && fBudgetedCount+1 <= fMaxCount;    
+    }
+
     uint32_t getNextTimestamp();
 
 #ifdef SK_DEBUG
index 8b04caca4ecc29ae8155f5cf45cef038b08aad56..3adb0fafc23b88a753ed7f83d70cb99419e70dcb 100644 (file)
@@ -106,7 +106,7 @@ GrIndexBuffer* GrResourceProvider::createIndexBuffer(size_t size, BufferUsage us
         } else {
             scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
         }
-        GrGpuResource* resource = this->cache()->findAndRefScratchResource(key, scratchFlags);
+        GrGpuResource* resource = this->cache()->findAndRefScratchResource(key, size, scratchFlags);
         if (resource) {
             return static_cast<GrIndexBuffer*>(resource);
         }
@@ -135,7 +135,7 @@ GrVertexBuffer* GrResourceProvider::createVertexBuffer(size_t size, BufferUsage
         } else {
             scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
         }
-        GrGpuResource* resource = this->cache()->findAndRefScratchResource(key, scratchFlags);
+        GrGpuResource* resource = this->cache()->findAndRefScratchResource(key, size, scratchFlags);
         if (resource) {
             return static_cast<GrVertexBuffer*>(resource);
         }
index 9bd9e8b5ef51b24290d80969e19dba961382d8da..89cbf4a5460679fad26d154bc017126a84f168c8 100644 (file)
 #include "SkImageEncoder.h"
 #include <stdio.h>
 
+size_t GrSurface::WorseCaseSize(const GrSurfaceDesc& desc) {
+    size_t size;
+
+    bool isRenderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
+    if (isRenderTarget) {
+        // We own one color value for each MSAA sample.
+        int colorValuesPerPixel = SkTMax(1, desc.fSampleCnt);
+        if (desc.fSampleCnt) {
+            // Worse case, we own the resolve buffer so that is one more sample per pixel.
+            colorValuesPerPixel += 1;
+        }
+        SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
+        SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
+        size_t colorBytes = GrBytesPerPixel(desc.fConfig);
+        SkASSERT(colorBytes > 0);
+        size = colorValuesPerPixel * desc.fWidth * desc.fHeight * colorBytes;
+    } else {
+        if (GrPixelConfigIsCompressed(desc.fConfig)) {
+            size = GrCompressedFormatDataSize(desc.fConfig, desc.fWidth, desc.fHeight);
+        } else {
+            size = (size_t) desc.fWidth * desc.fHeight * GrBytesPerPixel(desc.fConfig);
+        }
+
+        size += size/3;  // in case we have to mipmap
+    }
+
+    return size;
+}
+
 template<typename T> static bool adjust_params(int surfaceWidth,
                                                int surfaceHeight,
                                                size_t bpp,
index b76075747889f2fea50194c6be486c221a5d2c0a..7984460545db61d3b5dfb8c6120f24719e909365 100644 (file)
@@ -42,8 +42,12 @@ size_t GrTexture::onGpuMemorySize() const {
     if (this->texturePriv().hasMipMaps()) {
         // We don't have to worry about the mipmaps being a different size than
         // we'd expect because we never change fDesc.fWidth/fHeight.
-        textureSize *= 2;
+        textureSize += textureSize/3;
     }
+
+    SkASSERT(!SkToBool(fDesc.fFlags & kRenderTarget_GrSurfaceFlag));
+    SkASSERT(textureSize <= WorseCaseSize(fDesc));
+
     return textureSize;
 }
 
index 97d5a79da19ee6413ee804f3ed07da576f10bcd5..253fe032ed90e9b8cab86824560f0289a5150d7a 100644 (file)
@@ -86,7 +86,9 @@ GrTexture* GrTextureProvider::refScratchTexture(const GrSurfaceDesc& inDesc,
             // writePixels() which will trigger a flush if the texture has pending IO.
             scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
         }
-        GrGpuResource* resource = fCache->findAndRefScratchResource(key, scratchFlags);
+        GrGpuResource* resource = fCache->findAndRefScratchResource(key,
+                                                                   GrSurface::WorseCaseSize(*desc),
+                                                                   scratchFlags);
         if (resource) {
             GrSurface* surface = static_cast<GrSurface*>(resource);
             GrRenderTarget* rt = surface->asRenderTarget();
index e93c5c100be2a206756e107c675acd10d4bfe072..26c8d4665836ff4063ac4c66e08ba1afc0f0def0 100644 (file)
@@ -52,6 +52,8 @@ void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) {
     size_t colorBytes = GrBytesPerPixel(fDesc.fConfig);
     SkASSERT(colorBytes > 0);
     fGpuMemorySize = colorValuesPerPixel * fDesc.fWidth * fDesc.fHeight * colorBytes;
+
+    SkASSERT(fGpuMemorySize <= WorseCaseSize(desc));
 }
 
 size_t GrGLRenderTarget::onGpuMemorySize() const {
index 43f087004fc42b0dc31b77767dde4abaf247dfb5..d5ee8454afd798837d4d5edc6b179ec17ac5a5ef 100644 (file)
@@ -225,9 +225,9 @@ static void test_wrapped_resources(skiatest::Reporter* reporter, GrContext* cont
 }
 
 class TestResource : public GrGpuResource {
-    static const size_t kDefaultSize = 100;
     enum ScratchConstructor { kScratchConstructor };
 public:
+    static const size_t kDefaultSize = 100;
     
     /** Property that distinctly categorizes the resource.
      * For example, textures have width, height, ... */
@@ -560,7 +560,7 @@ void test_unbudgeted_to_scratch(skiatest::Reporter* reporter);
         REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key);
         REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch());
         REPORTER_ASSERT(reporter, !resource->resourcePriv().isBudgeted());
-        REPORTER_ASSERT(reporter, NULL == cache->findAndRefScratchResource(key));
+        REPORTER_ASSERT(reporter, NULL == cache->findAndRefScratchResource(key, TestResource::kDefaultSize, 0));
         REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
         REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
         REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
@@ -572,7 +572,7 @@ void test_unbudgeted_to_scratch(skiatest::Reporter* reporter);
         REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
         REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
         REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes());
-        resource = static_cast<TestResource*>(cache->findAndRefScratchResource(key));
+        resource = static_cast<TestResource*>(cache->findAndRefScratchResource(key, TestResource::kDefaultSize, 0));
         REPORTER_ASSERT(reporter, resource);
         REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key);
         REPORTER_ASSERT(reporter, resource->cacheAccess().isScratch());
@@ -618,7 +618,7 @@ static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
     GrScratchKey scratchKey1;
     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1);
     // Check for negative case consistency. (leaks upon test failure.)
-    REPORTER_ASSERT(reporter, NULL == cache->findAndRefScratchResource(scratchKey1));
+    REPORTER_ASSERT(reporter, NULL == cache->findAndRefScratchResource(scratchKey1, TestResource::kDefaultSize, 0));
 
     GrScratchKey scratchKey;
     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
@@ -665,7 +665,7 @@ static void test_remove_scratch_key(skiatest::Reporter* reporter) {
     // Ensure that scratch key lookup is correct for negative case.
     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
     // (following leaks upon test failure).
-    REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey) == NULL);
+    REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0) == NULL);
 
     // Scratch resources are registered with GrResourceCache just by existing. There are 2.
     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
@@ -675,7 +675,7 @@ static void test_remove_scratch_key(skiatest::Reporter* reporter) {
 
     // Find the first resource and remove its scratch key
     GrGpuResource* find;
-    find = cache->findAndRefScratchResource(scratchKey);
+    find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
     find->resourcePriv().removeScratchKey();
     // It's still alive, but not cached by scratch key anymore
     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
@@ -689,7 +689,7 @@ static void test_remove_scratch_key(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
 
     // Repeat for the second resource.
-    find = cache->findAndRefScratchResource(scratchKey);
+    find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
     find->resourcePriv().removeScratchKey();
     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
@@ -745,20 +745,20 @@ static void test_scratch_key_consistency(skiatest::Reporter* reporter) {
     // Ensure that scratch key lookup is correct for negative case.
     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
     // (following leaks upon test failure).
-    REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey) == NULL);
+    REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0) == NULL);
 
     // Find the first resource with a scratch key and a copy of a scratch key.
     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
-    GrGpuResource* find = cache->findAndRefScratchResource(scratchKey);
+    GrGpuResource* find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
     REPORTER_ASSERT(reporter, find != NULL);
     find->unref();
 
     scratchKey2 = scratchKey;
-    find = cache->findAndRefScratchResource(scratchKey2);
+    find = cache->findAndRefScratchResource(scratchKey2, TestResource::kDefaultSize, 0);
     REPORTER_ASSERT(reporter, find != NULL);
     REPORTER_ASSERT(reporter, find == a || find == b);
 
-    GrGpuResource* find2 = cache->findAndRefScratchResource(scratchKey2);
+    GrGpuResource* find2 = cache->findAndRefScratchResource(scratchKey2, TestResource::kDefaultSize, 0);
     REPORTER_ASSERT(reporter, find2 != NULL);
     REPORTER_ASSERT(reporter, find2 == a || find2 == b);
     REPORTER_ASSERT(reporter, find2 != find);
@@ -916,13 +916,13 @@ static void test_purge_invalidated(skiatest::Reporter* reporter) {
     // Make sure we actually get to c via it's scratch key, before we say goodbye.
     GrScratchKey scratchKey;
     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
-    GrGpuResource* scratch = cache->findAndRefScratchResource(scratchKey);
+    GrGpuResource* scratch = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
     REPORTER_ASSERT(reporter, scratch == c);
     SkSafeUnref(scratch);
 
     // Get rid of c.
     cache->purgeAllUnlocked();
-    scratch = cache->findAndRefScratchResource(scratchKey);
+    scratch = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());