1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpAtlas.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include <memory>
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_ci#include "include/core/SkLog.h"
13cb93a386Sopenharmony_ci#include "include/private/SkTPin.h"
14cb93a386Sopenharmony_ci#include "src/core/SkOpts.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrBackendUtils.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrOnFlushResourceProvider.h"
17cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h"
18cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h"
19cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h"
20cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProviderPriv.h"
21cb93a386Sopenharmony_ci#include "src/gpu/GrSurfaceProxyPriv.h"
22cb93a386Sopenharmony_ci#include "src/gpu/GrTexture.h"
23cb93a386Sopenharmony_ci#include "src/gpu/GrTracing.h"
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_ci#ifdef DUMP_ATLAS_DATA
26cb93a386Sopenharmony_cistatic bool gDumpAtlasData = false;
27cb93a386Sopenharmony_ci#endif
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci#ifdef SK_DEBUG
30cb93a386Sopenharmony_civoid GrDrawOpAtlas::validate(const AtlasLocator& atlasLocator) const {
31cb93a386Sopenharmony_ci    // Verify that the plotIndex stored in the PlotLocator is consistent with the glyph rectangle
32cb93a386Sopenharmony_ci    int numPlotsX = fTextureWidth / fPlotWidth;
33cb93a386Sopenharmony_ci    int numPlotsY = fTextureHeight / fPlotHeight;
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ci    int plotIndex = atlasLocator.plotIndex();
36cb93a386Sopenharmony_ci    auto topLeft = atlasLocator.topLeft();
37cb93a386Sopenharmony_ci    int plotX = topLeft.x() / fPlotWidth;
38cb93a386Sopenharmony_ci    int plotY = topLeft.y() / fPlotHeight;
39cb93a386Sopenharmony_ci    SkASSERT(plotIndex == (numPlotsY - plotY - 1) * numPlotsX + (numPlotsX - plotX - 1));
40cb93a386Sopenharmony_ci}
41cb93a386Sopenharmony_ci#endif
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ci// When proxy allocation is deferred until flush time the proxies acting as atlases require
44cb93a386Sopenharmony_ci// special handling. This is because the usage that can be determined from the ops themselves
45cb93a386Sopenharmony_ci// isn't sufficient. Independent of the ops there will be ASAP and inline uploads to the
46cb93a386Sopenharmony_ci// atlases. Extending the usage interval of any op that uses an atlas to the start of the
47cb93a386Sopenharmony_ci// flush (as is done for proxies that are used for sw-generated masks) also won't work because
48cb93a386Sopenharmony_ci// the atlas persists even beyond the last use in an op - for a given flush. Given this, atlases
49cb93a386Sopenharmony_ci// must explicitly manage the lifetime of their backing proxies via the onFlushCallback system
50cb93a386Sopenharmony_ci// (which calls this method).
51cb93a386Sopenharmony_civoid GrDrawOpAtlas::instantiate(GrOnFlushResourceProvider* onFlushResourceProvider) {
52cb93a386Sopenharmony_ci    for (uint32_t i = 0; i < fNumActivePages; ++i) {
53cb93a386Sopenharmony_ci        // All the atlas pages are now instantiated at flush time in the activeNewPage method.
54cb93a386Sopenharmony_ci        SkASSERT(fViews[i].proxy() && fViews[i].proxy()->isInstantiated());
55cb93a386Sopenharmony_ci    }
56cb93a386Sopenharmony_ci}
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_cistd::unique_ptr<GrDrawOpAtlas> GrDrawOpAtlas::Make(GrProxyProvider* proxyProvider,
59cb93a386Sopenharmony_ci                                                   const GrBackendFormat& format,
60cb93a386Sopenharmony_ci                                                   GrColorType colorType, int width,
61cb93a386Sopenharmony_ci                                                   int height, int plotWidth, int plotHeight,
62cb93a386Sopenharmony_ci                                                   GenerationCounter* generationCounter,
63cb93a386Sopenharmony_ci                                                   AllowMultitexturing allowMultitexturing,
64cb93a386Sopenharmony_ci#ifdef SK_ENABLE_SMALL_PAGE
65cb93a386Sopenharmony_ci                                                   int atlasPageNum,
66cb93a386Sopenharmony_ci#endif
67cb93a386Sopenharmony_ci                                                   EvictionCallback* evictor) {
68cb93a386Sopenharmony_ci    if (!format.isValid()) {
69cb93a386Sopenharmony_ci        return nullptr;
70cb93a386Sopenharmony_ci    }
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ci    std::unique_ptr<GrDrawOpAtlas> atlas(new GrDrawOpAtlas(proxyProvider, format, colorType,
73cb93a386Sopenharmony_ci                                                           width, height, plotWidth, plotHeight,
74cb93a386Sopenharmony_ci#ifdef SK_ENABLE_SMALL_PAGE
75cb93a386Sopenharmony_ci                                                           generationCounter, allowMultitexturing, atlasPageNum));
76cb93a386Sopenharmony_ci#else
77cb93a386Sopenharmony_ci                                                           generationCounter, allowMultitexturing));
78cb93a386Sopenharmony_ci#endif
79cb93a386Sopenharmony_ci    if (!atlas->getViews()[0].proxy()) {
80cb93a386Sopenharmony_ci        return nullptr;
81cb93a386Sopenharmony_ci    }
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci    if (evictor != nullptr) {
84cb93a386Sopenharmony_ci        atlas->fEvictionCallbacks.emplace_back(evictor);
85cb93a386Sopenharmony_ci    }
86cb93a386Sopenharmony_ci    return atlas;
87cb93a386Sopenharmony_ci}
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
90cb93a386Sopenharmony_ciGrDrawOpAtlas::Plot::Plot(int pageIndex, int plotIndex, GenerationCounter* generationCounter,
91cb93a386Sopenharmony_ci        int offX, int offY, int width, int height, GrColorType colorType)
92cb93a386Sopenharmony_ci        : fLastUpload(GrDeferredUploadToken::AlreadyFlushedToken())
93cb93a386Sopenharmony_ci        , fLastUse(GrDeferredUploadToken::AlreadyFlushedToken())
94cb93a386Sopenharmony_ci        , fFlushesSinceLastUse(0)
95cb93a386Sopenharmony_ci        , fPageIndex(pageIndex)
96cb93a386Sopenharmony_ci        , fPlotIndex(plotIndex)
97cb93a386Sopenharmony_ci        , fGenerationCounter(generationCounter)
98cb93a386Sopenharmony_ci        , fGenID(fGenerationCounter->next())
99cb93a386Sopenharmony_ci        , fPlotLocator(fPageIndex, fPlotIndex, fGenID)
100cb93a386Sopenharmony_ci        , fData(nullptr)
101cb93a386Sopenharmony_ci        , fWidth(width)
102cb93a386Sopenharmony_ci        , fHeight(height)
103cb93a386Sopenharmony_ci        , fX(offX)
104cb93a386Sopenharmony_ci        , fY(offY)
105cb93a386Sopenharmony_ci        , fRectanizer(width, height)
106cb93a386Sopenharmony_ci        , fOffset(SkIPoint16::Make(fX * fWidth, fY * fHeight))
107cb93a386Sopenharmony_ci        , fColorType(colorType)
108cb93a386Sopenharmony_ci        , fBytesPerPixel(GrColorTypeBytesPerPixel(colorType))
109cb93a386Sopenharmony_ci#ifdef SK_DEBUG
110cb93a386Sopenharmony_ci        , fDirty(false)
111cb93a386Sopenharmony_ci#endif
112cb93a386Sopenharmony_ci{
113cb93a386Sopenharmony_ci    // We expect the allocated dimensions to be a multiple of 4 bytes
114cb93a386Sopenharmony_ci    SkASSERT(((width*fBytesPerPixel) & 0x3) == 0);
115cb93a386Sopenharmony_ci    // The padding for faster uploads only works for 1, 2 and 4 byte texels
116cb93a386Sopenharmony_ci    SkASSERT(fBytesPerPixel != 3 && fBytesPerPixel <= 4);
117cb93a386Sopenharmony_ci    fDirtyRect.setEmpty();
118cb93a386Sopenharmony_ci}
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_ciGrDrawOpAtlas::Plot::~Plot() {
121cb93a386Sopenharmony_ci    sk_free(fData);
122cb93a386Sopenharmony_ci}
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_cibool GrDrawOpAtlas::Plot::addSubImage(
125cb93a386Sopenharmony_ci        int width, int height, const void* image, AtlasLocator* atlasLocator) {
126cb93a386Sopenharmony_ci    SkASSERT(width <= fWidth && height <= fHeight);
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_ci    SkIPoint16 loc;
129cb93a386Sopenharmony_ci    if (!fRectanizer.addRect(width, height, &loc)) {
130cb93a386Sopenharmony_ci        return false;
131cb93a386Sopenharmony_ci    }
132cb93a386Sopenharmony_ci
133cb93a386Sopenharmony_ci    GrIRect16 rect = GrIRect16::MakeXYWH(loc.fX, loc.fY, width, height);
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci    if (!fData) {
136cb93a386Sopenharmony_ci        fData = reinterpret_cast<unsigned char*>(
137cb93a386Sopenharmony_ci                sk_calloc_throw(fBytesPerPixel * fWidth * fHeight));
138cb93a386Sopenharmony_ci    }
139cb93a386Sopenharmony_ci    size_t rowBytes = width * fBytesPerPixel;
140cb93a386Sopenharmony_ci    const unsigned char* imagePtr = (const unsigned char*)image;
141cb93a386Sopenharmony_ci    // point ourselves at the right starting spot
142cb93a386Sopenharmony_ci    unsigned char* dataPtr = fData;
143cb93a386Sopenharmony_ci    dataPtr += fBytesPerPixel * fWidth * rect.fTop;
144cb93a386Sopenharmony_ci    dataPtr += fBytesPerPixel * rect.fLeft;
145cb93a386Sopenharmony_ci    // copy into the data buffer, swizzling as we go if this is ARGB data
146cb93a386Sopenharmony_ci    if (4 == fBytesPerPixel && kN32_SkColorType == kBGRA_8888_SkColorType) {
147cb93a386Sopenharmony_ci        for (int i = 0; i < height; ++i) {
148cb93a386Sopenharmony_ci            SkOpts::RGBA_to_BGRA((uint32_t*)dataPtr, (const uint32_t*)imagePtr, width);
149cb93a386Sopenharmony_ci            dataPtr += fBytesPerPixel * fWidth;
150cb93a386Sopenharmony_ci            imagePtr += rowBytes;
151cb93a386Sopenharmony_ci        }
152cb93a386Sopenharmony_ci    } else {
153cb93a386Sopenharmony_ci        for (int i = 0; i < height; ++i) {
154cb93a386Sopenharmony_ci            memcpy(dataPtr, imagePtr, rowBytes);
155cb93a386Sopenharmony_ci            dataPtr += fBytesPerPixel * fWidth;
156cb93a386Sopenharmony_ci            imagePtr += rowBytes;
157cb93a386Sopenharmony_ci        }
158cb93a386Sopenharmony_ci    }
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci    fDirtyRect.join({rect.fLeft, rect.fTop, rect.fRight, rect.fBottom});
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_ci    rect.offset(fOffset.fX, fOffset.fY);
163cb93a386Sopenharmony_ci    atlasLocator->updateRect(rect);
164cb93a386Sopenharmony_ci    SkDEBUGCODE(fDirty = true;)
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci    return true;
167cb93a386Sopenharmony_ci}
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_civoid GrDrawOpAtlas::Plot::uploadToTexture(GrDeferredTextureUploadWritePixelsFn& writePixels,
170cb93a386Sopenharmony_ci                                          GrTextureProxy* proxy) {
171cb93a386Sopenharmony_ci    // We should only be issuing uploads if we are in fact dirty
172cb93a386Sopenharmony_ci    SkASSERT(fDirty && fData && proxy && proxy->peekTexture());
173cb93a386Sopenharmony_ci    TRACE_EVENT0("skia.gpu", TRACE_FUNC);
174cb93a386Sopenharmony_ci    size_t rowBytes = fBytesPerPixel * fWidth;
175cb93a386Sopenharmony_ci    const unsigned char* dataPtr = fData;
176cb93a386Sopenharmony_ci    // Clamp to 4-byte aligned boundaries
177cb93a386Sopenharmony_ci    unsigned int clearBits = 0x3 / fBytesPerPixel;
178cb93a386Sopenharmony_ci    fDirtyRect.fLeft &= ~clearBits;
179cb93a386Sopenharmony_ci    fDirtyRect.fRight += clearBits;
180cb93a386Sopenharmony_ci    fDirtyRect.fRight &= ~clearBits;
181cb93a386Sopenharmony_ci    SkASSERT(fDirtyRect.fRight <= fWidth);
182cb93a386Sopenharmony_ci    // Set up dataPtr
183cb93a386Sopenharmony_ci    dataPtr += rowBytes * fDirtyRect.fTop;
184cb93a386Sopenharmony_ci    dataPtr += fBytesPerPixel * fDirtyRect.fLeft;
185cb93a386Sopenharmony_ci
186cb93a386Sopenharmony_ci    writePixels(proxy,
187cb93a386Sopenharmony_ci                fDirtyRect.makeOffset(fOffset.fX, fOffset.fY),
188cb93a386Sopenharmony_ci                fColorType,
189cb93a386Sopenharmony_ci                dataPtr,
190cb93a386Sopenharmony_ci                rowBytes);
191cb93a386Sopenharmony_ci    fDirtyRect.setEmpty();
192cb93a386Sopenharmony_ci    SkDEBUGCODE(fDirty = false;)
193cb93a386Sopenharmony_ci}
194cb93a386Sopenharmony_ci
195cb93a386Sopenharmony_civoid GrDrawOpAtlas::Plot::resetRects() {
196cb93a386Sopenharmony_ci    fRectanizer.reset();
197cb93a386Sopenharmony_ci
198cb93a386Sopenharmony_ci    fGenID = fGenerationCounter->next();
199cb93a386Sopenharmony_ci    fPlotLocator = PlotLocator(fPageIndex, fPlotIndex, fGenID);
200cb93a386Sopenharmony_ci    fLastUpload = GrDeferredUploadToken::AlreadyFlushedToken();
201cb93a386Sopenharmony_ci    fLastUse = GrDeferredUploadToken::AlreadyFlushedToken();
202cb93a386Sopenharmony_ci
203cb93a386Sopenharmony_ci    // zero out the plot
204cb93a386Sopenharmony_ci    if (fData) {
205cb93a386Sopenharmony_ci        sk_bzero(fData, fBytesPerPixel * fWidth * fHeight);
206cb93a386Sopenharmony_ci    }
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_ci    fDirtyRect.setEmpty();
209cb93a386Sopenharmony_ci    SkDEBUGCODE(fDirty = false;)
210cb93a386Sopenharmony_ci}
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ciGrDrawOpAtlas::GrDrawOpAtlas(GrProxyProvider* proxyProvider, const GrBackendFormat& format,
215cb93a386Sopenharmony_ci                             GrColorType colorType, int width, int height,
216cb93a386Sopenharmony_ci                             int plotWidth, int plotHeight, GenerationCounter* generationCounter,
217cb93a386Sopenharmony_ci#ifdef SK_ENABLE_SMALL_PAGE
218cb93a386Sopenharmony_ci                             AllowMultitexturing allowMultitexturing, int atlasPageNum)
219cb93a386Sopenharmony_ci#else
220cb93a386Sopenharmony_ci                             AllowMultitexturing allowMultitexturing)
221cb93a386Sopenharmony_ci#endif
222cb93a386Sopenharmony_ci        : fFormat(format)
223cb93a386Sopenharmony_ci        , fColorType(colorType)
224cb93a386Sopenharmony_ci        , fTextureWidth(width)
225cb93a386Sopenharmony_ci        , fTextureHeight(height)
226cb93a386Sopenharmony_ci        , fPlotWidth(plotWidth)
227cb93a386Sopenharmony_ci        , fPlotHeight(plotHeight)
228cb93a386Sopenharmony_ci        , fGenerationCounter(generationCounter)
229cb93a386Sopenharmony_ci        , fAtlasGeneration(fGenerationCounter->next())
230cb93a386Sopenharmony_ci        , fPrevFlushToken(GrDeferredUploadToken::AlreadyFlushedToken())
231cb93a386Sopenharmony_ci        , fFlushesSinceLastUse(0)
232cb93a386Sopenharmony_ci#ifdef SK_ENABLE_SMALL_PAGE
233cb93a386Sopenharmony_ci        , fMaxPages(AllowMultitexturing::kYes == allowMultitexturing ? ((atlasPageNum > 16) ? 16 : atlasPageNum) : 1)
234cb93a386Sopenharmony_ci#else
235cb93a386Sopenharmony_ci        , fMaxPages(AllowMultitexturing::kYes == allowMultitexturing ? kMaxMultitexturePages : 1)
236cb93a386Sopenharmony_ci#endif
237cb93a386Sopenharmony_ci        , fNumActivePages(0) {
238cb93a386Sopenharmony_ci    int numPlotsX = width/plotWidth;
239cb93a386Sopenharmony_ci    int numPlotsY = height/plotHeight;
240cb93a386Sopenharmony_ci    SkASSERT(numPlotsX * numPlotsY <= GrDrawOpAtlas::kMaxPlots);
241cb93a386Sopenharmony_ci    SkASSERT(fPlotWidth * numPlotsX == fTextureWidth);
242cb93a386Sopenharmony_ci    SkASSERT(fPlotHeight * numPlotsY == fTextureHeight);
243cb93a386Sopenharmony_ci
244cb93a386Sopenharmony_ci    fNumPlots = numPlotsX * numPlotsY;
245cb93a386Sopenharmony_ci
246cb93a386Sopenharmony_ci    this->createPages(proxyProvider, generationCounter);
247cb93a386Sopenharmony_ci    SK_LOGD("Texture[Width:%{public}d, Height:%{public}d, MaxPage:%{public}d], Plot[Width:%{public}d, Height:%{public}d].", \
248cb93a386Sopenharmony_ci        fTextureWidth, fTextureHeight, fMaxPages, fPlotWidth, fPlotHeight);
249cb93a386Sopenharmony_ci}
250cb93a386Sopenharmony_ci
251cb93a386Sopenharmony_ciinline void GrDrawOpAtlas::processEviction(PlotLocator plotLocator) {
252cb93a386Sopenharmony_ci    for (EvictionCallback* evictor : fEvictionCallbacks) {
253cb93a386Sopenharmony_ci        evictor->evict(plotLocator);
254cb93a386Sopenharmony_ci    }
255cb93a386Sopenharmony_ci
256cb93a386Sopenharmony_ci    fAtlasGeneration = fGenerationCounter->next();
257cb93a386Sopenharmony_ci}
258cb93a386Sopenharmony_ci
259cb93a386Sopenharmony_ciinline bool GrDrawOpAtlas::updatePlot(GrDeferredUploadTarget* target,
260cb93a386Sopenharmony_ci                                      AtlasLocator* atlasLocator, Plot* plot) {
261cb93a386Sopenharmony_ci    int pageIdx = plot->pageIndex();
262cb93a386Sopenharmony_ci    this->makeMRU(plot, pageIdx);
263cb93a386Sopenharmony_ci
264cb93a386Sopenharmony_ci    // If our most recent upload has already occurred then we have to insert a new
265cb93a386Sopenharmony_ci    // upload. Otherwise, we already have a scheduled upload that hasn't yet ocurred.
266cb93a386Sopenharmony_ci    // This new update will piggy back on that previously scheduled update.
267cb93a386Sopenharmony_ci    if (plot->lastUploadToken() < target->tokenTracker()->nextTokenToFlush()) {
268cb93a386Sopenharmony_ci        // With c+14 we could move sk_sp into lamba to only ref once.
269cb93a386Sopenharmony_ci        sk_sp<Plot> plotsp(SkRef(plot));
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ci        GrTextureProxy* proxy = fViews[pageIdx].asTextureProxy();
272cb93a386Sopenharmony_ci        SkASSERT(proxy && proxy->isInstantiated());  // This is occurring at flush time
273cb93a386Sopenharmony_ci
274cb93a386Sopenharmony_ci        GrDeferredUploadToken lastUploadToken = target->addASAPUpload(
275cb93a386Sopenharmony_ci                [plotsp, proxy](GrDeferredTextureUploadWritePixelsFn& writePixels) {
276cb93a386Sopenharmony_ci                    plotsp->uploadToTexture(writePixels, proxy);
277cb93a386Sopenharmony_ci                });
278cb93a386Sopenharmony_ci        plot->setLastUploadToken(lastUploadToken);
279cb93a386Sopenharmony_ci    }
280cb93a386Sopenharmony_ci    atlasLocator->updatePlotLocator(plot->plotLocator());
281cb93a386Sopenharmony_ci    SkDEBUGCODE(this->validate(*atlasLocator);)
282cb93a386Sopenharmony_ci    return true;
283cb93a386Sopenharmony_ci}
284cb93a386Sopenharmony_ci
285cb93a386Sopenharmony_cibool GrDrawOpAtlas::uploadToPage(unsigned int pageIdx, GrDeferredUploadTarget* target, int width,
286cb93a386Sopenharmony_ci                                 int height, const void* image, AtlasLocator* atlasLocator) {
287cb93a386Sopenharmony_ci    SkASSERT(fViews[pageIdx].proxy() && fViews[pageIdx].proxy()->isInstantiated());
288cb93a386Sopenharmony_ci
289cb93a386Sopenharmony_ci    // look through all allocated plots for one we can share, in Most Recently Refed order
290cb93a386Sopenharmony_ci    PlotList::Iter plotIter;
291cb93a386Sopenharmony_ci    plotIter.init(fPages[pageIdx].fPlotList, PlotList::Iter::kHead_IterStart);
292cb93a386Sopenharmony_ci
293cb93a386Sopenharmony_ci    for (Plot* plot = plotIter.get(); plot; plot = plotIter.next()) {
294cb93a386Sopenharmony_ci        SkASSERT(GrBackendFormatBytesPerPixel(fViews[pageIdx].proxy()->backendFormat()) ==
295cb93a386Sopenharmony_ci                 plot->bpp());
296cb93a386Sopenharmony_ci
297cb93a386Sopenharmony_ci        if (plot->addSubImage(width, height, image, atlasLocator)) {
298cb93a386Sopenharmony_ci            return this->updatePlot(target, atlasLocator, plot);
299cb93a386Sopenharmony_ci        }
300cb93a386Sopenharmony_ci    }
301cb93a386Sopenharmony_ci
302cb93a386Sopenharmony_ci    return false;
303cb93a386Sopenharmony_ci}
304cb93a386Sopenharmony_ci
305cb93a386Sopenharmony_ci// Number of atlas-related flushes beyond which we consider a plot to no longer be in use.
306cb93a386Sopenharmony_ci//
307cb93a386Sopenharmony_ci// This value is somewhat arbitrary -- the idea is to keep it low enough that
308cb93a386Sopenharmony_ci// a page with unused plots will get removed reasonably quickly, but allow it
309cb93a386Sopenharmony_ci// to hang around for a bit in case it's needed. The assumption is that flushes
310cb93a386Sopenharmony_ci// are rare; i.e., we are not continually refreshing the frame.
311cb93a386Sopenharmony_cistatic constexpr auto kPlotRecentlyUsedCount = 32;
312cb93a386Sopenharmony_cistatic constexpr auto kAtlasRecentlyUsedCount = 128;
313cb93a386Sopenharmony_ci
314cb93a386Sopenharmony_ciGrDrawOpAtlas::ErrorCode GrDrawOpAtlas::addToAtlas(GrResourceProvider* resourceProvider,
315cb93a386Sopenharmony_ci                                                   GrDeferredUploadTarget* target,
316cb93a386Sopenharmony_ci                                                   int width, int height, const void* image,
317cb93a386Sopenharmony_ci                                                   AtlasLocator* atlasLocator) {
318cb93a386Sopenharmony_ci    if (width > fPlotWidth || height > fPlotHeight) {
319cb93a386Sopenharmony_ci        return ErrorCode::kError;
320cb93a386Sopenharmony_ci    }
321cb93a386Sopenharmony_ci
322cb93a386Sopenharmony_ci    // Look through each page to see if we can upload without having to flush
323cb93a386Sopenharmony_ci    // We prioritize this upload to the first pages, not the most recently used, to make it easier
324cb93a386Sopenharmony_ci    // to remove unused pages in reverse page order.
325cb93a386Sopenharmony_ci    for (unsigned int pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
326cb93a386Sopenharmony_ci        if (this->uploadToPage(pageIdx, target, width, height, image, atlasLocator)) {
327cb93a386Sopenharmony_ci            return ErrorCode::kSucceeded;
328cb93a386Sopenharmony_ci        }
329cb93a386Sopenharmony_ci    }
330cb93a386Sopenharmony_ci
331cb93a386Sopenharmony_ci    // If the above fails, then see if the least recently used plot per page has already been
332cb93a386Sopenharmony_ci    // flushed to the gpu if we're at max page allocation, or if the plot has aged out otherwise.
333cb93a386Sopenharmony_ci    // We wait until we've grown to the full number of pages to begin evicting already flushed
334cb93a386Sopenharmony_ci    // plots so that we can maximize the opportunity for reuse.
335cb93a386Sopenharmony_ci    // As before we prioritize this upload to the first pages, not the most recently used.
336cb93a386Sopenharmony_ci    if (fNumActivePages == this->maxPages()) {
337cb93a386Sopenharmony_ci        for (unsigned int pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
338cb93a386Sopenharmony_ci            Plot* plot = fPages[pageIdx].fPlotList.tail();
339cb93a386Sopenharmony_ci            SkASSERT(plot);
340cb93a386Sopenharmony_ci            if (plot->lastUseToken() < target->tokenTracker()->nextTokenToFlush()) {
341cb93a386Sopenharmony_ci                this->processEvictionAndResetRects(plot);
342cb93a386Sopenharmony_ci                SkASSERT(GrBackendFormatBytesPerPixel(fViews[pageIdx].proxy()->backendFormat()) ==
343cb93a386Sopenharmony_ci                         plot->bpp());
344cb93a386Sopenharmony_ci                SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, atlasLocator);
345cb93a386Sopenharmony_ci                SkASSERT(verify);
346cb93a386Sopenharmony_ci                if (!this->updatePlot(target, atlasLocator, plot)) {
347cb93a386Sopenharmony_ci                    return ErrorCode::kError;
348cb93a386Sopenharmony_ci                }
349cb93a386Sopenharmony_ci                return ErrorCode::kSucceeded;
350cb93a386Sopenharmony_ci            }
351cb93a386Sopenharmony_ci        }
352cb93a386Sopenharmony_ci    } else {
353cb93a386Sopenharmony_ci        // If we haven't activated all the available pages, try to create a new one and add to it
354cb93a386Sopenharmony_ci        if (!this->activateNewPage(resourceProvider)) {
355cb93a386Sopenharmony_ci            return ErrorCode::kError;
356cb93a386Sopenharmony_ci        }
357cb93a386Sopenharmony_ci
358cb93a386Sopenharmony_ci        if (this->uploadToPage(fNumActivePages-1, target, width, height, image, atlasLocator)) {
359cb93a386Sopenharmony_ci            return ErrorCode::kSucceeded;
360cb93a386Sopenharmony_ci        } else {
361cb93a386Sopenharmony_ci            // If we fail to upload to a newly activated page then something has gone terribly
362cb93a386Sopenharmony_ci            // wrong - return an error
363cb93a386Sopenharmony_ci            return ErrorCode::kError;
364cb93a386Sopenharmony_ci        }
365cb93a386Sopenharmony_ci    }
366cb93a386Sopenharmony_ci
367cb93a386Sopenharmony_ci    if (!fNumActivePages) {
368cb93a386Sopenharmony_ci        return ErrorCode::kError;
369cb93a386Sopenharmony_ci    }
370cb93a386Sopenharmony_ci
371cb93a386Sopenharmony_ci    // Try to find a plot that we can perform an inline upload to.
372cb93a386Sopenharmony_ci    // We prioritize this upload in reverse order of pages to counterbalance the order above.
373cb93a386Sopenharmony_ci    Plot* plot = nullptr;
374cb93a386Sopenharmony_ci    for (int pageIdx = ((int)fNumActivePages)-1; pageIdx >= 0; --pageIdx) {
375cb93a386Sopenharmony_ci        Plot* currentPlot = fPages[pageIdx].fPlotList.tail();
376cb93a386Sopenharmony_ci        if (currentPlot->lastUseToken() != target->tokenTracker()->nextDrawToken()) {
377cb93a386Sopenharmony_ci            plot = currentPlot;
378cb93a386Sopenharmony_ci            break;
379cb93a386Sopenharmony_ci        }
380cb93a386Sopenharmony_ci    }
381cb93a386Sopenharmony_ci
382cb93a386Sopenharmony_ci    // If we can't find a plot that is not used in a draw currently being prepared by an op, then
383cb93a386Sopenharmony_ci    // we have to fail. This gives the op a chance to enqueue the draw, and call back into this
384cb93a386Sopenharmony_ci    // function. When that draw is enqueued, the draw token advances, and the subsequent call will
385cb93a386Sopenharmony_ci    // continue past this branch and prepare an inline upload that will occur after the enqueued
386cb93a386Sopenharmony_ci    // draw which references the plot's pre-upload content.
387cb93a386Sopenharmony_ci    if (!plot) {
388cb93a386Sopenharmony_ci        return ErrorCode::kTryAgain;
389cb93a386Sopenharmony_ci    }
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_ci    this->processEviction(plot->plotLocator());
392cb93a386Sopenharmony_ci    int pageIdx = plot->pageIndex();
393cb93a386Sopenharmony_ci    fPages[pageIdx].fPlotList.remove(plot);
394cb93a386Sopenharmony_ci    sk_sp<Plot>& newPlot = fPages[pageIdx].fPlotArray[plot->plotIndex()];
395cb93a386Sopenharmony_ci    newPlot.reset(plot->clone());
396cb93a386Sopenharmony_ci
397cb93a386Sopenharmony_ci    fPages[pageIdx].fPlotList.addToHead(newPlot.get());
398cb93a386Sopenharmony_ci    SkASSERT(GrBackendFormatBytesPerPixel(fViews[pageIdx].proxy()->backendFormat()) ==
399cb93a386Sopenharmony_ci             newPlot->bpp());
400cb93a386Sopenharmony_ci    SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, atlasLocator);
401cb93a386Sopenharmony_ci    SkASSERT(verify);
402cb93a386Sopenharmony_ci
403cb93a386Sopenharmony_ci    // Note that this plot will be uploaded inline with the draws whereas the
404cb93a386Sopenharmony_ci    // one it displaced most likely was uploaded ASAP.
405cb93a386Sopenharmony_ci    // With c++14 we could move sk_sp into lambda to only ref once.
406cb93a386Sopenharmony_ci    sk_sp<Plot> plotsp(SkRef(newPlot.get()));
407cb93a386Sopenharmony_ci
408cb93a386Sopenharmony_ci    GrTextureProxy* proxy = fViews[pageIdx].asTextureProxy();
409cb93a386Sopenharmony_ci    SkASSERT(proxy && proxy->isInstantiated());
410cb93a386Sopenharmony_ci
411cb93a386Sopenharmony_ci    GrDeferredUploadToken lastUploadToken = target->addInlineUpload(
412cb93a386Sopenharmony_ci            [plotsp, proxy](GrDeferredTextureUploadWritePixelsFn& writePixels) {
413cb93a386Sopenharmony_ci                plotsp->uploadToTexture(writePixels, proxy);
414cb93a386Sopenharmony_ci            });
415cb93a386Sopenharmony_ci    newPlot->setLastUploadToken(lastUploadToken);
416cb93a386Sopenharmony_ci
417cb93a386Sopenharmony_ci    atlasLocator->updatePlotLocator(newPlot->plotLocator());
418cb93a386Sopenharmony_ci    SkDEBUGCODE(this->validate(*atlasLocator);)
419cb93a386Sopenharmony_ci
420cb93a386Sopenharmony_ci    return ErrorCode::kSucceeded;
421cb93a386Sopenharmony_ci}
422cb93a386Sopenharmony_ci
423cb93a386Sopenharmony_ci#ifdef SK_ENABLE_SMALL_PAGE
424cb93a386Sopenharmony_civoid GrDrawOpAtlas::compactRadicals(GrDeferredUploadToken startTokenForNextFlush) {
425cb93a386Sopenharmony_ci    if (fNumActivePages <= 1) {
426cb93a386Sopenharmony_ci        return;
427cb93a386Sopenharmony_ci    }
428cb93a386Sopenharmony_ci    PlotList::Iter plotIter;
429cb93a386Sopenharmony_ci    unsigned short usedAtlasLastFlush = 0;
430cb93a386Sopenharmony_ci    for (uint32_t pageIndex = 0; pageIndex < fNumActivePages; ++pageIndex) {
431cb93a386Sopenharmony_ci        plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
432cb93a386Sopenharmony_ci        while (Plot* plot = plotIter.get()) {
433cb93a386Sopenharmony_ci            if (plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
434cb93a386Sopenharmony_ci                usedAtlasLastFlush |= (1 << pageIndex);
435cb93a386Sopenharmony_ci                break;
436cb93a386Sopenharmony_ci            } else if (plot->lastUploadToken() != GrDeferredUploadToken::AlreadyFlushedToken()) {
437cb93a386Sopenharmony_ci                this->processEvictionAndResetRects(plot);
438cb93a386Sopenharmony_ci            }
439cb93a386Sopenharmony_ci            plotIter.next();
440cb93a386Sopenharmony_ci        }
441cb93a386Sopenharmony_ci    }
442cb93a386Sopenharmony_ci    int lastPageIndex = fNumActivePages - 1;
443cb93a386Sopenharmony_ci    while (lastPageIndex > 0 && !(usedAtlasLastFlush & (1 << lastPageIndex))) {
444cb93a386Sopenharmony_ci        deactivateLastPage();
445cb93a386Sopenharmony_ci        lastPageIndex--;
446cb93a386Sopenharmony_ci    }
447cb93a386Sopenharmony_ci}
448cb93a386Sopenharmony_ci#endif
449cb93a386Sopenharmony_ci
450cb93a386Sopenharmony_civoid GrDrawOpAtlas::compact(GrDeferredUploadToken startTokenForNextFlush) {
451cb93a386Sopenharmony_ci#ifdef SK_ENABLE_SMALL_PAGE
452cb93a386Sopenharmony_ci    int threshold;
453cb93a386Sopenharmony_ci    if (this->fUseRadicalsCompact) {
454cb93a386Sopenharmony_ci        threshold = 1;
455cb93a386Sopenharmony_ci        compactRadicals(startTokenForNextFlush);
456cb93a386Sopenharmony_ci    } else {
457cb93a386Sopenharmony_ci        threshold = kPlotRecentlyUsedCount;
458cb93a386Sopenharmony_ci    }
459cb93a386Sopenharmony_ci#else
460cb93a386Sopenharmony_ci    int threshold = kPlotRecentlyUsedCount;
461cb93a386Sopenharmony_ci#endif
462cb93a386Sopenharmony_ci    if (fNumActivePages < 1) {
463cb93a386Sopenharmony_ci        fPrevFlushToken = startTokenForNextFlush;
464cb93a386Sopenharmony_ci        return;
465cb93a386Sopenharmony_ci    }
466cb93a386Sopenharmony_ci
467cb93a386Sopenharmony_ci    // For all plots, reset number of flushes since used if used this frame.
468cb93a386Sopenharmony_ci    PlotList::Iter plotIter;
469cb93a386Sopenharmony_ci    bool atlasUsedThisFlush = false;
470cb93a386Sopenharmony_ci    for (uint32_t pageIndex = 0; pageIndex < fNumActivePages; ++pageIndex) {
471cb93a386Sopenharmony_ci        plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
472cb93a386Sopenharmony_ci        while (Plot* plot = plotIter.get()) {
473cb93a386Sopenharmony_ci            // Reset number of flushes since used
474cb93a386Sopenharmony_ci            if (plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
475cb93a386Sopenharmony_ci                plot->resetFlushesSinceLastUsed();
476cb93a386Sopenharmony_ci                atlasUsedThisFlush = true;
477cb93a386Sopenharmony_ci            }
478cb93a386Sopenharmony_ci
479cb93a386Sopenharmony_ci            plotIter.next();
480cb93a386Sopenharmony_ci        }
481cb93a386Sopenharmony_ci    }
482cb93a386Sopenharmony_ci
483cb93a386Sopenharmony_ci    if (atlasUsedThisFlush) {
484cb93a386Sopenharmony_ci        fFlushesSinceLastUse = 0;
485cb93a386Sopenharmony_ci    } else {
486cb93a386Sopenharmony_ci        ++fFlushesSinceLastUse;
487cb93a386Sopenharmony_ci    }
488cb93a386Sopenharmony_ci
489cb93a386Sopenharmony_ci    // We only try to compact if the atlas was used in the recently completed flush or
490cb93a386Sopenharmony_ci    // hasn't been used in a long time.
491cb93a386Sopenharmony_ci    // This is to handle the case where a lot of text or path rendering has occurred but then just
492cb93a386Sopenharmony_ci    // a blinking cursor is drawn.
493cb93a386Sopenharmony_ci    if (atlasUsedThisFlush || fFlushesSinceLastUse > kAtlasRecentlyUsedCount) {
494cb93a386Sopenharmony_ci        SkTArray<Plot*> availablePlots;
495cb93a386Sopenharmony_ci        uint32_t lastPageIndex = fNumActivePages - 1;
496cb93a386Sopenharmony_ci
497cb93a386Sopenharmony_ci        // For all plots but the last one, update number of flushes since used, and check to see
498cb93a386Sopenharmony_ci        // if there are any in the first pages that the last page can safely upload to.
499cb93a386Sopenharmony_ci        for (uint32_t pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex) {
500cb93a386Sopenharmony_ci#ifdef DUMP_ATLAS_DATA
501cb93a386Sopenharmony_ci            if (gDumpAtlasData) {
502cb93a386Sopenharmony_ci                SkDebugf("page %d: ", pageIndex);
503cb93a386Sopenharmony_ci            }
504cb93a386Sopenharmony_ci#endif
505cb93a386Sopenharmony_ci            plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
506cb93a386Sopenharmony_ci            while (Plot* plot = plotIter.get()) {
507cb93a386Sopenharmony_ci                // Update number of flushes since plot was last used
508cb93a386Sopenharmony_ci                // We only increment the 'sinceLastUsed' count for flushes where the atlas was used
509cb93a386Sopenharmony_ci                // to avoid deleting everything when we return to text drawing in the blinking
510cb93a386Sopenharmony_ci                // cursor case
511cb93a386Sopenharmony_ci                if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
512cb93a386Sopenharmony_ci                    plot->incFlushesSinceLastUsed();
513cb93a386Sopenharmony_ci                }
514cb93a386Sopenharmony_ci
515cb93a386Sopenharmony_ci#ifdef DUMP_ATLAS_DATA
516cb93a386Sopenharmony_ci                if (gDumpAtlasData) {
517cb93a386Sopenharmony_ci                    SkDebugf("%d ", plot->flushesSinceLastUsed());
518cb93a386Sopenharmony_ci                }
519cb93a386Sopenharmony_ci#endif
520cb93a386Sopenharmony_ci                // Count plots we can potentially upload to in all pages except the last one
521cb93a386Sopenharmony_ci                // (the potential compactee).
522cb93a386Sopenharmony_ci                if (plot->flushesSinceLastUsed() > threshold) {
523cb93a386Sopenharmony_ci                    availablePlots.push_back() = plot;
524cb93a386Sopenharmony_ci                }
525cb93a386Sopenharmony_ci
526cb93a386Sopenharmony_ci                plotIter.next();
527cb93a386Sopenharmony_ci            }
528cb93a386Sopenharmony_ci#ifdef DUMP_ATLAS_DATA
529cb93a386Sopenharmony_ci            if (gDumpAtlasData) {
530cb93a386Sopenharmony_ci                SkDebugf("\n");
531cb93a386Sopenharmony_ci            }
532cb93a386Sopenharmony_ci#endif
533cb93a386Sopenharmony_ci        }
534cb93a386Sopenharmony_ci
535cb93a386Sopenharmony_ci        // Count recently used plots in the last page and evict any that are no longer in use.
536cb93a386Sopenharmony_ci        // Since we prioritize uploading to the first pages, this will eventually
537cb93a386Sopenharmony_ci        // clear out usage of this page unless we have a large need.
538cb93a386Sopenharmony_ci        plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
539cb93a386Sopenharmony_ci        unsigned int usedPlots = 0;
540cb93a386Sopenharmony_ci#ifdef DUMP_ATLAS_DATA
541cb93a386Sopenharmony_ci        if (gDumpAtlasData) {
542cb93a386Sopenharmony_ci            SkDebugf("page %d: ", lastPageIndex);
543cb93a386Sopenharmony_ci        }
544cb93a386Sopenharmony_ci#endif
545cb93a386Sopenharmony_ci        while (Plot* plot = plotIter.get()) {
546cb93a386Sopenharmony_ci            // Update number of flushes since plot was last used
547cb93a386Sopenharmony_ci            if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
548cb93a386Sopenharmony_ci                plot->incFlushesSinceLastUsed();
549cb93a386Sopenharmony_ci            }
550cb93a386Sopenharmony_ci
551cb93a386Sopenharmony_ci#ifdef DUMP_ATLAS_DATA
552cb93a386Sopenharmony_ci            if (gDumpAtlasData) {
553cb93a386Sopenharmony_ci                SkDebugf("%d ", plot->flushesSinceLastUsed());
554cb93a386Sopenharmony_ci            }
555cb93a386Sopenharmony_ci#endif
556cb93a386Sopenharmony_ci            // If this plot was used recently
557cb93a386Sopenharmony_ci            if (plot->flushesSinceLastUsed() <= threshold) {
558cb93a386Sopenharmony_ci                usedPlots++;
559cb93a386Sopenharmony_ci            } else if (plot->lastUseToken() != GrDeferredUploadToken::AlreadyFlushedToken()) {
560cb93a386Sopenharmony_ci                // otherwise if aged out just evict it.
561cb93a386Sopenharmony_ci                this->processEvictionAndResetRects(plot);
562cb93a386Sopenharmony_ci            }
563cb93a386Sopenharmony_ci            plotIter.next();
564cb93a386Sopenharmony_ci        }
565cb93a386Sopenharmony_ci#ifdef DUMP_ATLAS_DATA
566cb93a386Sopenharmony_ci        if (gDumpAtlasData) {
567cb93a386Sopenharmony_ci            SkDebugf("\n");
568cb93a386Sopenharmony_ci        }
569cb93a386Sopenharmony_ci#endif
570cb93a386Sopenharmony_ci
571cb93a386Sopenharmony_ci        // If recently used plots in the last page are using less than a quarter of the page, try
572cb93a386Sopenharmony_ci        // to evict them if there's available space in earlier pages. Since we prioritize uploading
573cb93a386Sopenharmony_ci        // to the first pages, this will eventually clear out usage of this page unless we have a
574cb93a386Sopenharmony_ci        // large need.
575cb93a386Sopenharmony_ci        if (availablePlots.count() && usedPlots && usedPlots <= fNumPlots / 4) {
576cb93a386Sopenharmony_ci            plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
577cb93a386Sopenharmony_ci            while (Plot* plot = plotIter.get()) {
578cb93a386Sopenharmony_ci                // If this plot was used recently
579cb93a386Sopenharmony_ci                if (plot->flushesSinceLastUsed() <= threshold) {
580cb93a386Sopenharmony_ci                    // See if there's room in an earlier page and if so evict.
581cb93a386Sopenharmony_ci                    // We need to be somewhat harsh here so that a handful of plots that are
582cb93a386Sopenharmony_ci                    // consistently in use don't end up locking the page in memory.
583cb93a386Sopenharmony_ci                    if (availablePlots.count() > 0) {
584cb93a386Sopenharmony_ci                        this->processEvictionAndResetRects(plot);
585cb93a386Sopenharmony_ci                        this->processEvictionAndResetRects(availablePlots.back());
586cb93a386Sopenharmony_ci                        availablePlots.pop_back();
587cb93a386Sopenharmony_ci                        --usedPlots;
588cb93a386Sopenharmony_ci                    }
589cb93a386Sopenharmony_ci                    if (!usedPlots || !availablePlots.count()) {
590cb93a386Sopenharmony_ci                        break;
591cb93a386Sopenharmony_ci                    }
592cb93a386Sopenharmony_ci                }
593cb93a386Sopenharmony_ci                plotIter.next();
594cb93a386Sopenharmony_ci            }
595cb93a386Sopenharmony_ci        }
596cb93a386Sopenharmony_ci
597cb93a386Sopenharmony_ci        // If none of the plots in the last page have been used recently, delete it.
598cb93a386Sopenharmony_ci        if (!usedPlots) {
599cb93a386Sopenharmony_ci#ifdef DUMP_ATLAS_DATA
600cb93a386Sopenharmony_ci            if (gDumpAtlasData) {
601cb93a386Sopenharmony_ci                SkDebugf("delete %d\n", fNumActivePages-1);
602cb93a386Sopenharmony_ci            }
603cb93a386Sopenharmony_ci#endif
604cb93a386Sopenharmony_ci            this->deactivateLastPage();
605cb93a386Sopenharmony_ci            fFlushesSinceLastUse = 0;
606cb93a386Sopenharmony_ci        }
607cb93a386Sopenharmony_ci    }
608cb93a386Sopenharmony_ci
609cb93a386Sopenharmony_ci    fPrevFlushToken = startTokenForNextFlush;
610cb93a386Sopenharmony_ci}
611cb93a386Sopenharmony_ci
612cb93a386Sopenharmony_cibool GrDrawOpAtlas::createPages(
613cb93a386Sopenharmony_ci        GrProxyProvider* proxyProvider, GenerationCounter* generationCounter) {
614cb93a386Sopenharmony_ci    SkASSERT(SkIsPow2(fTextureWidth) && SkIsPow2(fTextureHeight));
615cb93a386Sopenharmony_ci
616cb93a386Sopenharmony_ci    SkISize dims = {fTextureWidth, fTextureHeight};
617cb93a386Sopenharmony_ci
618cb93a386Sopenharmony_ci    int numPlotsX = fTextureWidth/fPlotWidth;
619cb93a386Sopenharmony_ci    int numPlotsY = fTextureHeight/fPlotHeight;
620cb93a386Sopenharmony_ci
621cb93a386Sopenharmony_ci    for (uint32_t i = 0; i < this->maxPages(); ++i) {
622cb93a386Sopenharmony_ci        GrSwizzle swizzle = proxyProvider->caps()->getReadSwizzle(fFormat, fColorType);
623cb93a386Sopenharmony_ci        if (GrColorTypeIsAlphaOnly(fColorType)) {
624cb93a386Sopenharmony_ci            swizzle = GrSwizzle::Concat(swizzle, GrSwizzle("aaaa"));
625cb93a386Sopenharmony_ci        }
626cb93a386Sopenharmony_ci        sk_sp<GrSurfaceProxy> proxy = proxyProvider->createProxy(
627cb93a386Sopenharmony_ci                fFormat, dims, GrRenderable::kNo, 1, GrMipmapped::kNo, SkBackingFit::kExact,
628cb93a386Sopenharmony_ci                SkBudgeted::kYes, GrProtected::kNo, GrInternalSurfaceFlags::kNone,
629cb93a386Sopenharmony_ci                GrSurfaceProxy::UseAllocator::kNo);
630cb93a386Sopenharmony_ci        if (!proxy) {
631cb93a386Sopenharmony_ci            return false;
632cb93a386Sopenharmony_ci        }
633cb93a386Sopenharmony_ci        fViews[i] = GrSurfaceProxyView(std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle);
634cb93a386Sopenharmony_ci
635cb93a386Sopenharmony_ci        // set up allocated plots
636cb93a386Sopenharmony_ci        fPages[i].fPlotArray = std::make_unique<sk_sp<Plot>[]>(numPlotsX * numPlotsY);
637cb93a386Sopenharmony_ci
638cb93a386Sopenharmony_ci        sk_sp<Plot>* currPlot = fPages[i].fPlotArray.get();
639cb93a386Sopenharmony_ci        for (int y = numPlotsY - 1, r = 0; y >= 0; --y, ++r) {
640cb93a386Sopenharmony_ci            for (int x = numPlotsX - 1, c = 0; x >= 0; --x, ++c) {
641cb93a386Sopenharmony_ci                uint32_t plotIndex = r * numPlotsX + c;
642cb93a386Sopenharmony_ci                currPlot->reset(new Plot(
643cb93a386Sopenharmony_ci                    i, plotIndex, generationCounter, x, y, fPlotWidth, fPlotHeight, fColorType));
644cb93a386Sopenharmony_ci
645cb93a386Sopenharmony_ci                // build LRU list
646cb93a386Sopenharmony_ci                fPages[i].fPlotList.addToHead(currPlot->get());
647cb93a386Sopenharmony_ci                ++currPlot;
648cb93a386Sopenharmony_ci            }
649cb93a386Sopenharmony_ci        }
650cb93a386Sopenharmony_ci
651cb93a386Sopenharmony_ci    }
652cb93a386Sopenharmony_ci
653cb93a386Sopenharmony_ci    return true;
654cb93a386Sopenharmony_ci}
655cb93a386Sopenharmony_ci
656cb93a386Sopenharmony_cibool GrDrawOpAtlas::activateNewPage(GrResourceProvider* resourceProvider) {
657cb93a386Sopenharmony_ci    SkASSERT(fNumActivePages < this->maxPages());
658cb93a386Sopenharmony_ci
659cb93a386Sopenharmony_ci    if (!fViews[fNumActivePages].proxy()->instantiate(resourceProvider)) {
660cb93a386Sopenharmony_ci        return false;
661cb93a386Sopenharmony_ci    }
662cb93a386Sopenharmony_ci
663cb93a386Sopenharmony_ci#ifdef DUMP_ATLAS_DATA
664cb93a386Sopenharmony_ci    if (gDumpAtlasData) {
665cb93a386Sopenharmony_ci        SkDebugf("activated page#: %d\n", fNumActivePages);
666cb93a386Sopenharmony_ci    }
667cb93a386Sopenharmony_ci#endif
668cb93a386Sopenharmony_ci
669cb93a386Sopenharmony_ci    ++fNumActivePages;
670cb93a386Sopenharmony_ci    return true;
671cb93a386Sopenharmony_ci}
672cb93a386Sopenharmony_ci
673cb93a386Sopenharmony_ci
674cb93a386Sopenharmony_ciinline void GrDrawOpAtlas::deactivateLastPage() {
675cb93a386Sopenharmony_ci    SkASSERT(fNumActivePages);
676cb93a386Sopenharmony_ci
677cb93a386Sopenharmony_ci    uint32_t lastPageIndex = fNumActivePages - 1;
678cb93a386Sopenharmony_ci
679cb93a386Sopenharmony_ci    int numPlotsX = fTextureWidth/fPlotWidth;
680cb93a386Sopenharmony_ci    int numPlotsY = fTextureHeight/fPlotHeight;
681cb93a386Sopenharmony_ci
682cb93a386Sopenharmony_ci    fPages[lastPageIndex].fPlotList.reset();
683cb93a386Sopenharmony_ci    for (int r = 0; r < numPlotsY; ++r) {
684cb93a386Sopenharmony_ci        for (int c = 0; c < numPlotsX; ++c) {
685cb93a386Sopenharmony_ci            uint32_t plotIndex = r * numPlotsX + c;
686cb93a386Sopenharmony_ci
687cb93a386Sopenharmony_ci            Plot* currPlot = fPages[lastPageIndex].fPlotArray[plotIndex].get();
688cb93a386Sopenharmony_ci            currPlot->resetRects();
689cb93a386Sopenharmony_ci            currPlot->resetFlushesSinceLastUsed();
690cb93a386Sopenharmony_ci
691cb93a386Sopenharmony_ci            // rebuild the LRU list
692cb93a386Sopenharmony_ci            SkDEBUGCODE(currPlot->fPrev = currPlot->fNext = nullptr);
693cb93a386Sopenharmony_ci            SkDEBUGCODE(currPlot->fList = nullptr);
694cb93a386Sopenharmony_ci            fPages[lastPageIndex].fPlotList.addToHead(currPlot);
695cb93a386Sopenharmony_ci        }
696cb93a386Sopenharmony_ci    }
697cb93a386Sopenharmony_ci
698cb93a386Sopenharmony_ci    // remove ref to the backing texture
699cb93a386Sopenharmony_ci    fViews[lastPageIndex].proxy()->deinstantiate();
700cb93a386Sopenharmony_ci    --fNumActivePages;
701cb93a386Sopenharmony_ci}
702cb93a386Sopenharmony_ci
703cb93a386Sopenharmony_ciGrDrawOpAtlasConfig::GrDrawOpAtlasConfig(int maxTextureSize, size_t maxBytes) {
704cb93a386Sopenharmony_ci    static const SkISize kARGBDimensions[] = {
705cb93a386Sopenharmony_ci        {256, 256},   // maxBytes < 2^19
706cb93a386Sopenharmony_ci        {512, 256},   // 2^19 <= maxBytes < 2^20
707cb93a386Sopenharmony_ci        {512, 512},   // 2^20 <= maxBytes < 2^21
708cb93a386Sopenharmony_ci        {1024, 512},  // 2^21 <= maxBytes < 2^22
709cb93a386Sopenharmony_ci        {1024, 1024}, // 2^22 <= maxBytes < 2^23
710cb93a386Sopenharmony_ci        {2048, 1024}, // 2^23 <= maxBytes
711cb93a386Sopenharmony_ci    };
712cb93a386Sopenharmony_ci
713cb93a386Sopenharmony_ci    // Index 0 corresponds to maxBytes of 2^18, so start by dividing it by that
714cb93a386Sopenharmony_ci    maxBytes >>= 18;
715cb93a386Sopenharmony_ci    // Take the floor of the log to get the index
716cb93a386Sopenharmony_ci    int index = maxBytes > 0
717cb93a386Sopenharmony_ci        ? SkTPin<int>(SkPrevLog2(maxBytes), 0, SK_ARRAY_COUNT(kARGBDimensions) - 1)
718cb93a386Sopenharmony_ci        : 0;
719cb93a386Sopenharmony_ci
720cb93a386Sopenharmony_ci    SkASSERT(kARGBDimensions[index].width() <= kMaxAtlasDim);
721cb93a386Sopenharmony_ci    SkASSERT(kARGBDimensions[index].height() <= kMaxAtlasDim);
722cb93a386Sopenharmony_ci    fARGBDimensions.set(std::min<int>(kARGBDimensions[index].width(), maxTextureSize),
723cb93a386Sopenharmony_ci                        std::min<int>(kARGBDimensions[index].height(), maxTextureSize));
724cb93a386Sopenharmony_ci    fMaxTextureSize = std::min<int>(maxTextureSize, kMaxAtlasDim);
725cb93a386Sopenharmony_ci}
726cb93a386Sopenharmony_ci
727cb93a386Sopenharmony_ci#ifdef SK_ENABLE_SMALL_PAGE
728cb93a386Sopenharmony_ciint GrDrawOpAtlasConfig::resetAsSmallPage() {
729cb93a386Sopenharmony_ci    size_t maxBytes = fARGBDimensions.width() * fARGBDimensions.height() * 4;
730cb93a386Sopenharmony_ci    fARGBDimensions.set(512, 512);
731cb93a386Sopenharmony_ci    return maxBytes / (fARGBDimensions.width() * fARGBDimensions.height());
732cb93a386Sopenharmony_ci}
733cb93a386Sopenharmony_ci#endif
734cb93a386Sopenharmony_ci
735cb93a386Sopenharmony_ciSkISize GrDrawOpAtlasConfig::atlasDimensions(GrMaskFormat type) const {
736cb93a386Sopenharmony_ci    if (kA8_GrMaskFormat == type) {
737cb93a386Sopenharmony_ci        // A8 is always 2x the ARGB dimensions, clamped to the max allowed texture size
738cb93a386Sopenharmony_ci        return { std::min<int>(2 * fARGBDimensions.width(), fMaxTextureSize),
739cb93a386Sopenharmony_ci                 std::min<int>(2 * fARGBDimensions.height(), fMaxTextureSize) };
740cb93a386Sopenharmony_ci    } else {
741cb93a386Sopenharmony_ci        return fARGBDimensions;
742cb93a386Sopenharmony_ci    }
743cb93a386Sopenharmony_ci}
744cb93a386Sopenharmony_ci
745cb93a386Sopenharmony_ciSkISize GrDrawOpAtlasConfig::plotDimensions(GrMaskFormat type) const {
746cb93a386Sopenharmony_ci    if (kA8_GrMaskFormat == type) {
747cb93a386Sopenharmony_ci        SkISize atlasDimensions = this->atlasDimensions(type);
748cb93a386Sopenharmony_ci        // For A8 we want to grow the plots at larger texture sizes to accept more of the
749cb93a386Sopenharmony_ci        // larger SDF glyphs. Since the largest SDF glyph can be 170x170 with padding, this
750cb93a386Sopenharmony_ci        // allows us to pack 3 in a 512x256 plot, or 9 in a 512x512 plot.
751cb93a386Sopenharmony_ci
752cb93a386Sopenharmony_ci#ifdef SK_ENABLE_SMALL_PAGE
753cb93a386Sopenharmony_ci        // This will give us 515×512 plots for 1024x1024, 256x256 plots otherwise.
754cb93a386Sopenharmony_ci        int plotWidth = atlasDimensions.width() >= 1024 ? 512 : 256;
755cb93a386Sopenharmony_ci        int plotHeight = atlasDimensions.height() >= 1024 ? 512 : 256;
756cb93a386Sopenharmony_ci#else
757cb93a386Sopenharmony_ci        // This will give us 512x256 plots for 2048x1024, 512x512 plots for 2048x2048,
758cb93a386Sopenharmony_ci        // and 256x256 plots otherwise.
759cb93a386Sopenharmony_ci        int plotWidth = atlasDimensions.width() >= 2048 ? 512 : 256;
760cb93a386Sopenharmony_ci        int plotHeight = atlasDimensions.height() >= 2048 ? 512 : 256;
761cb93a386Sopenharmony_ci#endif
762cb93a386Sopenharmony_ci
763cb93a386Sopenharmony_ci        return { plotWidth, plotHeight };
764cb93a386Sopenharmony_ci    } else {
765cb93a386Sopenharmony_ci        // ARGB and LCD always use 256x256 plots -- this has been shown to be faster
766cb93a386Sopenharmony_ci        return { 256, 256 };
767cb93a386Sopenharmony_ci    }
768cb93a386Sopenharmony_ci}
769