GrDrawOpAtlas.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. /*
  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. #include "src/gpu/GrDrawOpAtlas.h"
  8. #include "include/gpu/GrContext.h"
  9. #include "include/gpu/GrTexture.h"
  10. #include "src/gpu/GrContextPriv.h"
  11. #include "src/gpu/GrOnFlushResourceProvider.h"
  12. #include "src/gpu/GrOpFlushState.h"
  13. #include "src/gpu/GrProxyProvider.h"
  14. #include "src/gpu/GrRectanizer.h"
  15. #include "src/gpu/GrResourceProvider.h"
  16. #include "src/gpu/GrSurfaceProxyPriv.h"
  17. #include "src/gpu/GrTracing.h"
  18. // When proxy allocation is deferred until flush time the proxies acting as atlases require
  19. // special handling. This is because the usage that can be determined from the ops themselves
  20. // isn't sufficient. Independent of the ops there will be ASAP and inline uploads to the
  21. // atlases. Extending the usage interval of any op that uses an atlas to the start of the
  22. // flush (as is done for proxies that are used for sw-generated masks) also won't work because
  23. // the atlas persists even beyond the last use in an op - for a given flush. Given this, atlases
  24. // must explicitly manage the lifetime of their backing proxies via the onFlushCallback system
  25. // (which calls this method).
  26. void GrDrawOpAtlas::instantiate(GrOnFlushResourceProvider* onFlushResourceProvider) {
  27. for (uint32_t i = 0; i < fNumActivePages; ++i) {
  28. // All the atlas pages are now instantiated at flush time in the activeNewPage method.
  29. SkASSERT(fProxies[i] && fProxies[i]->isInstantiated());
  30. }
  31. }
  32. std::unique_ptr<GrDrawOpAtlas> GrDrawOpAtlas::Make(GrProxyProvider* proxyProvider,
  33. const GrBackendFormat& format,
  34. GrColorType colorType, int width,
  35. int height, int plotWidth, int plotHeight,
  36. AllowMultitexturing allowMultitexturing,
  37. GrDrawOpAtlas::EvictionFunc func, void* data) {
  38. std::unique_ptr<GrDrawOpAtlas> atlas(new GrDrawOpAtlas(proxyProvider, format, colorType, width,
  39. height, plotWidth, plotHeight,
  40. allowMultitexturing));
  41. if (!atlas->getProxies()[0]) {
  42. return nullptr;
  43. }
  44. atlas->registerEvictionCallback(func, data);
  45. return atlas;
  46. }
  47. #ifdef DUMP_ATLAS_DATA
  48. static bool gDumpAtlasData = false;
  49. #endif
  50. ////////////////////////////////////////////////////////////////////////////////
  51. GrDrawOpAtlas::Plot::Plot(int pageIndex, int plotIndex, uint64_t genID, int offX, int offY,
  52. int width, int height, GrColorType colorType)
  53. : fLastUpload(GrDeferredUploadToken::AlreadyFlushedToken())
  54. , fLastUse(GrDeferredUploadToken::AlreadyFlushedToken())
  55. , fFlushesSinceLastUse(0)
  56. , fPageIndex(pageIndex)
  57. , fPlotIndex(plotIndex)
  58. , fGenID(genID)
  59. , fID(CreateId(fPageIndex, fPlotIndex, fGenID))
  60. , fData(nullptr)
  61. , fWidth(width)
  62. , fHeight(height)
  63. , fX(offX)
  64. , fY(offY)
  65. , fRects(nullptr)
  66. , fOffset(SkIPoint16::Make(fX * fWidth, fY * fHeight))
  67. , fColorType(colorType)
  68. , fBytesPerPixel(GrColorTypeBytesPerPixel(colorType))
  69. #ifdef SK_DEBUG
  70. , fDirty(false)
  71. #endif
  72. {
  73. // We expect the allocated dimensions to be a multiple of 4 bytes
  74. SkASSERT(((width*fBytesPerPixel) & 0x3) == 0);
  75. // The padding for faster uploads only works for 1, 2 and 4 byte texels
  76. SkASSERT(fBytesPerPixel != 3 && fBytesPerPixel <= 4);
  77. fDirtyRect.setEmpty();
  78. }
  79. GrDrawOpAtlas::Plot::~Plot() {
  80. sk_free(fData);
  81. delete fRects;
  82. }
  83. bool GrDrawOpAtlas::Plot::addSubImage(int width, int height, const void* image, SkIPoint16* loc) {
  84. SkASSERT(width <= fWidth && height <= fHeight);
  85. if (!fRects) {
  86. fRects = GrRectanizer::Factory(fWidth, fHeight);
  87. }
  88. if (!fRects->addRect(width, height, loc)) {
  89. return false;
  90. }
  91. if (!fData) {
  92. fData = reinterpret_cast<unsigned char*>(sk_calloc_throw(fBytesPerPixel * fWidth *
  93. fHeight));
  94. }
  95. size_t rowBytes = width * fBytesPerPixel;
  96. const unsigned char* imagePtr = (const unsigned char*)image;
  97. // point ourselves at the right starting spot
  98. unsigned char* dataPtr = fData;
  99. dataPtr += fBytesPerPixel * fWidth * loc->fY;
  100. dataPtr += fBytesPerPixel * loc->fX;
  101. // copy into the data buffer, swizzling as we go if this is ARGB data
  102. if (4 == fBytesPerPixel && kSkia8888_GrPixelConfig == kBGRA_8888_GrPixelConfig) {
  103. for (int i = 0; i < height; ++i) {
  104. SkOpts::RGBA_to_BGRA((uint32_t*)dataPtr, (const uint32_t*)imagePtr, width);
  105. dataPtr += fBytesPerPixel * fWidth;
  106. imagePtr += rowBytes;
  107. }
  108. } else {
  109. for (int i = 0; i < height; ++i) {
  110. memcpy(dataPtr, imagePtr, rowBytes);
  111. dataPtr += fBytesPerPixel * fWidth;
  112. imagePtr += rowBytes;
  113. }
  114. }
  115. fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height);
  116. loc->fX += fOffset.fX;
  117. loc->fY += fOffset.fY;
  118. SkDEBUGCODE(fDirty = true;)
  119. return true;
  120. }
  121. void GrDrawOpAtlas::Plot::uploadToTexture(GrDeferredTextureUploadWritePixelsFn& writePixels,
  122. GrTextureProxy* proxy) {
  123. // We should only be issuing uploads if we are in fact dirty
  124. SkASSERT(fDirty && fData && proxy && proxy->peekTexture());
  125. TRACE_EVENT0("skia.gpu", TRACE_FUNC);
  126. size_t rowBytes = fBytesPerPixel * fWidth;
  127. const unsigned char* dataPtr = fData;
  128. // Clamp to 4-byte aligned boundaries
  129. unsigned int clearBits = 0x3 / fBytesPerPixel;
  130. fDirtyRect.fLeft &= ~clearBits;
  131. fDirtyRect.fRight += clearBits;
  132. fDirtyRect.fRight &= ~clearBits;
  133. SkASSERT(fDirtyRect.fRight <= fWidth);
  134. // Set up dataPtr
  135. dataPtr += rowBytes * fDirtyRect.fTop;
  136. dataPtr += fBytesPerPixel * fDirtyRect.fLeft;
  137. writePixels(proxy, fOffset.fX + fDirtyRect.fLeft, fOffset.fY + fDirtyRect.fTop,
  138. fDirtyRect.width(), fDirtyRect.height(), fColorType, dataPtr, rowBytes);
  139. fDirtyRect.setEmpty();
  140. SkDEBUGCODE(fDirty = false;)
  141. }
  142. void GrDrawOpAtlas::Plot::resetRects() {
  143. if (fRects) {
  144. fRects->reset();
  145. }
  146. fGenID++;
  147. fID = CreateId(fPageIndex, fPlotIndex, fGenID);
  148. fLastUpload = GrDeferredUploadToken::AlreadyFlushedToken();
  149. fLastUse = GrDeferredUploadToken::AlreadyFlushedToken();
  150. // zero out the plot
  151. if (fData) {
  152. sk_bzero(fData, fBytesPerPixel * fWidth * fHeight);
  153. }
  154. fDirtyRect.setEmpty();
  155. SkDEBUGCODE(fDirty = false;)
  156. }
  157. ///////////////////////////////////////////////////////////////////////////////
  158. GrDrawOpAtlas::GrDrawOpAtlas(GrProxyProvider* proxyProvider, const GrBackendFormat& format,
  159. GrColorType colorType, int width, int height,
  160. int plotWidth, int plotHeight, AllowMultitexturing allowMultitexturing)
  161. : fFormat(format)
  162. , fColorType(colorType)
  163. , fTextureWidth(width)
  164. , fTextureHeight(height)
  165. , fPlotWidth(plotWidth)
  166. , fPlotHeight(plotHeight)
  167. , fAtlasGeneration(kInvalidAtlasGeneration + 1)
  168. , fPrevFlushToken(GrDeferredUploadToken::AlreadyFlushedToken())
  169. , fMaxPages(AllowMultitexturing::kYes == allowMultitexturing ? kMaxMultitexturePages : 1)
  170. , fNumActivePages(0) {
  171. int numPlotsX = width/plotWidth;
  172. int numPlotsY = height/plotHeight;
  173. SkASSERT(numPlotsX * numPlotsY <= GrDrawOpAtlas::kMaxPlots);
  174. SkASSERT(fPlotWidth * numPlotsX == fTextureWidth);
  175. SkASSERT(fPlotHeight * numPlotsY == fTextureHeight);
  176. fNumPlots = numPlotsX * numPlotsY;
  177. this->createPages(proxyProvider);
  178. }
  179. inline void GrDrawOpAtlas::processEviction(AtlasID id) {
  180. for (int i = 0; i < fEvictionCallbacks.count(); i++) {
  181. (*fEvictionCallbacks[i].fFunc)(id, fEvictionCallbacks[i].fData);
  182. }
  183. ++fAtlasGeneration;
  184. }
  185. inline bool GrDrawOpAtlas::updatePlot(GrDeferredUploadTarget* target, AtlasID* id, Plot* plot) {
  186. int pageIdx = GetPageIndexFromID(plot->id());
  187. this->makeMRU(plot, pageIdx);
  188. // If our most recent upload has already occurred then we have to insert a new
  189. // upload. Otherwise, we already have a scheduled upload that hasn't yet ocurred.
  190. // This new update will piggy back on that previously scheduled update.
  191. if (plot->lastUploadToken() < target->tokenTracker()->nextTokenToFlush()) {
  192. // With c+14 we could move sk_sp into lamba to only ref once.
  193. sk_sp<Plot> plotsp(SkRef(plot));
  194. GrTextureProxy* proxy = fProxies[pageIdx].get();
  195. SkASSERT(proxy->isInstantiated()); // This is occurring at flush time
  196. GrDeferredUploadToken lastUploadToken = target->addASAPUpload(
  197. [plotsp, proxy](GrDeferredTextureUploadWritePixelsFn& writePixels) {
  198. plotsp->uploadToTexture(writePixels, proxy);
  199. });
  200. plot->setLastUploadToken(lastUploadToken);
  201. }
  202. *id = plot->id();
  203. return true;
  204. }
  205. bool GrDrawOpAtlas::uploadToPage(unsigned int pageIdx, AtlasID* id, GrDeferredUploadTarget* target,
  206. int width, int height, const void* image, SkIPoint16* loc) {
  207. SkASSERT(fProxies[pageIdx] && fProxies[pageIdx]->isInstantiated());
  208. // look through all allocated plots for one we can share, in Most Recently Refed order
  209. PlotList::Iter plotIter;
  210. plotIter.init(fPages[pageIdx].fPlotList, PlotList::Iter::kHead_IterStart);
  211. for (Plot* plot = plotIter.get(); plot; plot = plotIter.next()) {
  212. SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp());
  213. if (plot->addSubImage(width, height, image, loc)) {
  214. return this->updatePlot(target, id, plot);
  215. }
  216. }
  217. return false;
  218. }
  219. // Number of atlas-related flushes beyond which we consider a plot to no longer be in use.
  220. //
  221. // This value is somewhat arbitrary -- the idea is to keep it low enough that
  222. // a page with unused plots will get removed reasonably quickly, but allow it
  223. // to hang around for a bit in case it's needed. The assumption is that flushes
  224. // are rare; i.e., we are not continually refreshing the frame.
  225. static constexpr auto kRecentlyUsedCount = 256;
  226. GrDrawOpAtlas::ErrorCode GrDrawOpAtlas::addToAtlas(GrResourceProvider* resourceProvider,
  227. AtlasID* id, GrDeferredUploadTarget* target,
  228. int width, int height,
  229. const void* image, SkIPoint16* loc) {
  230. if (width > fPlotWidth || height > fPlotHeight) {
  231. return ErrorCode::kError;
  232. }
  233. // Look through each page to see if we can upload without having to flush
  234. // We prioritize this upload to the first pages, not the most recently used, to make it easier
  235. // to remove unused pages in reverse page order.
  236. for (unsigned int pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
  237. if (this->uploadToPage(pageIdx, id, target, width, height, image, loc)) {
  238. return ErrorCode::kSucceeded;
  239. }
  240. }
  241. // If the above fails, then see if the least recently used plot per page has already been
  242. // flushed to the gpu if we're at max page allocation, or if the plot has aged out otherwise.
  243. // We wait until we've grown to the full number of pages to begin evicting already flushed
  244. // plots so that we can maximize the opportunity for reuse.
  245. // As before we prioritize this upload to the first pages, not the most recently used.
  246. if (fNumActivePages == this->maxPages()) {
  247. for (unsigned int pageIdx = 0; pageIdx < fNumActivePages; ++pageIdx) {
  248. Plot* plot = fPages[pageIdx].fPlotList.tail();
  249. SkASSERT(plot);
  250. if (plot->lastUseToken() < target->tokenTracker()->nextTokenToFlush()) {
  251. this->processEvictionAndResetRects(plot);
  252. SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp());
  253. SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc);
  254. SkASSERT(verify);
  255. if (!this->updatePlot(target, id, plot)) {
  256. return ErrorCode::kError;
  257. }
  258. return ErrorCode::kSucceeded;
  259. }
  260. }
  261. } else {
  262. // If we haven't activated all the available pages, try to create a new one and add to it
  263. if (!this->activateNewPage(resourceProvider)) {
  264. return ErrorCode::kError;
  265. }
  266. if (this->uploadToPage(fNumActivePages-1, id, target, width, height, image, loc)) {
  267. return ErrorCode::kSucceeded;
  268. } else {
  269. // If we fail to upload to a newly activated page then something has gone terribly
  270. // wrong - return an error
  271. return ErrorCode::kError;
  272. }
  273. }
  274. if (!fNumActivePages) {
  275. return ErrorCode::kError;
  276. }
  277. // Try to find a plot that we can perform an inline upload to.
  278. // We prioritize this upload in reverse order of pages to counterbalance the order above.
  279. Plot* plot = nullptr;
  280. for (int pageIdx = ((int)fNumActivePages)-1; pageIdx >= 0; --pageIdx) {
  281. Plot* currentPlot = fPages[pageIdx].fPlotList.tail();
  282. if (currentPlot->lastUseToken() != target->tokenTracker()->nextDrawToken()) {
  283. plot = currentPlot;
  284. break;
  285. }
  286. }
  287. // If we can't find a plot that is not used in a draw currently being prepared by an op, then
  288. // we have to fail. This gives the op a chance to enqueue the draw, and call back into this
  289. // function. When that draw is enqueued, the draw token advances, and the subsequent call will
  290. // continue past this branch and prepare an inline upload that will occur after the enqueued
  291. // draw which references the plot's pre-upload content.
  292. if (!plot) {
  293. return ErrorCode::kTryAgain;
  294. }
  295. this->processEviction(plot->id());
  296. int pageIdx = GetPageIndexFromID(plot->id());
  297. fPages[pageIdx].fPlotList.remove(plot);
  298. sk_sp<Plot>& newPlot = fPages[pageIdx].fPlotArray[plot->index()];
  299. newPlot.reset(plot->clone());
  300. fPages[pageIdx].fPlotList.addToHead(newPlot.get());
  301. SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == newPlot->bpp());
  302. SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc);
  303. SkASSERT(verify);
  304. // Note that this plot will be uploaded inline with the draws whereas the
  305. // one it displaced most likely was uploaded ASAP.
  306. // With c+14 we could move sk_sp into lambda to only ref once.
  307. sk_sp<Plot> plotsp(SkRef(newPlot.get()));
  308. GrTextureProxy* proxy = fProxies[pageIdx].get();
  309. SkASSERT(proxy->isInstantiated());
  310. GrDeferredUploadToken lastUploadToken = target->addInlineUpload(
  311. [plotsp, proxy](GrDeferredTextureUploadWritePixelsFn& writePixels) {
  312. plotsp->uploadToTexture(writePixels, proxy);
  313. });
  314. newPlot->setLastUploadToken(lastUploadToken);
  315. *id = newPlot->id();
  316. return ErrorCode::kSucceeded;
  317. }
  318. void GrDrawOpAtlas::compact(GrDeferredUploadToken startTokenForNextFlush) {
  319. if (fNumActivePages <= 1) {
  320. fPrevFlushToken = startTokenForNextFlush;
  321. return;
  322. }
  323. // For all plots, reset number of flushes since used if used this frame.
  324. PlotList::Iter plotIter;
  325. bool atlasUsedThisFlush = false;
  326. for (uint32_t pageIndex = 0; pageIndex < fNumActivePages; ++pageIndex) {
  327. plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
  328. while (Plot* plot = plotIter.get()) {
  329. // Reset number of flushes since used
  330. if (plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
  331. plot->resetFlushesSinceLastUsed();
  332. atlasUsedThisFlush = true;
  333. }
  334. plotIter.next();
  335. }
  336. }
  337. // We only try to compact if the atlas was used in the recently completed flush.
  338. // This is to handle the case where a lot of text or path rendering has occurred but then just
  339. // a blinking cursor is drawn.
  340. // TODO: consider if we should also do this if it's been a long time since the last atlas use
  341. if (atlasUsedThisFlush) {
  342. SkTArray<Plot*> availablePlots;
  343. uint32_t lastPageIndex = fNumActivePages - 1;
  344. // For all plots but the last one, update number of flushes since used, and check to see
  345. // if there are any in the first pages that the last page can safely upload to.
  346. for (uint32_t pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex) {
  347. #ifdef DUMP_ATLAS_DATA
  348. if (gDumpAtlasData) {
  349. SkDebugf("page %d: ", pageIndex);
  350. }
  351. #endif
  352. plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
  353. while (Plot* plot = plotIter.get()) {
  354. // Update number of flushes since plot was last used
  355. // We only increment the 'sinceLastUsed' count for flushes where the atlas was used
  356. // to avoid deleting everything when we return to text drawing in the blinking
  357. // cursor case
  358. if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
  359. plot->incFlushesSinceLastUsed();
  360. }
  361. #ifdef DUMP_ATLAS_DATA
  362. if (gDumpAtlasData) {
  363. SkDebugf("%d ", plot->flushesSinceLastUsed());
  364. }
  365. #endif
  366. // Count plots we can potentially upload to in all pages except the last one
  367. // (the potential compactee).
  368. if (plot->flushesSinceLastUsed() > kRecentlyUsedCount) {
  369. availablePlots.push_back() = plot;
  370. }
  371. plotIter.next();
  372. }
  373. #ifdef DUMP_ATLAS_DATA
  374. if (gDumpAtlasData) {
  375. SkDebugf("\n");
  376. }
  377. #endif
  378. }
  379. // Count recently used plots in the last page and evict any that are no longer in use.
  380. // Since we prioritize uploading to the first pages, this will eventually
  381. // clear out usage of this page unless we have a large need.
  382. plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
  383. unsigned int usedPlots = 0;
  384. #ifdef DUMP_ATLAS_DATA
  385. if (gDumpAtlasData) {
  386. SkDebugf("page %d: ", lastPageIndex);
  387. }
  388. #endif
  389. while (Plot* plot = plotIter.get()) {
  390. // Update number of flushes since plot was last used
  391. if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) {
  392. plot->incFlushesSinceLastUsed();
  393. }
  394. #ifdef DUMP_ATLAS_DATA
  395. if (gDumpAtlasData) {
  396. SkDebugf("%d ", plot->flushesSinceLastUsed());
  397. }
  398. #endif
  399. // If this plot was used recently
  400. if (plot->flushesSinceLastUsed() <= kRecentlyUsedCount) {
  401. usedPlots++;
  402. } else if (plot->lastUseToken() != GrDeferredUploadToken::AlreadyFlushedToken()) {
  403. // otherwise if aged out just evict it.
  404. this->processEvictionAndResetRects(plot);
  405. }
  406. plotIter.next();
  407. }
  408. #ifdef DUMP_ATLAS_DATA
  409. if (gDumpAtlasData) {
  410. SkDebugf("\n");
  411. }
  412. #endif
  413. // If recently used plots in the last page are using less than a quarter of the page, try
  414. // to evict them if there's available space in earlier pages. Since we prioritize uploading
  415. // to the first pages, this will eventually clear out usage of this page unless we have a
  416. // large need.
  417. if (availablePlots.count() && usedPlots && usedPlots <= fNumPlots / 4) {
  418. plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart);
  419. while (Plot* plot = plotIter.get()) {
  420. // If this plot was used recently
  421. if (plot->flushesSinceLastUsed() <= kRecentlyUsedCount) {
  422. // See if there's room in an earlier page and if so evict.
  423. // We need to be somewhat harsh here so that a handful of plots that are
  424. // consistently in use don't end up locking the page in memory.
  425. if (availablePlots.count() > 0) {
  426. this->processEvictionAndResetRects(plot);
  427. this->processEvictionAndResetRects(availablePlots.back());
  428. availablePlots.pop_back();
  429. --usedPlots;
  430. }
  431. if (!usedPlots || !availablePlots.count()) {
  432. break;
  433. }
  434. }
  435. plotIter.next();
  436. }
  437. }
  438. // If none of the plots in the last page have been used recently, delete it.
  439. if (!usedPlots) {
  440. #ifdef DUMP_ATLAS_DATA
  441. if (gDumpAtlasData) {
  442. SkDebugf("delete %d\n", fNumPages-1);
  443. }
  444. #endif
  445. this->deactivateLastPage();
  446. }
  447. }
  448. fPrevFlushToken = startTokenForNextFlush;
  449. }
  450. bool GrDrawOpAtlas::createPages(GrProxyProvider* proxyProvider) {
  451. SkASSERT(SkIsPow2(fTextureWidth) && SkIsPow2(fTextureHeight));
  452. GrSurfaceDesc desc;
  453. desc.fWidth = fTextureWidth;
  454. desc.fHeight = fTextureHeight;
  455. desc.fConfig = GrColorTypeToPixelConfig(fColorType);
  456. int numPlotsX = fTextureWidth/fPlotWidth;
  457. int numPlotsY = fTextureHeight/fPlotHeight;
  458. for (uint32_t i = 0; i < this->maxPages(); ++i) {
  459. fProxies[i] = proxyProvider->createProxy(fFormat, desc, GrRenderable::kNo, 1,
  460. kTopLeft_GrSurfaceOrigin, SkBackingFit::kExact,
  461. SkBudgeted::kYes, GrProtected::kNo);
  462. if (!fProxies[i]) {
  463. return false;
  464. }
  465. fProxies[i]->priv().setIgnoredByResourceAllocator();
  466. // set up allocated plots
  467. fPages[i].fPlotArray.reset(new sk_sp<Plot>[ numPlotsX * numPlotsY ]);
  468. sk_sp<Plot>* currPlot = fPages[i].fPlotArray.get();
  469. for (int y = numPlotsY - 1, r = 0; y >= 0; --y, ++r) {
  470. for (int x = numPlotsX - 1, c = 0; x >= 0; --x, ++c) {
  471. uint32_t plotIndex = r * numPlotsX + c;
  472. currPlot->reset(new Plot(i, plotIndex, 1, x, y, fPlotWidth, fPlotHeight,
  473. fColorType));
  474. // build LRU list
  475. fPages[i].fPlotList.addToHead(currPlot->get());
  476. ++currPlot;
  477. }
  478. }
  479. }
  480. return true;
  481. }
  482. bool GrDrawOpAtlas::activateNewPage(GrResourceProvider* resourceProvider) {
  483. SkASSERT(fNumActivePages < this->maxPages());
  484. if (!fProxies[fNumActivePages]->instantiate(resourceProvider)) {
  485. return false;
  486. }
  487. #ifdef DUMP_ATLAS_DATA
  488. if (gDumpAtlasData) {
  489. SkDebugf("activated page#: %d\n", fNumActivePages);
  490. }
  491. #endif
  492. ++fNumActivePages;
  493. return true;
  494. }
  495. inline void GrDrawOpAtlas::deactivateLastPage() {
  496. SkASSERT(fNumActivePages);
  497. uint32_t lastPageIndex = fNumActivePages - 1;
  498. int numPlotsX = fTextureWidth/fPlotWidth;
  499. int numPlotsY = fTextureHeight/fPlotHeight;
  500. fPages[lastPageIndex].fPlotList.reset();
  501. for (int r = 0; r < numPlotsY; ++r) {
  502. for (int c = 0; c < numPlotsX; ++c) {
  503. uint32_t plotIndex = r * numPlotsX + c;
  504. Plot* currPlot = fPages[lastPageIndex].fPlotArray[plotIndex].get();
  505. currPlot->resetRects();
  506. currPlot->resetFlushesSinceLastUsed();
  507. // rebuild the LRU list
  508. SkDEBUGCODE(currPlot->fPrev = currPlot->fNext = nullptr);
  509. SkDEBUGCODE(currPlot->fList = nullptr);
  510. fPages[lastPageIndex].fPlotList.addToHead(currPlot);
  511. }
  512. }
  513. // remove ref to the backing texture
  514. fProxies[lastPageIndex]->deinstantiate();
  515. --fNumActivePages;
  516. }
  517. GrDrawOpAtlasConfig::GrDrawOpAtlasConfig(int maxTextureSize, size_t maxBytes) {
  518. static const SkISize kARGBDimensions[] = {
  519. {256, 256}, // maxBytes < 2^19
  520. {512, 256}, // 2^19 <= maxBytes < 2^20
  521. {512, 512}, // 2^20 <= maxBytes < 2^21
  522. {1024, 512}, // 2^21 <= maxBytes < 2^22
  523. {1024, 1024}, // 2^22 <= maxBytes < 2^23
  524. {2048, 1024}, // 2^23 <= maxBytes
  525. };
  526. // Index 0 corresponds to maxBytes of 2^18, so start by dividing it by that
  527. maxBytes >>= 18;
  528. // Take the floor of the log to get the index
  529. int index = maxBytes > 0
  530. ? SkTPin<int>(SkPrevLog2(maxBytes), 0, SK_ARRAY_COUNT(kARGBDimensions) - 1)
  531. : 0;
  532. SkASSERT(kARGBDimensions[index].width() <= kMaxAtlasDim);
  533. SkASSERT(kARGBDimensions[index].height() <= kMaxAtlasDim);
  534. fARGBDimensions.set(SkTMin<int>(kARGBDimensions[index].width(), maxTextureSize),
  535. SkTMin<int>(kARGBDimensions[index].height(), maxTextureSize));
  536. fMaxTextureSize = SkTMin<int>(maxTextureSize, kMaxAtlasDim);
  537. }
  538. SkISize GrDrawOpAtlasConfig::atlasDimensions(GrMaskFormat type) const {
  539. if (kA8_GrMaskFormat == type) {
  540. // A8 is always 2x the ARGB dimensions, clamped to the max allowed texture size
  541. return { SkTMin<int>(2 * fARGBDimensions.width(), fMaxTextureSize),
  542. SkTMin<int>(2 * fARGBDimensions.height(), fMaxTextureSize) };
  543. } else {
  544. return fARGBDimensions;
  545. }
  546. }
  547. SkISize GrDrawOpAtlasConfig::plotDimensions(GrMaskFormat type) const {
  548. if (kA8_GrMaskFormat == type) {
  549. SkISize atlasDimensions = this->atlasDimensions(type);
  550. // For A8 we want to grow the plots at larger texture sizes to accept more of the
  551. // larger SDF glyphs. Since the largest SDF glyph can be 170x170 with padding, this
  552. // allows us to pack 3 in a 512x256 plot, or 9 in a 512x512 plot.
  553. // This will give us 512x256 plots for 2048x1024, 512x512 plots for 2048x2048,
  554. // and 256x256 plots otherwise.
  555. int plotWidth = atlasDimensions.width() >= 2048 ? 512 : 256;
  556. int plotHeight = atlasDimensions.height() >= 2048 ? 512 : 256;
  557. return { plotWidth, plotHeight };
  558. } else {
  559. // ARGB and LCD always use 256x256 plots -- this has been shown to be faster
  560. return { 256, 256 };
  561. }
  562. }
  563. constexpr int GrDrawOpAtlasConfig::kMaxAtlasDim;