blob: 1a1452caac0632aefda4cde1f17fefaa59fdc5da [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
Robert Phillips256c37b2017-03-01 14:32:46 -050017std::unique_ptr<GrDrawOpAtlas> GrDrawOpAtlas::Make(GrContext* ctx, GrPixelConfig config,
18 int width, int height,
19 int numPlotsX, int numPlotsY,
20 GrDrawOpAtlas::EvictionFunc func,
21 void* data) {
Robert Phillips256c37b2017-03-01 14:32:46 -050022 std::unique_ptr<GrDrawOpAtlas> atlas(
Jim Van Verthd74f3f22017-08-31 16:44:08 -040023 new GrDrawOpAtlas(ctx, config, width, height, numPlotsX, numPlotsY));
Jim Van Vertha950b632017-09-12 11:54:11 -040024 if (!atlas->getProxies()[0]) {
Jim Van Verthd74f3f22017-08-31 16:44:08 -040025 return nullptr;
26 }
27
Robert Phillips256c37b2017-03-01 14:32:46 -050028 atlas->registerEvictionCallback(func, data);
29 return atlas;
30}
31
Jim Van Verthc3269ae2017-09-28 15:04:00 -040032#ifdef DUMP_ATLAS_DATA
33static bool gDumpAtlasData = false;
34#endif
Robert Phillips256c37b2017-03-01 14:32:46 -050035
joshualitt5df175e2015-11-18 13:37:54 -080036////////////////////////////////////////////////////////////////////////////////
joshualitt5bf99f12015-03-13 11:47:42 -070037
Jim Van Vertha950b632017-09-12 11:54:11 -040038GrDrawOpAtlas::Plot::Plot(int pageIndex, int plotIndex, uint64_t genID, int offX, int offY,
39 int width, int height, GrPixelConfig config)
Brian Salomon943ed792017-10-30 09:37:55 -040040 : fLastUpload(GrDeferredUploadToken::AlreadyFlushedToken())
41 , fLastUse(GrDeferredUploadToken::AlreadyFlushedToken())
Jim Van Verth106b5c42017-09-26 12:45:29 -040042 , fFlushesSinceLastUse(0)
Jim Van Vertha950b632017-09-12 11:54:11 -040043 , fPageIndex(pageIndex)
44 , fPlotIndex(plotIndex)
Brian Salomon2ee084e2016-12-16 18:59:19 -050045 , fGenID(genID)
Jim Van Vertha950b632017-09-12 11:54:11 -040046 , fID(CreateId(fPageIndex, fPlotIndex, fGenID))
Brian Salomon2ee084e2016-12-16 18:59:19 -050047 , fData(nullptr)
48 , fWidth(width)
49 , fHeight(height)
50 , fX(offX)
51 , fY(offY)
52 , fRects(nullptr)
53 , fOffset(SkIPoint16::Make(fX * fWidth, fY * fHeight))
54 , fConfig(config)
55 , fBytesPerPixel(GrBytesPerPixel(config))
joshualitt5df175e2015-11-18 13:37:54 -080056#ifdef SK_DEBUG
Brian Salomon2ee084e2016-12-16 18:59:19 -050057 , fDirty(false)
joshualitt5df175e2015-11-18 13:37:54 -080058#endif
59{
60 fDirtyRect.setEmpty();
61}
joshualitt5bf99f12015-03-13 11:47:42 -070062
Brian Salomon2ee084e2016-12-16 18:59:19 -050063GrDrawOpAtlas::Plot::~Plot() {
jvanverthc3d706f2016-04-20 10:33:27 -070064 sk_free(fData);
joshualitt5df175e2015-11-18 13:37:54 -080065 delete fRects;
66}
joshualitt5bf99f12015-03-13 11:47:42 -070067
Brian Salomon2ee084e2016-12-16 18:59:19 -050068bool GrDrawOpAtlas::Plot::addSubImage(int width, int height, const void* image, SkIPoint16* loc) {
joshualitt5df175e2015-11-18 13:37:54 -080069 SkASSERT(width <= fWidth && height <= fHeight);
joshualitt5bf99f12015-03-13 11:47:42 -070070
joshualitt5df175e2015-11-18 13:37:54 -080071 if (!fRects) {
72 fRects = GrRectanizer::Factory(fWidth, fHeight);
joshualitt5bf99f12015-03-13 11:47:42 -070073 }
74
joshualitt5df175e2015-11-18 13:37:54 -080075 if (!fRects->addRect(width, height, loc)) {
76 return false;
joshualittb4c507e2015-04-08 08:07:59 -070077 }
joshualitt5bf99f12015-03-13 11:47:42 -070078
jvanverthc3d706f2016-04-20 10:33:27 -070079 if (!fData) {
80 fData = reinterpret_cast<unsigned char*>(sk_calloc_throw(fBytesPerPixel * fWidth *
81 fHeight));
joshualitt5df175e2015-11-18 13:37:54 -080082 }
83 size_t rowBytes = width * fBytesPerPixel;
84 const unsigned char* imagePtr = (const unsigned char*)image;
85 // point ourselves at the right starting spot
jvanverthc3d706f2016-04-20 10:33:27 -070086 unsigned char* dataPtr = fData;
joshualitt5df175e2015-11-18 13:37:54 -080087 dataPtr += fBytesPerPixel * fWidth * loc->fY;
88 dataPtr += fBytesPerPixel * loc->fX;
Brian Osmancce3e582016-10-14 11:42:20 -040089 // copy into the data buffer, swizzling as we go if this is ARGB data
90 if (4 == fBytesPerPixel && kSkia8888_GrPixelConfig == kBGRA_8888_GrPixelConfig) {
91 for (int i = 0; i < height; ++i) {
92 SkOpts::RGBA_to_BGRA(reinterpret_cast<uint32_t*>(dataPtr), imagePtr, width);
93 dataPtr += fBytesPerPixel * fWidth;
94 imagePtr += rowBytes;
95 }
96 } else {
97 for (int i = 0; i < height; ++i) {
98 memcpy(dataPtr, imagePtr, rowBytes);
99 dataPtr += fBytesPerPixel * fWidth;
100 imagePtr += rowBytes;
101 }
joshualitt5bf99f12015-03-13 11:47:42 -0700102 }
103
joshualitt5df175e2015-11-18 13:37:54 -0800104 fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height);
robertphillips2b0536f2015-11-06 14:10:42 -0800105
joshualitt5df175e2015-11-18 13:37:54 -0800106 loc->fX += fOffset.fX;
107 loc->fY += fOffset.fY;
108 SkDEBUGCODE(fDirty = true;)
joshualitt5bf99f12015-03-13 11:47:42 -0700109
joshualitt5df175e2015-11-18 13:37:54 -0800110 return true;
111}
joshualitt5bf99f12015-03-13 11:47:42 -0700112
Brian Salomon943ed792017-10-30 09:37:55 -0400113void GrDrawOpAtlas::Plot::uploadToTexture(GrDeferredTextureUploadWritePixelsFn& writePixels,
Robert Phillipsacaa6072017-07-28 10:54:53 -0400114 GrTextureProxy* proxy) {
joshualitt5df175e2015-11-18 13:37:54 -0800115 // We should only be issuing uploads if we are in fact dirty
Robert Phillipsacaa6072017-07-28 10:54:53 -0400116 SkASSERT(fDirty && fData && proxy && proxy->priv().peekTexture());
Brian Osman39c08ac2017-07-26 09:36:09 -0400117 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
joshualitt5df175e2015-11-18 13:37:54 -0800118 size_t rowBytes = fBytesPerPixel * fWidth;
jvanverthc3d706f2016-04-20 10:33:27 -0700119 const unsigned char* dataPtr = fData;
120 dataPtr += rowBytes * fDirtyRect.fTop;
121 dataPtr += fBytesPerPixel * fDirtyRect.fLeft;
Robert Phillipsacaa6072017-07-28 10:54:53 -0400122 writePixels(proxy, fOffset.fX + fDirtyRect.fLeft, fOffset.fY + fDirtyRect.fTop,
jvanverthc3d706f2016-04-20 10:33:27 -0700123 fDirtyRect.width(), fDirtyRect.height(), fConfig, dataPtr, rowBytes);
joshualitt5df175e2015-11-18 13:37:54 -0800124 fDirtyRect.setEmpty();
125 SkDEBUGCODE(fDirty = false;)
126}
127
Brian Salomon2ee084e2016-12-16 18:59:19 -0500128void GrDrawOpAtlas::Plot::resetRects() {
joshualitt5df175e2015-11-18 13:37:54 -0800129 if (fRects) {
130 fRects->reset();
joshualitt5bf99f12015-03-13 11:47:42 -0700131 }
132
joshualitt5df175e2015-11-18 13:37:54 -0800133 fGenID++;
Jim Van Vertha950b632017-09-12 11:54:11 -0400134 fID = CreateId(fPageIndex, fPlotIndex, fGenID);
Brian Salomon943ed792017-10-30 09:37:55 -0400135 fLastUpload = GrDeferredUploadToken::AlreadyFlushedToken();
136 fLastUse = GrDeferredUploadToken::AlreadyFlushedToken();
joshualitt5df175e2015-11-18 13:37:54 -0800137
138 // zero out the plot
jvanverthc3d706f2016-04-20 10:33:27 -0700139 if (fData) {
140 sk_bzero(fData, fBytesPerPixel * fWidth * fHeight);
joshualitt5bf99f12015-03-13 11:47:42 -0700141 }
142
joshualitt5df175e2015-11-18 13:37:54 -0800143 fDirtyRect.setEmpty();
144 SkDEBUGCODE(fDirty = false;)
145}
joshualitt5bf99f12015-03-13 11:47:42 -0700146
joshualitt5bf99f12015-03-13 11:47:42 -0700147///////////////////////////////////////////////////////////////////////////////
148
Jim Van Verthd74f3f22017-08-31 16:44:08 -0400149GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, GrPixelConfig config, int width, int height,
Robert Phillips32f28182017-02-28 16:20:03 -0500150 int numPlotsX, int numPlotsY)
151 : fContext(context)
Jim Van Verthd74f3f22017-08-31 16:44:08 -0400152 , fPixelConfig(config)
153 , fTextureWidth(width)
154 , fTextureHeight(height)
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400155 , fAtlasGeneration(kInvalidAtlasGeneration + 1)
Brian Salomon943ed792017-10-30 09:37:55 -0400156 , fPrevFlushToken(GrDeferredUploadToken::AlreadyFlushedToken())
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
Robert Phillips256c37b2017-03-01 14:32:46 -0500176inline bool GrDrawOpAtlas::updatePlot(GrDrawOp::Target* 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.
bsalomon342bfc22016-04-01 06:06:20 -0700183 if (target->hasDrawBeenFlushed(plot->lastUploadToken())) {
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 Salomon943ed792017-10-30 09:37:55 -0400195 GrDeferredUploadToken lastUploadToken = target->addAsapUpload(
196 [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 Salomon2ee084e2016-12-16 18:59:19 -0500213bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDrawOp::Target* target, int width, int height,
214 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);
Jim Van Verth62ea0cd2017-09-27 12:59:45 -0400245 if ((fNumPages == kMaxPages && target->hasDrawBeenFlushed(plot->lastUseToken())) ||
246 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
305 // 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() {
451 if (fNumPages == kMaxPages) {
452 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}