Updates nvpr text blobs to not store a direct reference to the
per-glyph GPU path object, but rather store a key for looking it up in
the resource cache. This allows the cache to purge glyphs when needed.
Also indirectly fixes a memory leak that was introduced with nvpr text
blobs.
BUG=skia:
Review URL: https://codereview.chromium.org/1374853004
diff --git a/include/gpu/GrDrawContext.h b/include/gpu/GrDrawContext.h
index 9365021..03dd8c4 100644
--- a/include/gpu/GrDrawContext.h
+++ b/include/gpu/GrDrawContext.h
@@ -18,6 +18,7 @@
class GrDrawTarget;
class GrPaint;
class GrPathProcessor;
+class GrPathRange;
class GrPathRangeDraw;
class GrPipelineBuilder;
class GrRenderTarget;
@@ -67,6 +68,7 @@
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
GrColor color,
+ GrPathRange* range,
GrPathRangeDraw* draw,
int /*GrPathRendering::FillType*/ fill);
diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp
index 7e1e66f..96bc3f3 100644
--- a/src/gpu/GrDrawContext.cpp
+++ b/src/gpu/GrDrawContext.cpp
@@ -111,11 +111,12 @@
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
GrColor color,
+ GrPathRange* range,
GrPathRangeDraw* draw,
int /*GrPathRendering::FillType*/ fill) {
RETURN_IF_ABANDONED
- fDrawTarget->drawPathsFromRange(*pipelineBuilder, viewMatrix, localMatrix, color, draw,
+ fDrawTarget->drawPathsFromRange(*pipelineBuilder, viewMatrix, localMatrix, color, range, draw,
(GrPathRendering::FillType) fill);
}
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index ba0142e..cd86458 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -255,9 +255,11 @@
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
GrColor color,
+ GrPathRange* range,
GrPathRangeDraw* draw,
GrPathRendering::FillType fill) {
- GrDrawPathBatchBase* batch = GrDrawPathRangeBatch::Create(viewMatrix, localMatrix, color, draw);
+ GrDrawPathBatchBase* batch = GrDrawPathRangeBatch::Create(viewMatrix, localMatrix, color,
+ range, draw);
this->drawPathBatch(pipelineBuilder, batch, fill);
batch->unref();
}
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 8c85e0a..98faffc 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -92,7 +92,7 @@
*
* TODO: Remove this function and construct the batch outside GrDrawTarget.
*
- * @param draw The range, transforms, and indices for the draw.
+ * @param draw The transforms and indices for the draw.
* This object must only be drawn once. The draw
* may modify its contents.
* @param fill Fill type for drawing all the paths
@@ -101,6 +101,7 @@
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
GrColor color,
+ GrPathRange* range,
GrPathRangeDraw* draw,
GrPathRendering::FillType fill);
diff --git a/src/gpu/GrPathRange.cpp b/src/gpu/GrPathRange.cpp
index 117051d..754aca0 100644
--- a/src/gpu/GrPathRange.cpp
+++ b/src/gpu/GrPathRange.cpp
@@ -8,7 +8,6 @@
#include "GrPathRange.h"
#include "SkPath.h"
-
GrPathRange::GrPathRange(GrGpu* gpu,
PathGenerator* pathGenerator)
: INHERITED(gpu, kCached_LifeCycle),
@@ -27,10 +26,14 @@
void GrPathRange::loadPathsIfNeeded(const void* indices, PathIndexType indexType, int count) const {
switch (indexType) {
- case kU8_PathIndexType: return this->loadPathsIfNeeded<uint8_t>(indices, count);
- case kU16_PathIndexType: return this->loadPathsIfNeeded<uint16_t>(indices, count);
- case kU32_PathIndexType: return this->loadPathsIfNeeded<uint32_t>(indices, count);
- default: SkFAIL("Unknown path index type");
+ case kU8_PathIndexType:
+ return this->loadPathsIfNeeded(reinterpret_cast<const uint8_t*>(indices), count);
+ case kU16_PathIndexType:
+ return this->loadPathsIfNeeded(reinterpret_cast<const uint16_t*>(indices), count);
+ case kU32_PathIndexType:
+ return this->loadPathsIfNeeded(reinterpret_cast<const uint32_t*>(indices), count);
+ default:
+ SkFAIL("Unknown path index type");
}
}
@@ -38,10 +41,14 @@
void GrPathRange::assertPathsLoaded(const void* indices, PathIndexType indexType, int count) const {
switch (indexType) {
- case kU8_PathIndexType: return this->assertPathsLoaded<uint8_t>(indices, count);
- case kU16_PathIndexType: return this->assertPathsLoaded<uint16_t>(indices, count);
- case kU32_PathIndexType: return this->assertPathsLoaded<uint32_t>(indices, count);
- default: SkFAIL("Unknown path index type");
+ case kU8_PathIndexType:
+ return this->assertPathsLoaded(reinterpret_cast<const uint8_t*>(indices), count);
+ case kU16_PathIndexType:
+ return this->assertPathsLoaded(reinterpret_cast<const uint16_t*>(indices), count);
+ case kU32_PathIndexType:
+ return this->assertPathsLoaded(reinterpret_cast<const uint32_t*>(indices), count);
+ default:
+ SkFAIL("Unknown path index type");
}
}
diff --git a/src/gpu/GrPathRange.h b/src/gpu/GrPathRange.h
index 23b8beb..00165d1 100644
--- a/src/gpu/GrPathRange.h
+++ b/src/gpu/GrPathRange.h
@@ -72,18 +72,17 @@
void loadPathsIfNeeded(const void* indices, PathIndexType, int count) const;
- template<typename IndexType> void loadPathsIfNeeded(const void* indices, int count) const {
+ template<typename IndexType> void loadPathsIfNeeded(const IndexType* indices, int count) const {
if (!fPathGenerator) {
return;
}
- const IndexType* indexArray = reinterpret_cast<const IndexType*>(indices);
bool didLoadPaths = false;
for (int i = 0; i < count; ++i) {
- SkASSERT(indexArray[i] < static_cast<uint32_t>(fNumPaths));
+ SkASSERT(indices[i] < static_cast<uint32_t>(fNumPaths));
- const int groupIndex = indexArray[i] / kPathsPerGroup;
+ const int groupIndex = indices[i] / kPathsPerGroup;
const int groupByte = groupIndex / 8;
const uint8_t groupBit = 1 << (groupIndex % 8);
@@ -113,17 +112,15 @@
#ifdef SK_DEBUG
void assertPathsLoaded(const void* indices, PathIndexType, int count) const;
- template<typename IndexType> void assertPathsLoaded(const void* indices, int count) const {
+ template<typename IndexType> void assertPathsLoaded(const IndexType* indices, int count) const {
if (!fPathGenerator) {
return;
}
- const IndexType* indexArray = reinterpret_cast<const IndexType*>(indices);
-
for (int i = 0; i < count; ++i) {
- SkASSERT(indexArray[i] < static_cast<uint32_t>(fNumPaths));
+ SkASSERT(indices[i] < static_cast<uint32_t>(fNumPaths));
- const int groupIndex = indexArray[i] / kPathsPerGroup;
+ const int groupIndex = indices[i] / kPathsPerGroup;
const int groupByte = groupIndex / 8;
const uint8_t groupBit = 1 << (groupIndex % 8);
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index 0dc9029..ee1f1af 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -81,8 +81,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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::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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
-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 @@
*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 @@
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 @@
}
}
-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);
}
diff --git a/src/gpu/GrStencilAndCoverTextContext.h b/src/gpu/GrStencilAndCoverTextContext.h
index 008f61e..3bf89d3 100644
--- a/src/gpu/GrStencilAndCoverTextContext.h
+++ b/src/gpu/GrStencilAndCoverTextContext.h
@@ -17,7 +17,6 @@
class GrTextStrike;
class GrPath;
-class GrPathRange;
class SkSurfaceProps;
/*
@@ -60,22 +59,22 @@
TextRun(const SkPaint& fontAndStroke);
~TextRun();
- void setText(const char text[], size_t byteLength, SkScalar x, SkScalar y,
- GrContext*, const SkSurfaceProps*);
+ void setText(const char text[], size_t byteLength, SkScalar x, SkScalar y);
- void setPosText(const char text[], size_t byteLength,
- const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset,
- GrContext*, const SkSurfaceProps*);
+ void setPosText(const char text[], size_t byteLength, const SkScalar pos[],
+ int scalarsPerPosition, const SkPoint& offset);
- void draw(GrDrawContext*, GrPipelineBuilder*, GrColor, const SkMatrix&,
+ void draw(GrContext*, GrDrawContext*, GrPipelineBuilder*, GrColor, const SkMatrix&,
SkScalar x, SkScalar y, const SkIRect& clipBounds,
GrTextContext* fallbackTextContext, const SkPaint& originalSkPaint) const;
- int cpuMemorySize() const;
+ void releaseGlyphCache() const;
+
+ size_t computeSizeInCache() const;
private:
- GrPathRange* createGlyphs(GrContext*, SkGlyphCache*);
-
+ SkGlyphCache* getGlyphCache() const;
+ GrPathRange* createGlyphs(GrContext*) const;
void appendGlyph(const SkGlyph&, const SkPoint&, FallbackBlobBuilder*);
GrStrokeInfo fStroke;
@@ -83,9 +82,12 @@
SkScalar fTextRatio;
float fTextInverseRatio;
bool fUsingRawGlyphPaths;
+ GrUniqueKey fGlyphPathsKey;
int fTotalGlyphCount;
SkAutoTUnref<GrPathRangeDraw> fDraw;
SkAutoTUnref<const SkTextBlob> fFallbackTextBlob;
+ mutable SkGlyphCache* fDetachedGlyphCache;
+ mutable uint32_t fLastDrawnGlyphsID;
mutable SkMatrix fLocalMatrixTemplate;
};
@@ -102,27 +104,25 @@
return SkChecksum::Murmur3(key.begin(), sizeof(uint32_t) * key.count());
}
- TextBlob(uint32_t blobId, const SkTextBlob* skBlob, const SkPaint& skPaint,
- GrContext* ctx, const SkSurfaceProps* props)
- : fKey(&blobId, 1) { this->init(skBlob, skPaint, ctx, props); }
+ TextBlob(uint32_t blobId, const SkTextBlob* skBlob, const SkPaint& skPaint)
+ : fKey(&blobId, 1) { this->init(skBlob, skPaint); }
- TextBlob(const Key& key, const SkTextBlob* skBlob, const SkPaint& skPaint,
- GrContext* ctx, const SkSurfaceProps* props)
+ TextBlob(const Key& key, const SkTextBlob* skBlob, const SkPaint& skPaint)
: fKey(key) {
// 1-length keys are unterstood to be the blob id and must use the other constructor.
SkASSERT(fKey.count() > 1);
- this->init(skBlob, skPaint, ctx, props);
+ this->init(skBlob, skPaint);
}
const Key& key() const { return fKey; }
- int cpuMemorySize() const { return fCpuMemorySize; }
+ size_t cpuMemorySize() const { return fCpuMemorySize; }
private:
- void init(const SkTextBlob*, const SkPaint&, GrContext*, const SkSurfaceProps*);
+ void init(const SkTextBlob*, const SkPaint&);
const SkSTArray<1, uint32_t, true> fKey;
- int fCpuMemorySize;
+ size_t fCpuMemorySize;
SK_DECLARE_INTERNAL_LLIST_INTERFACE(TextBlob);
};
@@ -133,7 +133,7 @@
SkTHashMap<uint32_t, TextBlob*> fBlobIdCache;
SkTHashTable<TextBlob*, const TextBlob::Key&, TextBlob> fBlobKeyCache;
SkTInternalLList<TextBlob> fLRUList;
- int fCacheSize;
+ size_t fCacheSize;
typedef GrTextContext INHERITED;
};
diff --git a/src/gpu/batches/GrDrawPathBatch.cpp b/src/gpu/batches/GrDrawPathBatch.cpp
index c56c4ad..9beee8e 100644
--- a/src/gpu/batches/GrDrawPathBatch.cpp
+++ b/src/gpu/batches/GrDrawPathBatch.cpp
@@ -56,13 +56,14 @@
}
GrDrawPathRangeBatch::GrDrawPathRangeBatch(const SkMatrix& viewMatrix, const SkMatrix& localMatrix,
- GrColor color, GrPathRangeDraw* pathRangeDraw)
+ GrColor color, GrPathRange* range, GrPathRangeDraw* draw)
: INHERITED(ClassID(), viewMatrix, color)
+ , fPathRange(range)
, fDraws(4)
, fLocalMatrix(localMatrix) {
- SkDEBUGCODE(pathRangeDraw->fUsedInBatch = true;)
- fDraws.addToHead(SkRef(pathRangeDraw));
- fTotalPathCount = pathRangeDraw->count();
+ SkDEBUGCODE(draw->fUsedInBatch = true;)
+ fDraws.addToHead(SkRef(draw));
+ fTotalPathCount = draw->count();
// Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy
// the entire dst. Realistically this is a moot point, because any context that supports
// NV_path_rendering will also support NV_blend_equation_advanced.
@@ -72,6 +73,9 @@
bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) {
GrDrawPathRangeBatch* that = t->cast<GrDrawPathRangeBatch>();
+ if (this->fPathRange.get() != that->fPathRange.get()) {
+ return false;
+ }
if (!GrPathRangeDraw::CanMerge(**this->fDraws.head(), **that->fDraws.head())) {
return false;
}
@@ -116,13 +120,12 @@
&desc, &this->stencilSettings());
if (fDraws.count() == 1) {
const GrPathRangeDraw& draw = **fDraws.head();
- state->gpu()->pathRendering()->drawPaths(args, draw.range(), draw.indices(),
+ state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), draw.indices(),
GrPathRange::kU16_PathIndexType, draw.transforms(), draw.transformType(),
draw.count());
return;
}
- const GrPathRange* range = (*fDraws.head())->range();
GrPathRendering::PathTransformType transformType = (*fDraws.head())->transformType();
int floatsPerTransform = GrPathRendering::PathTransformSize(transformType);
SkAutoSTMalloc<512, float> transformStorage(floatsPerTransform * fTotalPathCount);
@@ -131,7 +134,6 @@
float* transforms = transformStorage.get();
for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
SkASSERT((*iter.get())->transformType() == transformType);
- SkASSERT((*iter.get())->range() == range);
int cnt = (*iter.get())->count();
memcpy(indices, (*iter.get())->indices(), cnt * sizeof(uint16_t));
indices += cnt;
@@ -139,7 +141,7 @@
transforms += cnt * floatsPerTransform;
}
SkASSERT(indices - indexStorage.get() == fTotalPathCount);
- state->gpu()->pathRendering()->drawPaths(args, range, indexStorage.get(),
+ state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), indexStorage.get(),
GrPathRange::kU16_PathIndexType, transformStorage.get(), transformType,
fTotalPathCount);
}
diff --git a/src/gpu/batches/GrDrawPathBatch.h b/src/gpu/batches/GrDrawPathBatch.h
index 91e0e41..d6d0711 100644
--- a/src/gpu/batches/GrDrawPathBatch.h
+++ b/src/gpu/batches/GrDrawPathBatch.h
@@ -95,9 +95,8 @@
public:
typedef GrPathRendering::PathTransformType TransformType;
- static GrPathRangeDraw* Create(GrPathRange* range, TransformType transformType,
- int reserveCnt) {
- return new GrPathRangeDraw(range, transformType, reserveCnt);
+ static GrPathRangeDraw* Create(TransformType transformType, int reserveCnt) {
+ return new GrPathRangeDraw(transformType, reserveCnt);
}
void append(uint16_t index, float transform[]) {
@@ -113,20 +112,13 @@
const uint16_t* indices() const { return fIndices.begin(); }
- const GrPathRange* range() const { return fPathRange.get(); }
-
- void loadGlyphPathsIfNeeded() {
- fPathRange.get()->loadPathsIfNeeded<uint16_t>(fIndices.begin(), fIndices.count());
- }
-
static bool CanMerge(const GrPathRangeDraw& a, const GrPathRangeDraw& b) {
- return a.transformType() == b.transformType() && a.range() == b.range();
+ return a.transformType() == b.transformType();
}
private:
- GrPathRangeDraw(GrPathRange* range, TransformType transformType, int reserveCnt)
- : fPathRange(range)
- , fTransformType(transformType)
+ GrPathRangeDraw(TransformType transformType, int reserveCnt)
+ : fTransformType(transformType)
, fIndices(reserveCnt)
, fTransforms(reserveCnt * GrPathRendering::PathTransformSize(transformType)) {
SkDEBUGCODE(fUsedInBatch = false;)
@@ -136,7 +128,6 @@
static const int kIndexReserveCnt = 64;
static const int kTransformBufferReserveCnt = 2 * 64;
- GrPendingIOResource<const GrPathRange, kRead_GrIOType> fPathRange;
GrPathRendering::PathTransformType fTransformType;
SkSTArray<kIndexReserveCnt, uint16_t, true> fIndices;
SkSTArray<kTransformBufferReserveCnt, float, true> fTransforms;
@@ -157,8 +148,8 @@
// This can't return a more abstract type because we install the stencil settings late :(
static GrDrawPathBatchBase* Create(const SkMatrix& viewMatrix, const SkMatrix& localMatrix,
- GrColor color, GrPathRangeDraw* pathRangeDraw) {
- return new GrDrawPathRangeBatch(viewMatrix, localMatrix, color, pathRangeDraw);
+ GrColor color, GrPathRange* range, GrPathRangeDraw* draw) {
+ return new GrDrawPathRangeBatch(viewMatrix, localMatrix, color, range, draw);
}
~GrDrawPathRangeBatch() override;
@@ -171,7 +162,7 @@
inline bool isWinding() const;
GrDrawPathRangeBatch(const SkMatrix& viewMatrix, const SkMatrix& localMatrix, GrColor color,
- GrPathRangeDraw* pathRangeDraw);
+ GrPathRange* range, GrPathRangeDraw* draw);
bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override;
@@ -179,10 +170,12 @@
void onDraw(GrBatchFlushState* state) override;
+ typedef GrPendingIOResource<const GrPathRange, kRead_GrIOType> PendingPathRange;
typedef SkTLList<GrPathRangeDraw*> DrawList;
- DrawList fDraws;
- int fTotalPathCount;
- SkMatrix fLocalMatrix;
+ PendingPathRange fPathRange;
+ DrawList fDraws;
+ int fTotalPathCount;
+ SkMatrix fLocalMatrix;
typedef GrDrawPathBatchBase INHERITED;
};