Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(266)

Unified Diff: src/gpu/GrAtlasTextContext.cpp

Issue 1062863002: Avoid regenerating cached textblobs on integer scrolls (Closed) Base URL: https://skia.googlesource.com/skia.git@atlastextcache
Patch Set: some sleight bug fixes Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/gpu/GrAtlasTextContext.h ('k') | src/gpu/GrContext.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/GrAtlasTextContext.cpp
diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp
index 0de5ee35822674b9f0e16244f12a1c0b2100894a..8ea5f16ec29c921778d2a09b54c4e5360ee4defa 100644
--- a/src/gpu/GrAtlasTextContext.cpp
+++ b/src/gpu/GrAtlasTextContext.cpp
@@ -15,6 +15,7 @@
#include "GrFontScaler.h"
#include "GrIndexBuffer.h"
#include "GrStrokeInfo.h"
+#include "GrTextBlobCache.h"
#include "GrTexturePriv.h"
#include "SkAutoKern.h"
@@ -66,17 +67,14 @@ static size_t get_vertex_stride(GrMaskFormat maskFormat) {
GrAtlasTextContext::GrAtlasTextContext(GrContext* context,
SkGpuDevice* gpuDevice,
- const SkDeviceProperties& properties)
+ const SkDeviceProperties& properties)
: INHERITED(context, gpuDevice, properties) {
+ // We overallocate vertices in our textblobs based on the assumption that A8 has the greatest
+ // vertexStride
+ SK_COMPILE_ASSERT(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >= kLCDTextVASize,
+ vertex_attribute_changed);
fCurrStrike = NULL;
-}
-
-GrAtlasTextContext::~GrAtlasTextContext() {/*
- SkTDynamicHash<BitmapTextBlob, uint32_t>::Iter iter(&fCache);
- while (!iter.done()) {
- (&(*iter))->unref();
- ++iter;
- }*/
+ fCache = context->getTextBlobCache();
}
GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context,
@@ -93,12 +91,57 @@ bool GrAtlasTextContext::canDraw(const GrRenderTarget*,
return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix);
}
-bool GrAtlasTextContext::MustRegenerateBlob(const BitmapTextBlob& blob, const SkPaint& paint,
+static const SkScalar kThreshold = 0.0625;
+
+bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY,
+ const BitmapTextBlob& blob, const SkPaint& paint,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
- // We always regenerate blobs with patheffects or mask filters we could cache these
- // TODO find some way to cache the maskfilter / patheffects on the textblob
- return !blob.fViewMatrix.cheapEqualTo(viewMatrix) || blob.fX != x || blob.fY != y ||
- paint.getMaskFilter() || paint.getPathEffect() || paint.getStyle() != blob.fStyle;
+ // Color can affect the mask
+ // TODO we can adjust the color within specific gamma slots
+ if (blob.fColor != paint.getColor()) {
+ return true;
+ }
+
+ if (blob.fViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) {
+ return true;
+ }
+
+ if (blob.fViewMatrix.hasPerspective() && !blob.fViewMatrix.cheapEqualTo(viewMatrix)) {
+ return true;
+ }
+
+ if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() ||
+ blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() ||
+ blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() ||
+ blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) {
+ return true;
+ }
+
+ // We can update the positions in the cachedtextblobs without regenerating the whole blob, but
+ // only for integer translations.
+ // TODO I think this is wrong
+ if (SkScalarFraction(blob.fViewMatrix.getTranslateX() -
+ viewMatrix.getTranslateX()) > kThreshold ||
+ SkScalarFraction(x - blob.fX) > kThreshold ||
+ SkScalarFraction(blob.fViewMatrix.getTranslateX() -
+ viewMatrix.getTranslateX()) > kThreshold ||
+ SkScalarFraction(y - blob.fY) > kThreshold) {
+ return true;
+ }
+
+ SkScalar transX = viewMatrix.getTranslateX() +
bsalomon 2015/04/08 15:42:59 Do we need to worry about presence/absence of subp
joshualitt 2015/04/08 15:52:28 Jim, thoughts? I don't really know enough about s
+ viewMatrix.getScaleX() * (x - blob.fX) +
+ viewMatrix.getSkewX() * (y - blob.fY) -
+ blob.fViewMatrix.getTranslateX();
+
+ SkScalar transY = viewMatrix.getTranslateY() +
+ viewMatrix.getSkewY() * (x - blob.fX) +
+ viewMatrix.getScaleY() * (y - blob.fY) -
+ blob.fViewMatrix.getTranslateY();
+
+ (*outTransX) = transX;
+ (*outTransY) = transY;
bsalomon 2015/04/08 15:43:00 why have intermediates?
joshualitt 2015/04/08 15:52:28 done
+ return false;
}
@@ -110,80 +153,52 @@ inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run,
return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc());
}
-inline void GrAtlasTextContext::BlobGlyphCount(int* glyphCount, int* runCount,
- const SkTextBlob* blob) {
- SkTextBlob::RunIterator itCounter(blob);
- for (; !itCounter.done(); itCounter.next(), (*runCount)++) {
- *glyphCount += itCounter.glyphCount();
- }
-}
-
-GrAtlasTextContext::BitmapTextBlob*
-GrAtlasTextContext::CreateBlob(int glyphCount, int runCount, GrMemoryPool* pool) {
- // We allocate size for the BitmapTextBlob itself, plus size for the vertices array,
- // and size for the glyphIds array.
- SK_COMPILE_ASSERT(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >= kLCDTextVASize,
- vertex_attribute_changed);
- size_t verticesCount = glyphCount * kVerticesPerGlyph * kGrayTextVASize;
- size_t size = sizeof(BitmapTextBlob) +
- verticesCount +
- glyphCount * sizeof(GrGlyph::PackedID) +
- sizeof(BitmapTextBlob::Run) * runCount;
-
- BitmapTextBlob* cacheBlob;
- cacheBlob = SkNEW_PLACEMENT(pool->allocate(size), BitmapTextBlob);
-
- // setup offsets for vertices / glyphs
- cacheBlob->fVertices = sizeof(BitmapTextBlob) + reinterpret_cast<unsigned char*>(cacheBlob);
- cacheBlob->fGlyphIDs =
- reinterpret_cast<GrGlyph::PackedID*>(cacheBlob->fVertices + verticesCount);
- cacheBlob->fRuns = reinterpret_cast<BitmapTextBlob::Run*>(cacheBlob->fGlyphIDs + glyphCount);
-
- // Initialize runs
- for (int i = 0; i < runCount; i++) {
- SkNEW_PLACEMENT(&cacheBlob->fRuns[i], BitmapTextBlob::Run);
- }
- cacheBlob->fRunCount = runCount;
- cacheBlob->fSize = size;
- cacheBlob->fPool = pool;
- return cacheBlob;
-}
-
void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip,
const SkPaint& skPaint, const SkMatrix& viewMatrix,
const SkTextBlob* blob, SkScalar x, SkScalar y,
- SkDrawFilter* drawFilter, const SkIRect& clipBounds) {/*
+ SkDrawFilter* drawFilter, const SkIRect& clipBounds) {
uint32_t uniqueID = blob->uniqueID();
- BitmapTextBlob* cacheBlob = fCache.find(uniqueID);
+ SkAutoTUnref<BitmapTextBlob> cacheBlob;
+ // TODO start caching these, mix bits into the key
+ bool mustNotCache = skPaint.getPathEffect() ||
+ skPaint.getMaskFilter() ||
+ skPaint.getColorFilter() ||
+ skPaint.getStyle() != SkPaint::kFill_Style ||
+ drawFilter;
+
+ if (!mustNotCache) {
+ cacheBlob.reset(SkSafeRef(fCache->find(uniqueID)));
+ }
+
SkIRect clipRect;
clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
+ SkScalar transX = 0.f;
+ SkScalar transY = 0.f;
+
if (cacheBlob) {
- if (MustRegenerateBlob(*cacheBlob, skPaint, viewMatrix, x, y)) {
+ if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, viewMatrix, x, y)) {
// We have to remake the blob because changes may invalidate our masks.
// TODO we could probably get away reuse most of the time if the pointer is unique,
// but we'd have to clear the subrun information
- fCache.remove(uniqueID);
- fBlobList.remove(cacheBlob);
- cacheBlob->unref();
- int glyphCount = 0;
- int runCount = 0;
- BlobGlyphCount(&glyphCount, &runCount, blob);
- cacheBlob = CreateBlob(glyphCount, runCount, fContext->getTextTarget()->pool());
- cacheBlob->fUniqueID = uniqueID;
- fCache.add(cacheBlob);
- fBlobList.addToHead(cacheBlob);
+ fCache->remove(cacheBlob);
+ cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, kGrayTextVASize)));
this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter,
clipRect);
+ } else {
+ // If we can reuse the blob, then make sure we update the blob's viewmatrix and x/y
+ // offsets to reflect the results of any translations we may apply in generateGeometry
+ cacheBlob->fViewMatrix = viewMatrix;
+ cacheBlob->fX = x;
+ cacheBlob->fY = y;
+ fCache->makeMRU(cacheBlob);
}
} else {
- int glyphCount = 0;
- int runCount = 0;
- BlobGlyphCount(&glyphCount, &runCount, blob);
- cacheBlob = CreateBlob(glyphCount, runCount, fContext->getTextTarget()->pool());
- cacheBlob->fUniqueID = uniqueID;
- fCache.add(cacheBlob);
- fBlobList.addToHead(cacheBlob);
+ if (mustNotCache) {
+ cacheBlob.reset(fCache->createBlob(blob, kGrayTextVASize));
+ } else {
+ cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, kGrayTextVASize)));
+ }
this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter, clipRect);
}
@@ -193,7 +208,7 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip,
SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint);
this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint, drawFilter,
- clip, viewMatrix, clipBounds, x, y);*/
+ clip, viewMatrix, clipBounds, x, y, transX, transY);
}
void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob,
@@ -203,6 +218,7 @@ void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob,
cacheBlob->fViewMatrix = viewMatrix;
cacheBlob->fX = x;
cacheBlob->fY = y;
+ cacheBlob->fColor = skPaint.getColor();
cacheBlob->fStyle = skPaint.getStyle();
// Regenerate textblob
@@ -238,7 +254,7 @@ void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob,
newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex;
}
- if (SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix)) {
+ if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) {
cacheBlob->fRuns[run].fDrawAsPaths = true;
continue;
}
@@ -277,7 +293,7 @@ void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip,
const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkIRect& regionClipBounds) {
int glyphCount = skPaint.countText(text, byteLength);
- SkAutoTUnref<BitmapTextBlob> blob(CreateBlob(glyphCount, 1, fContext->getTextTarget()->pool()));
+ SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTextVASize));
blob->fViewMatrix = viewMatrix;
blob->fX = x;
blob->fY = y;
@@ -391,7 +407,7 @@ void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkIRect& regionClipBounds) {
int glyphCount = skPaint.countText(text, byteLength);
- SkAutoTUnref<BitmapTextBlob> blob(CreateBlob(glyphCount, 1, fContext->getTextTarget()->pool()));
+ SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTextVASize));
blob->fStyle = skPaint.getStyle();
blob->fViewMatrix = viewMatrix;
@@ -589,11 +605,6 @@ void GrAtlasTextContext::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGlyph
int width = glyph->fBounds.width();
int height = glyph->fBounds.height();
- // check if we clipped out
- if (clipRect.quickReject(x, y, x + width, y + height)) {
- return;
- }
-
// If the glyph is too large we fall back to paths
if (fCurrStrike->glyphTooLargeForAtlas(glyph)) {
if (NULL == glyph->fPath) {
@@ -651,7 +662,6 @@ void GrAtlasTextContext::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGlyph
*colorPtr = color;
}
vertex += vertexStride;
-
// V1
position = reinterpret_cast<SkPoint*>(vertex);
position->set(r.fLeft, r.fBottom);
@@ -693,11 +703,15 @@ public:
: fBlob(SkRef(geometry.fBlob.get()))
, fRun(geometry.fRun)
, fSubRun(geometry.fSubRun)
- , fColor(geometry.fColor) {}
+ , fColor(geometry.fColor)
+ , fTransX(geometry.fTransX)
+ , fTransY(geometry.fTransY) {}
SkAutoTUnref<Blob> fBlob;
int fRun;
int fSubRun;
GrColor fColor;
+ SkScalar fTransX;
+ SkScalar fTransY;
};
static GrBatch* Create(const Geometry& geometry, GrMaskFormat maskFormat,
@@ -811,6 +825,7 @@ public:
uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat);
bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlasGen;
bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColor != args.fColor;
+ bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.f;
int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
// We regenerate both texture coords and colors in the blob itself, and update the
@@ -821,7 +836,7 @@ public:
// or coords as needed. One final note, if we have to break a run for an atlas eviction
// then we can't really trust the atlas has all of the correct data. Atlas evictions
// should be pretty rare, so we just always regenerate in those cases
- if (regenerateTextureCoords || regenerateColors) {
+ if (regenerateTextureCoords || regenerateColors || regeneratePositions) {
// first regenerate texture coordinates / colors if need be
const SkDescriptor* desc = NULL;
SkGlyphCache* cache = NULL;
@@ -875,9 +890,19 @@ public:
this->regenerateColors(vertex, vertexStride, args.fColor);
}
+ if (regeneratePositions) {
+ intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices);
+ vertex += info.fVertexStartIndex;
+ vertex += vertexStride * glyphIdx * kVerticesPerGlyph;
+ SkScalar transX = args.fTransX;
+ SkScalar transY = args.fTransY;
+ this->regeneratePositions(vertex, vertexStride, transX, transY);
+ }
instancesToFlush++;
}
+ // We my have changed the color so update it here
+ run.fColor = args.fColor;
if (regenerateTextureCoords) {
SkGlyphCache::AttachCache(cache);
info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAtlasGeneration :
@@ -957,6 +982,16 @@ private:
}
}
+ void regeneratePositions(intptr_t vertex, size_t vertexStride, SkScalar transX,
+ SkScalar transY) {
+ for (int i = 0; i < kVerticesPerGlyph; i++) {
+ SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
+ point->fX += transX;
+ point->fY += transY;
+ vertex += vertexStride;
+ }
+ }
+
void initDraw(GrBatchTarget* batchTarget,
const GrGeometryProcessor* gp,
const GrPipeline* pipeline) {
@@ -1063,7 +1098,7 @@ void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, cons
inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder* pipelineBuilder,
BitmapTextBlob* cacheBlob, int run, GrColor color,
- uint8_t paintAlpha) {
+ uint8_t paintAlpha, SkScalar transX, SkScalar transY) {
for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); subRun++) {
const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun];
int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
@@ -1081,6 +1116,8 @@ inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder
geometry.fRun = run;
geometry.fSubRun = subRun;
geometry.fColor = subRunColor;
+ geometry.fTransX = transX;
+ geometry.fTransY = transY;
SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, format, glyphCount,
fContext->getBatchFontCache()));
@@ -1089,11 +1126,15 @@ inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder
}
inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget* rt,
- const GrPaint& grPaint, const GrClip& clip) {
+ const GrPaint& grPaint, const GrClip& clip,
+ SkScalar transX, SkScalar transY) {
for (int i = 0; i < cacheBlob->fBigGlyphs.count(); i++) {
- const BitmapTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i];
+ BitmapTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i];
+ bigGlyph.fVx += transX;
+ bigGlyph.fVy += transY;
SkMatrix translate;
- translate.setTranslate(SkIntToScalar(bigGlyph.fVx), SkIntToScalar(bigGlyph.fVy));
+ translate.setTranslate(SkIntToScalar(bigGlyph.fVx),
+ SkIntToScalar(bigGlyph.fVy));
SkPath tmpPath(bigGlyph.fPath);
tmpPath.transform(translate);
GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
@@ -1111,8 +1152,8 @@ void GrAtlasTextContext::flush(GrDrawTarget* target,
const GrClip& clip,
const SkMatrix& viewMatrix,
const SkIRect& clipBounds,
- SkScalar x,
- SkScalar y) {
+ SkScalar x, SkScalar y,
+ SkScalar transX, SkScalar transY) {
// We loop through the runs of the blob, flushing each. If any run is too large, then we flush
// it as paths
GrPipelineBuilder pipelineBuilder;
@@ -1127,11 +1168,12 @@ void GrAtlasTextContext::flush(GrDrawTarget* target,
this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBounds, x, y);
continue;
}
- this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlpha);
+ cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY);
+ this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlpha, transX, transY);
}
// Now flush big glyphs
- this->flushBigGlyphs(cacheBlob, rt, grPaint, clip);
+ this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, transX, transY);
}
void GrAtlasTextContext::flush(GrDrawTarget* target,
@@ -1147,9 +1189,9 @@ void GrAtlasTextContext::flush(GrDrawTarget* target,
GrColor color = grPaint.getColor();
uint8_t paintAlpha = skPaint.getAlpha();
for (int run = 0; run < cacheBlob->fRunCount; run++) {
- this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlpha);
+ this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlpha, 0, 0);
}
// Now flush big glyphs
- this->flushBigGlyphs(cacheBlob, rt, grPaint, clip);
+ this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0);
}
« no previous file with comments | « src/gpu/GrAtlasTextContext.h ('k') | src/gpu/GrContext.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698