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

Unified Diff: src/gpu/GrStencilAndCoverTextContext.cpp

Issue 563283004: Use per-typeface sets of glyphs for nvpr text (Closed) Base URL: https://skia.googlesource.com/skia.git@upload_glyphmemorypath
Patch Set: Fix builds Created 6 years, 3 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/GrStencilAndCoverTextContext.h ('k') | src/gpu/gl/GrGLPath.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/GrStencilAndCoverTextContext.cpp
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index f6ce261ab7a7235ad8a298a8e238fc6904a875cc..c1d9e9d32d8b8a9eff2ee1ded132f7a74eafa81d 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -17,97 +17,11 @@
#include "SkGpuDevice.h"
#include "SkPath.h"
#include "SkTextMapStateProc.h"
-
-class GrStencilAndCoverTextContext::GlyphPathRange : public GrGpuResource {
- static const int kMaxGlyphCount = 1 << 16; // Glyph IDs are uint16_t's
- static const int kGlyphGroupSize = 16; // Glyphs get tracked in groups of 16
-
-public:
- static GlyphPathRange* Create(GrContext* context,
- SkGlyphCache* cache,
- const SkStrokeRec& stroke) {
- static const GrCacheID::Domain gGlyphPathRangeDomain = GrCacheID::GenerateDomain();
-
- GrCacheID::Key key;
- key.fData32[0] = cache->getDescriptor().getChecksum();
- key.fData32[1] = cache->getScalerContext()->getTypeface()->uniqueID();
- key.fData64[1] = GrPath::ComputeStrokeKey(stroke);
-
- GrResourceKey resourceKey(GrCacheID(gGlyphPathRangeDomain, key),
- GrPathRange::resourceType(), 0);
- SkAutoTUnref<GlyphPathRange> glyphs(
- static_cast<GlyphPathRange*>(context->findAndRefCachedResource(resourceKey)));
-
- if (NULL == glyphs ||
- !glyphs->fDesc->equals(cache->getDescriptor() /*checksum collision*/)) {
- glyphs.reset(SkNEW_ARGS(GlyphPathRange, (context, cache->getDescriptor(), stroke)));
- glyphs->registerWithCache();
- context->addResourceToCache(resourceKey, glyphs);
- }
-
- return glyphs.detach();
- }
-
- const GrPathRange* pathRange() const { return fPathRange.get(); }
-
- void preloadGlyph(uint16_t glyphID, SkGlyphCache* cache) {
- const uint16_t groupIndex = glyphID / kGlyphGroupSize;
- const uint16_t groupByte = groupIndex >> 3;
- const uint8_t groupBit = 1 << (groupIndex & 7);
-
- const bool hasGlyph = 0 != (fLoadedGlyphs[groupByte] & groupBit);
- if (hasGlyph) {
- return;
- }
-
- // We track which glyphs are loaded in groups of kGlyphGroupSize. To
- // mark a glyph loaded we need to load the entire group.
- const uint16_t groupFirstID = groupIndex * kGlyphGroupSize;
- const uint16_t groupLastID = groupFirstID + kGlyphGroupSize - 1;
- SkPath skPath;
- for (int id = groupFirstID; id <= groupLastID; ++id) {
- const SkGlyph& skGlyph = cache->getGlyphIDMetrics(id);
- if (const SkPath* skPath = cache->findPath(skGlyph)) {
- fPathRange->initAt(id, *skPath);
- } // GrGpu::drawPaths will silently ignore undefined paths.
- }
-
- fLoadedGlyphs[groupByte] |= groupBit;
- this->didChangeGpuMemorySize();
- }
-
- // GrGpuResource overrides
- virtual size_t gpuMemorySize() const SK_OVERRIDE { return fPathRange->gpuMemorySize(); }
-
-private:
- GlyphPathRange(GrContext* context, const SkDescriptor& desc, const SkStrokeRec& stroke)
- : INHERITED(context->getGpu(), false)
- , fDesc(desc.copy())
- // We reserve a range of kMaxGlyphCount paths because of fallbacks fonts. We
- // can't know exactly how many glyphs we might need without preloading every
- // fallback, which we don't want to do at this point.
- , fPathRange(context->getGpu()->pathRendering()->createPathRange(kMaxGlyphCount, stroke)) {
- memset(fLoadedGlyphs, 0, sizeof(fLoadedGlyphs));
- }
-
- ~GlyphPathRange() {
- this->release();
- SkDescriptor::Free(fDesc);
- }
-
- static const int kMaxGroupCount = (kMaxGlyphCount + (kGlyphGroupSize - 1)) / kGlyphGroupSize;
- SkDescriptor* const fDesc;
- uint8_t fLoadedGlyphs[(kMaxGroupCount + 7) >> 3]; // One bit per glyph group
- SkAutoTUnref<GrPathRange> fPathRange;
-
- typedef GrGpuResource INHERITED;
-};
-
+#include "SkTextFormatParams.h"
GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(
GrContext* context, const SkDeviceProperties& properties)
: GrTextContext(context, properties)
- , fStroke(SkStrokeRec::kFill_InitStyle)
, fPendingGlyphCount(0) {
}
@@ -140,22 +54,18 @@ void GrStencilAndCoverTextContext::drawText(const GrPaint& paint,
// will turn off the use of device-space glyphs when perspective transforms
// are in use.
- this->init(paint, skPaint, byteLength, kUseIfNeeded_DeviceSpaceGlyphsBehavior);
+ this->init(paint, skPaint, byteLength, kMaxAccuracy_RenderMode);
- SkMatrix* glyphCacheTransform = NULL;
// Transform our starting point.
if (fNeedsDeviceSpaceGlyphs) {
SkPoint loc;
fContextInitialMatrix.mapXY(x, y, &loc);
x = loc.fX;
y = loc.fY;
- glyphCacheTransform = &fContextInitialMatrix;
}
SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
- SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, glyphCacheTransform);
- fGlyphCache = autoCache.getCache();
- fGlyphs = GlyphPathRange::Create(fContext, fGlyphCache, fStroke);
+
fTransformType = GrPathRendering::kTranslate_PathTransformType;
const char* stop = text + byteLength;
@@ -232,14 +142,10 @@ void GrStencilAndCoverTextContext::drawPosText(const GrPaint& paint,
// same glyphs as what were measured.
const float textTranslateY = (1 == scalarsPerPosition ? constY : 0);
- this->init(paint, skPaint, byteLength, kDoNotUse_DeviceSpaceGlyphsBehavior, textTranslateY);
+ this->init(paint, skPaint, byteLength, kMaxPerformance_RenderMode, textTranslateY);
SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
- SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, NULL);
- fGlyphCache = autoCache.getCache();
- fGlyphs = GlyphPathRange::Create(fContext, fGlyphCache, fStroke);
-
const char* stop = text + byteLength;
if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
@@ -308,76 +214,145 @@ bool GrStencilAndCoverTextContext::canDraw(const SkPaint& paint) {
return rec.getFormat() != SkMask::kARGB32_Format;
}
+static GrPathRange* get_gr_glyphs(GrContext* ctx,
+ const SkTypeface* typeface,
+ const SkDescriptor* desc,
+ const SkStrokeRec& stroke) {
+ static const GrCacheID::Domain gGlyphsDomain = GrCacheID::GenerateDomain();
+
+ GrCacheID::Key key;
+ uint64_t* keyData = key.fData64;
+ keyData[0] = desc ? desc->getChecksum() : 0;
+ keyData[0] = (keyData[0] << 32) | (typeface ? typeface->uniqueID() : 0);
+ keyData[1] = GrPath::ComputeStrokeKey(stroke);
+ GrResourceKey resourceKey = GrResourceKey(GrCacheID(gGlyphsDomain, key),
+ GrPathRange::resourceType(), 0);
+
+ SkAutoTUnref<GrPathRange> glyphs(
+ static_cast<GrPathRange*>(ctx->findAndRefCachedResource(resourceKey)));
+ if (NULL == glyphs || (NULL != desc && !glyphs->isEqualTo(*desc))) {
+ glyphs.reset(ctx->getGpu()->pathRendering()->createGlyphs(typeface, desc, stroke));
+ ctx->addResourceToCache(resourceKey, glyphs);
+ }
+
+ return glyphs.detach();
+}
+
void GrStencilAndCoverTextContext::init(const GrPaint& paint,
const SkPaint& skPaint,
size_t textByteLength,
- DeviceSpaceGlyphsBehavior deviceSpaceGlyphsBehavior,
+ RenderMode renderMode,
SkScalar textTranslateY) {
GrTextContext::init(paint, skPaint);
fContextInitialMatrix = fContext->getMatrix();
- bool otherBackendsWillDrawAsPaths =
+ const bool otherBackendsWillDrawAsPaths =
SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix);
- if (otherBackendsWillDrawAsPaths) {
- // This is to reproduce SkDraw::drawText_asPaths glyph positions.
- fSkPaint.setLinearText(true);
- fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
- fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize();
- fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
- if (fSkPaint.getStyle() != SkPaint::kFill_Style) {
- // Compensate the glyphs being scaled up by fTextRatio by scaling the
- // stroke down.
- fSkPaint.setStrokeWidth(fSkPaint.getStrokeWidth() / fTextRatio);
- }
- fNeedsDeviceSpaceGlyphs = false;
- } else {
- fTextRatio = fTextInverseRatio = 1.0f;
- fNeedsDeviceSpaceGlyphs =
- kUseIfNeeded_DeviceSpaceGlyphsBehavior == deviceSpaceGlyphsBehavior &&
- (fContextInitialMatrix.getType() &
- (SkMatrix::kScale_Mask | SkMatrix::kAffine_Mask)) != 0;
+ fNeedsDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths &&
+ kMaxAccuracy_RenderMode == renderMode &&
+ SkToBool(fContextInitialMatrix.getType() &
+ (SkMatrix::kScale_Mask | SkMatrix::kAffine_Mask));
+
+ if (fNeedsDeviceSpaceGlyphs) {
// SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms.
SkASSERT(!fContextInitialMatrix.hasPerspective());
- }
+ SkASSERT(0 == textTranslateY); // TODO: Handle textTranslateY in device-space usecase.
- fStroke = SkStrokeRec(fSkPaint);
+ fTextRatio = fTextInverseRatio = 1.0f;
- if (fNeedsDeviceSpaceGlyphs) {
- SkASSERT(1.0f == fTextRatio);
- SkASSERT(0.0f == textTranslateY);
- fPaint.localCoordChangeInverse(fContextInitialMatrix);
- fContext->setIdentityMatrix();
-
- // The whole shape is baked into the glyph. Make NVPR just fill the
- // baked shape.
- fStroke.setStrokeStyle(-1, false);
+ // Glyphs loaded by GPU path rendering have an inverted y-direction.
+ SkMatrix m;
+ m.setScale(1, -1);
+ fContext->setMatrix(m);
+
+ // Post-flip the initial matrix so we're left with just the flip after
+ // the paint preConcats the inverse.
+ m = fContextInitialMatrix;
+ m.postScale(1, -1);
+ fPaint.localCoordChangeInverse(m);
+
+ // The whole shape (including stroke) will be baked into the glyph outlines. Make
+ // NVPR just fill the baked shapes.
+ fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, &fContextInitialMatrix, false);
+ fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
+ &fGlyphCache->getDescriptor(),
+ SkStrokeRec(SkStrokeRec::kFill_InitStyle));
} else {
- if (1.0f != fTextRatio || 0.0f != textTranslateY) {
- SkMatrix textMatrix;
- textMatrix.setTranslate(0, textTranslateY);
- textMatrix.preScale(fTextRatio, fTextRatio);
- fPaint.localCoordChange(textMatrix);
- fContext->concatMatrix(textMatrix);
+ // Don't bake strokes into the glyph outlines. We will stroke the glyphs
+ // using the GPU instead. This is the fast path.
+ SkStrokeRec gpuStroke = SkStrokeRec(fSkPaint);
+ fSkPaint.setStyle(SkPaint::kFill_Style);
+
+ if (gpuStroke.isHairlineStyle()) {
+ // Approximate hairline stroke.
+ SkScalar strokeWidth = SK_Scalar1 /
+ (SkVector::Make(fContextInitialMatrix.getScaleX(),
+ fContextInitialMatrix.getSkewY()).length());
+ gpuStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/);
+
+ } else if (fSkPaint.isFakeBoldText() &&
+#ifdef SK_USE_FREETYPE_EMBOLDEN
+ kMaxPerformance_RenderMode == renderMode &&
+#endif
+ SkStrokeRec::kStroke_Style != gpuStroke.getStyle()) {
+
+ // Instead of baking fake bold into the glyph outlines, do it with the GPU stroke.
+ SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(),
+ kStdFakeBoldInterpKeys,
+ kStdFakeBoldInterpValues,
+ kStdFakeBoldInterpLength);
+ SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale);
+ gpuStroke.setStrokeStyle(gpuStroke.needToApply() ? gpuStroke.getWidth() + extra : extra,
+ true /*strokeAndFill*/);
+
+ fSkPaint.setFakeBoldText(false);
}
- if (fSkPaint.getStrokeWidth() == 0.0f) {
- if (fSkPaint.getStyle() == SkPaint::kStrokeAndFill_Style) {
- fStroke.setStrokeStyle(-1, false);
- } else if (fSkPaint.getStyle() == SkPaint::kStroke_Style) {
- // Approximate hairline stroke.
- const SkMatrix& ctm = fContext->getMatrix();
- SkScalar strokeWidth = SK_Scalar1 /
- (SkVector::Make(ctm.getScaleX(), ctm.getSkewY()).length());
- fStroke.setStrokeStyle(strokeWidth, false);
+ bool canUseRawPaths;
+
+ if (otherBackendsWillDrawAsPaths || kMaxPerformance_RenderMode == renderMode) {
+ // We can draw the glyphs from canonically sized paths.
+ fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
+ fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize();
+
+ // Compensate for the glyphs being scaled by fTextRatio.
+ if (!gpuStroke.isFillStyle()) {
+ gpuStroke.setStrokeStyle(gpuStroke.getWidth() / fTextRatio,
+ SkStrokeRec::kStrokeAndFill_Style == gpuStroke.getStyle());
}
+
+ fSkPaint.setLinearText(true);
+ fSkPaint.setLCDRenderText(false);
+ fSkPaint.setAutohinted(false);
+ fSkPaint.setHinting(SkPaint::kNo_Hinting);
+ fSkPaint.setSubpixelText(true);
+ fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
+
+ canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() &&
+ 0 == fSkPaint.getTextSkewX() &&
+ !fSkPaint.isFakeBoldText() &&
+ !fSkPaint.isVerticalText();
+ } else {
+ fTextRatio = fTextInverseRatio = 1.0f;
+ canUseRawPaths = false;
}
- // Make glyph cache produce paths geometry for fill. We will stroke them
- // by passing fStroke to drawPath. This is the fast path.
- fSkPaint.setStyle(SkPaint::kFill_Style);
+ SkMatrix textMatrix;
+ textMatrix.setTranslate(0, textTranslateY);
+ // Glyphs loaded by GPU path rendering have an inverted y-direction.
+ textMatrix.preScale(fTextRatio, -fTextRatio);
+ fPaint.localCoordChange(textMatrix);
+ fContext->concatMatrix(textMatrix);
+
+ fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, NULL, false);
+ fGlyphs = canUseRawPaths ?
+ get_gr_glyphs(fContext, fSkPaint.getTypeface(), NULL, gpuStroke) :
+ get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
+ &fGlyphCache->getDescriptor(), gpuStroke);
}
+
fStateRestore.set(fDrawTarget->drawState());
fDrawTarget->drawState()->setFromPaint(fPaint, fContext->getMatrix(),
@@ -403,8 +378,6 @@ inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x)
this->flush();
}
- fGlyphs->preloadGlyph(glyphID, fGlyphCache);
-
fIndexBuffer[fPendingGlyphCount] = glyphID;
fTransformBuffer[fPendingGlyphCount] = fTextInverseRatio * x;
@@ -418,11 +391,9 @@ inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x,
this->flush();
}
- fGlyphs->preloadGlyph(glyphID, fGlyphCache);
-
fIndexBuffer[fPendingGlyphCount] = glyphID;
fTransformBuffer[2 * fPendingGlyphCount] = fTextInverseRatio * x;
- fTransformBuffer[2 * fPendingGlyphCount + 1] = fTextInverseRatio * y;
+ fTransformBuffer[2 * fPendingGlyphCount + 1] = -fTextInverseRatio * y;
++fPendingGlyphCount;
}
@@ -432,7 +403,7 @@ void GrStencilAndCoverTextContext::flush() {
return;
}
- fDrawTarget->drawPaths(fGlyphs->pathRange(), fIndexBuffer, fPendingGlyphCount,
+ fDrawTarget->drawPaths(fGlyphs, fIndexBuffer, fPendingGlyphCount,
fTransformBuffer, fTransformType, SkPath::kWinding_FillType);
fPendingGlyphCount = 0;
@@ -441,8 +412,10 @@ void GrStencilAndCoverTextContext::flush() {
void GrStencilAndCoverTextContext::finish() {
this->flush();
- SkSafeUnref(fGlyphs);
+ fGlyphs->unref();
fGlyphs = NULL;
+
+ SkGlyphCache::AttachCache(fGlyphCache);
fGlyphCache = NULL;
fDrawTarget->drawState()->stencil()->setDisabled();
« no previous file with comments | « src/gpu/GrStencilAndCoverTextContext.h ('k') | src/gpu/gl/GrGLPath.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698