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