Restructure flushing relationship between GrContext, GrDrawingManager, and GrResourceCache.

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

Review-Url: https://codereview.chromium.org/2307053002
This commit is contained in:
bsalomon 2016-09-06 12:38:00 -07:00 committed by Commit bot
parent 0a441077dc
commit 1dbb207bab
9 changed files with 70 additions and 105 deletions

View File

@ -213,32 +213,11 @@ public:
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Misc. // 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 * Call to ensure all drawing to the context has been issued to the
* underlying 3D API. * underlying 3D API.
* @param flagsBitfield flags that control the flushing behavior. See
* FlushBits.
*/ */
void flush(int flagsBitfield = 0); void flush();
void flushIfNecessary() {
if (fFlushToReduceCacheSize || this->caps()->immediateFlush()) {
this->flush();
}
}
/** /**
* These flags can be used with the read/write pixels functions below. * These flags can be used with the read/write pixels functions below.
@ -409,8 +388,6 @@ private:
GrBatchFontCache* fBatchFontCache; GrBatchFontCache* fBatchFontCache;
SkAutoTDelete<GrTextBlobCache> fTextBlobCache; SkAutoTDelete<GrTextBlobCache> fTextBlobCache;
// Set by OverbudgetCB() to request that GrContext flush before exiting a draw.
bool fFlushToReduceCacheSize;
bool fDidTestPMConversions; bool fDidTestPMConversions;
int fPMToUPMConversion; int fPMToUPMConversion;
int fUPMToPMConversion; int fUPMToPMConversion;
@ -471,12 +448,6 @@ private:
will fail. In such cases fall back to SW conversion. */ will fail. In such cases fall back to SW conversion. */
bool didFailPMUPMConversionTest() const; 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 * 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. * TODO move textblob draw calls below context so we can use the call above.

View File

@ -66,7 +66,6 @@ GrContext::GrContext() : fUniqueID(next_id()) {
fResourceCache = nullptr; fResourceCache = nullptr;
fResourceProvider = nullptr; fResourceProvider = nullptr;
fBatchFontCache = nullptr; fBatchFontCache = nullptr;
fFlushToReduceCacheSize = false;
} }
bool GrContext::init(GrBackend backend, GrBackendContext backendContext, bool GrContext::init(GrBackend backend, GrBackendContext backendContext,
@ -87,7 +86,6 @@ void GrContext::initCommon(const GrContextOptions& options) {
fCaps = SkRef(fGpu->caps()); fCaps = SkRef(fGpu->caps());
fResourceCache = new GrResourceCache(fCaps); fResourceCache = new GrResourceCache(fCaps);
fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner); fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner);
fDidTestPMConversions = false; fDidTestPMConversions = false;
@ -97,7 +95,8 @@ void GrContext::initCommon(const GrContextOptions& options) {
dtOptions.fDrawBatchBounds = options.fDrawBatchBounds; dtOptions.fDrawBatchBounds = options.fDrawBatchBounds;
dtOptions.fMaxBatchLookback = options.fMaxBatchLookback; dtOptions.fMaxBatchLookback = options.fMaxBatchLookback;
dtOptions.fMaxBatchLookahead = options.fMaxBatchLookahead; 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 // GrBatchFontCache will eventually replace GrFontCache
fBatchFontCache = new GrBatchFontCache(this); 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) { void GrContext::TextBlobCacheOverBudgetCB(void* data) {
SkASSERT(data); SkASSERT(data);
// TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on GrDrawContext
// Unlike the GrResourceCache, TextBlobs are drawn at the SkGpuDevice level, therefore they // to perform a necessary flush. The solution is to move drawText calls to below the GrContext
// cannot use fFlushTorReduceCacheSize because it uses AutoCheckFlush. The solution is to move // level, but this is not trivial because they call drawPath on SkGpuDevice.
// drawText calls to below the GrContext level, but this is not trivial because they call
// drawPath on SkGpuDevice
GrContext* context = reinterpret_cast<GrContext*>(data); GrContext* context = reinterpret_cast<GrContext*>(data);
context->flush(); context->flush();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void GrContext::flush(int flagsBitfield) { void GrContext::flush() {
ASSERT_SINGLE_OWNER ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED RETURN_IF_ABANDONED
bool flushed = false; fDrawingManager->flush();
if (kDiscard_FlushBit & flagsBitfield) {
fDrawingManager->reset();
} else {
flushed = fDrawingManager->flush();
}
if (flushed) {
fResourceCache->notifyFlushOccurred();
}
fFlushToReduceCacheSize = false;
} }
bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes, bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,

View File

@ -59,7 +59,7 @@ public:
AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) { AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
SkASSERT(fDrawingManager); SkASSERT(fDrawingManager);
} }
~AutoCheckFlush() { fDrawingManager->getContext()->flushIfNecessary(); } ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
private: private:
GrDrawingManager* fDrawingManager; GrDrawingManager* fDrawingManager;

View File

@ -5,8 +5,10 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#include "GrDrawContext.h"
#include "GrDrawingManager.h" #include "GrDrawingManager.h"
#include "GrContext.h"
#include "GrDrawContext.h"
#include "GrDrawTarget.h" #include "GrDrawTarget.h"
#include "GrPathRenderingDrawContext.h" #include "GrPathRenderingDrawContext.h"
#include "GrResourceProvider.h" #include "GrResourceProvider.h"
@ -74,9 +76,9 @@ void GrDrawingManager::reset() {
fFlushState.reset(); fFlushState.reset();
} }
bool GrDrawingManager::flush() { void GrDrawingManager::internalFlush(GrResourceCache::FlushType type) {
if (fFlushing || this->wasAbandoned()) { if (fFlushing || this->wasAbandoned()) {
return false; return;
} }
fFlushing = true; fFlushing = true;
bool flushed = false; bool flushed = false;
@ -126,8 +128,11 @@ bool GrDrawingManager::flush() {
#endif #endif
fFlushState.reset(); 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; fFlushing = false;
return flushed;
} }
GrDrawTarget* GrDrawingManager::newDrawTarget(GrRenderTarget* rt) { GrDrawTarget* GrDrawingManager::newDrawTarget(GrRenderTarget* rt) {

View File

@ -13,6 +13,7 @@
#include "GrBatchFlushState.h" #include "GrBatchFlushState.h"
#include "GrPathRendererChain.h" #include "GrPathRendererChain.h"
#include "GrPathRenderer.h" #include "GrPathRenderer.h"
#include "GrResourceCache.h"
#include "SkTDArray.h" #include "SkTDArray.h"
class GrContext; class GrContext;
@ -49,11 +50,19 @@ public:
GrPathRendererChain::DrawType drawType, GrPathRendererChain::DrawType drawType,
GrPathRenderer::StencilSupport* stencilSupport = NULL); 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); static bool ProgramUnitTest(GrContext* context, int maxStages);
private: private:
GrDrawingManager(GrContext* context, const GrDrawTarget::Options& optionsForDrawTargets, GrDrawingManager(GrContext* context, const GrDrawTarget::Options& optionsForDrawTargets,
GrSingleOwner* singleOwner) bool isImmediateMode, GrSingleOwner* singleOwner)
: fContext(context) : fContext(context)
, fOptionsForDrawTargets(optionsForDrawTargets) , fOptionsForDrawTargets(optionsForDrawTargets)
, fSingleOwner(singleOwner) , fSingleOwner(singleOwner)
@ -68,8 +77,8 @@ private:
void abandon(); void abandon();
void cleanup(); void cleanup();
void reset(); void reset();
/** Returns true if there was anything to flush and false otherwise */ void flush() { this->internalFlush(GrResourceCache::FlushType::kExternal); }
bool flush(); void internalFlush(GrResourceCache::FlushType);
friend class GrContext; // for access to: ctor, abandon, reset & flush friend class GrContext; // for access to: ctor, abandon, reset & flush
@ -92,6 +101,8 @@ private:
GrBatchFlushState fFlushState; GrBatchFlushState fFlushState;
bool fFlushing; bool fFlushing;
bool fIsImmediateMode;
}; };
#endif #endif

View File

@ -73,8 +73,6 @@ GrResourceCache::GrResourceCache(const GrCaps* caps)
, fBytes(0) , fBytes(0)
, fBudgetedCount(0) , fBudgetedCount(0)
, fBudgetedBytes(0) , fBudgetedBytes(0)
, fOverBudgetCB(nullptr)
, fOverBudgetData(nullptr)
, fFlushTimestamps(nullptr) , fFlushTimestamps(nullptr)
, fLastFlushTimestampIndex(0) , fLastFlushTimestampIndex(0)
, fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) { , fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) {
@ -503,10 +501,9 @@ void GrResourceCache::purgeAsNeeded() {
this->validate(); this->validate();
if (stillOverbudget) { if (stillOverbudget) {
// Despite the purge we're still over budget. Call our over budget callback. If this frees // Set this so that GrDrawingManager will issue a flush to free up resources with pending
// any resources then we'll get notified and take appropriate action. // IO that we were unable to purge in this pass.
(*fOverBudgetCB)(fOverBudgetData); fRequestFlush = true;
this->validate();
} }
} }
@ -621,16 +618,26 @@ uint32_t GrResourceCache::getNextTimestamp() {
return fTimestamp++; return fTimestamp++;
} }
void GrResourceCache::notifyFlushOccurred() { void GrResourceCache::notifyFlushOccurred(FlushType type) {
if (fFlushTimestamps) { switch (type) {
SkASSERT(SkIsPow2(fMaxUnusedFlushes)); case FlushType::kImmediateMode:
fLastFlushTimestampIndex = (fLastFlushTimestampIndex + 1) & (fMaxUnusedFlushes - 1); break;
// get the timestamp before accessing fFlushTimestamps because getNextTimestamp will case FlushType::kCacheRequested:
// reallocate fFlushTimestamps on timestamp overflow. SkASSERT(fRequestFlush);
uint32_t timestamp = this->getNextTimestamp(); fRequestFlush = false;
fFlushTimestamps[fLastFlushTimestampIndex] = timestamp; break;
this->purgeAsNeeded(); 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 { void GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {

View File

@ -11,6 +11,7 @@
#include "GrGpuResource.h" #include "GrGpuResource.h"
#include "GrGpuResourceCacheAccess.h" #include "GrGpuResourceCacheAccess.h"
#include "GrGpuResourcePriv.h" #include "GrGpuResourcePriv.h"
#include "GrResourceCache.h"
#include "GrResourceKey.h" #include "GrResourceKey.h"
#include "SkMessageBus.h" #include "SkMessageBus.h"
#include "SkRefCnt.h" #include "SkRefCnt.h"
@ -163,23 +164,16 @@ public:
/** Purges all resources that don't have external owners. */ /** Purges all resources that don't have external owners. */
void purgeAllUnlocked(); void purgeAllUnlocked();
/** /** Returns true if the cache would like a flush to occur in order to make more resources
* The callback function used by the cache when it is still over budget after a purge. The purgeable. */
* passed in 'data' is the same 'data' handed to setOverbudgetCallback. bool requestsFlush() const { return fRequestFlush; }
*/
typedef void (*PFOverBudgetCB)(void* data);
/** enum FlushType {
* Set the callback the cache should use when it is still over budget after a purge. The 'data' kExternal,
* provided here will be passed back to the callback. Note that the cache will attempt to purge kImmediateMode,
* any resources newly freed by the callback. kCacheRequested,
*/ };
void setOverBudgetCallback(PFOverBudgetCB overBudgetCB, void* data) { void notifyFlushOccurred(FlushType);
fOverBudgetCB = overBudgetCB;
fOverBudgetData = data;
}
void notifyFlushOccurred();
#if GR_CACHE_STATS #if GR_CACHE_STATS
struct Stats { struct Stats {
@ -326,8 +320,7 @@ private:
int fBudgetedCount; int fBudgetedCount;
size_t fBudgetedBytes; size_t fBudgetedBytes;
PFOverBudgetCB fOverBudgetCB; bool fRequestFlush;
void* fOverBudgetData;
// We keep track of the "timestamps" of the last n flushes. If a resource hasn't been used in // 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. // that time then we well preemptively purge it to reduce memory usage.

View File

@ -1008,7 +1008,6 @@ void SkGpuDevice::drawBitmapTile(const SkBitmap& bitmap,
if (nullptr == texture) { if (nullptr == texture) {
return; return;
} }
sk_sp<GrColorSpaceXform> colorSpaceXform = sk_sp<GrColorSpaceXform> colorSpaceXform =
GrColorSpaceXform::Make(bitmap.colorSpace(), fDrawContext->getColorSpace()); GrColorSpaceXform::Make(bitmap.colorSpace(), fDrawContext->getColorSpace());

View File

@ -1133,7 +1133,7 @@ static void test_flush(skiatest::Reporter* reporter) {
make_unique_key<1>(&k, i); make_unique_key<1>(&k, i);
r->resourcePriv().setUniqueKey(k); r->resourcePriv().setUniqueKey(k);
r->unref(); r->unref();
cache->notifyFlushOccurred(); cache->notifyFlushOccurred(GrResourceCache::kExternal);
} }
// Send flush notifications to the cache. Each flush should purge the oldest resource. // 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)); REPORTER_ASSERT(reporter, !SkToBool(r));
SkSafeUnref(r); SkSafeUnref(r);
} }
cache->notifyFlushOccurred(); cache->notifyFlushOccurred(GrResourceCache::kExternal);
} }
REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
@ -1169,13 +1169,13 @@ static void test_flush(skiatest::Reporter* reporter) {
} else { } else {
r->unref(); r->unref();
} }
cache->notifyFlushOccurred(); cache->notifyFlushOccurred(GrResourceCache::kExternal);
} }
for (int i = 0; i < kFlushCount; ++i) { for (int i = 0; i < kFlushCount; ++i) {
// Should get a resource purged every other flush. // Should get a resource purged every other flush.
REPORTER_ASSERT(reporter, kFlushCount - i/2 - 1 == cache->getResourceCount()); 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. // 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. // get kFlushCount additional flushes. Then everything should be purged.
for (int i = 0; i < kFlushCount; ++i) { for (int i = 0; i < kFlushCount; ++i) {
REPORTER_ASSERT(reporter, kFlushCount >> 1 == cache->getResourceCount()); REPORTER_ASSERT(reporter, kFlushCount >> 1 == cache->getResourceCount());
cache->notifyFlushOccurred(); cache->notifyFlushOccurred(GrResourceCache::kExternal);
} }
REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());