OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2015 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 */ |
| 7 |
| 8 #ifndef GrAtlasTextBlob_DEFINED |
| 9 #define GrAtlasTextBlob_DEFINED |
| 10 |
| 11 #include "GrBatchAtlas.h" |
| 12 #include "GrBatchFontCache.h" |
| 13 #include "SkDescriptor.h" |
| 14 #include "SkMaskFilter.h" |
| 15 #include "GrMemoryPool.h" |
| 16 #include "SkTInternalLList.h" |
| 17 |
| 18 /* |
| 19 * A GrAtlasTextBlob contains a fully processed SkTextBlob, suitable for nearly
immediate drawing |
| 20 * on the GPU. These are initially created with valid positions and colors, but
invalid |
| 21 * texture coordinates. The GrAtlasTextBlob itself has a few Blob-wide properti
es, and also |
| 22 * consists of a number of runs. Runs inside a blob are flushed individually so
they can be |
| 23 * reordered. |
| 24 * |
| 25 * The only thing(aside from a memcopy) required to flush a GrAtlasTextBlob is t
o ensure that |
| 26 * the GrAtlas will not evict anything the Blob needs. |
| 27 * |
| 28 * Note: This struct should really be named GrCachedAtasTextBlob, but that is to
o verbose. |
| 29 */ |
| 30 struct GrAtlasTextBlob : public SkRefCnt { |
| 31 SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrAtlasTextBlob); |
| 32 |
| 33 /* |
| 34 * Each Run inside of the blob can have its texture coordinates regenerated
if required. |
| 35 * To determine if regeneration is necessary, fAtlasGeneration is used. If
there have been |
| 36 * any evictions inside of the atlas, then we will simply regenerate Runs.
We could track |
| 37 * this at a more fine grained level, but its not clear if this is worth it,
as evictions |
| 38 * should be fairly rare. |
| 39 * |
| 40 * One additional point, each run can contain glyphs with any of the three m
ask formats. |
| 41 * We call these SubRuns. Because a subrun must be a contiguous range, we h
ave to create |
| 42 * a new subrun each time the mask format changes in a run. In theory, a ru
n can have as |
| 43 * many SubRuns as it has glyphs, ie if a run alternates between color emoji
and A8. In |
| 44 * practice, the vast majority of runs have only a single subrun. |
| 45 * |
| 46 * Finally, for runs where the entire thing is too large for the GrAtlasText
Context to |
| 47 * handle, we have a bit to mark the run as flusahable via rendering as path
s. It is worth |
| 48 * pointing. It would be a bit expensive to figure out ahead of time whether
or not a run |
| 49 * can flush in this manner, so we always allocate vertices for the run, reg
ardless of |
| 50 * whether or not it is too large. The benefit of this strategy is that we
can always reuse |
| 51 * a blob allocation regardless of viewmatrix changes. We could store posit
ions for these |
| 52 * glyphs. However, its not clear if this is a win because we'd still have
to either go the |
| 53 * glyph cache to get the path at flush time, or hold onto the path in the c
ache, which |
| 54 * would greatly increase the memory of these cached items. |
| 55 */ |
| 56 struct Run { |
| 57 Run() |
| 58 : fColor(GrColor_ILLEGAL) |
| 59 , fInitialized(false) |
| 60 , fDrawAsPaths(false) { |
| 61 fVertexBounds.setLargestInverted(); |
| 62 // To ensure we always have one subrun, we push back a fresh run her
e |
| 63 fSubRunInfo.push_back(); |
| 64 } |
| 65 struct SubRunInfo { |
| 66 SubRunInfo() |
| 67 : fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration) |
| 68 , fVertexStartIndex(0) |
| 69 , fVertexEndIndex(0) |
| 70 , fGlyphStartIndex(0) |
| 71 , fGlyphEndIndex(0) |
| 72 , fDrawAsDistanceFields(false) {} |
| 73 // Distance field text cannot draw coloremoji, and so has to fall ba
ck. However, |
| 74 // though the distance field text and the coloremoji may share the s
ame run, they |
| 75 // will have different descriptors. If fOverrideDescriptor is non-N
ULL, then it |
| 76 // will be used in place of the run's descriptor to regen texture co
ords |
| 77 // TODO we could have a descriptor cache, it would reduce the size o
f these blobs |
| 78 // significantly, and then the subrun could just have a refed pointe
r to the |
| 79 // correct descriptor. |
| 80 GrBatchAtlas::BulkUseTokenUpdater fBulkUseToken; |
| 81 uint64_t fAtlasGeneration; |
| 82 size_t fVertexStartIndex; |
| 83 size_t fVertexEndIndex; |
| 84 uint32_t fGlyphStartIndex; |
| 85 uint32_t fGlyphEndIndex; |
| 86 SkScalar fTextRatio; // df property |
| 87 GrMaskFormat fMaskFormat; |
| 88 bool fDrawAsDistanceFields; // df property |
| 89 bool fUseLCDText; // df property |
| 90 }; |
| 91 |
| 92 SubRunInfo& push_back() { |
| 93 // Forward glyph / vertex information to seed the new sub run |
| 94 SubRunInfo& prevSubRun = fSubRunInfo.back(); |
| 95 SubRunInfo& newSubRun = fSubRunInfo.push_back(); |
| 96 newSubRun.fGlyphStartIndex = prevSubRun.fGlyphEndIndex; |
| 97 newSubRun.fGlyphEndIndex = prevSubRun.fGlyphEndIndex; |
| 98 |
| 99 newSubRun.fVertexStartIndex = prevSubRun.fVertexEndIndex; |
| 100 newSubRun.fVertexEndIndex = prevSubRun.fVertexEndIndex; |
| 101 return newSubRun; |
| 102 } |
| 103 static const int kMinSubRuns = 1; |
| 104 SkAutoTUnref<GrBatchTextStrike> fStrike; |
| 105 SkAutoTUnref<SkTypeface> fTypeface; |
| 106 SkRect fVertexBounds; |
| 107 SkSTArray<kMinSubRuns, SubRunInfo> fSubRunInfo; |
| 108 SkAutoDescriptor fDescriptor; |
| 109 SkAutoTDelete<SkAutoDescriptor> fOverrideDescriptor; // df properties |
| 110 GrColor fColor; |
| 111 bool fInitialized; |
| 112 bool fDrawAsPaths; |
| 113 }; |
| 114 |
| 115 struct BigGlyph { |
| 116 BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy) |
| 117 : fPath(path) |
| 118 , fVx(vx) |
| 119 , fVy(vy) {} |
| 120 SkPath fPath; |
| 121 SkScalar fVx; |
| 122 SkScalar fVy; |
| 123 }; |
| 124 |
| 125 struct Key { |
| 126 Key() { |
| 127 sk_bzero(this, sizeof(Key)); |
| 128 } |
| 129 uint32_t fUniqueID; |
| 130 // Color may affect the gamma of the mask we generate, but in a fairly l
imited way. |
| 131 // Each color is assigned to on of a fixed number of buckets based on it
s |
| 132 // luminance. For each luminance bucket there is a "canonical color" tha
t |
| 133 // represents the bucket. This functionality is currently only supporte
d for A8 |
| 134 SkColor fCanonicalColor; |
| 135 SkPaint::Style fStyle; |
| 136 SkPixelGeometry fPixelGeometry; |
| 137 bool fHasBlur; |
| 138 |
| 139 bool operator==(const Key& other) const { |
| 140 return 0 == memcmp(this, &other, sizeof(Key)); |
| 141 } |
| 142 }; |
| 143 |
| 144 struct StrokeInfo { |
| 145 SkScalar fFrameWidth; |
| 146 SkScalar fMiterLimit; |
| 147 SkPaint::Join fJoin; |
| 148 }; |
| 149 |
| 150 enum TextType { |
| 151 kHasDistanceField_TextType = 0x1, |
| 152 kHasBitmap_TextType = 0x2, |
| 153 }; |
| 154 |
| 155 // all glyph / vertex offsets are into these pools. |
| 156 unsigned char* fVertices; |
| 157 GrGlyph** fGlyphs; |
| 158 Run* fRuns; |
| 159 GrMemoryPool* fPool; |
| 160 SkMaskFilter::BlurRec fBlurRec; |
| 161 StrokeInfo fStrokeInfo; |
| 162 SkTArray<BigGlyph> fBigGlyphs; |
| 163 Key fKey; |
| 164 SkMatrix fViewMatrix; |
| 165 SkColor fPaintColor; |
| 166 SkScalar fX; |
| 167 SkScalar fY; |
| 168 |
| 169 // We can reuse distance field text, but only if the new viewmatrix would no
t result in |
| 170 // a mip change. Because there can be multiple runs in a blob, we track the
overall |
| 171 // maximum minimum scale, and minimum maximum scale, we can support before w
e need to regen |
| 172 SkScalar fMaxMinScale; |
| 173 SkScalar fMinMaxScale; |
| 174 int fRunCount; |
| 175 uint8_t fTextType; |
| 176 |
| 177 GrAtlasTextBlob() |
| 178 : fMaxMinScale(-SK_ScalarMax) |
| 179 , fMinMaxScale(SK_ScalarMax) |
| 180 , fTextType(0) {} |
| 181 |
| 182 ~GrAtlasTextBlob() override { |
| 183 for (int i = 0; i < fRunCount; i++) { |
| 184 fRuns[i].~Run(); |
| 185 } |
| 186 } |
| 187 |
| 188 static const Key& GetKey(const GrAtlasTextBlob& blob) { |
| 189 return blob.fKey; |
| 190 } |
| 191 |
| 192 static uint32_t Hash(const Key& key) { |
| 193 return SkChecksum::Murmur3(&key, sizeof(Key)); |
| 194 } |
| 195 |
| 196 void operator delete(void* p) { |
| 197 GrAtlasTextBlob* blob = reinterpret_cast<GrAtlasTextBlob*>(p); |
| 198 blob->fPool->release(p); |
| 199 } |
| 200 void* operator new(size_t) { |
| 201 SkFAIL("All blobs are created by placement new."); |
| 202 return sk_malloc_throw(0); |
| 203 } |
| 204 |
| 205 void* operator new(size_t, void* p) { return p; } |
| 206 void operator delete(void* target, void* placement) { |
| 207 ::operator delete(target, placement); |
| 208 } |
| 209 |
| 210 bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceFiel
d_TextType); } |
| 211 bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); } |
| 212 void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; } |
| 213 void setHasBitmap() { fTextType |= kHasBitmap_TextType; } |
| 214 }; |
| 215 |
| 216 #endif |
OLD | NEW |