Store pointers to GrGlyph directly in BitmapTextBlob. This patch improves performance by avoiding hashmap lookups under normal use
BUG=skia: Review URL: https://codereview.chromium.org/1087203004
This commit is contained in:
parent
cdec56e72b
commit
ae32c102e7
@ -1164,8 +1164,10 @@ void GrAtlasTextContext::bmpAppendGlyph(BitmapTextBlob* blob, int runIndex,
|
||||
GrGlyph::PackedID packed,
|
||||
int vx, int vy, GrColor color, GrFontScaler* scaler,
|
||||
const SkIRect& clipRect) {
|
||||
Run& run = blob->fRuns[runIndex];
|
||||
if (!fCurrStrike) {
|
||||
fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler);
|
||||
run.fStrike.reset(SkRef(fCurrStrike));
|
||||
}
|
||||
|
||||
GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler);
|
||||
@ -1198,8 +1200,6 @@ void GrAtlasTextContext::bmpAppendGlyph(BitmapTextBlob* blob, int runIndex,
|
||||
return;
|
||||
}
|
||||
|
||||
Run& run = blob->fRuns[runIndex];
|
||||
|
||||
GrMaskFormat format = glyph->fMaskFormat;
|
||||
|
||||
PerSubRunInfo* subRun = &run.fSubRunInfo.back();
|
||||
@ -1218,7 +1218,7 @@ void GrAtlasTextContext::bmpAppendGlyph(BitmapTextBlob* blob, int runIndex,
|
||||
r.fBottom = r.fTop + SkIntToScalar(height);
|
||||
subRun->fMaskFormat = format;
|
||||
this->appendGlyphCommon(blob, &run, subRun, r, color, vertexStride, kA8_GrMaskFormat == format,
|
||||
packed);
|
||||
glyph);
|
||||
}
|
||||
|
||||
bool GrAtlasTextContext::dfAppendGlyph(BitmapTextBlob* blob, int runIndex,
|
||||
@ -1227,8 +1227,10 @@ bool GrAtlasTextContext::dfAppendGlyph(BitmapTextBlob* blob, int runIndex,
|
||||
GrFontScaler* scaler,
|
||||
const SkIRect& clipRect,
|
||||
SkScalar textRatio, const SkMatrix& viewMatrix) {
|
||||
Run& run = blob->fRuns[runIndex];
|
||||
if (!fCurrStrike) {
|
||||
fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler);
|
||||
run.fStrike.reset(SkRef(fCurrStrike));
|
||||
}
|
||||
|
||||
GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler);
|
||||
@ -1275,8 +1277,6 @@ bool GrAtlasTextContext::dfAppendGlyph(BitmapTextBlob* blob, int runIndex,
|
||||
return true;
|
||||
}
|
||||
|
||||
Run& run = blob->fRuns[runIndex];
|
||||
|
||||
PerSubRunInfo* subRun = &run.fSubRunInfo.back();
|
||||
SkASSERT(glyph->fMaskFormat == kA8_GrMaskFormat);
|
||||
subRun->fMaskFormat = kA8_GrMaskFormat;
|
||||
@ -1285,7 +1285,7 @@ bool GrAtlasTextContext::dfAppendGlyph(BitmapTextBlob* blob, int runIndex,
|
||||
|
||||
bool useColorVerts = !subRun->fUseLCDText;
|
||||
this->appendGlyphCommon(blob, &run, subRun, glyphRect, color, vertexStride, useColorVerts,
|
||||
packed);
|
||||
glyph);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1308,8 +1308,8 @@ inline void GrAtlasTextContext::appendGlyphCommon(BitmapTextBlob* blob, Run* run
|
||||
Run::SubRunInfo* subRun,
|
||||
const SkRect& positions, GrColor color,
|
||||
size_t vertexStride, bool useVertexColor,
|
||||
GrGlyph::PackedID packed) {
|
||||
blob->fGlyphIDs[subRun->fGlyphEndIndex] = packed;
|
||||
GrGlyph* glyph) {
|
||||
blob->fGlyphs[subRun->fGlyphEndIndex] = glyph;
|
||||
run->fVertexBounds.joinNonEmptyArg(positions);
|
||||
run->fColor = color;
|
||||
|
||||
@ -1508,7 +1508,6 @@ public:
|
||||
const SkDescriptor* desc = NULL;
|
||||
SkGlyphCache* cache = NULL;
|
||||
GrFontScaler* scaler = NULL;
|
||||
GrBatchTextStrike* strike = NULL;
|
||||
SkTypeface* typeface = NULL;
|
||||
|
||||
int instancesToFlush = 0;
|
||||
@ -1540,6 +1539,17 @@ public:
|
||||
if (regenerateTextureCoords || regenerateColors || regeneratePositions) {
|
||||
// first regenerate texture coordinates / colors if need be
|
||||
bool brokenRun = false;
|
||||
|
||||
// Because the GrBatchFontCache may evict the strike a blob depends on using for
|
||||
// generating its texture coords, we have to track whether or not the strike has
|
||||
// been abandoned. If it hasn't been abandoned, then we can use the GrGlyph*s as is
|
||||
// otherwise we have to get the new strike, and use that to get the correct glyphs.
|
||||
// Because we do not have the packed ids, and thus can't look up our glyphs in the
|
||||
// new strike, we instead keep our ref to the old strike and use the packed ids from
|
||||
// it. These ids will still be valid as long as we hold the ref. When we are done
|
||||
// updating our cache of the GrGlyph*s, we drop our ref on the old strike
|
||||
bool regenerateGlyphs = false;
|
||||
GrBatchTextStrike* strike = NULL;
|
||||
if (regenerateTextureCoords) {
|
||||
info.fBulkUseToken.reset();
|
||||
|
||||
@ -1556,16 +1566,30 @@ public:
|
||||
desc = newDesc;
|
||||
cache = SkGlyphCache::DetachCache(run.fTypeface, desc);
|
||||
scaler = GrTextContext::GetGrFontScaler(cache);
|
||||
strike = fFontCache->getStrike(scaler);
|
||||
strike = run.fStrike;
|
||||
typeface = run.fTypeface;
|
||||
}
|
||||
}
|
||||
for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) {
|
||||
GrGlyph::PackedID glyphID = blob->fGlyphIDs[glyphIdx + info.fGlyphStartIndex];
|
||||
|
||||
if (run.fStrike->isAbandoned()) {
|
||||
regenerateGlyphs = true;
|
||||
strike = fFontCache->getStrike(scaler);
|
||||
} else {
|
||||
strike = run.fStrike;
|
||||
}
|
||||
}
|
||||
|
||||
for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) {
|
||||
if (regenerateTextureCoords) {
|
||||
// Upload the glyph only if needed
|
||||
GrGlyph* glyph = strike->getGlyph(glyphID, scaler);
|
||||
size_t glyphOffset = glyphIdx + info.fGlyphStartIndex;
|
||||
GrGlyph* glyph;
|
||||
if (regenerateGlyphs) {
|
||||
// Get the id from the old glyph, and use the new strike to lookup
|
||||
// the glyph.
|
||||
glyph = blob->fGlyphs[glyphOffset];
|
||||
blob->fGlyphs[glyphOffset] = strike->getGlyph(glyph->fPackedID,
|
||||
scaler);
|
||||
}
|
||||
glyph = blob->fGlyphs[glyphOffset];
|
||||
SkASSERT(glyph);
|
||||
|
||||
if (!fFontCache->hasGlyph(glyph) &&
|
||||
@ -1576,7 +1600,8 @@ public:
|
||||
instancesToFlush = 0;
|
||||
brokenRun = glyphIdx > 0;
|
||||
|
||||
SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(batchTarget, glyph,
|
||||
SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(batchTarget,
|
||||
glyph,
|
||||
scaler);
|
||||
SkASSERT(success);
|
||||
}
|
||||
@ -1614,6 +1639,9 @@ public:
|
||||
// We my have changed the color so update it here
|
||||
run.fColor = args.fColor;
|
||||
if (regenerateTextureCoords) {
|
||||
if (regenerateGlyphs) {
|
||||
run.fStrike.reset(SkRef(strike));
|
||||
}
|
||||
info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAtlasGeneration :
|
||||
fFontCache->atlasGeneration(fMaskFormat);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "GrTextContext.h"
|
||||
|
||||
#include "GrBatchAtlas.h"
|
||||
#include "GrBatchFontCache.h"
|
||||
#include "GrGeometryProcessor.h"
|
||||
#include "SkDescriptor.h"
|
||||
#include "GrMemoryPool.h"
|
||||
@ -18,7 +19,6 @@
|
||||
#include "SkTextBlob.h"
|
||||
#include "SkTInternalLList.h"
|
||||
|
||||
class GrBatchTextStrike;
|
||||
class GrPipelineBuilder;
|
||||
class GrTextBlobCache;
|
||||
|
||||
@ -175,6 +175,7 @@ private:
|
||||
int fSubRunCount;
|
||||
int fSubRunAllocation;
|
||||
};
|
||||
SkAutoTUnref<GrBatchTextStrike> fStrike;
|
||||
SkAutoTUnref<SkTypeface> fTypeface;
|
||||
SkRect fVertexBounds;
|
||||
SubRunInfoArray fSubRunInfo;
|
||||
@ -222,7 +223,7 @@ private:
|
||||
|
||||
// all glyph / vertex offsets are into these pools.
|
||||
unsigned char* fVertices;
|
||||
GrGlyph::PackedID* fGlyphIDs;
|
||||
GrGlyph** fGlyphs;
|
||||
Run* fRuns;
|
||||
GrMemoryPool* fPool;
|
||||
SkMaskFilter::BlurRec fBlurRec;
|
||||
@ -287,7 +288,7 @@ private:
|
||||
inline void appendGlyphCommon(BitmapTextBlob*, Run*, Run::SubRunInfo*,
|
||||
const SkRect& positions, GrColor color,
|
||||
size_t vertexStride, bool useVertexColor,
|
||||
GrGlyph::PackedID);
|
||||
GrGlyph*);
|
||||
|
||||
inline void flushRunAsPaths(const SkTextBlob::RunIterator&, const SkPaint&, SkDrawFilter*,
|
||||
const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x,
|
||||
|
@ -74,7 +74,7 @@ GrBatchFontCache::GrBatchFontCache(GrContext* context)
|
||||
GrBatchFontCache::~GrBatchFontCache() {
|
||||
SkTDynamicHash<GrBatchTextStrike, GrFontDescKey>::Iter iter(&fCache);
|
||||
while (!iter.done()) {
|
||||
SkDELETE(&(*iter));
|
||||
(*iter).unref();
|
||||
++iter;
|
||||
}
|
||||
for (int i = 0; i < kMaskFormatCount; ++i) {
|
||||
@ -85,7 +85,7 @@ GrBatchFontCache::~GrBatchFontCache() {
|
||||
void GrBatchFontCache::freeAll() {
|
||||
SkTDynamicHash<GrBatchTextStrike, GrFontDescKey>::Iter iter(&fCache);
|
||||
while (!iter.done()) {
|
||||
SkDELETE(&(*iter));
|
||||
(*iter).unref();
|
||||
++iter;
|
||||
}
|
||||
fCache.rewind();
|
||||
@ -118,7 +118,8 @@ void GrBatchFontCache::HandleEviction(GrBatchAtlas::AtlasID id, void* ptr) {
|
||||
// triggered the eviction
|
||||
if (strike != fontCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) {
|
||||
fontCache->fCache.remove(*(strike->fFontScalerKey));
|
||||
SkDELETE(strike);
|
||||
strike->fIsAbandoned = true;
|
||||
strike->unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -155,7 +156,8 @@ void GrBatchFontCache::dump() const {
|
||||
GrBatchTextStrike::GrBatchTextStrike(GrBatchFontCache* cache, const GrFontDescKey* key)
|
||||
: fFontScalerKey(SkRef(key))
|
||||
, fPool(9/*start allocations at 512 bytes*/)
|
||||
, fAtlasedGlyphs(0) {
|
||||
, fAtlasedGlyphs(0)
|
||||
, fIsAbandoned(false) {
|
||||
|
||||
fBatchFontCache = cache; // no need to ref, it won't go away before we do
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class GrGpu;
|
||||
* is abstracted by GrGlyph, and indexed by a PackedID and GrFontScaler. The GrFontScaler is what
|
||||
* actually creates the mask.
|
||||
*/
|
||||
class GrBatchTextStrike {
|
||||
class GrBatchTextStrike : public SkNVRefCnt<GrBatchTextStrike> {
|
||||
public:
|
||||
GrBatchTextStrike(GrBatchFontCache*, const GrFontDescKey* fontScalerKey);
|
||||
~GrBatchTextStrike();
|
||||
@ -52,6 +52,9 @@ public:
|
||||
// remove any references to this plot
|
||||
void removeID(GrBatchAtlas::AtlasID);
|
||||
|
||||
// If a TextStrike is abandoned by the cache, then the caller must get a new strike
|
||||
bool isAbandoned() const { return fIsAbandoned; }
|
||||
|
||||
static const GrFontDescKey& GetKey(const GrBatchTextStrike& ts) {
|
||||
return *(ts.fFontScalerKey);
|
||||
}
|
||||
@ -66,6 +69,7 @@ private:
|
||||
|
||||
GrBatchFontCache* fBatchFontCache;
|
||||
int fAtlasedGlyphs;
|
||||
bool fIsAbandoned;
|
||||
|
||||
GrGlyph* generateGlyph(GrGlyph::PackedID packed, GrFontScaler* scaler);
|
||||
|
||||
@ -84,7 +88,10 @@ class GrBatchFontCache {
|
||||
public:
|
||||
GrBatchFontCache(GrContext*);
|
||||
~GrBatchFontCache();
|
||||
|
||||
// The user of the cache may hold a long-lived ref to the returned strike. However, actions by
|
||||
// another client of the cache may cause the strike to be purged while it is still reffed.
|
||||
// Therefore, the caller must check GrBatchTextStrike::isAbandoned() if there are other
|
||||
// interactions with the cache since the strike was received.
|
||||
inline GrBatchTextStrike* getStrike(GrFontScaler* scaler) {
|
||||
GrBatchTextStrike* strike = fCache.find(*(scaler->getKey()));
|
||||
if (NULL == strike) {
|
||||
|
@ -20,16 +20,15 @@ GrAtlasTextContext::BitmapTextBlob* GrTextBlobCache::createBlob(int glyphCount,
|
||||
size_t verticesCount = glyphCount * kVerticesPerGlyph * maxVASize;
|
||||
size_t size = sizeof(BitmapTextBlob) +
|
||||
verticesCount +
|
||||
glyphCount * sizeof(GrGlyph::PackedID) +
|
||||
glyphCount * sizeof(GrGlyph**) +
|
||||
sizeof(BitmapTextBlob::Run) * runCount;
|
||||
|
||||
BitmapTextBlob* cacheBlob = SkNEW_PLACEMENT(fPool.allocate(size), BitmapTextBlob);
|
||||
|
||||
// setup offsets for vertices / glyphs
|
||||
cacheBlob->fVertices = sizeof(BitmapTextBlob) + reinterpret_cast<unsigned char*>(cacheBlob);
|
||||
cacheBlob->fGlyphIDs =
|
||||
reinterpret_cast<GrGlyph::PackedID*>(cacheBlob->fVertices + verticesCount);
|
||||
cacheBlob->fRuns = reinterpret_cast<BitmapTextBlob::Run*>(cacheBlob->fGlyphIDs + glyphCount);
|
||||
cacheBlob->fGlyphs = reinterpret_cast<GrGlyph**>(cacheBlob->fVertices + verticesCount);
|
||||
cacheBlob->fRuns = reinterpret_cast<BitmapTextBlob::Run*>(cacheBlob->fGlyphs + glyphCount);
|
||||
|
||||
// Initialize runs
|
||||
for (int i = 0; i < runCount; i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user