From: joshualitt Date: Wed, 8 Apr 2015 15:07:59 +0000 (-0700) Subject: Adding bulk plot reffer to cached textblobs X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~2851 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b4c507e03386f2105e33f0c4c09b4a9d0a23196d;p=platform%2Fupstream%2FlibSkiaSharp.git Adding bulk plot reffer to cached textblobs This change will prevent the atlas from evicting glyphs the TextBlob needs. BUG=skia: Committed: https://skia.googlesource.com/skia/+/7281c61e7bc689d484dcbda49be3cef4ce4f11c2 Review URL: https://codereview.chromium.org/1050113004 --- diff --git a/src/gpu/GrAADistanceFieldPathRenderer.cpp b/src/gpu/GrAADistanceFieldPathRenderer.cpp index 789406b..cbb0824 100755 --- a/src/gpu/GrAADistanceFieldPathRenderer.cpp +++ b/src/gpu/GrAADistanceFieldPathRenderer.cpp @@ -275,7 +275,7 @@ public: } } - atlas->setLastRefToken(args.fPathData->fID, batchTarget->currentToken()); + atlas->setLastUseToken(args.fPathData->fID, batchTarget->currentToken()); // Now set vertices intptr_t offset = reinterpret_cast(vertices); diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp index 08e6a9a..38edc8e 100644 --- a/src/gpu/GrAtlasTextContext.cpp +++ b/src/gpu/GrAtlasTextContext.cpp @@ -821,6 +821,7 @@ public: GrBatchTextStrike* strike = NULL; bool brokenRun = false; if (regenerateTextureCoords) { + info.fBulkUseToken.reset(); desc = run.fDescriptor.getDesc(); cache = SkGlyphCache::DetachCache(run.fTypeface, desc); scaler = GrTextContext::GetGrFontScaler(cache); @@ -846,8 +847,8 @@ public: scaler); SkASSERT(success); } - - fFontCache->setGlyphRefToken(glyph, batchTarget->currentToken()); + fFontCache->addGlyphToBulkAndSetUseToken(&info.fBulkUseToken, glyph, + batchTarget->currentToken()); // Texture coords are the last vertex attribute so we get a pointer to the // first one and then map with stride in regenerateTextureCoords @@ -876,6 +877,12 @@ public: } } else { instancesToFlush += glyphCount; + + // set use tokens for all of the glyphs in our subrun. This is only valid if we + // have a valid atlas generation + fFontCache->setUseTokenBulk(info.fBulkUseToken, + batchTarget->currentToken(), + fMaskFormat); } // now copy all vertices diff --git a/src/gpu/GrAtlasTextContext.h b/src/gpu/GrAtlasTextContext.h index de07d1f..a75eb0e 100644 --- a/src/gpu/GrAtlasTextContext.h +++ b/src/gpu/GrAtlasTextContext.h @@ -10,6 +10,7 @@ #include "GrTextContext.h" +#include "GrBatchAtlas.h" #include "GrGeometryProcessor.h" #include "SkDescriptor.h" #include "SkTextBlob.h" @@ -103,6 +104,7 @@ private: uint32_t fGlyphEndIndex; size_t fVertexStartIndex; size_t fVertexEndIndex; + GrBatchAtlas::BulkUseTokenUpdater fBulkUseToken; }; SkSTArray<1, SubRunInfo, true> fSubRunInfo; SkAutoDescriptor fDescriptor; diff --git a/src/gpu/GrBatchAtlas.cpp b/src/gpu/GrBatchAtlas.cpp index 3374e00..53ed177 100644 --- a/src/gpu/GrBatchAtlas.cpp +++ b/src/gpu/GrBatchAtlas.cpp @@ -11,12 +11,6 @@ #include "GrRectanizer.h" #include "GrTracing.h" -// for testing -#define ATLAS_STATS 0 -#if ATLAS_STATS -static int g_UploadCount = 0; -#endif - static inline void adjust_for_offset(SkIPoint16* loc, const SkIPoint16& offset) { loc->fX += offset.fX; loc->fY += offset.fY; @@ -73,10 +67,6 @@ public: adjust_for_offset(loc, fOffset); SkDEBUGCODE(fDirty = true;) -#if ATLAS_STATS - ++g_UploadCount; -#endif - return true; } @@ -86,9 +76,15 @@ public: // when we can evict a plot from the cache, ie if the last ref has already flushed through // the gpu then we can reuse the plot BatchToken lastUploadToken() const { return fLastUpload; } - BatchToken lastRefToken() const { return fLastRef; } - void setLastUploadToken(BatchToken batchToken) { fLastUpload = batchToken; } - void setLastRefToken(BatchToken batchToken) { fLastRef = batchToken; } + BatchToken lastUseToken() const { return fLastUse; } + void setLastUploadToken(BatchToken batchToken) { + SkASSERT(batchToken >= fLastUpload); + fLastUpload = batchToken; + } + void setLastUseToken(BatchToken batchToken) { + SkASSERT(batchToken >= fLastUse); + fLastUse = batchToken; + } void uploadToTexture(GrBatchTarget::TextureUploader uploader) { // We should only be issuing uploads if we are in fact dirty @@ -127,7 +123,7 @@ public: private: BatchPlot() : fLastUpload(0) - , fLastRef(0) + , fLastUse(0) , fIndex(-1) , fGenID(-1) , fID(0) @@ -177,7 +173,7 @@ private: } BatchToken fLastUpload; - BatchToken fLastRef; + BatchToken fLastUse; uint32_t fIndex; uint32_t fGenID; @@ -229,6 +225,7 @@ GrBatchAtlas::GrBatchAtlas(GrTexture* texture, int numPlotsX, int numPlotsY) , fPlotWidth(texture->width() / numPlotsX) , fPlotHeight(texture->height() / numPlotsY) , fAtlasGeneration(kInvalidAtlasGeneration + 1) { + SkASSERT(fNumPlotsX * fNumPlotsY <= BulkUseTokenUpdater::kMaxPlots); SkASSERT(fPlotWidth * fNumPlotsX == texture->width()); SkASSERT(fPlotHeight * fNumPlotsY == texture->height()); @@ -256,10 +253,6 @@ GrBatchAtlas::GrBatchAtlas(GrTexture* texture, int numPlotsX, int numPlotsY) GrBatchAtlas::~GrBatchAtlas() { SkSafeUnref(fTexture); SkDELETE_ARRAY(fPlotArray); - -#if ATLAS_STATS - SkDebugf("Num uploads: %d\n", g_UploadCount); -#endif } void GrBatchAtlas::processEviction(AtlasID id) { @@ -313,7 +306,7 @@ bool GrBatchAtlas::addToAtlas(AtlasID* id, GrBatchTarget* batchTarget, plotIter.init(fPlotList, GrBatchPlotList::Iter::kTail_IterStart); plot = plotIter.get(); SkASSERT(plot); - if (batchTarget->isIssued(plot->lastRefToken())) { + if (batchTarget->isIssued(plot->lastUseToken())) { this->processEviction(plot->id()); plot->resetRects(); SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc, fBPP * width); @@ -329,7 +322,7 @@ bool GrBatchAtlas::addToAtlas(AtlasID* id, GrBatchTarget* batchTarget, // off the plot(ie let the batch target manage it) and create a new plot in its place in our // array. If it is equal to the currentToken, then the caller has to flush draws to the batch // target so we can spin off the plot - if (plot->lastRefToken() == batchTarget->currentToken()) { + if (plot->lastUseToken() == batchTarget->currentToken()) { return false; } @@ -359,14 +352,23 @@ bool GrBatchAtlas::addToAtlas(AtlasID* id, GrBatchTarget* batchTarget, } bool GrBatchAtlas::hasID(AtlasID id) { - int index = this->getIndexFromID(id); + int index = GetIndexFromID(id); SkASSERT(index < fNumPlotsX * fNumPlotsY); - return fPlotArray[index]->genID() == this->getGenerationFromID(id); + return fPlotArray[index]->genID() == GetGenerationFromID(id); } -void GrBatchAtlas::setLastRefToken(AtlasID id, BatchToken batchToken) { +void GrBatchAtlas::setLastUseToken(AtlasID id, BatchToken batchToken) { SkASSERT(this->hasID(id)); - int index = this->getIndexFromID(id); + int index = GetIndexFromID(id); + SkASSERT(index < fNumPlotsX * fNumPlotsY); this->makeMRU(fPlotArray[index]); - fPlotArray[index]->setLastRefToken(batchToken); + fPlotArray[index]->setLastUseToken(batchToken); +} + +void GrBatchAtlas::setLastUseTokenBulk(const BulkUseTokenUpdater& updater, BatchToken batchToken) { + for (int i = 0; i < updater.fCount; i++) { + BatchPlot* plot = fPlotArray[updater.fPlotsToUpdate[i]]; + this->makeMRU(plot); + plot->setLastUseToken(batchToken); + } } diff --git a/src/gpu/GrBatchAtlas.h b/src/gpu/GrBatchAtlas.h index cd8123f..889d260 100644 --- a/src/gpu/GrBatchAtlas.h +++ b/src/gpu/GrBatchAtlas.h @@ -40,6 +40,9 @@ public: // the containing GrPlot and absolute location in the backing texture. // NULL is returned if the subimage cannot fit in the atlas. // If provided, the image data will be written to the CPU-side backing bitmap. + // NOTE: If the client intends to refer to the atlas, they should immediately call 'setUseToken' + // with the currentToken from the batch target, otherwise the next call to addToAtlas might + // cause an eviction bool addToAtlas(AtlasID*, GrBatchTarget*, int width, int height, const void* image, SkIPoint16* loc); @@ -47,19 +50,74 @@ public: uint64_t atlasGeneration() const { return fAtlasGeneration; } bool hasID(AtlasID id); - void setLastRefToken(AtlasID id, BatchToken batchToken); + + // To ensure the atlas does not evict a given entry, the client must set the last use token + void setLastUseToken(AtlasID id, BatchToken batchToken); void registerEvictionCallback(EvictionFunc func, void* userData) { EvictionData* data = fEvictionCallbacks.append(); data->fFunc = func; data->fData = userData; } + /* + * A class which can be handed back to GrBatchAtlas for updating in bulk last use tokens. The + * current max number of plots the GrBatchAtlas can handle is 32, if in the future this is + * insufficient then we can move to a 64 bit int + */ + class BulkUseTokenUpdater { + public: + BulkUseTokenUpdater() : fPlotAlreadyUpdated(0), fCount(0), fAllocated(kMinItems) {} + void add(AtlasID id) { + int index = GrBatchAtlas::GetIndexFromID(id); + if (!this->find(index)) { + this->set(index); + } + } + + void reset() { + fPlotsToUpdate.reset(kMinItems); + fAllocated = kMinItems; + fCount = 0; + fPlotAlreadyUpdated = 0; + } + + private: + bool find(int index) const { + SkASSERT(index < kMaxPlots); + return (fPlotAlreadyUpdated >> index) & 1; + } + + void set(int index) { + SkASSERT(!this->find(index)); + fPlotAlreadyUpdated = fPlotAlreadyUpdated | (1 << index); + if (fCount < fAllocated) { + fPlotsToUpdate[fCount++] = index; + } else { + // This case will almost never happen + fAllocated = fCount << 1; + fPlotsToUpdate.realloc(fAllocated); + fPlotsToUpdate[fCount++] = index; + } + } + + static const int kMinItems = 4; + static const int kMaxPlots = 32; + uint32_t fPlotAlreadyUpdated; + SkAutoSTMalloc fPlotsToUpdate; + int fCount; + int fAllocated; + + friend class GrBatchAtlas; + }; + + void setLastUseTokenBulk(const BulkUseTokenUpdater& reffer, BatchToken); + private: - int getIndexFromID(AtlasID id) { + static int GetIndexFromID(AtlasID id) { return id & 0xffff; } - int getGenerationFromID(AtlasID id) { + static int GetGenerationFromID(AtlasID id) { return (id >> 16) & 0xffff; } diff --git a/src/gpu/GrBatchFontCache.cpp b/src/gpu/GrBatchFontCache.cpp index c429d53..3cd7a64 100644 --- a/src/gpu/GrBatchFontCache.cpp +++ b/src/gpu/GrBatchFontCache.cpp @@ -128,10 +128,18 @@ bool GrBatchFontCache::hasGlyph(GrGlyph* glyph) { return this->getAtlas(glyph->fMaskFormat)->hasID(glyph->fID); } -void GrBatchFontCache::setGlyphRefToken(GrGlyph* glyph, GrBatchAtlas::BatchToken batchToken) { +void GrBatchFontCache::addGlyphToBulkAndSetUseToken(GrBatchAtlas::BulkUseTokenUpdater* updater, + GrGlyph* glyph, + GrBatchAtlas::BatchToken token) { SkASSERT(glyph); - SkASSERT(this->getAtlas(glyph->fMaskFormat)->hasID(glyph->fID)); - this->getAtlas(glyph->fMaskFormat)->setLastRefToken(glyph->fID, batchToken); + updater->add(glyph->fID); + this->getAtlas(glyph->fMaskFormat)->setLastUseToken(glyph->fID, token); +} + +void GrBatchFontCache::setUseTokenBulk(const GrBatchAtlas::BulkUseTokenUpdater& updater, + GrBatchAtlas::BatchToken token, + GrMaskFormat format) { + this->getAtlas(format)->setLastUseTokenBulk(updater, token); } bool GrBatchFontCache::addToAtlas(GrBatchTextStrike* strike, GrBatchAtlas::AtlasID* id, diff --git a/src/gpu/GrBatchFontCache.h b/src/gpu/GrBatchFontCache.h index 6300fbe..d935232 100644 --- a/src/gpu/GrBatchFontCache.h +++ b/src/gpu/GrBatchFontCache.h @@ -97,8 +97,15 @@ public: bool hasGlyph(GrGlyph* glyph); // To ensure the GrBatchAtlas does not evict the Glyph Mask from its texture backing store, - // the client must pass in the currentToken from the GrBatchTarget along with the GrGlyph - void setGlyphRefToken(GrGlyph*, GrBatchAtlas::BatchToken); + // the client must pass in the currentToken from the GrBatchTarget along with the GrGlyph. + // A BulkUseTokenUpdater is used to manage bulk last use token updating in the Atlas. + // For convenience, this function will also set the use token for the current glyph if required + // NOTE: the bulk uploader is only valid if the subrun has a valid atlasGeneration + void addGlyphToBulkAndSetUseToken(GrBatchAtlas::BulkUseTokenUpdater*, GrGlyph*, + GrBatchAtlas::BatchToken); + + void setUseTokenBulk(const GrBatchAtlas::BulkUseTokenUpdater&, GrBatchAtlas::BatchToken, + GrMaskFormat); // add to texture atlas that matches this format bool addToAtlas(GrBatchTextStrike*, GrBatchAtlas::AtlasID*, GrBatchTarget*,