Flutter Engine
The Flutter Engine
Classes | Public Types | Public Member Functions | Static Public Member Functions | List of all members
skgpu::graphite::DrawAtlas Class Reference

#include <DrawAtlas.h>

Public Types

enum class  AllowMultitexturing : bool { kNo , kYes }
 
enum class  UseStorageTextures : bool { kNo , kYes }
 
enum class  ErrorCode { kError , kSucceeded , kTryAgain }
 

Public Member Functions

ErrorCode addToAtlas (Recorder *, int width, int height, const void *image, AtlasLocator *)
 
ErrorCode addRect (Recorder *, int width, int height, AtlasLocator *)
 
SkIPoint prepForRender (const AtlasLocator &, SkAutoPixmapStorage *)
 
bool recordUploads (DrawContext *, Recorder *)
 
const sk_sp< TextureProxy > * getProxies () const
 
uint32_t atlasID () const
 
uint64_t atlasGeneration () const
 
uint32_t numActivePages () const
 
unsigned int numPlots () const
 
SkISize plotSize () const
 
bool hasID (const PlotLocator &plotLocator)
 
void setLastUseToken (const AtlasLocator &atlasLocator, AtlasToken token)
 
void setLastUseTokenBulk (const BulkUsePlotUpdater &updater, AtlasToken token)
 
void compact (AtlasToken startTokenForNextFlush)
 
void markUsedPlotsAsFull ()
 
void evictAllPlots ()
 
uint32_t maxPages () const
 
int numAllocated_TestingOnly () const
 
void setMaxPages_TestingOnly (uint32_t maxPages)
 

Static Public Member Functions

static std::unique_ptr< DrawAtlasMake (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)
 

Detailed Description

TODO: the process described here is tentative, and this comment revised once locked down.

This class manages one or more atlas textures on behalf of primitive draws in Device. The drawing processes that use the atlas add preceding UploadTasks when generating RenderPassTasks. The class provides facilities for using DrawTokens to detect data hazards. Plots that need uploads are tracked until it is impossible to add data without overwriting texels read by draws that have not yet been snapped to a RenderPassTask. At that point, the atlas will attempt to allocate a new atlas texture (or "page") of the same size, up to a maximum number of textures, and upload to that texture. If that's not possible, then the atlas will fail to add a subimage. This gives the Device the chance to end the current draw, snap a RenderpassTask, and begin a new one. Additional uploads will then succeed.

When the atlas has multiple pages, new uploads are prioritized to the lower index pages, i.e., it will try to upload to page 0 before page 1 or 2. To keep the atlas from continually using excess space, periodic garbage collection is needed to shift data from the higher index pages to the lower ones, and then eventually remove any pages that are no longer in use. "In use" is determined by using the AtlasToken system: After a DrawPass is snapped a subarea of the page, or "plot" is checked to see whether it was used in that DrawPass. If less than a quarter of the plots have been used recently (within kPlotRecentlyUsedCount iterations) and there are available plots in lower index pages, the higher index page will be deactivated, and its glyphs will gradually migrate to other pages via the usual upload system.

Garbage collection is initiated by the DrawAtlas's client via the compact() method.

Definition at line 53 of file DrawAtlas.h.

Member Enumeration Documentation

◆ AllowMultitexturing

Is the atlas allowed to use more than one texture?

Enumerator
kNo 
kYes 

Definition at line 56 of file DrawAtlas.h.

56: bool { kNo, kYes };
@ kYes
Do pre-clip the geometry before applying the (perspective) matrix.
@ kNo
Don't pre-clip the geometry before applying the (perspective) matrix.

◆ ErrorCode

Adds a width x height subimage to the atlas. Upon success it returns 'kSucceeded' and returns the ID and the subimage's coordinates in the backing texture. 'kTryAgain' is returned if the subimage cannot fit in the atlas without overwriting texels that will be read in the current list of draws. This indicates that the Device should end its current draw, snap a DrawPass, and begin another before adding more data. 'kError' will be returned when some unrecoverable error was encountered while trying to add the subimage. In this case the draw being created should be discarded.

This tracking does not generate UploadTasks per se. Instead, when the RenderPassTask is ready to be snapped, recordUploads() will be called by the Device and that will generate the necessary UploadTasks. If the useCachedUploads argument in recordUploads() is true, this will generate uploads for the entire area of each Plot that has changed since the last eviction. Otherwise it will only generate uploads for newly added changes.

