| 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);
|
| }
|
|
|