Flutter Engine
The Flutter Engine
AtlasTextOp.cpp
Go to the documentation of this file.
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
9
40
41#if defined(SK_GAMMA_APPLY_TO_A8)
44#endif
45
46#include <algorithm>
47#include <functional>
48#include <new>
49#include <tuple>
50#include <utility>
51
52struct GrShaderCaps;
53
55
56namespace skgpu::ganesh {
57
58inline static constexpr int kVerticesPerGlyph = 4;
59inline static constexpr int kIndicesPerGlyph = 6;
60
61// If we have thread local, then cache memory for a single AtlasTextOp.
62static thread_local void* gCache = nullptr;
63void* AtlasTextOp::operator new(size_t s) {
64 if (gCache != nullptr) {
65 return std::exchange(gCache, nullptr);
66 }
67
68 return ::operator new(s);
69}
70
71void AtlasTextOp::operator delete(void* bytes) noexcept {
72 if (gCache == nullptr) {
73 gCache = bytes;
74 return;
75 }
76 ::operator delete(bytes);
77}
78
80 ::operator delete(gCache);
81 gCache = nullptr;
82}
83
84AtlasTextOp::AtlasTextOp(MaskType maskType,
85 bool needsTransform,
86 int glyphCount,
87 SkRect deviceRect,
88 Geometry* geo,
89 const GrColorInfo& dstColorInfo,
90 GrPaint&& paint)
91 : INHERITED{ClassID()}
92 , fProcessors(std::move(paint))
93 , fNumGlyphs(glyphCount)
94 , fDFGPFlags(0)
95 , fMaskType(static_cast<uint32_t>(maskType))
96 , fUsesLocalCoords(false)
97 , fNeedsGlyphTransform(needsTransform)
98 , fHasPerspective(needsTransform && geo->fDrawMatrix.hasPerspective())
99 , fUseGammaCorrectDistanceTable(false)
100 , fHead{geo}
101 , fTail{&fHead->fNext} {
102 // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds
103 // we treat this as a set of non-AA rects rendered with a texture.
104 this->setBounds(deviceRect, HasAABloat::kNo, IsHairline::kNo);
105 if (maskType == MaskType::kColorBitmap) {
106 // We assume that color emoji use the sRGB colorspace
107 fColorSpaceXform = dstColorInfo.refColorSpaceXformFromSRGB();
108 }
109}
110
111AtlasTextOp::AtlasTextOp(MaskType maskType,
112 bool needsTransform,
113 int glyphCount,
114 SkRect deviceRect,
115 SkColor luminanceColor,
116 bool useGammaCorrectDistanceTable,
117 uint32_t DFGPFlags,
118 Geometry* geo,
119 GrPaint&& paint)
120 : INHERITED{ClassID()}
121 , fProcessors(std::move(paint))
122 , fNumGlyphs(glyphCount)
123 , fDFGPFlags(DFGPFlags)
124 , fMaskType(static_cast<uint32_t>(maskType))
125 , fUsesLocalCoords(false)
126 , fNeedsGlyphTransform(needsTransform)
127 , fHasPerspective(needsTransform && geo->fDrawMatrix.hasPerspective())
128 , fUseGammaCorrectDistanceTable(useGammaCorrectDistanceTable)
129 , fLuminanceColor(luminanceColor)
130 , fHead{geo}
131 , fTail{&fHead->fNext} {
132 // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds
133 // we treat this as a set of non-AA rects rendered with a texture.
134 this->setBounds(deviceRect, HasAABloat::kNo, IsHairline::kNo);
135}
136
138 const SkMatrix& drawMatrix,
139 SkPoint drawOrigin,
141 sk_sp<SkRefCnt>&& supportData,
142 const SkPMColor4f& color,
143 SkArenaAlloc* alloc) -> Geometry* {
144 // Bypass the automatic dtor behavior in SkArenaAlloc. I'm leaving this up to the Op to run
145 // all geometry dtors for now.
146 void* geo = alloc->makeBytesAlignedTo(sizeof(Geometry), alignof(Geometry));
147 return new(geo) Geometry{subRun,
148 drawMatrix,
149 drawOrigin,
150 clipRect,
151 std::move(supportData),
152 color};
153}
154
156 fSubRun.fillVertexData(
158}
159
161 fProcessors.visitProxies(func);
162}
163
164#if defined(GR_TEST_UTILS)
165SkString AtlasTextOp::onDumpInfo() const {
166 SkString str;
167 int i = 0;
168 for(Geometry* geom = fHead; geom != nullptr; geom = geom->fNext) {
169 str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f\n",
170 i++,
171 geom->fColor.toBytes_RGBA(),
172 geom->fDrawOrigin.x(),
173 geom->fDrawOrigin.y());
174 }
175
176 str += fProcessors.dumpProcessors();
177 return str;
178}
179#endif
180
183}
184
186 const GrAppliedClip* clip,
187 GrClampType clampType) {
190 if (this->maskType() == MaskType::kColorBitmap) {
191 color.setToUnknown();
192 } else {
193 // finalize() is called before any merging is done, so at this point there's at most one
194 // Geometry with a color. Later, for non-bitmap ops, we may have mixed colors.
195 color.setToConstant(fHead->fColor);
196 }
197
198 switch (this->maskType()) {
200#if !defined(SK_DISABLE_SDF_TEXT)
203#endif
205 break;
207#if !defined(SK_DISABLE_SDF_TEXT)
209#endif
211 break;
214 break;
215 }
216
217 auto analysis = fProcessors.finalize(color, coverage, clip, &GrUserStencilSettings::kUnused,
218 caps, clampType, &fHead->fColor);
219 // TODO(michaelludwig): Once processor analysis can be done external to op creation/finalization
220 // the atlas op metadata can be fully const. This is okay for now since finalize() happens
221 // before the op is merged, so during combineIfPossible, metadata is effectively const.
222 fUsesLocalCoords = analysis.usesLocalCoords();
223 return analysis;
224}
225
226void AtlasTextOp::onPrepareDraws(GrMeshDrawTarget* target) {
227 auto resourceProvider = target->resourceProvider();
228
229 // If we need local coordinates, compute an inverse view matrix. If this is solid color, the
230 // processor analysis will not require local coords and the GPs will skip local coords when
231 // the matrix is identity. When the shaders require local coords, combineIfPossible requires all
232 // all geometries to have same draw matrix.
233 SkMatrix localMatrix = SkMatrix::I();
234 if (fUsesLocalCoords && !fHead->fDrawMatrix.invert(&localMatrix)) {
235 return;
236 }
237
238 GrAtlasManager* atlasManager = target->atlasManager();
239
240 MaskFormat maskFormat = this->maskFormat();
241
242 unsigned int numActiveViews;
243 const GrSurfaceProxyView* views = atlasManager->getViews(maskFormat, &numActiveViews);
244 if (!views) {
245 SkDebugf("Could not allocate backing texture for atlas\n");
246 return;
247 }
248 SkASSERT(views[0].proxy());
249
250 static constexpr int kMaxTextures = GrBitmapTextGeoProc::kMaxTextures;
251#if !defined(SK_DISABLE_SDF_TEXT)
252 static_assert(GrDistanceFieldA8TextGeoProc::kMaxTextures == kMaxTextures);
253 static_assert(GrDistanceFieldLCDTextGeoProc::kMaxTextures == kMaxTextures);
254#endif
255
256 auto primProcProxies = target->allocPrimProcProxyPtrs(kMaxTextures);
257 for (unsigned i = 0; i < numActiveViews; ++i) {
258 primProcProxies[i] = views[i].proxy();
259 // This op does not know its atlas proxies when it is added to a OpsTasks, so the proxies
260 // don't get added during the visitProxies call. Thus we add them here.
261 target->sampledProxyArray()->push_back(views[i].proxy());
262 }
263
264 FlushInfo flushInfo;
265 flushInfo.fPrimProcProxies = primProcProxies;
266 flushInfo.fIndexBuffer = resourceProvider->refNonAAQuadIndexBuffer();
267
268#if !defined(SK_DISABLE_SDF_TEXT)
269 if (this->usesDistanceFields()) {
270 flushInfo.fGeometryProcessor = this->setupDfProcessor(target->allocator(),
271 *target->caps().shaderCaps(),
272 localMatrix, views, numActiveViews);
273 } else
274#endif
275 {
276 auto filter = fNeedsGlyphTransform ? GrSamplerState::Filter::kLinear
278 // Bitmap text uses a single color, combineIfPossible ensures all geometries have the same
279 // color, so we can use the first's without worry.
280 flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
281 target->allocator(), *target->caps().shaderCaps(), fHead->fColor,
282 /*wideColor=*/false, fColorSpaceXform, views, numActiveViews, filter,
283 maskFormat, localMatrix, fHasPerspective);
284 }
285
286 const int vertexStride = (int)flushInfo.fGeometryProcessor->vertexStride();
287
288 // Ensure we don't request an insanely large contiguous vertex allocation.
289 static const int kMaxVertexBytes = GrBufferAllocPool::kDefaultBufferSize;
290 const int quadSize = vertexStride * kVerticesPerGlyph;
291 const int maxQuadsPerBuffer = kMaxVertexBytes / quadSize;
292
293 int allGlyphsCursor = 0;
294 const int allGlyphsEnd = fNumGlyphs;
295 int quadCursor;
296 int quadEnd;
297 char* vertices;
298
299 auto resetVertexBuffer = [&] {
300 quadCursor = 0;
301 quadEnd = std::min(maxQuadsPerBuffer, allGlyphsEnd - allGlyphsCursor);
302
303 vertices = (char*)target->makeVertexSpace(
304 vertexStride,
305 kVerticesPerGlyph * quadEnd,
306 &flushInfo.fVertexBuffer,
307 &flushInfo.fVertexOffset);
308
309 if (!vertices || !flushInfo.fVertexBuffer) {
310 SkDebugf("Could not allocate vertices\n");
311 return false;
312 }
313 return true;
314 };
315
316 if (!resetVertexBuffer()) {
317 return;
318 }
319
320 for (const Geometry* geo = fHead; geo != nullptr; geo = geo->fNext) {
321 const sktext::gpu::AtlasSubRun& subRun = geo->fSubRun;
322 SkASSERTF((int) subRun.vertexStride(geo->fDrawMatrix) == vertexStride,
323 "subRun stride: %d vertex buffer stride: %d\n",
324 (int)subRun.vertexStride(geo->fDrawMatrix), vertexStride);
325
326 const int subRunEnd = subRun.glyphCount();
327 auto regenerateDelegate = [&](sktext::gpu::GlyphVector* glyphs,
328 int begin,
329 int end,
330 skgpu::MaskFormat maskFormat,
331 int padding) {
332 return glyphs->regenerateAtlasForGanesh(begin, end, maskFormat, padding, target);
333 };
334 for (int subRunCursor = 0; subRunCursor < subRunEnd;) {
335 // Regenerate the atlas for the remainder of the glyphs in the run, or the remainder
336 // of the glyphs to fill the vertex buffer.
337 int regenEnd = subRunCursor + std::min(subRunEnd - subRunCursor, quadEnd - quadCursor);
338 auto[ok, glyphsRegenerated] = subRun.regenerateAtlas(subRunCursor, regenEnd,
339 regenerateDelegate);
340 // There was a problem allocating the glyph in the atlas. Bail.
341 if (!ok) {
342 return;
343 }
344
345 geo->fillVertexData(vertices + quadCursor * quadSize, subRunCursor, glyphsRegenerated);
346
347 subRunCursor += glyphsRegenerated;
348 quadCursor += glyphsRegenerated;
349 allGlyphsCursor += glyphsRegenerated;
350 flushInfo.fGlyphsToFlush += glyphsRegenerated;
351
352 if (quadCursor == quadEnd || subRunCursor < subRunEnd) {
353 // Flush if not all the glyphs are drawn because either the quad buffer is full or
354 // the atlas is out of space.
355 if (subRunCursor < subRunEnd) {
357 }
358 this->createDrawForGeneratedGlyphs(target, &flushInfo);
359 if (quadCursor == quadEnd && allGlyphsCursor < allGlyphsEnd) {
360 // If the vertex buffer is full and there are still glyphs to draw then
361 // get a new buffer.
362 if(!resetVertexBuffer()) {
363 return;
364 }
365 }
366 }
367 }
368 }
369}
370
371void AtlasTextOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
372 auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState,
373 std::move(fProcessors),
375
376 flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline,
378}
379
380void AtlasTextOp::createDrawForGeneratedGlyphs(GrMeshDrawTarget* target,
381 FlushInfo* flushInfo) const {
382 if (!flushInfo->fGlyphsToFlush) {
383 return;
384 }
385
386 auto atlasManager = target->atlasManager();
387
388 GrGeometryProcessor* gp = flushInfo->fGeometryProcessor;
389 MaskFormat maskFormat = this->maskFormat();
390
391 unsigned int numActiveViews;
392 const GrSurfaceProxyView* views = atlasManager->getViews(maskFormat, &numActiveViews);
393 SkASSERT(views);
394 // Something has gone terribly wrong, bail
395 if (!views || 0 == numActiveViews) {
396 return;
397 }
398 if (gp->numTextureSamplers() != (int) numActiveViews) {
399 // During preparation the number of atlas pages has increased.
400 // Update the proxies used in the GP to match.
401 for (unsigned i = gp->numTextureSamplers(); i < numActiveViews; ++i) {
402 flushInfo->fPrimProcProxies[i] = views[i].proxy();
403 // This op does not know its atlas proxies when it is added to a OpsTasks, so the
404 // proxies don't get added during the visitProxies call. Thus we add them here.
405 target->sampledProxyArray()->push_back(views[i].proxy());
406 // These will get unreffed when the previously recorded draws destruct.
407 for (int d = 0; d < flushInfo->fNumDraws; ++d) {
408 flushInfo->fPrimProcProxies[i]->ref();
409 }
410 }
411#if !defined(SK_DISABLE_SDF_TEXT)
412 if (this->usesDistanceFields()) {
413 if (this->isLCD()) {
414 reinterpret_cast<GrDistanceFieldLCDTextGeoProc*>(gp)->addNewViews(
415 views, numActiveViews, GrSamplerState::Filter::kLinear);
416 } else {
417 reinterpret_cast<GrDistanceFieldA8TextGeoProc*>(gp)->addNewViews(
418 views, numActiveViews, GrSamplerState::Filter::kLinear);
419 }
420 } else
421#endif
422 {
423 auto filter = fNeedsGlyphTransform ? GrSamplerState::Filter::kLinear
425 reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewViews(views, numActiveViews, filter);
426 }
427 }
428 int maxGlyphsPerDraw = static_cast<int>(flushInfo->fIndexBuffer->size() / sizeof(uint16_t) / 6);
429 GrSimpleMesh* mesh = target->allocMesh();
430 mesh->setIndexedPatterned(flushInfo->fIndexBuffer, kIndicesPerGlyph, flushInfo->fGlyphsToFlush,
431 maxGlyphsPerDraw, flushInfo->fVertexBuffer, kVerticesPerGlyph,
432 flushInfo->fVertexOffset);
433 target->recordDraw(flushInfo->fGeometryProcessor, mesh, 1, flushInfo->fPrimProcProxies,
435 flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
436 flushInfo->fGlyphsToFlush = 0;
437 ++flushInfo->fNumDraws;
438}
439
440GrOp::CombineResult AtlasTextOp::onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) {
441 auto that = t->cast<AtlasTextOp>();
442
443 if (fDFGPFlags != that->fDFGPFlags ||
444 fMaskType != that->fMaskType ||
445 fUsesLocalCoords != that->fUsesLocalCoords ||
446 fNeedsGlyphTransform != that->fNeedsGlyphTransform ||
447 fHasPerspective != that->fHasPerspective ||
448 fUseGammaCorrectDistanceTable != that->fUseGammaCorrectDistanceTable) {
449 // All flags must match for an op to be combined
451 }
452
453 if (fProcessors != that->fProcessors) {
455 }
456
457 if (fUsesLocalCoords) {
458 // If the fragment processors use local coordinates, the GPs compute them using the inverse
459 // of the view matrix stored in a uniform, so all geometries must have the same matrix.
460 const SkMatrix& thisFirstMatrix = fHead->fDrawMatrix;
461 const SkMatrix& thatFirstMatrix = that->fHead->fDrawMatrix;
462 if (!SkMatrixPriv::CheapEqual(thisFirstMatrix, thatFirstMatrix)) {
464 }
465 }
466
467#if !defined(SK_DISABLE_SDF_TEXT)
468 if (this->usesDistanceFields()) {
469 SkASSERT(that->usesDistanceFields());
470 if (fLuminanceColor != that->fLuminanceColor) {
472 }
473 } else
474#endif
475 {
476 if (this->maskType() == MaskType::kColorBitmap &&
477 fHead->fColor != that->fHead->fColor) {
478 // This ensures all merged bitmap color text ops have a constant color
480 }
481 }
482
483 fNumGlyphs += that->fNumGlyphs;
484
485 // After concat, that's geometry list is emptied so it will not unref the blobs when destructed
486 this->addGeometry(that->fHead);
487 that->fHead = nullptr;
489}
490
491#if !defined(SK_DISABLE_SDF_TEXT)
492GrGeometryProcessor* AtlasTextOp::setupDfProcessor(SkArenaAlloc* arena,
493 const GrShaderCaps& caps,
494 const SkMatrix& localMatrix,
495 const GrSurfaceProxyView* views,
496 unsigned int numActiveViews) const {
497 auto dfAdjustTable = sktext::gpu::DistanceFieldAdjustTable::Get();
498
499 // see if we need to create a new effect
500 if (this->isLCD()) {
501 float redCorrection = dfAdjustTable->getAdjustment(SkColorGetR(fLuminanceColor),
502 fUseGammaCorrectDistanceTable);
503 float greenCorrection = dfAdjustTable->getAdjustment(SkColorGetG(fLuminanceColor),
504 fUseGammaCorrectDistanceTable);
505 float blueCorrection = dfAdjustTable->getAdjustment(SkColorGetB(fLuminanceColor),
506 fUseGammaCorrectDistanceTable);
509 redCorrection, greenCorrection, blueCorrection);
510 return GrDistanceFieldLCDTextGeoProc::Make(arena, caps, views, numActiveViews,
512 fDFGPFlags, localMatrix);
513 } else {
514#if defined(SK_GAMMA_APPLY_TO_A8)
515 float correction = 0;
516 if (this->maskType() != MaskType::kAliasedDistanceField) {
518 correction = dfAdjustTable->getAdjustment(lum, fUseGammaCorrectDistanceTable);
519 }
520 return GrDistanceFieldA8TextGeoProc::Make(arena, caps, views, numActiveViews,
522 fDFGPFlags, localMatrix);
523#else
524 return GrDistanceFieldA8TextGeoProc::Make(arena, caps, views, numActiveViews,
526 localMatrix);
527#endif
528 }
529}
530#endif // !defined(SK_DISABLE_SDF_TEXT)
531
532} // namespace skgpu::ganesh
533
534
Instance * fNext
uint16_t glyphs[5]
Definition: FontMgrTest.cpp:46
int count
Definition: FontMgrTest.cpp:50
GrProcessorAnalysisCoverage
GrClampType
Definition: GrTypesPriv.h:228
std::function< void(GrSurfaceProxy *, skgpu::Mipmapped)> GrVisitProxyFunc
Definition: GrTypesPriv.h:943
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SkASSERTF(cond, fmt,...)
Definition: SkAssert.h:117
unsigned U8CPU
Definition: SkCPUTypes.h:18
#define SkColorGetR(color)
Definition: SkColor.h:65
#define SkColorGetG(color)
Definition: SkColor.h:69
uint32_t SkColor
Definition: SkColor.h:37
#define SkColorGetB(color)
Definition: SkColor.h:73
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static bool ok(int result)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
#define ATRACE_ANDROID_FRAMEWORK_ALWAYS(fmt,...)
#define SK_GAMMA_EXPONENT
Definition: SkTypes.h:86
const GrSurfaceProxyView * getViews(skgpu::MaskFormat format, unsigned int *numActiveProxies)
static GrGeometryProcessor * Make(SkArenaAlloc *arena, const GrShaderCaps &caps, const SkPMColor4f &color, bool wideColor, sk_sp< GrColorSpaceXform > colorSpaceXform, const GrSurfaceProxyView *views, int numActiveViews, GrSamplerState p, skgpu::MaskFormat format, const SkMatrix &localMatrix, bool usesW)
static constexpr int kMaxTextures
static constexpr size_t kDefaultBufferSize
Definition: GrCaps.h:57
sk_sp< GrColorSpaceXform > refColorSpaceXformFromSRGB() const
Definition: GrColorInfo.h:41
static GrGeometryProcessor * Make(SkArenaAlloc *arena, const GrShaderCaps &caps, const GrSurfaceProxyView *views, int numActiveViews, GrSamplerState params, uint32_t flags, const SkMatrix &localMatrixIfUsesLocalCoords)
static GrGeometryProcessor * Make(SkArenaAlloc *arena, const GrShaderCaps &caps, const GrSurfaceProxyView *views, int numActiveViews, GrSamplerState params, DistanceAdjust distanceAdjust, uint32_t flags, const SkMatrix &localMatrixIfUsesLocalCoords)
FixedFunctionFlags
Definition: GrDrawOp.h:104
void executeDrawsAndUploadsForMeshDrawOp(const GrOp *op, const SkRect &chainBounds, const GrPipeline *, const GrUserStencilSettings *)
Definition: GrOp.h:70
CombineResult
Definition: GrOp.h:99
const T & cast() const
Definition: GrOp.h:148
void setBounds(const SkRect &newBounds, HasAABloat aabloat, IsHairline zeroArea)
Definition: GrOp.h:279
void visitProxies(const GrVisitProxyFunc &) const
Analysis finalize(const GrProcessorAnalysisColor &, const GrProcessorAnalysisCoverage, const GrAppliedClip *, const GrUserStencilSettings *, const GrCaps &, GrClampType, SkPMColor4f *inputColorOverride)
static const GrPipeline * CreatePipeline(const GrCaps *, SkArenaAlloc *, skgpu::Swizzle writeViewSwizzle, GrAppliedClip &&, const GrDstProxyView &, GrProcessorSet &&, GrPipeline::InputFlags pipelineFlags)
GrSurfaceProxy * proxy() const
static U8CPU computeLuminance(SkScalar gamma, SkColor c)
Definition: SkMaskGamma.h:39
static bool CheapEqual(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrixPriv.h:181
bool invert(SkMatrix *inverse) const
Definition: SkMatrix.h:1206
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:550
GrProcessorSet::Analysis finalize(const GrCaps &, const GrAppliedClip *, GrClampType) override
FixedFunctionFlags fixedFunctionFlags() const override
void visitProxies(const GrVisitProxyFunc &) const override
virtual std::tuple< bool, int > regenerateAtlas(int begin, int end, RegenerateAtlasDelegate) const =0
virtual int glyphCount() const =0
static const DistanceFieldAdjustTable * Get()
const Paint & paint
Definition: color_source.cc:38
DlColor color
static const char * begin(const StringSlice &s)
Definition: editor.cpp:252
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
struct MyStruct s
glong glong end
uint32_t * target
static float lum(float r, float g, float b)
Definition: hsl.cpp:52
static float min(float r, float g, float b)
Definition: hsl.cpp:48
clipRect(r.rect, r.opAA.op(), r.opAA.aa())) template<> void Draw
SkMesh mesh
Definition: SkRecords.h:345
dst
Definition: cp.py:12
static constexpr int kVerticesPerGlyph
Definition: AtlasTextOp.cpp:58
static constexpr int kIndicesPerGlyph
Definition: AtlasTextOp.cpp:59
static thread_local void * gCache
Definition: AtlasTextOp.cpp:62
MaskFormat
Definition: AtlasTypes.h:98
Definition: ref_ptr.h:256
SeparatedVector2 offset
static DistanceAdjust Make(SkScalar r, SkScalar g, SkScalar b)
static const GrUserStencilSettings & kUnused
Definition: SkRect.h:32
uint32_t toBytes_RGBA() const
static Geometry * Make(const sktext::gpu::AtlasSubRun &subRun, const SkMatrix &drawMatrix, SkPoint drawOrigin, SkIRect clipRect, sk_sp< SkRefCnt > &&supportData, const SkPMColor4f &color, SkArenaAlloc *alloc)
void fillVertexData(void *dst, int offset, int count) const
const sktext::gpu::AtlasSubRun & fSubRun
Definition: AtlasTextOp.h:94