NOTE: When a draw that reads from the atlas is added to the DrawList, the client using this DrawAtlas must immediately call 'setLastUseToken' with the currentToken from the Recorder, otherwise the next call to addToAtlas might cause the previous data to be overwritten before it has been read.

Enumerator
kError 
kSucceeded 
kTryAgain 

Definition at line 107 of file DrawAtlas.h.

107 {
108 kError,
109 kSucceeded,
110 kTryAgain
111 };

◆ UseStorageTextures

Should the atlas use storage textures?

Enumerator
kNo 
kYes 

Definition at line 59 of file DrawAtlas.h.

59: bool { kNo, kYes };

Member Function Documentation

◆ addRect()

DrawAtlas::ErrorCode skgpu::graphite::DrawAtlas::addRect ( Recorder recorder,
int  width,
int  height,
AtlasLocator atlasLocator 
)

Definition at line 189 of file DrawAtlas.cpp.

191 {
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());
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)) {
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)) {
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.
261}
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
void updateRect(skgpu::IRect16 rect)
Definition: AtlasTypes.h:345
void updatePlotLocator(PlotLocator p)
Definition: AtlasTypes.h:337
AtlasToken nextFlushToken() const
Definition: AtlasTypes.h:207
ErrorCode addRect(Recorder *, int width, int height, AtlasLocator *)
Definition: DrawAtlas.cpp:189
uint32_t maxPages() const
Definition: DrawAtlas.h:168
TokenTracker * tokenTracker()
Definition: RecorderPriv.h:62
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
static IRect16 MakeXYWH(int16_t x, int16_t y, int16_t w, int16_t h)
Definition: AtlasTypes.h:54

◆ addToAtlas()

DrawAtlas::ErrorCode skgpu::graphite::DrawAtlas::addToAtlas ( Recorder recorder,
int  width,
int  height,
const void *  image,
AtlasLocator atlasLocator 
)

Definition at line 263 of file DrawAtlas.cpp.

265 {
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}
sk_sp< const SkImage > image
Definition: SkRecords.h:269

◆ atlasGeneration()

uint64_t skgpu::graphite::DrawAtlas::atlasGeneration ( ) const
inline

Definition at line 123 of file DrawAtlas.h.

123{ return fAtlasGeneration; }

◆ atlasID()

uint32_t skgpu::graphite::DrawAtlas::atlasID ( ) const
inline

Definition at line 122 of file DrawAtlas.h.

122{ return fAtlasID; }

◆ compact()

void skgpu::graphite::DrawAtlas::compact ( AtlasToken  startTokenForNextFlush)

Definition at line 280 of file DrawAtlas.cpp.

280 {
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}
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static AtlasToken InvalidToken()
Definition: AtlasTypes.h:153
int size() const
Definition: SkTArray.h:421
static constexpr auto kPlotRecentlyUsedCount
Definition: DrawAtlas.cpp:186
static const constexpr bool kDumpAtlasData
Definition: DrawAtlas.cpp:35
static constexpr auto kAtlasRecentlyUsedCount
Definition: DrawAtlas.cpp:187

◆ evictAllPlots()

void skgpu::graphite::DrawAtlas::evictAllPlots ( )

Definition at line 522 of file DrawAtlas.cpp.

522 {
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}

◆ getProxies()

const sk_sp< TextureProxy > * skgpu::graphite::DrawAtlas::getProxies ( ) const
inline

Definition at line 120 of file DrawAtlas.h.

120{ return fProxies; }

◆ hasID()

bool skgpu::graphite::DrawAtlas::hasID ( const PlotLocator plotLocator)
inline

Definition at line 128 of file DrawAtlas.h.

128 {
129 if (!plotLocator.isValid()) {
130 return false;
131 }
132
133 uint32_t plot = plotLocator.plotIndex();
134 uint32_t page = plotLocator.pageIndex();
135 uint64_t plotGeneration = fPages[page].fPlotArray[plot]->genID();
136 uint64_t locatorGeneration = plotLocator.genID();
137 return plot < fNumPlots && page < fNumActivePages && plotGeneration == locatorGeneration;
138 }
uint64_t genID() const
Definition: AtlasTypes.h:280
uint32_t plotIndex() const
Definition: AtlasTypes.h:279
bool isValid() const
Definition: AtlasTypes.h:262
uint32_t pageIndex() const
Definition: AtlasTypes.h:278

◆ Make()

std::unique_ptr< DrawAtlas > skgpu::graphite::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 
)
static

