blob: 0ba9deca0496b1433dc96ec1316a69ef4be38a09 [file] [log] [blame]
joshualitt5bf99f12015-03-13 11:47:42 -07001/*
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
Brian Salomon903da792016-12-16 14:24:46 -05008#include "GrDrawOpAtlas.h"
Robert Phillips32f28182017-02-28 16:20:03 -05009
10#include "GrContext.h"
Robert Phillips0bd24dc2018-01-16 08:06:32 -050011#include "GrContextPriv.h"
Brian Salomon742e31d2016-12-07 17:06:19 -050012#include "GrOpFlushState.h"
joshualitt5bf99f12015-03-13 11:47:42 -070013#include "GrRectanizer.h"
Robert Phillips0bd24dc2018-01-16 08:06:32 -050014#include "GrProxyProvider.h"
Robert Phillips256c37b2017-03-01 14:32:46 -050015#include "GrResourceProvider.h"
Robert Phillips646e4292017-06-13 12:44:56 -040016#include "GrTexture.h"
joshualitt5bf99f12015-03-13 11:47:42 -070017#include "GrTracing.h"
18
Brian Salomon9f545bc2017-11-06 10:36:57 -050019std::unique_ptr<GrDrawOpAtlas> GrDrawOpAtlas::Make(GrContext* ctx, GrPixelConfig config, int width,
20 int height, int numPlotsX, int numPlotsY,
21 AllowMultitexturing allowMultitexturing,
22 GrDrawOpAtlas::EvictionFunc func, void* data) {
23 std::unique_ptr<GrDrawOpAtlas> atlas(new GrDrawOpAtlas(ctx, config, width, height, numPlotsX,
24 numPlotsY, allowMultitexturing));
Jim Van Vertha950b632017-09-12 11:54:11 -040025 if (!atlas->getProxies()[0]) {
Jim Van Verthd74f3f22017-08-31 16:44:08 -040026 return nullptr;
27 }
28
Robert Phillips256c37b2017-03-01 14:32:46 -050029 atlas->registerEvictionCallback(func, data);
30 return atlas;
31}
32
Jim Van Verthc3269ae2017-09-28 15:04:00 -040033#ifdef DUMP_ATLAS_DATA
34static bool gDumpAtlasData = false;
35#endif
Robert Phillips256c37b2017-03-01 14:32:46 -050036
joshualitt5df175e2015-11-18 13:37:54 -080037////////////////////////////////////////////////////////////////////////////////
joshualitt5bf99f12015-03-13 11:47:42 -070038
Jim Van Vertha950b632017-09-12 11:54:11 -040039GrDrawOpAtlas::Plot::Plot(int pageIndex, int plotIndex, uint64_t genID, int offX, int offY,
40 int width, int height, GrPixelConfig config)
Brian Salomon943ed792017-10-30 09:37:55 -040041 : fLastUpload(GrDeferredUploadToken::AlreadyFlushedToken())
42 , fLastUse(GrDeferredUploadToken::AlreadyFlushedToken())
Jim Van Verth106b5c42017-09-26 12:45:29 -040043 , fFlushesSinceLastUse(0)
Jim Van Vertha950b632017-09-12 11:54:11 -040044 , fPageIndex(pageIndex)
45 , fPlotIndex(plotIndex)
Brian Salomon2ee084e2016-12-16 18:59:19 -050046 , fGenID(genID)
Jim Van Vertha950b632017-09-12 11:54:11 -040047 , fID(CreateId(fPageIndex, fPlotIndex, fGenID))
Brian Salomon2ee084e2016-12-16 18:59:19 -050048 , fData(nullptr)
49 , fWidth(width)
50 , fHeight(height)
51 , fX(offX)
52 , fY(offY)
53 , fRects(nullptr)
54 , fOffset(SkIPoint16::Make(fX * fWidth, fY * fHeight))
55 , fConfig(config)
56 , fBytesPerPixel(GrBytesPerPixel(config))
joshualitt5df175e2015-11-18 13:37:54 -080057#ifdef SK_DEBUG
Brian Salomon2ee084e2016-12-16 18:59:19 -050058 , fDirty(false)
joshualitt5df175e2015-11-18 13:37:54 -080059#endif
60{
61 fDirtyRect.setEmpty();
62}
joshualitt5bf99f12015-03-13 11:47:42 -070063
Brian Salomon2ee084e2016-12-16 18:59:19 -050064GrDrawOpAtlas::Plot::~Plot() {
jvanverthc3d706f2016-04-20 10:33:27 -070065 sk_free(fData);
joshualitt5df175e2015-11-18 13:37:54 -080066 delete fRects;
67}
joshualitt5bf99f12015-03-13 11:47:42 -070068
Brian Salomon2ee084e2016-12-16 18:59:19 -050069bool GrDrawOpAtlas::Plot::addSubImage(int width, int height, const void* image, SkIPoint16* loc) {
joshualitt5df175e2015-11-18 13:37:54 -080070 SkASSERT(width <= fWidth && height <= fHeight);
joshualitt5bf99f12015-03-13 11:47:42 -070071
joshualitt5df175e2015-11-18 13:37:54 -080072 if (!fRects) {
73 fRects = GrRectanizer::Factory(fWidth, fHeight);
joshualitt5bf99f12015-03-13 11:47:42 -070074 }
75
joshualitt5df175e2015-11-18 13:37:54 -080076 if (!fRects->addRect(width, height, loc)) {
77 return false;
joshualittb4c507e2015-04-08 08:07:59 -070078 }
joshualitt5bf99f12015-03-13 11:47:42 -070079
jvanverthc3d706f2016-04-20 10:33:27 -070080 if (!fData) {
81 fData = reinterpret_cast<unsigned char*>(sk_calloc_throw(fBytesPerPixel * fWidth *
82 fHeight));
joshualitt5df175e2015-11-18 13:37:54 -080083 }
84 size_t rowBytes = width * fBytesPerPixel;
85 const unsigned char* imagePtr = (const unsigned char*)image;
86 // point ourselves at the right starting spot
jvanverthc3d706f2016-04-20 10:33:27 -070087 unsigned char* dataPtr = fData;
joshualitt5df175e2015-11-18 13:37:54 -080088 dataPtr += fBytesPerPixel * fWidth * loc->fY;
89 dataPtr += fBytesPerPixel * loc->fX;
Brian Osmancce3e582016-10-14 11:42:20 -040090 // copy into the data buffer, swizzling as we go if this is ARGB data
91 if (4 == fBytesPerPixel && kSkia8888_GrPixelConfig == kBGRA_8888_GrPixelConfig) {
92 for (int i = 0; i < height; ++i) {
93 SkOpts::RGBA_to_BGRA(reinterpret_cast<uint32_t*>(dataPtr), imagePtr, width);
94 dataPtr += fBytesPerPixel * fWidth;
95 imagePtr += rowBytes;
96 }
97 } else {
98 for (int i = 0; i < height; ++i) {
99 memcpy(dataPtr, imagePtr, rowBytes);
100 dataPtr += fBytesPerPixel * fWidth;
101 imagePtr += rowBytes;
102 }
joshualitt5bf99f12015-03-13 11:47:42 -0700103 }
104
joshualitt5df175e2015-11-18 13:37:54 -0800105 fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height);
robertphillips2b0536f2015-11-06 14:10:42 -0800106
joshualitt5df175e2015-11-18 13:37:54 -0800107 loc->fX += fOffset.fX;
108 loc->fY += fOffset.fY;
109 SkDEBUGCODE(fDirty = true;)
joshualitt5bf99f12015-03-13 11:47:42 -0700110
joshualitt5df175e2015-11-18 13:37:54 -0800111 return true;
112}
joshualitt5bf99f12015-03-13 11:47:42 -0700113
Brian Salomon943ed792017-10-30 09:37:55 -0400114void GrDrawOpAtlas::Plot::uploadToTexture(GrDeferredTextureUploadWritePixelsFn& writePixels,
Robert Phillipsacaa6072017-07-28 10:54:53 -0400115 GrTextureProxy* proxy) {
joshualitt5df175e2015-11-18 13:37:54 -0800116 // We should only be issuing uploads if we are in fact dirty
Robert Phillipsacaa6072017-07-28 10:54:53 -0400117 SkASSERT(fDirty && fData && proxy && proxy->priv().peekTexture());
Brian Osman39c08ac2017-07-26 09:36:09 -0400118 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
joshualitt5df175e2015-11-18 13:37:54 -0800119 size_t rowBytes = fBytesPerPixel * fWidth;
jvanverthc3d706f2016-04-20 10:33:27 -0700120 const unsigned char* dataPtr = fData;
121 dataPtr += rowBytes * fDirtyRect.fTop;
122 dataPtr += fBytesPerPixel * fDirtyRect.fLeft;
Robert Phillipsacaa6072017-07-28 10:54:53 -0400123 writePixels(proxy, fOffset.fX + fDirtyRect.fLeft, fOffset.fY + fDirtyRect.fTop,
jvanverthc3d706f2016-04-20 10:33:27 -0700124 fDirtyRect.width(), fDirtyRect.height(), fConfig, dataPtr, rowBytes);
joshualitt5df175e2015-11-18 13:37:54 -0800125 fDirtyRect.setEmpty();
126 SkDEBUGCODE(fDirty = false;)
127}
128
Brian Salomon2ee084e2016-12-16 18:59:19 -0500129void GrDrawOpAtlas::Plot::resetRects() {
joshualitt5df175e2015-11-18 13:37:54 -0800130 if (fRects) {
131 fRects->reset();
joshualitt5bf99f12015-03-13 11:47:42 -0700132 }
133
joshualitt5df175e2015-11-18 13:37:54 -0800134 fGenID++;
Jim Van Vertha950b632017-09-12 11:54:11 -0400135 fID = CreateId(fPageIndex, fPlotIndex, fGenID);
Brian Salomon943ed792017-10-30 09:37:55 -0400136 fLastUpload = GrDeferredUploadToken::AlreadyFlushedToken();
137 fLastUse = GrDeferredUploadToken::AlreadyFlushedToken();
joshualitt5df175e2015-11-18 13:37:54 -0800138
139 // zero out the plot
jvanverthc3d706f2016-04-20 10:33:27 -0700140 if (fData) {
141 sk_bzero(fData, fBytesPerPixel * fWidth * fHeight);
joshualitt5bf99f12015-03-13 11:47:42 -0700142 }
143
joshualitt5df175e2015-11-18 13:37:54 -0800144 fDirtyRect.setEmpty();
145 SkDEBUGCODE(fDirty = false;)
146}
joshualitt5bf99f12015-03-13 11:47:42 -0700147
joshualitt5bf99f12015-03-13 11:47:42 -0700148///////////////////////////////////////////////////////////////////////////////
149
Jim Van Verthd74f3f22017-08-31 16:44:08 -0400150GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, GrPixelConfig config, int width, int height,
Brian Salomon9f545bc2017-11-06 10:36:57 -0500151 int numPlotsX, int numPlotsY, AllowMultitexturing allowMultitexturing)
Robert Phillips32f28182017-02-28 16:20:03 -0500152 : fContext(context)
Jim Van Verthd74f3f22017-08-31 16:44:08 -0400153 , fPixelConfig(config)
154 , fTextureWidth(width)
155 , fTextureHeight(height)
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400156 , fAtlasGeneration(kInvalidAtlasGeneration + 1)
Brian Salomon943ed792017-10-30 09:37:55 -0400157 , fPrevFlushToken(GrDeferredUploadToken::AlreadyFlushedToken())
Brian Salomon9f545bc2017-11-06 10:36:57 -0500158 , fAllowMultitexturing(allowMultitexturing)
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400159 , fNumPages(0) {
Jim Van Verthd74f3f22017-08-31 16:44:08 -0400160 fPlotWidth = fTextureWidth / numPlotsX;
161 fPlotHeight = fTextureHeight / numPlotsY;
robertphillips2b0536f2015-11-06 14:10:42 -0800162 SkASSERT(numPlotsX * numPlotsY <= BulkUseTokenUpdater::kMaxPlots);
Jim Van Verthd74f3f22017-08-31 16:44:08 -0400163 SkASSERT(fPlotWidth * numPlotsX == fTextureWidth);
164 SkASSERT(fPlotHeight * numPlotsY == fTextureHeight);
robertphillips2b0536f2015-11-06 14:10:42 -0800165
166 SkDEBUGCODE(fNumPlots = numPlotsX * numPlotsY;)
joshualitt5bf99f12015-03-13 11:47:42 -0700167
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400168 this->createNewPage();
joshualitt5bf99f12015-03-13 11:47:42 -0700169}
170
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400171inline void GrDrawOpAtlas::processEviction(AtlasID id) {
joshualitt5bf99f12015-03-13 11:47:42 -0700172 for (int i = 0; i < fEvictionCallbacks.count(); i++) {
173 (*fEvictionCallbacks[i].fFunc)(id, fEvictionCallbacks[i].fData);
174 }
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400175 ++fAtlasGeneration;
joshualitt5bf99f12015-03-13 11:47:42 -0700176}
177
Brian Salomon29b60c92017-10-31 14:42:10 -0400178inline bool GrDrawOpAtlas::updatePlot(GrDeferredUploadTarget* target, AtlasID* id, Plot* plot) {
Jim Van Vertha950b632017-09-12 11:54:11 -0400179 int pageIdx = GetPageIndexFromID(plot->id());
180 this->makeMRU(plot, pageIdx);
joshualitt5bf99f12015-03-13 11:47:42 -0700181
182 // If our most recent upload has already occurred then we have to insert a new
183 // upload. Otherwise, we already have a scheduled upload that hasn't yet ocurred.
184 // This new update will piggy back on that previously scheduled update.
Brian Salomon29b60c92017-10-31 14:42:10 -0400185 if (plot->lastUploadToken() < target->nextTokenToFlush()) {
jvanverthc3d706f2016-04-20 10:33:27 -0700186 // With c+14 we could move sk_sp into lamba to only ref once.
Brian Salomon2ee084e2016-12-16 18:59:19 -0500187 sk_sp<Plot> plotsp(SkRef(plot));
Robert Phillips256c37b2017-03-01 14:32:46 -0500188
Robert Phillips32f28182017-02-28 16:20:03 -0500189 // MDB TODO: this is currently fine since the atlas' proxy is always pre-instantiated.
190 // Once it is deferred more care must be taken upon instantiation failure.
Hal Canarybe46e242018-01-16 18:33:07 +0000191 if (!fProxies[pageIdx]->instantiate(fContext->resourceProvider())) {
Robert Phillips256c37b2017-03-01 14:32:46 -0500192 return false;
Robert Phillips32f28182017-02-28 16:20:03 -0500193 }
Robert Phillipsacaa6072017-07-28 10:54:53 -0400194
Jim Van Vertha950b632017-09-12 11:54:11 -0400195 GrTextureProxy* proxy = fProxies[pageIdx].get();
Robert Phillips256c37b2017-03-01 14:32:46 -0500196
Brian Salomon29b60c92017-10-31 14:42:10 -0400197 GrDeferredUploadToken lastUploadToken = target->addASAPUpload(
Brian Salomon943ed792017-10-30 09:37:55 -0400198 [plotsp, proxy](GrDeferredTextureUploadWritePixelsFn& writePixels) {
199 plotsp->uploadToTexture(writePixels, proxy);
200 });
Robert Phillips256c37b2017-03-01 14:32:46 -0500201 plot->setLastUploadToken(lastUploadToken);
joshualitt5bf99f12015-03-13 11:47:42 -0700202 }
203 *id = plot->id();
Robert Phillips256c37b2017-03-01 14:32:46 -0500204 return true;
joshualitt5bf99f12015-03-13 11:47:42 -0700205}
206
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400207// Number of atlas-related flushes beyond which we consider a plot to no longer be in use.
208//
209// This value is somewhat arbitrary -- the idea is to keep it low enough that
210// a page with unused plots will get removed reasonably quickly, but allow it
211// to hang around for a bit in case it's needed. The assumption is that flushes
212// are rare; i.e., we are not continually refreshing the frame.
Derek Sollenberger90196cc2017-10-09 15:00:33 -0400213static constexpr auto kRecentlyUsedCount = 256;
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400214
Brian Salomon29b60c92017-10-31 14:42:10 -0400215bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDeferredUploadTarget* target, int width, int height,
Brian Salomon2ee084e2016-12-16 18:59:19 -0500216 const void* image, SkIPoint16* loc) {
bsalomon6d6b6ad2016-07-13 14:45:28 -0700217 if (width > fPlotWidth || height > fPlotHeight) {
218 return false;
219 }
joshualitt5bf99f12015-03-13 11:47:42 -0700220
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400221 // Look through each page to see if we can upload without having to flush
222 // We prioritize this upload to the first pages, not the most recently used, to make it easier
223 // to remove unused pages in reverse page order.
224 for (unsigned int pageIdx = 0; pageIdx < fNumPages; ++pageIdx) {
225 SkASSERT(fProxies[pageIdx]);
226 // look through all allocated plots for one we can share, in Most Recently Refed order
227 PlotList::Iter plotIter;
228 plotIter.init(fPages[pageIdx].fPlotList, PlotList::Iter::kHead_IterStart);
229 Plot* plot;
230 while ((plot = plotIter.get())) {
231 SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp());
232 if (plot->addSubImage(width, height, image, loc)) {
233 return this->updatePlot(target, id, plot);
234 }
235 plotIter.next();
236 }
Jim Van Verth712fe732017-09-25 16:53:49 -0400237 }
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400238
Jim Van Verth712fe732017-09-25 16:53:49 -0400239 // If the above fails, then see if the least recently used plot per page has already been
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400240 // flushed to the gpu if we're at max page allocation, or if the plot has aged out otherwise.
241 // We wait until we've grown to the full number of pages to begin evicting already flushed
242 // plots so that we can maximize the opportunity for reuse.
Jim Van Verth712fe732017-09-25 16:53:49 -0400243 // As before we prioritize this upload to the first pages, not the most recently used.
244 for (unsigned int pageIdx = 0; pageIdx < fNumPages; ++pageIdx) {
245 Plot* plot = fPages[pageIdx].fPlotList.tail();
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400246 SkASSERT(plot);
Brian Salomon9f545bc2017-11-06 10:36:57 -0500247 if ((fNumPages == this->maxPages() && plot->lastUseToken() < target->nextTokenToFlush()) ||
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400248 plot->flushesSinceLastUsed() >= kRecentlyUsedCount) {
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400249 this->processEvictionAndResetRects(plot);
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400250 SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp());
251 SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc);
252 SkASSERT(verify);
253 if (!this->updatePlot(target, id, plot)) {
254 return false;
255 }
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400256 return true;
257 }
258 }
259
260 // If the simple cases fail, try to create a new page and add to it
261 if (this->createNewPage()) {
262 unsigned int pageIdx = fNumPages-1;
263 SkASSERT(fProxies[pageIdx]);
264 Plot* plot = fPages[pageIdx].fPlotList.head();
Jim Van Vertha950b632017-09-12 11:54:11 -0400265 SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp());
robertphillips2b0536f2015-11-06 14:10:42 -0800266 if (plot->addSubImage(width, height, image, loc)) {
Robert Phillips256c37b2017-03-01 14:32:46 -0500267 return this->updatePlot(target, id, plot);
joshualitt5bf99f12015-03-13 11:47:42 -0700268 }
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400269
270 // we shouldn't get here -- if so, something has gone terribly wrong
271 SkASSERT(false);
272 return false;
joshualitt5bf99f12015-03-13 11:47:42 -0700273 }
274
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400275 // Try to find a plot that we can perform an inline upload to.
276 // We prioritize this upload in reverse order of pages to counterbalance the order above.
277 Plot* plot = nullptr;
278 for (int pageIdx = (int)(fNumPages-1); pageIdx >= 0; --pageIdx) {
279 Plot* currentPlot = fPages[pageIdx].fPlotList.tail();
280 if (currentPlot->lastUseToken() != target->nextDrawToken()) {
281 plot = currentPlot;
282 break;
Robert Phillips256c37b2017-03-01 14:32:46 -0500283 }
joshualitt5bf99f12015-03-13 11:47:42 -0700284 }
285
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400286 // If we can't find a plot that is not used in a draw currently being prepared by an op, then
287 // we have to fail. This gives the op a chance to enqueue the draw, and call back into this
288 // function. When that draw is enqueued, the draw token advances, and the subsequent call will
289 // continue past this branch and prepare an inline upload that will occur after the enqueued
290 //draw which references the plot's pre-upload content.
291 if (!plot) {
joshualitt5bf99f12015-03-13 11:47:42 -0700292 return false;
293 }
294
joshualitt5bf99f12015-03-13 11:47:42 -0700295 this->processEviction(plot->id());
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400296 int pageIdx = GetPageIndexFromID(plot->id());
Jim Van Vertha950b632017-09-12 11:54:11 -0400297 fPages[pageIdx].fPlotList.remove(plot);
298 sk_sp<Plot>& newPlot = fPages[pageIdx].fPlotArray[plot->index()];
robertphillips2b0536f2015-11-06 14:10:42 -0800299 newPlot.reset(plot->clone());
joshualitt5bf99f12015-03-13 11:47:42 -0700300
Jim Van Vertha950b632017-09-12 11:54:11 -0400301 fPages[pageIdx].fPlotList.addToHead(newPlot.get());
302 SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == newPlot->bpp());
robertphillips2b0536f2015-11-06 14:10:42 -0800303 SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc);
joshualitt5bf99f12015-03-13 11:47:42 -0700304 SkASSERT(verify);
robertphillips2b0536f2015-11-06 14:10:42 -0800305
robertphillips1f0e3502015-11-10 10:19:50 -0800306 // Note that this plot will be uploaded inline with the draws whereas the
Brian Salomon29b60c92017-10-31 14:42:10 -0400307 // one it displaced most likely was uploaded ASAP.
Brian Salomon2ee084e2016-12-16 18:59:19 -0500308 // With c+14 we could move sk_sp into lambda to only ref once.
309 sk_sp<Plot> plotsp(SkRef(newPlot.get()));
Robert Phillips32f28182017-02-28 16:20:03 -0500310 // MDB TODO: this is currently fine since the atlas' proxy is always pre-instantiated.
311 // Once it is deferred more care must be taken upon instantiation failure.
Hal Canarybe46e242018-01-16 18:33:07 +0000312 if (!fProxies[pageIdx]->instantiate(fContext->resourceProvider())) {
Robert Phillips256c37b2017-03-01 14:32:46 -0500313 return false;
Robert Phillips32f28182017-02-28 16:20:03 -0500314 }
Jim Van Vertha950b632017-09-12 11:54:11 -0400315 GrTextureProxy* proxy = fProxies[pageIdx].get();
bsalomon342bfc22016-04-01 06:06:20 -0700316
Brian Salomon943ed792017-10-30 09:37:55 -0400317 GrDeferredUploadToken lastUploadToken = target->addInlineUpload(
318 [plotsp, proxy](GrDeferredTextureUploadWritePixelsFn& writePixels) {
319 plotsp->uploadToTexture(writePixels, proxy);
320 });
Robert Phillips256c37b2017-03-01 14:32:46 -0500321 newPlot->setLastUploadToken(lastUploadToken);
322
joshualitt5bf99f12015-03-13 11:47:42 -0700323 *id = newPlot->id();
robertphillips2b0536f2015-11-06 14:10:42 -0800324
joshualitt5bf99f12015-03-13 11:47:42 -0700325 return true;
326}
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400327
Brian Salomon943ed792017-10-30 09:37:55 -0400328void GrDrawOpAtlas::compact(GrDeferredUploadToken startTokenForNextFlush) {
Jim Van Verth106b5c42017-09-26 12:45:29 -0400329 if (fNumPages <= 1) {
330 fPrevFlushToken = startTokenForNextFlush;
331 return;
332 }
333
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400334 // For all plots, reset number of flushes since used if used this frame.
Jim Van Verth106b5c42017-09-26 12:45:29 -0400335 PlotList::Iter plotIter;
Jim Van Verth106b5c42017-09-26 12:45:29 -0400336 bool atlasUsedThisFlush = false;
337 for (uint32_t pageIndex = 0; pageIndex < fNumPages; ++pageIndex) {
338 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
339 while (Plot* plot = plotIter.get()) {
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400340 // Reset number of flushes since used
Jim Van Verth106b5c42017-09-26 12:45:29 -0400341 if (plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
342 plot->resetFlushesSinceLastUsed();
343 atlasUsedThisFlush = true;
Jim Van Verth106b5c42017-09-26 12:45:29 -0400344 }
345
346 plotIter.next();
347 }
348 }
349
350 // We only try to compact if the atlas was used in the recently completed flush.
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400351 // This is to handle the case where a lot of text or path rendering has occurred but then just
352 // a blinking cursor is drawn.
Jim Van Verth106b5c42017-09-26 12:45:29 -0400353 // TODO: consider if we should also do this if it's been a long time since the last atlas use
354 if (atlasUsedThisFlush) {
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400355 int availablePlots = 0;
356 uint32_t lastPageIndex = fNumPages - 1;
357
358 // For all plots but the last one, update number of flushes since used, and check to see
359 // if there are any in the first pages that the last page can safely upload to.
360 for (uint32_t pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex) {
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400361#ifdef DUMP_ATLAS_DATA
362 if (gDumpAtlasData) {
363 SkDebugf("page %d: ", pageIndex);
364 }
365#endif
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400366 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
367 while (Plot* plot = plotIter.get()) {
368 // Update number of flushes since plot was last used
369 // We only increment the 'sinceLastUsed' count for flushes where the atlas was used
370 // to avoid deleting everything when we return to text drawing in the blinking
371 // cursor case
372 if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
373 plot->incFlushesSinceLastUsed();
374 }
375
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400376#ifdef DUMP_ATLAS_DATA
377 if (gDumpAtlasData) {
378 SkDebugf("%d ", plot->flushesSinceLastUsed());
379 }
380#endif
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400381 // Count plots we can potentially upload to in all pages except the last one
382 // (the potential compactee).
383 if (plot->flushesSinceLastUsed() > kRecentlyUsedCount) {
384 ++availablePlots;
385 }
386
387 plotIter.next();
388 }
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400389#ifdef DUMP_ATLAS_DATA
390 if (gDumpAtlasData) {
391 SkDebugf("\n");
392 }
393#endif
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400394 }
395
Jim Van Verth106b5c42017-09-26 12:45:29 -0400396 // Count recently used plots in the last page and evict them if there's available space
397 // in earlier pages. Since we prioritize uploading to the first pages, this will eventually
398 // clear out usage of this page unless we have a large need.
399 plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
400 int usedPlots = 0;
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400401#ifdef DUMP_ATLAS_DATA
402 if (gDumpAtlasData) {
403 SkDebugf("page %d: ", lastPageIndex);
404 }
405#endif
Jim Van Verth106b5c42017-09-26 12:45:29 -0400406 while (Plot* plot = plotIter.get()) {
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400407 // Update number of flushes since plot was last used
408 if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
409 plot->incFlushesSinceLastUsed();
410 }
411
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400412#ifdef DUMP_ATLAS_DATA
413 if (gDumpAtlasData) {
414 SkDebugf("%d ", plot->flushesSinceLastUsed());
415 }
416#endif
Jim Van Verth106b5c42017-09-26 12:45:29 -0400417 // If this plot was used recently
418 if (plot->flushesSinceLastUsed() <= kRecentlyUsedCount) {
419 usedPlots++;
420 // see if there's room in an earlier page and if so evict.
421 // We need to be somewhat harsh here so that one plot that is consistently in use
422 // doesn't end up locking the page in memory.
423 if (availablePlots) {
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400424 this->processEvictionAndResetRects(plot);
Jim Van Verth106b5c42017-09-26 12:45:29 -0400425 --availablePlots;
426 }
Brian Salomon943ed792017-10-30 09:37:55 -0400427 } else if (plot->lastUseToken() != GrDeferredUploadToken::AlreadyFlushedToken()) {
Jim Van Verth106b5c42017-09-26 12:45:29 -0400428 // otherwise if aged out just evict it.
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400429 this->processEvictionAndResetRects(plot);
Jim Van Verth106b5c42017-09-26 12:45:29 -0400430 }
431 plotIter.next();
432 }
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400433#ifdef DUMP_ATLAS_DATA
434 if (gDumpAtlasData) {
435 SkDebugf("\n");
436 }
437#endif
Jim Van Verth106b5c42017-09-26 12:45:29 -0400438 // If none of the plots in the last page have been used recently, delete it.
439 if (!usedPlots) {
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400440#ifdef DUMP_ATLAS_DATA
441 if (gDumpAtlasData) {
442 SkDebugf("delete %d\n", fNumPages-1);
443 }
444#endif
Jim Van Verth106b5c42017-09-26 12:45:29 -0400445 this->deleteLastPage();
446 }
447 }
448
449 fPrevFlushToken = startTokenForNextFlush;
450}
451
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400452bool GrDrawOpAtlas::createNewPage() {
Brian Salomon9f545bc2017-11-06 10:36:57 -0500453 if (fNumPages == this->maxPages()) {
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400454 return false;
455 }
456
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500457 GrProxyProvider* proxyProvider = fContext->contextPriv().proxyProvider();
458
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400459 GrSurfaceDesc desc;
460 desc.fFlags = kNone_GrSurfaceFlags;
461 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
462 desc.fWidth = fTextureWidth;
463 desc.fHeight = fTextureHeight;
464 desc.fConfig = fPixelConfig;
465
466 // We don't want to flush the context so we claim we're in the middle of flushing so as to
467 // guarantee we do not recieve a texture with pending IO
468 // TODO: Determine how to avoid having to do this. (https://bug.skia.org/4156)
469 static const uint32_t kFlags = GrResourceProvider::kNoPendingIO_Flag;
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500470 // MDB TODO: for now, wrap an instantiated texture. Having the deferred instantiation
471 // possess the correct properties (e.g., no pendingIO) should fall out of the system but
472 // should receive special attention.
473 // Note: When switching over to the deferred proxy, use the kExact flag to create
474 // the atlas and assert that the width & height are powers of 2.
475 // DDL TODO: remove this use of createInstantitateProxy & convert it to a testing-only method.
476 fProxies[fNumPages] = proxyProvider->createInstantiatedProxy(desc, SkBackingFit::kApprox,
477 SkBudgeted::kYes, kFlags);
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400478 if (!fProxies[fNumPages]) {
479 return false;
480 }
481
482 int numPlotsX = fTextureWidth/fPlotWidth;
483 int numPlotsY = fTextureHeight/fPlotHeight;
484
485 // set up allocated plots
486 fPages[fNumPages].fPlotArray.reset(new sk_sp<Plot>[ numPlotsX * numPlotsY ]);
487
488 sk_sp<Plot>* currPlot = fPages[fNumPages].fPlotArray.get();
489 for (int y = numPlotsY - 1, r = 0; y >= 0; --y, ++r) {
490 for (int x = numPlotsX - 1, c = 0; x >= 0; --x, ++c) {
491 uint32_t plotIndex = r * numPlotsX + c;
492 currPlot->reset(new Plot(fNumPages, plotIndex, 1, x, y, fPlotWidth, fPlotHeight,
493 fPixelConfig));
494
495 // build LRU list
496 fPages[fNumPages].fPlotList.addToHead(currPlot->get());
497 ++currPlot;
498 }
499 }
500
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400501#ifdef DUMP_ATLAS_DATA
502 if (gDumpAtlasData) {
503 SkDebugf("created %d\n", fNumPages);
504 }
505#endif
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400506 fNumPages++;
507 return true;
508}
Jim Van Verth106b5c42017-09-26 12:45:29 -0400509
510inline void GrDrawOpAtlas::deleteLastPage() {
511 uint32_t lastPageIndex = fNumPages - 1;
512 // clean out the plots
513 fPages[lastPageIndex].fPlotList.reset();
514 fPages[lastPageIndex].fPlotArray.reset(nullptr);
515 // remove ref to texture proxy
516 fProxies[lastPageIndex].reset(nullptr);
517 --fNumPages;
518}