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