Returns a DrawAtlas.

Parameters
ctThe colorType which this atlas will store.
bppSize in bytes of each pixel.
widthWidth in pixels of the atlas.
heightHeight in pixels of the atlas.
plotWidthThe width of each plot. width/plotWidth should be an integer.
plotWidthThe height of each plot. height/plotHeight should be an integer.
atlasGenerationA pointer to the context's generation counter.
allowMultitexturingCan the atlas use more than one texture.
useStorageTexturesShould the atlas use storage textures.
evictorA pointer to an eviction callback class.
labelLabel for texture resources.
Returns
An initialized DrawAtlas, or nullptr if creation fails.

Definition at line 52 of file DrawAtlas.cpp.

58 {
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}
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
sk_sp< const SkImage > atlas
Definition: SkRecords.h:331

◆ markUsedPlotsAsFull()

void skgpu::graphite::DrawAtlas::markUsedPlotsAsFull ( )

Definition at line 511 of file DrawAtlas.cpp.

511 {
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}

◆ maxPages()

uint32_t skgpu::graphite::DrawAtlas::maxPages ( ) const
inline

Definition at line 168 of file DrawAtlas.h.

168 {
169 return fMaxPages;
170 }

◆ numActivePages()

uint32_t skgpu::graphite::DrawAtlas::numActivePages ( ) const
inline

Definition at line 124 of file DrawAtlas.h.

124{ return fNumActivePages; }

◆ numAllocated_TestingOnly()

int skgpu::graphite::DrawAtlas::numAllocated_TestingOnly ( ) const

◆ numPlots()

unsigned int skgpu::graphite::DrawAtlas::numPlots ( ) const
inline

Definition at line 125 of file DrawAtlas.h.

125{ return fNumPlots; }

◆ plotSize()

SkISize skgpu::graphite::DrawAtlas::plotSize ( ) const
inline

Definition at line 126 of file DrawAtlas.h.

126{ return {fPlotWidth, fPlotHeight}; }

◆ prepForRender()

SkIPoint skgpu::graphite::DrawAtlas::prepForRender ( const AtlasLocator locator,
SkAutoPixmapStorage pixmap 
)

Definition at line 275 of file DrawAtlas.cpp.

275 {
276 Plot* plot = this->findPlot(locator);
277 return plot->prepForRender(locator, pixmap);
278}

◆ recordUploads()

bool skgpu::graphite::DrawAtlas::recordUploads ( DrawContext dc,
Recorder recorder 
)

Definition at line 148 of file DrawAtlas.cpp.

148 {
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}
@ kUnknown_SkAlphaType
uninitialized
Definition: SkAlphaType.h:27
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
#define TRACE_FUNC
Definition: SkTraceEvent.h:30
Definition: SkRect.h:32
bool isEmpty() const
Definition: SkRect.h:202
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131

◆ setLastUseToken()

void skgpu::graphite::DrawAtlas::setLastUseToken ( const AtlasLocator atlasLocator,
AtlasToken  token 
)
inline

To ensure the atlas does not evict a given entry, the client must set the last use token.

Definition at line 141 of file DrawAtlas.h.

141 {
142 Plot* plot = this->findPlot(atlasLocator);
143 this->internalSetLastUseToken(plot, atlasLocator.pageIndex(), token);
144 }
uint32_t pageIndex() const
Definition: AtlasTypes.h:303

◆ setLastUseTokenBulk()

void skgpu::graphite::DrawAtlas::setLastUseTokenBulk ( const BulkUsePlotUpdater updater,
AtlasToken  token 
)
inline

Definition at line 146 of file DrawAtlas.h.

147 {
148 int count = updater.count();
149 for (int i = 0; i < count; i++) {
150 const BulkUsePlotUpdater::PlotData& pd = updater.plotData(i);
151 // it's possible we've added a plot to the updater and subsequently the plot's page
152 // was deleted -- so we check to prevent a crash
153 if (pd.fPageIndex < fNumActivePages) {
154 Plot* plot = fPages[pd.fPageIndex].fPlotArray[pd.fPlotIndex].get();
155 this->internalSetLastUseToken(plot, pd.fPageIndex, token);
156 }
157 }
158 }
int count
Definition: FontMgrTest.cpp:50

◆ setMaxPages_TestingOnly()

void skgpu::graphite::DrawAtlas::setMaxPages_TestingOnly ( uint32_t  maxPages)

The documentation for this class was generated from the following files: