1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2020 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/GrDynamicAtlas.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "src/core/SkIPoint16.h" 11cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrOnFlushResourceProvider.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrRectanizerPow2.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrRectanizerSkyline.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrRenderTarget.h" 17cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrSurfaceProxyPriv.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrSurfaceProxyView.h" 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci// Each Node covers a sub-rectangle of the final atlas. When a GrDynamicAtlas runs out of room, we 22cb93a386Sopenharmony_ci// create a new Node the same size as all combined nodes in the atlas as-is, and then place the new 23cb93a386Sopenharmony_ci// Node immediately below or beside the others (thereby doubling the size of the GyDynamicAtlas). 24cb93a386Sopenharmony_ciclass GrDynamicAtlas::Node { 25cb93a386Sopenharmony_cipublic: 26cb93a386Sopenharmony_ci Node(Node* previous, GrRectanizer* rectanizer, int x, int y) 27cb93a386Sopenharmony_ci : fPrevious(previous), fRectanizer(rectanizer), fX(x), fY(y) {} 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci Node* previous() const { return fPrevious; } 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci bool addRect(int w, int h, SkIPoint16* loc) { 32cb93a386Sopenharmony_ci // Pad all paths except those that are expected to take up an entire physical texture. 33cb93a386Sopenharmony_ci if (w < fRectanizer->width()) { 34cb93a386Sopenharmony_ci w = std::min(w + kPadding, fRectanizer->width()); 35cb93a386Sopenharmony_ci } 36cb93a386Sopenharmony_ci if (h < fRectanizer->height()) { 37cb93a386Sopenharmony_ci h = std::min(h + kPadding, fRectanizer->height()); 38cb93a386Sopenharmony_ci } 39cb93a386Sopenharmony_ci if (!fRectanizer->addRect(w, h, loc)) { 40cb93a386Sopenharmony_ci return false; 41cb93a386Sopenharmony_ci } 42cb93a386Sopenharmony_ci loc->fX += fX; 43cb93a386Sopenharmony_ci loc->fY += fY; 44cb93a386Sopenharmony_ci return true; 45cb93a386Sopenharmony_ci } 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ciprivate: 48cb93a386Sopenharmony_ci Node* const fPrevious; 49cb93a386Sopenharmony_ci GrRectanizer* const fRectanizer; 50cb93a386Sopenharmony_ci const int fX, fY; 51cb93a386Sopenharmony_ci}; 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_cisk_sp<GrTextureProxy> GrDynamicAtlas::MakeLazyAtlasProxy( 54cb93a386Sopenharmony_ci LazyInstantiateAtlasCallback&& callback, 55cb93a386Sopenharmony_ci GrColorType colorType, 56cb93a386Sopenharmony_ci InternalMultisample internalMultisample, 57cb93a386Sopenharmony_ci const GrCaps& caps, 58cb93a386Sopenharmony_ci GrSurfaceProxy::UseAllocator useAllocator) { 59cb93a386Sopenharmony_ci GrBackendFormat format = caps.getDefaultBackendFormat(colorType, GrRenderable::kYes); 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci int sampleCount = 1; 62cb93a386Sopenharmony_ci if (InternalMultisample::kYes == internalMultisample) { 63cb93a386Sopenharmony_ci sampleCount = caps.internalMultisampleCount(format); 64cb93a386Sopenharmony_ci } 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci sk_sp<GrTextureProxy> proxy = 67cb93a386Sopenharmony_ci GrProxyProvider::MakeFullyLazyProxy(std::move(callback), format, GrRenderable::kYes, 68cb93a386Sopenharmony_ci sampleCount, GrProtected::kNo, caps, useAllocator); 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci return proxy; 71cb93a386Sopenharmony_ci} 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ciGrDynamicAtlas::GrDynamicAtlas(GrColorType colorType, InternalMultisample internalMultisample, 74cb93a386Sopenharmony_ci SkISize initialSize, int maxAtlasSize, const GrCaps& caps, 75cb93a386Sopenharmony_ci RectanizerAlgorithm algorithm) 76cb93a386Sopenharmony_ci : fColorType(colorType) 77cb93a386Sopenharmony_ci , fInternalMultisample(internalMultisample) 78cb93a386Sopenharmony_ci , fMaxAtlasSize(maxAtlasSize) 79cb93a386Sopenharmony_ci , fRectanizerAlgorithm(algorithm) { 80cb93a386Sopenharmony_ci SkASSERT(fMaxAtlasSize <= caps.maxTextureSize()); 81cb93a386Sopenharmony_ci this->reset(initialSize, caps); 82cb93a386Sopenharmony_ci} 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ciGrDynamicAtlas::~GrDynamicAtlas() { 85cb93a386Sopenharmony_ci} 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_civoid GrDynamicAtlas::reset(SkISize initialSize, const GrCaps& caps) { 88cb93a386Sopenharmony_ci fNodeAllocator.reset(); 89cb93a386Sopenharmony_ci fWidth = std::min(SkNextPow2(initialSize.width()), fMaxAtlasSize); 90cb93a386Sopenharmony_ci fHeight = std::min(SkNextPow2(initialSize.height()), fMaxAtlasSize); 91cb93a386Sopenharmony_ci fTopNode = nullptr; 92cb93a386Sopenharmony_ci fDrawBounds.setEmpty(); 93cb93a386Sopenharmony_ci fTextureProxy = MakeLazyAtlasProxy( 94cb93a386Sopenharmony_ci [this](GrResourceProvider* resourceProvider, const LazyAtlasDesc& desc) { 95cb93a386Sopenharmony_ci if (!fBackingTexture) { 96cb93a386Sopenharmony_ci fBackingTexture = resourceProvider->createTexture( 97cb93a386Sopenharmony_ci fTextureProxy->backingStoreDimensions(), 98cb93a386Sopenharmony_ci desc.fFormat, 99cb93a386Sopenharmony_ci desc.fTextureType, 100cb93a386Sopenharmony_ci desc.fRenderable, 101cb93a386Sopenharmony_ci desc.fSampleCnt, 102cb93a386Sopenharmony_ci desc.fMipmapped, 103cb93a386Sopenharmony_ci desc.fBudgeted, 104cb93a386Sopenharmony_ci desc.fProtected); 105cb93a386Sopenharmony_ci } 106cb93a386Sopenharmony_ci return GrSurfaceProxy::LazyCallbackResult(fBackingTexture); 107cb93a386Sopenharmony_ci }, 108cb93a386Sopenharmony_ci fColorType, fInternalMultisample, caps, GrSurfaceProxy::UseAllocator::kNo); 109cb93a386Sopenharmony_ci fBackingTexture = nullptr; 110cb93a386Sopenharmony_ci} 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ciGrDynamicAtlas::Node* GrDynamicAtlas::makeNode(Node* previous, int l, int t, int r, int b) { 113cb93a386Sopenharmony_ci int width = r - l; 114cb93a386Sopenharmony_ci int height = b - t; 115cb93a386Sopenharmony_ci GrRectanizer* rectanizer = (fRectanizerAlgorithm == RectanizerAlgorithm::kSkyline) 116cb93a386Sopenharmony_ci ? (GrRectanizer*)fNodeAllocator.make<GrRectanizerSkyline>(width, height) 117cb93a386Sopenharmony_ci : fNodeAllocator.make<GrRectanizerPow2>(width, height); 118cb93a386Sopenharmony_ci return fNodeAllocator.make<Node>(previous, rectanizer, l, t); 119cb93a386Sopenharmony_ci} 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ciGrSurfaceProxyView GrDynamicAtlas::readView(const GrCaps& caps) const { 122cb93a386Sopenharmony_ci return {fTextureProxy, kTextureOrigin, 123cb93a386Sopenharmony_ci caps.getReadSwizzle(fTextureProxy->backendFormat(), fColorType)}; 124cb93a386Sopenharmony_ci} 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ciGrSurfaceProxyView GrDynamicAtlas::writeView(const GrCaps& caps) const { 127cb93a386Sopenharmony_ci return {fTextureProxy, kTextureOrigin, 128cb93a386Sopenharmony_ci caps.getWriteSwizzle(fTextureProxy->backendFormat(), fColorType)}; 129cb93a386Sopenharmony_ci} 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_cibool GrDynamicAtlas::addRect(int width, int height, SkIPoint16* location) { 132cb93a386Sopenharmony_ci // This can't be called anymore once instantiate() has been called. 133cb93a386Sopenharmony_ci SkASSERT(!this->isInstantiated()); 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci if (!this->internalPlaceRect(width, height, location)) { 136cb93a386Sopenharmony_ci return false; 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci fDrawBounds.fWidth = std::max(fDrawBounds.width(), location->x() + width); 140cb93a386Sopenharmony_ci fDrawBounds.fHeight = std::max(fDrawBounds.height(), location->y() + height); 141cb93a386Sopenharmony_ci return true; 142cb93a386Sopenharmony_ci} 143cb93a386Sopenharmony_ci 144cb93a386Sopenharmony_cibool GrDynamicAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) { 145cb93a386Sopenharmony_ci if (std::max(h, w) > fMaxAtlasSize) { 146cb93a386Sopenharmony_ci return false; 147cb93a386Sopenharmony_ci } 148cb93a386Sopenharmony_ci if (std::min(h, w) <= 0) { 149cb93a386Sopenharmony_ci loc->set(0, 0); 150cb93a386Sopenharmony_ci return true; 151cb93a386Sopenharmony_ci } 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci if (!fTopNode) { 154cb93a386Sopenharmony_ci if (w > fWidth) { 155cb93a386Sopenharmony_ci fWidth = std::min(SkNextPow2(w), fMaxAtlasSize); 156cb93a386Sopenharmony_ci } 157cb93a386Sopenharmony_ci if (h > fHeight) { 158cb93a386Sopenharmony_ci fHeight = std::min(SkNextPow2(h), fMaxAtlasSize); 159cb93a386Sopenharmony_ci } 160cb93a386Sopenharmony_ci fTopNode = this->makeNode(nullptr, 0, 0, fWidth, fHeight); 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ci for (Node* node = fTopNode; node; node = node->previous()) { 164cb93a386Sopenharmony_ci if (node->addRect(w, h, loc)) { 165cb93a386Sopenharmony_ci return true; 166cb93a386Sopenharmony_ci } 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci // The rect didn't fit. Grow the atlas and try again. 170cb93a386Sopenharmony_ci do { 171cb93a386Sopenharmony_ci if (fWidth >= fMaxAtlasSize && fHeight >= fMaxAtlasSize) { 172cb93a386Sopenharmony_ci return false; 173cb93a386Sopenharmony_ci } 174cb93a386Sopenharmony_ci if (fHeight <= fWidth) { 175cb93a386Sopenharmony_ci int top = fHeight; 176cb93a386Sopenharmony_ci fHeight = std::min(fHeight * 2, fMaxAtlasSize); 177cb93a386Sopenharmony_ci fTopNode = this->makeNode(fTopNode, 0, top, fWidth, fHeight); 178cb93a386Sopenharmony_ci } else { 179cb93a386Sopenharmony_ci int left = fWidth; 180cb93a386Sopenharmony_ci fWidth = std::min(fWidth * 2, fMaxAtlasSize); 181cb93a386Sopenharmony_ci fTopNode = this->makeNode(fTopNode, left, 0, fWidth, fHeight); 182cb93a386Sopenharmony_ci } 183cb93a386Sopenharmony_ci } while (!fTopNode->addRect(w, h, loc)); 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci return true; 186cb93a386Sopenharmony_ci} 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_civoid GrDynamicAtlas::instantiate(GrOnFlushResourceProvider* onFlushRP, 189cb93a386Sopenharmony_ci sk_sp<GrTexture> backingTexture) { 190cb93a386Sopenharmony_ci SkASSERT(!this->isInstantiated()); // This method should only be called once. 191cb93a386Sopenharmony_ci // Caller should have cropped any paths to the destination render target instead of asking for 192cb93a386Sopenharmony_ci // an atlas larger than maxRenderTargetSize. 193cb93a386Sopenharmony_ci SkASSERT(std::max(fHeight, fWidth) <= fMaxAtlasSize); 194cb93a386Sopenharmony_ci SkASSERT(fMaxAtlasSize <= onFlushRP->caps()->maxRenderTargetSize()); 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci if (fTextureProxy->isFullyLazy()) { 197cb93a386Sopenharmony_ci // Finalize the content size of our proxy. The GPU can potentially make optimizations if it 198cb93a386Sopenharmony_ci // knows we only intend to write out a smaller sub-rectangle of the backing texture. 199cb93a386Sopenharmony_ci fTextureProxy->priv().setLazyDimensions(fDrawBounds); 200cb93a386Sopenharmony_ci } 201cb93a386Sopenharmony_ci SkASSERT(fTextureProxy->dimensions() == fDrawBounds); 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci if (backingTexture) { 204cb93a386Sopenharmony_ci#ifdef SK_DEBUG 205cb93a386Sopenharmony_ci auto backingRT = backingTexture->asRenderTarget(); 206cb93a386Sopenharmony_ci SkASSERT(backingRT); 207cb93a386Sopenharmony_ci SkASSERT(backingRT->backendFormat() == fTextureProxy->backendFormat()); 208cb93a386Sopenharmony_ci SkASSERT(backingRT->numSamples() == fTextureProxy->asRenderTargetProxy()->numSamples()); 209cb93a386Sopenharmony_ci SkASSERT(backingRT->dimensions() == fTextureProxy->backingStoreDimensions()); 210cb93a386Sopenharmony_ci#endif 211cb93a386Sopenharmony_ci fBackingTexture = std::move(backingTexture); 212cb93a386Sopenharmony_ci } 213cb93a386Sopenharmony_ci onFlushRP->instatiateProxy(fTextureProxy.get()); 214cb93a386Sopenharmony_ci} 215