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
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkColorType.h"
12 #include "include/core/SkTypes.h"
13 #include "include/private/base/SkTo.h"
14 #include "src/base/SkMathPriv.h"
15 #include "src/core/SkImageInfoPriv.h"
16 #include "src/core/SkMipmapBuilder.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
SkMipmap(void * malloc,size_t size)29 SkMipmap::SkMipmap(void* malloc, size_t size) : SkCachedData(malloc, size) {}
SkMipmap(size_t size,SkDiscardableMemory * dm)30 SkMipmap::SkMipmap(size_t size, SkDiscardableMemory* dm) : SkCachedData(size, dm) {}
31
32 SkMipmap::~SkMipmap() = default;
33
AllocLevelsSize(int levelCount,size_t pixelSize)34 size_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
Build(const SkPixmap & src,SkDiscardableFactoryProc fact,bool computeContents)45 SkMipmap* SkMipmap::Build(const SkPixmap& src, SkDiscardableFactoryProc fact,
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
ComputeLevelCount(int baseWidth,int baseHeight)134 int 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
ComputeLevelSize(int baseWidth,int baseHeight,int level)168 SkISize 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.
ComputeLevel(SkSize scaleSize)195 float SkMipmap::ComputeLevel(SkSize scaleSize) {
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
extractLevel(SkSize scaleSize,Level * levelPtr) const220 bool SkMipmap::extractLevel(SkSize scaleSize, Level* levelPtr) const {
221 if (nullptr == fLevels) {
222 return false;
223 }
224
225 float L = ComputeLevel(scaleSize);
226 int level = sk_float_round2int(L);
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
validForRootLevel(const SkImageInfo & root) const242 bool SkMipmap::validForRootLevel(const SkImageInfo& root) const {
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 //
Build(const SkBitmap & src,SkDiscardableFactoryProc fact)268 SkMipmap* SkMipmap::Build(const SkBitmap& src, SkDiscardableFactoryProc fact) {
269 SkPixmap srcPixmap;
270 if (!src.peekPixels(&srcPixmap)) {
271 return nullptr;
272 }
273 return Build(srcPixmap, fact);
274 }
275
countLevels() const276 int SkMipmap::countLevels() const {
277 return fCount;
278 }
279
getLevel(int index,Level * levelPtr) const280 bool 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 }
297