| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkMipMap.h" | 8 #include "SkMipMap.h" |
| 9 #include "SkBitmap.h" | 9 #include "SkBitmap.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| 11 | 11 |
| 12 #ifdef SK_SUPPORT_LEGACY_MIPLEVEL_BUILDER | |
| 13 | |
| 14 static void downsample32_nocheck(void* dst, int, int, const void* srcPtr, const
SkPixmap& srcPM) { | |
| 15 const uint32_t* p = static_cast<const uint32_t*>(srcPtr); | |
| 16 const uint32_t* baseP = p; | |
| 17 uint32_t c, ag, rb; | |
| 18 | |
| 19 c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF; | |
| 20 p += 1; | |
| 21 | |
| 22 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
| 23 | |
| 24 p = baseP; | |
| 25 p += srcPM.rowBytes() >> 2; | |
| 26 | |
| 27 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
| 28 p += 1; | |
| 29 | |
| 30 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
| 31 | |
| 32 *(uint32_t*)dst = ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00); | |
| 33 } | |
| 34 | |
| 35 static void downsample32_check(void* dst, int x, int y, const void* srcPtr, cons
t SkPixmap& srcPM) { | |
| 36 const uint32_t* p = static_cast<const uint32_t*>(srcPtr); | |
| 37 const uint32_t* baseP = p; | |
| 38 | |
| 39 x <<= 1; | |
| 40 y <<= 1; | |
| 41 SkASSERT(srcPM.addr32(x, y) == p); | |
| 42 | |
| 43 SkPMColor c, ag, rb; | |
| 44 | |
| 45 c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF; | |
| 46 if (x < srcPM.width() - 1) { | |
| 47 p += 1; | |
| 48 } | |
| 49 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
| 50 | |
| 51 p = baseP; | |
| 52 if (y < srcPM.height() - 1) { | |
| 53 p += srcPM.rowBytes() >> 2; | |
| 54 } | |
| 55 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
| 56 if (x < srcPM.width() - 1) { | |
| 57 p += 1; | |
| 58 } | |
| 59 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
| 60 | |
| 61 *((uint32_t*)dst) = ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00); | |
| 62 } | |
| 63 | |
| 64 static inline uint32_t expand16(U16CPU c) { | |
| 65 return (c & ~SK_G16_MASK_IN_PLACE) | ((c & SK_G16_MASK_IN_PLACE) << 16); | |
| 66 } | |
| 67 | |
| 68 // returns dirt in the top 16bits, but we don't care, since we only | |
| 69 // store the low 16bits. | |
| 70 static inline U16CPU pack16(uint32_t c) { | |
| 71 return (c & ~SK_G16_MASK_IN_PLACE) | ((c >> 16) & SK_G16_MASK_IN_PLACE); | |
| 72 } | |
| 73 | |
| 74 static void downsample16(void* dst, int x, int y, const void* srcPtr, const SkPi
xmap& srcPM) { | |
| 75 const uint16_t* p = static_cast<const uint16_t*>(srcPtr); | |
| 76 const uint16_t* baseP = p; | |
| 77 | |
| 78 x <<= 1; | |
| 79 y <<= 1; | |
| 80 SkASSERT(srcPM.addr16(x, y) == p); | |
| 81 | |
| 82 SkPMColor c; | |
| 83 | |
| 84 c = expand16(*p); | |
| 85 if (x < srcPM.width() - 1) { | |
| 86 p += 1; | |
| 87 } | |
| 88 c += expand16(*p); | |
| 89 | |
| 90 p = baseP; | |
| 91 if (y < srcPM.height() - 1) { | |
| 92 p += srcPM.rowBytes() >> 1; | |
| 93 } | |
| 94 c += expand16(*p); | |
| 95 if (x < srcPM.width() - 1) { | |
| 96 p += 1; | |
| 97 } | |
| 98 c += expand16(*p); | |
| 99 | |
| 100 *((uint16_t*)dst) = (uint16_t)pack16(c >> 2); | |
| 101 } | |
| 102 | |
| 103 static uint32_t expand4444(U16CPU c) { | |
| 104 return (c & 0xF0F) | ((c & ~0xF0F) << 12); | |
| 105 } | |
| 106 | |
| 107 static U16CPU collaps4444(uint32_t c) { | |
| 108 return (c & 0xF0F) | ((c >> 12) & ~0xF0F); | |
| 109 } | |
| 110 | |
| 111 static void downsample4444(void* dst, int x, int y, const void* srcPtr, const Sk
Pixmap& srcPM) { | |
| 112 const uint16_t* p = static_cast<const uint16_t*>(srcPtr); | |
| 113 const uint16_t* baseP = p; | |
| 114 | |
| 115 x <<= 1; | |
| 116 y <<= 1; | |
| 117 SkASSERT(srcPM.addr16(x, y) == p); | |
| 118 | |
| 119 uint32_t c; | |
| 120 | |
| 121 c = expand4444(*p); | |
| 122 if (x < srcPM.width() - 1) { | |
| 123 p += 1; | |
| 124 } | |
| 125 c += expand4444(*p); | |
| 126 | |
| 127 p = baseP; | |
| 128 if (y < srcPM.height() - 1) { | |
| 129 p += srcPM.rowBytes() >> 1; | |
| 130 } | |
| 131 c += expand4444(*p); | |
| 132 if (x < srcPM.width() - 1) { | |
| 133 p += 1; | |
| 134 } | |
| 135 c += expand4444(*p); | |
| 136 | |
| 137 *((uint16_t*)dst) = (uint16_t)collaps4444(c >> 2); | |
| 138 } | |
| 139 | |
| 140 static void downsample8_nocheck(void* dst, int, int, const void* srcPtr, const S
kPixmap& srcPM) { | |
| 141 const size_t rb = srcPM.rowBytes(); | |
| 142 const uint8_t* p = static_cast<const uint8_t*>(srcPtr); | |
| 143 *(uint8_t*)dst = (p[0] + p[1] + p[rb] + p[rb + 1]) >> 2; | |
| 144 } | |
| 145 | |
| 146 static void downsample8_check(void* dst, int x, int y, const void* srcPtr, const
SkPixmap& srcPM) { | |
| 147 const uint8_t* p = static_cast<const uint8_t*>(srcPtr); | |
| 148 const uint8_t* baseP = p; | |
| 149 | |
| 150 x <<= 1; | |
| 151 y <<= 1; | |
| 152 SkASSERT(srcPM.addr8(x, y) == p); | |
| 153 | |
| 154 unsigned c = *p; | |
| 155 if (x < srcPM.width() - 1) { | |
| 156 p += 1; | |
| 157 } | |
| 158 c += *p; | |
| 159 | |
| 160 p = baseP; | |
| 161 if (y < srcPM.height() - 1) { | |
| 162 p += srcPM.rowBytes(); | |
| 163 } | |
| 164 c += *p; | |
| 165 if (x < srcPM.width() - 1) { | |
| 166 p += 1; | |
| 167 } | |
| 168 c += *p; | |
| 169 | |
| 170 *(uint8_t*)dst = c >> 2; | |
| 171 } | |
| 172 | |
| 173 size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) { | |
| 174 if (levelCount < 0) { | |
| 175 return 0; | |
| 176 } | |
| 177 int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize; | |
| 178 if (!sk_64_isS32(size)) { | |
| 179 return 0; | |
| 180 } | |
| 181 return sk_64_asS32(size); | |
| 182 } | |
| 183 | |
| 184 typedef void SkDownSampleProc(void*, int x, int y, const void* srcPtr, const SkP
ixmap& srcPM); | |
| 185 | |
| 186 SkMipMap* SkMipMap::Build(const SkPixmap& src, SkDiscardableFactoryProc fact) { | |
| 187 SkDownSampleProc* proc_nocheck, *proc_check; | |
| 188 | |
| 189 const SkColorType ct = src.colorType(); | |
| 190 const SkAlphaType at = src.alphaType(); | |
| 191 switch (ct) { | |
| 192 case kRGBA_8888_SkColorType: | |
| 193 case kBGRA_8888_SkColorType: | |
| 194 proc_check = downsample32_check; | |
| 195 proc_nocheck = downsample32_nocheck; | |
| 196 break; | |
| 197 case kRGB_565_SkColorType: | |
| 198 proc_check = downsample16; | |
| 199 proc_nocheck = proc_check; | |
| 200 break; | |
| 201 case kARGB_4444_SkColorType: | |
| 202 proc_check = downsample4444; | |
| 203 proc_nocheck = proc_check; | |
| 204 break; | |
| 205 case kAlpha_8_SkColorType: | |
| 206 case kGray_8_SkColorType: | |
| 207 proc_check = downsample8_check; | |
| 208 proc_nocheck = downsample8_nocheck; | |
| 209 break; | |
| 210 default: | |
| 211 return nullptr; // don't build mipmaps for any other colortypes (yet
) | |
| 212 } | |
| 213 | |
| 214 // whip through our loop to compute the exact size needed | |
| 215 size_t size = 0; | |
| 216 int countLevels = 0; | |
| 217 { | |
| 218 int width = src.width(); | |
| 219 int height = src.height(); | |
| 220 for (;;) { | |
| 221 width >>= 1; | |
| 222 height >>= 1; | |
| 223 if (0 == width || 0 == height) { | |
| 224 break; | |
| 225 } | |
| 226 size += SkColorTypeMinRowBytes(ct, width) * height; | |
| 227 countLevels += 1; | |
| 228 } | |
| 229 } | |
| 230 if (0 == countLevels) { | |
| 231 return nullptr; | |
| 232 } | |
| 233 | |
| 234 size_t storageSize = SkMipMap::AllocLevelsSize(countLevels, size); | |
| 235 if (0 == storageSize) { | |
| 236 return nullptr; | |
| 237 } | |
| 238 | |
| 239 SkMipMap* mipmap; | |
| 240 if (fact) { | |
| 241 SkDiscardableMemory* dm = fact(storageSize); | |
| 242 if (nullptr == dm) { | |
| 243 return nullptr; | |
| 244 } | |
| 245 mipmap = new SkMipMap(storageSize, dm); | |
| 246 } else { | |
| 247 mipmap = new SkMipMap(sk_malloc_throw(storageSize), storageSize); | |
| 248 } | |
| 249 | |
| 250 // init | |
| 251 mipmap->fCount = countLevels; | |
| 252 mipmap->fLevels = (Level*)mipmap->writable_data(); | |
| 253 | |
| 254 Level* levels = mipmap->fLevels; | |
| 255 uint8_t* baseAddr = (uint8_t*)&levels[countLevels]; | |
| 256 uint8_t* addr = baseAddr; | |
| 257 int width = src.width(); | |
| 258 int height = src.height(); | |
| 259 uint32_t rowBytes; | |
| 260 SkPixmap srcPM(src); | |
| 261 | |
| 262 for (int i = 0; i < countLevels; ++i) { | |
| 263 width >>= 1; | |
| 264 height >>= 1; | |
| 265 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); | |
| 266 | |
| 267 levels[i].fPixmap = SkPixmap(SkImageInfo::Make(width, height, ct, at), a
ddr, rowBytes); | |
| 268 levels[i].fScale = (float)width / src.width(); | |
| 269 | |
| 270 SkPixmap dstPM(SkImageInfo::Make(width, height, ct, at), addr, rowBytes)
; | |
| 271 | |
| 272 const int widthEven = width & ~1; | |
| 273 const int heightEven = height & ~1; | |
| 274 const size_t pixelSize = srcPM.info().bytesPerPixel(); | |
| 275 | |
| 276 const void* srcBasePtr = srcPM.addr(); | |
| 277 void* dstBasePtr = dstPM.writable_addr(); | |
| 278 for (int y = 0; y < heightEven; y++) { | |
| 279 const void* srcPtr = srcBasePtr; | |
| 280 void* dstPtr = dstBasePtr; | |
| 281 for (int x = 0; x < widthEven; x++) { | |
| 282 proc_nocheck(dstPtr, x, y, srcPtr, srcPM); | |
| 283 srcPtr = (char*)srcPtr + pixelSize * 2; | |
| 284 dstPtr = (char*)dstPtr + pixelSize; | |
| 285 } | |
| 286 if (width & 1) { | |
| 287 proc_check(dstPtr, widthEven, y, srcPtr, srcPM); | |
| 288 } | |
| 289 | |
| 290 srcBasePtr = (char*)srcBasePtr + srcPM.rowBytes() * 2; | |
| 291 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); | |
| 292 } | |
| 293 if (height & 1) { | |
| 294 const void* srcPtr = srcBasePtr; | |
| 295 void* dstPtr = dstBasePtr; | |
| 296 for (int x = 0; x < width; x++) { | |
| 297 proc_check(dstPtr, x, heightEven, srcPtr, srcPM); | |
| 298 srcPtr = (char*)srcPtr + pixelSize * 2; | |
| 299 dstPtr = (char*)dstPtr + pixelSize; | |
| 300 } | |
| 301 } | |
| 302 srcPM = dstPM; | |
| 303 addr += height * rowBytes; | |
| 304 } | |
| 305 SkASSERT(addr == baseAddr + size); | |
| 306 | |
| 307 return mipmap; | |
| 308 } | |
| 309 | |
| 310 #else // new technique that handles odd dimensions better | |
| 311 | |
| 312 // | 12 // |
| 313 // ColorTypeFilter is the "Type" we pass to some downsample template functions. | 13 // ColorTypeFilter is the "Type" we pass to some downsample template functions. |
| 314 // It controls how we expand a pixel into a large type, with space between each
component, | 14 // It controls how we expand a pixel into a large type, with space between each
component, |
| 315 // so we can then perform our simple filter (either box or triangle) and store t
he intermediates | 15 // so we can then perform our simple filter (either box or triangle) and store t
he intermediates |
| 316 // in the expanded type. | 16 // in the expanded type. |
| 317 // | 17 // |
| 318 | 18 |
| 319 struct ColorTypeFilter_8888 { | 19 struct ColorTypeFilter_8888 { |
| 320 typedef uint32_t Type; | 20 typedef uint32_t Type; |
| 321 static uint64_t Expand(uint32_t x) { | 21 static uint64_t Expand(uint32_t x) { |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 597 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows | 297 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows |
| 598 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); | 298 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); |
| 599 } | 299 } |
| 600 srcPM = dstPM; | 300 srcPM = dstPM; |
| 601 addr += height * rowBytes; | 301 addr += height * rowBytes; |
| 602 } | 302 } |
| 603 SkASSERT(addr == baseAddr + size); | 303 SkASSERT(addr == baseAddr + size); |
| 604 | 304 |
| 605 return mipmap; | 305 return mipmap; |
| 606 } | 306 } |
| 607 #endif | |
| 608 | 307 |
| 609 /////////////////////////////////////////////////////////////////////////////// | 308 /////////////////////////////////////////////////////////////////////////////// |
| 610 | 309 |
| 611 bool SkMipMap::extractLevel(SkScalar scale, Level* levelPtr) const { | 310 bool SkMipMap::extractLevel(SkScalar scale, Level* levelPtr) const { |
| 612 if (nullptr == fLevels) { | 311 if (nullptr == fLevels) { |
| 613 return false; | 312 return false; |
| 614 } | 313 } |
| 615 | 314 |
| 616 if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { | 315 if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { |
| 617 return false; | 316 return false; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 648 return nullptr; | 347 return nullptr; |
| 649 } | 348 } |
| 650 const SkPixmap& srcPixmap = srcUnlocker.pixmap(); | 349 const SkPixmap& srcPixmap = srcUnlocker.pixmap(); |
| 651 // Try to catch where we might have returned nullptr for src crbug.com/49281
8 | 350 // Try to catch where we might have returned nullptr for src crbug.com/49281
8 |
| 652 if (nullptr == srcPixmap.addr()) { | 351 if (nullptr == srcPixmap.addr()) { |
| 653 sk_throw(); | 352 sk_throw(); |
| 654 } | 353 } |
| 655 return Build(srcPixmap, fact); | 354 return Build(srcPixmap, fact); |
| 656 } | 355 } |
| 657 | 356 |
| OLD | NEW |