rename BitmapTextBlob and move it to its own file
BUG=skia: Review URL: https://codereview.chromium.org/1249663002
This commit is contained in:
parent
4ec1ac6a2d
commit
374b2f7cea
@ -72,6 +72,7 @@
|
||||
'<(skia_src_path)/gpu/GrAllocator.h',
|
||||
'<(skia_src_path)/gpu/GrAtlas.cpp',
|
||||
'<(skia_src_path)/gpu/GrAtlas.h',
|
||||
'<(skia_src_path)/gpu/GrAtlasTextBlob.h',
|
||||
'<(skia_src_path)/gpu/GrAtlasTextContext.cpp',
|
||||
'<(skia_src_path)/gpu/GrAtlasTextContext.h',
|
||||
'<(skia_src_path)/gpu/GrBatch.cpp',
|
||||
|
216
src/gpu/GrAtlasTextBlob.h
Normal file
216
src/gpu/GrAtlasTextBlob.h
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrAtlasTextBlob_DEFINED
|
||||
#define GrAtlasTextBlob_DEFINED
|
||||
|
||||
#include "GrBatchAtlas.h"
|
||||
#include "GrBatchFontCache.h"
|
||||
#include "SkDescriptor.h"
|
||||
#include "SkMaskFilter.h"
|
||||
#include "GrMemoryPool.h"
|
||||
#include "SkTInternalLList.h"
|
||||
|
||||
/*
|
||||
* A GrAtlasTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
|
||||
* on the GPU. These are initially created with valid positions and colors, but invalid
|
||||
* texture coordinates. The GrAtlasTextBlob itself has a few Blob-wide properties, and also
|
||||
* consists of a number of runs. Runs inside a blob are flushed individually so they can be
|
||||
* reordered.
|
||||
*
|
||||
* The only thing(aside from a memcopy) required to flush a GrAtlasTextBlob is to ensure that
|
||||
* the GrAtlas will not evict anything the Blob needs.
|
||||
*
|
||||
* Note: This struct should really be named GrCachedAtasTextBlob, but that is too verbose.
|
||||
*/
|
||||
struct GrAtlasTextBlob : public SkRefCnt {
|
||||
SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrAtlasTextBlob);
|
||||
|
||||
/*
|
||||
* Each Run inside of the blob can have its texture coordinates regenerated if required.
|
||||
* To determine if regeneration is necessary, fAtlasGeneration is used. If there have been
|
||||
* any evictions inside of the atlas, then we will simply regenerate Runs. We could track
|
||||
* this at a more fine grained level, but its not clear if this is worth it, as evictions
|
||||
* should be fairly rare.
|
||||
*
|
||||
* One additional point, each run can contain glyphs with any of the three mask formats.
|
||||
* We call these SubRuns. Because a subrun must be a contiguous range, we have to create
|
||||
* a new subrun each time the mask format changes in a run. In theory, a run can have as
|
||||
* many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8. In
|
||||
* practice, the vast majority of runs have only a single subrun.
|
||||
*
|
||||
* Finally, for runs where the entire thing is too large for the GrAtlasTextContext to
|
||||
* handle, we have a bit to mark the run as flusahable via rendering as paths. It is worth
|
||||
* pointing. It would be a bit expensive to figure out ahead of time whether or not a run
|
||||
* can flush in this manner, so we always allocate vertices for the run, regardless of
|
||||
* whether or not it is too large. The benefit of this strategy is that we can always reuse
|
||||
* a blob allocation regardless of viewmatrix changes. We could store positions for these
|
||||
* glyphs. However, its not clear if this is a win because we'd still have to either go the
|
||||
* glyph cache to get the path at flush time, or hold onto the path in the cache, which
|
||||
* would greatly increase the memory of these cached items.
|
||||
*/
|
||||
struct Run {
|
||||
Run()
|
||||
: fColor(GrColor_ILLEGAL)
|
||||
, fInitialized(false)
|
||||
, fDrawAsPaths(false) {
|
||||
fVertexBounds.setLargestInverted();
|
||||
// To ensure we always have one subrun, we push back a fresh run here
|
||||
fSubRunInfo.push_back();
|
||||
}
|
||||
struct SubRunInfo {
|
||||
SubRunInfo()
|
||||
: fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration)
|
||||
, fVertexStartIndex(0)
|
||||
, fVertexEndIndex(0)
|
||||
, fGlyphStartIndex(0)
|
||||
, fGlyphEndIndex(0)
|
||||
, fDrawAsDistanceFields(false) {}
|
||||
// Distance field text cannot draw coloremoji, and so has to fall back. However,
|
||||
// though the distance field text and the coloremoji may share the same run, they
|
||||
// will have different descriptors. If fOverrideDescriptor is non-NULL, then it
|
||||
// will be used in place of the run's descriptor to regen texture coords
|
||||
// TODO we could have a descriptor cache, it would reduce the size of these blobs
|
||||
// significantly, and then the subrun could just have a refed pointer to the
|
||||
// correct descriptor.
|
||||
GrBatchAtlas::BulkUseTokenUpdater fBulkUseToken;
|
||||
uint64_t fAtlasGeneration;
|
||||
size_t fVertexStartIndex;
|
||||
size_t fVertexEndIndex;
|
||||
uint32_t fGlyphStartIndex;
|
||||
uint32_t fGlyphEndIndex;
|
||||
SkScalar fTextRatio; // df property
|
||||
GrMaskFormat fMaskFormat;
|
||||
bool fDrawAsDistanceFields; // df property
|
||||
bool fUseLCDText; // df property
|
||||
};
|
||||
|
||||
SubRunInfo& push_back() {
|
||||
// Forward glyph / vertex information to seed the new sub run
|
||||
SubRunInfo& prevSubRun = fSubRunInfo.back();
|
||||
SubRunInfo& newSubRun = fSubRunInfo.push_back();
|
||||
newSubRun.fGlyphStartIndex = prevSubRun.fGlyphEndIndex;
|
||||
newSubRun.fGlyphEndIndex = prevSubRun.fGlyphEndIndex;
|
||||
|
||||
newSubRun.fVertexStartIndex = prevSubRun.fVertexEndIndex;
|
||||
newSubRun.fVertexEndIndex = prevSubRun.fVertexEndIndex;
|
||||
return newSubRun;
|
||||
}
|
||||
static const int kMinSubRuns = 1;
|
||||
SkAutoTUnref<GrBatchTextStrike> fStrike;
|
||||
SkAutoTUnref<SkTypeface> fTypeface;
|
||||
SkRect fVertexBounds;
|
||||
SkSTArray<kMinSubRuns, SubRunInfo> fSubRunInfo;
|
||||
SkAutoDescriptor fDescriptor;
|
||||
SkAutoTDelete<SkAutoDescriptor> fOverrideDescriptor; // df properties
|
||||
GrColor fColor;
|
||||
bool fInitialized;
|
||||
bool fDrawAsPaths;
|
||||
};
|
||||
|
||||
struct BigGlyph {
|
||||
BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy)
|
||||
: fPath(path)
|
||||
, fVx(vx)
|
||||
, fVy(vy) {}
|
||||
SkPath fPath;
|
||||
SkScalar fVx;
|
||||
SkScalar fVy;
|
||||
};
|
||||
|
||||
struct Key {
|
||||
Key() {
|
||||
sk_bzero(this, sizeof(Key));
|
||||
}
|
||||
uint32_t fUniqueID;
|
||||
// Color may affect the gamma of the mask we generate, but in a fairly limited way.
|
||||
// Each color is assigned to on of a fixed number of buckets based on its
|
||||
// luminance. For each luminance bucket there is a "canonical color" that
|
||||
// represents the bucket. This functionality is currently only supported for A8
|
||||
SkColor fCanonicalColor;
|
||||
SkPaint::Style fStyle;
|
||||
SkPixelGeometry fPixelGeometry;
|
||||
bool fHasBlur;
|
||||
|
||||
bool operator==(const Key& other) const {
|
||||
return 0 == memcmp(this, &other, sizeof(Key));
|
||||
}
|
||||
};
|
||||
|
||||
struct StrokeInfo {
|
||||
SkScalar fFrameWidth;
|
||||
SkScalar fMiterLimit;
|
||||
SkPaint::Join fJoin;
|
||||
};
|
||||
|
||||
enum TextType {
|
||||
kHasDistanceField_TextType = 0x1,
|
||||
kHasBitmap_TextType = 0x2,
|
||||
};
|
||||
|
||||
// all glyph / vertex offsets are into these pools.
|
||||
unsigned char* fVertices;
|
||||
GrGlyph** fGlyphs;
|
||||
Run* fRuns;
|
||||
GrMemoryPool* fPool;
|
||||
SkMaskFilter::BlurRec fBlurRec;
|
||||
StrokeInfo fStrokeInfo;
|
||||
SkTArray<BigGlyph> fBigGlyphs;
|
||||
Key fKey;
|
||||
SkMatrix fViewMatrix;
|
||||
SkColor fPaintColor;
|
||||
SkScalar fX;
|
||||
SkScalar fY;
|
||||
|
||||
// We can reuse distance field text, but only if the new viewmatrix would not result in
|
||||
// a mip change. Because there can be multiple runs in a blob, we track the overall
|
||||
// maximum minimum scale, and minimum maximum scale, we can support before we need to regen
|
||||
SkScalar fMaxMinScale;
|
||||
SkScalar fMinMaxScale;
|
||||
int fRunCount;
|
||||
uint8_t fTextType;
|
||||
|
||||
GrAtlasTextBlob()
|
||||
: fMaxMinScale(-SK_ScalarMax)
|
||||
, fMinMaxScale(SK_ScalarMax)
|
||||
, fTextType(0) {}
|
||||
|
||||
~GrAtlasTextBlob() override {
|
||||
for (int i = 0; i < fRunCount; i++) {
|
||||
fRuns[i].~Run();
|
||||
}
|
||||
}
|
||||
|
||||
static const Key& GetKey(const GrAtlasTextBlob& blob) {
|
||||
return blob.fKey;
|
||||
}
|
||||
|
||||
static uint32_t Hash(const Key& key) {
|
||||
return SkChecksum::Murmur3(&key, sizeof(Key));
|
||||
}
|
||||
|
||||
void operator delete(void* p) {
|
||||
GrAtlasTextBlob* blob = reinterpret_cast<GrAtlasTextBlob*>(p);
|
||||
blob->fPool->release(p);
|
||||
}
|
||||
void* operator new(size_t) {
|
||||
SkFAIL("All blobs are created by placement new.");
|
||||
return sk_malloc_throw(0);
|
||||
}
|
||||
|
||||
void* operator new(size_t, void* p) { return p; }
|
||||
void operator delete(void* target, void* placement) {
|
||||
::operator delete(target, placement);
|
||||
}
|
||||
|
||||
bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); }
|
||||
bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
|
||||
void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
|
||||
void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
|
||||
};
|
||||
|
||||
#endif
|
@ -244,7 +244,7 @@ bool GrAtlasTextContext::HasLCD(const SkTextBlob* blob) {
|
||||
}
|
||||
|
||||
bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY,
|
||||
const BitmapTextBlob& blob, const SkPaint& paint,
|
||||
const GrAtlasTextBlob& blob, const SkPaint& paint,
|
||||
const SkMaskFilter::BlurRec& blurRec,
|
||||
const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
|
||||
// If we have LCD text then our canonical color will be set to transparent, in this case we have
|
||||
@ -326,15 +326,15 @@ bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTr
|
||||
(*outTransX) = x - blob.fX;
|
||||
(*outTransY) = y - blob.fY;
|
||||
}
|
||||
|
||||
// It is possible that a blob has neither distanceField nor bitmaptext. This is in the case
|
||||
// when all of the runs inside the blob are drawn as paths. In this case, we always regenerate
|
||||
// the blob anyways at flush time, so no need to regenerate explicitly
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run,
|
||||
inline SkGlyphCache* GrAtlasTextContext::setupCache(GrAtlasTextBlob::Run* run,
|
||||
const SkPaint& skPaint,
|
||||
const SkMatrix* viewMatrix,
|
||||
bool noGamma) {
|
||||
@ -353,9 +353,9 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt,
|
||||
return;
|
||||
}
|
||||
|
||||
SkAutoTUnref<BitmapTextBlob> cacheBlob;
|
||||
SkAutoTUnref<GrAtlasTextBlob> cacheBlob;
|
||||
SkMaskFilter::BlurRec blurRec;
|
||||
BitmapTextBlob::Key key;
|
||||
GrAtlasTextBlob::Key key;
|
||||
// It might be worth caching these things, but its not clear at this time
|
||||
// TODO for animated mask filters, this will fill up our cache. We need a safeguard here
|
||||
const SkMaskFilter* mf = skPaint.getMaskFilter();
|
||||
@ -470,7 +470,7 @@ inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint,
|
||||
return true;
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob,
|
||||
void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob,
|
||||
const SkPaint& skPaint, GrColor color,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkTextBlob* blob, SkScalar x, SkScalar y,
|
||||
@ -594,7 +594,7 @@ void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob,
|
||||
}
|
||||
}
|
||||
|
||||
inline void GrAtlasTextContext::initDistanceFieldPaint(BitmapTextBlob* blob,
|
||||
inline void GrAtlasTextContext::initDistanceFieldPaint(GrAtlasTextBlob* blob,
|
||||
SkPaint* skPaint,
|
||||
SkScalar* textRatio,
|
||||
const SkMatrix& viewMatrix) {
|
||||
@ -648,7 +648,7 @@ inline void GrAtlasTextContext::initDistanceFieldPaint(BitmapTextBlob* blob,
|
||||
skPaint->setSubpixelText(true);
|
||||
}
|
||||
|
||||
inline void GrAtlasTextContext::fallbackDrawPosText(BitmapTextBlob* blob,
|
||||
inline void GrAtlasTextContext::fallbackDrawPosText(GrAtlasTextBlob* blob,
|
||||
int runIndex,
|
||||
GrRenderTarget* rt, const GrClip& clip,
|
||||
const GrPaint& paint,
|
||||
@ -675,11 +675,11 @@ inline void GrAtlasTextContext::fallbackDrawPosText(BitmapTextBlob* blob,
|
||||
SkGlyphCache::AttachCache(cache);
|
||||
}
|
||||
|
||||
inline GrAtlasTextContext::BitmapTextBlob*
|
||||
inline GrAtlasTextBlob*
|
||||
GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint,
|
||||
const SkMatrix& viewMatrix, SkGlyphCache** cache,
|
||||
SkPaint* dfPaint, SkScalar* textRatio) {
|
||||
BitmapTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize);
|
||||
GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize);
|
||||
|
||||
*dfPaint = origPaint;
|
||||
this->initDistanceFieldPaint(blob, dfPaint, textRatio, viewMatrix);
|
||||
@ -693,7 +693,7 @@ GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint,
|
||||
return blob;
|
||||
}
|
||||
|
||||
inline GrAtlasTextContext::BitmapTextBlob*
|
||||
inline GrAtlasTextBlob*
|
||||
GrAtlasTextContext::createDrawTextBlob(GrRenderTarget* rt, const GrClip& clip,
|
||||
const GrPaint& paint, const SkPaint& skPaint,
|
||||
const SkMatrix& viewMatrix,
|
||||
@ -703,7 +703,7 @@ GrAtlasTextContext::createDrawTextBlob(GrRenderTarget* rt, const GrClip& clip,
|
||||
SkIRect clipRect;
|
||||
clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
|
||||
|
||||
BitmapTextBlob* blob;
|
||||
GrAtlasTextBlob* blob;
|
||||
if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) {
|
||||
SkPaint dfPaint;
|
||||
SkScalar textRatio;
|
||||
@ -733,7 +733,7 @@ GrAtlasTextContext::createDrawTextBlob(GrRenderTarget* rt, const GrClip& clip,
|
||||
return blob;
|
||||
}
|
||||
|
||||
inline GrAtlasTextContext::BitmapTextBlob*
|
||||
inline GrAtlasTextBlob*
|
||||
GrAtlasTextContext::createDrawPosTextBlob(GrRenderTarget* rt, const GrClip& clip,
|
||||
const GrPaint& paint, const SkPaint& skPaint,
|
||||
const SkMatrix& viewMatrix,
|
||||
@ -745,7 +745,7 @@ GrAtlasTextContext::createDrawPosTextBlob(GrRenderTarget* rt, const GrClip& clip
|
||||
SkIRect clipRect;
|
||||
clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
|
||||
|
||||
BitmapTextBlob* blob;
|
||||
GrAtlasTextBlob* blob;
|
||||
if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) {
|
||||
SkPaint dfPaint;
|
||||
SkScalar textRatio;
|
||||
@ -779,7 +779,7 @@ void GrAtlasTextContext::onDrawText(GrRenderTarget* rt,
|
||||
const SkMatrix& viewMatrix,
|
||||
const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y, const SkIRect& regionClipBounds) {
|
||||
SkAutoTUnref<BitmapTextBlob> blob(
|
||||
SkAutoTUnref<GrAtlasTextBlob> blob(
|
||||
this->createDrawTextBlob(rt, clip, paint, skPaint, viewMatrix,
|
||||
text, byteLength, x, y, regionClipBounds));
|
||||
this->flush(blob, rt, skPaint, paint, clip, regionClipBounds);
|
||||
@ -792,7 +792,7 @@ void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt,
|
||||
const char text[], size_t byteLength,
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
const SkPoint& offset, const SkIRect& regionClipBounds) {
|
||||
SkAutoTUnref<BitmapTextBlob> blob(
|
||||
SkAutoTUnref<GrAtlasTextBlob> blob(
|
||||
this->createDrawPosTextBlob(rt, clip, paint, skPaint, viewMatrix,
|
||||
text, byteLength,
|
||||
pos, scalarsPerPosition,
|
||||
@ -801,7 +801,7 @@ void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt,
|
||||
this->flush(blob, rt, skPaint, paint, clip, regionClipBounds);
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::internalDrawBMPText(BitmapTextBlob* blob, int runIndex,
|
||||
void GrAtlasTextContext::internalDrawBMPText(GrAtlasTextBlob* blob, int runIndex,
|
||||
SkGlyphCache* cache, const SkPaint& skPaint,
|
||||
GrColor color,
|
||||
const SkMatrix& viewMatrix,
|
||||
@ -892,7 +892,7 @@ void GrAtlasTextContext::internalDrawBMPText(BitmapTextBlob* blob, int runIndex,
|
||||
}
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::internalDrawBMPPosText(BitmapTextBlob* blob, int runIndex,
|
||||
void GrAtlasTextContext::internalDrawBMPPosText(GrAtlasTextBlob* blob, int runIndex,
|
||||
SkGlyphCache* cache, const SkPaint& skPaint,
|
||||
GrColor color,
|
||||
const SkMatrix& viewMatrix,
|
||||
@ -1057,7 +1057,7 @@ void GrAtlasTextContext::internalDrawBMPPosText(BitmapTextBlob* blob, int runInd
|
||||
}
|
||||
|
||||
|
||||
void GrAtlasTextContext::internalDrawDFText(BitmapTextBlob* blob, int runIndex,
|
||||
void GrAtlasTextContext::internalDrawDFText(GrAtlasTextBlob* blob, int runIndex,
|
||||
SkGlyphCache* cache, const SkPaint& skPaint,
|
||||
GrColor color,
|
||||
const SkMatrix& viewMatrix,
|
||||
@ -1131,7 +1131,7 @@ void GrAtlasTextContext::internalDrawDFText(BitmapTextBlob* blob, int runIndex,
|
||||
SkGlyphCache::AttachCache(origPaintCache);
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::internalDrawDFPosText(BitmapTextBlob* blob, int runIndex,
|
||||
void GrAtlasTextContext::internalDrawDFPosText(GrAtlasTextBlob* blob, int runIndex,
|
||||
SkGlyphCache* cache, const SkPaint& skPaint,
|
||||
GrColor color,
|
||||
const SkMatrix& viewMatrix,
|
||||
@ -1224,7 +1224,7 @@ void GrAtlasTextContext::internalDrawDFPosText(BitmapTextBlob* blob, int runInde
|
||||
}
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::bmpAppendGlyph(BitmapTextBlob* blob, int runIndex,
|
||||
void GrAtlasTextContext::bmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex,
|
||||
GrGlyph::PackedID packed,
|
||||
int vx, int vy, GrColor color, GrFontScaler* scaler,
|
||||
const SkIRect& clipRect) {
|
||||
@ -1285,7 +1285,7 @@ void GrAtlasTextContext::bmpAppendGlyph(BitmapTextBlob* blob, int runIndex,
|
||||
glyph);
|
||||
}
|
||||
|
||||
bool GrAtlasTextContext::dfAppendGlyph(BitmapTextBlob* blob, int runIndex,
|
||||
bool GrAtlasTextContext::dfAppendGlyph(GrAtlasTextBlob* blob, int runIndex,
|
||||
GrGlyph::PackedID packed,
|
||||
SkScalar sx, SkScalar sy, GrColor color,
|
||||
GrFontScaler* scaler,
|
||||
@ -1352,7 +1352,7 @@ bool GrAtlasTextContext::dfAppendGlyph(BitmapTextBlob* blob, int runIndex,
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void GrAtlasTextContext::appendGlyphPath(BitmapTextBlob* blob, GrGlyph* glyph,
|
||||
inline void GrAtlasTextContext::appendGlyphPath(GrAtlasTextBlob* blob, GrGlyph* glyph,
|
||||
GrFontScaler* scaler, SkScalar x, SkScalar y) {
|
||||
if (NULL == glyph->fPath) {
|
||||
SkPath* path = SkNEW(SkPath);
|
||||
@ -1364,10 +1364,10 @@ inline void GrAtlasTextContext::appendGlyphPath(BitmapTextBlob* blob, GrGlyph* g
|
||||
glyph->fPath = path;
|
||||
}
|
||||
SkASSERT(glyph->fPath);
|
||||
blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, x, y));
|
||||
blob->fBigGlyphs.push_back(GrAtlasTextBlob::BigGlyph(*glyph->fPath, x, y));
|
||||
}
|
||||
|
||||
inline void GrAtlasTextContext::appendGlyphCommon(BitmapTextBlob* blob, Run* run,
|
||||
inline void GrAtlasTextContext::appendGlyphCommon(GrAtlasTextBlob* blob, Run* run,
|
||||
Run::SubRunInfo* subRun,
|
||||
const SkRect& positions, GrColor color,
|
||||
size_t vertexStride, bool useVertexColor,
|
||||
@ -1433,7 +1433,7 @@ inline void GrAtlasTextContext::appendGlyphCommon(BitmapTextBlob* blob, Run* run
|
||||
class BitmapTextBatch : public GrBatch {
|
||||
public:
|
||||
typedef GrAtlasTextContext::DistanceAdjustTable DistanceAdjustTable;
|
||||
typedef GrAtlasTextContext::BitmapTextBlob Blob;
|
||||
typedef GrAtlasTextBlob Blob;
|
||||
typedef Blob::Run Run;
|
||||
typedef Run::SubRunInfo TextInfo;
|
||||
struct Geometry {
|
||||
@ -2074,7 +2074,7 @@ void GrAtlasTextContext::flushRunAsPaths(GrRenderTarget* rt, const SkTextBlob::R
|
||||
|
||||
|
||||
inline BitmapTextBatch*
|
||||
GrAtlasTextContext::createBatch(BitmapTextBlob* cacheBlob, const PerSubRunInfo& info,
|
||||
GrAtlasTextContext::createBatch(GrAtlasTextBlob* cacheBlob, const PerSubRunInfo& info,
|
||||
int glyphCount, int run, int subRun,
|
||||
GrColor color, SkScalar transX, SkScalar transY,
|
||||
const SkPaint& skPaint) {
|
||||
@ -2116,7 +2116,7 @@ GrAtlasTextContext::createBatch(BitmapTextBlob* cacheBlob, const PerSubRunInfo&
|
||||
}
|
||||
|
||||
inline void GrAtlasTextContext::flushRun(GrPipelineBuilder* pipelineBuilder,
|
||||
BitmapTextBlob* cacheBlob, int run, GrColor color,
|
||||
GrAtlasTextBlob* cacheBlob, int run, GrColor color,
|
||||
SkScalar transX, SkScalar transY,
|
||||
const SkPaint& skPaint) {
|
||||
for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); subRun++) {
|
||||
@ -2133,7 +2133,7 @@ inline void GrAtlasTextContext::flushRun(GrPipelineBuilder* pipelineBuilder,
|
||||
}
|
||||
}
|
||||
|
||||
inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget* rt,
|
||||
inline void GrAtlasTextContext::flushBigGlyphs(GrAtlasTextBlob* cacheBlob, GrRenderTarget* rt,
|
||||
const GrClip& clip, const SkPaint& skPaint,
|
||||
SkScalar transX, SkScalar transY,
|
||||
const SkIRect& clipBounds) {
|
||||
@ -2148,7 +2148,7 @@ inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRend
|
||||
}
|
||||
|
||||
for (int i = 0; i < cacheBlob->fBigGlyphs.count(); i++) {
|
||||
BitmapTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i];
|
||||
GrAtlasTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i];
|
||||
bigGlyph.fVx += transX;
|
||||
bigGlyph.fVy += transY;
|
||||
SkMatrix translate = cacheBlob->fViewMatrix;
|
||||
@ -2160,7 +2160,7 @@ inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRend
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::flush(const SkTextBlob* blob,
|
||||
BitmapTextBlob* cacheBlob,
|
||||
GrAtlasTextBlob* cacheBlob,
|
||||
GrRenderTarget* rt,
|
||||
const SkPaint& skPaint,
|
||||
const GrPaint& grPaint,
|
||||
@ -2192,7 +2192,7 @@ void GrAtlasTextContext::flush(const SkTextBlob* blob,
|
||||
this->flushBigGlyphs(cacheBlob, rt, clip, skPaint, transX, transY, clipBounds);
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::flush(BitmapTextBlob* cacheBlob,
|
||||
void GrAtlasTextContext::flush(GrAtlasTextBlob* cacheBlob,
|
||||
GrRenderTarget* rt,
|
||||
const SkPaint& skPaint,
|
||||
const GrPaint& grPaint,
|
||||
@ -2265,13 +2265,13 @@ BATCH_TEST_DEFINE(TextBlobBatch) {
|
||||
|
||||
// right now we don't handle textblobs, nor do we handle drawPosText. Since we only
|
||||
// intend to test the batch with this unit test, that is okay.
|
||||
SkAutoTUnref<GrAtlasTextContext::BitmapTextBlob> blob(
|
||||
SkAutoTUnref<GrAtlasTextBlob> blob(
|
||||
gTextContext->createDrawTextBlob(rt, clip, grPaint, skPaint, viewMatrix, text,
|
||||
static_cast<size_t>(textLen), 0, 0, noClip));
|
||||
|
||||
SkScalar transX = static_cast<SkScalar>(random->nextU());
|
||||
SkScalar transY = static_cast<SkScalar>(random->nextU());
|
||||
const GrAtlasTextContext::BitmapTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0];
|
||||
const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0];
|
||||
return gTextContext->createBatch(blob, info, textLen, 0, 0, color, transX, transY, skPaint);
|
||||
}
|
||||
|
||||
|
@ -10,14 +10,9 @@
|
||||
|
||||
#include "GrTextContext.h"
|
||||
|
||||
#include "GrBatchAtlas.h"
|
||||
#include "GrBatchFontCache.h"
|
||||
#include "GrAtlasTextBlob.h"
|
||||
#include "GrGeometryProcessor.h"
|
||||
#include "SkDescriptor.h"
|
||||
#include "GrMemoryPool.h"
|
||||
#include "SkMaskFilter.h"
|
||||
#include "SkTextBlob.h"
|
||||
#include "SkTInternalLList.h"
|
||||
|
||||
#ifdef GR_TEST_UTILS
|
||||
#include "GrBatchTest.h"
|
||||
@ -56,217 +51,21 @@ private:
|
||||
const SkMatrix& viewMatrix, const SkTextBlob*, SkScalar x, SkScalar y,
|
||||
SkDrawFilter*, const SkIRect& clipBounds) override;
|
||||
|
||||
/*
|
||||
* A BitmapTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
|
||||
* on the GPU. These are initially created with valid positions and colors, but invalid
|
||||
* texture coordinates. The BitmapTextBlob itself has a few Blob-wide properties, and also
|
||||
* consists of a number of runs. Runs inside a blob are flushed individually so they can be
|
||||
* reordered.
|
||||
*
|
||||
* The only thing(aside from a memcopy) required to flush a BitmapTextBlob is to ensure that
|
||||
* the GrAtlas will not evict anything the Blob needs.
|
||||
*/
|
||||
struct BitmapTextBlob : public SkRefCnt {
|
||||
SK_DECLARE_INTERNAL_LLIST_INTERFACE(BitmapTextBlob);
|
||||
|
||||
/*
|
||||
* Each Run inside of the blob can have its texture coordinates regenerated if required.
|
||||
* To determine if regeneration is necessary, fAtlasGeneration is used. If there have been
|
||||
* any evictions inside of the atlas, then we will simply regenerate Runs. We could track
|
||||
* this at a more fine grained level, but its not clear if this is worth it, as evictions
|
||||
* should be fairly rare.
|
||||
*
|
||||
* One additional point, each run can contain glyphs with any of the three mask formats.
|
||||
* We call these SubRuns. Because a subrun must be a contiguous range, we have to create
|
||||
* a new subrun each time the mask format changes in a run. In theory, a run can have as
|
||||
* many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8. In
|
||||
* practice, the vast majority of runs have only a single subrun.
|
||||
*
|
||||
* Finally, for runs where the entire thing is too large for the GrAtlasTextContext to
|
||||
* handle, we have a bit to mark the run as flusahable via rendering as paths. It is worth
|
||||
* pointing. It would be a bit expensive to figure out ahead of time whether or not a run
|
||||
* can flush in this manner, so we always allocate vertices for the run, regardless of
|
||||
* whether or not it is too large. The benefit of this strategy is that we can always reuse
|
||||
* a blob allocation regardless of viewmatrix changes. We could store positions for these
|
||||
* glyphs. However, its not clear if this is a win because we'd still have to either go the
|
||||
* glyph cache to get the path at flush time, or hold onto the path in the cache, which
|
||||
* would greatly increase the memory of these cached items.
|
||||
*/
|
||||
struct Run {
|
||||
Run()
|
||||
: fColor(GrColor_ILLEGAL)
|
||||
, fInitialized(false)
|
||||
, fDrawAsPaths(false) {
|
||||
fVertexBounds.setLargestInverted();
|
||||
// To ensure we always have one subrun, we push back a fresh run here
|
||||
fSubRunInfo.push_back();
|
||||
}
|
||||
struct SubRunInfo {
|
||||
SubRunInfo()
|
||||
: fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration)
|
||||
, fVertexStartIndex(0)
|
||||
, fVertexEndIndex(0)
|
||||
, fGlyphStartIndex(0)
|
||||
, fGlyphEndIndex(0)
|
||||
, fDrawAsDistanceFields(false) {}
|
||||
// Distance field text cannot draw coloremoji, and so has to fall back. However,
|
||||
// though the distance field text and the coloremoji may share the same run, they
|
||||
// will have different descriptors. If fOverrideDescriptor is non-NULL, then it
|
||||
// will be used in place of the run's descriptor to regen texture coords
|
||||
// TODO we could have a descriptor cache, it would reduce the size of these blobs
|
||||
// significantly, and then the subrun could just have a refed pointer to the
|
||||
// correct descriptor.
|
||||
GrBatchAtlas::BulkUseTokenUpdater fBulkUseToken;
|
||||
uint64_t fAtlasGeneration;
|
||||
size_t fVertexStartIndex;
|
||||
size_t fVertexEndIndex;
|
||||
uint32_t fGlyphStartIndex;
|
||||
uint32_t fGlyphEndIndex;
|
||||
SkScalar fTextRatio; // df property
|
||||
GrMaskFormat fMaskFormat;
|
||||
bool fDrawAsDistanceFields; // df property
|
||||
bool fUseLCDText; // df property
|
||||
};
|
||||
|
||||
SubRunInfo& push_back() {
|
||||
// Forward glyph / vertex information to seed the new sub run
|
||||
SubRunInfo& prevSubRun = fSubRunInfo.back();
|
||||
SubRunInfo& newSubRun = fSubRunInfo.push_back();
|
||||
newSubRun.fGlyphStartIndex = prevSubRun.fGlyphEndIndex;
|
||||
newSubRun.fGlyphEndIndex = prevSubRun.fGlyphEndIndex;
|
||||
|
||||
newSubRun.fVertexStartIndex = prevSubRun.fVertexEndIndex;
|
||||
newSubRun.fVertexEndIndex = prevSubRun.fVertexEndIndex;
|
||||
return newSubRun;
|
||||
}
|
||||
static const int kMinSubRuns = 1;
|
||||
SkAutoTUnref<GrBatchTextStrike> fStrike;
|
||||
SkAutoTUnref<SkTypeface> fTypeface;
|
||||
SkRect fVertexBounds;
|
||||
SkSTArray<kMinSubRuns, SubRunInfo> fSubRunInfo;
|
||||
SkAutoDescriptor fDescriptor;
|
||||
SkAutoTDelete<SkAutoDescriptor> fOverrideDescriptor; // df properties
|
||||
GrColor fColor;
|
||||
bool fInitialized;
|
||||
bool fDrawAsPaths;
|
||||
};
|
||||
|
||||
struct BigGlyph {
|
||||
BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy)
|
||||
: fPath(path)
|
||||
, fVx(vx)
|
||||
, fVy(vy) {}
|
||||
SkPath fPath;
|
||||
SkScalar fVx;
|
||||
SkScalar fVy;
|
||||
};
|
||||
|
||||
struct Key {
|
||||
Key() {
|
||||
sk_bzero(this, sizeof(Key));
|
||||
}
|
||||
uint32_t fUniqueID;
|
||||
// Color may affect the gamma of the mask we generate, but in a fairly limited way.
|
||||
// Each color is assigned to on of a fixed number of buckets based on its
|
||||
// luminance. For each luminance bucket there is a "canonical color" that
|
||||
// represents the bucket. This functionality is currently only supported for A8
|
||||
SkColor fCanonicalColor;
|
||||
SkPaint::Style fStyle;
|
||||
SkPixelGeometry fPixelGeometry;
|
||||
bool fHasBlur;
|
||||
|
||||
bool operator==(const Key& other) const {
|
||||
return 0 == memcmp(this, &other, sizeof(Key));
|
||||
}
|
||||
};
|
||||
|
||||
struct StrokeInfo {
|
||||
SkScalar fFrameWidth;
|
||||
SkScalar fMiterLimit;
|
||||
SkPaint::Join fJoin;
|
||||
};
|
||||
|
||||
enum TextType {
|
||||
kHasDistanceField_TextType = 0x1,
|
||||
kHasBitmap_TextType = 0x2,
|
||||
};
|
||||
|
||||
// all glyph / vertex offsets are into these pools.
|
||||
unsigned char* fVertices;
|
||||
GrGlyph** fGlyphs;
|
||||
Run* fRuns;
|
||||
GrMemoryPool* fPool;
|
||||
SkMaskFilter::BlurRec fBlurRec;
|
||||
StrokeInfo fStrokeInfo;
|
||||
SkTArray<BigGlyph> fBigGlyphs;
|
||||
Key fKey;
|
||||
SkMatrix fViewMatrix;
|
||||
SkColor fPaintColor;
|
||||
SkScalar fX;
|
||||
SkScalar fY;
|
||||
|
||||
// We can reuse distance field text, but only if the new viewmatrix would not result in
|
||||
// a mip change. Because there can be multiple runs in a blob, we track the overall
|
||||
// maximum minimum scale, and minimum maximum scale, we can support before we need to regen
|
||||
SkScalar fMaxMinScale;
|
||||
SkScalar fMinMaxScale;
|
||||
int fRunCount;
|
||||
uint8_t fTextType;
|
||||
|
||||
BitmapTextBlob()
|
||||
: fMaxMinScale(-SK_ScalarMax)
|
||||
, fMinMaxScale(SK_ScalarMax)
|
||||
, fTextType(0) {}
|
||||
|
||||
~BitmapTextBlob() override {
|
||||
for (int i = 0; i < fRunCount; i++) {
|
||||
fRuns[i].~Run();
|
||||
}
|
||||
}
|
||||
|
||||
static const Key& GetKey(const BitmapTextBlob& blob) {
|
||||
return blob.fKey;
|
||||
}
|
||||
|
||||
static uint32_t Hash(const Key& key) {
|
||||
return SkChecksum::Murmur3(&key, sizeof(Key));
|
||||
}
|
||||
|
||||
void operator delete(void* p) {
|
||||
BitmapTextBlob* blob = reinterpret_cast<BitmapTextBlob*>(p);
|
||||
blob->fPool->release(p);
|
||||
}
|
||||
void* operator new(size_t) {
|
||||
SkFAIL("All blobs are created by placement new.");
|
||||
return sk_malloc_throw(0);
|
||||
}
|
||||
|
||||
void* operator new(size_t, void* p) { return p; }
|
||||
void operator delete(void* target, void* placement) {
|
||||
::operator delete(target, placement);
|
||||
}
|
||||
|
||||
bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); }
|
||||
bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
|
||||
void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
|
||||
void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
|
||||
};
|
||||
|
||||
typedef BitmapTextBlob::Run Run;
|
||||
typedef GrAtlasTextBlob::Run Run;
|
||||
typedef Run::SubRunInfo PerSubRunInfo;
|
||||
|
||||
inline bool canDrawAsDistanceFields(const SkPaint&, const SkMatrix& viewMatrix);
|
||||
BitmapTextBlob* setupDFBlob(int glyphCount, const SkPaint& origPaint,
|
||||
GrAtlasTextBlob* setupDFBlob(int glyphCount, const SkPaint& origPaint,
|
||||
const SkMatrix& viewMatrix, SkGlyphCache** cache,
|
||||
SkPaint* dfPaint, SkScalar* textRatio);
|
||||
void bmpAppendGlyph(BitmapTextBlob*, int runIndex, GrGlyph::PackedID, int left, int top,
|
||||
void bmpAppendGlyph(GrAtlasTextBlob*, int runIndex, GrGlyph::PackedID, int left, int top,
|
||||
GrColor color, GrFontScaler*, const SkIRect& clipRect);
|
||||
bool dfAppendGlyph(BitmapTextBlob*, int runIndex, GrGlyph::PackedID, SkScalar sx, SkScalar sy,
|
||||
bool dfAppendGlyph(GrAtlasTextBlob*, int runIndex, GrGlyph::PackedID, SkScalar sx, SkScalar sy,
|
||||
GrColor color, GrFontScaler*, const SkIRect& clipRect, SkScalar textRatio,
|
||||
const SkMatrix& viewMatrix);
|
||||
inline void appendGlyphPath(BitmapTextBlob* blob, GrGlyph* glyph,
|
||||
inline void appendGlyphPath(GrAtlasTextBlob* blob, GrGlyph* glyph,
|
||||
GrFontScaler* scaler, SkScalar x, SkScalar y);
|
||||
inline void appendGlyphCommon(BitmapTextBlob*, Run*, Run::SubRunInfo*,
|
||||
inline void appendGlyphCommon(GrAtlasTextBlob*, Run*, Run::SubRunInfo*,
|
||||
const SkRect& positions, GrColor color,
|
||||
size_t vertexStride, bool useVertexColor,
|
||||
GrGlyph*);
|
||||
@ -276,26 +75,26 @@ private:
|
||||
const SkPaint&, SkDrawFilter*,
|
||||
const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x,
|
||||
SkScalar y);
|
||||
inline BitmapTextBatch* createBatch(BitmapTextBlob*, const PerSubRunInfo&,
|
||||
inline BitmapTextBatch* createBatch(GrAtlasTextBlob*, const PerSubRunInfo&,
|
||||
int glyphCount, int run, int subRun,
|
||||
GrColor, SkScalar transX, SkScalar transY,
|
||||
const SkPaint&);
|
||||
inline void flushRun(GrPipelineBuilder*, BitmapTextBlob*, int run, GrColor,
|
||||
inline void flushRun(GrPipelineBuilder*, GrAtlasTextBlob*, int run, GrColor,
|
||||
SkScalar transX, SkScalar transY, const SkPaint&);
|
||||
inline void flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget*,
|
||||
inline void flushBigGlyphs(GrAtlasTextBlob* cacheBlob, GrRenderTarget*,
|
||||
const GrClip& clip, const SkPaint& skPaint,
|
||||
SkScalar transX, SkScalar transY, const SkIRect& clipBounds);
|
||||
|
||||
// We have to flush SkTextBlobs differently from drawText / drawPosText
|
||||
void flush(const SkTextBlob*, BitmapTextBlob*, GrRenderTarget*,
|
||||
void flush(const SkTextBlob*, GrAtlasTextBlob*, GrRenderTarget*,
|
||||
const SkPaint&, const GrPaint&, SkDrawFilter*, const GrClip&,
|
||||
const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y,
|
||||
SkScalar transX, SkScalar transY);
|
||||
void flush(BitmapTextBlob*, GrRenderTarget*, const SkPaint&,
|
||||
void flush(GrAtlasTextBlob*, GrRenderTarget*, const SkPaint&,
|
||||
const GrPaint&, const GrClip&, const SkIRect& clipBounds);
|
||||
|
||||
// A helper for drawing BitmapText in a run of distance fields
|
||||
inline void fallbackDrawPosText(BitmapTextBlob*, int runIndex,
|
||||
inline void fallbackDrawPosText(GrAtlasTextBlob*, int runIndex,
|
||||
GrRenderTarget*, const GrClip&,
|
||||
const GrPaint&,
|
||||
const SkPaint&, const SkMatrix& viewMatrix,
|
||||
@ -305,17 +104,17 @@ private:
|
||||
const SkPoint& offset,
|
||||
const SkIRect& clipRect);
|
||||
|
||||
void internalDrawBMPText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
|
||||
void internalDrawBMPText(GrAtlasTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
|
||||
GrColor color, const SkMatrix& viewMatrix,
|
||||
const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y, const SkIRect& clipRect);
|
||||
void internalDrawBMPPosText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
|
||||
void internalDrawBMPPosText(GrAtlasTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
|
||||
GrColor color, const SkMatrix& viewMatrix,
|
||||
const char text[], size_t byteLength,
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
const SkPoint& offset, const SkIRect& clipRect);
|
||||
|
||||
void internalDrawDFText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
|
||||
void internalDrawDFText(GrAtlasTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
|
||||
GrColor color, const SkMatrix& viewMatrix,
|
||||
const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y, const SkIRect& clipRect,
|
||||
@ -323,7 +122,7 @@ private:
|
||||
SkTDArray<char>* fallbackTxt,
|
||||
SkTDArray<SkScalar>* fallbackPos,
|
||||
SkPoint* offset, const SkPaint& origPaint);
|
||||
void internalDrawDFPosText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
|
||||
void internalDrawDFPosText(GrAtlasTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
|
||||
GrColor color, const SkMatrix& viewMatrix,
|
||||
const char text[], size_t byteLength,
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
@ -336,26 +135,26 @@ private:
|
||||
inline static GrColor ComputeCanonicalColor(const SkPaint&, bool lcd);
|
||||
inline SkGlyphCache* setupCache(Run*, const SkPaint&, const SkMatrix* viewMatrix, bool noGamma);
|
||||
static inline bool MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY,
|
||||
const BitmapTextBlob&, const SkPaint&,
|
||||
const GrAtlasTextBlob&, const SkPaint&,
|
||||
const SkMaskFilter::BlurRec&,
|
||||
const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
|
||||
void regenerateTextBlob(BitmapTextBlob* bmp, const SkPaint& skPaint, GrColor,
|
||||
void regenerateTextBlob(GrAtlasTextBlob* bmp, const SkPaint& skPaint, GrColor,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkTextBlob* blob, SkScalar x, SkScalar y,
|
||||
SkDrawFilter* drawFilter, const SkIRect& clipRect, GrRenderTarget*,
|
||||
const GrClip&, const GrPaint&);
|
||||
inline static bool HasLCD(const SkTextBlob*);
|
||||
inline void initDistanceFieldPaint(BitmapTextBlob*, SkPaint*, SkScalar* textRatio,
|
||||
inline void initDistanceFieldPaint(GrAtlasTextBlob*, SkPaint*, SkScalar* textRatio,
|
||||
const SkMatrix&);
|
||||
|
||||
// Test methods
|
||||
// TODO this is really ugly. It'd be much nicer if positioning could be moved to batch
|
||||
inline BitmapTextBlob* createDrawTextBlob(GrRenderTarget*, const GrClip&, const GrPaint&,
|
||||
inline GrAtlasTextBlob* createDrawTextBlob(GrRenderTarget*, const GrClip&, const GrPaint&,
|
||||
const SkPaint&, const SkMatrix& viewMatrix,
|
||||
const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y,
|
||||
const SkIRect& regionClipBounds);
|
||||
inline BitmapTextBlob* createDrawPosTextBlob(GrRenderTarget*, const GrClip&, const GrPaint&,
|
||||
inline GrAtlasTextBlob* createDrawPosTextBlob(GrRenderTarget*, const GrClip&, const GrPaint&,
|
||||
const SkPaint&, const SkMatrix& viewMatrix,
|
||||
const char text[], size_t byteLength,
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
|
@ -13,26 +13,26 @@ GrTextBlobCache::~GrTextBlobCache() {
|
||||
this->freeAll();
|
||||
}
|
||||
|
||||
GrAtlasTextContext::BitmapTextBlob* GrTextBlobCache::createBlob(int glyphCount, int runCount,
|
||||
GrAtlasTextBlob* GrTextBlobCache::createBlob(int glyphCount, int runCount,
|
||||
size_t maxVASize) {
|
||||
// We allocate size for the BitmapTextBlob itself, plus size for the vertices array,
|
||||
// We allocate size for the GrAtlasTextBlob itself, plus size for the vertices array,
|
||||
// and size for the glyphIds array.
|
||||
size_t verticesCount = glyphCount * kVerticesPerGlyph * maxVASize;
|
||||
size_t size = sizeof(BitmapTextBlob) +
|
||||
size_t size = sizeof(GrAtlasTextBlob) +
|
||||
verticesCount +
|
||||
glyphCount * sizeof(GrGlyph**) +
|
||||
sizeof(BitmapTextBlob::Run) * runCount;
|
||||
sizeof(GrAtlasTextBlob::Run) * runCount;
|
||||
|
||||
BitmapTextBlob* cacheBlob = SkNEW_PLACEMENT(fPool.allocate(size), BitmapTextBlob);
|
||||
GrAtlasTextBlob* cacheBlob = SkNEW_PLACEMENT(fPool.allocate(size), GrAtlasTextBlob);
|
||||
|
||||
// setup offsets for vertices / glyphs
|
||||
cacheBlob->fVertices = sizeof(BitmapTextBlob) + reinterpret_cast<unsigned char*>(cacheBlob);
|
||||
cacheBlob->fVertices = sizeof(GrAtlasTextBlob) + reinterpret_cast<unsigned char*>(cacheBlob);
|
||||
cacheBlob->fGlyphs = reinterpret_cast<GrGlyph**>(cacheBlob->fVertices + verticesCount);
|
||||
cacheBlob->fRuns = reinterpret_cast<BitmapTextBlob::Run*>(cacheBlob->fGlyphs + glyphCount);
|
||||
cacheBlob->fRuns = reinterpret_cast<GrAtlasTextBlob::Run*>(cacheBlob->fGlyphs + glyphCount);
|
||||
|
||||
// Initialize runs
|
||||
for (int i = 0; i < runCount; i++) {
|
||||
SkNEW_PLACEMENT(&cacheBlob->fRuns[i], BitmapTextBlob::Run);
|
||||
SkNEW_PLACEMENT(&cacheBlob->fRuns[i], GrAtlasTextBlob::Run);
|
||||
}
|
||||
cacheBlob->fRunCount = runCount;
|
||||
cacheBlob->fPool = &fPool;
|
||||
@ -40,9 +40,9 @@ GrAtlasTextContext::BitmapTextBlob* GrTextBlobCache::createBlob(int glyphCount,
|
||||
}
|
||||
|
||||
void GrTextBlobCache::freeAll() {
|
||||
SkTDynamicHash<BitmapTextBlob, BitmapTextBlob::Key>::Iter iter(&fCache);
|
||||
SkTDynamicHash<GrAtlasTextBlob, GrAtlasTextBlob::Key>::Iter iter(&fCache);
|
||||
while (!iter.done()) {
|
||||
BitmapTextBlob* blob = &(*iter);
|
||||
GrAtlasTextBlob* blob = &(*iter);
|
||||
fBlobList.remove(blob);
|
||||
blob->unref();
|
||||
++iter;
|
||||
|
@ -14,8 +14,6 @@
|
||||
|
||||
class GrTextBlobCache {
|
||||
public:
|
||||
typedef GrAtlasTextContext::BitmapTextBlob BitmapTextBlob;
|
||||
|
||||
/**
|
||||
* The callback function used by the cache when it is still over budget after a purge. The
|
||||
* passed in 'data' is the same 'data' handed to setOverbudgetCallback.
|
||||
@ -31,24 +29,24 @@ public:
|
||||
~GrTextBlobCache();
|
||||
|
||||
// creates an uncached blob
|
||||
BitmapTextBlob* createBlob(int glyphCount, int runCount, size_t maxVASize);
|
||||
BitmapTextBlob* createBlob(const SkTextBlob* blob, size_t maxVAStride) {
|
||||
GrAtlasTextBlob* createBlob(int glyphCount, int runCount, size_t maxVASize);
|
||||
GrAtlasTextBlob* createBlob(const SkTextBlob* blob, size_t maxVAStride) {
|
||||
int glyphCount = 0;
|
||||
int runCount = 0;
|
||||
BlobGlyphCount(&glyphCount, &runCount, blob);
|
||||
BitmapTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride);
|
||||
GrAtlasTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride);
|
||||
return cacheBlob;
|
||||
}
|
||||
|
||||
BitmapTextBlob* createCachedBlob(const SkTextBlob* blob,
|
||||
const BitmapTextBlob::Key& key,
|
||||
GrAtlasTextBlob* createCachedBlob(const SkTextBlob* blob,
|
||||
const GrAtlasTextBlob::Key& key,
|
||||
const SkMaskFilter::BlurRec& blurRec,
|
||||
const SkPaint& paint,
|
||||
size_t maxVAStride) {
|
||||
int glyphCount = 0;
|
||||
int runCount = 0;
|
||||
BlobGlyphCount(&glyphCount, &runCount, blob);
|
||||
BitmapTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride);
|
||||
GrAtlasTextBlob* cacheBlob = this->createBlob(glyphCount, runCount, maxVAStride);
|
||||
cacheBlob->fKey = key;
|
||||
if (key.fHasBlur) {
|
||||
cacheBlob->fBlurRec = blurRec;
|
||||
@ -62,17 +60,17 @@ public:
|
||||
return cacheBlob;
|
||||
}
|
||||
|
||||
BitmapTextBlob* find(const BitmapTextBlob::Key& key) {
|
||||
GrAtlasTextBlob* find(const GrAtlasTextBlob::Key& key) {
|
||||
return fCache.find(key);
|
||||
}
|
||||
|
||||
void remove(BitmapTextBlob* blob) {
|
||||
void remove(GrAtlasTextBlob* blob) {
|
||||
fCache.remove(blob->fKey);
|
||||
fBlobList.remove(blob);
|
||||
blob->unref();
|
||||
}
|
||||
|
||||
void add(BitmapTextBlob* blob) {
|
||||
void add(GrAtlasTextBlob* blob) {
|
||||
fCache.add(blob);
|
||||
fBlobList.addToHead(blob);
|
||||
|
||||
@ -80,7 +78,7 @@ public:
|
||||
if (fPool.size() > kBudget) {
|
||||
BitmapBlobList::Iter iter;
|
||||
iter.init(fBlobList, BitmapBlobList::Iter::kTail_IterStart);
|
||||
BitmapTextBlob* lruBlob = iter.get();
|
||||
GrAtlasTextBlob* lruBlob = iter.get();
|
||||
SkASSERT(lruBlob);
|
||||
while (fPool.size() > kBudget && (lruBlob = iter.get()) && lruBlob != blob) {
|
||||
fCache.remove(lruBlob->fKey);
|
||||
@ -106,7 +104,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void makeMRU(BitmapTextBlob* blob) {
|
||||
void makeMRU(GrAtlasTextBlob* blob) {
|
||||
if (fBlobList.head() == blob) {
|
||||
return;
|
||||
}
|
||||
@ -126,7 +124,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
typedef SkTInternalLList<BitmapTextBlob> BitmapBlobList;
|
||||
typedef SkTInternalLList<GrAtlasTextBlob> BitmapBlobList;
|
||||
|
||||
// Budget was chosen to be ~4 megabytes. The min alloc and pre alloc sizes in the pool are
|
||||
// based off of the largest cached textblob I have seen in the skps(a couple of kilobytes).
|
||||
@ -134,7 +132,7 @@ private:
|
||||
static const int kMinGrowthSize = 1 << 17;
|
||||
static const int kBudget = 1 << 22;
|
||||
BitmapBlobList fBlobList;
|
||||
SkTDynamicHash<BitmapTextBlob, BitmapTextBlob::Key> fCache;
|
||||
SkTDynamicHash<GrAtlasTextBlob, GrAtlasTextBlob::Key> fCache;
|
||||
GrMemoryPool fPool;
|
||||
PFOverBudgetCB fCallback;
|
||||
void* fData;
|
||||
|
Loading…
Reference in New Issue
Block a user