OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 #include "GrAtlasTextContext.h" | 7 #include "GrAtlasTextContext.h" |
8 | 8 |
9 #include "GrAtlas.h" | 9 #include "GrAtlas.h" |
10 #include "GrBatch.h" | 10 #include "GrBatch.h" |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 case kARGB_GrMaskFormat: | 53 case kARGB_GrMaskFormat: |
54 return kColorTextVASize; | 54 return kColorTextVASize; |
55 default: | 55 default: |
56 return kLCDTextVASize; | 56 return kLCDTextVASize; |
57 } | 57 } |
58 } | 58 } |
59 | 59 |
60 }; | 60 }; |
61 | 61 |
62 // TODO | 62 // TODO |
63 // More tests | 63 // Gamma slotting to preserve color |
64 // move to SkCache | 64 // Better reuse on regeneration |
65 // handle textblobs where the whole run is larger than the cache size | 65 // Telemetry tests |
66 // TODO implement micro speedy hash map for fast refing of glyphs | 66 // possibly consider having a regeneration ratio on the textblob itself for anim
ated textblobs |
67 | 67 |
68 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, | 68 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, |
69 SkGpuDevice* gpuDevice, | 69 SkGpuDevice* gpuDevice, |
70 const SkDeviceProperties& properties) | 70 const SkDeviceProperties& properties) |
71 : INHERITED(context, gpuDevice, properties) { | 71 : INHERITED(context, gpuDevice, properties) { |
72 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest | 72 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest |
73 // vertexStride | 73 // vertexStride |
74 SK_COMPILE_ASSERT(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >=
kLCDTextVASize, | 74 SK_COMPILE_ASSERT(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >=
kLCDTextVASize, |
75 vertex_attribute_changed); | 75 vertex_attribute_changed); |
76 fCurrStrike = NULL; | 76 fCurrStrike = NULL; |
77 fCache = context->getTextBlobCache(); | 77 fCache = context->getTextBlobCache(); |
78 } | 78 } |
79 | 79 |
80 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, | 80 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, |
81 SkGpuDevice* gpuDevice, | 81 SkGpuDevice* gpuDevice, |
82 const SkDeviceProperties& props)
{ | 82 const SkDeviceProperties& props)
{ |
83 return SkNEW_ARGS(GrAtlasTextContext, (context, gpuDevice, props)); | 83 return SkNEW_ARGS(GrAtlasTextContext, (context, gpuDevice, props)); |
84 } | 84 } |
85 | 85 |
86 bool GrAtlasTextContext::canDraw(const GrRenderTarget*, | 86 bool GrAtlasTextContext::canDraw(const GrRenderTarget*, |
87 const GrClip&, | 87 const GrClip&, |
88 const GrPaint&, | 88 const GrPaint&, |
89 const SkPaint& skPaint, | 89 const SkPaint& skPaint, |
90 const SkMatrix& viewMatrix) { | 90 const SkMatrix& viewMatrix) { |
91 return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); | 91 return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); |
92 } | 92 } |
93 | 93 |
94 bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTr
ansY, | 94 bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTr
ansY, |
95 const BitmapTextBlob& blob, const Sk
Paint& paint, | 95 const BitmapTextBlob& blob, const Sk
Paint& paint, |
| 96 const SkMaskFilter::BlurRec& blurRec
, |
96 const SkMatrix& viewMatrix, SkScalar
x, SkScalar y) { | 97 const SkMatrix& viewMatrix, SkScalar
x, SkScalar y) { |
97 // Color can affect the mask | 98 // Color can affect the mask |
98 // TODO we can adjust the color within specific gamma slots | 99 // TODO we can adjust the color within specific gamma slots |
99 if (blob.fColor != paint.getColor()) { | 100 if (blob.fColor != paint.getColor()) { |
100 return true; | 101 return true; |
101 } | 102 } |
102 | 103 |
103 if (blob.fViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) { | 104 if (blob.fViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) { |
104 return true; | 105 return true; |
105 } | 106 } |
106 | 107 |
107 if (blob.fViewMatrix.hasPerspective() && !blob.fViewMatrix.cheapEqualTo(view
Matrix)) { | 108 if (blob.fViewMatrix.hasPerspective() && !blob.fViewMatrix.cheapEqualTo(view
Matrix)) { |
108 return true; | 109 return true; |
109 } | 110 } |
110 | 111 |
111 if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() || | 112 if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() || |
112 blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() || | 113 blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() || |
113 blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() || | 114 blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() || |
114 blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) { | 115 blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) { |
115 return true; | 116 return true; |
116 } | 117 } |
117 | 118 |
| 119 // We only cache one masked version |
| 120 if (blob.fKey.fHasBlur && |
| 121 (blob.fBlurRec.fSigma != blurRec.fSigma || |
| 122 blob.fBlurRec.fStyle != blurRec.fStyle || |
| 123 blob.fBlurRec.fQuality != blurRec.fQuality)) { |
| 124 return true; |
| 125 } |
| 126 |
| 127 // Similarly, we only cache one version for each style |
| 128 if (blob.fKey.fStyle != SkPaint::kFill_Style && |
| 129 (blob.fStrokeInfo.fFrameWidth != paint.getStrokeWidth() || |
| 130 blob.fStrokeInfo.fMiterLimit != paint.getStrokeMiter() || |
| 131 blob.fStrokeInfo.fJoin != paint.getStrokeJoin())) { |
| 132 return true; |
| 133 } |
| 134 |
118 // We can update the positions in the cachedtextblobs without regenerating t
he whole blob, but | 135 // We can update the positions in the cachedtextblobs without regenerating t
he whole blob, but |
119 // only for integer translations. | 136 // only for integer translations. |
120 // This cool bit of math will determine the necessary translation to apply t
o the already | 137 // This cool bit of math will determine the necessary translation to apply t
o the already |
121 // generated vertex coordinates to move them to the correct position | 138 // generated vertex coordinates to move them to the correct position |
122 SkScalar transX = viewMatrix.getTranslateX() + | 139 SkScalar transX = viewMatrix.getTranslateX() + |
123 viewMatrix.getScaleX() * (x - blob.fX) + | 140 viewMatrix.getScaleX() * (x - blob.fX) + |
124 viewMatrix.getSkewX() * (y - blob.fY) - | 141 viewMatrix.getSkewX() * (y - blob.fY) - |
125 blob.fViewMatrix.getTranslateX(); | 142 blob.fViewMatrix.getTranslateX(); |
126 SkScalar transY = viewMatrix.getTranslateY() + | 143 SkScalar transY = viewMatrix.getTranslateY() + |
127 viewMatrix.getSkewY() * (x - blob.fX) + | 144 viewMatrix.getSkewY() * (x - blob.fX) + |
(...skipping 27 matching lines...) Expand all Loading... |
155 const SkMatrix& viewMatrix)
{ | 172 const SkMatrix& viewMatrix)
{ |
156 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &v
iewMatrix, false); | 173 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &v
iewMatrix, false); |
157 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); | 174 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); |
158 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc())
; | 175 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc())
; |
159 } | 176 } |
160 | 177 |
161 void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, | 178 void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, |
162 const SkPaint& skPaint, const SkMatrix& vi
ewMatrix, | 179 const SkPaint& skPaint, const SkMatrix& vi
ewMatrix, |
163 const SkTextBlob* blob, SkScalar x, SkScal
ar y, | 180 const SkTextBlob* blob, SkScalar x, SkScal
ar y, |
164 SkDrawFilter* drawFilter, const SkIRect& c
lipBounds) { | 181 SkDrawFilter* drawFilter, const SkIRect& c
lipBounds) { |
165 uint32_t uniqueID = blob->uniqueID(); | |
166 SkAutoTUnref<BitmapTextBlob> cacheBlob; | 182 SkAutoTUnref<BitmapTextBlob> cacheBlob; |
167 // TODO start caching these, mix bits into the key | 183 |
| 184 SkMaskFilter::BlurRec blurRec; |
| 185 BitmapTextBlob::Key key; |
| 186 // It might be worth caching these things, but its not clear at this time |
| 187 // TODO for animated mask filters, this will fill up our cache. We need a s
afeguard here |
| 188 const SkMaskFilter* mf = skPaint.getMaskFilter(); |
168 bool canCache = !(skPaint.getPathEffect() || | 189 bool canCache = !(skPaint.getPathEffect() || |
169 skPaint.getMaskFilter() || | 190 (mf && !mf->asABlur(&blurRec)) || |
170 skPaint.getColorFilter() || | |
171 skPaint.getStyle() != SkPaint::kFill_Style || | |
172 drawFilter); | 191 drawFilter); |
173 | 192 |
174 if (canCache) { | 193 if (canCache) { |
175 cacheBlob.reset(SkSafeRef(fCache->find(uniqueID))); | 194 key.fUniqueID = blob->uniqueID(); |
| 195 key.fStyle = skPaint.getStyle(); |
| 196 key.fHasBlur = SkToBool(mf); |
| 197 cacheBlob.reset(SkSafeRef(fCache->find(key))); |
176 } | 198 } |
177 | 199 |
178 SkIRect clipRect; | 200 SkIRect clipRect; |
179 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); | 201 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); |
180 | 202 |
181 SkScalar transX = 0.f; | 203 SkScalar transX = 0.f; |
182 SkScalar transY = 0.f; | 204 SkScalar transY = 0.f; |
183 | 205 |
184 if (cacheBlob) { | 206 if (cacheBlob) { |
185 if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, viewMatrix
, x, y)) { | 207 if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, blurRec, v
iewMatrix, x, y)) { |
186 // We have to remake the blob because changes may invalidate our mas
ks. | 208 // We have to remake the blob because changes may invalidate our mas
ks. |
187 // TODO we could probably get away reuse most of the time if the poi
nter is unique, | 209 // TODO we could probably get away reuse most of the time if the poi
nter is unique, |
188 // but we'd have to clear the subrun information | 210 // but we'd have to clear the subrun information |
189 fCache->remove(cacheBlob); | 211 fCache->remove(cacheBlob); |
190 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, kGrayTextVASize
))); | 212 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, s
kPaint, |
| 213 kGrayTextVASize))); |
191 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y,
drawFilter, | 214 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y,
drawFilter, |
192 clipRect); | 215 clipRect); |
193 } else { | 216 } else { |
194 // If we can reuse the blob, then make sure we update the blob's vie
wmatrix and x/y | 217 // If we can reuse the blob, then make sure we update the blob's vie
wmatrix and x/y |
195 // offsets to reflect the results of any translations we may apply i
n generateGeometry | 218 // offsets to reflect the results of any translations we may apply i
n generateGeometry |
196 cacheBlob->fViewMatrix = viewMatrix; | 219 cacheBlob->fViewMatrix = viewMatrix; |
197 cacheBlob->fX = x; | 220 cacheBlob->fX = x; |
198 cacheBlob->fY = y; | 221 cacheBlob->fY = y; |
199 fCache->makeMRU(cacheBlob); | 222 fCache->makeMRU(cacheBlob); |
200 } | 223 } |
201 } else { | 224 } else { |
202 if (canCache) { | 225 if (canCache) { |
203 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, kGrayTextVASize
))); | 226 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, s
kPaint, |
| 227 kGrayTextVASize))); |
204 } else { | 228 } else { |
205 cacheBlob.reset(fCache->createBlob(blob, kGrayTextVASize)); | 229 cacheBlob.reset(fCache->createBlob(blob, kGrayTextVASize)); |
206 } | 230 } |
207 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, dra
wFilter, clipRect); | 231 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, dra
wFilter, clipRect); |
208 } | 232 } |
209 | 233 |
210 // Though for the time being runs in the textblob can override the paint, th
ey only touch font | 234 // Though for the time being runs in the textblob can override the paint, th
ey only touch font |
211 // info. | 235 // info. |
212 GrPaint grPaint; | 236 GrPaint grPaint; |
213 SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint); | 237 SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint); |
214 | 238 |
215 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint
, drawFilter, | 239 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint
, drawFilter, |
216 clip, viewMatrix, clipBounds, x, y, transX, transY); | 240 clip, viewMatrix, clipBounds, x, y, transX, transY); |
217 } | 241 } |
218 | 242 |
219 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, | 243 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, |
220 const SkPaint& skPaint, const SkMatr
ix& viewMatrix, | 244 const SkPaint& skPaint, const SkMatr
ix& viewMatrix, |
221 const SkTextBlob* blob, SkScalar x,
SkScalar y, | 245 const SkTextBlob* blob, SkScalar x,
SkScalar y, |
222 SkDrawFilter* drawFilter, const SkIR
ect& clipRect) { | 246 SkDrawFilter* drawFilter, const SkIR
ect& clipRect) { |
223 cacheBlob->fViewMatrix = viewMatrix; | 247 cacheBlob->fViewMatrix = viewMatrix; |
224 cacheBlob->fX = x; | 248 cacheBlob->fX = x; |
225 cacheBlob->fY = y; | 249 cacheBlob->fY = y; |
226 cacheBlob->fColor = skPaint.getColor(); | 250 cacheBlob->fColor = skPaint.getColor(); |
227 cacheBlob->fStyle = skPaint.getStyle(); | |
228 | 251 |
229 // Regenerate textblob | 252 // Regenerate textblob |
230 SkPaint runPaint = skPaint; | 253 SkPaint runPaint = skPaint; |
231 SkTextBlob::RunIterator it(blob); | 254 SkTextBlob::RunIterator it(blob); |
232 for (int run = 0; !it.done(); it.next(), run++) { | 255 for (int run = 0; !it.done(); it.next(), run++) { |
233 int glyphCount = it.glyphCount(); | 256 int glyphCount = it.glyphCount(); |
234 size_t textLen = glyphCount * sizeof(uint16_t); | 257 size_t textLen = glyphCount * sizeof(uint16_t); |
235 const SkPoint& offset = it.offset(); | 258 const SkPoint& offset = it.offset(); |
236 // applyFontToPaint() always overwrites the exact same attributes, | 259 // applyFontToPaint() always overwrites the exact same attributes, |
237 // so it is safe to not re-seed the paint for this reason. | 260 // so it is safe to not re-seed the paint for this reason. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, | 318 void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, |
296 const GrPaint& paint, const SkPaint& skPaint
, | 319 const GrPaint& paint, const SkPaint& skPaint
, |
297 const SkMatrix& viewMatrix, | 320 const SkMatrix& viewMatrix, |
298 const char text[], size_t byteLength, | 321 const char text[], size_t byteLength, |
299 SkScalar x, SkScalar y, const SkIRect& regio
nClipBounds) { | 322 SkScalar x, SkScalar y, const SkIRect& regio
nClipBounds) { |
300 int glyphCount = skPaint.countText(text, byteLength); | 323 int glyphCount = skPaint.countText(text, byteLength); |
301 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTex
tVASize)); | 324 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTex
tVASize)); |
302 blob->fViewMatrix = viewMatrix; | 325 blob->fViewMatrix = viewMatrix; |
303 blob->fX = x; | 326 blob->fX = x; |
304 blob->fY = y; | 327 blob->fY = y; |
305 blob->fStyle = skPaint.getStyle(); | |
306 | 328 |
307 SkIRect clipRect; | 329 SkIRect clipRect; |
308 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); | 330 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); |
309 | 331 |
310 // setup cache | 332 // setup cache |
311 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix)
; | 333 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix)
; |
312 this->internalDrawText(blob, 0, cache, skPaint, viewMatrix, text, byteLength
, x, y, clipRect); | 334 this->internalDrawText(blob, 0, cache, skPaint, viewMatrix, text, byteLength
, x, y, clipRect); |
313 SkGlyphCache::AttachCache(cache); | 335 SkGlyphCache::AttachCache(cache); |
314 | 336 |
315 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, viewM
atrix); | 337 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, viewM
atrix); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 } | 428 } |
407 | 429 |
408 void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, | 430 void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, |
409 const GrPaint& paint, const SkPaint& skPa
int, | 431 const GrPaint& paint, const SkPaint& skPa
int, |
410 const SkMatrix& viewMatrix, | 432 const SkMatrix& viewMatrix, |
411 const char text[], size_t byteLength, | 433 const char text[], size_t byteLength, |
412 const SkScalar pos[], int scalarsPerPosit
ion, | 434 const SkScalar pos[], int scalarsPerPosit
ion, |
413 const SkPoint& offset, const SkIRect& reg
ionClipBounds) { | 435 const SkPoint& offset, const SkIRect& reg
ionClipBounds) { |
414 int glyphCount = skPaint.countText(text, byteLength); | 436 int glyphCount = skPaint.countText(text, byteLength); |
415 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTex
tVASize)); | 437 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTex
tVASize)); |
416 blob->fStyle = skPaint.getStyle(); | |
417 blob->fViewMatrix = viewMatrix; | 438 blob->fViewMatrix = viewMatrix; |
418 | 439 |
419 SkIRect clipRect; | 440 SkIRect clipRect; |
420 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); | 441 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); |
421 | 442 |
422 // setup cache | 443 // setup cache |
423 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix)
; | 444 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix)
; |
424 this->internalDrawPosText(blob, 0, cache, skPaint, viewMatrix, text, byteLen
gth, pos, | 445 this->internalDrawPosText(blob, 0, cache, skPaint, viewMatrix, text, byteLen
gth, pos, |
425 scalarsPerPosition, offset, clipRect); | 446 scalarsPerPosition, offset, clipRect); |
426 SkGlyphCache::AttachCache(cache); | 447 SkGlyphCache::AttachCache(cache); |
(...skipping 784 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1211 | 1232 |
1212 GrColor color = grPaint.getColor(); | 1233 GrColor color = grPaint.getColor(); |
1213 uint8_t paintAlpha = skPaint.getAlpha(); | 1234 uint8_t paintAlpha = skPaint.getAlpha(); |
1214 for (int run = 0; run < cacheBlob->fRunCount; run++) { | 1235 for (int run = 0; run < cacheBlob->fRunCount; run++) { |
1215 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp
ha, 0, 0); | 1236 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp
ha, 0, 0); |
1216 } | 1237 } |
1217 | 1238 |
1218 // Now flush big glyphs | 1239 // Now flush big glyphs |
1219 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); | 1240 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); |
1220 } | 1241 } |
OLD | NEW |