Flutter Engine
The Flutter Engine
DrawAtlas.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 Google LLC
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
10#include <memory>
11
17
18#include "src/base/SkMathPriv.h"
20#include "src/gpu/AtlasTypes.h"
27
28using namespace skia_private;
29
30namespace skgpu::graphite {
31
32#if defined(DUMP_ATLAS_DATA)
33static const constexpr bool kDumpAtlasData = true;
34#else
35static const constexpr bool kDumpAtlasData = false;
36#endif
37
38#ifdef SK_DEBUG
39void DrawAtlas::validate(const AtlasLocator& atlasLocator) const {
40 // Verify that the plotIndex stored in the PlotLocator is consistent with the glyph rectangle
41 int numPlotsX = fTextureWidth / fPlotWidth;
42 int numPlotsY = fTextureHeight / fPlotHeight;
43
44 int plotIndex = atlasLocator.plotIndex();
45 auto topLeft = atlasLocator.topLeft();
46 int plotX = topLeft.x() / fPlotWidth;
47 int plotY = topLeft.y() / fPlotHeight;
48 SkASSERT(plotIndex == (numPlotsY - plotY - 1) * numPlotsX + (numPlotsX - plotX - 1));
49}
50#endif
51
52std::unique_ptr<DrawAtlas> DrawAtlas::Make(SkColorType colorType, size_t bpp, int width,
53 int height, int plotWidth, int plotHeight,
54 AtlasGenerationCounter* generationCounter,
55 AllowMultitexturing allowMultitexturing,
56 UseStorageTextures useStorageTextures,
57 PlotEvictionCallback* evictor,
58 std::string_view label) {
59 std::unique_ptr<DrawAtlas> atlas(new DrawAtlas(colorType, bpp, width, height,
60 plotWidth, plotHeight, generationCounter,
61 allowMultitexturing, useStorageTextures, label));
62
63 if (evictor != nullptr) {
64 atlas->fEvictionCallbacks.emplace_back(evictor);
65 }
66 return atlas;
67}
68
69///////////////////////////////////////////////////////////////////////////////
70static uint32_t next_id() {
71 static std::atomic<uint32_t> nextID{1};
72 uint32_t id;
73 do {
74 id = nextID.fetch_add(1, std::memory_order_relaxed);
75 } while (id == SK_InvalidGenID);
76 return id;
77}
78DrawAtlas::DrawAtlas(SkColorType colorType, size_t bpp, int width, int height,
79 int plotWidth, int plotHeight, AtlasGenerationCounter* generationCounter,
80 AllowMultitexturing allowMultitexturing,
81 UseStorageTextures useStorageTextures,
82 std::string_view label)
84 , fBytesPerPixel(bpp)
85 , fTextureWidth(width)
86 , fTextureHeight(height)
87 , fPlotWidth(plotWidth)
88 , fPlotHeight(plotHeight)
89 , fUseStorageTextures(useStorageTextures)
90 , fLabel(label)
91 , fAtlasID(next_id())
92 , fGenerationCounter(generationCounter)
93 , fAtlasGeneration(fGenerationCounter->next())
94 , fPrevFlushToken(AtlasToken::InvalidToken())
95 , fFlushesSinceLastUse(0)
96 , fMaxPages(allowMultitexturing == AllowMultitexturing::kYes ?
97 PlotLocator::kMaxMultitexturePages : 1)
98 , fNumActivePages(0) {
99 int numPlotsX = width/plotWidth;
100 int numPlotsY = height/plotHeight;
101 SkASSERT(numPlotsX * numPlotsY <= PlotLocator::kMaxPlots);
102 SkASSERTF(fPlotWidth * numPlotsX == fTextureWidth,
103 "Invalid DrawAtlas. Plot width: %d, texture width %d", fPlotWidth, fTextureWidth);
104 SkASSERTF(fPlotHeight * numPlotsY == fTextureHeight,
105 "Invalid DrawAtlas. Plot height: %d, texture height %d", fPlotHeight, fTextureHeight);
106
107 fNumPlots = numPlotsX * numPlotsY;
108
109 this->createPages(generationCounter);
110}
111
112inline void DrawAtlas::processEviction(PlotLocator plotLocator) {
113 for (PlotEvictionCallback* evictor : fEvictionCallbacks) {
114 evictor->evict(plotLocator);
115 }
116
117 fAtlasGeneration = fGenerationCounter->next();
118}
119
120inline void DrawAtlas::updatePlot(Plot* plot, AtlasLocator* atlasLocator) {
121 int pageIdx = plot->pageIndex();
122 this->makeMRU(plot, pageIdx);
123
124 // The actual upload will be created in recordUploads().
125
126 atlasLocator->updatePlotLocator(plot->plotLocator());
127 SkDEBUGCODE(this->validate(*atlasLocator);)
128}
129
130bool DrawAtlas::addRectToPage(unsigned int pageIdx, int width, int height,
131 AtlasLocator* atlasLocator) {
132 SkASSERT(fProxies[pageIdx]);
133
134 // look through all allocated plots for one we can share, in Most Recently Refed order
135 PlotList::Iter plotIter;
136 plotIter.init(fPages[pageIdx].fPlotList, PlotList::Iter::kHead_IterStart);
137
138 for (Plot* plot = plotIter.get(); plot; plot = plotIter.next()) {
139 if (plot->addRect(width, height, atlasLocator)) {
140 this->updatePlot(plot, atlasLocator);
141 return true;
142 }
143 }
144
145 return false;
146}
147
148bool DrawAtlas::recordUploads(DrawContext* dc, Recorder* recorder) {
149 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
150 for (uint32_t pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
151 PlotList::Iter plotIter;
152 plotIter.init(fPages[pageIdx].fPlotList, PlotList::Iter::kHead_IterStart);
153 for (Plot* plot = plotIter.get(); plot; plot = plotIter.next()) {
154 if (plot->needsUpload()) {
155 TextureProxy* proxy = fProxies[pageIdx].get();
156 SkASSERT(proxy);
157
158 const void* dataPtr;
159 SkIRect dstRect;
160 std::tie(dataPtr, dstRect) = plot->prepareForUpload();
161 if (dstRect.isEmpty()) {
162 continue;
163 }
164
165 std::vector<MipLevel> levels;
166 levels.push_back({dataPtr, fBytesPerPixel*fPlotWidth});
167
168 // Src and dst colorInfo are the same
169 SkColorInfo colorInfo(fColorType, kUnknown_SkAlphaType, nullptr);
170 if (!dc->recordUpload(recorder, sk_ref_sp(proxy), colorInfo, colorInfo, levels,
171 dstRect, /*ConditionalUploadContext=*/nullptr)) {
172 return false;
173 }
174 }
175 }
176 }
177 return true;
178}
179
180// Number of atlas-related flushes beyond which we consider a plot to no longer be in use.
181//
182// This value is somewhat arbitrary -- the idea is to keep it low enough that
183// a page with unused plots will get removed reasonably quickly, but allow it
184// to hang around for a bit in case it's needed. The assumption is that flushes
185// are rare; i.e., we are not continually refreshing the frame.
186static constexpr auto kPlotRecentlyUsedCount = 32;
187static constexpr auto kAtlasRecentlyUsedCount = 128;
188
189DrawAtlas::ErrorCode DrawAtlas::addRect(Recorder* recorder,
190 int width, int height,
191 AtlasLocator* atlasLocator) {
192 if (width > fPlotWidth || height > fPlotHeight || width < 0 || height < 0) {
193 return ErrorCode::kError;
194 }
195
196 // We permit zero-sized rects to allow inverse fills in the PathAtlases to work,
197 // but we don't want to enter them in the Rectanizer. So we handle this special case here.
198 // For text this should be caught at a higher level, but if not the only end result
199 // will be rendering a degenerate quad.
200 if (width == 0 || height == 0) {
201 if (fNumActivePages == 0) {
202 // Make sure we have a Page for the AtlasLocator to refer to
203 this->activateNewPage(recorder);
204 }
205 atlasLocator->updateRect(skgpu::IRect16::MakeXYWH(0, 0, 0, 0));
206 // Use the MRU Plot from the first Page
207 atlasLocator->updatePlotLocator(fPages[0].fPlotList.head()->plotLocator());
208 return ErrorCode::kSucceeded;
209 }
210
211 // Look through each page to see if we can upload without having to flush
212 // We prioritize this upload to the first pages, not the most recently used, to make it easier
213 // to remove unused pages in reverse page order.
214 for (unsigned int pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
215 if (this->addRectToPage(pageIdx, width, height, atlasLocator)) {
216 return ErrorCode::kSucceeded;
217 }
218 }
219
220 // If the above fails, then see if the least recently used plot per page has already been
221 // queued for upload if we're at max page allocation, or if the plot has aged out otherwise.
222 // We wait until we've grown to the full number of pages to begin evicting already queued
223 // plots so that we can maximize the opportunity for reuse.
224 // As before we prioritize this upload to the first pages, not the most recently used.
225 if (fNumActivePages == this->maxPages()) {
226 for (unsigned int pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
227 Plot* plot = fPages[pageIdx].fPlotList.tail();
228 SkASSERT(plot);
229 if (plot->lastUseToken() < recorder->priv().tokenTracker()->nextFlushToken()) {
230 this->processEvictionAndResetRects(plot);
231 SkDEBUGCODE(bool verify = )plot->addRect(width, height, atlasLocator);
232 SkASSERT(verify);
233 this->updatePlot(plot, atlasLocator);
234 return ErrorCode::kSucceeded;
235 }
236 }
237 } else {
238 // If we haven't activated all the available pages, try to create a new one and add to it
239 if (!this->activateNewPage(recorder)) {
240 return ErrorCode::kError;
241 }
242
243 if (this->addRectToPage(fNumActivePages-1, width, height, atlasLocator)) {
244 return ErrorCode::kSucceeded;
245 } else {
246 // If we fail to upload to a newly activated page then something has gone terribly
247 // wrong - return an error
248 return ErrorCode::kError;
249 }
250 }
251
252 if (!fNumActivePages) {
253 return ErrorCode::kError;
254 }
255
256 // All plots are currently in use by the current set of draws, so we need to fail. This
257 // gives the Device a chance to snap the current set of uploads and draws, advance the draw
258 // token, and call back into this function. The subsequent call will have plots available
259 // for fresh uploads.
260 return ErrorCode::kTryAgain;
261}
262
263DrawAtlas::ErrorCode DrawAtlas::addToAtlas(Recorder* recorder,
264 int width, int height, const void* image,
265 AtlasLocator* atlasLocator) {
266 ErrorCode ec = this->addRect(recorder, width, height, atlasLocator);
267 if (ec == ErrorCode::kSucceeded) {
268 Plot* plot = this->findPlot(*atlasLocator);
269 plot->copySubImage(*atlasLocator, image);
270 }
271
272 return ec;
273}
274
275SkIPoint DrawAtlas::prepForRender(const AtlasLocator& locator, SkAutoPixmapStorage* pixmap) {
276 Plot* plot = this->findPlot(locator);
277 return plot->prepForRender(locator, pixmap);
278}
279
280void DrawAtlas::compact(AtlasToken startTokenForNextFlush) {
281 if (fNumActivePages < 1) {
282 fPrevFlushToken = startTokenForNextFlush;
283 return;
284 }
285
286 // For all plots, reset number of flushes since used if used this frame.
287 PlotList::Iter plotIter;
288 bool atlasUsedThisFlush = false;
289 for (uint32_t pageIndex = 0; pageIndex < fNumActivePages; ++pageIndex) {
290 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
291 while (Plot* plot = plotIter.get()) {
292 // Reset number of flushes since used
293 if (plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
294 plot->resetFlushesSinceLastUsed();
295 atlasUsedThisFlush = true;
296 }
297
298 plotIter.next();
299 }
300 }
301
302 if (atlasUsedThisFlush) {
303 fFlushesSinceLastUse = 0;
304 } else {
305 ++fFlushesSinceLastUse;
306 }
307
308 // We only try to compact if the atlas was used in the recently completed flush or
309 // hasn't been used in a long time.
310 // This is to handle the case where a lot of text or path rendering has occurred but then just
311 // a blinking cursor is drawn.
312 if (atlasUsedThisFlush || fFlushesSinceLastUse > kAtlasRecentlyUsedCount) {
313 TArray<Plot*> availablePlots;
314 uint32_t lastPageIndex = fNumActivePages - 1;
315
316 // For all plots but the last one, update number of flushes since used, and check to see
317 // if there are any in the first pages that the last page can safely upload to.
318 for (uint32_t pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex) {
319 if constexpr (kDumpAtlasData) {
320 SkDebugf("page %u: ", pageIndex);
321 }
322
323 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
324 while (Plot* plot = plotIter.get()) {
325 // Update number of flushes since plot was last used
326 // We only increment the 'sinceLastUsed' count for flushes where the atlas was used
327 // to avoid deleting everything when we return to text drawing in the blinking
328 // cursor case
329 if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
330 plot->incFlushesSinceLastUsed();
331 }
332
333 if constexpr (kDumpAtlasData) {
334 SkDebugf("%d ", plot->flushesSinceLastUsed());
335 }
336
337 // Count plots we can potentially upload to in all pages except the last one
338 // (the potential compactee).
339 if (plot->flushesSinceLastUsed() > kPlotRecentlyUsedCount) {
340 availablePlots.push_back() = plot;
341 }
342
343 plotIter.next();
344 }
345
346 if constexpr (kDumpAtlasData) {
347 SkDebugf("\n");
348 }
349 }
350
351 // Count recently used plots in the last page and evict any that are no longer in use.
352 // Since we prioritize uploading to the first pages, this will eventually
353 // clear out usage of this page unless we have a large need.
354 plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
355 unsigned int usedPlots = 0;
356 if constexpr (kDumpAtlasData) {
357 SkDebugf("page %u: ", lastPageIndex);
358 }
359 while (Plot* plot = plotIter.get()) {
360 // Update number of flushes since plot was last used
361 if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
362 plot->incFlushesSinceLastUsed();
363 }
364
365 if constexpr (kDumpAtlasData) {
366 SkDebugf("%d ", plot->flushesSinceLastUsed());
367 }
368
369 // If this plot was used recently
370 if (plot->flushesSinceLastUsed() <= kPlotRecentlyUsedCount) {
371 usedPlots++;
372 } else if (plot->lastUseToken() != AtlasToken::InvalidToken()) {
373 // otherwise if aged out just evict it.
374 this->processEvictionAndResetRects(plot);
375 }
376 plotIter.next();
377 }
378
379 if constexpr (kDumpAtlasData) {
380 SkDebugf("\n");
381 }
382
383 // If recently used plots in the last page are using less than a quarter of the page, try
384 // to evict them if there's available space in lower index pages. Since we prioritize
385 // uploading to the first pages, this will eventually clear out usage of this page unless
386 // we have a large need.
387 if (availablePlots.size() && usedPlots && usedPlots <= fNumPlots / 4) {
388 plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
389 while (Plot* plot = plotIter.get()) {
390 // If this plot was used recently
391 if (plot->flushesSinceLastUsed() <= kPlotRecentlyUsedCount) {
392 // See if there's room in an lower index page and if so evict.
393 // We need to be somewhat harsh here so that a handful of plots that are
394 // consistently in use don't end up locking the page in memory.
395 if (availablePlots.size() > 0) {
396 this->processEvictionAndResetRects(plot);
397 this->processEvictionAndResetRects(availablePlots.back());
398 availablePlots.pop_back();
399 --usedPlots;
400 }
401 if (!usedPlots || !availablePlots.size()) {
402 break;
403 }
404 }
405 plotIter.next();
406 }
407 }
408
409 // If none of the plots in the last page have been used recently, delete it.
410 if (!usedPlots) {
411 if constexpr (kDumpAtlasData) {
412 SkDebugf("delete %u\n", fNumActivePages-1);
413 }
414
415 this->deactivateLastPage();
416 fFlushesSinceLastUse = 0;
417 }
418 }
419
420 fPrevFlushToken = startTokenForNextFlush;
421}
422
423bool DrawAtlas::createPages(AtlasGenerationCounter* generationCounter) {
424 SkASSERT(SkIsPow2(fTextureWidth) && SkIsPow2(fTextureHeight));
425
426 int numPlotsX = fTextureWidth/fPlotWidth;
427 int numPlotsY = fTextureHeight/fPlotHeight;
428
429 for (uint32_t i = 0; i < this->maxPages(); ++i) {
430 // Proxies are uncreated at first
431 fProxies[i] = nullptr;
432
433 // set up allocated plots
434 fPages[i].fPlotArray = std::make_unique<sk_sp<Plot>[]>(numPlotsX * numPlotsY);
435
436 sk_sp<Plot>* currPlot = fPages[i].fPlotArray.get();
437 for (int y = numPlotsY - 1, r = 0; y >= 0; --y, ++r) {
438 for (int x = numPlotsX - 1, c = 0; x >= 0; --x, ++c) {
439 uint32_t plotIndex = r * numPlotsX + c;
440 currPlot->reset(new Plot(
441 i, plotIndex, generationCounter, x, y, fPlotWidth, fPlotHeight, fColorType,
442 fBytesPerPixel));
443
444 // build LRU list
445 fPages[i].fPlotList.addToHead(currPlot->get());
446 ++currPlot;
447 }
448 }
449 }
450
451 return true;
452}
453
454bool DrawAtlas::activateNewPage(Recorder* recorder) {
455 SkASSERT(fNumActivePages < this->maxPages());
456 SkASSERT(!fProxies[fNumActivePages]);
457
458 const Caps* caps = recorder->priv().caps();
459 auto textureInfo = fUseStorageTextures == UseStorageTextures::kYes
461 : caps->getDefaultSampledTextureInfo(fColorType,
463 recorder->priv().isProtected(),
465 fProxies[fNumActivePages] = TextureProxy::Make(caps,
466 recorder->priv().resourceProvider(),
467 {fTextureWidth, fTextureHeight},
468 textureInfo,
469 fLabel,
471 if (!fProxies[fNumActivePages]) {
472 return false;
473 }
474
475 if constexpr (kDumpAtlasData) {
476 SkDebugf("activated page#: %u\n", fNumActivePages);
477 }
478
479 ++fNumActivePages;
480 return true;
481}
482
483inline void DrawAtlas::deactivateLastPage() {
484 SkASSERT(fNumActivePages);
485
486 uint32_t lastPageIndex = fNumActivePages - 1;
487
488 int numPlotsX = fTextureWidth/fPlotWidth;
489 int numPlotsY = fTextureHeight/fPlotHeight;
490
491 fPages[lastPageIndex].fPlotList.reset();
492 for (int r = 0; r < numPlotsY; ++r) {
493 for (int c = 0; c < numPlotsX; ++c) {
494 uint32_t plotIndex = r * numPlotsX + c;
495
496 Plot* currPlot = fPages[lastPageIndex].fPlotArray[plotIndex].get();
497 currPlot->resetRects();
498 currPlot->resetFlushesSinceLastUsed();
499
500 // rebuild the LRU list
501 SkDEBUGCODE(currPlot->resetListPtrs());
502 fPages[lastPageIndex].fPlotList.addToHead(currPlot);
503 }
504 }
505
506 // remove ref to the texture proxy
507 fProxies[lastPageIndex].reset();
508 --fNumActivePages;
509}
510
511void DrawAtlas::markUsedPlotsAsFull() {
512 PlotList::Iter plotIter;
513 for (uint32_t pageIndex = 0; pageIndex < fNumActivePages; ++pageIndex) {
514 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
515 while (Plot* plot = plotIter.get()) {
516 plot->markFullIfUsed();
517 plotIter.next();
518 }
519 }
520}
521
522void DrawAtlas::evictAllPlots() {
523 PlotList::Iter plotIter;
524 for (uint32_t pageIndex = 0; pageIndex < fNumActivePages; ++pageIndex) {
525 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
526 while (Plot* plot = plotIter.get()) {
527 this->processEvictionAndResetRects(plot);
528 plotIter.next();
529 }
530 }
531}
532
533DrawAtlasConfig::DrawAtlasConfig(int maxTextureSize, size_t maxBytes) {
534 static const SkISize kARGBDimensions[] = {
535 {256, 256}, // maxBytes < 2^19
536 {512, 256}, // 2^19 <= maxBytes < 2^20
537 {512, 512}, // 2^20 <= maxBytes < 2^21
538 {1024, 512}, // 2^21 <= maxBytes < 2^22
539 {1024, 1024}, // 2^22 <= maxBytes < 2^23
540 {2048, 1024}, // 2^23 <= maxBytes
541 };
542
543 // Index 0 corresponds to maxBytes of 2^18, so start by dividing it by that
544 maxBytes >>= 18;
545 // Take the floor of the log to get the index
546 int index = maxBytes > 0
547 ? SkTPin<int>(SkPrevLog2(maxBytes), 0, std::size(kARGBDimensions) - 1)
548 : 0;
549
550 SkASSERT(kARGBDimensions[index].width() <= kMaxAtlasDim);
551 SkASSERT(kARGBDimensions[index].height() <= kMaxAtlasDim);
552 fARGBDimensions.set(std::min<int>(kARGBDimensions[index].width(), maxTextureSize),
553 std::min<int>(kARGBDimensions[index].height(), maxTextureSize));
554 fMaxTextureSize = std::min<int>(maxTextureSize, kMaxAtlasDim);
555}
556
557SkISize DrawAtlasConfig::atlasDimensions(MaskFormat type) const {
558 if (MaskFormat::kA8 == type) {
559 // A8 is always 2x the ARGB dimensions, clamped to the max allowed texture size
560 return { std::min<int>(2 * fARGBDimensions.width(), fMaxTextureSize),
561 std::min<int>(2 * fARGBDimensions.height(), fMaxTextureSize) };
562 } else {
563 return fARGBDimensions;
564 }
565}
566
567SkISize DrawAtlasConfig::plotDimensions(MaskFormat type) const {
568 if (MaskFormat::kA8 == type) {
569 SkISize atlasDimensions = this->atlasDimensions(type);
570 // For A8 we want to grow the plots at larger texture sizes to accept more of the
571 // larger SDF glyphs. Since the largest SDF glyph can be 170x170 with padding, this
572 // allows us to pack 3 in a 512x256 plot, or 9 in a 512x512 plot.
573
574 // This will give us 512x256 plots for 2048x1024, 512x512 plots for 2048x2048,
575 // and 256x256 plots otherwise.
576 int plotWidth = atlasDimensions.width() >= 2048 ? 512 : 256;
577 int plotHeight = atlasDimensions.height() >= 2048 ? 512 : 256;
578
579 return { plotWidth, plotHeight };
580 } else {
581 // ARGB and LCD always use 256x256 plots -- this has been shown to be faster
582 return { 256, 256 };
583 }
584}
585
586} // namespace skgpu::graphite
static constexpr auto kPlotRecentlyUsedCount
skgpu::Plot Plot
static constexpr auto kAtlasRecentlyUsedCount
static const constexpr bool kDumpAtlasData
static float next(float f)
SkColorType fColorType
@ kUnknown_SkAlphaType
uninitialized
Definition: SkAlphaType.h:27
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SkASSERTF(cond, fmt,...)
Definition: SkAssert.h:117
SkColorType
Definition: SkColorType.h:19
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static int SkPrevLog2(uint32_t value)
Definition: SkMathPriv.h:257
constexpr bool SkIsPow2(T value)
Definition: SkMath.h:51
@ kYes
Do pre-clip the geometry before applying the (perspective) matrix.
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
#define TRACE_FUNC
Definition: SkTraceEvent.h:30
static constexpr uint32_t SK_InvalidGenID
Definition: SkTypes.h:192
GLenum type
T * get() const
Definition: SkRefCnt.h:303
uint32_t plotIndex() const
Definition: AtlasTypes.h:305
void updateRect(skgpu::IRect16 rect)
Definition: AtlasTypes.h:345
SkIPoint topLeft() const
Definition: AtlasTypes.h:309
void updatePlotLocator(PlotLocator p)
Definition: AtlasTypes.h:337
static AtlasToken InvalidToken()
Definition: AtlasTypes.h:153
static constexpr int kMaxPlots
Definition: AtlasTypes.h:246
void resetRects()
Definition: AtlasTypes.cpp:160
void resetFlushesSinceLastUsed()
Definition: AtlasTypes.h:484
AtlasToken nextFlushToken() const
Definition: AtlasTypes.h:207
virtual TextureInfo getDefaultStorageTextureInfo(SkColorType) const =0
static std::unique_ptr< DrawAtlas > Make(SkColorType ct, size_t bpp, int width, int height, int plotWidth, int plotHeight, AtlasGenerationCounter *generationCounter, AllowMultitexturing allowMultitexturing, UseStorageTextures useStorageTextures, PlotEvictionCallback *evictor, std::string_view label)
Definition: DrawAtlas.cpp:52
bool recordUpload(Recorder *recorder, sk_sp< TextureProxy > targetProxy, const SkColorInfo &srcColorInfo, const SkColorInfo &dstColorInfo, const std::vector< MipLevel > &levels, const SkIRect &dstRect, std::unique_ptr< ConditionalUploadContext >)
TokenTracker * tokenTracker()
Definition: RecorderPriv.h:62
Protected isProtected() const
Definition: RecorderPriv.h:52
const Caps * caps() const
Definition: RecorderPriv.h:31
ResourceProvider * resourceProvider()
Definition: RecorderPriv.h:33
int size() const
Definition: SkTArray.h:421
double y
double x
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
sk_sp< const SkImage > atlas
Definition: SkRecords.h:331
sk_sp< const SkImage > image
Definition: SkRecords.h:269
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
static const constexpr bool kDumpAtlasData
Definition: DrawAtlas.cpp:35
static uint32_t next_id()
Definition: DrawAtlas.cpp:70
MaskFormat
Definition: AtlasTypes.h:98
@ kA8
1-byte per pixel
static void plot(SkCanvas *canvas, const char *fn, float xMin, float xMax, float yMin, float yMax, const char *label=nullptr, bool requireES3=false)
int32_t height
int32_t width
constexpr int32_t x() const
Definition: SkPoint_impl.h:46
Definition: SkRect.h:32
bool isEmpty() const
Definition: SkRect.h:202
Definition: SkSize.h:16
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
static IRect16 MakeXYWH(int16_t x, int16_t y, int16_t w, int16_t h)
Definition: AtlasTypes.h:54
const uintptr_t id
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131