Flutter Engine
The Flutter Engine
GrDrawOpAtlas.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
10#include <memory>
11
23
24using namespace skia_private;
25
34
35#if defined(DUMP_ATLAS_DATA)
36static const constexpr bool kDumpAtlasData = true;
37#else
38static const constexpr bool kDumpAtlasData = false;
39#endif
40
41#ifdef SK_DEBUG
42void GrDrawOpAtlas::validate(const AtlasLocator& atlasLocator) const {
43 // Verify that the plotIndex stored in the PlotLocator is consistent with the glyph rectangle
44 int numPlotsX = fTextureWidth / fPlotWidth;
45 int numPlotsY = fTextureHeight / fPlotHeight;
46
47 int plotIndex = atlasLocator.plotIndex();
48 auto topLeft = atlasLocator.topLeft();
49 int plotX = topLeft.x() / fPlotWidth;
50 int plotY = topLeft.y() / fPlotHeight;
51 SkASSERT(plotIndex == (numPlotsY - plotY - 1) * numPlotsX + (numPlotsX - plotX - 1));
52}
53#endif
54
55// When proxy allocation is deferred until flush time the proxies acting as atlases require
56// special handling. This is because the usage that can be determined from the ops themselves
57// isn't sufficient. Independent of the ops there will be ASAP and inline uploads to the
58// atlases. Extending the usage interval of any op that uses an atlas to the start of the
59// flush (as is done for proxies that are used for sw-generated masks) also won't work because
60// the atlas persists even beyond the last use in an op - for a given flush. Given this, atlases
61// must explicitly manage the lifetime of their backing proxies via the onFlushCallback system
62// (which calls this method).
64 for (uint32_t i = 0; i < fNumActivePages; ++i) {
65 // All the atlas pages are now instantiated at flush time in the activeNewPage method.
66 SkASSERT(fViews[i].proxy() && fViews[i].proxy()->isInstantiated());
67 }
68}
69
70std::unique_ptr<GrDrawOpAtlas> GrDrawOpAtlas::Make(GrProxyProvider* proxyProvider,
72 SkColorType colorType, size_t bpp, int width,
73 int height, int plotWidth, int plotHeight,
74 GenerationCounter* generationCounter,
75 AllowMultitexturing allowMultitexturing,
76 EvictionCallback* evictor,
77 std::string_view label) {
78 if (!format.isValid()) {
79 return nullptr;
80 }
81
82 std::unique_ptr<GrDrawOpAtlas> atlas(new GrDrawOpAtlas(proxyProvider, format, colorType, bpp,
83 width, height, plotWidth, plotHeight,
84 generationCounter,
85 allowMultitexturing, label));
86 if (!atlas->createPages(proxyProvider, generationCounter) || !atlas->getViews()[0].proxy()) {
87 return nullptr;
88 }
89
90 if (evictor != nullptr) {
91 atlas->fEvictionCallbacks.emplace_back(evictor);
92 }
93 return atlas;
94}
95
96///////////////////////////////////////////////////////////////////////////////
97
98GrDrawOpAtlas::GrDrawOpAtlas(GrProxyProvider* proxyProvider, const GrBackendFormat& format,
99 SkColorType colorType, size_t bpp, int width, int height,
100 int plotWidth, int plotHeight, GenerationCounter* generationCounter,
101 AllowMultitexturing allowMultitexturing, std::string_view label)
102 : fFormat(format)
104 , fBytesPerPixel(bpp)
105 , fTextureWidth(width)
106 , fTextureHeight(height)
107 , fPlotWidth(plotWidth)
108 , fPlotHeight(plotHeight)
109 , fLabel(label)
110 , fGenerationCounter(generationCounter)
111 , fAtlasGeneration(fGenerationCounter->next())
112 , fPrevFlushToken(AtlasToken::InvalidToken())
113 , fFlushesSinceLastUse(0)
114 , fMaxPages(AllowMultitexturing::kYes == allowMultitexturing ?
115 PlotLocator::kMaxMultitexturePages : 1)
116 , fNumActivePages(0) {
117 int numPlotsX = width/plotWidth;
118 int numPlotsY = height/plotHeight;
119 SkASSERT(numPlotsX * numPlotsY <= PlotLocator::kMaxPlots);
120 SkASSERT(fPlotWidth * numPlotsX == fTextureWidth);
121 SkASSERT(fPlotHeight * numPlotsY == fTextureHeight);
122
123 fNumPlots = numPlotsX * numPlotsY;
124}
125
126inline void GrDrawOpAtlas::processEviction(PlotLocator plotLocator) {
127 for (EvictionCallback* evictor : fEvictionCallbacks) {
128 evictor->evict(plotLocator);
129 }
130
131 fAtlasGeneration = fGenerationCounter->next();
132}
133
134void GrDrawOpAtlas::uploadPlotToTexture(GrDeferredTextureUploadWritePixelsFn& writePixels,
135 GrTextureProxy* proxy,
136 Plot* plot) {
137 SkASSERT(proxy && proxy->peekTexture());
138 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
139
140 const void* dataPtr;
142 std::tie(dataPtr, rect) = plot->prepareForUpload();
143
144 writePixels(proxy,
145 rect,
146 SkColorTypeToGrColorType(fColorType),
147 dataPtr,
148 fBytesPerPixel*fPlotWidth);
149}
150
151inline bool GrDrawOpAtlas::updatePlot(GrDeferredUploadTarget* target,
152 AtlasLocator* atlasLocator, Plot* plot) {
153 uint32_t pageIdx = plot->pageIndex();
154 if (pageIdx >= fNumActivePages) {
155 return false;
156 }
157 this->makeMRU(plot, pageIdx);
158
159 // If our most recent upload has already occurred then we have to insert a new
160 // upload. Otherwise, we already have a scheduled upload that hasn't yet ocurred.
161 // This new update will piggy back on that previously scheduled update.
162 if (plot->lastUploadToken() < target->tokenTracker()->nextFlushToken()) {
163 // With c+14 we could move sk_sp into lamba to only ref once.
164 sk_sp<Plot> plotsp(SkRef(plot));
165
166 GrTextureProxy* proxy = fViews[pageIdx].asTextureProxy();
167 SkASSERT(proxy && proxy->isInstantiated()); // This is occurring at flush time
168
169 AtlasToken lastUploadToken = target->addASAPUpload(
170 [this, plotsp, proxy](GrDeferredTextureUploadWritePixelsFn& writePixels) {
171 this->uploadPlotToTexture(writePixels, proxy, plotsp.get());
172 });
173 plot->setLastUploadToken(lastUploadToken);
174 }
175 atlasLocator->updatePlotLocator(plot->plotLocator());
176 SkDEBUGCODE(this->validate(*atlasLocator);)
177 return true;
178}
179
180bool GrDrawOpAtlas::uploadToPage(unsigned int pageIdx, GrDeferredUploadTarget* target, int width,
181 int height, const void* image, AtlasLocator* atlasLocator) {
182 SkASSERT(fViews[pageIdx].proxy() && fViews[pageIdx].proxy()->isInstantiated());
183
184 // look through all allocated plots for one we can share, in Most Recently Refed order
185 PlotList::Iter plotIter;
186 plotIter.init(fPages[pageIdx].fPlotList, PlotList::Iter::kHead_IterStart);
187
188 for (Plot* plot = plotIter.get(); plot; plot = plotIter.next()) {
189 SkASSERT(GrBackendFormatBytesPerPixel(fViews[pageIdx].proxy()->backendFormat()) ==
190 plot->bpp());
191
192 if (plot->addSubImage(width, height, image, atlasLocator)) {
193 return this->updatePlot(target, atlasLocator, plot);
194 }
195 }
196
197 return false;
198}
199
200// Number of atlas-related flushes beyond which we consider a plot to no longer be in use.
201//
202// This value is somewhat arbitrary -- the idea is to keep it low enough that
203// a page with unused plots will get removed reasonably quickly, but allow it
204// to hang around for a bit in case it's needed. The assumption is that flushes
205// are rare; i.e., we are not continually refreshing the frame.
206static constexpr auto kPlotRecentlyUsedCount = 32;
207static constexpr auto kAtlasRecentlyUsedCount = 128;
208
211 int width, int height, const void* image,
212 AtlasLocator* atlasLocator) {
213 if (width > fPlotWidth || height > fPlotHeight) {
214 return ErrorCode::kError;
215 }
216
217 // Look through each page to see if we can upload without having to flush
218 // We prioritize this upload to the first pages, not the most recently used, to make it easier
219 // to remove unused pages in reverse page order.
220 for (unsigned int pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
221 if (this->uploadToPage(pageIdx, target, width, height, image, atlasLocator)) {
223 }
224 }
225
226 // If the above fails, then see if the least recently used plot per page has already been
227 // flushed to the gpu if we're at max page allocation, or if the plot has aged out otherwise.
228 // We wait until we've grown to the full number of pages to begin evicting already flushed
229 // plots so that we can maximize the opportunity for reuse.
230 // As before we prioritize this upload to the first pages, not the most recently used.
231 if (fNumActivePages == this->maxPages()) {
232 for (unsigned int pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
233 Plot* plot = fPages[pageIdx].fPlotList.tail();
234 SkASSERT(plot);
235 if (plot->lastUseToken() < target->tokenTracker()->nextFlushToken()) {
236 this->processEvictionAndResetRects(plot);
237 SkASSERT(GrBackendFormatBytesPerPixel(fViews[pageIdx].proxy()->backendFormat()) ==
238 plot->bpp());
239 SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, atlasLocator);
240 SkASSERT(verify);
241 if (!this->updatePlot(target, atlasLocator, plot)) {
242 return ErrorCode::kError;
243 }
245 }
246 }
247 } else {
248 // If we haven't activated all the available pages, try to create a new one and add to it
249 if (!this->activateNewPage(resourceProvider)) {
250 return ErrorCode::kError;
251 }
252
253 if (this->uploadToPage(fNumActivePages-1, target, width, height, image, atlasLocator)) {
255 } else {
256 // If we fail to upload to a newly activated page then something has gone terribly
257 // wrong - return an error
258 return ErrorCode::kError;
259 }
260 }
261
262 if (!fNumActivePages) {
263 return ErrorCode::kError;
264 }
265
266 // Try to find a plot that we can perform an inline upload to.
267 // We prioritize this upload in reverse order of pages to counterbalance the order above.
268 Plot* plot = nullptr;
269 for (int pageIdx = ((int)fNumActivePages)-1; pageIdx >= 0; --pageIdx) {
270 Plot* currentPlot = fPages[pageIdx].fPlotList.tail();
271 if (currentPlot->lastUseToken() != target->tokenTracker()->nextDrawToken()) {
272 plot = currentPlot;
273 break;
274 }
275 }
276
277 // If we can't find a plot that is not used in a draw currently being prepared by an op, then
278 // we have to fail. This gives the op a chance to enqueue the draw, and call back into this
279 // function. When that draw is enqueued, the draw token advances, and the subsequent call will
280 // continue past this branch and prepare an inline upload that will occur after the enqueued
281 // draw which references the plot's pre-upload content.
282 if (!plot) {
284 }
285
286 this->processEviction(plot->plotLocator());
287 int pageIdx = plot->pageIndex();
288 fPages[pageIdx].fPlotList.remove(plot);
289 sk_sp<Plot>& newPlot = fPages[pageIdx].fPlotArray[plot->plotIndex()];
290 newPlot = plot->clone();
291
292 fPages[pageIdx].fPlotList.addToHead(newPlot.get());
293 SkASSERT(GrBackendFormatBytesPerPixel(fViews[pageIdx].proxy()->backendFormat()) ==
294 newPlot->bpp());
295 SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, atlasLocator);
296 SkASSERT(verify);
297
298 // Note that this plot will be uploaded inline with the draws whereas the
299 // one it displaced most likely was uploaded ASAP.
300 // With c++14 we could move sk_sp into lambda to only ref once.
301 sk_sp<Plot> plotsp(SkRef(newPlot.get()));
302
303 GrTextureProxy* proxy = fViews[pageIdx].asTextureProxy();
304 SkASSERT(proxy && proxy->isInstantiated());
305
306 AtlasToken lastUploadToken = target->addInlineUpload(
307 [this, plotsp, proxy](GrDeferredTextureUploadWritePixelsFn& writePixels) {
308 this->uploadPlotToTexture(writePixels, proxy, plotsp.get());
309 });
310 newPlot->setLastUploadToken(lastUploadToken);
311
312 atlasLocator->updatePlotLocator(newPlot->plotLocator());
313 SkDEBUGCODE(this->validate(*atlasLocator);)
314
316}
317
318void GrDrawOpAtlas::compact(AtlasToken startTokenForNextFlush) {
319 if (fNumActivePages < 1) {
320 fPrevFlushToken = startTokenForNextFlush;
321 return;
322 }
323
324 // For all plots, reset number of flushes since used if used this frame.
325 PlotList::Iter plotIter;
326 bool atlasUsedThisFlush = false;
327 for (uint32_t pageIndex = 0; pageIndex < fNumActivePages; ++pageIndex) {
328 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
329 while (Plot* plot = plotIter.get()) {
330 // Reset number of flushes since used
331 if (plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
332 plot->resetFlushesSinceLastUsed();
333 atlasUsedThisFlush = true;
334 }
335
336 plotIter.next();
337 }
338 }
339
340 if (atlasUsedThisFlush) {
341 fFlushesSinceLastUse = 0;
342 } else {
343 ++fFlushesSinceLastUse;
344 }
345
346 // We only try to compact if the atlas was used in the recently completed flush or
347 // hasn't been used in a long time.
348 // This is to handle the case where a lot of text or path rendering has occurred but then just
349 // a blinking cursor is drawn.
350 if (atlasUsedThisFlush || fFlushesSinceLastUse > kAtlasRecentlyUsedCount) {
351 TArray<Plot*> availablePlots;
352 uint32_t lastPageIndex = fNumActivePages - 1;
353
354 // For all plots but the last one, update number of flushes since used, and check to see
355 // if there are any in the first pages that the last page can safely upload to.
356 for (uint32_t pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex) {
357 if constexpr (kDumpAtlasData) {
358 SkDebugf("page %u: ", pageIndex);
359 }
360
361 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
362 while (Plot* plot = plotIter.get()) {
363 // Update number of flushes since plot was last used
364 // We only increment the 'sinceLastUsed' count for flushes where the atlas was used
365 // to avoid deleting everything when we return to text drawing in the blinking
366 // cursor case
367 if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
368 plot->incFlushesSinceLastUsed();
369 }
370
371 if constexpr (kDumpAtlasData) {
372 SkDebugf("%d ", plot->flushesSinceLastUsed());
373 }
374
375 // Count plots we can potentially upload to in all pages except the last one
376 // (the potential compactee).
377 if (plot->flushesSinceLastUsed() > kPlotRecentlyUsedCount) {
378 availablePlots.push_back() = plot;
379 }
380
381 plotIter.next();
382 }
383
384 if constexpr (kDumpAtlasData) {
385 SkDebugf("\n");
386 }
387 }
388
389 // Count recently used plots in the last page and evict any that are no longer in use.
390 // Since we prioritize uploading to the first pages, this will eventually
391 // clear out usage of this page unless we have a large need.
392 plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
393 unsigned int usedPlots = 0;
394 if constexpr (kDumpAtlasData) {
395 SkDebugf("page %u: ", lastPageIndex);
396 }
397
398 while (Plot* plot = plotIter.get()) {
399 // Update number of flushes since plot was last used
400 if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
401 plot->incFlushesSinceLastUsed();
402 }
403
404 if constexpr (kDumpAtlasData) {
405 SkDebugf("%d ", plot->flushesSinceLastUsed());
406 }
407
408 // If this plot was used recently
409 if (plot->flushesSinceLastUsed() <= kPlotRecentlyUsedCount) {
410 usedPlots++;
411 } else if (plot->lastUseToken() != AtlasToken::InvalidToken()) {
412 // otherwise if aged out just evict it.
413 this->processEvictionAndResetRects(plot);
414 }
415 plotIter.next();
416 }
417
418 if constexpr (kDumpAtlasData) {
419 SkDebugf("\n");
420 }
421
422 // If recently used plots in the last page are using less than a quarter of the page, try
423 // to evict them if there's available space in earlier pages. Since we prioritize uploading
424 // to the first pages, this will eventually clear out usage of this page unless we have a
425 // large need.
426 if (!availablePlots.empty() && usedPlots && usedPlots <= fNumPlots / 4) {
427 plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
428 while (Plot* plot = plotIter.get()) {
429 // If this plot was used recently
430 if (plot->flushesSinceLastUsed() <= kPlotRecentlyUsedCount) {
431 // See if there's room in an earlier page and if so evict.
432 // We need to be somewhat harsh here so that a handful of plots that are
433 // consistently in use don't end up locking the page in memory.
434 if (!availablePlots.empty()) {
435 this->processEvictionAndResetRects(plot);
436 this->processEvictionAndResetRects(availablePlots.back());
437 availablePlots.pop_back();
438 --usedPlots;
439 }
440 if (!usedPlots || availablePlots.empty()) {
441 break;
442 }
443 }
444 plotIter.next();
445 }
446 }
447
448 // If none of the plots in the last page have been used recently, delete it.
449 if (!usedPlots) {
450 if constexpr (kDumpAtlasData) {
451 SkDebugf("delete %u\n", fNumActivePages - 1);
452 }
453
454 this->deactivateLastPage();
455 fFlushesSinceLastUse = 0;
456 }
457 }
458
459 fPrevFlushToken = startTokenForNextFlush;
460}
461
462bool GrDrawOpAtlas::createPages(
463 GrProxyProvider* proxyProvider, GenerationCounter* generationCounter) {
464 SkASSERT(SkIsPow2(fTextureWidth) && SkIsPow2(fTextureHeight));
465
466 SkISize dims = {fTextureWidth, fTextureHeight};
467
468 int numPlotsX = fTextureWidth/fPlotWidth;
469 int numPlotsY = fTextureHeight/fPlotHeight;
470
471 GrColorType grColorType = SkColorTypeToGrColorType(fColorType);
472
473 for (uint32_t i = 0; i < this->maxPages(); ++i) {
474 skgpu::Swizzle swizzle = proxyProvider->caps()->getReadSwizzle(fFormat, grColorType);
475 if (GrColorTypeIsAlphaOnly(grColorType)) {
476 swizzle = skgpu::Swizzle::Concat(swizzle, skgpu::Swizzle("aaaa"));
477 }
478 sk_sp<GrSurfaceProxy> proxy = proxyProvider->createProxy(fFormat,
479 dims,
481 1,
486 fLabel,
489 if (!proxy) {
490 return false;
491 }
492 fViews[i] = GrSurfaceProxyView(std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle);
493
494 // set up allocated plots
495 fPages[i].fPlotArray = std::make_unique<sk_sp<Plot>[]>(numPlotsX * numPlotsY);
496
497 sk_sp<Plot>* currPlot = fPages[i].fPlotArray.get();
498 for (int y = numPlotsY - 1, r = 0; y >= 0; --y, ++r) {
499 for (int x = numPlotsX - 1, c = 0; x >= 0; --x, ++c) {
500 uint32_t plotIndex = r * numPlotsX + c;
501 currPlot->reset(new Plot(
502 i, plotIndex, generationCounter, x, y, fPlotWidth, fPlotHeight, fColorType,
503 fBytesPerPixel));
504
505 // build LRU list
506 fPages[i].fPlotList.addToHead(currPlot->get());
507 ++currPlot;
508 }
509 }
510
511 }
512
513 return true;
514}
515
516bool GrDrawOpAtlas::activateNewPage(GrResourceProvider* resourceProvider) {
517 SkASSERT(fNumActivePages < this->maxPages());
518
519 if (!fViews[fNumActivePages].proxy()->instantiate(resourceProvider)) {
520 return false;
521 }
522
523 if constexpr (kDumpAtlasData) {
524 SkDebugf("activated page#: %u\n", fNumActivePages);
525 }
526
527 ++fNumActivePages;
528 return true;
529}
530
531inline void GrDrawOpAtlas::deactivateLastPage() {
532 SkASSERT(fNumActivePages);
533
534 uint32_t lastPageIndex = fNumActivePages - 1;
535
536 int numPlotsX = fTextureWidth/fPlotWidth;
537 int numPlotsY = fTextureHeight/fPlotHeight;
538
539 fPages[lastPageIndex].fPlotList.reset();
540 for (int r = 0; r < numPlotsY; ++r) {
541 for (int c = 0; c < numPlotsX; ++c) {
542 uint32_t plotIndex = r * numPlotsX + c;
543
544 Plot* currPlot = fPages[lastPageIndex].fPlotArray[plotIndex].get();
545 currPlot->resetRects();
546 currPlot->resetFlushesSinceLastUsed();
547
548 // rebuild the LRU list
549 SkDEBUGCODE(currPlot->resetListPtrs());
550 fPages[lastPageIndex].fPlotList.addToHead(currPlot);
551 }
552 }
553
554 // remove ref to the backing texture
555 fViews[lastPageIndex].proxy()->deinstantiate();
556 --fNumActivePages;
557}
558
559GrDrawOpAtlasConfig::GrDrawOpAtlasConfig(int maxTextureSize, size_t maxBytes) {
560 static const SkISize kARGBDimensions[] = {
561 {256, 256}, // maxBytes < 2^19
562 {512, 256}, // 2^19 <= maxBytes < 2^20
563 {512, 512}, // 2^20 <= maxBytes < 2^21
564 {1024, 512}, // 2^21 <= maxBytes < 2^22
565 {1024, 1024}, // 2^22 <= maxBytes < 2^23
566 {2048, 1024}, // 2^23 <= maxBytes
567 };
568
569 // Index 0 corresponds to maxBytes of 2^18, so start by dividing it by that
570 maxBytes >>= 18;
571 // Take the floor of the log to get the index
572 int index = maxBytes > 0
573 ? SkTPin<int>(SkPrevLog2(maxBytes), 0, std::size(kARGBDimensions) - 1)
574 : 0;
575
576 SkASSERT(kARGBDimensions[index].width() <= kMaxAtlasDim);
577 SkASSERT(kARGBDimensions[index].height() <= kMaxAtlasDim);
578 fARGBDimensions.set(std::min<int>(kARGBDimensions[index].width(), maxTextureSize),
579 std::min<int>(kARGBDimensions[index].height(), maxTextureSize));
580 fMaxTextureSize = std::min<int>(maxTextureSize, kMaxAtlasDim);
581}
582
584 if (MaskFormat::kA8 == type) {
585 // A8 is always 2x the ARGB dimensions, clamped to the max allowed texture size
586 return { std::min<int>(2 * fARGBDimensions.width(), fMaxTextureSize),
587 std::min<int>(2 * fARGBDimensions.height(), fMaxTextureSize) };
588 } else {
589 return fARGBDimensions;
590 }
591}
592
594 if (MaskFormat::kA8 == type) {
596 // For A8 we want to grow the plots at larger texture sizes to accept more of the
597 // larger SDF glyphs. Since the largest SDF glyph can be 170x170 with padding, this
598 // allows us to pack 3 in a 512x256 plot, or 9 in a 512x512 plot.
599
600 // This will give us 512x256 plots for 2048x1024, 512x512 plots for 2048x2048,
601 // and 256x256 plots otherwise.
602 int plotWidth = atlasDimensions.width() >= 2048 ? 512 : 256;
603 int plotHeight = atlasDimensions.height() >= 2048 ? 512 : 256;
604
605 return { plotWidth, plotHeight };
606 } else {
607 // ARGB and LCD always use 256x256 plots -- this has been shown to be faster
608 return { 256, 256 };
609 }
610}
size_t GrBackendFormatBytesPerPixel(const GrBackendFormat &format)
std::function< bool(GrTextureProxy *, SkIRect, GrColorType srcColorType, const void *, size_t rowBytes)> GrDeferredTextureUploadWritePixelsFn
skgpu::AtlasLocator AtlasLocator
static constexpr auto kPlotRecentlyUsedCount
skgpu::Plot Plot
static constexpr auto kAtlasRecentlyUsedCount
skgpu::PlotLocator PlotLocator
skgpu::AtlasToken AtlasToken
static const constexpr bool kDumpAtlasData
static constexpr bool GrColorTypeIsAlphaOnly(GrColorType ct)
Definition: GrTypesPriv.h:888
GrColorType
Definition: GrTypesPriv.h:540
static constexpr GrColorType SkColorTypeToGrColorType(SkColorType ct)
Definition: GrTypesPriv.h:629
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
static float next(float f)
SkColorType fColorType
#define SkASSERT(cond)
Definition: SkAssert.h:116
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.
static T * SkRef(T *obj)
Definition: SkRefCnt.h:132
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
#define TRACE_FUNC
Definition: SkTraceEvent.h:30
GLenum type
skgpu::Swizzle getReadSwizzle(const GrBackendFormat &format, GrColorType colorType) const
Definition: GrCaps.cpp:443
SkISize atlasDimensions(skgpu::MaskFormat type) const
SkISize plotDimensions(skgpu::MaskFormat type) const
void compact(skgpu::AtlasToken startTokenForNextFlush)
static std::unique_ptr< GrDrawOpAtlas > Make(GrProxyProvider *proxyProvider, const GrBackendFormat &format, SkColorType ct, size_t bpp, int width, int height, int plotWidth, int plotHeight, skgpu::AtlasGenerationCounter *generationCounter, AllowMultitexturing allowMultitexturing, skgpu::PlotEvictionCallback *evictor, std::string_view label)
ErrorCode addToAtlas(GrResourceProvider *, GrDeferredUploadTarget *, int width, int height, const void *image, skgpu::AtlasLocator *)
void instantiate(GrOnFlushResourceProvider *)
uint32_t maxPages() const
sk_sp< GrTextureProxy > createProxy(const GrBackendFormat &, SkISize dimensions, GrRenderable, int renderTargetSampleCnt, skgpu::Mipmapped, SkBackingFit, skgpu::Budgeted, GrProtected, std::string_view label, GrInternalSurfaceFlags=GrInternalSurfaceFlags::kNone, UseAllocator useAllocator=UseAllocator::kYes)
const GrCaps * caps() const
GrTextureProxy * asTextureProxy() const
GrSurfaceProxy * proxy() const
GrTexture * peekTexture() const
bool isInstantiated() const
T * get() const
Definition: SkRefCnt.h:303
uint32_t plotIndex() const
Definition: AtlasTypes.h:305
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
skgpu::AtlasToken lastUseToken() const
Definition: AtlasTypes.h:479
void resetRects()
Definition: AtlasTypes.cpp:160
void resetFlushesSinceLastUsed()
Definition: AtlasTypes.h:484
static constexpr Swizzle Concat(const Swizzle &a, const Swizzle &b)
Definition: Swizzle.h:156
bool empty() const
Definition: SkTArray.h:199
uint32_t uint32_t * format
uint32_t * target
double y
double x
sk_sp< const SkImage > atlas
Definition: SkRecords.h:331
sk_sp< const SkImage > image
Definition: SkRecords.h:269
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
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
SkTInternalLList< Plot > PlotList
Definition: AtlasTypes.h:538
MaskFormat
Definition: AtlasTypes.h:98
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
Definition: SkSize.h:16
constexpr int32_t width() const
Definition: SkSize.h:36
void set(int32_t w, int32_t h)
Definition: SkSize.h:24
constexpr int32_t height() const
Definition: SkSize.h:37
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131