1 | /* |
2 | * Copyright 2017 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 | #include "include/atlastext/SkAtlasTextTarget.h" |
9 | |
10 | #include "include/atlastext/SkAtlasTextContext.h" |
11 | #include "include/atlastext/SkAtlasTextFont.h" |
12 | #include "include/atlastext/SkAtlasTextRenderer.h" |
13 | #include "src/atlastext/SkInternalAtlasTextContext.h" |
14 | #include "src/core/SkGlyphRunPainter.h" |
15 | #include "src/gpu/GrClip.h" |
16 | #include "src/gpu/GrContextPriv.h" |
17 | #include "src/gpu/GrDrawingManager.h" |
18 | #include "src/gpu/GrMemoryPool.h" |
19 | #include "src/gpu/GrRecordingContextPriv.h" |
20 | #include "src/gpu/SkGr.h" |
21 | #include "src/gpu/ops/GrAtlasTextOp.h" |
22 | #include "src/gpu/text/GrAtlasManager.h" |
23 | #include "src/gpu/text/GrTextContext.h" |
24 | |
25 | static constexpr int kMaxBatchLookBack = 10; |
26 | |
27 | SkAtlasTextTarget::SkAtlasTextTarget(sk_sp<SkAtlasTextContext> context, int width, int height, |
28 | void* handle) |
29 | : fHandle(handle) |
30 | , fContext(std::move(context)) |
31 | , fWidth(width) |
32 | , fHeight(height) |
33 | , fMatrixStack(sizeof(SkMatrix), 4) |
34 | , fSaveCnt(0) { |
35 | fMatrixStack.push_back(); |
36 | this->accessCTM()->reset(); |
37 | } |
38 | |
39 | SkAtlasTextTarget::~SkAtlasTextTarget() { fContext->renderer()->targetDeleted(fHandle); } |
40 | |
41 | int SkAtlasTextTarget::save() { |
42 | const auto& currCTM = this->ctm(); |
43 | *static_cast<SkMatrix*>(fMatrixStack.push_back()) = currCTM; |
44 | return fSaveCnt++; |
45 | } |
46 | |
47 | void SkAtlasTextTarget::restore() { |
48 | if (fSaveCnt) { |
49 | fMatrixStack.pop_back(); |
50 | fSaveCnt--; |
51 | } |
52 | } |
53 | |
54 | void SkAtlasTextTarget::restoreToCount(int count) { |
55 | while (fSaveCnt > count) { |
56 | this->restore(); |
57 | } |
58 | } |
59 | |
60 | void SkAtlasTextTarget::translate(SkScalar dx, SkScalar dy) { |
61 | this->accessCTM()->preTranslate(dx, dy); |
62 | } |
63 | |
64 | void SkAtlasTextTarget::scale(SkScalar sx, SkScalar sy) { this->accessCTM()->preScale(sx, sy); } |
65 | |
66 | void SkAtlasTextTarget::rotate(SkScalar degrees) { this->accessCTM()->preRotate(degrees); } |
67 | |
68 | void SkAtlasTextTarget::rotate(SkScalar degrees, SkScalar px, SkScalar py) { |
69 | this->accessCTM()->preRotate(degrees, px, py); |
70 | } |
71 | |
72 | void SkAtlasTextTarget::skew(SkScalar sx, SkScalar sy) { this->accessCTM()->preSkew(sx, sy); } |
73 | |
74 | void SkAtlasTextTarget::concat(const SkMatrix& matrix) { this->accessCTM()->preConcat(matrix); } |
75 | |
76 | ////////////////////////////////////////////////////////////////////////////// |
77 | |
78 | static const GrColorInfo kColorInfo(GrColorType::kRGBA_8888, kPremul_SkAlphaType, nullptr); |
79 | static const SkSurfaceProps kProps( |
80 | SkSurfaceProps::kUseDistanceFieldFonts_Flag, kUnknown_SkPixelGeometry); |
81 | |
82 | ////////////////////////////////////////////////////////////////////////////// |
83 | |
84 | class SkInternalAtlasTextTarget : public GrTextTarget, public SkAtlasTextTarget { |
85 | public: |
86 | SkInternalAtlasTextTarget(sk_sp<SkAtlasTextContext> context, int width, int height, |
87 | void* handle) |
88 | : GrTextTarget(width, height, kColorInfo) |
89 | , SkAtlasTextTarget(std::move(context), width, height, handle) |
90 | , fGlyphPainter(kProps, kColorInfo) {} |
91 | |
92 | ~SkInternalAtlasTextTarget() override { |
93 | this->deleteOps(); |
94 | } |
95 | |
96 | /** GrTextTarget overrides */ |
97 | |
98 | void addDrawOp(const GrClip&, std::unique_ptr<GrAtlasTextOp> op) override; |
99 | |
100 | void drawShape(const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, |
101 | const GrShape&) override { |
102 | SkDebugf("Path glyph??" ); |
103 | } |
104 | |
105 | void makeGrPaint(GrMaskFormat, const SkPaint& skPaint, const SkMatrix&, |
106 | GrPaint* grPaint) override { |
107 | grPaint->setColor4f(skPaint.getColor4f().premul()); |
108 | } |
109 | |
110 | GrContext* getContext() override { |
111 | return this->context()->internal().grContext(); |
112 | } |
113 | |
114 | SkGlyphRunListPainter* glyphPainter() override { |
115 | return &fGlyphPainter; |
116 | } |
117 | |
118 | /** SkAtlasTextTarget overrides */ |
119 | |
120 | void drawText(const SkGlyphID[], const SkPoint[], int glyphCnt, uint32_t color, |
121 | const SkAtlasTextFont&) override; |
122 | void flush() override; |
123 | |
124 | private: |
125 | void deleteOps(); |
126 | |
127 | GrRecordingContext::Arenas arenas() { |
128 | return fContext->internal().grContext()->GrRecordingContext::priv().arenas(); |
129 | } |
130 | |
131 | uint32_t fColor; |
132 | using SkAtlasTextTarget::fWidth; |
133 | using SkAtlasTextTarget::fHeight; |
134 | SkTArray<std::unique_ptr<GrAtlasTextOp>, true> fOps; |
135 | SkGlyphRunListPainter fGlyphPainter; |
136 | }; |
137 | |
138 | ////////////////////////////////////////////////////////////////////////////// |
139 | |
140 | std::unique_ptr<SkAtlasTextTarget> SkAtlasTextTarget::Make(sk_sp<SkAtlasTextContext> context, |
141 | int width, int height, void* handle) { |
142 | return std::unique_ptr<SkAtlasTextTarget>( |
143 | new SkInternalAtlasTextTarget(std::move(context), width, height, handle)); |
144 | } |
145 | |
146 | ////////////////////////////////////////////////////////////////////////////// |
147 | |
148 | void SkInternalAtlasTextTarget::drawText(const SkGlyphID glyphs[], const SkPoint positions[], |
149 | int glyphCnt, uint32_t color, |
150 | const SkAtlasTextFont& font) { |
151 | SkPaint paint; |
152 | paint.setAntiAlias(true); |
153 | |
154 | // The atlas text context does munging of the paint color. We store the client's color here |
155 | // and then overwrite the generated op's color when addDrawOp() is called. |
156 | fColor = color; |
157 | |
158 | SkSurfaceProps props(SkSurfaceProps::kUseDistanceFieldFonts_Flag, kUnknown_SkPixelGeometry); |
159 | auto grContext = this->context()->internal().grContext(); |
160 | auto atlasTextContext = grContext->priv().drawingManager()->getTextContext(); |
161 | SkGlyphRunBuilder builder; |
162 | builder.drawGlyphsWithPositions(paint, font.makeFont(), |
163 | SkSpan<const SkGlyphID>{glyphs, SkTo<size_t>(glyphCnt)}, |
164 | positions); |
165 | auto glyphRunList = builder.useGlyphRunList(); |
166 | if (!glyphRunList.empty()) { |
167 | atlasTextContext->drawGlyphRunList(grContext, this, GrNoClip(), this->ctm(), props, |
168 | glyphRunList); |
169 | } |
170 | } |
171 | |
172 | void SkInternalAtlasTextTarget::addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) { |
173 | SkASSERT(clip.quickContains(SkRect::MakeIWH(fWidth, fHeight))); |
174 | // The SkAtlasTextRenderer currently only handles grayscale SDF glyphs. |
175 | if (op->maskType() != GrAtlasTextOp::kGrayscaleDistanceField_MaskType) { |
176 | return; |
177 | } |
178 | const GrCaps& caps = *this->context()->internal().grContext()->priv().caps(); |
179 | op->finalizeForTextTarget(fColor, caps); |
180 | int n = std::min(kMaxBatchLookBack, fOps.count()); |
181 | |
182 | GrRecordingContext::Arenas arenas = this->arenas(); |
183 | for (int i = 0; i < n; ++i) { |
184 | GrAtlasTextOp* other = fOps.fromBack(i).get(); |
185 | if (other->combineIfPossible(op.get(), &arenas, caps) == GrOp::CombineResult::kMerged) { |
186 | arenas.opMemoryPool()->release(std::move(op)); |
187 | return; |
188 | } |
189 | if (GrRectsOverlap(op->bounds(), other->bounds())) { |
190 | break; |
191 | } |
192 | } |
193 | fOps.emplace_back(std::move(op)); |
194 | } |
195 | |
196 | void SkInternalAtlasTextTarget::deleteOps() { |
197 | GrOpMemoryPool* pool = this->arenas().opMemoryPool(); |
198 | for (int i = 0; i < fOps.count(); ++i) { |
199 | if (fOps[i]) { |
200 | pool->release(std::move(fOps[i])); |
201 | } |
202 | } |
203 | fOps.reset(); |
204 | } |
205 | |
206 | void SkInternalAtlasTextTarget::flush() { |
207 | for (int i = 0; i < fOps.count(); ++i) { |
208 | fOps[i]->executeForTextTarget(this); |
209 | } |
210 | this->context()->internal().flush(); |
211 | this->deleteOps(); |
212 | } |
213 | |
214 | void GrAtlasTextOp::finalizeForTextTarget(uint32_t color, const GrCaps& caps) { |
215 | // TODO4F: Odd handling of client colors among AtlasTextTarget and AtlasTextRenderer |
216 | SkPMColor4f color4f = SkPMColor4f::FromBytes_RGBA(color); |
217 | for (int i = 0; i < fGeoCount; ++i) { |
218 | fGeoData[i].fColor = color4f; |
219 | } |
220 | // Atlas text doesn't use MSAA, so no need to handle mixed samples. |
221 | // Also, no need to support normalized F16 with manual clamp? |
222 | this->finalize(caps, nullptr /* applied clip */, false /* mixed samples */, GrClampType::kAuto); |
223 | } |
224 | |
225 | void GrAtlasTextOp::executeForTextTarget(SkAtlasTextTarget* target) { |
226 | auto& context = target->context()->internal(); |
227 | auto atlasManager = context.grContext()->priv().getAtlasManager(); |
228 | auto resourceProvider = context.grContext()->priv().resourceProvider(); |
229 | |
230 | unsigned int numProxies; |
231 | if (!atlasManager->getViews(kA8_GrMaskFormat, &numProxies)) { |
232 | return; |
233 | } |
234 | |
235 | for (int i = 0; i < fGeoCount; ++i) { |
236 | auto subRun = fGeoData[i].fSubRunPtr; |
237 | subRun->prepareGrGlyphs(context.grContext()->priv().getGrStrikeCache()); |
238 | // TODO4F: Preserve float colors |
239 | subRun->updateVerticesColorIfNeeded(fGeoData[i].fColor.toBytes_RGBA()); |
240 | subRun->translateVerticesIfNeeded(fGeoData[i].fDrawMatrix, fGeoData[i].fDrawOrigin); |
241 | GrTextBlob::VertexRegenerator regenerator(resourceProvider, subRun, &context, atlasManager); |
242 | int subRunEnd = subRun->fGlyphs.count(); |
243 | for (int subRunIndex = 0; subRunIndex < subRunEnd;) { |
244 | auto [ok, glyphsRegenerated] = regenerator.regenerate(subRunIndex, subRunEnd); |
245 | if (!ok) { |
246 | break; |
247 | } |
248 | |
249 | context.recordDraw(subRun->quadStart(subRunIndex), glyphsRegenerated, |
250 | fGeoData[i].fDrawMatrix, target->handle()); |
251 | subRunIndex += glyphsRegenerated; |
252 | if (subRunIndex != subRunEnd) { |
253 | // Make space in the atlas so we can continue generating vertices. |
254 | context.flush(); |
255 | } |
256 | } |
257 | } |
258 | } |
259 | |