Flutter Engine
The Flutter Engine
GrDynamicAtlas.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2020 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
9
10#include "src/core/SkIPoint16.h"
22
23using namespace skgpu;
24
25// Each Node covers a sub-rectangle of the final atlas. When a GrDynamicAtlas runs out of room, we
26// create a new Node the same size as all combined nodes in the atlas as-is, and then place the new
27// Node immediately below or beside the others (thereby doubling the size of the GyDynamicAtlas).
29public:
30 Node(Node* previous, Rectanizer* rectanizer, int x, int y)
31 : fPrevious(previous), fRectanizer(rectanizer), fX(x), fY(y) {}
32
33 Node* previous() const { return fPrevious; }
34
35 bool addRect(int w, int h, SkIPoint16* loc) {
36 // Pad all paths except those that are expected to take up an entire physical texture.
37 if (w < fRectanizer->width()) {
38 w = std::min(w + kPadding, fRectanizer->width());
39 }
40 if (h < fRectanizer->height()) {
41 h = std::min(h + kPadding, fRectanizer->height());
42 }
43 if (!fRectanizer->addRect(w, h, loc)) {
44 return false;
45 }
46 loc->fX += fX;
47 loc->fY += fY;
48 return true;
49 }
50
51private:
52 Node* const fPrevious;
53 Rectanizer* const fRectanizer;
54 const int fX, fY;
55};
56
60 InternalMultisample internalMultisample,
61 const GrCaps& caps,
62 GrSurfaceProxy::UseAllocator useAllocator) {
64
65 int sampleCount = 1;
66 if (InternalMultisample::kYes == internalMultisample) {
67 sampleCount = caps.internalMultisampleCount(format);
68 }
69
72 sampleCount, GrProtected::kNo, caps, useAllocator);
73
74 return proxy;
75}
76
78 SkISize initialSize, int maxAtlasSize, const GrCaps& caps,
79 RectanizerAlgorithm algorithm)
81 , fInternalMultisample(internalMultisample)
82 , fMaxAtlasSize(maxAtlasSize)
83 , fRectanizerAlgorithm(algorithm) {
84 SkASSERT(fMaxAtlasSize <= caps.maxTextureSize());
85 this->reset(initialSize, caps);
86}
87
89}
90
91void GrDynamicAtlas::reset(SkISize initialSize, const GrCaps& caps) {
92 fNodeAllocator.reset();
93 fWidth = std::min(SkNextPow2(initialSize.width()), fMaxAtlasSize);
94 fHeight = std::min(SkNextPow2(initialSize.height()), fMaxAtlasSize);
95 fTopNode = nullptr;
96 fDrawBounds.setEmpty();
97 fTextureProxy = MakeLazyAtlasProxy(
98 [this](GrResourceProvider* resourceProvider, const LazyAtlasDesc& desc) {
99 if (!fBackingTexture) {
100 fBackingTexture =
101 resourceProvider->createTexture(fTextureProxy->backingStoreDimensions(),
102 desc.fFormat,
103 desc.fTextureType,
104 desc.fRenderable,
105 desc.fSampleCnt,
106 desc.fMipmapped,
107 desc.fBudgeted,
108 desc.fProtected,
109 desc.fLabel);
110 }
111 return GrSurfaceProxy::LazyCallbackResult(fBackingTexture);
112 },
113 fColorType, fInternalMultisample, caps, GrSurfaceProxy::UseAllocator::kNo);
114 fBackingTexture = nullptr;
115}
116
117GrDynamicAtlas::Node* GrDynamicAtlas::makeNode(Node* previous, int l, int t, int r, int b) {
118 int width = r - l;
119 int height = b - t;
120 Rectanizer* rectanizer = (fRectanizerAlgorithm == RectanizerAlgorithm::kSkyline)
121 ? (Rectanizer*)fNodeAllocator.make<RectanizerSkyline>(width, height)
122 : fNodeAllocator.make<RectanizerPow2>(width, height);
123 return fNodeAllocator.make<Node>(previous, rectanizer, l, t);
124}
125
127 return {fTextureProxy, kTextureOrigin,
128 caps.getReadSwizzle(fTextureProxy->backendFormat(), fColorType)};
129}
130
132 return {fTextureProxy, kTextureOrigin,
133 caps.getWriteSwizzle(fTextureProxy->backendFormat(), fColorType)};
134}
135
137 // This can't be called anymore once instantiate() has been called.
138 SkASSERT(!this->isInstantiated());
139
140 if (!this->internalPlaceRect(width, height, location)) {
141 return false;
142 }
143
144 fDrawBounds.fWidth = std::max(fDrawBounds.width(), location->x() + width);
145 fDrawBounds.fHeight = std::max(fDrawBounds.height(), location->y() + height);
146 return true;
147}
148
149bool GrDynamicAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
150 if (std::max(h, w) > fMaxAtlasSize) {
151 return false;
152 }
153 if (std::min(h, w) <= 0) {
154 loc->set(0, 0);
155 return true;
156 }
157
158 if (!fTopNode) {
159 if (w > fWidth) {
160 fWidth = std::min(SkNextPow2(w), fMaxAtlasSize);
161 }
162 if (h > fHeight) {
163 fHeight = std::min(SkNextPow2(h), fMaxAtlasSize);
164 }
165 fTopNode = this->makeNode(nullptr, 0, 0, fWidth, fHeight);
166 }
167
168 for (Node* node = fTopNode; node; node = node->previous()) {
169 if (node->addRect(w, h, loc)) {
170 return true;
171 }
172 }
173
174 // The rect didn't fit. Grow the atlas and try again.
175 do {
176 if (fWidth >= fMaxAtlasSize && fHeight >= fMaxAtlasSize) {
177 return false;
178 }
179 if (fHeight <= fWidth) {
180 int top = fHeight;
181 fHeight = std::min(fHeight * 2, fMaxAtlasSize);
182 fTopNode = this->makeNode(fTopNode, 0, top, fWidth, fHeight);
183 } else {
184 int left = fWidth;
185 fWidth = std::min(fWidth * 2, fMaxAtlasSize);
186 fTopNode = this->makeNode(fTopNode, left, 0, fWidth, fHeight);
187 }
188 } while (!fTopNode->addRect(w, h, loc));
189
190 return true;
191}
192
194 sk_sp<GrTexture> backingTexture) {
195 SkASSERT(!this->isInstantiated()); // This method should only be called once.
196 // Caller should have cropped any paths to the destination render target instead of asking for
197 // an atlas larger than maxRenderTargetSize.
198 SkASSERT(std::max(fHeight, fWidth) <= fMaxAtlasSize);
199 SkASSERT(fMaxAtlasSize <= onFlushRP->caps()->maxRenderTargetSize());
200
201 if (fTextureProxy->isFullyLazy()) {
202 // Finalize the content size of our proxy. The GPU can potentially make optimizations if it
203 // knows we only intend to write out a smaller sub-rectangle of the backing texture.
204 fTextureProxy->priv().setLazyDimensions(fDrawBounds);
205 }
206 SkASSERT(fTextureProxy->dimensions() == fDrawBounds);
207
208 if (backingTexture) {
209#ifdef SK_DEBUG
210 auto backingRT = backingTexture->asRenderTarget();
211 SkASSERT(backingRT);
212 SkASSERT(backingRT->backendFormat() == fTextureProxy->backendFormat());
213 SkASSERT(backingRT->numSamples() == fTextureProxy->asRenderTargetProxy()->numSamples());
214 SkASSERT(backingRT->dimensions() == fTextureProxy->backingStoreDimensions());
215#endif
216 // This works bc 'fTextureProxy' is a lazy proxy and, in its LazyInstantiateAtlasCallback,
217 // it will just wrap 'fBackingTexture' if it is non-null.
218 fBackingTexture = std::move(backingTexture);
219 }
220 return onFlushRP->instantiateProxy(fTextureProxy.get());
221}
GrColorType
Definition: GrTypesPriv.h:540
SkColorType fColorType
#define SkASSERT(cond)
Definition: SkAssert.h:116
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static int SkNextPow2(int value)
Definition: SkMathPriv.h:272
static bool left(const SkPoint &p0, const SkPoint &p1)
Definition: GrCaps.h:57
virtual skgpu::Swizzle getWriteSwizzle(const GrBackendFormat &, GrColorType) const =0
int maxTextureSize() const
Definition: GrCaps.h:229
GrBackendFormat getDefaultBackendFormat(GrColorType, GrRenderable) const
Definition: GrCaps.cpp:400
int internalMultisampleCount(const GrBackendFormat &format) const
Definition: GrCaps.h:271
skgpu::Swizzle getReadSwizzle(const GrBackendFormat &format, GrColorType colorType) const
Definition: GrCaps.cpp:443
Node(Node *previous, Rectanizer *rectanizer, int x, int y)
Node * previous() const
bool addRect(int w, int h, SkIPoint16 *loc)
virtual ~GrDynamicAtlas()
GrColorType colorType() const
GrSurfaceProxyView writeView(const GrCaps &) const
static constexpr GrSurfaceOrigin kTextureOrigin
static constexpr int kPadding
bool instantiate(GrOnFlushResourceProvider *, sk_sp< GrTexture > backingTexture=nullptr)
GrSurfaceProxy::LazyInstantiateCallback LazyInstantiateAtlasCallback
GrDynamicAtlas(GrColorType colorType, InternalMultisample, SkISize initialSize, int maxAtlasSize, const GrCaps &, RectanizerAlgorithm=RectanizerAlgorithm::kSkyline)
static sk_sp< GrTextureProxy > MakeLazyAtlasProxy(LazyInstantiateAtlasCallback &&, GrColorType colorType, InternalMultisample, const GrCaps &, GrSurfaceProxy::UseAllocator)
bool addRect(int width, int height, SkIPoint16 *location)
bool isInstantiated() const
GrSurfaceProxyView readView(const GrCaps &) const
void reset(SkISize initialSize, const GrCaps &desc)
bool instantiateProxy(GrSurfaceProxy *)
static sk_sp< GrTextureProxy > MakeFullyLazyProxy(LazyInstantiateCallback &&, const GrBackendFormat &, GrRenderable, int renderTargetSampleCnt, GrProtected, const GrCaps &, UseAllocator)
sk_sp< GrTexture > createTexture(SkISize dimensions, const GrBackendFormat &format, GrTextureType textureType, skgpu::Renderable renderable, int renderTargetSampleCnt, skgpu::Mipmapped mipmapped, skgpu::Budgeted budgeted, skgpu::Protected isProtected, std::string_view label)
void setLazyDimensions(SkISize dimensions)
SkISize backingStoreDimensions() const
virtual GrRenderTargetProxy * asRenderTargetProxy()
const GrBackendFormat & backendFormat() const
GrSurfaceProxyPriv priv()
bool isFullyLazy() const
SkISize dimensions() const
virtual GrRenderTarget * asRenderTarget()
Definition: GrSurface.h:65
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
Definition: SkArenaAlloc.h:120
T * get() const
Definition: SkRefCnt.h:303
int width() const
Definition: Rectanizer.h:26
int height() const
Definition: Rectanizer.h:27
virtual bool addRect(int width, int height, SkIPoint16 *loc)=0
static bool b
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
uint32_t uint32_t * format
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
Definition: dart.idl:29
double y
double x
Definition: GpuTools.h:21
SkScalar w
SkScalar h
int32_t height
int32_t width
void set(int x, int y)
Definition: SkIPoint16.h:50
int16_t fY
y-axis value used by SkIPoint16
Definition: SkIPoint16.h:20
int16_t fX
x-axis value used by SkIPoint16
Definition: SkIPoint16.h:18
int16_t y() const
Definition: SkIPoint16.h:43
int16_t x() const
Definition: SkIPoint16.h:37
Definition: SkSize.h:16
int32_t fHeight
Definition: SkSize.h:18
void setEmpty()
Definition: SkSize.h:34
int32_t fWidth
Definition: SkSize.h:17
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37