Flutter Engine
The Flutter Engine
SkMipmap.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2013 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/core/SkMipmap.h"
8
14#include "src/base/SkMathPriv.h"
17
18#include <new>
19
20//
21// ColorTypeFilter is the "Type" we pass to some downsample template functions.
22// It controls how we expand a pixel into a large type, with space between each component,
23// so we can then perform our simple filter (either box or triangle) and store the intermediates
24// in the expanded type.
25//
26
27///////////////////////////////////////////////////////////////////////////////////////////////////
28
29SkMipmap::SkMipmap(void* malloc, size_t size) : SkCachedData(malloc, size) {}
30SkMipmap::SkMipmap(size_t size, SkDiscardableMemory* dm) : SkCachedData(size, dm) {}
31
32SkMipmap::~SkMipmap() = default;
33
34size_t SkMipmap::AllocLevelsSize(int levelCount, size_t pixelSize) {
35 if (levelCount < 0) {
36 return 0;
37 }
38 int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize;
39 if (!SkTFitsIn<int32_t>(size)) {
40 return 0;
41 }
42 return SkTo<int32_t>(size);
43}
44
46 bool computeContents) {
47 if (src.width() <= 1 && src.height() <= 1) {
48 return nullptr;
49 }
50
51 const SkColorType ct = src.colorType();
52 const SkAlphaType at = src.alphaType();
53
54 // whip through our loop to compute the exact size needed
55 size_t size = 0;
56 int countLevels = ComputeLevelCount(src.width(), src.height());
57 for (int currentMipLevel = countLevels; currentMipLevel >= 0; currentMipLevel--) {
58 SkISize mipSize = ComputeLevelSize(src.width(), src.height(), currentMipLevel);
59 size += SkColorTypeMinRowBytes(ct, mipSize.fWidth) * mipSize.fHeight;
60 }
61
62 size_t storageSize = SkMipmap::AllocLevelsSize(countLevels, size);
63 if (0 == storageSize) {
64 return nullptr;
65 }
66
67 SkMipmap* mipmap;
68 if (fact) {
69 SkDiscardableMemory* dm = fact(storageSize);
70 if (nullptr == dm) {
71 return nullptr;
72 }
73 mipmap = new SkMipmap(storageSize, dm);
74 } else {
75 void* tmp = sk_malloc_canfail(storageSize);
76 if (!tmp) {
77 return nullptr;
78 }
79
80 mipmap = new SkMipmap(tmp, storageSize);
81 }
82
83 // init
84 mipmap->fCS = sk_ref_sp(src.info().colorSpace());
85 mipmap->fCount = countLevels;
86 mipmap->fLevels = (Level*)mipmap->writable_data();
87 SkASSERT(mipmap->fLevels);
88
89 Level* levels = mipmap->fLevels;
90 uint8_t* baseAddr = (uint8_t*)&levels[countLevels];
91 uint8_t* addr = baseAddr;
92 int width = src.width();
93 int height = src.height();
94 uint32_t rowBytes;
95 SkPixmap srcPM(src);
96
97 // Depending on architecture and other factors, the pixel data alignment may need to be as
98 // large as 8 (for F16 pixels). See the comment on SkMipmap::Level.
99 SkASSERT(SkIsAlign8((uintptr_t)addr));
100
101 std::unique_ptr<SkMipmapDownSampler> downsampler;
102 if (computeContents) {
103 downsampler = MakeDownSampler(src);
104 if (!downsampler) {
105 return nullptr;
106 }
107 }
108
109 for (int i = 0; i < countLevels; ++i) {
110 width = std::max(1, width >> 1);
111 height = std::max(1, height >> 1);
112 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width));
113
114 // We make the Info w/o any colorspace, since that storage is not under our control, and
115 // will not be deleted in a controlled fashion. When the caller is given the pixmap for
116 // a given level, we augment this pixmap with fCS (which we do manage).
117 new (&levels[i].fPixmap) SkPixmap(SkImageInfo::Make(width, height, ct, at), addr, rowBytes);
118 levels[i].fScale = SkSize::Make(SkIntToScalar(width) / src.width(),
119 SkIntToScalar(height) / src.height());
120
121 const SkPixmap& dstPM = levels[i].fPixmap;
122 if (downsampler) {
123 downsampler->buildLevel(dstPM, srcPM);
124 }
125 srcPM = dstPM;
126 addr += height * rowBytes;
127 }
128 SkASSERT(addr == baseAddr + size);
129
130 SkASSERT(mipmap->fLevels);
131 return mipmap;
132}
133
134int SkMipmap::ComputeLevelCount(int baseWidth, int baseHeight) {
135 if (baseWidth < 1 || baseHeight < 1) {
136 return 0;
137 }
138
139 // OpenGL's spec requires that each mipmap level have height/width equal to
140 // max(1, floor(original_height / 2^i)
141 // (or original_width) where i is the mipmap level.
142 // Continue scaling down until both axes are size 1.
143
144 const int largestAxis = std::max(baseWidth, baseHeight);
145 if (largestAxis < 2) {
146 // SkMipmap::Build requires a minimum size of 2.
147 return 0;
148 }
149 const int leadingZeros = SkCLZ(static_cast<uint32_t>(largestAxis));
150 // If the value 00011010 has 3 leading 0s then it has 5 significant bits
151 // (the bits which are not leading zeros)
152 const int significantBits = (sizeof(uint32_t) * 8) - leadingZeros;
153 // This is making the assumption that the size of a byte is 8 bits
154 // and that sizeof(uint32_t)'s implementation-defined behavior is 4.
155 int mipLevelCount = significantBits;
156
157 // SkMipmap does not include the base mip level.
158 // For example, it contains levels 1-x instead of 0-x.
159 // This is because the image used to create SkMipmap is the base level.
160 // So subtract 1 from the mip level count.
161 if (mipLevelCount > 0) {
162 --mipLevelCount;
163 }
164
165 return mipLevelCount;
166}
167
168SkISize SkMipmap::ComputeLevelSize(int baseWidth, int baseHeight, int level) {
169 if (baseWidth < 1 || baseHeight < 1) {
170 return SkISize::Make(0, 0);
171 }
172
173 int maxLevelCount = ComputeLevelCount(baseWidth, baseHeight);
174 if (level >= maxLevelCount || level < 0) {
175 return SkISize::Make(0, 0);
176 }
177 // OpenGL's spec requires that each mipmap level have height/width equal to
178 // max(1, floor(original_height / 2^i)
179 // (or original_width) where i is the mipmap level.
180
181 // SkMipmap does not include the base mip level.
182 // For example, it contains levels 1-x instead of 0-x.
183 // This is because the image used to create SkMipmap is the base level.
184 // So subtract 1 from the mip level to get the index stored by SkMipmap.
185 int width = std::max(1, baseWidth >> (level + 1));
186 int height = std::max(1, baseHeight >> (level + 1));
187
188 return SkISize::Make(width, height);
189}
190
191///////////////////////////////////////////////////////////////////////////////
192
193// Returns fractional level value. floor(level) is the index of the larger level.
194// < 0 means failure.
196 SkASSERT(scaleSize.width() >= 0 && scaleSize.height() >= 0);
197
198#ifndef SK_SUPPORT_LEGACY_ANISOTROPIC_MIPMAP_SCALE
199 // Use the smallest scale to match the GPU impl.
200 const float scale = std::min(scaleSize.width(), scaleSize.height());
201#else
202 // Ideally we'd pick the smaller scale, to match Ganesh. But ignoring one of the
203 // scales can produce some atrocious results, so for now we use the geometric mean.
204 // (https://bugs.chromium.org/p/skia/issues/detail?id=4863)
205 const float scale = std::sqrt(scaleSize.width() * scaleSize.height());
206#endif
207
208 if (scale >= SK_Scalar1 || scale <= 0 || !SkIsFinite(scale)) {
209 return -1;
210 }
211
212 // The -0.5 bias here is to emulate GPU's sharpen mipmap option.
213 float L = std::max(-SkScalarLog2(scale) - 0.5f, 0.f);
214 if (!SkIsFinite(L)) {
215 return -1;
216 }
217 return L;
218}
219
220bool SkMipmap::extractLevel(SkSize scaleSize, Level* levelPtr) const {
221 if (nullptr == fLevels) {
222 return false;
223 }
224
225 float L = ComputeLevel(scaleSize);
227 if (level <= 0) {
228 return false;
229 }
230
231 if (level > fCount) {
232 level = fCount;
233 }
234 if (levelPtr) {
235 *levelPtr = fLevels[level - 1];
236 // need to augment with our colorspace
237 levelPtr->fPixmap.setColorSpace(fCS);
238 }
239 return true;
240}
241
243 if (nullptr == fLevels) {
244 return false;
245 }
246
247 const SkISize dimension = root.dimensions();
248 if (dimension.width() <= 1 && dimension.height() <= 1) {
249 return false;
250 }
251
252 if (fLevels[0].fPixmap. width() != std::max(1, dimension. width() >> 1) ||
253 fLevels[0].fPixmap.height() != std::max(1, dimension.height() >> 1)) {
254 return false;
255 }
256
257 for (int i = 0; i < this->countLevels(); ++i) {
258 if (fLevels[i].fPixmap.colorType() != root.colorType() ||
259 fLevels[i].fPixmap.alphaType() != root.alphaType()) {
260 return false;
261 }
262 }
263 return true;
264}
265
266// Helper which extracts a pixmap from the src bitmap
267//
269 SkPixmap srcPixmap;
270 if (!src.peekPixels(&srcPixmap)) {
271 return nullptr;
272 }
273 return Build(srcPixmap, fact);
274}
275
277 return fCount;
278}
279
280bool SkMipmap::getLevel(int index, Level* levelPtr) const {
281 if (nullptr == fLevels) {
282 return false;
283 }
284 if (index < 0) {
285 return false;
286 }
287 if (index > fCount - 1) {
288 return false;
289 }
290 if (levelPtr) {
291 *levelPtr = fLevels[index];
292 // need to augment with our colorspace
293 levelPtr->fPixmap.setColorSpace(fCS);
294 }
295 return true;
296}
static constexpr bool SkIsAlign8(T x)
Definition: SkAlign.h:21
SkAlphaType
Definition: SkAlphaType.h:26
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkColorType
Definition: SkColorType.h:19
static bool SkIsFinite(T x, Pack... values)
#define sk_float_round2int(x)
static size_t SkColorTypeMinRowBytes(SkColorType ct, int width)
static void * sk_malloc_canfail(size_t size)
Definition: SkMalloc.h:93
static int SkCLZ(uint32_t mask)
Definition: SkMathPriv.h:186
static int64_t sk_64_mul(int64_t a, int64_t b)
Definition: SkMath.h:33
SkDiscardableMemory *(* SkDiscardableFactoryProc)(size_t bytes)
Definition: SkMipmap.h:24
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
#define SK_Scalar1
Definition: SkScalar.h:18
#define SkIntToScalar(x)
Definition: SkScalar.h:57
#define SkScalarLog2(x)
Definition: SkScalar.h:53
constexpr uint32_t SkToU32(S x)
Definition: SkTo.h:26
void * writable_data()
Definition: SkCachedData.h:28
size_t size() const
Definition: SkCachedData.h:25
static SkMipmap * Build(const SkPixmap &src, SkDiscardableFactoryProc, bool computeContents=true)
Definition: SkMipmap.cpp:45
static float ComputeLevel(SkSize scaleSize)
Definition: SkMipmap.cpp:195
bool validForRootLevel(const SkImageInfo &) const
Definition: SkMipmap.cpp:242
static SkISize ComputeLevelSize(int baseWidth, int baseHeight, int level)
Definition: SkMipmap.cpp:168
~SkMipmap() override
static std::unique_ptr< SkMipmapDownSampler > MakeDownSampler(const SkPixmap &)
bool extractLevel(SkSize scale, Level *) const
Definition: SkMipmap.cpp:220
int countLevels() const
Definition: SkMipmap.cpp:276
bool getLevel(int index, Level *) const
Definition: SkMipmap.cpp:280
static int ComputeLevelCount(int baseWidth, int baseHeight)
Definition: SkMipmap.cpp:134
void setColorSpace(sk_sp< SkColorSpace > colorSpace)
Definition: SkPixmap.cpp:57
SkAlphaType alphaType() const
Definition: SkPixmap.h:175
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
void * malloc(size_t size)
Definition: allocation.cc:19
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
string root
Definition: scale_cpu.py:20
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition: SkVx.h:706
int32_t height
int32_t width
const Scalar scale
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
int32_t fHeight
Definition: SkSize.h:18
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
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
SkSize fScale
Definition: SkMipmap.h:72
SkPixmap fPixmap
Definition: SkMipmap.h:71
Definition: SkSize.h:52
static constexpr SkSize Make(SkScalar w, SkScalar h)
Definition: SkSize.h:56
SkScalar width() const
Definition: SkSize.h:76
SkScalar height() const
Definition: SkSize.h:77