Restructure flushing relationship between GrContext, GrDrawingManager, and GrResource...
authorbsalomon <bsalomon@google.com>
Wed, 7 Sep 2016 17:02:04 +0000 (10:02 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 7 Sep 2016 17:02:04 +0000 (10:02 -0700)
Consolidates all flush actions into GrDrawingManager and makes GrContext::flush a passthrough.

Removes the unused and untested discard flush variation.

Replaces the indirect overbudget callback mechanism of GrResourceCache with a flag set by resource cache when it wants to flush that is checked after each draw by GrDrawContext.

Modifies GrResourceCache::notifyFlushOccurred() to take a param indicating whether it triggered the
flush that just occurred.

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2307053002

Committed: https://skia.googlesource.com/skia/+/1dbb207babecdae8f1f74ed9d9900c73064df744
Review-Url: https://codereview.chromium.org/2307053002

include/gpu/GrContext.h
src/gpu/GrContext.cpp
src/gpu/GrDrawContext.cpp
src/gpu/GrDrawingManager.cpp
src/gpu/GrDrawingManager.h
src/gpu/GrResourceCache.cpp
src/gpu/GrResourceCache.h
src/gpu/SkGpuDevice.cpp
tests/ResourceCacheTest.cpp

index f14c36e..996b77f 100644 (file)
@@ -214,31 +214,10 @@ public:
     // Misc.
 
     /**
-     * Flags that affect flush() behavior.
-     */
-    enum FlushBits {
-        /**
-         * A client may reach a point where it has partially rendered a frame
-         * through a GrContext that it knows the user will never see. This flag
-         * causes the flush to skip submission of deferred content to the 3D API
-         * during the flush.
-         */
-        kDiscard_FlushBit                    = 0x2,
-    };
-
-    /**
      * Call to ensure all drawing to the context has been issued to the
      * underlying 3D API.
-     * @param flagsBitfield     flags that control the flushing behavior. See
-     *                          FlushBits.
      */
-    void flush(int flagsBitfield = 0);
-
-    void flushIfNecessary() {
-        if (fFlushToReduceCacheSize || this->caps()->immediateFlush()) {
-            this->flush();
-        }
-    }
+    void flush();
 
    /**
     * These flags can be used with the read/write pixels functions below.
@@ -409,8 +388,6 @@ private:
     GrBatchFontCache*                       fBatchFontCache;
     SkAutoTDelete<GrTextBlobCache>          fTextBlobCache;
 
-    // Set by OverbudgetCB() to request that GrContext flush before exiting a draw.
-    bool                                    fFlushToReduceCacheSize;
     bool                                    fDidTestPMConversions;
     int                                     fPMToUPMConversion;
     int                                     fUPMToPMConversion;
@@ -472,12 +449,6 @@ private:
     bool didFailPMUPMConversionTest() const;
 
     /**
-     *  This callback allows the resource cache to callback into the GrContext
-     *  when the cache is still over budget after a purge.
-     */
-    static void OverBudgetCB(void* data);
-
-    /**
      * A callback similar to the above for use by the TextBlobCache
      * TODO move textblob draw calls below context so we can use the call above.
      */
index 3f4d2fa..357f58e 100644 (file)
@@ -66,7 +66,6 @@ GrContext::GrContext() : fUniqueID(next_id()) {
     fResourceCache = nullptr;
     fResourceProvider = nullptr;
     fBatchFontCache = nullptr;
-    fFlushToReduceCacheSize = false;
 }
 
 bool GrContext::init(GrBackend backend, GrBackendContext backendContext,
@@ -87,7 +86,6 @@ void GrContext::initCommon(const GrContextOptions& options) {
 
     fCaps = SkRef(fGpu->caps());
     fResourceCache = new GrResourceCache(fCaps);
-    fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
     fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner);
 
     fDidTestPMConversions = false;
@@ -97,7 +95,8 @@ void GrContext::initCommon(const GrContextOptions& options) {
     dtOptions.fDrawBatchBounds = options.fDrawBatchBounds;
     dtOptions.fMaxBatchLookback = options.fMaxBatchLookback;
     dtOptions.fMaxBatchLookahead = options.fMaxBatchLookahead;
-    fDrawingManager.reset(new GrDrawingManager(this, dtOptions, &fSingleOwner));
+    fDrawingManager.reset(new GrDrawingManager(this, dtOptions, options.fImmediateMode,
+                                               &fSingleOwner));
 
     // GrBatchFontCache will eventually replace GrFontCache
     fBatchFontCache = new GrBatchFontCache(this);
@@ -203,41 +202,21 @@ void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes)
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrContext::OverBudgetCB(void* data) {
-    SkASSERT(data);
-
-    GrContext* context = reinterpret_cast<GrContext*>(data);
-
-    // Flush the GrBufferedDrawTarget to possibly free up some textures
-    context->fFlushToReduceCacheSize = true;
-}
-
 void GrContext::TextBlobCacheOverBudgetCB(void* data) {
     SkASSERT(data);
-
-    // Unlike the GrResourceCache, TextBlobs are drawn at the SkGpuDevice level, therefore they
-    // cannot use fFlushTorReduceCacheSize because it uses AutoCheckFlush.  The solution is to move
-    // drawText calls to below the GrContext level, but this is not trivial because they call
-    // drawPath on SkGpuDevice
+    // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on GrDrawContext
+    // to perform a necessary flush.  The solution is to move drawText calls to below the GrContext
+    // level, but this is not trivial because they call drawPath on SkGpuDevice.
     GrContext* context = reinterpret_cast<GrContext*>(data);
     context->flush();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrContext::flush(int flagsBitfield) {
+void GrContext::flush() {
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
-    bool flushed = false;
-    if (kDiscard_FlushBit & flagsBitfield) {
-        fDrawingManager->reset();
-    } else {
-        flushed = fDrawingManager->flush();
-    }
-    if (flushed) {
-        fResourceCache->notifyFlushOccurred();
-    }
-    fFlushToReduceCacheSize = false;
+    fDrawingManager->flush();
 }
 
 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
index 87252f3..ed02602 100644 (file)
@@ -59,7 +59,7 @@ public:
     AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
         SkASSERT(fDrawingManager);
     }
-    ~AutoCheckFlush() { fDrawingManager->getContext()->flushIfNecessary(); }
+    ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
 
 private:
     GrDrawingManager* fDrawingManager;
index 6c75c0d..4642e1a 100644 (file)
@@ -5,8 +5,10 @@
  * found in the LICENSE file.
  */
 
-#include "GrDrawContext.h"
 #include "GrDrawingManager.h"
+
+#include "GrContext.h"
+#include "GrDrawContext.h"
 #include "GrDrawTarget.h"
 #include "GrPathRenderingDrawContext.h"
 #include "GrResourceProvider.h"
@@ -74,9 +76,9 @@ void GrDrawingManager::reset() {
     fFlushState.reset();
 }
 
-bool GrDrawingManager::flush() {
+void GrDrawingManager::internalFlush(GrResourceCache::FlushType type) {
     if (fFlushing || this->wasAbandoned()) {
-        return false;
+        return;
     }
     fFlushing = true;
     bool flushed = false;
@@ -126,8 +128,11 @@ bool GrDrawingManager::flush() {
 #endif
 
     fFlushState.reset();
+    // We always have to notify the cache when it requested a flush so it can reset its state.
+    if (flushed || type == GrResourceCache::FlushType::kCacheRequested) {
+        fContext->getResourceCache()->notifyFlushOccurred(type);
+    }
     fFlushing = false;
-    return flushed;
 }
 
 GrDrawTarget* GrDrawingManager::newDrawTarget(GrRenderTarget* rt) {
index 745820f..449044f 100644 (file)
@@ -13,6 +13,7 @@
 #include "GrBatchFlushState.h"
 #include "GrPathRendererChain.h"
 #include "GrPathRenderer.h"
+#include "GrResourceCache.h"
 #include "SkTDArray.h"
 
 class GrContext;
@@ -49,11 +50,19 @@ public:
                                     GrPathRendererChain::DrawType drawType,
                                     GrPathRenderer::StencilSupport* stencilSupport = NULL);
 
+    void flushIfNecessary() {
+        if (fContext->getResourceCache()->requestsFlush()) {
+            this->internalFlush(GrResourceCache::kCacheRequested);
+        } else if (fIsImmediateMode) {
+            this->internalFlush(GrResourceCache::kImmediateMode);
+        }
+    }
+
     static bool ProgramUnitTest(GrContext* context, int maxStages);
 
 private:
     GrDrawingManager(GrContext* context, const GrDrawTarget::Options& optionsForDrawTargets,
-                     GrSingleOwner* singleOwner)
+                     bool isImmediateMode, GrSingleOwner* singleOwner)
         : fContext(context)
         , fOptionsForDrawTargets(optionsForDrawTargets)
         , fSingleOwner(singleOwner)
@@ -62,14 +71,15 @@ private:
         , fPathRendererChain(nullptr)
         , fSoftwarePathRenderer(nullptr)
         , fFlushState(context->getGpu(), context->resourceProvider())
-        , fFlushing(false) {
+        , fFlushing(false)
+        , fIsImmediateMode(isImmediateMode) {
     }
 
     void abandon();
     void cleanup();
     void reset();
-    /** Returns true if there was anything to flush and false otherwise */
-    bool flush();
+    void flush() { this->internalFlush(GrResourceCache::FlushType::kExternal); }
+    void internalFlush(GrResourceCache::FlushType);
 
     friend class GrContext;  // for access to: ctor, abandon, reset & flush
 
@@ -92,6 +102,8 @@ private:
 
     GrBatchFlushState                 fFlushState;
     bool                              fFlushing;
+
+    bool                              fIsImmediateMode;
 };
 
 #endif
index 62360ed..529f87c 100644 (file)
@@ -73,8 +73,7 @@ GrResourceCache::GrResourceCache(const GrCaps* caps)
     , fBytes(0)
     , fBudgetedCount(0)
     , fBudgetedBytes(0)
-    , fOverBudgetCB(nullptr)
-    , fOverBudgetData(nullptr)
+    , fRequestFlush(false)
     , fFlushTimestamps(nullptr)
     , fLastFlushTimestampIndex(0)
     , fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) {
@@ -503,10 +502,9 @@ void GrResourceCache::purgeAsNeeded() {
     this->validate();
 
     if (stillOverbudget) {
-        // Despite the purge we're still over budget. Call our over budget callback. If this frees
-        // any resources then we'll get notified and take appropriate action.
-        (*fOverBudgetCB)(fOverBudgetData);
-        this->validate();
+        // Set this so that GrDrawingManager will issue a flush to free up resources with pending
+        // IO that we were unable to purge in this pass.
+        fRequestFlush = true;
     }
 }
 
@@ -621,16 +619,26 @@ uint32_t GrResourceCache::getNextTimestamp() {
     return fTimestamp++;
 }
 
-void GrResourceCache::notifyFlushOccurred() {
-    if (fFlushTimestamps) {
-        SkASSERT(SkIsPow2(fMaxUnusedFlushes));
-        fLastFlushTimestampIndex = (fLastFlushTimestampIndex + 1) & (fMaxUnusedFlushes - 1);
-        // get the timestamp before accessing fFlushTimestamps because getNextTimestamp will
-        // reallocate fFlushTimestamps on timestamp overflow.
-        uint32_t timestamp = this->getNextTimestamp();
-        fFlushTimestamps[fLastFlushTimestampIndex] = timestamp;
-        this->purgeAsNeeded();
+void GrResourceCache::notifyFlushOccurred(FlushType type) {
+    switch (type) {
+        case FlushType::kImmediateMode:
+            break;
+        case FlushType::kCacheRequested:
+            SkASSERT(fRequestFlush);
+            fRequestFlush = false;
+            break;
+        case FlushType::kExternal:
+            if (fFlushTimestamps) {
+                SkASSERT(SkIsPow2(fMaxUnusedFlushes));
+                fLastFlushTimestampIndex = (fLastFlushTimestampIndex + 1) & (fMaxUnusedFlushes - 1);
+                // get the timestamp before accessing fFlushTimestamps because getNextTimestamp will
+                // reallocate fFlushTimestamps on timestamp overflow.
+                uint32_t timestamp = this->getNextTimestamp();
+                fFlushTimestamps[fLastFlushTimestampIndex] = timestamp;
+            }
+            break;
     }
+    this->purgeAsNeeded();
 }
 
 void GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
index 6c64ddc..bf7b237 100644 (file)
@@ -11,6 +11,7 @@
 #include "GrGpuResource.h"
 #include "GrGpuResourceCacheAccess.h"
 #include "GrGpuResourcePriv.h"
+#include "GrResourceCache.h"
 #include "GrResourceKey.h"
 #include "SkMessageBus.h"
 #include "SkRefCnt.h"
@@ -163,23 +164,16 @@ public:
     /** Purges all resources that don't have external owners. */
     void purgeAllUnlocked();
 
-    /**
-     * The callback function used by the cache when it is still over budget after a purge. The
-     * passed in 'data' is the same 'data' handed to setOverbudgetCallback.
-     */
-    typedef void (*PFOverBudgetCB)(void* data);
+    /** Returns true if the cache would like a flush to occur in order to make more resources
+        purgeable. */
+    bool requestsFlush() const { return fRequestFlush; }
 
-    /**
-     * Set the callback the cache should use when it is still over budget after a purge. The 'data'
-     * provided here will be passed back to the callback. Note that the cache will attempt to purge
-     * any resources newly freed by the callback.
-     */
-    void setOverBudgetCallback(PFOverBudgetCB overBudgetCB, void* data) {
-        fOverBudgetCB = overBudgetCB;
-        fOverBudgetData = data;
-    }
-
-    void notifyFlushOccurred();
+    enum FlushType {
+        kExternal,
+        kImmediateMode,
+        kCacheRequested,
+    };
+    void notifyFlushOccurred(FlushType);
 
 #if GR_CACHE_STATS
     struct Stats {
@@ -326,8 +320,7 @@ private:
     int                                 fBudgetedCount;
     size_t                              fBudgetedBytes;
 
-    PFOverBudgetCB                      fOverBudgetCB;
-    void*                               fOverBudgetData;
+    bool                                fRequestFlush;
 
     // We keep track of the "timestamps" of the last n flushes. If a resource hasn't been used in
     // that time then we well preemptively purge it to reduce memory usage.
index ca84121..4b77431 100644 (file)
@@ -1008,7 +1008,6 @@ void SkGpuDevice::drawBitmapTile(const SkBitmap& bitmap,
     if (nullptr == texture) {
         return;
     }
-
     sk_sp<GrColorSpaceXform> colorSpaceXform =
         GrColorSpaceXform::Make(bitmap.colorSpace(), fDrawContext->getColorSpace(),
                                 bitmap.alphaType());
index 2cbf81c..b568485 100644 (file)
@@ -1133,7 +1133,7 @@ static void test_flush(skiatest::Reporter* reporter) {
             make_unique_key<1>(&k, i);
             r->resourcePriv().setUniqueKey(k);
             r->unref();
-            cache->notifyFlushOccurred();
+            cache->notifyFlushOccurred(GrResourceCache::kExternal);
         }
 
         // Send flush notifications to the cache. Each flush should purge the oldest resource.
@@ -1147,7 +1147,7 @@ static void test_flush(skiatest::Reporter* reporter) {
                 REPORTER_ASSERT(reporter, !SkToBool(r));
                 SkSafeUnref(r);
             }
-            cache->notifyFlushOccurred();
+            cache->notifyFlushOccurred(GrResourceCache::kExternal);
         }
 
         REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
@@ -1169,13 +1169,13 @@ static void test_flush(skiatest::Reporter* reporter) {
             } else {
                 r->unref();
             }
-            cache->notifyFlushOccurred();
+            cache->notifyFlushOccurred(GrResourceCache::kExternal);
         }
 
         for (int i = 0; i < kFlushCount; ++i) {
             // Should get a resource purged every other flush.
             REPORTER_ASSERT(reporter, kFlushCount - i/2 - 1 == cache->getResourceCount());
-            cache->notifyFlushOccurred();
+            cache->notifyFlushOccurred(GrResourceCache::kExternal);
         }
 
         // Unref all the resources that we kept refs on in the first loop.
@@ -1187,7 +1187,7 @@ static void test_flush(skiatest::Reporter* reporter) {
         // get kFlushCount additional flushes. Then everything should be purged.
         for (int i = 0; i < kFlushCount; ++i) {
             REPORTER_ASSERT(reporter, kFlushCount >> 1 == cache->getResourceCount());
-            cache->notifyFlushOccurred();
+            cache->notifyFlushOccurred(GrResourceCache::kExternal);
         }
         REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());