Index: src/gpu/GrStencilAndCoverTextContext.cpp |
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp |
index 0dc902928b0568abec3d296b4ba5d5c5f3c13860..ee1f1af4107ac17597732daeb5364d77581f8099 100644 |
--- a/src/gpu/GrStencilAndCoverTextContext.cpp |
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp |
@@ -81,8 +81,8 @@ void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget* |
const SkIRect& clipBounds) { |
TextRun run(skPaint); |
GrPipelineBuilder pipelineBuilder(paint, rt, clip); |
- run.setText(text, byteLength, x, y, fContext, &fSurfaceProps); |
- run.draw(dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBounds, |
+ run.setText(text, byteLength, x, y); |
+ run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBounds, |
fFallbackTextContext, skPaint); |
} |
@@ -99,8 +99,8 @@ void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarg |
const SkIRect& clipBounds) { |
TextRun run(skPaint); |
GrPipelineBuilder pipelineBuilder(paint, rt, clip); |
- run.setPosText(text, byteLength, pos, scalarsPerPosition, offset, fContext, &fSurfaceProps); |
- run.draw(dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBounds, |
+ run.setPosText(text, byteLength, pos, scalarsPerPosition, offset); |
+ run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBounds, |
fFallbackTextContext, skPaint); |
} |
@@ -137,8 +137,9 @@ void GrStencilAndCoverTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarge |
TextBlob::Iter iter(blob); |
for (TextRun* run = iter.get(); run; run = iter.next()) { |
- run->draw(dc, &pipelineBuilder, paint.getColor(), viewMatrix, x, y, clipBounds, |
+ run->draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, x, y, clipBounds, |
fFallbackTextContext, skPaint); |
+ run->releaseGlyphCache(); |
} |
} |
@@ -153,8 +154,7 @@ GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob, |
fLRUList.addToTail(*found); |
return **found; |
} |
- TextBlob* blob = new TextBlob(skBlob->uniqueID(), skBlob, skPaint, fContext, |
- &fSurfaceProps); |
+ TextBlob* blob = new TextBlob(skBlob->uniqueID(), skBlob, skPaint); |
this->purgeToFit(*blob); |
fBlobIdCache.set(skBlob->uniqueID(), blob); |
fLRUList.addToTail(blob); |
@@ -171,7 +171,7 @@ GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob, |
fLRUList.addToTail(*found); |
return **found; |
} |
- TextBlob* blob = new TextBlob(key, skBlob, skPaint, fContext, &fSurfaceProps); |
+ TextBlob* blob = new TextBlob(key, skBlob, skPaint); |
this->purgeToFit(*blob); |
fBlobKeyCache.set(blob); |
fLRUList.addToTail(blob); |
@@ -181,9 +181,9 @@ GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob, |
} |
void GrStencilAndCoverTextContext::purgeToFit(const TextBlob& blob) { |
- static const int maxCacheSize = 4 * 1024 * 1024; // Allow up to 4 MB for caching text blobs. |
+ static const size_t maxCacheSize = 4 * 1024 * 1024; // Allow up to 4 MB for caching text blobs. |
- int maxSizeForNewBlob = maxCacheSize - blob.cpuMemorySize(); |
+ size_t maxSizeForNewBlob = maxCacheSize - blob.cpuMemorySize(); |
while (fCacheSize && fCacheSize > maxSizeForNewBlob) { |
TextBlob* lru = fLRUList.head(); |
if (1 == lru->key().count()) { |
@@ -200,8 +200,8 @@ void GrStencilAndCoverTextContext::purgeToFit(const TextBlob& blob) { |
//////////////////////////////////////////////////////////////////////////////////////////////////// |
-void GrStencilAndCoverTextContext::TextBlob::init(const SkTextBlob* skBlob, const SkPaint& skPaint, |
- GrContext* ctx, const SkSurfaceProps* props) { |
+void GrStencilAndCoverTextContext::TextBlob::init(const SkTextBlob* skBlob, |
+ const SkPaint& skPaint) { |
fCpuMemorySize = sizeof(TextBlob); |
SkPaint runPaint(skPaint); |
for (SkTextBlob::RunIterator iter(skBlob); !iter.done(); iter.next()) { |
@@ -214,18 +214,17 @@ void GrStencilAndCoverTextContext::TextBlob::init(const SkTextBlob* skBlob, cons |
switch (iter.positioning()) { |
case SkTextBlob::kDefault_Positioning: |
- run->setText(text, byteLength, runOffset.fX, runOffset.fY, ctx, props); |
+ run->setText(text, byteLength, runOffset.fX, runOffset.fY); |
break; |
case SkTextBlob::kHorizontal_Positioning: |
- run->setPosText(text, byteLength, iter.pos(), 1, SkPoint::Make(0, runOffset.fY), |
- ctx, props); |
+ run->setPosText(text, byteLength, iter.pos(), 1, SkPoint::Make(0, runOffset.fY)); |
break; |
case SkTextBlob::kFull_Positioning: |
- run->setPosText(text, byteLength, iter.pos(), 2, SkPoint::Make(0, 0), ctx, props); |
+ run->setPosText(text, byteLength, iter.pos(), 2, SkPoint::Make(0, 0)); |
break; |
} |
- fCpuMemorySize += run->cpuMemorySize(); |
+ fCpuMemorySize += run->computeSizeInCache(); |
} |
} |
@@ -260,7 +259,9 @@ private: |
GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) |
: fStroke(fontAndStroke), |
fFont(fontAndStroke), |
- fTotalGlyphCount(0) { |
+ fTotalGlyphCount(0), |
+ fDetachedGlyphCache(nullptr), |
+ fLastDrawnGlyphsID(SK_InvalidUniqueID) { |
SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported. |
// Setting to "fill" ensures that no strokes get baked into font outlines. (We use the GPU path |
@@ -307,28 +308,55 @@ GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) |
fUsingRawGlyphPaths = false; |
} |
+ // Generate the key that will be used to cache the GPU glyph path objects. |
+ if (fUsingRawGlyphPaths && fStroke.isFillStyle()) { |
+ static const GrUniqueKey::Domain kRawFillPathGlyphDomain = GrUniqueKey::GenerateDomain(); |
+ |
+ const SkTypeface* typeface = fFont.getTypeface(); |
+ GrUniqueKey::Builder builder(&fGlyphPathsKey, kRawFillPathGlyphDomain, 1); |
+ reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0; |
+ } else { |
+ static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDomain(); |
+ |
+ int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt(); |
+ if (fUsingRawGlyphPaths) { |
+ const SkTypeface* typeface = fFont.getTypeface(); |
+ GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 + strokeDataCount); |
+ reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0; |
+ reinterpret_cast<uint32_t&>(builder[1]) = strokeDataCount; |
+ fStroke.asUniqueKeyFragment(&builder[2]); |
+ } else { |
+ SkGlyphCache* glyphCache = this->getGlyphCache(); |
+ const SkTypeface* typeface = glyphCache->getScalerContext()->getTypeface(); |
+ const SkDescriptor* desc = &glyphCache->getDescriptor(); |
+ int descDataCount = (desc->getLength() + 3) / 4; |
+ GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, |
+ 2 + strokeDataCount + descDataCount); |
+ reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0; |
+ reinterpret_cast<uint32_t&>(builder[1]) = strokeDataCount | (descDataCount << 16); |
+ fStroke.asUniqueKeyFragment(&builder[2]); |
+ memcpy(&builder[2 + strokeDataCount], desc, desc->getLength()); |
+ } |
+ } |
+ |
// When drawing from canonically sized paths, the actual local coords are fTextRatio * coords. |
fLocalMatrixTemplate.setScale(fTextRatio, fTextRatio); |
} |
GrStencilAndCoverTextContext::TextRun::~TextRun() { |
+ this->releaseGlyphCache(); |
} |
void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t byteLength, |
- SkScalar x, SkScalar y, GrContext* ctx, |
- const SkSurfaceProps* surfaceProps) { |
+ SkScalar x, SkScalar y) { |
SkASSERT(byteLength == 0 || text != nullptr); |
- SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr); |
- SkGlyphCache* glyphCache = autoGlyphCache.getCache(); |
- |
- fTotalGlyphCount = fFont.countText(text, byteLength); |
- fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache), |
- GrPathRendering::kTranslate_PathTransformType, |
- fTotalGlyphCount)); |
- |
+ SkGlyphCache* glyphCache = this->getGlyphCache(); |
SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); |
+ fDraw.reset(GrPathRangeDraw::Create(GrPathRendering::kTranslate_PathTransformType, |
+ fTotalGlyphCount = fFont.countText(text, byteLength))); |
+ |
const char* stop = text + byteLength; |
// Measure first if needed. |
@@ -378,28 +406,21 @@ void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t by |
fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio); |
} |
- fDraw->loadGlyphPathsIfNeeded(); |
- |
fFallbackTextBlob.reset(fallback.buildIfInitialized()); |
} |
void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t byteLength, |
const SkScalar pos[], int scalarsPerPosition, |
- const SkPoint& offset, GrContext* ctx, |
- const SkSurfaceProps* surfaceProps) { |
+ const SkPoint& offset) { |
SkASSERT(byteLength == 0 || text != nullptr); |
SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
- SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr); |
- SkGlyphCache* glyphCache = autoGlyphCache.getCache(); |
- |
- fTotalGlyphCount = fFont.countText(text, byteLength); |
- fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache), |
- GrPathRendering::kTranslate_PathTransformType, |
- fTotalGlyphCount)); |
- |
+ SkGlyphCache* glyphCache = this->getGlyphCache(); |
SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); |
+ fDraw.reset(GrPathRangeDraw::Create(GrPathRendering::kTranslate_PathTransformType, |
+ fTotalGlyphCount = fFont.countText(text, byteLength))); |
+ |
const char* stop = text + byteLength; |
SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); |
@@ -418,39 +439,24 @@ void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t |
pos += scalarsPerPosition; |
} |
- fDraw->loadGlyphPathsIfNeeded(); |
- |
fFallbackTextBlob.reset(fallback.buildIfInitialized()); |
} |
-GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx, |
- SkGlyphCache* glyphCache) { |
- SkTypeface* typeface = fUsingRawGlyphPaths ? fFont.getTypeface() |
- : glyphCache->getScalerContext()->getTypeface(); |
- const SkDescriptor* desc = fUsingRawGlyphPaths ? nullptr : &glyphCache->getDescriptor(); |
- |
- static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDomain(); |
- int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt(); |
- GrUniqueKey glyphKey; |
- GrUniqueKey::Builder builder(&glyphKey, kPathGlyphDomain, 2 + strokeDataCount); |
- reinterpret_cast<uint32_t&>(builder[0]) = desc ? desc->getChecksum() : 0; |
- reinterpret_cast<uint32_t&>(builder[1]) = typeface ? typeface->uniqueID() : 0; |
- if (strokeDataCount > 0) { |
- fStroke.asUniqueKeyFragment(&builder[2]); |
- } |
- builder.finish(); |
- |
- SkAutoTUnref<GrPathRange> glyphs( |
- static_cast<GrPathRange*>( |
- ctx->resourceProvider()->findAndRefResourceByUniqueKey(glyphKey))); |
+GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx) const { |
+ GrPathRange* glyphs = static_cast<GrPathRange*>( |
+ ctx->resourceProvider()->findAndRefResourceByUniqueKey(fGlyphPathsKey)); |
if (nullptr == glyphs) { |
- glyphs.reset(ctx->resourceProvider()->createGlyphs(typeface, desc, fStroke)); |
- ctx->resourceProvider()->assignUniqueKeyToResource(glyphKey, glyphs); |
- } else { |
- SkASSERT(nullptr == desc || glyphs->isEqualTo(*desc)); |
+ if (fUsingRawGlyphPaths) { |
+ glyphs = ctx->resourceProvider()->createGlyphs(fFont.getTypeface(), nullptr, fStroke); |
+ } else { |
+ SkGlyphCache* cache = this->getGlyphCache(); |
+ glyphs = ctx->resourceProvider()->createGlyphs(cache->getScalerContext()->getTypeface(), |
+ &cache->getDescriptor(), |
+ fStroke); |
+ } |
+ ctx->resourceProvider()->assignUniqueKeyToResource(fGlyphPathsKey, glyphs); |
} |
- |
- return glyphs.detach(); |
+ return glyphs; |
} |
inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& glyph, |
@@ -468,7 +474,8 @@ inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& gl |
} |
} |
-void GrStencilAndCoverTextContext::TextRun::draw(GrDrawContext* dc, |
+void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, |
+ GrDrawContext* dc, |
GrPipelineBuilder* pipelineBuilder, |
GrColor color, |
const SkMatrix& viewMatrix, |
@@ -493,6 +500,13 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrDrawContext* dc, |
*pipelineBuilder->stencil() = kStencilPass; |
+ SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx)); |
+ if (fLastDrawnGlyphsID != glyphs->getUniqueID()) { |
+ // Either this is the first draw or the glyphs object was purged since last draw. |
+ glyphs->loadPathsIfNeeded(fDraw->indices(), fDraw->count()); |
+ fLastDrawnGlyphsID = glyphs->getUniqueID(); |
+ } |
+ |
SkMatrix drawMatrix(viewMatrix); |
drawMatrix.preTranslate(x, y); |
drawMatrix.preScale(fTextRatio, fTextRatio); |
@@ -501,7 +515,7 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrDrawContext* dc, |
localMatrix.setTranslateX(x); |
localMatrix.setTranslateY(y); |
- dc->drawPathsFromRange(pipelineBuilder, drawMatrix, localMatrix, color, fDraw, |
+ dc->drawPathsFromRange(pipelineBuilder, drawMatrix, localMatrix, color, glyphs, fDraw, |
GrPathRendering::kWinding_FillType); |
} |
@@ -518,8 +532,25 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrDrawContext* dc, |
} |
} |
-int GrStencilAndCoverTextContext::TextRun::cpuMemorySize() const { |
- int size = sizeof(TextRun) + fTotalGlyphCount * (sizeof(uint16_t) + 2 * sizeof(float)); |
+SkGlyphCache* GrStencilAndCoverTextContext::TextRun::getGlyphCache() const { |
+ if (!fDetachedGlyphCache) { |
+ fDetachedGlyphCache = fFont.detachCache(nullptr, nullptr, true /*ignoreGamma*/); |
+ } |
+ return fDetachedGlyphCache; |
+} |
+ |
+ |
+void GrStencilAndCoverTextContext::TextRun::releaseGlyphCache() const { |
+ if (fDetachedGlyphCache) { |
+ SkGlyphCache::AttachCache(fDetachedGlyphCache); |
+ fDetachedGlyphCache = nullptr; |
+ } |
+} |
+ |
+size_t GrStencilAndCoverTextContext::TextRun::computeSizeInCache() const { |
+ size_t size = sizeof(TextRun) + |
+ fGlyphPathsKey.size() + |
+ fTotalGlyphCount * (sizeof(uint16_t) + 2 * sizeof(float)); |
if (fDraw) { |
size += sizeof(GrPathRangeDraw); |
} |