blob: c0358b79eaf102ee19854575a50ea2dbf9ad907c [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"
Brian Salomon742e31d2016-12-07 17:06:19 -050011#include "GrOpFlushState.h"
joshualitt5bf99f12015-03-13 11:47:42 -070012#include "GrRectanizer.h"
Robert Phillips256c37b2017-03-01 14:32:46 -050013#include "GrResourceProvider.h"
Robert Phillips646e4292017-06-13 12:44:56 -040014#include "GrTexture.h"
joshualitt5bf99f12015-03-13 11:47:42 -070015#include "GrTracing.h"
16
Brian Salomon9f545bc2017-11-06 10:36:57 -050017std::unique_ptr<GrDrawOpAtlas> GrDrawOpAtlas::Make(GrContext* ctx, GrPixelConfig config, int width,
18 int height, int numPlotsX, int numPlotsY,
19 AllowMultitexturing allowMultitexturing,
20 GrDrawOpAtlas::EvictionFunc func, void* data) {
21 std::unique_ptr<GrDrawOpAtlas> atlas(new GrDrawOpAtlas(ctx, config, width, height, numPlotsX,
22 numPlotsY, allowMultitexturing));
Jim Van Vertha950b632017-09-12 11:54:11 -040023 if (!atlas->getProxies()[0]) {
Jim Van Verthd74f3f22017-08-31 16:44:08 -040024 return nullptr;
25 }
26
Robert Phillips256c37b2017-03-01 14:32:46 -050027 atlas->registerEvictionCallback(func, data);
28 return atlas;
29}
30
Jim Van Verthc3269ae2017-09-28 15:04:00 -040031#ifdef DUMP_ATLAS_DATA
32static bool gDumpAtlasData = false;
33#endif
Robert Phillips256c37b2017-03-01 14:32:46 -050034
joshualitt5df175e2015-11-18 13:37:54 -080035////////////////////////////////////////////////////////////////////////////////
joshualitt5bf99f12015-03-13 11:47:42 -070036
Jim Van Vertha950b632017-09-12 11:54:11 -040037GrDrawOpAtlas::Plot::Plot(int pageIndex, int plotIndex, uint64_t genID, int offX, int offY,
38 int width, int height, GrPixelConfig config)
Brian Salomon943ed792017-10-30 09:37:55 -040039 : fLastUpload(GrDeferredUploadToken::AlreadyFlushedToken())
40 , fLastUse(GrDeferredUploadToken::AlreadyFlushedToken())
Jim Van Verth106b5c42017-09-26 12:45:29 -040041 , fFlushesSinceLastUse(0)
Jim Van Vertha950b632017-09-12 11:54:11 -040042 , fPageIndex(pageIndex)
43 , fPlotIndex(plotIndex)
Brian Salomon2ee084e2016-12-16 18:59:19 -050044 , fGenID(genID)
Jim Van Vertha950b632017-09-12 11:54:11 -040045 , fID(CreateId(fPageIndex, fPlotIndex, fGenID))
Brian Salomon2ee084e2016-12-16 18:59:19 -050046 , fData(nullptr)
47 , fWidth(width)
48 , fHeight(height)
49 , fX(offX)
50 , fY(offY)
51 , fRects(nullptr)
52 , fOffset(SkIPoint16::Make(fX * fWidth, fY * fHeight))
53 , fConfig(config)
54 , fBytesPerPixel(GrBytesPerPixel(config))
joshualitt5df175e2015-11-18 13:37:54 -080055#ifdef SK_DEBUG
Brian Salomon2ee084e2016-12-16 18:59:19 -050056 , fDirty(false)
joshualitt5df175e2015-11-18 13:37:54 -080057#endif
58{
59 fDirtyRect.setEmpty();
60}
joshualitt5bf99f12015-03-13 11:47:42 -070061
Brian Salomon2ee084e2016-12-16 18:59:19 -050062GrDrawOpAtlas::Plot::~Plot() {
jvanverthc3d706f2016-04-20 10:33:27 -070063 sk_free(fData);
joshualitt5df175e2015-11-18 13:37:54 -080064 delete fRects;
65}
joshualitt5bf99f12015-03-13 11:47:42 -070066
Brian Salomon2ee084e2016-12-16 18:59:19 -050067bool GrDrawOpAtlas::Plot::addSubImage(int width, int height, const void* image, SkIPoint16* loc) {
joshualitt5df175e2015-11-18 13:37:54 -080068 SkASSERT(width <= fWidth && height <= fHeight);
joshualitt5bf99f12015-03-13 11:47:42 -070069
joshualitt5df175e2015-11-18 13:37:54 -080070 if (!fRects) {
71 fRects = GrRectanizer::Factory(fWidth, fHeight);
joshualitt5bf99f12015-03-13 11:47:42 -070072 }
73
joshualitt5df175e2015-11-18 13:37:54 -080074 if (!fRects->addRect(width, height, loc)) {
75 return false;
joshualittb4c507e2015-04-08 08:07:59 -070076 }
joshualitt5bf99f12015-03-13 11:47:42 -070077
jvanverthc3d706f2016-04-20 10:33:27 -070078 if (!fData) {
79 fData = reinterpret_cast<unsigned char*>(sk_calloc_throw(fBytesPerPixel * fWidth *
80 fHeight));
joshualitt5df175e2015-11-18 13:37:54 -080081 }
82 size_t rowBytes = width * fBytesPerPixel;
83 const unsigned char* imagePtr = (const unsigned char*)image;
84 // point ourselves at the right starting spot
jvanverthc3d706f2016-04-20 10:33:27 -070085 unsigned char* dataPtr = fData;
joshualitt5df175e2015-11-18 13:37:54 -080086 dataPtr += fBytesPerPixel * fWidth * loc->fY;
87 dataPtr += fBytesPerPixel * loc->fX;
Brian Osmancce3e582016-10-14 11:42:20 -040088 // copy into the data buffer, swizzling as we go if this is ARGB data
89 if (4 == fBytesPerPixel && kSkia8888_GrPixelConfig == kBGRA_8888_GrPixelConfig) {
90 for (int i = 0; i < height; ++i) {
91 SkOpts::RGBA_to_BGRA(reinterpret_cast<uint32_t*>(dataPtr), imagePtr, width);
92 dataPtr += fBytesPerPixel * fWidth;
93 imagePtr += rowBytes;
94 }
95 } else {
96 for (int i = 0; i < height; ++i) {
97 memcpy(dataPtr, imagePtr, rowBytes);
98 dataPtr += fBytesPerPixel * fWidth;
99 imagePtr += rowBytes;
100 }
joshualitt5bf99f12015-03-13 11:47:42 -0700101 }
102
joshualitt5df175e2015-11-18 13:37:54 -0800103 fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height);
robertphillips2b0536f2015-11-06 14:10:42 -0800104
joshualitt5df175e2015-11-18 13:37:54 -0800105 loc->fX += fOffset.fX;
106 loc->fY += fOffset.fY;
107 SkDEBUGCODE(fDirty = true;)
joshualitt5bf99f12015-03-13 11:47:42 -0700108
joshualitt5df175e2015-11-18 13:37:54 -0800109 return true;
110}
joshualitt5bf99f12015-03-13 11:47:42 -0700111
Brian Salomon943ed792017-10-30 09:37:55 -0400112void GrDrawOpAtlas::Plot::uploadToTexture(GrDeferredTextureUploadWritePixelsFn& writePixels,
Robert Phillipsacaa6072017-07-28 10:54:53 -0400113 GrTextureProxy* proxy) {
joshualitt5df175e2015-11-18 13:37:54 -0800114 // We should only be issuing uploads if we are in fact dirty
Robert Phillipsacaa6072017-07-28 10:54:53 -0400115 SkASSERT(fDirty && fData && proxy && proxy->priv().peekTexture());
Brian Osman39c08ac2017-07-26 09:36:09 -0400116 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
joshualitt5df175e2015-11-18 13:37:54 -0800117 size_t rowBytes = fBytesPerPixel * fWidth;
jvanverthc3d706f2016-04-20 10:33:27 -0700118 const unsigned char* dataPtr = fData;
119 dataPtr += rowBytes * fDirtyRect.fTop;
120 dataPtr += fBytesPerPixel * fDirtyRect.fLeft;
Robert Phillipsacaa6072017-07-28 10:54:53 -0400121 writePixels(proxy, fOffset.fX + fDirtyRect.fLeft, fOffset.fY + fDirtyRect.fTop,
jvanverthc3d706f2016-04-20 10:33:27 -0700122 fDirtyRect.width(), fDirtyRect.height(), fConfig, dataPtr, rowBytes);
joshualitt5df175e2015-11-18 13:37:54 -0800123 fDirtyRect.setEmpty();
124 SkDEBUGCODE(fDirty = false;)
125}
126
Brian Salomon2ee084e2016-12-16 18:59:19 -0500127void GrDrawOpAtlas::Plot::resetRects() {
joshualitt5df175e2015-11-18 13:37:54 -0800128 if (fRects) {
129 fRects->reset();
joshualitt5bf99f12015-03-13 11:47:42 -0700130 }
131
joshualitt5df175e2015-11-18 13:37:54 -0800132 fGenID++;
Jim Van Vertha950b632017-09-12 11:54:11 -0400133 fID = CreateId(fPageIndex, fPlotIndex, fGenID);
Brian Salomon943ed792017-10-30 09:37:55 -0400134 fLastUpload = GrDeferredUploadToken::AlreadyFlushedToken();
135 fLastUse = GrDeferredUploadToken::AlreadyFlushedToken();
joshualitt5df175e2015-11-18 13:37:54 -0800136
137 // zero out the plot
jvanverthc3d706f2016-04-20 10:33:27 -0700138 if (fData) {
139 sk_bzero(fData, fBytesPerPixel * fWidth * fHeight);
joshualitt5bf99f12015-03-13 11:47:42 -0700140 }
141
joshualitt5df175e2015-11-18 13:37:54 -0800142 fDirtyRect.setEmpty();
143 SkDEBUGCODE(fDirty = false;)
144}
joshualitt5bf99f12015-03-13 11:47:42 -0700145
joshualitt5bf99f12015-03-13 11:47:42 -0700146///////////////////////////////////////////////////////////////////////////////
147
Jim Van Verthd74f3f22017-08-31 16:44:08 -0400148GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, GrPixelConfig config, int width, int height,
Brian Salomon9f545bc2017-11-06 10:36:57 -0500149 int numPlotsX, int numPlotsY, AllowMultitexturing allowMultitexturing)
Robert Phillips32f28182017-02-28 16:20:03 -0500150 : fContext(context)
Jim Van Verthd74f3f22017-08-31 16:44:08 -0400151 , fPixelConfig(config)
152 , fTextureWidth(width)
153 , fTextureHeight(height)
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400154 , fAtlasGeneration(kInvalidAtlasGeneration + 1)
Brian Salomon943ed792017-10-30 09:37:55 -0400155 , fPrevFlushToken(GrDeferredUploadToken::AlreadyFlushedToken())
Brian Salomon9f545bc2017-11-06 10:36:57 -0500156 , fAllowMultitexturing(allowMultitexturing)
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400157 , fNumPages(0) {
Jim Van Verthd74f3f22017-08-31 16:44:08 -0400158 fPlotWidth = fTextureWidth / numPlotsX;
159 fPlotHeight = fTextureHeight / numPlotsY;
robertphillips2b0536f2015-11-06 14:10:42 -0800160 SkASSERT(numPlotsX * numPlotsY <= BulkUseTokenUpdater::kMaxPlots);
Jim Van Verthd74f3f22017-08-31 16:44:08 -0400161 SkASSERT(fPlotWidth * numPlotsX == fTextureWidth);
162 SkASSERT(fPlotHeight * numPlotsY == fTextureHeight);
robertphillips2b0536f2015-11-06 14:10:42 -0800163
164 SkDEBUGCODE(fNumPlots = numPlotsX * numPlotsY;)
joshualitt5bf99f12015-03-13 11:47:42 -0700165
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400166 this->createNewPage();
joshualitt5bf99f12015-03-13 11:47:42 -0700167}
168
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400169inline void GrDrawOpAtlas::processEviction(AtlasID id) {
joshualitt5bf99f12015-03-13 11:47:42 -0700170 for (int i = 0; i < fEvictionCallbacks.count(); i++) {
171 (*fEvictionCallbacks[i].fFunc)(id, fEvictionCallbacks[i].fData);
172 }
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400173 ++fAtlasGeneration;
joshualitt5bf99f12015-03-13 11:47:42 -0700174}
175
Brian Salomon29b60c92017-10-31 14:42:10 -0400176inline bool GrDrawOpAtlas::updatePlot(GrDeferredUploadTarget* target, AtlasID* id, Plot* plot) {
Jim Van Vertha950b632017-09-12 11:54:11 -0400177 int pageIdx = GetPageIndexFromID(plot->id());
178 this->makeMRU(plot, pageIdx);
joshualitt5bf99f12015-03-13 11:47:42 -0700179
180 // If our most recent upload has already occurred then we have to insert a new
181 // upload. Otherwise, we already have a scheduled upload that hasn't yet ocurred.
182 // This new update will piggy back on that previously scheduled update.
Brian Salomon29b60c92017-10-31 14:42:10 -0400183 if (plot->lastUploadToken() < target->nextTokenToFlush()) {
jvanverthc3d706f2016-04-20 10:33:27 -0700184 // With c+14 we could move sk_sp into lamba to only ref once.
Brian Salomon2ee084e2016-12-16 18:59:19 -0500185 sk_sp<Plot> plotsp(SkRef(plot));
Robert Phillips256c37b2017-03-01 14:32:46 -0500186
Robert Phillips32f28182017-02-28 16:20:03 -0500187 // MDB TODO: this is currently fine since the atlas' proxy is always pre-instantiated.
188 // Once it is deferred more care must be taken upon instantiation failure.
Jim Van Vertha950b632017-09-12 11:54:11 -0400189 if (!fProxies[pageIdx]->instantiate(fContext->resourceProvider())) {
Robert Phillips256c37b2017-03-01 14:32:46 -0500190 return false;
Robert Phillips32f28182017-02-28 16:20:03 -0500191 }
Robert Phillipsacaa6072017-07-28 10:54:53 -0400192
Jim Van Vertha950b632017-09-12 11:54:11 -0400193 GrTextureProxy* proxy = fProxies[pageIdx].get();
Robert Phillips256c37b2017-03-01 14:32:46 -0500194
Brian Salomon29b60c92017-10-31 14:42:10 -0400195 GrDeferredUploadToken lastUploadToken = target->addASAPUpload(
Brian Salomon943ed792017-10-30 09:37:55 -0400196 [plotsp, proxy](GrDeferredTextureUploadWritePixelsFn& writePixels) {
197 plotsp->uploadToTexture(writePixels, proxy);
198 });
Robert Phillips256c37b2017-03-01 14:32:46 -0500199 plot->setLastUploadToken(lastUploadToken);
joshualitt5bf99f12015-03-13 11:47:42 -0700200 }
201 *id = plot->id();
Robert Phillips256c37b2017-03-01 14:32:46 -0500202 return true;
joshualitt5bf99f12015-03-13 11:47:42 -0700203}
204
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400205// Number of atlas-related flushes beyond which we consider a plot to no longer be in use.
206//
207// This value is somewhat arbitrary -- the idea is to keep it low enough that
208// a page with unused plots will get removed reasonably quickly, but allow it
209// to hang around for a bit in case it's needed. The assumption is that flushes
210// are rare; i.e., we are not continually refreshing the frame.
Derek Sollenberger90196cc2017-10-09 15:00:33 -0400211static constexpr auto kRecentlyUsedCount = 256;
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400212
Brian Salomon29b60c92017-10-31 14:42:10 -0400213bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDeferredUploadTarget* target, int width, int height,
Brian Salomon2ee084e2016-12-16 18:59:19 -0500214 const void* image, SkIPoint16* loc) {
bsalomon6d6b6ad2016-07-13 14:45:28 -0700215 if (width > fPlotWidth || height > fPlotHeight) {
216 return false;
217 }
joshualitt5bf99f12015-03-13 11:47:42 -0700218
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400219 // Look through each page to see if we can upload without having to flush
220 // We prioritize this upload to the first pages, not the most recently used, to make it easier
221 // to remove unused pages in reverse page order.
222 for (unsigned int pageIdx = 0; pageIdx < fNumPages; ++pageIdx) {
223 SkASSERT(fProxies[pageIdx]);
224 // look through all allocated plots for one we can share, in Most Recently Refed order
225 PlotList::Iter plotIter;
226 plotIter.init(fPages[pageIdx].fPlotList, PlotList::Iter::kHead_IterStart);
227 Plot* plot;
228 while ((plot = plotIter.get())) {
229 SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp());
230 if (plot->addSubImage(width, height, image, loc)) {
231 return this->updatePlot(target, id, plot);
232 }
233 plotIter.next();
234 }
Jim Van Verth712fe732017-09-25 16:53:49 -0400235 }
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400236
Jim Van Verth712fe732017-09-25 16:53:49 -0400237 // 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 -0400238 // flushed to the gpu if we're at max page allocation, or if the plot has aged out otherwise.
239 // We wait until we've grown to the full number of pages to begin evicting already flushed
240 // plots so that we can maximize the opportunity for reuse.
Jim Van Verth712fe732017-09-25 16:53:49 -0400241 // As before we prioritize this upload to the first pages, not the most recently used.
242 for (unsigned int pageIdx = 0; pageIdx < fNumPages; ++pageIdx) {
243 Plot* plot = fPages[pageIdx].fPlotList.tail();
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400244 SkASSERT(plot);
Brian Salomon9f545bc2017-11-06 10:36:57 -0500245 if ((fNumPages == this->maxPages() && plot->lastUseToken() < target->nextTokenToFlush()) ||
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400246 plot->flushesSinceLastUsed() >= kRecentlyUsedCount) {
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400247 this->processEvictionAndResetRects(plot);
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400248 SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp());
249 SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc);
250 SkASSERT(verify);
251 if (!this->updatePlot(target, id, plot)) {
252 return false;
253 }
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400254 return true;
255 }
256 }
257
258 // If the simple cases fail, try to create a new page and add to it
259 if (this->createNewPage()) {
260 unsigned int pageIdx = fNumPages-1;
261 SkASSERT(fProxies[pageIdx]);
262 Plot* plot = fPages[pageIdx].fPlotList.head();
Jim Van Vertha950b632017-09-12 11:54:11 -0400263 SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp());
robertphillips2b0536f2015-11-06 14:10:42 -0800264 if (plot->addSubImage(width, height, image, loc)) {
Robert Phillips256c37b2017-03-01 14:32:46 -0500265 return this->updatePlot(target, id, plot);
joshualitt5bf99f12015-03-13 11:47:42 -0700266 }
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400267
268 // we shouldn't get here -- if so, something has gone terribly wrong
269 SkASSERT(false);
270 return false;
joshualitt5bf99f12015-03-13 11:47:42 -0700271 }
272
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400273 // Try to find a plot that we can perform an inline upload to.
274 // We prioritize this upload in reverse order of pages to counterbalance the order above.
275 Plot* plot = nullptr;
276 for (int pageIdx = (int)(fNumPages-1); pageIdx >= 0; --pageIdx) {
277 Plot* currentPlot = fPages[pageIdx].fPlotList.tail();
278 if (currentPlot->lastUseToken() != target->nextDrawToken()) {
279 plot = currentPlot;
280 break;
Robert Phillips256c37b2017-03-01 14:32:46 -0500281 }
joshualitt5bf99f12015-03-13 11:47:42 -0700282 }
283
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400284 // If we can't find a plot that is not used in a draw currently being prepared by an op, then
285 // we have to fail. This gives the op a chance to enqueue the draw, and call back into this
286 // function. When that draw is enqueued, the draw token advances, and the subsequent call will
287 // continue past this branch and prepare an inline upload that will occur after the enqueued
288 //draw which references the plot's pre-upload content.
289 if (!plot) {
joshualitt5bf99f12015-03-13 11:47:42 -0700290 return false;
291 }
292
joshualitt5bf99f12015-03-13 11:47:42 -0700293 this->processEviction(plot->id());
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400294 int pageIdx = GetPageIndexFromID(plot->id());
Jim Van Vertha950b632017-09-12 11:54:11 -0400295 fPages[pageIdx].fPlotList.remove(plot);
296 sk_sp<Plot>& newPlot = fPages[pageIdx].fPlotArray[plot->index()];
robertphillips2b0536f2015-11-06 14:10:42 -0800297 newPlot.reset(plot->clone());
joshualitt5bf99f12015-03-13 11:47:42 -0700298
Jim Van Vertha950b632017-09-12 11:54:11 -0400299 fPages[pageIdx].fPlotList.addToHead(newPlot.get());
300 SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == newPlot->bpp());
robertphillips2b0536f2015-11-06 14:10:42 -0800301 SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc);
joshualitt5bf99f12015-03-13 11:47:42 -0700302 SkASSERT(verify);
robertphillips2b0536f2015-11-06 14:10:42 -0800303
robertphillips1f0e3502015-11-10 10:19:50 -0800304 // Note that this plot will be uploaded inline with the draws whereas the
Brian Salomon29b60c92017-10-31 14:42:10 -0400305 // one it displaced most likely was uploaded ASAP.
Brian Salomon2ee084e2016-12-16 18:59:19 -0500306 // With c+14 we could move sk_sp into lambda to only ref once.
307 sk_sp<Plot> plotsp(SkRef(newPlot.get()));
Robert Phillips32f28182017-02-28 16:20:03 -0500308 // MDB TODO: this is currently fine since the atlas' proxy is always pre-instantiated.
309 // Once it is deferred more care must be taken upon instantiation failure.
Jim Van Vertha950b632017-09-12 11:54:11 -0400310 if (!fProxies[pageIdx]->instantiate(fContext->resourceProvider())) {
Robert Phillips256c37b2017-03-01 14:32:46 -0500311 return false;
Robert Phillips32f28182017-02-28 16:20:03 -0500312 }
Jim Van Vertha950b632017-09-12 11:54:11 -0400313 GrTextureProxy* proxy = fProxies[pageIdx].get();
bsalomon342bfc22016-04-01 06:06:20 -0700314
Brian Salomon943ed792017-10-30 09:37:55 -0400315 GrDeferredUploadToken lastUploadToken = target->addInlineUpload(
316 [plotsp, proxy](GrDeferredTextureUploadWritePixelsFn& writePixels) {
317 plotsp->uploadToTexture(writePixels, proxy);
318 });
Robert Phillips256c37b2017-03-01 14:32:46 -0500319 newPlot->setLastUploadToken(lastUploadToken);
320
joshualitt5bf99f12015-03-13 11:47:42 -0700321 *id = newPlot->id();
robertphillips2b0536f2015-11-06 14:10:42 -0800322
joshualitt5bf99f12015-03-13 11:47:42 -0700323 return true;
324}
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400325
Brian Salomon943ed792017-10-30 09:37:55 -0400326void GrDrawOpAtlas::compact(GrDeferredUploadToken startTokenForNextFlush) {
Jim Van Verth106b5c42017-09-26 12:45:29 -0400327 if (fNumPages <= 1) {
328 fPrevFlushToken = startTokenForNextFlush;
329 return;
330 }
331
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400332 // For all plots, reset number of flushes since used if used this frame.
Jim Van Verth106b5c42017-09-26 12:45:29 -0400333 PlotList::Iter plotIter;
Jim Van Verth106b5c42017-09-26 12:45:29 -0400334 bool atlasUsedThisFlush = false;
335 for (uint32_t pageIndex = 0; pageIndex < fNumPages; ++pageIndex) {
336 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
337 while (Plot* plot = plotIter.get()) {
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400338 // Reset number of flushes since used
Jim Van Verth106b5c42017-09-26 12:45:29 -0400339 if (plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
340 plot->resetFlushesSinceLastUsed();
341 atlasUsedThisFlush = true;
Jim Van Verth106b5c42017-09-26 12:45:29 -0400342 }
343
344 plotIter.next();
345 }
346 }
347
348 // We only try to compact if the atlas was used in the recently completed flush.
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400349 // This is to handle the case where a lot of text or path rendering has occurred but then just
350 // a blinking cursor is drawn.
Jim Van Verth106b5c42017-09-26 12:45:29 -0400351 // TODO: consider if we should also do this if it's been a long time since the last atlas use
352 if (atlasUsedThisFlush) {
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400353 int availablePlots = 0;
354 uint32_t lastPageIndex = fNumPages - 1;
355
356 // For all plots but the last one, update number of flushes since used, and check to see
357 // if there are any in the first pages that the last page can safely upload to.
358 for (uint32_t pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex) {
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400359#ifdef DUMP_ATLAS_DATA
360 if (gDumpAtlasData) {
361 SkDebugf("page %d: ", pageIndex);
362 }
363#endif
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400364 plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
365 while (Plot* plot = plotIter.get()) {
366 // Update number of flushes since plot was last used
367 // We only increment the 'sinceLastUsed' count for flushes where the atlas was used
368 // to avoid deleting everything when we return to text drawing in the blinking
369 // cursor case
370 if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
371 plot->incFlushesSinceLastUsed();
372 }
373
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400374#ifdef DUMP_ATLAS_DATA
375 if (gDumpAtlasData) {
376 SkDebugf("%d ", plot->flushesSinceLastUsed());
377 }
378#endif
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400379 // Count plots we can potentially upload to in all pages except the last one
380 // (the potential compactee).
381 if (plot->flushesSinceLastUsed() > kRecentlyUsedCount) {
382 ++availablePlots;
383 }
384
385 plotIter.next();
386 }
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400387#ifdef DUMP_ATLAS_DATA
388 if (gDumpAtlasData) {
389 SkDebugf("\n");
390 }
391#endif
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400392 }
393
Jim Van Verth106b5c42017-09-26 12:45:29 -0400394 // Count recently used plots in the last page and evict them if there's available space
395 // in earlier pages. Since we prioritize uploading to the first pages, this will eventually
396 // clear out usage of this page unless we have a large need.
397 plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
398 int usedPlots = 0;
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400399#ifdef DUMP_ATLAS_DATA
400 if (gDumpAtlasData) {
401 SkDebugf("page %d: ", lastPageIndex);
402 }
403#endif
Jim Van Verth106b5c42017-09-26 12:45:29 -0400404 while (Plot* plot = plotIter.get()) {
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400405 // Update number of flushes since plot was last used
406 if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
407 plot->incFlushesSinceLastUsed();
408 }
409
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400410#ifdef DUMP_ATLAS_DATA
411 if (gDumpAtlasData) {
412 SkDebugf("%d ", plot->flushesSinceLastUsed());
413 }
414#endif
Jim Van Verth106b5c42017-09-26 12:45:29 -0400415 // If this plot was used recently
416 if (plot->flushesSinceLastUsed() <= kRecentlyUsedCount) {
417 usedPlots++;
418 // see if there's room in an earlier page and if so evict.
419 // We need to be somewhat harsh here so that one plot that is consistently in use
420 // doesn't end up locking the page in memory.
421 if (availablePlots) {
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400422 this->processEvictionAndResetRects(plot);
Jim Van Verth106b5c42017-09-26 12:45:29 -0400423 --availablePlots;
424 }
Brian Salomon943ed792017-10-30 09:37:55 -0400425 } else if (plot->lastUseToken() != GrDeferredUploadToken::AlreadyFlushedToken()) {
Jim Van Verth106b5c42017-09-26 12:45:29 -0400426 // otherwise if aged out just evict it.
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400427 this->processEvictionAndResetRects(plot);
Jim Van Verth106b5c42017-09-26 12:45:29 -0400428 }
429 plotIter.next();
430 }
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400431#ifdef DUMP_ATLAS_DATA
432 if (gDumpAtlasData) {
433 SkDebugf("\n");
434 }
435#endif
Jim Van Verth106b5c42017-09-26 12:45:29 -0400436 // If none of the plots in the last page have been used recently, delete it.
437 if (!usedPlots) {
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400438#ifdef DUMP_ATLAS_DATA
439 if (gDumpAtlasData) {
440 SkDebugf("delete %d\n", fNumPages-1);
441 }
442#endif
Jim Van Verth106b5c42017-09-26 12:45:29 -0400443 this->deleteLastPage();
444 }
445 }
446
447 fPrevFlushToken = startTokenForNextFlush;
448}
449
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400450bool GrDrawOpAtlas::createNewPage() {
Brian Salomon9f545bc2017-11-06 10:36:57 -0500451 if (fNumPages == this->maxPages()) {
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400452 return false;
453 }
454
455 GrSurfaceDesc desc;
456 desc.fFlags = kNone_GrSurfaceFlags;
457 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
458 desc.fWidth = fTextureWidth;
459 desc.fHeight = fTextureHeight;
460 desc.fConfig = fPixelConfig;
461
462 // We don't want to flush the context so we claim we're in the middle of flushing so as to
463 // guarantee we do not recieve a texture with pending IO
464 // TODO: Determine how to avoid having to do this. (https://bug.skia.org/4156)
465 static const uint32_t kFlags = GrResourceProvider::kNoPendingIO_Flag;
466 sk_sp<GrTexture> texture(fContext->resourceProvider()->createApproxTexture(desc, kFlags));
467 if (texture) {
468 // MDB TODO: for now, wrap an instantiated texture. Having the deferred instantiation
469 // possess the correct properties (e.g., no pendingIO) should fall out of the system but
470 // should receive special attention.
471 // Note: When switching over to the deferred proxy, use the kExact flag to create
472 // the atlas and assert that the width & height are powers of 2.
473 fProxies[fNumPages] = GrSurfaceProxy::MakeWrapped(std::move(texture),
474 kTopLeft_GrSurfaceOrigin);
475 }
476 if (!fProxies[fNumPages]) {
477 return false;
478 }
479
480 int numPlotsX = fTextureWidth/fPlotWidth;
481 int numPlotsY = fTextureHeight/fPlotHeight;
482
483 // set up allocated plots
484 fPages[fNumPages].fPlotArray.reset(new sk_sp<Plot>[ numPlotsX * numPlotsY ]);
485
486 sk_sp<Plot>* currPlot = fPages[fNumPages].fPlotArray.get();
487 for (int y = numPlotsY - 1, r = 0; y >= 0; --y, ++r) {
488 for (int x = numPlotsX - 1, c = 0; x >= 0; --x, ++c) {
489 uint32_t plotIndex = r * numPlotsX + c;
490 currPlot->reset(new Plot(fNumPages, plotIndex, 1, x, y, fPlotWidth, fPlotHeight,
491 fPixelConfig));
492
493 // build LRU list
494 fPages[fNumPages].fPlotList.addToHead(currPlot->get());
495 ++currPlot;
496 }
497 }
498
Jim Van Verthc3269ae2017-09-28 15:04:00 -0400499#ifdef DUMP_ATLAS_DATA
500 if (gDumpAtlasData) {
501 SkDebugf("created %d\n", fNumPages);
502 }
503#endif
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400504 fNumPages++;
505 return true;
506}
Jim Van Verth106b5c42017-09-26 12:45:29 -0400507
508inline void GrDrawOpAtlas::deleteLastPage() {
509 uint32_t lastPageIndex = fNumPages - 1;
510 // clean out the plots
511 fPages[lastPageIndex].fPlotList.reset();
512 fPages[lastPageIndex].fPlotArray.reset(nullptr);
513 // remove ref to texture proxy
514 fProxies[lastPageIndex].reset(nullptr);
515 --fNumPages;
516}