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:
parent
bf90520f63
commit
8585dd26bf
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user