32#if defined(DUMP_ATLAS_DATA)
39void DrawAtlas::validate(
const AtlasLocator& atlasLocator)
const {
41 int numPlotsX = fTextureWidth / fPlotWidth;
42 int numPlotsY = fTextureHeight / fPlotHeight;
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));
53 int height,
int plotWidth,
int plotHeight,
57 std::string_view label) {
59 plotWidth, plotHeight, generationCounter,
60 allowMultitexturing, label));
62 if (evictor !=
nullptr) {
63 atlas->fEvictionCallbacks.emplace_back(evictor);
70 static std::atomic<uint32_t> nextID{1};
73 id = nextID.fetch_add(1, std::memory_order_relaxed);
79 AllowMultitexturing allowMultitexturing, std::string_view label)
82 , fTextureWidth(
width)
84 , fPlotWidth(plotWidth)
85 , fPlotHeight(plotHeight)
88 , fGenerationCounter(generationCounter)
89 , fAtlasGeneration(fGenerationCounter->
next())
91 , fFlushesSinceLastUse(0)
92 , fMaxPages(AllowMultitexturing::
kYes == allowMultitexturing ?
94 , fNumActivePages(0) {
95 int numPlotsX =
width/plotWidth;
96 int numPlotsY =
height/plotHeight;
98 SkASSERTF(fPlotWidth * numPlotsX == fTextureWidth,
99 "Invalid DrawAtlas. Plot width: %d, texture width %d", fPlotWidth, fTextureWidth);
100 SkASSERTF(fPlotHeight * numPlotsY == fTextureHeight,
101 "Invalid DrawAtlas. Plot height: %d, texture height %d", fPlotHeight, fTextureHeight);
103 fNumPlots = numPlotsX * numPlotsY;
105 this->createPages(generationCounter);
108inline void DrawAtlas::processEviction(
PlotLocator plotLocator) {
109 for (PlotEvictionCallback* evictor : fEvictionCallbacks) {
110 evictor->evict(plotLocator);
113 fAtlasGeneration = fGenerationCounter->next();
117 int pageIdx =
plot->pageIndex();
118 this->makeMRU(
plot, pageIdx);
126bool DrawAtlas::addRectToPage(
unsigned int pageIdx,
int width,
int height,
131 PlotList::Iter plotIter;
132 plotIter.init(fPages[pageIdx].fPlotList, PlotList::Iter::kHead_IterStart);
136 this->updatePlot(
plot, atlasLocator);
146 for (uint32_t pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
147 PlotList::Iter plotIter;
148 plotIter.init(fPages[pageIdx].fPlotList, PlotList::Iter::kHead_IterStart);
150 if (
plot->needsUpload()) {
156 std::tie(dataPtr, dstRect) =
plot->prepareForUpload();
161 std::vector<MipLevel> levels;
162 levels.push_back({dataPtr, fBytesPerPixel*fPlotWidth});
189 return ErrorCode::kError;
197 if (fNumActivePages == 0) {
199 this->activateNewPage(recorder);
204 return ErrorCode::kSucceeded;
210 for (
unsigned int pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
211 if (this->addRectToPage(pageIdx,
width,
height, atlasLocator)) {
212 return ErrorCode::kSucceeded;
221 if (fNumActivePages == this->maxPages()) {
222 for (
unsigned int pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
223 Plot*
plot = fPages[pageIdx].fPlotList.tail();
226 this->processEvictionAndResetRects(
plot);
229 this->updatePlot(
plot, atlasLocator);
230 return ErrorCode::kSucceeded;
235 if (!this->activateNewPage(recorder)) {
236 return ErrorCode::kError;
239 if (this->addRectToPage(fNumActivePages-1,
width,
height, atlasLocator)) {
240 return ErrorCode::kSucceeded;
244 return ErrorCode::kError;
248 if (!fNumActivePages) {
249 return ErrorCode::kError;
256 return ErrorCode::kTryAgain;
263 if (ec == ErrorCode::kSucceeded) {
264 Plot*
plot = this->findPlot(*atlasLocator);
265 plot->copySubImage(*atlasLocator,
image);
272 Plot*
plot = this->findPlot(locator);
273 return plot->prepForRender(locator, pixmap);
277 if (fNumActivePages < 1) {
278 fPrevFlushToken = startTokenForNextFlush;
283 PlotList::Iter plotIter;
284 bool atlasUsedThisFlush =
false;
285 for (uint32_t pageIndex = 0; pageIndex < fNumActivePages; ++pageIndex) {
286 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
287 while (
Plot*
plot = plotIter.get()) {
289 if (
plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
290 plot->resetFlushesSinceLastUsed();
291 atlasUsedThisFlush =
true;
298 if (atlasUsedThisFlush) {
299 fFlushesSinceLastUse = 0;
301 ++fFlushesSinceLastUse;
310 uint32_t lastPageIndex = fNumActivePages - 1;
314 for (uint32_t pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex) {
319 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
320 while (
Plot*
plot = plotIter.get()) {
325 if (!
plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
326 plot->incFlushesSinceLastUsed();
350 plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
351 unsigned int usedPlots = 0;
353 SkDebugf(
"page %u: ", lastPageIndex);
355 while (
Plot*
plot = plotIter.get()) {
357 if (!
plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
358 plot->incFlushesSinceLastUsed();
370 this->processEvictionAndResetRects(
plot);
383 if (availablePlots.
size() && usedPlots && usedPlots <= fNumPlots / 4) {
384 plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
385 while (
Plot*
plot = plotIter.get()) {
391 if (availablePlots.
size() > 0) {
392 this->processEvictionAndResetRects(
plot);
393 this->processEvictionAndResetRects(availablePlots.
back());
397 if (!usedPlots || !availablePlots.
size()) {
408 SkDebugf(
"delete %u\n", fNumActivePages-1);
411 this->deactivateLastPage();
412 fFlushesSinceLastUse = 0;
416 fPrevFlushToken = startTokenForNextFlush;
422 int numPlotsX = fTextureWidth/fPlotWidth;
423 int numPlotsY = fTextureHeight/fPlotHeight;
425 for (uint32_t i = 0; i < this->maxPages(); ++i) {
427 fProxies[i] =
nullptr;
430 fPages[i].fPlotArray = std::make_unique<sk_sp<Plot>[]>(numPlotsX * numPlotsY);
433 for (
int y = numPlotsY - 1, r = 0;
y >= 0; --
y, ++r) {
434 for (
int x = numPlotsX - 1, c = 0;
x >= 0; --
x, ++c) {
435 uint32_t plotIndex = r * numPlotsX + c;
436 currPlot->reset(
new Plot(
437 i, plotIndex, generationCounter,
x,
y, fPlotWidth, fPlotHeight,
fColorType,
441 fPages[i].fPlotList.addToHead(currPlot->get());
451bool DrawAtlas::activateNewPage(
Recorder* recorder) {
452 SkASSERT(fNumActivePages < this->maxPages());
453 SkASSERT(!fProxies[fNumActivePages]);
455 const Caps* caps = recorder->
priv().
caps();
460 fProxies[fNumActivePages] = TextureProxy::Make(caps,
462 {fTextureWidth, fTextureHeight},
465 if (!fProxies[fNumActivePages]) {
470 SkDebugf(
"activated page#: %u\n", fNumActivePages);
477inline void DrawAtlas::deactivateLastPage() {
480 uint32_t lastPageIndex = fNumActivePages - 1;
482 int numPlotsX = fTextureWidth/fPlotWidth;
483 int numPlotsY = fTextureHeight/fPlotHeight;
485 fPages[lastPageIndex].fPlotList.reset();
486 for (
int r = 0; r < numPlotsY; ++r) {
487 for (
int c = 0; c < numPlotsX; ++c) {
488 uint32_t plotIndex = r * numPlotsX + c;
490 Plot* currPlot = fPages[lastPageIndex].fPlotArray[plotIndex].get();
496 fPages[lastPageIndex].fPlotList.addToHead(currPlot);
501 fProxies[lastPageIndex].reset();
505void DrawAtlas::evictAllPlots() {
506 PlotList::Iter plotIter;
507 for (uint32_t pageIndex = 0; pageIndex < fNumActivePages; ++pageIndex) {
508 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
509 while (
Plot*
plot = plotIter.get()) {
510 this->processEvictionAndResetRects(
plot);
516DrawAtlasConfig::DrawAtlasConfig(
int maxTextureSize,
size_t maxBytes) {
517 static const SkISize kARGBDimensions[] = {
529 int index = maxBytes > 0
530 ? SkTPin<int>(
SkPrevLog2(maxBytes), 0, std::size(kARGBDimensions) - 1)
535 fARGBDimensions.set(std::min<int>(kARGBDimensions[index].
width(), maxTextureSize),
536 std::min<int>(kARGBDimensions[index].
height(), maxTextureSize));
537 fMaxTextureSize = std::min<int>(maxTextureSize, kMaxAtlasDim);
541 if (MaskFormat::kA8 ==
type) {
543 return { std::min<int>(2 * fARGBDimensions.width(), fMaxTextureSize),
544 std::min<int>(2 * fARGBDimensions.height(), fMaxTextureSize) };
546 return fARGBDimensions;
551 if (MaskFormat::kA8 ==
type) {
552 SkISize atlasDimensions = this->atlasDimensions(
type);
559 int plotWidth = atlasDimensions.
width() >= 2048 ? 512 : 256;
560 int plotHeight = atlasDimensions.
height() >= 2048 ? 512 : 256;
562 return { plotWidth, plotHeight };
static constexpr auto kPlotRecentlyUsedCount
static constexpr auto kAtlasRecentlyUsedCount
static const constexpr bool kDumpAtlasData
static float next(float f)
@ kUnknown_SkAlphaType
uninitialized
#define SkASSERTF(cond, fmt,...)
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)
constexpr bool SkIsPow2(T value)
sk_sp< T > sk_ref_sp(T *obj)
static constexpr uint32_t SK_InvalidGenID
uint32_t plotIndex() const
void updateRect(skgpu::IRect16 rect)
void updatePlotLocator(PlotLocator p)
static AtlasToken InvalidToken()
static constexpr int kMaxPlots
void resetFlushesSinceLastUsed()
AtlasToken nextFlushToken() const
virtual TextureInfo getDefaultSampledTextureInfo(SkColorType, Mipmapped mipmapped, Protected, Renderable) 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, PlotEvictionCallback *evictor, std::string_view label)
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()
Protected isProtected() const
const Caps * caps() const
ResourceProvider * resourceProvider()
static const constexpr bool kDumpAtlasData
static uint32_t next_id()
static void plot(SkCanvas *canvas, const char *fn, float xMin, float xMax, float yMin, float yMax, const char *label=nullptr, bool requireES3=false)
constexpr int32_t x() const
constexpr int32_t width() const
constexpr int32_t height() const
static IRect16 MakeXYWH(int16_t x, int16_t y, int16_t w, int16_t h)
#define TRACE_EVENT0(category_group, name)