Update Layer Hoisting to store its atlas texture in the resource cache
BUG=skia:4346 Committed: https://skia.googlesource.com/skia/+/42597bc99f00553825843b5ed41e81b121773368 Review URL: https://codereview.chromium.org/1406013006
This commit is contained in:
parent
e5911c9c5b
commit
60029a5397
@ -116,6 +116,8 @@ void SkMultiPictureDraw::draw(bool flush) {
|
||||
// drawing the canvas that requires them.
|
||||
SkTDArray<GrHoistedLayer> atlasedNeedRendering, atlasedRecycled;
|
||||
|
||||
GrLayerHoister::Begin(context);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const DrawData& data = fGPUDrawData[i];
|
||||
// we only expect 1 context for all the canvases
|
||||
@ -199,9 +201,7 @@ void SkMultiPictureDraw::draw(bool flush) {
|
||||
#if !defined(SK_IGNORE_GPU_LAYER_HOISTING) && SK_SUPPORT_GPU
|
||||
GrLayerHoister::UnlockLayers(context, atlasedNeedRendering);
|
||||
GrLayerHoister::UnlockLayers(context, atlasedRecycled);
|
||||
#if !GR_CACHE_HOISTED_LAYERS
|
||||
GrLayerHoister::PurgeCache(context);
|
||||
#endif
|
||||
GrLayerHoister::End(context);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrGpuResourcePriv.h"
|
||||
#include "GrLayerAtlas.h"
|
||||
#include "GrRectanizer.h"
|
||||
#include "GrTextureProvider.h"
|
||||
@ -43,6 +44,32 @@ void GrLayerAtlas::Plot::reset() {
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
GR_DECLARE_STATIC_UNIQUE_KEY(gLayerAtlasKey);
|
||||
static const GrUniqueKey& get_layer_atlas_key() {
|
||||
GR_DEFINE_STATIC_UNIQUE_KEY(gLayerAtlasKey);
|
||||
return gLayerAtlasKey;
|
||||
}
|
||||
|
||||
bool GrLayerAtlas::reattachBackingTexture() {
|
||||
SkASSERT(!fTexture);
|
||||
|
||||
fTexture.reset(fTexProvider->findAndRefTextureByUniqueKey(get_layer_atlas_key()));
|
||||
return SkToBool(fTexture);
|
||||
}
|
||||
|
||||
void GrLayerAtlas::createBackingTexture() {
|
||||
SkASSERT(!fTexture);
|
||||
|
||||
GrSurfaceDesc desc;
|
||||
desc.fFlags = fFlags;
|
||||
desc.fWidth = fBackingTextureSize.width();
|
||||
desc.fHeight = fBackingTextureSize.height();
|
||||
desc.fConfig = fPixelConfig;
|
||||
|
||||
fTexture.reset(fTexProvider->createTexture(desc, true, nullptr, 0));
|
||||
|
||||
fTexture->resourcePriv().setUniqueKey(get_layer_atlas_key());
|
||||
}
|
||||
|
||||
GrLayerAtlas::GrLayerAtlas(GrTextureProvider* texProvider, GrPixelConfig config,
|
||||
GrSurfaceFlags flags,
|
||||
@ -52,7 +79,6 @@ GrLayerAtlas::GrLayerAtlas(GrTextureProvider* texProvider, GrPixelConfig config,
|
||||
fPixelConfig = config;
|
||||
fFlags = flags;
|
||||
fBackingTextureSize = backingTextureSize;
|
||||
fTexture = nullptr;
|
||||
|
||||
int textureWidth = fBackingTextureSize.width();
|
||||
int textureHeight = fBackingTextureSize.height();
|
||||
@ -81,8 +107,14 @@ GrLayerAtlas::GrLayerAtlas(GrTextureProvider* texProvider, GrPixelConfig config,
|
||||
}
|
||||
}
|
||||
|
||||
void GrLayerAtlas::resetPlots() {
|
||||
PlotIter iter;
|
||||
for (Plot* plot = iter.init(fPlotList, PlotIter::kHead_IterStart); plot; plot = iter.next()) {
|
||||
plot->reset();
|
||||
}
|
||||
}
|
||||
|
||||
GrLayerAtlas::~GrLayerAtlas() {
|
||||
SkSafeUnref(fTexture);
|
||||
delete[] fPlotArray;
|
||||
}
|
||||
|
||||
@ -111,14 +143,7 @@ GrLayerAtlas::Plot* GrLayerAtlas::addToAtlas(ClientPlotUsage* usage,
|
||||
|
||||
// before we get a new plot, make sure we have a backing texture
|
||||
if (nullptr == fTexture) {
|
||||
// TODO: Update this to use the cache rather than directly creating a texture.
|
||||
GrSurfaceDesc desc;
|
||||
desc.fFlags = fFlags;
|
||||
desc.fWidth = fBackingTextureSize.width();
|
||||
desc.fHeight = fBackingTextureSize.height();
|
||||
desc.fConfig = fPixelConfig;
|
||||
|
||||
fTexture = fTexProvider->createTexture(desc, true, nullptr, 0);
|
||||
this->createBackingTexture();
|
||||
if (nullptr == fTexture) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -9,15 +9,13 @@
|
||||
#ifndef GrLayerAtlas_DEFINED
|
||||
#define GrLayerAtlas_DEFINED
|
||||
|
||||
#include "GrTypes.h"
|
||||
#include "GrTexture.h"
|
||||
|
||||
#include "SkPoint.h"
|
||||
#include "SkSize.h"
|
||||
#include "SkTDArray.h"
|
||||
#include "SkTInternalLList.h"
|
||||
|
||||
class GrLayerAtlas;
|
||||
class GrTexture;
|
||||
class GrTextureProvider;
|
||||
class GrRectanizer;
|
||||
|
||||
@ -109,10 +107,23 @@ public:
|
||||
// nullptr is returned if there is no more space in the atlas.
|
||||
Plot* addToAtlas(ClientPlotUsage*, int width, int height, SkIPoint16* loc);
|
||||
|
||||
GrTexture* getTexture() const {
|
||||
GrTexture* getTextureOrNull() const {
|
||||
return fTexture;
|
||||
}
|
||||
|
||||
GrTexture* getTexture() const {
|
||||
SkASSERT(fTexture);
|
||||
return fTexture;
|
||||
}
|
||||
|
||||
bool reattachBackingTexture();
|
||||
|
||||
void detachBackingTexture() {
|
||||
fTexture.reset(nullptr);
|
||||
}
|
||||
|
||||
void resetPlots();
|
||||
|
||||
enum IterOrder {
|
||||
kLRUFirst_IterOrder,
|
||||
kMRUFirst_IterOrder
|
||||
@ -127,12 +138,14 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void createBackingTexture();
|
||||
|
||||
void makeMRU(Plot* plot);
|
||||
|
||||
GrTextureProvider* fTexProvider;
|
||||
GrPixelConfig fPixelConfig;
|
||||
GrSurfaceFlags fFlags;
|
||||
GrTexture* fTexture;
|
||||
SkAutoTUnref<GrTexture> fTexture;
|
||||
|
||||
SkISize fBackingTextureSize;
|
||||
|
||||
|
@ -27,9 +27,11 @@ void GrCachedLayer::validate(const GrTexture* backingTexture) const {
|
||||
SkASSERT(fRect.isEmpty());
|
||||
SkASSERT(nullptr == fPlot);
|
||||
SkASSERT(!fLocked); // layers without a texture cannot be locked
|
||||
SkASSERT(!fAtlased); // can't be atlased if it doesn't have a texture
|
||||
}
|
||||
|
||||
if (fPlot) {
|
||||
SkASSERT(fAtlased);
|
||||
// If a layer has a plot (i.e., is atlased) then it must point to
|
||||
// the backing texture. Additionally, its rect should be non-empty.
|
||||
SkASSERT(fTexture && backingTexture == fTexture);
|
||||
@ -119,8 +121,10 @@ void GrLayerCache::freeAll() {
|
||||
}
|
||||
fLayerHash.rewind();
|
||||
|
||||
// The atlas only lets go of its texture when the atlas is deleted.
|
||||
fAtlas.free();
|
||||
if (fAtlas) {
|
||||
fAtlas->resetPlots();
|
||||
fAtlas->detachBackingTexture();
|
||||
}
|
||||
}
|
||||
|
||||
GrCachedLayer* GrLayerCache::createLayer(uint32_t pictureID,
|
||||
@ -167,7 +171,7 @@ GrCachedLayer* GrLayerCache::findLayerOrCreate(uint32_t pictureID,
|
||||
bool GrLayerCache::tryToAtlas(GrCachedLayer* layer,
|
||||
const GrSurfaceDesc& desc,
|
||||
bool* needsRendering) {
|
||||
SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTexture() : nullptr, layer);)
|
||||
SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTextureOrNull() : nullptr, layer);)
|
||||
|
||||
SkASSERT(PlausiblyAtlasable(desc.fWidth, desc.fHeight));
|
||||
SkASSERT(0 == desc.fSampleCnt);
|
||||
@ -217,7 +221,7 @@ bool GrLayerCache::tryToAtlas(GrCachedLayer* layer,
|
||||
// The layer was successfully added to the atlas
|
||||
const SkIRect bounds = SkIRect::MakeXYWH(loc.fX, loc.fY,
|
||||
desc.fWidth, desc.fHeight);
|
||||
layer->setTexture(fAtlas->getTexture(), bounds);
|
||||
layer->setTexture(fAtlas->getTexture(), bounds, true);
|
||||
layer->setPlot(plot);
|
||||
layer->setLocked(true);
|
||||
this->incPlotLock(layer->plot()->id());
|
||||
@ -227,7 +231,7 @@ bool GrLayerCache::tryToAtlas(GrCachedLayer* layer,
|
||||
|
||||
// The layer was rejected by the atlas (even though we know it is
|
||||
// plausibly atlas-able). See if a plot can be purged and try again.
|
||||
if (!this->purgePlot()) {
|
||||
if (!this->purgePlots(true)) {
|
||||
break; // We weren't able to purge any plots
|
||||
}
|
||||
}
|
||||
@ -260,14 +264,14 @@ bool GrLayerCache::lock(GrCachedLayer* layer, const GrSurfaceDesc& desc, bool* n
|
||||
return false;
|
||||
}
|
||||
|
||||
layer->setTexture(tex, SkIRect::MakeWH(desc.fWidth, desc.fHeight));
|
||||
layer->setTexture(tex, SkIRect::MakeWH(desc.fWidth, desc.fHeight), false);
|
||||
layer->setLocked(true);
|
||||
*needsRendering = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GrLayerCache::unlock(GrCachedLayer* layer) {
|
||||
SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTexture() : nullptr, layer);)
|
||||
SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTextureOrNull() : nullptr, layer);)
|
||||
|
||||
if (nullptr == layer || !layer->locked()) {
|
||||
// invalid or not locked
|
||||
@ -299,11 +303,11 @@ void GrLayerCache::unlock(GrCachedLayer* layer) {
|
||||
}
|
||||
|
||||
layer->setPlot(nullptr);
|
||||
layer->setTexture(nullptr, SkIRect::MakeEmpty());
|
||||
layer->setTexture(nullptr, SkIRect::MakeEmpty(), false);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
layer->setTexture(nullptr, SkIRect::MakeEmpty());
|
||||
layer->setTexture(nullptr, SkIRect::MakeEmpty(), false);
|
||||
}
|
||||
|
||||
layer->setLocked(false);
|
||||
@ -318,7 +322,7 @@ void GrLayerCache::validate() const {
|
||||
for (; !iter.done(); ++iter) {
|
||||
const GrCachedLayer* layer = &(*iter);
|
||||
|
||||
layer->validate(fAtlas.get() ? fAtlas->getTexture() : nullptr);
|
||||
layer->validate(fAtlas.get() ? fAtlas->getTextureOrNull() : nullptr);
|
||||
|
||||
const GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
|
||||
if (!pictInfo) {
|
||||
@ -389,10 +393,11 @@ void GrLayerCache::purge(uint32_t pictureID) {
|
||||
}
|
||||
}
|
||||
|
||||
bool GrLayerCache::purgePlot() {
|
||||
bool GrLayerCache::purgePlots(bool justOne) {
|
||||
SkDEBUGCODE(GrAutoValidateCache avc(this);)
|
||||
SkASSERT(fAtlas);
|
||||
|
||||
bool anyPurged = false;
|
||||
GrLayerAtlas::PlotIter iter;
|
||||
GrLayerAtlas::Plot* plot;
|
||||
for (plot = fAtlas->iterInit(&iter, GrLayerAtlas::kLRUFirst_IterOrder);
|
||||
@ -402,11 +407,14 @@ bool GrLayerCache::purgePlot() {
|
||||
continue;
|
||||
}
|
||||
|
||||
anyPurged = true;
|
||||
this->purgePlot(plot);
|
||||
return true;
|
||||
if (justOne) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return anyPurged;
|
||||
}
|
||||
|
||||
void GrLayerCache::purgePlot(GrLayerAtlas::Plot* plot) {
|
||||
@ -455,27 +463,57 @@ void GrLayerCache::purgeAll() {
|
||||
return;
|
||||
}
|
||||
|
||||
GrLayerAtlas::PlotIter iter;
|
||||
GrLayerAtlas::Plot* plot;
|
||||
for (plot = fAtlas->iterInit(&iter, GrLayerAtlas::kLRUFirst_IterOrder);
|
||||
plot;
|
||||
plot = iter.prev()) {
|
||||
SkASSERT(0 == fPlotLocks[plot->id()]);
|
||||
|
||||
this->purgePlot(plot);
|
||||
}
|
||||
this->purgePlots(false); // clear them all out
|
||||
|
||||
SkASSERT(0 == fPictureHash.count());
|
||||
|
||||
SkAutoTUnref<GrDrawContext> drawContext(
|
||||
fContext->drawContext(fAtlas->getTexture()->asRenderTarget()));
|
||||
if (fAtlas->getTextureOrNull()) {
|
||||
SkAutoTUnref<GrDrawContext> drawContext(
|
||||
fContext->drawContext(fAtlas->getTexture()->asRenderTarget()));
|
||||
|
||||
if (drawContext) {
|
||||
drawContext->discard();
|
||||
if (drawContext) {
|
||||
drawContext->discard();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void GrLayerCache::begin() {
|
||||
if (!fAtlas) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fAtlas->reattachBackingTexture()) {
|
||||
// We weren't able to re-attach. Clear out all the atlased layers.
|
||||
this->purgePlots(false);
|
||||
SkASSERT(0 == fPictureHash.count());
|
||||
}
|
||||
#ifdef SK_DEBUG
|
||||
else {
|
||||
// we've reattached - everything had better make sense
|
||||
SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
|
||||
for (; !iter.done(); ++iter) {
|
||||
GrCachedLayer* layer = &(*iter);
|
||||
|
||||
if (layer->isAtlased()) {
|
||||
SkASSERT(fAtlas->getTexture() == layer->texture());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GrLayerCache::end() {
|
||||
if (!fAtlas) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Adding this call will clear out all the layers in the atlas
|
||||
//this->purgePlots(false);
|
||||
|
||||
fAtlas->detachBackingTexture();
|
||||
}
|
||||
|
||||
void GrLayerCache::processDeletedPictures() {
|
||||
SkTArray<SkPicture::DeletionMessage> deletedPictures;
|
||||
fPictDeletionInbox.poll(&deletedPictures);
|
||||
@ -489,7 +527,7 @@ void GrLayerCache::processDeletedPictures() {
|
||||
void GrLayerCache::writeLayersToDisk(const SkString& dirName) {
|
||||
|
||||
if (fAtlas) {
|
||||
GrTexture* atlasTexture = fAtlas->getTexture();
|
||||
GrTexture* atlasTexture = fAtlas->getTextureOrNull();
|
||||
if (nullptr != atlasTexture) {
|
||||
SkString fileName(dirName);
|
||||
fileName.append("\\atlas.png");
|
||||
|
@ -165,6 +165,7 @@ public:
|
||||
, fPaint(paint ? new SkPaint(*paint) : nullptr)
|
||||
, fFilter(nullptr)
|
||||
, fTexture(nullptr)
|
||||
, fAtlased(false)
|
||||
, fRect(SkIRect::MakeEmpty())
|
||||
, fPlot(nullptr)
|
||||
, fUses(0)
|
||||
@ -180,7 +181,9 @@ public:
|
||||
}
|
||||
|
||||
~GrCachedLayer() {
|
||||
SkSafeUnref(fTexture);
|
||||
if (!fAtlased) {
|
||||
SkSafeUnref(fTexture);
|
||||
}
|
||||
SkSafeUnref(fFilter);
|
||||
delete fPaint;
|
||||
}
|
||||
@ -195,8 +198,15 @@ public:
|
||||
const SkIRect& srcIR() const { return fSrcIR; }
|
||||
const SkIRect& dstIR() const { return fDstIR; }
|
||||
int stop() const { return fStop; }
|
||||
void setTexture(GrTexture* texture, const SkIRect& rect) {
|
||||
SkRefCnt_SafeAssign(fTexture, texture);
|
||||
void setTexture(GrTexture* texture, const SkIRect& rect, bool atlased) {
|
||||
if (texture && !atlased) {
|
||||
texture->ref(); // non-atlased textures carry a ref
|
||||
}
|
||||
if (fTexture && !fAtlased) {
|
||||
fTexture->unref(); // non-atlased textures carry a ref
|
||||
}
|
||||
fTexture = texture;
|
||||
fAtlased = atlased;
|
||||
fRect = rect;
|
||||
if (!fTexture) {
|
||||
fLocked = false;
|
||||
@ -216,7 +226,7 @@ public:
|
||||
}
|
||||
GrLayerAtlas::Plot* plot() { return fPlot; }
|
||||
|
||||
bool isAtlased() const { return SkToBool(fPlot); }
|
||||
bool isAtlased() const { SkASSERT(fAtlased == SkToBool(fPlot)); return fAtlased; }
|
||||
|
||||
void setLocked(bool locked) { fLocked = locked; }
|
||||
bool locked() const { return fLocked; }
|
||||
@ -252,6 +262,10 @@ private:
|
||||
// ref on a GrTexture for non-atlased textures.
|
||||
GrTexture* fTexture;
|
||||
|
||||
// true if this layer is in the atlas (and 'fTexture' doesn't carry a ref)
|
||||
// and false if the layer is a free floater (and carries a ref).
|
||||
bool fAtlased;
|
||||
|
||||
// For both atlased and non-atlased layers 'fRect' contains the bound of
|
||||
// the layer in whichever texture it resides. It is empty when 'fTexture'
|
||||
// is nullptr.
|
||||
@ -285,10 +299,9 @@ private:
|
||||
// The GrLayerCache caches pre-computed saveLayers for later rendering.
|
||||
// Non-atlased layers are stored in their own GrTexture while the atlased
|
||||
// layers share a single GrTexture.
|
||||
// Unlike the GrFontCache, the GrTexture atlas only has one GrAtlas (for 8888)
|
||||
// and one GrPlot (for the entire atlas). As such, the GrLayerCache
|
||||
// roughly combines the functionality of the GrFontCache and GrTextStrike
|
||||
// classes.
|
||||
// Unlike the GrFontCache, the GrLayerCache only has one atlas (for 8888).
|
||||
// As such, the GrLayerCache roughly combines the functionality of the
|
||||
// GrFontCache and GrTextStrike classes.
|
||||
class GrLayerCache {
|
||||
public:
|
||||
GrLayerCache(GrContext*);
|
||||
@ -346,6 +359,9 @@ public:
|
||||
return width <= kPlotWidth && height <= kPlotHeight;
|
||||
}
|
||||
|
||||
void begin();
|
||||
void end();
|
||||
|
||||
#if !GR_CACHE_HOISTED_LAYERS
|
||||
void purgeAll();
|
||||
#endif
|
||||
@ -361,7 +377,7 @@ private:
|
||||
static const int kPlotHeight = kAtlasTextureHeight / kNumPlotsY;
|
||||
|
||||
GrContext* fContext; // pointer back to owning context
|
||||
SkAutoTDelete<GrLayerAtlas> fAtlas; // TODO: could lazily allocate
|
||||
SkAutoTDelete<GrLayerAtlas> fAtlas; // lazily allocated
|
||||
|
||||
// We cache this information here (rather then, say, on the owning picture)
|
||||
// because we want to be able to clean it up as needed (e.g., if a picture
|
||||
@ -397,9 +413,9 @@ private:
|
||||
|
||||
void purgePlot(GrLayerAtlas::Plot* plot);
|
||||
|
||||
// Try to find a purgeable plot and clear it out. Return true if a plot
|
||||
// Either purge all un-locked plots or just one. Return true if >= 1 plot
|
||||
// was purged; false otherwise.
|
||||
bool purgePlot();
|
||||
bool purgePlots(bool justOne);
|
||||
|
||||
void incPlotLock(int plotIdx) { ++fPlotLocks[plotIdx]; }
|
||||
void decPlotLock(int plotIdx) {
|
||||
|
@ -322,7 +322,7 @@ void GrLayerHoister::FilterLayer(GrContext* context,
|
||||
}
|
||||
|
||||
SkIRect newRect = SkIRect::MakeWH(filteredBitmap.width(), filteredBitmap.height());
|
||||
layer->setTexture(filteredBitmap.getTexture(), newRect);
|
||||
layer->setTexture(filteredBitmap.getTexture(), newRect, false);
|
||||
layer->setOffset(offset);
|
||||
}
|
||||
|
||||
@ -380,13 +380,22 @@ void GrLayerHoister::UnlockLayers(GrContext* context,
|
||||
SkDEBUGCODE(layerCache->validate();)
|
||||
}
|
||||
|
||||
void GrLayerHoister::PurgeCache(GrContext* context) {
|
||||
#if !GR_CACHE_HOISTED_LAYERS
|
||||
void GrLayerHoister::Begin(GrContext* context) {
|
||||
GrLayerCache* layerCache = context->getLayerCache();
|
||||
|
||||
layerCache->begin();
|
||||
}
|
||||
|
||||
void GrLayerHoister::End(GrContext* context) {
|
||||
GrLayerCache* layerCache = context->getLayerCache();
|
||||
|
||||
#if !GR_CACHE_HOISTED_LAYERS
|
||||
|
||||
// This code completely clears out the atlas. It is required when
|
||||
// caching is disabled so the atlas doesn't fill up and force more
|
||||
// free floating layers
|
||||
layerCache->purgeAll();
|
||||
#endif
|
||||
|
||||
layerCache->end();
|
||||
}
|
||||
|
@ -33,6 +33,13 @@ public:
|
||||
// UnlockLayers should be called once to allow the texture resources to be recycled
|
||||
class GrLayerHoister {
|
||||
public:
|
||||
/** Attempt to reattach layers that may have been atlased in the past
|
||||
*/
|
||||
static void Begin(GrContext* context);
|
||||
|
||||
/** Release cache resources
|
||||
*/
|
||||
static void End(GrContext* context);
|
||||
|
||||
/** Find the layers in 'topLevelPicture' that can be atlased. Note that the discovered
|
||||
layers can be inside nested sub-pictures.
|
||||
|
@ -19,9 +19,9 @@ public:
|
||||
this->reset();
|
||||
}
|
||||
|
||||
virtual ~GrRectanizerSkyline() { }
|
||||
~GrRectanizerSkyline() override { }
|
||||
|
||||
void reset() override{
|
||||
void reset() override {
|
||||
fAreaSoFar = 0;
|
||||
fSkyline.reset();
|
||||
SkylineSegment* seg = fSkyline.append(1);
|
||||
|
@ -182,7 +182,52 @@ public:
|
||||
|
||||
void notifyFlushOccurred();
|
||||
|
||||
#if GR_GPU_STATS
|
||||
#if GR_CACHE_STATS
|
||||
struct Stats {
|
||||
int fTotal;
|
||||
int fNumPurgeable;
|
||||
int fNumNonPurgeable;
|
||||
|
||||
int fScratch;
|
||||
int fExternal;
|
||||
int fBorrowed;
|
||||
int fAdopted;
|
||||
size_t fUnbudgetedSize;
|
||||
|
||||
Stats() { this->reset(); }
|
||||
|
||||
void reset() {
|
||||
fTotal = 0;
|
||||
fNumPurgeable = 0;
|
||||
fNumNonPurgeable = 0;
|
||||
fScratch = 0;
|
||||
fExternal = 0;
|
||||
fBorrowed = 0;
|
||||
fAdopted = 0;
|
||||
fUnbudgetedSize = 0;
|
||||
}
|
||||
|
||||
void update(GrGpuResource* resource) {
|
||||
if (resource->cacheAccess().isScratch()) {
|
||||
++fScratch;
|
||||
}
|
||||
if (resource->cacheAccess().isExternal()) {
|
||||
++fExternal;
|
||||
}
|
||||
if (resource->cacheAccess().isBorrowed()) {
|
||||
++fBorrowed;
|
||||
}
|
||||
if (resource->cacheAccess().isAdopted()) {
|
||||
++fAdopted;
|
||||
}
|
||||
if (!resource->resourcePriv().isBudgeted()) {
|
||||
fUnbudgetedSize += resource->gpuMemorySize();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void getStats(Stats*) const;
|
||||
|
||||
void dumpStats(SkString*) const;
|
||||
#endif
|
||||
|
||||
|
@ -140,47 +140,27 @@ void GrGpu::Stats::dump(SkString* out) {
|
||||
#endif
|
||||
|
||||
#if GR_CACHE_STATS
|
||||
void GrResourceCache::getStats(Stats* stats) const {
|
||||
stats->reset();
|
||||
|
||||
stats->fTotal = this->getResourceCount();
|
||||
stats->fNumNonPurgeable = fNonpurgeableResources.count();
|
||||
stats->fNumPurgeable = fPurgeableQueue.count();
|
||||
|
||||
for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
|
||||
stats->update(fNonpurgeableResources[i]);
|
||||
}
|
||||
for (int i = 0; i < fPurgeableQueue.count(); ++i) {
|
||||
stats->update(fPurgeableQueue.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
void GrResourceCache::dumpStats(SkString* out) const {
|
||||
this->validate();
|
||||
|
||||
int locked = fNonpurgeableResources.count();
|
||||
|
||||
struct Stats {
|
||||
int fScratch;
|
||||
int fExternal;
|
||||
int fBorrowed;
|
||||
int fAdopted;
|
||||
size_t fUnbudgetedSize;
|
||||
|
||||
Stats() : fScratch(0), fExternal(0), fBorrowed(0), fAdopted(0), fUnbudgetedSize(0) {}
|
||||
|
||||
void update(GrGpuResource* resource) {
|
||||
if (resource->cacheAccess().isScratch()) {
|
||||
++fScratch;
|
||||
}
|
||||
if (resource->cacheAccess().isExternal()) {
|
||||
++fExternal;
|
||||
}
|
||||
if (resource->cacheAccess().isBorrowed()) {
|
||||
++fBorrowed;
|
||||
}
|
||||
if (resource->cacheAccess().isAdopted()) {
|
||||
++fAdopted;
|
||||
}
|
||||
if (!resource->resourcePriv().isBudgeted()) {
|
||||
fUnbudgetedSize += resource->gpuMemorySize();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Stats stats;
|
||||
|
||||
for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
|
||||
stats.update(fNonpurgeableResources[i]);
|
||||
}
|
||||
for (int i = 0; i < fPurgeableQueue.count(); ++i) {
|
||||
stats.update(fPurgeableQueue.at(i));
|
||||
}
|
||||
this->getStats(&stats);
|
||||
|
||||
float countUtilization = (100.f * fBudgetedCount) / fMaxCount;
|
||||
float byteUtilization = (100.f * fBudgetedBytes) / fMaxBytes;
|
||||
@ -188,8 +168,9 @@ void GrResourceCache::dumpStats(SkString* out) const {
|
||||
out->appendf("Budget: %d items %d bytes\n", fMaxCount, (int)fMaxBytes);
|
||||
out->appendf("\t\tEntry Count: current %d"
|
||||
" (%d budgeted, %d external(%d borrowed, %d adopted), %d locked, %d scratch %.2g%% full), high %d\n",
|
||||
this->getResourceCount(), fBudgetedCount, stats.fExternal, stats.fBorrowed,
|
||||
stats.fAdopted, locked, stats.fScratch, countUtilization, fHighWaterCount);
|
||||
stats.fTotal, fBudgetedCount, stats.fExternal, stats.fBorrowed,
|
||||
stats.fAdopted, stats.fNumNonPurgeable, stats.fScratch, countUtilization,
|
||||
fHighWaterCount);
|
||||
out->appendf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full, %d unbudgeted) high %d\n",
|
||||
SkToInt(fBytes), SkToInt(fBudgetedBytes), byteUtilization,
|
||||
SkToInt(stats.fUnbudgetedSize), SkToInt(fHighWaterBytes));
|
||||
|
@ -2028,6 +2028,8 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
|
||||
|
||||
SkMatrix initialMatrix = mainCanvas->getTotalMatrix();
|
||||
|
||||
GrLayerHoister::Begin(fContext);
|
||||
|
||||
GrLayerHoister::FindLayersToAtlas(fContext, mainPicture,
|
||||
initialMatrix,
|
||||
clipBounds,
|
||||
@ -2056,6 +2058,7 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
|
||||
GrLayerHoister::UnlockLayers(fContext, recycled);
|
||||
GrLayerHoister::UnlockLayers(fContext, atlasedNeedRendering);
|
||||
GrLayerHoister::UnlockLayers(fContext, atlasedRecycled);
|
||||
GrLayerHoister::End(fContext);
|
||||
|
||||
return true;
|
||||
#else
|
||||
|
@ -10,11 +10,24 @@
|
||||
#include "GrContext.h"
|
||||
#include "GrContextFactory.h"
|
||||
#include "GrLayerCache.h"
|
||||
#include "GrResourceCache.h"
|
||||
#include "SkPictureRecorder.h"
|
||||
#include "Test.h"
|
||||
|
||||
class TestingAccess {
|
||||
public:
|
||||
static int NumPlots() {
|
||||
return GrLayerCache::kNumPlotsX * GrLayerCache::kNumPlotsY;
|
||||
}
|
||||
static SkISize PlotSize() {
|
||||
return SkISize::Make(GrLayerCache::kAtlasTextureWidth / GrLayerCache::kNumPlotsX,
|
||||
GrLayerCache::kAtlasTextureHeight / GrLayerCache::kNumPlotsY);
|
||||
}
|
||||
|
||||
static GrTexture* GetBackingTexture(GrLayerCache* cache) {
|
||||
return cache->fAtlas->getTextureOrNull();
|
||||
}
|
||||
|
||||
static int NumLayers(GrLayerCache* cache) {
|
||||
return cache->numLayers();
|
||||
}
|
||||
@ -39,17 +52,17 @@ static void create_layers(skiatest::Reporter* reporter,
|
||||
int idOffset) {
|
||||
|
||||
for (int i = 0; i < numToAdd; ++i) {
|
||||
int indices[1] = { idOffset+i+1 };
|
||||
int key[1] = { idOffset+i+1 };
|
||||
GrCachedLayer* layer = cache->findLayerOrCreate(picture.uniqueID(),
|
||||
idOffset+i+1, idOffset+i+2,
|
||||
SkIRect::MakeEmpty(),
|
||||
SkIRect::MakeEmpty(),
|
||||
SkMatrix::I(),
|
||||
indices, 1,
|
||||
key, 1,
|
||||
nullptr);
|
||||
REPORTER_ASSERT(reporter, layer);
|
||||
GrCachedLayer* temp = TestingAccess::Find(cache, picture.uniqueID(), SkMatrix::I(),
|
||||
indices, 1);
|
||||
key, 1);
|
||||
REPORTER_ASSERT(reporter, temp == layer);
|
||||
|
||||
REPORTER_ASSERT(reporter, TestingAccess::NumLayers(cache) == idOffset + i + 1);
|
||||
@ -66,10 +79,11 @@ static void create_layers(skiatest::Reporter* reporter,
|
||||
static void lock_layer(skiatest::Reporter* reporter,
|
||||
GrLayerCache* cache,
|
||||
GrCachedLayer* layer) {
|
||||
// Make the layer 512x512 (so it can be atlased)
|
||||
// Make each layer big enough to consume one whole plot in the atlas
|
||||
GrSurfaceDesc desc;
|
||||
desc.fWidth = 512;
|
||||
desc.fHeight = 512;
|
||||
desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
||||
desc.fWidth = TestingAccess::PlotSize().fWidth;
|
||||
desc.fHeight = TestingAccess::PlotSize().fHeight;
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
|
||||
bool needsRerendering;
|
||||
@ -95,9 +109,14 @@ static void lock_layer(skiatest::Reporter* reporter,
|
||||
// locking & unlocking textures).
|
||||
// TODO: need to add checks on VRAM usage!
|
||||
DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
static const int kInitialNumLayers = 5;
|
||||
// Add one more layer than can fit in the atlas
|
||||
static const int kInitialNumLayers = TestingAccess::NumPlots() + 1;
|
||||
|
||||
for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
|
||||
#if GR_CACHE_STATS
|
||||
GrResourceCache::Stats stats;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
|
||||
GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
|
||||
|
||||
if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
|
||||
@ -110,50 +129,73 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SkPictureRecorder recorder;
|
||||
SkCanvas* c = recorder.beginRecording(1, 1);
|
||||
// Draw something, anything, to prevent an empty-picture optimization,
|
||||
// which is a singleton and never purged.
|
||||
c->drawRect(SkRect::MakeWH(1,1), SkPaint());
|
||||
SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
|
||||
SkAutoTUnref<const SkPicture> picture;
|
||||
|
||||
{
|
||||
SkPictureRecorder recorder;
|
||||
SkCanvas* c = recorder.beginRecording(1, 1);
|
||||
// Draw something, anything, to prevent an empty-picture optimization,
|
||||
// which is a singleton and never purged.
|
||||
c->drawRect(SkRect::MakeWH(1,1), SkPaint());
|
||||
picture.reset(recorder.endRecording());
|
||||
}
|
||||
|
||||
GrResourceCache* resourceCache = context->getResourceCache();
|
||||
|
||||
GrLayerCache cache(context);
|
||||
|
||||
create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
|
||||
|
||||
for (int i = 0; i < kInitialNumLayers; ++i) {
|
||||
int indices[1] = { i + 1 };
|
||||
int key[1] = { i + 1 };
|
||||
GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
|
||||
indices, 1);
|
||||
key, 1);
|
||||
REPORTER_ASSERT(reporter, layer);
|
||||
|
||||
lock_layer(reporter, &cache, layer);
|
||||
|
||||
// The first 4 layers should be in the atlas (and thus have non-empty
|
||||
// rects)
|
||||
if (i < 4) {
|
||||
#if GR_CACHE_STATS
|
||||
resourceCache->getStats(&stats);
|
||||
#endif
|
||||
|
||||
// The first 4 layers should be in the atlas (and thus have non-empty rects)
|
||||
if (i < TestingAccess::NumPlots()) {
|
||||
REPORTER_ASSERT(reporter, layer->isAtlased());
|
||||
#if GR_CACHE_STATS
|
||||
REPORTER_ASSERT(reporter, 1 == stats.fTotal);
|
||||
#endif
|
||||
} else {
|
||||
// The 5th layer couldn't fit in the atlas
|
||||
REPORTER_ASSERT(reporter, !layer->isAtlased());
|
||||
#if GR_CACHE_STATS
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fTotal);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock the textures
|
||||
for (int i = 0; i < kInitialNumLayers; ++i) {
|
||||
int indices[1] = { i+1 };
|
||||
int key[1] = { i+1 };
|
||||
|
||||
GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
|
||||
indices, 1);
|
||||
key, 1);
|
||||
REPORTER_ASSERT(reporter, layer);
|
||||
cache.removeUse(layer);
|
||||
}
|
||||
|
||||
#if GR_CACHE_STATS
|
||||
resourceCache->getStats(&stats);
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fTotal);
|
||||
// The floating layer is purgeable the cache is not
|
||||
REPORTER_ASSERT(reporter, 1 == stats.fNumPurgeable);
|
||||
REPORTER_ASSERT(reporter, 1 == stats.fNumNonPurgeable);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < kInitialNumLayers; ++i) {
|
||||
int indices[1] = { i+1 };
|
||||
int key[1] = { i+1 };
|
||||
|
||||
GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
|
||||
indices, 1);
|
||||
key, 1);
|
||||
REPORTER_ASSERT(reporter, layer);
|
||||
|
||||
// All the layers should be unlocked
|
||||
@ -176,14 +218,37 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Let go of the backing texture
|
||||
cache.end();
|
||||
REPORTER_ASSERT(reporter, nullptr == TestingAccess::GetBackingTexture(&cache));
|
||||
|
||||
#if GR_CACHE_STATS
|
||||
resourceCache->getStats(&stats);
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fTotal);
|
||||
// Now both the floater and the atlas are purgeable
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fNumPurgeable);
|
||||
#endif
|
||||
|
||||
// re-attach to the backing texture
|
||||
cache.begin();
|
||||
REPORTER_ASSERT(reporter, TestingAccess::GetBackingTexture(&cache));
|
||||
|
||||
#if GR_CACHE_STATS
|
||||
resourceCache->getStats(&stats);
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fTotal);
|
||||
// The atlas is restored to being non-purgeable
|
||||
REPORTER_ASSERT(reporter, 1 == stats.fNumPurgeable);
|
||||
REPORTER_ASSERT(reporter, 1 == stats.fNumNonPurgeable);
|
||||
#endif
|
||||
|
||||
{
|
||||
int indices[1] = { kInitialNumLayers+1 };
|
||||
int key[1] = { kInitialNumLayers+1 };
|
||||
|
||||
// Add an additional layer. Since all the layers are unlocked this
|
||||
// will force out the first atlased layer
|
||||
create_layers(reporter, &cache, *picture, 1, kInitialNumLayers);
|
||||
GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
|
||||
indices, 1);
|
||||
key, 1);
|
||||
REPORTER_ASSERT(reporter, layer);
|
||||
|
||||
lock_layer(reporter, &cache, layer);
|
||||
@ -191,10 +256,10 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
}
|
||||
|
||||
for (int i = 0; i < kInitialNumLayers+1; ++i) {
|
||||
int indices[1] = { i+1 };
|
||||
int key[1] = { i+1 };
|
||||
|
||||
GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
|
||||
indices, 1);
|
||||
key, 1);
|
||||
#if GR_CACHE_HOISTED_LAYERS
|
||||
// 3 old layers plus the new one should be in the atlas.
|
||||
if (1 == i || 2 == i || 3 == i || 5 == i) {
|
||||
@ -223,7 +288,14 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
TestingAccess::Purge(&cache, picture->uniqueID());
|
||||
|
||||
REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
|
||||
// TODO: add VRAM/resource cache check here
|
||||
|
||||
#if GR_CACHE_STATS
|
||||
resourceCache->getStats(&stats);
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fTotal);
|
||||
// Atlas isn't purgeable
|
||||
REPORTER_ASSERT(reporter, 1 == stats.fNumPurgeable);
|
||||
REPORTER_ASSERT(reporter, 1 == stats.fNumNonPurgeable);
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Test out the GrContext-style purge. This should remove all the layers
|
||||
@ -235,18 +307,77 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
|
||||
cache.freeAll();
|
||||
|
||||
REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
|
||||
// TODO: add VRAM/resource cache check here
|
||||
|
||||
REPORTER_ASSERT(reporter, nullptr == TestingAccess::GetBackingTexture(&cache));
|
||||
|
||||
#if GR_CACHE_STATS
|
||||
resourceCache->getStats(&stats);
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fTotal);
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fNumPurgeable);
|
||||
#endif
|
||||
|
||||
// Purge the resource cache ...
|
||||
resourceCache->purgeAllUnlocked();
|
||||
|
||||
#if GR_CACHE_STATS
|
||||
resourceCache->getStats(&stats);
|
||||
REPORTER_ASSERT(reporter, 0 == stats.fTotal);
|
||||
#endif
|
||||
|
||||
// and try to re-attach to the backing texture. This should fail
|
||||
cache.begin();
|
||||
REPORTER_ASSERT(reporter, nullptr == TestingAccess::GetBackingTexture(&cache));
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Test out the MessageBus-style purge. This will not free the atlas
|
||||
// but should eliminate the free-floating layers.
|
||||
create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
|
||||
|
||||
// Allocate/use the layers
|
||||
for (int i = 0; i < kInitialNumLayers; ++i) {
|
||||
int key[1] = { i + 1 };
|
||||
GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
|
||||
key, 1);
|
||||
REPORTER_ASSERT(reporter, layer);
|
||||
|
||||
lock_layer(reporter, &cache, layer);
|
||||
}
|
||||
|
||||
#if GR_CACHE_STATS
|
||||
resourceCache->getStats(&stats);
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fTotal);
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fNumNonPurgeable);
|
||||
#endif
|
||||
|
||||
// Unlock the textures
|
||||
for (int i = 0; i < kInitialNumLayers; ++i) {
|
||||
int key[1] = { i+1 };
|
||||
|
||||
GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
|
||||
key, 1);
|
||||
REPORTER_ASSERT(reporter, layer);
|
||||
cache.removeUse(layer);
|
||||
}
|
||||
|
||||
picture.reset(nullptr);
|
||||
cache.processDeletedPictures();
|
||||
|
||||
REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
|
||||
// TODO: add VRAM/resource cache check here
|
||||
|
||||
#if GR_CACHE_STATS
|
||||
resourceCache->getStats(&stats);
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fTotal);
|
||||
REPORTER_ASSERT(reporter, 1 == stats.fNumPurgeable);
|
||||
REPORTER_ASSERT(reporter, 1 == stats.fNumNonPurgeable);
|
||||
#endif
|
||||
|
||||
cache.end();
|
||||
|
||||
#if GR_CACHE_STATS
|
||||
resourceCache->getStats(&stats);
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fTotal);
|
||||
REPORTER_ASSERT(reporter, 2 == stats.fNumPurgeable);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ void test_replacements(skiatest::Reporter* r, GrContext* context, bool doReplace
|
||||
desc.fSampleCnt = 0;
|
||||
|
||||
texture.reset(context->textureProvider()->createTexture(desc, false, nullptr, 0));
|
||||
layer->setTexture(texture, SkIRect::MakeWH(kWidth, kHeight));
|
||||
layer->setTexture(texture, SkIRect::MakeWH(kWidth, kHeight), false);
|
||||
}
|
||||
|
||||
SkRecord rerecord;
|
||||
|
Loading…
Reference in New Issue
Block a user