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
This commit is contained in:
cdalton 2015-10-08 08:04:09 -07:00 committed by Commit bot
parent bf90520f63
commit 8585dd26bf
10 changed files with 177 additions and 141 deletions

View File

@ -18,6 +18,7 @@ class GrDrawBatch;
class GrDrawTarget;
class GrPaint;
class GrPathProcessor;
class GrPathRange;
class GrPathRangeDraw;
class GrPipelineBuilder;
class GrRenderTarget;
@ -67,6 +68,7 @@ public:
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
GrColor color,
GrPathRange* range,
GrPathRangeDraw* draw,
int /*GrPathRendering::FillType*/ fill);

View File

@ -111,11 +111,12 @@ void GrDrawContext::drawPathsFromRange(const GrPipelineBuilder* pipelineBuilder,
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);
}

View File

@ -255,9 +255,11 @@ void GrDrawTarget::drawPathsFromRange(const GrPipelineBuilder& pipelineBuilder,
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();
}

View File

@ -92,7 +92,7 @@ public:
*
* 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 @@ public:
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
GrColor color,
GrPathRange* range,
GrPathRangeDraw* draw,
GrPathRendering::FillType fill);

View File

@ -8,7 +8,6 @@
#include "GrPathRange.h"
#include "SkPath.h"
GrPathRange::GrPathRange(GrGpu* gpu,
PathGenerator* pathGenerator)
: INHERITED(gpu, kCached_LifeCycle),
@ -27,10 +26,14 @@ GrPathRange::GrPathRange(GrGpu* gpu,
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::loadPathsIfNeeded(const void* indices, PathIndexType indexType
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");
}
}

View File

@ -72,18 +72,17 @@ public:
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 @@ public:
#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);

View File

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

View File

@ -17,7 +17,6 @@
class GrTextStrike;
class GrPath;
class GrPathRange;
class SkSurfaceProps;
/*
@ -60,22 +59,22 @@ private:
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 @@ private:
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 @@ private:
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 @@ private:
SkTHashMap<uint32_t, TextBlob*> fBlobIdCache;
SkTHashTable<TextBlob*, const TextBlob::Key&, TextBlob> fBlobKeyCache;
SkTInternalLList<TextBlob> fLRUList;
int fCacheSize;
size_t fCacheSize;
typedef GrTextContext INHERITED;
};

View File

@ -56,13 +56,14 @@ bool GrDrawPathRangeBatch::isWinding() const {
}
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 @@ GrDrawPathRangeBatch::GrDrawPathRangeBatch(const SkMatrix& viewMatrix, const SkM
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 @@ void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) {
&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 @@ void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) {
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 @@ void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) {
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);
}

View File

@ -95,9 +95,8 @@ class GrPathRangeDraw : public GrNonAtomicRef {
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 @@ public:
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 @@ private:
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 @@ public:
// 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 @@ private:
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 @@ private:
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;
};