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