/src/skia/src/gpu/ops/GrAtlasTextOp.h
Line | Count | Source (jump to first uncovered line) |
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 GrAtlasTextOp_DEFINED |
9 | | #define GrAtlasTextOp_DEFINED |
10 | | |
11 | | #include "src/gpu/GrTBlockList.h" |
12 | | #include "src/gpu/effects/GrDistanceFieldGeoProc.h" |
13 | | #include "src/gpu/ops/GrMeshDrawOp.h" |
14 | | #include "src/gpu/text/GrTextBlob.h" |
15 | | |
16 | | #if !defined(SK_BUILD_FOR_IOS) || \ |
17 | | (defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MIN_REQUIRED > __IPHONE_9_0) |
18 | | #define GR_HAS_THREAD_LOCAL |
19 | | #endif |
20 | | |
21 | | class GrRecordingContext; |
22 | | |
23 | | class GrAtlasTextOp final : public GrMeshDrawOp { |
24 | | public: |
25 | | DEFINE_OP_CLASS_ID |
26 | | |
27 | 520 | ~GrAtlasTextOp() override { |
28 | 1.04k | for (const Geometry* g = fHead; g != nullptr;) { |
29 | 520 | const Geometry* next = g->fNext; |
30 | 520 | g->~Geometry(); |
31 | 520 | g = next; |
32 | 520 | } |
33 | 520 | } |
34 | | |
35 | | #if defined(GR_HAS_THREAD_LOCAL) |
36 | | void* operator new(size_t s); |
37 | | void operator delete(void* b) noexcept; |
38 | | static void ClearCache(); |
39 | | #else |
40 | | static void ClearCache() {} |
41 | | #endif |
42 | | |
43 | | static const int kVerticesPerGlyph = GrAtlasSubRun::kVerticesPerGlyph; |
44 | | static const int kIndicesPerGlyph = 6; |
45 | | |
46 | | struct Geometry { |
47 | | Geometry(const GrAtlasSubRun& subRun, |
48 | | const SkMatrix& drawMatrix, |
49 | | SkPoint drawOrigin, |
50 | | SkIRect clipRect, |
51 | | sk_sp<GrTextBlob> blob, |
52 | | GrAtlasSubRunOwner subRunOwner, |
53 | | const SkPMColor4f& color) |
54 | | : fSubRun{subRun} |
55 | | , fBlob{std::move(blob)} |
56 | | , fSubRunDtor{std::move(subRunOwner)} |
57 | | , fDrawMatrix{drawMatrix} |
58 | | , fDrawOrigin{drawOrigin} |
59 | | , fClipRect{clipRect} |
60 | 520 | , fColor{color} { |
61 | 520 | SkASSERT(fBlob != nullptr || fSubRunDtor != nullptr); |
62 | 520 | SkASSERT(SkToBool(fSubRunDtor) != SkToBool(fBlob)); |
63 | 520 | } |
64 | | |
65 | | static Geometry* MakeForBlob(const GrAtlasSubRun& subRun, |
66 | | const SkMatrix& drawMatrix, |
67 | | SkPoint drawOrigin, |
68 | | SkIRect clipRect, |
69 | | sk_sp<GrTextBlob> blob, |
70 | | const SkPMColor4f& color, |
71 | | SkArenaAlloc* alloc); |
72 | | |
73 | | void fillVertexData(void* dst, int offset, int count) const; |
74 | | |
75 | | const GrAtlasSubRun& fSubRun; |
76 | | |
77 | | // Either this Geometry holds a ref to the GrTextBlob in the case of a text blob based |
78 | | // SubRun (WithCaching case), or it holds a unique_ptr to a SubRun allocated on the |
79 | | // GrTextBlobAllocator in the NoCache case. It must hold one, and can't hold both. |
80 | | sk_sp<GrTextBlob> fBlob; // mutable to make unref call in Op dtor. |
81 | | GrAtlasSubRunOwner fSubRunDtor; |
82 | | |
83 | | const SkMatrix fDrawMatrix; |
84 | | const SkPoint fDrawOrigin; |
85 | | |
86 | | // fClipRect is only used in the DirectMaskSubRun case to do geometric clipping. |
87 | | // TransformedMaskSubRun, and SDFTSubRun don't use this field, and expect an empty rect. |
88 | | const SkIRect fClipRect; |
89 | | |
90 | | // Color is updated after processor analysis if it was determined the shader resolves to |
91 | | // a constant color that we then evaluate on the CPU. |
92 | | // TODO: This can be made const once processor analysis is separated from op creation. |
93 | | SkPMColor4f fColor; |
94 | | Geometry* fNext{nullptr}; |
95 | | }; |
96 | | |
97 | 0 | const char* name() const override { return "AtlasTextOp"; } |
98 | | |
99 | | void visitProxies(const GrVisitProxyFunc&) const override; |
100 | | |
101 | | FixedFunctionFlags fixedFunctionFlags() const override; |
102 | | |
103 | | GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override; |
104 | | |
105 | | enum class MaskType : uint32_t { |
106 | | kGrayscaleCoverage, |
107 | | kLCDCoverage, |
108 | | kColorBitmap, |
109 | | kAliasedDistanceField, |
110 | | kGrayscaleDistanceField, |
111 | | kLCDDistanceField, |
112 | | kLCDBGRDistanceField, |
113 | | |
114 | | kLast = kLCDBGRDistanceField |
115 | | }; |
116 | | static constexpr int kMaskTypeCount = static_cast<int>(MaskType::kLast) + 1; |
117 | | |
118 | | #if GR_TEST_UTILS && SK_GPU_V1 |
119 | | static GrOp::Owner CreateOpTestingOnly(skgpu::v1::SurfaceDrawContext*, |
120 | | const SkPaint&, |
121 | | const SkFont&, |
122 | | const SkMatrixProvider&, |
123 | | const char* text, |
124 | | int x, |
125 | | int y); |
126 | | #endif |
127 | | |
128 | | private: |
129 | | friend class GrOp; // for ctor |
130 | | |
131 | | struct FlushInfo { |
132 | | sk_sp<const GrBuffer> fVertexBuffer; |
133 | | sk_sp<const GrBuffer> fIndexBuffer; |
134 | | GrGeometryProcessor* fGeometryProcessor; |
135 | | const GrSurfaceProxy** fPrimProcProxies; |
136 | | int fGlyphsToFlush = 0; |
137 | | int fVertexOffset = 0; |
138 | | int fNumDraws = 0; |
139 | | }; |
140 | | |
141 | | GrAtlasTextOp(MaskType maskType, |
142 | | bool needsTransform, |
143 | | int glyphCount, |
144 | | SkRect deviceRect, |
145 | | Geometry* geo, |
146 | | GrPaint&& paint); |
147 | | |
148 | | GrAtlasTextOp(MaskType maskType, |
149 | | bool needsTransform, |
150 | | int glyphCount, |
151 | | SkRect deviceRect, |
152 | | SkColor luminanceColor, |
153 | | bool useGammaCorrectDistanceTable, |
154 | | uint32_t DFGPFlags, |
155 | | Geometry* geo, |
156 | | GrPaint&& paint); |
157 | | |
158 | 0 | GrProgramInfo* programInfo() override { |
159 | | // TODO [PI]: implement |
160 | 0 | return nullptr; |
161 | 0 | } |
162 | | |
163 | 173 | void addGeometry(Geometry* geometry) { |
164 | 173 | *fTail = geometry; |
165 | | // The geometry may have many entries. Find the end. |
166 | 173 | do { |
167 | 173 | fTail = &(*fTail)->fNext; |
168 | 173 | } while (*fTail != nullptr); |
169 | 173 | } |
170 | | |
171 | | void onCreateProgramInfo(const GrCaps*, |
172 | | SkArenaAlloc*, |
173 | | const GrSurfaceProxyView& writeView, |
174 | | bool usesMSAASurface, |
175 | | GrAppliedClip&&, |
176 | | const GrDstProxyView&, |
177 | | GrXferBarrierFlags renderPassXferBarriers, |
178 | 0 | GrLoadOp colorLoadOp) override { |
179 | | // We cannot surface the GrAtlasTextOp's programInfo at record time. As currently |
180 | | // implemented, the GP is modified at flush time based on the number of pages in the |
181 | | // atlas. |
182 | 0 | } |
183 | | |
184 | | void onPrePrepareDraws(GrRecordingContext*, |
185 | | const GrSurfaceProxyView& writeView, |
186 | | GrAppliedClip*, |
187 | | const GrDstProxyView&, |
188 | | GrXferBarrierFlags renderPassXferBarriers, |
189 | 0 | GrLoadOp colorLoadOp) override { |
190 | | // TODO [PI]: implement |
191 | 0 | } |
192 | | |
193 | | void onPrepareDraws(GrMeshDrawTarget*) override; |
194 | | void onExecute(GrOpFlushState*, const SkRect& chainBounds) override; |
195 | | |
196 | | #if GR_TEST_UTILS |
197 | | SkString onDumpInfo() const override; |
198 | | #endif |
199 | | |
200 | 670 | GrMaskFormat maskFormat() const { |
201 | 670 | switch (this->maskType()) { |
202 | 0 | case MaskType::kLCDCoverage: |
203 | 0 | return kA565_GrMaskFormat; |
204 | 8 | case MaskType::kColorBitmap: |
205 | 8 | return kARGB_GrMaskFormat; |
206 | 532 | case MaskType::kGrayscaleCoverage: |
207 | 586 | case MaskType::kAliasedDistanceField: |
208 | 662 | case MaskType::kGrayscaleDistanceField: |
209 | 662 | case MaskType::kLCDDistanceField: |
210 | 662 | case MaskType::kLCDBGRDistanceField: |
211 | 662 | return kA8_GrMaskFormat; |
212 | 0 | } |
213 | | // SkUNREACHABLE; |
214 | 0 | return kA8_GrMaskFormat; |
215 | 0 | } |
216 | | |
217 | 622 | bool usesDistanceFields() const { |
218 | 622 | return MaskType::kAliasedDistanceField == this->maskType() || |
219 | 582 | MaskType::kGrayscaleDistanceField == this->maskType() || |
220 | 520 | MaskType::kLCDDistanceField == this->maskType() || |
221 | 520 | MaskType::kLCDBGRDistanceField == this->maskType(); |
222 | 622 | } |
223 | | |
224 | 78 | bool isLCD() const { |
225 | 78 | return MaskType::kLCDCoverage == this->maskType() || |
226 | 78 | MaskType::kLCDDistanceField == this->maskType() || |
227 | 78 | MaskType::kLCDBGRDistanceField == this->maskType(); |
228 | 78 | } |
229 | | |
230 | | inline void createDrawForGeneratedGlyphs( |
231 | | GrMeshDrawTarget* target, FlushInfo* flushInfo) const; |
232 | | |
233 | 4.37k | MaskType maskType() const { return static_cast<MaskType>(fMaskType); } |
234 | | |
235 | | CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override; |
236 | | |
237 | | GrGeometryProcessor* setupDfProcessor(SkArenaAlloc*, |
238 | | const GrShaderCaps&, |
239 | | const SkMatrix& localMatrix, |
240 | | const GrSurfaceProxyView* views, |
241 | | unsigned int numActiveViews) const; |
242 | | |
243 | | GrProcessorSet fProcessors; |
244 | | int fNumGlyphs; // Sum of glyphs in each geometry's subrun |
245 | | |
246 | | // All combinable atlas ops have equal bit field values |
247 | | uint32_t fDFGPFlags : 9; // Distance field properties |
248 | | uint32_t fMaskType : 3; // MaskType |
249 | | uint32_t fUsesLocalCoords : 1; // Filled in post processor analysis |
250 | | uint32_t fNeedsGlyphTransform : 1; |
251 | | uint32_t fHasPerspective : 1; // True if perspective affects draw |
252 | | uint32_t fUseGammaCorrectDistanceTable : 1; |
253 | | static_assert(kMaskTypeCount <= 8, "MaskType does not fit in 3 bits"); |
254 | | static_assert(kInvalid_DistanceFieldEffectFlag <= (1 << 8), "DFGP Flags do not fit in 9 bits"); |
255 | | |
256 | | // Only used for distance fields; per-channel luminance for LCD, or gamma-corrected luminance |
257 | | // for single-channel distance fields. |
258 | | const SkColor fLuminanceColor{0}; |
259 | | |
260 | | Geometry* fHead{nullptr}; |
261 | | Geometry** fTail{&fHead}; |
262 | | |
263 | | using INHERITED = GrMeshDrawOp; |
264 | | }; |
265 | | |
266 | | #endif |