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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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(const BitmapTextBlob& blob, const Sk
Paint& paint, | 94 bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTr
ansY, |
| 95 const BitmapTextBlob& blob, const Sk
Paint& paint, |
95 const SkMatrix& viewMatrix, SkScalar
x, SkScalar y) { | 96 const SkMatrix& viewMatrix, SkScalar
x, SkScalar y) { |
96 // We always regenerate blobs with patheffects or mask filters we could cach
e these | 97 // Color can affect the mask |
97 // TODO find some way to cache the maskfilter / patheffects on the textblob | 98 // TODO we can adjust the color within specific gamma slots |
98 return !blob.fViewMatrix.cheapEqualTo(viewMatrix) || blob.fX != x || blob.fY
!= y || | 99 if (blob.fColor != paint.getColor()) { |
99 paint.getMaskFilter() || paint.getPathEffect() || paint.getStyle() !
= blob.fStyle; | 100 return true; |
| 101 } |
| 102 |
| 103 if (blob.fViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) { |
| 104 return true; |
| 105 } |
| 106 |
| 107 if (blob.fViewMatrix.hasPerspective() && !blob.fViewMatrix.cheapEqualTo(view
Matrix)) { |
| 108 return true; |
| 109 } |
| 110 |
| 111 if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() || |
| 112 blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() || |
| 113 blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() || |
| 114 blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) { |
| 115 return true; |
| 116 } |
| 117 |
| 118 // We can update the positions in the cachedtextblobs without regenerating t
he whole blob, but |
| 119 // only for integer translations. |
| 120 // 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 |
| 122 SkScalar transX = viewMatrix.getTranslateX() + |
| 123 viewMatrix.getScaleX() * (x - blob.fX) + |
| 124 viewMatrix.getSkewX() * (y - blob.fY) - |
| 125 blob.fViewMatrix.getTranslateX(); |
| 126 SkScalar transY = viewMatrix.getTranslateY() + |
| 127 viewMatrix.getSkewY() * (x - blob.fX) + |
| 128 viewMatrix.getScaleY() * (y - blob.fY) - |
| 129 blob.fViewMatrix.getTranslateY(); |
| 130 if (SkScalarFraction(transX) > SK_ScalarNearlyZero || |
| 131 SkScalarFraction(transY) > SK_ScalarNearlyZero) { |
| 132 return true; |
| 133 } |
| 134 |
| 135 #ifdef SK_DEBUG |
| 136 static const SkScalar kMinDiscernableTranslation = 0.0625; |
| 137 // As a safeguard when debugging, we store the total error across all transl
ations and print if |
| 138 // the error becomes discernable. This is pretty unlikely to occur given th
e tight bounds above |
| 139 // on translation |
| 140 blob.fTotalXError += SkScalarAbs(SkScalarFraction(transX)); |
| 141 blob.fTotalYError += SkScalarAbs(SkScalarFraction(transY)); |
| 142 if (blob.fTotalXError > kMinDiscernableTranslation || |
| 143 blob.fTotalYError > kMinDiscernableTranslation) { |
| 144 SkDebugf("Exceeding error threshold for bitmap text translation"); |
| 145 } |
| 146 #endif |
| 147 (*outTransX) = transX; |
| 148 (*outTransY) = transY; |
| 149 return false; |
100 } | 150 } |
101 | 151 |
102 | 152 |
103 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, | 153 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, |
104 const SkPaint& skPaint, | 154 const SkPaint& skPaint, |
105 const SkMatrix& viewMatrix)
{ | 155 const SkMatrix& viewMatrix)
{ |
106 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &v
iewMatrix, false); | 156 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &v
iewMatrix, false); |
107 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); | 157 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); |
108 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc())
; | 158 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc())
; |
109 } | 159 } |
110 | 160 |
111 void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, | 161 void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, |
112 const SkPaint& skPaint, const SkMatrix& vi
ewMatrix, | 162 const SkPaint& skPaint, const SkMatrix& vi
ewMatrix, |
113 const SkTextBlob* blob, SkScalar x, SkScal
ar y, | 163 const SkTextBlob* blob, SkScalar x, SkScal
ar y, |
114 SkDrawFilter* drawFilter, const SkIRect& c
lipBounds) { | 164 SkDrawFilter* drawFilter, const SkIRect& c
lipBounds) { |
115 uint32_t uniqueID = blob->uniqueID(); | 165 uint32_t uniqueID = blob->uniqueID(); |
116 BitmapTextBlob* cacheBlob = fCache->find(uniqueID); | 166 SkAutoTUnref<BitmapTextBlob> cacheBlob; |
| 167 // TODO start caching these, mix bits into the key |
| 168 bool canCache = !(skPaint.getPathEffect() || |
| 169 skPaint.getMaskFilter() || |
| 170 skPaint.getColorFilter() || |
| 171 skPaint.getStyle() != SkPaint::kFill_Style || |
| 172 drawFilter); |
| 173 |
| 174 if (canCache) { |
| 175 cacheBlob.reset(SkSafeRef(fCache->find(uniqueID))); |
| 176 } |
| 177 |
117 SkIRect clipRect; | 178 SkIRect clipRect; |
118 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); | 179 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); |
119 | 180 |
| 181 SkScalar transX = 0.f; |
| 182 SkScalar transY = 0.f; |
| 183 |
120 if (cacheBlob) { | 184 if (cacheBlob) { |
121 if (MustRegenerateBlob(*cacheBlob, skPaint, viewMatrix, x, y)) { | 185 if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, viewMatrix
, x, y)) { |
122 // We have to remake the blob because changes may invalidate our mas
ks. | 186 // We have to remake the blob because changes may invalidate our mas
ks. |
123 // TODO we could probably get away reuse most of the time if the poi
nter is unique, | 187 // TODO we could probably get away reuse most of the time if the poi
nter is unique, |
124 // but we'd have to clear the subrun information | 188 // but we'd have to clear the subrun information |
125 fCache->remove(cacheBlob); | 189 fCache->remove(cacheBlob); |
126 cacheBlob = fCache->createCachedBlob(blob, kGrayTextVASize); | 190 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, kGrayTextVASize
))); |
127 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y,
drawFilter, | 191 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y,
drawFilter, |
128 clipRect); | 192 clipRect); |
129 } else { | 193 } else { |
| 194 // 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 |
| 196 cacheBlob->fViewMatrix = viewMatrix; |
| 197 cacheBlob->fX = x; |
| 198 cacheBlob->fY = y; |
130 fCache->makeMRU(cacheBlob); | 199 fCache->makeMRU(cacheBlob); |
131 } | 200 } |
132 } else { | 201 } else { |
133 cacheBlob = fCache->createCachedBlob(blob, kGrayTextVASize); | 202 if (canCache) { |
| 203 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, kGrayTextVASize
))); |
| 204 } else { |
| 205 cacheBlob.reset(fCache->createBlob(blob, kGrayTextVASize)); |
| 206 } |
134 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, dra
wFilter, clipRect); | 207 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, dra
wFilter, clipRect); |
135 } | 208 } |
136 | 209 |
137 // Though for the time being runs in the textblob can override the paint, th
ey only touch font | 210 // Though for the time being runs in the textblob can override the paint, th
ey only touch font |
138 // info. | 211 // info. |
139 GrPaint grPaint; | 212 GrPaint grPaint; |
140 SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint); | 213 SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint); |
141 | 214 |
142 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint
, drawFilter, | 215 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint
, drawFilter, |
143 clip, viewMatrix, clipBounds, x, y); | 216 clip, viewMatrix, clipBounds, x, y, transX, transY); |
144 } | 217 } |
145 | 218 |
146 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, | 219 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, |
147 const SkPaint& skPaint, const SkMatr
ix& viewMatrix, | 220 const SkPaint& skPaint, const SkMatr
ix& viewMatrix, |
148 const SkTextBlob* blob, SkScalar x,
SkScalar y, | 221 const SkTextBlob* blob, SkScalar x,
SkScalar y, |
149 SkDrawFilter* drawFilter, const SkIR
ect& clipRect) { | 222 SkDrawFilter* drawFilter, const SkIR
ect& clipRect) { |
150 cacheBlob->fViewMatrix = viewMatrix; | 223 cacheBlob->fViewMatrix = viewMatrix; |
151 cacheBlob->fX = x; | 224 cacheBlob->fX = x; |
152 cacheBlob->fY = y; | 225 cacheBlob->fY = y; |
| 226 cacheBlob->fColor = skPaint.getColor(); |
153 cacheBlob->fStyle = skPaint.getStyle(); | 227 cacheBlob->fStyle = skPaint.getStyle(); |
154 | 228 |
155 // Regenerate textblob | 229 // Regenerate textblob |
156 SkPaint runPaint = skPaint; | 230 SkPaint runPaint = skPaint; |
157 SkTextBlob::RunIterator it(blob); | 231 SkTextBlob::RunIterator it(blob); |
158 for (int run = 0; !it.done(); it.next(), run++) { | 232 for (int run = 0; !it.done(); it.next(), run++) { |
159 int glyphCount = it.glyphCount(); | 233 int glyphCount = it.glyphCount(); |
160 size_t textLen = glyphCount * sizeof(uint16_t); | 234 size_t textLen = glyphCount * sizeof(uint16_t); |
161 const SkPoint& offset = it.offset(); | 235 const SkPoint& offset = it.offset(); |
162 // applyFontToPaint() always overwrites the exact same attributes, | 236 // applyFontToPaint() always overwrites the exact same attributes, |
(...skipping 15 matching lines...) Expand all Loading... |
178 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back(); | 252 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back(); |
179 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back(
); | 253 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back(
); |
180 | 254 |
181 newRun.fVertexStartIndex = lastRun.fVertexEndIndex; | 255 newRun.fVertexStartIndex = lastRun.fVertexEndIndex; |
182 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; | 256 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; |
183 | 257 |
184 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; | 258 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; |
185 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; | 259 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; |
186 } | 260 } |
187 | 261 |
188 if (SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix)) { | 262 if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { |
189 cacheBlob->fRuns[run].fDrawAsPaths = true; | 263 cacheBlob->fRuns[run].fDrawAsPaths = true; |
190 continue; | 264 continue; |
191 } | 265 } |
192 cacheBlob->fRuns[run].fDrawAsPaths = false; | 266 cacheBlob->fRuns[run].fDrawAsPaths = false; |
193 | 267 |
194 switch (it.positioning()) { | 268 switch (it.positioning()) { |
195 case SkTextBlob::kDefault_Positioning: | 269 case SkTextBlob::kDefault_Positioning: |
196 this->internalDrawText(cacheBlob, run, cache, runPaint, viewMatr
ix, | 270 this->internalDrawText(cacheBlob, run, cache, runPaint, viewMatr
ix, |
197 (const char *)it.glyphs(), textLen, | 271 (const char *)it.glyphs(), textLen, |
198 x + offset.x(), y + offset.y(), clipRect)
; | 272 x + offset.x(), y + offset.y(), clipRect)
; |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
529 return; | 603 return; |
530 } | 604 } |
531 | 605 |
532 int x = vx + glyph->fBounds.fLeft; | 606 int x = vx + glyph->fBounds.fLeft; |
533 int y = vy + glyph->fBounds.fTop; | 607 int y = vy + glyph->fBounds.fTop; |
534 | 608 |
535 // keep them as ints until we've done the clip-test | 609 // keep them as ints until we've done the clip-test |
536 int width = glyph->fBounds.width(); | 610 int width = glyph->fBounds.width(); |
537 int height = glyph->fBounds.height(); | 611 int height = glyph->fBounds.height(); |
538 | 612 |
| 613 #if 0 |
| 614 // Not checking the clip bounds might introduce a performance regression. H
owever, its not |
| 615 // clear if this is still true today with the larger tiles we use in Chrome.
For repositionable |
| 616 // blobs, we want to make sure we have all of the glyphs, so clipping them o
ut is not ideal. |
| 617 // We could store the cliprect in the key, but then we'd lose the ability to
do integer scrolls |
| 618 // TODO verify this |
539 // check if we clipped out | 619 // check if we clipped out |
540 if (clipRect.quickReject(x, y, x + width, y + height)) { | 620 if (clipRect.quickReject(x, y, x + width, y + height)) { |
541 return; | 621 return; |
542 } | 622 } |
| 623 #endif |
543 | 624 |
544 // If the glyph is too large we fall back to paths | 625 // If the glyph is too large we fall back to paths |
545 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) { | 626 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) { |
546 if (NULL == glyph->fPath) { | 627 if (NULL == glyph->fPath) { |
547 SkPath* path = SkNEW(SkPath); | 628 SkPath* path = SkNEW(SkPath); |
548 if (!scaler->getGlyphPath(glyph->glyphID(), path)) { | 629 if (!scaler->getGlyphPath(glyph->glyphID(), path)) { |
549 // flag the glyph as being dead? | 630 // flag the glyph as being dead? |
550 SkDELETE(path); | 631 SkDELETE(path); |
551 return; | 632 return; |
552 } | 633 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert
exEndIndex); | 672 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert
exEndIndex); |
592 | 673 |
593 // V0 | 674 // V0 |
594 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); | 675 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); |
595 position->set(r.fLeft, r.fTop); | 676 position->set(r.fLeft, r.fTop); |
596 if (kA8_GrMaskFormat == format) { | 677 if (kA8_GrMaskFormat == format) { |
597 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint))
; | 678 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint))
; |
598 *colorPtr = color; | 679 *colorPtr = color; |
599 } | 680 } |
600 vertex += vertexStride; | 681 vertex += vertexStride; |
601 | |
602 // V1 | 682 // V1 |
603 position = reinterpret_cast<SkPoint*>(vertex); | 683 position = reinterpret_cast<SkPoint*>(vertex); |
604 position->set(r.fLeft, r.fBottom); | 684 position->set(r.fLeft, r.fBottom); |
605 if (kA8_GrMaskFormat == format) { | 685 if (kA8_GrMaskFormat == format) { |
606 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint))
; | 686 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint))
; |
607 *colorPtr = color; | 687 *colorPtr = color; |
608 } | 688 } |
609 vertex += vertexStride; | 689 vertex += vertexStride; |
610 | 690 |
611 // V2 | 691 // V2 |
(...skipping 21 matching lines...) Expand all Loading... |
633 public: | 713 public: |
634 typedef GrAtlasTextContext::BitmapTextBlob Blob; | 714 typedef GrAtlasTextContext::BitmapTextBlob Blob; |
635 typedef Blob::Run Run; | 715 typedef Blob::Run Run; |
636 typedef Run::SubRunInfo TextInfo; | 716 typedef Run::SubRunInfo TextInfo; |
637 struct Geometry { | 717 struct Geometry { |
638 Geometry() {} | 718 Geometry() {} |
639 Geometry(const Geometry& geometry) | 719 Geometry(const Geometry& geometry) |
640 : fBlob(SkRef(geometry.fBlob.get())) | 720 : fBlob(SkRef(geometry.fBlob.get())) |
641 , fRun(geometry.fRun) | 721 , fRun(geometry.fRun) |
642 , fSubRun(geometry.fSubRun) | 722 , fSubRun(geometry.fSubRun) |
643 , fColor(geometry.fColor) {} | 723 , fColor(geometry.fColor) |
| 724 , fTransX(geometry.fTransX) |
| 725 , fTransY(geometry.fTransY) {} |
644 SkAutoTUnref<Blob> fBlob; | 726 SkAutoTUnref<Blob> fBlob; |
645 int fRun; | 727 int fRun; |
646 int fSubRun; | 728 int fSubRun; |
647 GrColor fColor; | 729 GrColor fColor; |
| 730 SkScalar fTransX; |
| 731 SkScalar fTransY; |
648 }; | 732 }; |
649 | 733 |
650 static GrBatch* Create(const Geometry& geometry, GrMaskFormat maskFormat, | 734 static GrBatch* Create(const Geometry& geometry, GrMaskFormat maskFormat, |
651 int glyphCount, GrBatchFontCache* fontCache) { | 735 int glyphCount, GrBatchFontCache* fontCache) { |
652 return SkNEW_ARGS(BitmapTextBatch, (geometry, maskFormat, glyphCount, fo
ntCache)); | 736 return SkNEW_ARGS(BitmapTextBatch, (geometry, maskFormat, glyphCount, fo
ntCache)); |
653 } | 737 } |
654 | 738 |
655 const char* name() const override { return "BitmapTextBatch"; } | 739 const char* name() const override { return "BitmapTextBatch"; } |
656 | 740 |
657 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | 741 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
757 int instancesToFlush = 0; | 841 int instancesToFlush = 0; |
758 for (int i = 0; i < instanceCount; i++) { | 842 for (int i = 0; i < instanceCount; i++) { |
759 Geometry& args = fGeoData[i]; | 843 Geometry& args = fGeoData[i]; |
760 Blob* blob = args.fBlob; | 844 Blob* blob = args.fBlob; |
761 Run& run = blob->fRuns[args.fRun]; | 845 Run& run = blob->fRuns[args.fRun]; |
762 TextInfo& info = run.fSubRunInfo[args.fSubRun]; | 846 TextInfo& info = run.fSubRunInfo[args.fSubRun]; |
763 | 847 |
764 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat); | 848 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat); |
765 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas
Gen; | 849 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas
Gen; |
766 bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColo
r != args.fColor; | 850 bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColo
r != args.fColor; |
| 851 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.
f; |
767 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; | 852 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; |
768 | 853 |
769 // We regenerate both texture coords and colors in the blob itself,
and update the | 854 // We regenerate both texture coords and colors in the blob itself,
and update the |
770 // atlas generation. If we don't end up purging any unused plots, w
e can avoid | 855 // atlas generation. If we don't end up purging any unused plots, w
e can avoid |
771 // regenerating the coords. We could take a finer grained approach
to updating texture | 856 // regenerating the coords. We could take a finer grained approach
to updating texture |
772 // coords but its not clear if the extra bookkeeping would offset an
y gains. | 857 // coords but its not clear if the extra bookkeeping would offset an
y gains. |
773 // To avoid looping over the glyphs twice, we do one loop and condit
ionally update color | 858 // To avoid looping over the glyphs twice, we do one loop and condit
ionally update color |
774 // or coords as needed. One final note, if we have to break a run f
or an atlas eviction | 859 // or coords as needed. One final note, if we have to break a run f
or an atlas eviction |
775 // then we can't really trust the atlas has all of the correct data.
Atlas evictions | 860 // then we can't really trust the atlas has all of the correct data.
Atlas evictions |
776 // should be pretty rare, so we just always regenerate in those case
s | 861 // should be pretty rare, so we just always regenerate in those case
s |
777 if (regenerateTextureCoords || regenerateColors) { | 862 if (regenerateTextureCoords || regenerateColors || regeneratePositio
ns) { |
778 // first regenerate texture coordinates / colors if need be | 863 // first regenerate texture coordinates / colors if need be |
779 const SkDescriptor* desc = NULL; | 864 const SkDescriptor* desc = NULL; |
780 SkGlyphCache* cache = NULL; | 865 SkGlyphCache* cache = NULL; |
781 GrFontScaler* scaler = NULL; | 866 GrFontScaler* scaler = NULL; |
782 GrBatchTextStrike* strike = NULL; | 867 GrBatchTextStrike* strike = NULL; |
783 bool brokenRun = false; | 868 bool brokenRun = false; |
784 if (regenerateTextureCoords) { | 869 if (regenerateTextureCoords) { |
785 info.fBulkUseToken.reset(); | 870 info.fBulkUseToken.reset(); |
786 desc = run.fDescriptor.getDesc(); | 871 desc = run.fDescriptor.getDesc(); |
787 cache = SkGlyphCache::DetachCache(run.fTypeface, desc); | 872 cache = SkGlyphCache::DetachCache(run.fTypeface, desc); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
821 this->regenerateTextureCoords(glyph, vertex, vertexStrid
e); | 906 this->regenerateTextureCoords(glyph, vertex, vertexStrid
e); |
822 } | 907 } |
823 | 908 |
824 if (regenerateColors) { | 909 if (regenerateColors) { |
825 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert
ices); | 910 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert
ices); |
826 vertex += info.fVertexStartIndex; | 911 vertex += info.fVertexStartIndex; |
827 vertex += vertexStride * glyphIdx * kVerticesPerGlyph +
sizeof(SkPoint); | 912 vertex += vertexStride * glyphIdx * kVerticesPerGlyph +
sizeof(SkPoint); |
828 this->regenerateColors(vertex, vertexStride, args.fColor
); | 913 this->regenerateColors(vertex, vertexStride, args.fColor
); |
829 } | 914 } |
830 | 915 |
| 916 if (regeneratePositions) { |
| 917 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert
ices); |
| 918 vertex += info.fVertexStartIndex; |
| 919 vertex += vertexStride * glyphIdx * kVerticesPerGlyph; |
| 920 SkScalar transX = args.fTransX; |
| 921 SkScalar transY = args.fTransY; |
| 922 this->regeneratePositions(vertex, vertexStride, transX,
transY); |
| 923 } |
831 instancesToFlush++; | 924 instancesToFlush++; |
832 } | 925 } |
833 | 926 |
| 927 // We my have changed the color so update it here |
| 928 run.fColor = args.fColor; |
834 if (regenerateTextureCoords) { | 929 if (regenerateTextureCoords) { |
835 SkGlyphCache::AttachCache(cache); | 930 SkGlyphCache::AttachCache(cache); |
836 info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAt
lasGeneration : | 931 info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAt
lasGeneration : |
837 fFontCache->atlasGenerat
ion(fMaskFormat); | 932 fFontCache->atlasGenerat
ion(fMaskFormat); |
838 } | 933 } |
839 } else { | 934 } else { |
840 instancesToFlush += glyphCount; | 935 instancesToFlush += glyphCount; |
841 | 936 |
842 // set use tokens for all of the glyphs in our subrun. This is
only valid if we | 937 // set use tokens for all of the glyphs in our subrun. This is
only valid if we |
843 // have a valid atlas generation | 938 // have a valid atlas generation |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
903 } | 998 } |
904 | 999 |
905 void regenerateColors(intptr_t vertex, size_t vertexStride, GrColor color) { | 1000 void regenerateColors(intptr_t vertex, size_t vertexStride, GrColor color) { |
906 for (int i = 0; i < kVerticesPerGlyph; i++) { | 1001 for (int i = 0; i < kVerticesPerGlyph; i++) { |
907 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex); | 1002 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex); |
908 *vcolor = color; | 1003 *vcolor = color; |
909 vertex += vertexStride; | 1004 vertex += vertexStride; |
910 } | 1005 } |
911 } | 1006 } |
912 | 1007 |
| 1008 void regeneratePositions(intptr_t vertex, size_t vertexStride, SkScalar tran
sX, |
| 1009 SkScalar transY) { |
| 1010 for (int i = 0; i < kVerticesPerGlyph; i++) { |
| 1011 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); |
| 1012 point->fX += transX; |
| 1013 point->fY += transY; |
| 1014 vertex += vertexStride; |
| 1015 } |
| 1016 } |
| 1017 |
913 void initDraw(GrBatchTarget* batchTarget, | 1018 void initDraw(GrBatchTarget* batchTarget, |
914 const GrGeometryProcessor* gp, | 1019 const GrGeometryProcessor* gp, |
915 const GrPipeline* pipeline) { | 1020 const GrPipeline* pipeline) { |
916 batchTarget->initDraw(gp, pipeline); | 1021 batchTarget->initDraw(gp, pipeline); |
917 | 1022 |
918 // TODO remove this when batch is everywhere | 1023 // TODO remove this when batch is everywhere |
919 GrPipelineInfo init; | 1024 GrPipelineInfo init; |
920 init.fColorIgnored = fBatch.fColorIgnored; | 1025 init.fColorIgnored = fBatch.fColorIgnored; |
921 init.fOverrideColor = GrColor_ILLEGAL; | 1026 init.fOverrideColor = GrColor_ILLEGAL; |
922 init.fCoverageIgnored = fBatch.fCoverageIgnored; | 1027 init.fCoverageIgnored = fBatch.fCoverageIgnored; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1009 break; | 1114 break; |
1010 case SkTextBlob::kFull_Positioning: | 1115 case SkTextBlob::kFull_Positioning: |
1011 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs
(), | 1116 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs
(), |
1012 textLen, it.pos(), 2, SkPoint::Make(x, y), c
lipBounds); | 1117 textLen, it.pos(), 2, SkPoint::Make(x, y), c
lipBounds); |
1013 break; | 1118 break; |
1014 } | 1119 } |
1015 } | 1120 } |
1016 | 1121 |
1017 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder
* pipelineBuilder, | 1122 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder
* pipelineBuilder, |
1018 BitmapTextBlob* cacheBlob, int run, GrC
olor color, | 1123 BitmapTextBlob* cacheBlob, int run, GrC
olor color, |
1019 uint8_t paintAlpha) { | 1124 uint8_t paintAlpha, SkScalar transX, Sk
Scalar transY) { |
1020 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub
Run++) { | 1125 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub
Run++) { |
1021 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun]; | 1126 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun]; |
1022 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; | 1127 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; |
1023 if (0 == glyphCount) { | 1128 if (0 == glyphCount) { |
1024 continue; | 1129 continue; |
1025 } | 1130 } |
1026 | 1131 |
1027 GrMaskFormat format = info.fMaskFormat; | 1132 GrMaskFormat format = info.fMaskFormat; |
1028 GrColor subRunColor = kARGB_GrMaskFormat == format ? | 1133 GrColor subRunColor = kARGB_GrMaskFormat == format ? |
1029 SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha,
paintAlpha) : | 1134 SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha,
paintAlpha) : |
1030 color; | 1135 color; |
1031 | 1136 |
1032 BitmapTextBatch::Geometry geometry; | 1137 BitmapTextBatch::Geometry geometry; |
1033 geometry.fBlob.reset(SkRef(cacheBlob)); | 1138 geometry.fBlob.reset(SkRef(cacheBlob)); |
1034 geometry.fRun = run; | 1139 geometry.fRun = run; |
1035 geometry.fSubRun = subRun; | 1140 geometry.fSubRun = subRun; |
1036 geometry.fColor = subRunColor; | 1141 geometry.fColor = subRunColor; |
| 1142 geometry.fTransX = transX; |
| 1143 geometry.fTransY = transY; |
1037 SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, format, gl
yphCount, | 1144 SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, format, gl
yphCount, |
1038 fContext->getBatchFo
ntCache())); | 1145 fContext->getBatchFo
ntCache())); |
1039 | 1146 |
1040 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex
Bounds); | 1147 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex
Bounds); |
1041 } | 1148 } |
1042 } | 1149 } |
1043 | 1150 |
1044 inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRend
erTarget* rt, | 1151 inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRend
erTarget* rt, |
1045 const GrPaint& grPaint, const GrC
lip& clip) { | 1152 const GrPaint& grPaint, const GrC
lip& clip, |
| 1153 SkScalar transX, SkScalar transY)
{ |
1046 for (int i = 0; i < cacheBlob->fBigGlyphs.count(); i++) { | 1154 for (int i = 0; i < cacheBlob->fBigGlyphs.count(); i++) { |
1047 const BitmapTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i]; | 1155 BitmapTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i]; |
| 1156 bigGlyph.fVx += SkScalarTruncToInt(transX); |
| 1157 bigGlyph.fVy += SkScalarTruncToInt(transY); |
1048 SkMatrix translate; | 1158 SkMatrix translate; |
1049 translate.setTranslate(SkIntToScalar(bigGlyph.fVx), SkIntToScalar(bigGly
ph.fVy)); | 1159 translate.setTranslate(SkIntToScalar(bigGlyph.fVx), |
| 1160 SkIntToScalar(bigGlyph.fVy)); |
1050 SkPath tmpPath(bigGlyph.fPath); | 1161 SkPath tmpPath(bigGlyph.fPath); |
1051 tmpPath.transform(translate); | 1162 tmpPath.transform(translate); |
1052 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); | 1163 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); |
1053 fContext->drawPath(rt, clip, grPaint, SkMatrix::I(), tmpPath, strokeInfo
); | 1164 fContext->drawPath(rt, clip, grPaint, SkMatrix::I(), tmpPath, strokeInfo
); |
1054 } | 1165 } |
1055 } | 1166 } |
1056 | 1167 |
1057 void GrAtlasTextContext::flush(GrDrawTarget* target, | 1168 void GrAtlasTextContext::flush(GrDrawTarget* target, |
1058 const SkTextBlob* blob, | 1169 const SkTextBlob* blob, |
1059 BitmapTextBlob* cacheBlob, | 1170 BitmapTextBlob* cacheBlob, |
1060 GrRenderTarget* rt, | 1171 GrRenderTarget* rt, |
1061 const SkPaint& skPaint, | 1172 const SkPaint& skPaint, |
1062 const GrPaint& grPaint, | 1173 const GrPaint& grPaint, |
1063 SkDrawFilter* drawFilter, | 1174 SkDrawFilter* drawFilter, |
1064 const GrClip& clip, | 1175 const GrClip& clip, |
1065 const SkMatrix& viewMatrix, | 1176 const SkMatrix& viewMatrix, |
1066 const SkIRect& clipBounds, | 1177 const SkIRect& clipBounds, |
1067 SkScalar x, | 1178 SkScalar x, SkScalar y, |
1068 SkScalar y) { | 1179 SkScalar transX, SkScalar transY) { |
1069 // We loop through the runs of the blob, flushing each. If any run is too l
arge, then we flush | 1180 // We loop through the runs of the blob, flushing each. If any run is too l
arge, then we flush |
1070 // it as paths | 1181 // it as paths |
1071 GrPipelineBuilder pipelineBuilder; | 1182 GrPipelineBuilder pipelineBuilder; |
1072 pipelineBuilder.setFromPaint(grPaint, rt, clip); | 1183 pipelineBuilder.setFromPaint(grPaint, rt, clip); |
1073 | 1184 |
1074 GrColor color = grPaint.getColor(); | 1185 GrColor color = grPaint.getColor(); |
1075 uint8_t paintAlpha = skPaint.getAlpha(); | 1186 uint8_t paintAlpha = skPaint.getAlpha(); |
1076 | 1187 |
1077 SkTextBlob::RunIterator it(blob); | 1188 SkTextBlob::RunIterator it(blob); |
1078 for (int run = 0; !it.done(); it.next(), run++) { | 1189 for (int run = 0; !it.done(); it.next(), run++) { |
1079 if (cacheBlob->fRuns[run].fDrawAsPaths) { | 1190 if (cacheBlob->fRuns[run].fDrawAsPaths) { |
1080 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound
s, x, y); | 1191 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound
s, x, y); |
1081 continue; | 1192 continue; |
1082 } | 1193 } |
1083 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp
ha); | 1194 cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY); |
| 1195 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp
ha, transX, transY); |
1084 } | 1196 } |
1085 | 1197 |
1086 // Now flush big glyphs | 1198 // Now flush big glyphs |
1087 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip); | 1199 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, transX, transY); |
1088 } | 1200 } |
1089 | 1201 |
1090 void GrAtlasTextContext::flush(GrDrawTarget* target, | 1202 void GrAtlasTextContext::flush(GrDrawTarget* target, |
1091 BitmapTextBlob* cacheBlob, | 1203 BitmapTextBlob* cacheBlob, |
1092 GrRenderTarget* rt, | 1204 GrRenderTarget* rt, |
1093 const SkPaint& skPaint, | 1205 const SkPaint& skPaint, |
1094 const GrPaint& grPaint, | 1206 const GrPaint& grPaint, |
1095 const GrClip& clip, | 1207 const GrClip& clip, |
1096 const SkMatrix& viewMatrix) { | 1208 const SkMatrix& viewMatrix) { |
1097 GrPipelineBuilder pipelineBuilder; | 1209 GrPipelineBuilder pipelineBuilder; |
1098 pipelineBuilder.setFromPaint(grPaint, rt, clip); | 1210 pipelineBuilder.setFromPaint(grPaint, rt, clip); |
1099 | 1211 |
1100 GrColor color = grPaint.getColor(); | 1212 GrColor color = grPaint.getColor(); |
1101 uint8_t paintAlpha = skPaint.getAlpha(); | 1213 uint8_t paintAlpha = skPaint.getAlpha(); |
1102 for (int run = 0; run < cacheBlob->fRunCount; run++) { | 1214 for (int run = 0; run < cacheBlob->fRunCount; run++) { |
1103 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp
ha); | 1215 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp
ha, 0, 0); |
1104 } | 1216 } |
1105 | 1217 |
1106 // Now flush big glyphs | 1218 // Now flush big glyphs |
1107 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip); | 1219 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); |
1108 } | 1220 } |
OLD | NEW |