1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2013 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 "include/core/SkBitmap.h" 9cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 10cb93a386Sopenharmony_ci#include "include/private/SkColorData.h" 11cb93a386Sopenharmony_ci#include "include/private/SkHalf.h" 12cb93a386Sopenharmony_ci#include "include/private/SkImageInfoPriv.h" 13cb93a386Sopenharmony_ci#include "include/private/SkNx.h" 14cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 15cb93a386Sopenharmony_ci#include "include/private/SkVx.h" 16cb93a386Sopenharmony_ci#include "src/core/SkMathPriv.h" 17cb93a386Sopenharmony_ci#include "src/core/SkMipmap.h" 18cb93a386Sopenharmony_ci#include "src/core/SkMipmapBuilder.h" 19cb93a386Sopenharmony_ci#include <new> 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci// 22cb93a386Sopenharmony_ci// ColorTypeFilter is the "Type" we pass to some downsample template functions. 23cb93a386Sopenharmony_ci// It controls how we expand a pixel into a large type, with space between each component, 24cb93a386Sopenharmony_ci// so we can then perform our simple filter (either box or triangle) and store the intermediates 25cb93a386Sopenharmony_ci// in the expanded type. 26cb93a386Sopenharmony_ci// 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_cistruct ColorTypeFilter_8888 { 29cb93a386Sopenharmony_ci typedef uint32_t Type; 30cb93a386Sopenharmony_ci static Sk4h Expand(uint32_t x) { 31cb93a386Sopenharmony_ci return SkNx_cast<uint16_t>(Sk4b::Load(&x)); 32cb93a386Sopenharmony_ci } 33cb93a386Sopenharmony_ci static uint32_t Compact(const Sk4h& x) { 34cb93a386Sopenharmony_ci uint32_t r; 35cb93a386Sopenharmony_ci SkNx_cast<uint8_t>(x).store(&r); 36cb93a386Sopenharmony_ci return r; 37cb93a386Sopenharmony_ci } 38cb93a386Sopenharmony_ci}; 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_cistruct ColorTypeFilter_565 { 41cb93a386Sopenharmony_ci typedef uint16_t Type; 42cb93a386Sopenharmony_ci static uint32_t Expand(uint16_t x) { 43cb93a386Sopenharmony_ci return (x & ~SK_G16_MASK_IN_PLACE) | ((x & SK_G16_MASK_IN_PLACE) << 16); 44cb93a386Sopenharmony_ci } 45cb93a386Sopenharmony_ci static uint16_t Compact(uint32_t x) { 46cb93a386Sopenharmony_ci return ((x & ~SK_G16_MASK_IN_PLACE) & 0xFFFF) | ((x >> 16) & SK_G16_MASK_IN_PLACE); 47cb93a386Sopenharmony_ci } 48cb93a386Sopenharmony_ci}; 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_cistruct ColorTypeFilter_4444 { 51cb93a386Sopenharmony_ci typedef uint16_t Type; 52cb93a386Sopenharmony_ci static uint32_t Expand(uint16_t x) { 53cb93a386Sopenharmony_ci return (x & 0xF0F) | ((x & ~0xF0F) << 12); 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci static uint16_t Compact(uint32_t x) { 56cb93a386Sopenharmony_ci return (x & 0xF0F) | ((x >> 12) & ~0xF0F); 57cb93a386Sopenharmony_ci } 58cb93a386Sopenharmony_ci}; 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_cistruct ColorTypeFilter_8 { 61cb93a386Sopenharmony_ci typedef uint8_t Type; 62cb93a386Sopenharmony_ci static unsigned Expand(unsigned x) { 63cb93a386Sopenharmony_ci return x; 64cb93a386Sopenharmony_ci } 65cb93a386Sopenharmony_ci static uint8_t Compact(unsigned x) { 66cb93a386Sopenharmony_ci return (uint8_t)x; 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci}; 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_cistruct ColorTypeFilter_Alpha_F16 { 71cb93a386Sopenharmony_ci typedef uint16_t Type; 72cb93a386Sopenharmony_ci static Sk4f Expand(uint16_t x) { 73cb93a386Sopenharmony_ci return SkHalfToFloat_finite_ftz((uint64_t) x); // expand out to four lanes 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci static uint16_t Compact(const Sk4f& x) { 77cb93a386Sopenharmony_ci uint64_t r; 78cb93a386Sopenharmony_ci SkFloatToHalf_finite_ftz(x).store(&r); 79cb93a386Sopenharmony_ci return r & 0xFFFF; // but ignore the extra 3 here 80cb93a386Sopenharmony_ci } 81cb93a386Sopenharmony_ci}; 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_cistruct ColorTypeFilter_RGBA_F16 { 84cb93a386Sopenharmony_ci typedef uint64_t Type; // SkHalf x4 85cb93a386Sopenharmony_ci static Sk4f Expand(uint64_t x) { 86cb93a386Sopenharmony_ci return SkHalfToFloat_finite_ftz(x); 87cb93a386Sopenharmony_ci } 88cb93a386Sopenharmony_ci static uint64_t Compact(const Sk4f& x) { 89cb93a386Sopenharmony_ci uint64_t r; 90cb93a386Sopenharmony_ci SkFloatToHalf_finite_ftz(x).store(&r); 91cb93a386Sopenharmony_ci return r; 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci}; 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_cistruct ColorTypeFilter_88 { 96cb93a386Sopenharmony_ci typedef uint16_t Type; 97cb93a386Sopenharmony_ci static uint32_t Expand(uint16_t x) { 98cb93a386Sopenharmony_ci return (x & 0xFF) | ((x & ~0xFF) << 8); 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci static uint16_t Compact(uint32_t x) { 101cb93a386Sopenharmony_ci return (x & 0xFF) | ((x >> 8) & ~0xFF); 102cb93a386Sopenharmony_ci } 103cb93a386Sopenharmony_ci}; 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_cistruct ColorTypeFilter_1616 { 106cb93a386Sopenharmony_ci typedef uint32_t Type; 107cb93a386Sopenharmony_ci static uint64_t Expand(uint32_t x) { 108cb93a386Sopenharmony_ci return (x & 0xFFFF) | ((x & ~0xFFFF) << 16); 109cb93a386Sopenharmony_ci } 110cb93a386Sopenharmony_ci static uint16_t Compact(uint64_t x) { 111cb93a386Sopenharmony_ci return (x & 0xFFFF) | ((x >> 16) & ~0xFFFF); 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci}; 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_cistruct ColorTypeFilter_F16F16 { 116cb93a386Sopenharmony_ci typedef uint32_t Type; 117cb93a386Sopenharmony_ci static Sk4f Expand(uint32_t x) { 118cb93a386Sopenharmony_ci return SkHalfToFloat_finite_ftz((uint64_t) x); // expand out to four lanes 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci static uint32_t Compact(const Sk4f& x) { 121cb93a386Sopenharmony_ci uint64_t r; 122cb93a386Sopenharmony_ci SkFloatToHalf_finite_ftz(x).store(&r); 123cb93a386Sopenharmony_ci return (uint32_t) (r & 0xFFFFFFFF); // but ignore the extra 2 here 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci}; 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_cistruct ColorTypeFilter_16161616 { 128cb93a386Sopenharmony_ci typedef uint64_t Type; 129cb93a386Sopenharmony_ci static skvx::Vec<4, uint32_t> Expand(uint64_t x) { 130cb93a386Sopenharmony_ci return skvx::cast<uint32_t>(skvx::Vec<4, uint16_t>::Load(&x)); 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci static uint64_t Compact(const skvx::Vec<4, uint32_t>& x) { 133cb93a386Sopenharmony_ci uint64_t r; 134cb93a386Sopenharmony_ci skvx::cast<uint16_t>(x).store(&r); 135cb93a386Sopenharmony_ci return r; 136cb93a386Sopenharmony_ci } 137cb93a386Sopenharmony_ci}; 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_cistruct ColorTypeFilter_16 { 140cb93a386Sopenharmony_ci typedef uint16_t Type; 141cb93a386Sopenharmony_ci static uint32_t Expand(uint16_t x) { 142cb93a386Sopenharmony_ci return x; 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci static uint16_t Compact(uint32_t x) { 145cb93a386Sopenharmony_ci return (uint16_t) x; 146cb93a386Sopenharmony_ci } 147cb93a386Sopenharmony_ci}; 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_cistruct ColorTypeFilter_1010102 { 150cb93a386Sopenharmony_ci typedef uint32_t Type; 151cb93a386Sopenharmony_ci static uint64_t Expand(uint64_t x) { 152cb93a386Sopenharmony_ci return (((x ) & 0x3ff) ) | 153cb93a386Sopenharmony_ci (((x >> 10) & 0x3ff) << 20) | 154cb93a386Sopenharmony_ci (((x >> 20) & 0x3ff) << 40) | 155cb93a386Sopenharmony_ci (((x >> 30) & 0x3 ) << 60); 156cb93a386Sopenharmony_ci } 157cb93a386Sopenharmony_ci static uint32_t Compact(uint64_t x) { 158cb93a386Sopenharmony_ci return (((x ) & 0x3ff) ) | 159cb93a386Sopenharmony_ci (((x >> 20) & 0x3ff) << 10) | 160cb93a386Sopenharmony_ci (((x >> 40) & 0x3ff) << 20) | 161cb93a386Sopenharmony_ci (((x >> 60) & 0x3 ) << 30); 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci}; 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_citemplate <typename T> T add_121(const T& a, const T& b, const T& c) { 166cb93a386Sopenharmony_ci return a + b + b + c; 167cb93a386Sopenharmony_ci} 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_citemplate <typename T> T shift_right(const T& x, int bits) { 170cb93a386Sopenharmony_ci return x >> bits; 171cb93a386Sopenharmony_ci} 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ciSk4f shift_right(const Sk4f& x, int bits) { 174cb93a386Sopenharmony_ci return x * (1.0f / (1 << bits)); 175cb93a386Sopenharmony_ci} 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_citemplate <typename T> T shift_left(const T& x, int bits) { 178cb93a386Sopenharmony_ci return x << bits; 179cb93a386Sopenharmony_ci} 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ciSk4f shift_left(const Sk4f& x, int bits) { 182cb93a386Sopenharmony_ci return x * (1 << bits); 183cb93a386Sopenharmony_ci} 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci// 186cb93a386Sopenharmony_ci// To produce each mip level, we need to filter down by 1/2 (e.g. 100x100 -> 50,50) 187cb93a386Sopenharmony_ci// If the starting dimension is odd, we floor the size of the lower level (e.g. 101 -> 50) 188cb93a386Sopenharmony_ci// In those (odd) cases, we use a triangle filter, with 1-pixel overlap between samplings, 189cb93a386Sopenharmony_ci// else for even cases, we just use a 2x box filter. 190cb93a386Sopenharmony_ci// 191cb93a386Sopenharmony_ci// This produces 4 possible isotropic filters: 2x2 2x3 3x2 3x3 where WxH indicates the number of 192cb93a386Sopenharmony_ci// src pixels we need to sample in each dimension to produce 1 dst pixel. 193cb93a386Sopenharmony_ci// 194cb93a386Sopenharmony_ci// OpenGL expects a full mipmap stack to contain anisotropic space as well. 195cb93a386Sopenharmony_ci// This means a 100x1 image would continue down to a 50x1 image, 25x1 image... 196cb93a386Sopenharmony_ci// Because of this, we need 4 more anisotropic filters: 1x2, 1x3, 2x1, 3x1. 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_citemplate <typename F> void downsample_1_2(void* dst, const void* src, size_t srcRB, int count) { 199cb93a386Sopenharmony_ci SkASSERT(count > 0); 200cb93a386Sopenharmony_ci auto p0 = static_cast<const typename F::Type*>(src); 201cb93a386Sopenharmony_ci auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); 202cb93a386Sopenharmony_ci auto d = static_cast<typename F::Type*>(dst); 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 205cb93a386Sopenharmony_ci auto c00 = F::Expand(p0[0]); 206cb93a386Sopenharmony_ci auto c10 = F::Expand(p1[0]); 207cb93a386Sopenharmony_ci 208cb93a386Sopenharmony_ci auto c = c00 + c10; 209cb93a386Sopenharmony_ci d[i] = F::Compact(shift_right(c, 1)); 210cb93a386Sopenharmony_ci p0 += 2; 211cb93a386Sopenharmony_ci p1 += 2; 212cb93a386Sopenharmony_ci } 213cb93a386Sopenharmony_ci} 214cb93a386Sopenharmony_ci 215cb93a386Sopenharmony_citemplate <typename F> void downsample_1_3(void* dst, const void* src, size_t srcRB, int count) { 216cb93a386Sopenharmony_ci SkASSERT(count > 0); 217cb93a386Sopenharmony_ci auto p0 = static_cast<const typename F::Type*>(src); 218cb93a386Sopenharmony_ci auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); 219cb93a386Sopenharmony_ci auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); 220cb93a386Sopenharmony_ci auto d = static_cast<typename F::Type*>(dst); 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 223cb93a386Sopenharmony_ci auto c00 = F::Expand(p0[0]); 224cb93a386Sopenharmony_ci auto c10 = F::Expand(p1[0]); 225cb93a386Sopenharmony_ci auto c20 = F::Expand(p2[0]); 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci auto c = add_121(c00, c10, c20); 228cb93a386Sopenharmony_ci d[i] = F::Compact(shift_right(c, 2)); 229cb93a386Sopenharmony_ci p0 += 2; 230cb93a386Sopenharmony_ci p1 += 2; 231cb93a386Sopenharmony_ci p2 += 2; 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci} 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_citemplate <typename F> void downsample_2_1(void* dst, const void* src, size_t srcRB, int count) { 236cb93a386Sopenharmony_ci SkASSERT(count > 0); 237cb93a386Sopenharmony_ci auto p0 = static_cast<const typename F::Type*>(src); 238cb93a386Sopenharmony_ci auto d = static_cast<typename F::Type*>(dst); 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 241cb93a386Sopenharmony_ci auto c00 = F::Expand(p0[0]); 242cb93a386Sopenharmony_ci auto c01 = F::Expand(p0[1]); 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci auto c = c00 + c01; 245cb93a386Sopenharmony_ci d[i] = F::Compact(shift_right(c, 1)); 246cb93a386Sopenharmony_ci p0 += 2; 247cb93a386Sopenharmony_ci } 248cb93a386Sopenharmony_ci} 249cb93a386Sopenharmony_ci 250cb93a386Sopenharmony_citemplate <typename F> void downsample_2_2(void* dst, const void* src, size_t srcRB, int count) { 251cb93a386Sopenharmony_ci SkASSERT(count > 0); 252cb93a386Sopenharmony_ci auto p0 = static_cast<const typename F::Type*>(src); 253cb93a386Sopenharmony_ci auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); 254cb93a386Sopenharmony_ci auto d = static_cast<typename F::Type*>(dst); 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 257cb93a386Sopenharmony_ci auto c00 = F::Expand(p0[0]); 258cb93a386Sopenharmony_ci auto c01 = F::Expand(p0[1]); 259cb93a386Sopenharmony_ci auto c10 = F::Expand(p1[0]); 260cb93a386Sopenharmony_ci auto c11 = F::Expand(p1[1]); 261cb93a386Sopenharmony_ci 262cb93a386Sopenharmony_ci auto c = c00 + c10 + c01 + c11; 263cb93a386Sopenharmony_ci d[i] = F::Compact(shift_right(c, 2)); 264cb93a386Sopenharmony_ci p0 += 2; 265cb93a386Sopenharmony_ci p1 += 2; 266cb93a386Sopenharmony_ci } 267cb93a386Sopenharmony_ci} 268cb93a386Sopenharmony_ci 269cb93a386Sopenharmony_citemplate <typename F> void downsample_2_3(void* dst, const void* src, size_t srcRB, int count) { 270cb93a386Sopenharmony_ci SkASSERT(count > 0); 271cb93a386Sopenharmony_ci auto p0 = static_cast<const typename F::Type*>(src); 272cb93a386Sopenharmony_ci auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); 273cb93a386Sopenharmony_ci auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); 274cb93a386Sopenharmony_ci auto d = static_cast<typename F::Type*>(dst); 275cb93a386Sopenharmony_ci 276cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 277cb93a386Sopenharmony_ci auto c00 = F::Expand(p0[0]); 278cb93a386Sopenharmony_ci auto c01 = F::Expand(p0[1]); 279cb93a386Sopenharmony_ci auto c10 = F::Expand(p1[0]); 280cb93a386Sopenharmony_ci auto c11 = F::Expand(p1[1]); 281cb93a386Sopenharmony_ci auto c20 = F::Expand(p2[0]); 282cb93a386Sopenharmony_ci auto c21 = F::Expand(p2[1]); 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci auto c = add_121(c00, c10, c20) + add_121(c01, c11, c21); 285cb93a386Sopenharmony_ci d[i] = F::Compact(shift_right(c, 3)); 286cb93a386Sopenharmony_ci p0 += 2; 287cb93a386Sopenharmony_ci p1 += 2; 288cb93a386Sopenharmony_ci p2 += 2; 289cb93a386Sopenharmony_ci } 290cb93a386Sopenharmony_ci} 291cb93a386Sopenharmony_ci 292cb93a386Sopenharmony_citemplate <typename F> void downsample_3_1(void* dst, const void* src, size_t srcRB, int count) { 293cb93a386Sopenharmony_ci SkASSERT(count > 0); 294cb93a386Sopenharmony_ci auto p0 = static_cast<const typename F::Type*>(src); 295cb93a386Sopenharmony_ci auto d = static_cast<typename F::Type*>(dst); 296cb93a386Sopenharmony_ci 297cb93a386Sopenharmony_ci auto c02 = F::Expand(p0[0]); 298cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 299cb93a386Sopenharmony_ci auto c00 = c02; 300cb93a386Sopenharmony_ci auto c01 = F::Expand(p0[1]); 301cb93a386Sopenharmony_ci c02 = F::Expand(p0[2]); 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci auto c = add_121(c00, c01, c02); 304cb93a386Sopenharmony_ci d[i] = F::Compact(shift_right(c, 2)); 305cb93a386Sopenharmony_ci p0 += 2; 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci} 308cb93a386Sopenharmony_ci 309cb93a386Sopenharmony_citemplate <typename F> void downsample_3_2(void* dst, const void* src, size_t srcRB, int count) { 310cb93a386Sopenharmony_ci SkASSERT(count > 0); 311cb93a386Sopenharmony_ci auto p0 = static_cast<const typename F::Type*>(src); 312cb93a386Sopenharmony_ci auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); 313cb93a386Sopenharmony_ci auto d = static_cast<typename F::Type*>(dst); 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci // Given pixels: 316cb93a386Sopenharmony_ci // a0 b0 c0 d0 e0 ... 317cb93a386Sopenharmony_ci // a1 b1 c1 d1 e1 ... 318cb93a386Sopenharmony_ci // We want: 319cb93a386Sopenharmony_ci // (a0 + 2*b0 + c0 + a1 + 2*b1 + c1) / 8 320cb93a386Sopenharmony_ci // (c0 + 2*d0 + e0 + c1 + 2*d1 + e1) / 8 321cb93a386Sopenharmony_ci // ... 322cb93a386Sopenharmony_ci 323cb93a386Sopenharmony_ci auto c0 = F::Expand(p0[0]); 324cb93a386Sopenharmony_ci auto c1 = F::Expand(p1[0]); 325cb93a386Sopenharmony_ci auto c = c0 + c1; 326cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 327cb93a386Sopenharmony_ci auto a = c; 328cb93a386Sopenharmony_ci 329cb93a386Sopenharmony_ci auto b0 = F::Expand(p0[1]); 330cb93a386Sopenharmony_ci auto b1 = F::Expand(p1[1]); 331cb93a386Sopenharmony_ci auto b = b0 + b0 + b1 + b1; 332cb93a386Sopenharmony_ci 333cb93a386Sopenharmony_ci c0 = F::Expand(p0[2]); 334cb93a386Sopenharmony_ci c1 = F::Expand(p1[2]); 335cb93a386Sopenharmony_ci c = c0 + c1; 336cb93a386Sopenharmony_ci 337cb93a386Sopenharmony_ci auto sum = a + b + c; 338cb93a386Sopenharmony_ci d[i] = F::Compact(shift_right(sum, 3)); 339cb93a386Sopenharmony_ci p0 += 2; 340cb93a386Sopenharmony_ci p1 += 2; 341cb93a386Sopenharmony_ci } 342cb93a386Sopenharmony_ci} 343cb93a386Sopenharmony_ci 344cb93a386Sopenharmony_citemplate <typename F> void downsample_3_3(void* dst, const void* src, size_t srcRB, int count) { 345cb93a386Sopenharmony_ci SkASSERT(count > 0); 346cb93a386Sopenharmony_ci auto p0 = static_cast<const typename F::Type*>(src); 347cb93a386Sopenharmony_ci auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); 348cb93a386Sopenharmony_ci auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); 349cb93a386Sopenharmony_ci auto d = static_cast<typename F::Type*>(dst); 350cb93a386Sopenharmony_ci 351cb93a386Sopenharmony_ci // Given pixels: 352cb93a386Sopenharmony_ci // a0 b0 c0 d0 e0 ... 353cb93a386Sopenharmony_ci // a1 b1 c1 d1 e1 ... 354cb93a386Sopenharmony_ci // a2 b2 c2 d2 e2 ... 355cb93a386Sopenharmony_ci // We want: 356cb93a386Sopenharmony_ci // (a0 + 2*b0 + c0 + 2*a1 + 4*b1 + 2*c1 + a2 + 2*b2 + c2) / 16 357cb93a386Sopenharmony_ci // (c0 + 2*d0 + e0 + 2*c1 + 4*d1 + 2*e1 + c2 + 2*d2 + e2) / 16 358cb93a386Sopenharmony_ci // ... 359cb93a386Sopenharmony_ci 360cb93a386Sopenharmony_ci auto c0 = F::Expand(p0[0]); 361cb93a386Sopenharmony_ci auto c1 = F::Expand(p1[0]); 362cb93a386Sopenharmony_ci auto c2 = F::Expand(p2[0]); 363cb93a386Sopenharmony_ci auto c = add_121(c0, c1, c2); 364cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 365cb93a386Sopenharmony_ci auto a = c; 366cb93a386Sopenharmony_ci 367cb93a386Sopenharmony_ci auto b0 = F::Expand(p0[1]); 368cb93a386Sopenharmony_ci auto b1 = F::Expand(p1[1]); 369cb93a386Sopenharmony_ci auto b2 = F::Expand(p2[1]); 370cb93a386Sopenharmony_ci auto b = shift_left(add_121(b0, b1, b2), 1); 371cb93a386Sopenharmony_ci 372cb93a386Sopenharmony_ci c0 = F::Expand(p0[2]); 373cb93a386Sopenharmony_ci c1 = F::Expand(p1[2]); 374cb93a386Sopenharmony_ci c2 = F::Expand(p2[2]); 375cb93a386Sopenharmony_ci c = add_121(c0, c1, c2); 376cb93a386Sopenharmony_ci 377cb93a386Sopenharmony_ci auto sum = a + b + c; 378cb93a386Sopenharmony_ci d[i] = F::Compact(shift_right(sum, 4)); 379cb93a386Sopenharmony_ci p0 += 2; 380cb93a386Sopenharmony_ci p1 += 2; 381cb93a386Sopenharmony_ci p2 += 2; 382cb93a386Sopenharmony_ci } 383cb93a386Sopenharmony_ci} 384cb93a386Sopenharmony_ci 385cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 386cb93a386Sopenharmony_ci 387cb93a386Sopenharmony_cisize_t SkMipmap::AllocLevelsSize(int levelCount, size_t pixelSize) { 388cb93a386Sopenharmony_ci if (levelCount < 0) { 389cb93a386Sopenharmony_ci return 0; 390cb93a386Sopenharmony_ci } 391cb93a386Sopenharmony_ci int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize; 392cb93a386Sopenharmony_ci if (!SkTFitsIn<int32_t>(size)) { 393cb93a386Sopenharmony_ci return 0; 394cb93a386Sopenharmony_ci } 395cb93a386Sopenharmony_ci return SkTo<int32_t>(size); 396cb93a386Sopenharmony_ci} 397cb93a386Sopenharmony_ci 398cb93a386Sopenharmony_ciSkMipmap* SkMipmap::Build(const SkPixmap& src, SkDiscardableFactoryProc fact, 399cb93a386Sopenharmony_ci bool computeContents) { 400cb93a386Sopenharmony_ci typedef void FilterProc(void*, const void* srcPtr, size_t srcRB, int count); 401cb93a386Sopenharmony_ci 402cb93a386Sopenharmony_ci FilterProc* proc_1_2 = nullptr; 403cb93a386Sopenharmony_ci FilterProc* proc_1_3 = nullptr; 404cb93a386Sopenharmony_ci FilterProc* proc_2_1 = nullptr; 405cb93a386Sopenharmony_ci FilterProc* proc_2_2 = nullptr; 406cb93a386Sopenharmony_ci FilterProc* proc_2_3 = nullptr; 407cb93a386Sopenharmony_ci FilterProc* proc_3_1 = nullptr; 408cb93a386Sopenharmony_ci FilterProc* proc_3_2 = nullptr; 409cb93a386Sopenharmony_ci FilterProc* proc_3_3 = nullptr; 410cb93a386Sopenharmony_ci 411cb93a386Sopenharmony_ci const SkColorType ct = src.colorType(); 412cb93a386Sopenharmony_ci const SkAlphaType at = src.alphaType(); 413cb93a386Sopenharmony_ci 414cb93a386Sopenharmony_ci switch (ct) { 415cb93a386Sopenharmony_ci case kRGBA_8888_SkColorType: 416cb93a386Sopenharmony_ci case kBGRA_8888_SkColorType: 417cb93a386Sopenharmony_ci proc_1_2 = downsample_1_2<ColorTypeFilter_8888>; 418cb93a386Sopenharmony_ci proc_1_3 = downsample_1_3<ColorTypeFilter_8888>; 419cb93a386Sopenharmony_ci proc_2_1 = downsample_2_1<ColorTypeFilter_8888>; 420cb93a386Sopenharmony_ci proc_2_2 = downsample_2_2<ColorTypeFilter_8888>; 421cb93a386Sopenharmony_ci proc_2_3 = downsample_2_3<ColorTypeFilter_8888>; 422cb93a386Sopenharmony_ci proc_3_1 = downsample_3_1<ColorTypeFilter_8888>; 423cb93a386Sopenharmony_ci proc_3_2 = downsample_3_2<ColorTypeFilter_8888>; 424cb93a386Sopenharmony_ci proc_3_3 = downsample_3_3<ColorTypeFilter_8888>; 425cb93a386Sopenharmony_ci break; 426cb93a386Sopenharmony_ci case kRGB_565_SkColorType: 427cb93a386Sopenharmony_ci proc_1_2 = downsample_1_2<ColorTypeFilter_565>; 428cb93a386Sopenharmony_ci proc_1_3 = downsample_1_3<ColorTypeFilter_565>; 429cb93a386Sopenharmony_ci proc_2_1 = downsample_2_1<ColorTypeFilter_565>; 430cb93a386Sopenharmony_ci proc_2_2 = downsample_2_2<ColorTypeFilter_565>; 431cb93a386Sopenharmony_ci proc_2_3 = downsample_2_3<ColorTypeFilter_565>; 432cb93a386Sopenharmony_ci proc_3_1 = downsample_3_1<ColorTypeFilter_565>; 433cb93a386Sopenharmony_ci proc_3_2 = downsample_3_2<ColorTypeFilter_565>; 434cb93a386Sopenharmony_ci proc_3_3 = downsample_3_3<ColorTypeFilter_565>; 435cb93a386Sopenharmony_ci break; 436cb93a386Sopenharmony_ci case kARGB_4444_SkColorType: 437cb93a386Sopenharmony_ci proc_1_2 = downsample_1_2<ColorTypeFilter_4444>; 438cb93a386Sopenharmony_ci proc_1_3 = downsample_1_3<ColorTypeFilter_4444>; 439cb93a386Sopenharmony_ci proc_2_1 = downsample_2_1<ColorTypeFilter_4444>; 440cb93a386Sopenharmony_ci proc_2_2 = downsample_2_2<ColorTypeFilter_4444>; 441cb93a386Sopenharmony_ci proc_2_3 = downsample_2_3<ColorTypeFilter_4444>; 442cb93a386Sopenharmony_ci proc_3_1 = downsample_3_1<ColorTypeFilter_4444>; 443cb93a386Sopenharmony_ci proc_3_2 = downsample_3_2<ColorTypeFilter_4444>; 444cb93a386Sopenharmony_ci proc_3_3 = downsample_3_3<ColorTypeFilter_4444>; 445cb93a386Sopenharmony_ci break; 446cb93a386Sopenharmony_ci case kAlpha_8_SkColorType: 447cb93a386Sopenharmony_ci case kGray_8_SkColorType: 448cb93a386Sopenharmony_ci proc_1_2 = downsample_1_2<ColorTypeFilter_8>; 449cb93a386Sopenharmony_ci proc_1_3 = downsample_1_3<ColorTypeFilter_8>; 450cb93a386Sopenharmony_ci proc_2_1 = downsample_2_1<ColorTypeFilter_8>; 451cb93a386Sopenharmony_ci proc_2_2 = downsample_2_2<ColorTypeFilter_8>; 452cb93a386Sopenharmony_ci proc_2_3 = downsample_2_3<ColorTypeFilter_8>; 453cb93a386Sopenharmony_ci proc_3_1 = downsample_3_1<ColorTypeFilter_8>; 454cb93a386Sopenharmony_ci proc_3_2 = downsample_3_2<ColorTypeFilter_8>; 455cb93a386Sopenharmony_ci proc_3_3 = downsample_3_3<ColorTypeFilter_8>; 456cb93a386Sopenharmony_ci break; 457cb93a386Sopenharmony_ci case kRGBA_F16Norm_SkColorType: 458cb93a386Sopenharmony_ci case kRGBA_F16_SkColorType: 459cb93a386Sopenharmony_ci proc_1_2 = downsample_1_2<ColorTypeFilter_RGBA_F16>; 460cb93a386Sopenharmony_ci proc_1_3 = downsample_1_3<ColorTypeFilter_RGBA_F16>; 461cb93a386Sopenharmony_ci proc_2_1 = downsample_2_1<ColorTypeFilter_RGBA_F16>; 462cb93a386Sopenharmony_ci proc_2_2 = downsample_2_2<ColorTypeFilter_RGBA_F16>; 463cb93a386Sopenharmony_ci proc_2_3 = downsample_2_3<ColorTypeFilter_RGBA_F16>; 464cb93a386Sopenharmony_ci proc_3_1 = downsample_3_1<ColorTypeFilter_RGBA_F16>; 465cb93a386Sopenharmony_ci proc_3_2 = downsample_3_2<ColorTypeFilter_RGBA_F16>; 466cb93a386Sopenharmony_ci proc_3_3 = downsample_3_3<ColorTypeFilter_RGBA_F16>; 467cb93a386Sopenharmony_ci break; 468cb93a386Sopenharmony_ci case kR8G8_unorm_SkColorType: 469cb93a386Sopenharmony_ci proc_1_2 = downsample_1_2<ColorTypeFilter_88>; 470cb93a386Sopenharmony_ci proc_1_3 = downsample_1_3<ColorTypeFilter_88>; 471cb93a386Sopenharmony_ci proc_2_1 = downsample_2_1<ColorTypeFilter_88>; 472cb93a386Sopenharmony_ci proc_2_2 = downsample_2_2<ColorTypeFilter_88>; 473cb93a386Sopenharmony_ci proc_2_3 = downsample_2_3<ColorTypeFilter_88>; 474cb93a386Sopenharmony_ci proc_3_1 = downsample_3_1<ColorTypeFilter_88>; 475cb93a386Sopenharmony_ci proc_3_2 = downsample_3_2<ColorTypeFilter_88>; 476cb93a386Sopenharmony_ci proc_3_3 = downsample_3_3<ColorTypeFilter_88>; 477cb93a386Sopenharmony_ci break; 478cb93a386Sopenharmony_ci case kR16G16_unorm_SkColorType: 479cb93a386Sopenharmony_ci proc_1_2 = downsample_1_2<ColorTypeFilter_1616>; 480cb93a386Sopenharmony_ci proc_1_3 = downsample_1_3<ColorTypeFilter_1616>; 481cb93a386Sopenharmony_ci proc_2_1 = downsample_2_1<ColorTypeFilter_1616>; 482cb93a386Sopenharmony_ci proc_2_2 = downsample_2_2<ColorTypeFilter_1616>; 483cb93a386Sopenharmony_ci proc_2_3 = downsample_2_3<ColorTypeFilter_1616>; 484cb93a386Sopenharmony_ci proc_3_1 = downsample_3_1<ColorTypeFilter_1616>; 485cb93a386Sopenharmony_ci proc_3_2 = downsample_3_2<ColorTypeFilter_1616>; 486cb93a386Sopenharmony_ci proc_3_3 = downsample_3_3<ColorTypeFilter_1616>; 487cb93a386Sopenharmony_ci break; 488cb93a386Sopenharmony_ci case kA16_unorm_SkColorType: 489cb93a386Sopenharmony_ci proc_1_2 = downsample_1_2<ColorTypeFilter_16>; 490cb93a386Sopenharmony_ci proc_1_3 = downsample_1_3<ColorTypeFilter_16>; 491cb93a386Sopenharmony_ci proc_2_1 = downsample_2_1<ColorTypeFilter_16>; 492cb93a386Sopenharmony_ci proc_2_2 = downsample_2_2<ColorTypeFilter_16>; 493cb93a386Sopenharmony_ci proc_2_3 = downsample_2_3<ColorTypeFilter_16>; 494cb93a386Sopenharmony_ci proc_3_1 = downsample_3_1<ColorTypeFilter_16>; 495cb93a386Sopenharmony_ci proc_3_2 = downsample_3_2<ColorTypeFilter_16>; 496cb93a386Sopenharmony_ci proc_3_3 = downsample_3_3<ColorTypeFilter_16>; 497cb93a386Sopenharmony_ci break; 498cb93a386Sopenharmony_ci case kRGBA_1010102_SkColorType: 499cb93a386Sopenharmony_ci case kBGRA_1010102_SkColorType: 500cb93a386Sopenharmony_ci proc_1_2 = downsample_1_2<ColorTypeFilter_1010102>; 501cb93a386Sopenharmony_ci proc_1_3 = downsample_1_3<ColorTypeFilter_1010102>; 502cb93a386Sopenharmony_ci proc_2_1 = downsample_2_1<ColorTypeFilter_1010102>; 503cb93a386Sopenharmony_ci proc_2_2 = downsample_2_2<ColorTypeFilter_1010102>; 504cb93a386Sopenharmony_ci proc_2_3 = downsample_2_3<ColorTypeFilter_1010102>; 505cb93a386Sopenharmony_ci proc_3_1 = downsample_3_1<ColorTypeFilter_1010102>; 506cb93a386Sopenharmony_ci proc_3_2 = downsample_3_2<ColorTypeFilter_1010102>; 507cb93a386Sopenharmony_ci proc_3_3 = downsample_3_3<ColorTypeFilter_1010102>; 508cb93a386Sopenharmony_ci break; 509cb93a386Sopenharmony_ci case kA16_float_SkColorType: 510cb93a386Sopenharmony_ci proc_1_2 = downsample_1_2<ColorTypeFilter_Alpha_F16>; 511cb93a386Sopenharmony_ci proc_1_3 = downsample_1_3<ColorTypeFilter_Alpha_F16>; 512cb93a386Sopenharmony_ci proc_2_1 = downsample_2_1<ColorTypeFilter_Alpha_F16>; 513cb93a386Sopenharmony_ci proc_2_2 = downsample_2_2<ColorTypeFilter_Alpha_F16>; 514cb93a386Sopenharmony_ci proc_2_3 = downsample_2_3<ColorTypeFilter_Alpha_F16>; 515cb93a386Sopenharmony_ci proc_3_1 = downsample_3_1<ColorTypeFilter_Alpha_F16>; 516cb93a386Sopenharmony_ci proc_3_2 = downsample_3_2<ColorTypeFilter_Alpha_F16>; 517cb93a386Sopenharmony_ci proc_3_3 = downsample_3_3<ColorTypeFilter_Alpha_F16>; 518cb93a386Sopenharmony_ci break; 519cb93a386Sopenharmony_ci case kR16G16_float_SkColorType: 520cb93a386Sopenharmony_ci proc_1_2 = downsample_1_2<ColorTypeFilter_F16F16>; 521cb93a386Sopenharmony_ci proc_1_3 = downsample_1_3<ColorTypeFilter_F16F16>; 522cb93a386Sopenharmony_ci proc_2_1 = downsample_2_1<ColorTypeFilter_F16F16>; 523cb93a386Sopenharmony_ci proc_2_2 = downsample_2_2<ColorTypeFilter_F16F16>; 524cb93a386Sopenharmony_ci proc_2_3 = downsample_2_3<ColorTypeFilter_F16F16>; 525cb93a386Sopenharmony_ci proc_3_1 = downsample_3_1<ColorTypeFilter_F16F16>; 526cb93a386Sopenharmony_ci proc_3_2 = downsample_3_2<ColorTypeFilter_F16F16>; 527cb93a386Sopenharmony_ci proc_3_3 = downsample_3_3<ColorTypeFilter_F16F16>; 528cb93a386Sopenharmony_ci break; 529cb93a386Sopenharmony_ci case kR16G16B16A16_unorm_SkColorType: 530cb93a386Sopenharmony_ci proc_1_2 = downsample_1_2<ColorTypeFilter_16161616>; 531cb93a386Sopenharmony_ci proc_1_3 = downsample_1_3<ColorTypeFilter_16161616>; 532cb93a386Sopenharmony_ci proc_2_1 = downsample_2_1<ColorTypeFilter_16161616>; 533cb93a386Sopenharmony_ci proc_2_2 = downsample_2_2<ColorTypeFilter_16161616>; 534cb93a386Sopenharmony_ci proc_2_3 = downsample_2_3<ColorTypeFilter_16161616>; 535cb93a386Sopenharmony_ci proc_3_1 = downsample_3_1<ColorTypeFilter_16161616>; 536cb93a386Sopenharmony_ci proc_3_2 = downsample_3_2<ColorTypeFilter_16161616>; 537cb93a386Sopenharmony_ci proc_3_3 = downsample_3_3<ColorTypeFilter_16161616>; 538cb93a386Sopenharmony_ci break; 539cb93a386Sopenharmony_ci 540cb93a386Sopenharmony_ci case kUnknown_SkColorType: 541cb93a386Sopenharmony_ci case kRGB_888x_SkColorType: // TODO: use 8888? 542cb93a386Sopenharmony_ci case kRGB_101010x_SkColorType: // TODO: use 1010102? 543cb93a386Sopenharmony_ci case kBGR_101010x_SkColorType: // TODO: use 1010102? 544cb93a386Sopenharmony_ci case kRGBA_F32_SkColorType: 545cb93a386Sopenharmony_ci return nullptr; 546cb93a386Sopenharmony_ci 547cb93a386Sopenharmony_ci case kSRGBA_8888_SkColorType: // TODO: needs careful handling 548cb93a386Sopenharmony_ci return nullptr; 549cb93a386Sopenharmony_ci } 550cb93a386Sopenharmony_ci 551cb93a386Sopenharmony_ci if (src.width() <= 1 && src.height() <= 1) { 552cb93a386Sopenharmony_ci return nullptr; 553cb93a386Sopenharmony_ci } 554cb93a386Sopenharmony_ci // whip through our loop to compute the exact size needed 555cb93a386Sopenharmony_ci size_t size = 0; 556cb93a386Sopenharmony_ci int countLevels = ComputeLevelCount(src.width(), src.height()); 557cb93a386Sopenharmony_ci for (int currentMipLevel = countLevels; currentMipLevel >= 0; currentMipLevel--) { 558cb93a386Sopenharmony_ci SkISize mipSize = ComputeLevelSize(src.width(), src.height(), currentMipLevel); 559cb93a386Sopenharmony_ci size += SkColorTypeMinRowBytes(ct, mipSize.fWidth) * mipSize.fHeight; 560cb93a386Sopenharmony_ci } 561cb93a386Sopenharmony_ci 562cb93a386Sopenharmony_ci size_t storageSize = SkMipmap::AllocLevelsSize(countLevels, size); 563cb93a386Sopenharmony_ci if (0 == storageSize) { 564cb93a386Sopenharmony_ci return nullptr; 565cb93a386Sopenharmony_ci } 566cb93a386Sopenharmony_ci 567cb93a386Sopenharmony_ci SkMipmap* mipmap; 568cb93a386Sopenharmony_ci if (fact) { 569cb93a386Sopenharmony_ci SkDiscardableMemory* dm = fact(storageSize); 570cb93a386Sopenharmony_ci if (nullptr == dm) { 571cb93a386Sopenharmony_ci return nullptr; 572cb93a386Sopenharmony_ci } 573cb93a386Sopenharmony_ci mipmap = new SkMipmap(storageSize, dm); 574cb93a386Sopenharmony_ci } else { 575cb93a386Sopenharmony_ci mipmap = new SkMipmap(sk_malloc_throw(storageSize), storageSize); 576cb93a386Sopenharmony_ci } 577cb93a386Sopenharmony_ci 578cb93a386Sopenharmony_ci // init 579cb93a386Sopenharmony_ci mipmap->fCS = sk_ref_sp(src.info().colorSpace()); 580cb93a386Sopenharmony_ci mipmap->fCount = countLevels; 581cb93a386Sopenharmony_ci mipmap->fLevels = (Level*)mipmap->writable_data(); 582cb93a386Sopenharmony_ci SkASSERT(mipmap->fLevels); 583cb93a386Sopenharmony_ci 584cb93a386Sopenharmony_ci Level* levels = mipmap->fLevels; 585cb93a386Sopenharmony_ci uint8_t* baseAddr = (uint8_t*)&levels[countLevels]; 586cb93a386Sopenharmony_ci uint8_t* addr = baseAddr; 587cb93a386Sopenharmony_ci int width = src.width(); 588cb93a386Sopenharmony_ci int height = src.height(); 589cb93a386Sopenharmony_ci uint32_t rowBytes; 590cb93a386Sopenharmony_ci SkPixmap srcPM(src); 591cb93a386Sopenharmony_ci 592cb93a386Sopenharmony_ci // Depending on architecture and other factors, the pixel data alignment may need to be as 593cb93a386Sopenharmony_ci // large as 8 (for F16 pixels). See the comment on SkMipmap::Level. 594cb93a386Sopenharmony_ci SkASSERT(SkIsAlign8((uintptr_t)addr)); 595cb93a386Sopenharmony_ci 596cb93a386Sopenharmony_ci for (int i = 0; i < countLevels; ++i) { 597cb93a386Sopenharmony_ci FilterProc* proc; 598cb93a386Sopenharmony_ci if (height & 1) { 599cb93a386Sopenharmony_ci if (height == 1) { // src-height is 1 600cb93a386Sopenharmony_ci if (width & 1) { // src-width is 3 601cb93a386Sopenharmony_ci proc = proc_3_1; 602cb93a386Sopenharmony_ci } else { // src-width is 2 603cb93a386Sopenharmony_ci proc = proc_2_1; 604cb93a386Sopenharmony_ci } 605cb93a386Sopenharmony_ci } else { // src-height is 3 606cb93a386Sopenharmony_ci if (width & 1) { 607cb93a386Sopenharmony_ci if (width == 1) { // src-width is 1 608cb93a386Sopenharmony_ci proc = proc_1_3; 609cb93a386Sopenharmony_ci } else { // src-width is 3 610cb93a386Sopenharmony_ci proc = proc_3_3; 611cb93a386Sopenharmony_ci } 612cb93a386Sopenharmony_ci } else { // src-width is 2 613cb93a386Sopenharmony_ci proc = proc_2_3; 614cb93a386Sopenharmony_ci } 615cb93a386Sopenharmony_ci } 616cb93a386Sopenharmony_ci } else { // src-height is 2 617cb93a386Sopenharmony_ci if (width & 1) { 618cb93a386Sopenharmony_ci if (width == 1) { // src-width is 1 619cb93a386Sopenharmony_ci proc = proc_1_2; 620cb93a386Sopenharmony_ci } else { // src-width is 3 621cb93a386Sopenharmony_ci proc = proc_3_2; 622cb93a386Sopenharmony_ci } 623cb93a386Sopenharmony_ci } else { // src-width is 2 624cb93a386Sopenharmony_ci proc = proc_2_2; 625cb93a386Sopenharmony_ci } 626cb93a386Sopenharmony_ci } 627cb93a386Sopenharmony_ci width = std::max(1, width >> 1); 628cb93a386Sopenharmony_ci height = std::max(1, height >> 1); 629cb93a386Sopenharmony_ci rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); 630cb93a386Sopenharmony_ci 631cb93a386Sopenharmony_ci // We make the Info w/o any colorspace, since that storage is not under our control, and 632cb93a386Sopenharmony_ci // will not be deleted in a controlled fashion. When the caller is given the pixmap for 633cb93a386Sopenharmony_ci // a given level, we augment this pixmap with fCS (which we do manage). 634cb93a386Sopenharmony_ci new (&levels[i].fPixmap) SkPixmap(SkImageInfo::Make(width, height, ct, at), addr, rowBytes); 635cb93a386Sopenharmony_ci levels[i].fScale = SkSize::Make(SkIntToScalar(width) / src.width(), 636cb93a386Sopenharmony_ci SkIntToScalar(height) / src.height()); 637cb93a386Sopenharmony_ci 638cb93a386Sopenharmony_ci const SkPixmap& dstPM = levels[i].fPixmap; 639cb93a386Sopenharmony_ci if (computeContents) { 640cb93a386Sopenharmony_ci const void* srcBasePtr = srcPM.addr(); 641cb93a386Sopenharmony_ci void* dstBasePtr = dstPM.writable_addr(); 642cb93a386Sopenharmony_ci 643cb93a386Sopenharmony_ci const size_t srcRB = srcPM.rowBytes(); 644cb93a386Sopenharmony_ci for (int y = 0; y < height; y++) { 645cb93a386Sopenharmony_ci proc(dstBasePtr, srcBasePtr, srcRB, width); 646cb93a386Sopenharmony_ci srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows 647cb93a386Sopenharmony_ci dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); 648cb93a386Sopenharmony_ci } 649cb93a386Sopenharmony_ci } 650cb93a386Sopenharmony_ci srcPM = dstPM; 651cb93a386Sopenharmony_ci addr += height * rowBytes; 652cb93a386Sopenharmony_ci } 653cb93a386Sopenharmony_ci SkASSERT(addr == baseAddr + size); 654cb93a386Sopenharmony_ci 655cb93a386Sopenharmony_ci SkASSERT(mipmap->fLevels); 656cb93a386Sopenharmony_ci return mipmap; 657cb93a386Sopenharmony_ci} 658cb93a386Sopenharmony_ci 659cb93a386Sopenharmony_ciint SkMipmap::ComputeLevelCount(int baseWidth, int baseHeight) { 660cb93a386Sopenharmony_ci if (baseWidth < 1 || baseHeight < 1) { 661cb93a386Sopenharmony_ci return 0; 662cb93a386Sopenharmony_ci } 663cb93a386Sopenharmony_ci 664cb93a386Sopenharmony_ci // OpenGL's spec requires that each mipmap level have height/width equal to 665cb93a386Sopenharmony_ci // max(1, floor(original_height / 2^i) 666cb93a386Sopenharmony_ci // (or original_width) where i is the mipmap level. 667cb93a386Sopenharmony_ci // Continue scaling down until both axes are size 1. 668cb93a386Sopenharmony_ci 669cb93a386Sopenharmony_ci const int largestAxis = std::max(baseWidth, baseHeight); 670cb93a386Sopenharmony_ci if (largestAxis < 2) { 671cb93a386Sopenharmony_ci // SkMipmap::Build requires a minimum size of 2. 672cb93a386Sopenharmony_ci return 0; 673cb93a386Sopenharmony_ci } 674cb93a386Sopenharmony_ci const int leadingZeros = SkCLZ(static_cast<uint32_t>(largestAxis)); 675cb93a386Sopenharmony_ci // If the value 00011010 has 3 leading 0s then it has 5 significant bits 676cb93a386Sopenharmony_ci // (the bits which are not leading zeros) 677cb93a386Sopenharmony_ci const int significantBits = (sizeof(uint32_t) * 8) - leadingZeros; 678cb93a386Sopenharmony_ci // This is making the assumption that the size of a byte is 8 bits 679cb93a386Sopenharmony_ci // and that sizeof(uint32_t)'s implementation-defined behavior is 4. 680cb93a386Sopenharmony_ci int mipLevelCount = significantBits; 681cb93a386Sopenharmony_ci 682cb93a386Sopenharmony_ci // SkMipmap does not include the base mip level. 683cb93a386Sopenharmony_ci // For example, it contains levels 1-x instead of 0-x. 684cb93a386Sopenharmony_ci // This is because the image used to create SkMipmap is the base level. 685cb93a386Sopenharmony_ci // So subtract 1 from the mip level count. 686cb93a386Sopenharmony_ci if (mipLevelCount > 0) { 687cb93a386Sopenharmony_ci --mipLevelCount; 688cb93a386Sopenharmony_ci } 689cb93a386Sopenharmony_ci 690cb93a386Sopenharmony_ci return mipLevelCount; 691cb93a386Sopenharmony_ci} 692cb93a386Sopenharmony_ci 693cb93a386Sopenharmony_ciSkISize SkMipmap::ComputeLevelSize(int baseWidth, int baseHeight, int level) { 694cb93a386Sopenharmony_ci if (baseWidth < 1 || baseHeight < 1) { 695cb93a386Sopenharmony_ci return SkISize::Make(0, 0); 696cb93a386Sopenharmony_ci } 697cb93a386Sopenharmony_ci 698cb93a386Sopenharmony_ci int maxLevelCount = ComputeLevelCount(baseWidth, baseHeight); 699cb93a386Sopenharmony_ci if (level >= maxLevelCount || level < 0) { 700cb93a386Sopenharmony_ci return SkISize::Make(0, 0); 701cb93a386Sopenharmony_ci } 702cb93a386Sopenharmony_ci // OpenGL's spec requires that each mipmap level have height/width equal to 703cb93a386Sopenharmony_ci // max(1, floor(original_height / 2^i) 704cb93a386Sopenharmony_ci // (or original_width) where i is the mipmap level. 705cb93a386Sopenharmony_ci 706cb93a386Sopenharmony_ci // SkMipmap does not include the base mip level. 707cb93a386Sopenharmony_ci // For example, it contains levels 1-x instead of 0-x. 708cb93a386Sopenharmony_ci // This is because the image used to create SkMipmap is the base level. 709cb93a386Sopenharmony_ci // So subtract 1 from the mip level to get the index stored by SkMipmap. 710cb93a386Sopenharmony_ci int width = std::max(1, baseWidth >> (level + 1)); 711cb93a386Sopenharmony_ci int height = std::max(1, baseHeight >> (level + 1)); 712cb93a386Sopenharmony_ci 713cb93a386Sopenharmony_ci return SkISize::Make(width, height); 714cb93a386Sopenharmony_ci} 715cb93a386Sopenharmony_ci 716cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 717cb93a386Sopenharmony_ci 718cb93a386Sopenharmony_ci// Returns fractional level value. floor(level) is the index of the larger level. 719cb93a386Sopenharmony_ci// < 0 means failure. 720cb93a386Sopenharmony_cifloat SkMipmap::ComputeLevel(SkSize scaleSize) { 721cb93a386Sopenharmony_ci SkASSERT(scaleSize.width() >= 0 && scaleSize.height() >= 0); 722cb93a386Sopenharmony_ci 723cb93a386Sopenharmony_ci#ifndef SK_SUPPORT_LEGACY_ANISOTROPIC_MIPMAP_SCALE 724cb93a386Sopenharmony_ci // Use the smallest scale to match the GPU impl. 725cb93a386Sopenharmony_ci const SkScalar scale = std::min(scaleSize.width(), scaleSize.height()); 726cb93a386Sopenharmony_ci#else 727cb93a386Sopenharmony_ci // Ideally we'd pick the smaller scale, to match Ganesh. But ignoring one of the 728cb93a386Sopenharmony_ci // scales can produce some atrocious results, so for now we use the geometric mean. 729cb93a386Sopenharmony_ci // (https://bugs.chromium.org/p/skia/issues/detail?id=4863) 730cb93a386Sopenharmony_ci const SkScalar scale = SkScalarSqrt(scaleSize.width() * scaleSize.height()); 731cb93a386Sopenharmony_ci#endif 732cb93a386Sopenharmony_ci 733cb93a386Sopenharmony_ci if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { 734cb93a386Sopenharmony_ci return -1; 735cb93a386Sopenharmony_ci } 736cb93a386Sopenharmony_ci 737cb93a386Sopenharmony_ci SkScalar L = -SkScalarLog2(scale); 738cb93a386Sopenharmony_ci if (!SkScalarIsFinite(L)) { 739cb93a386Sopenharmony_ci return -1; 740cb93a386Sopenharmony_ci } 741cb93a386Sopenharmony_ci SkASSERT(L >= 0); 742cb93a386Sopenharmony_ci return L; 743cb93a386Sopenharmony_ci} 744cb93a386Sopenharmony_ci 745cb93a386Sopenharmony_cibool SkMipmap::extractLevel(SkSize scaleSize, Level* levelPtr) const { 746cb93a386Sopenharmony_ci if (nullptr == fLevels) { 747cb93a386Sopenharmony_ci return false; 748cb93a386Sopenharmony_ci } 749cb93a386Sopenharmony_ci 750cb93a386Sopenharmony_ci float L = ComputeLevel(scaleSize); 751cb93a386Sopenharmony_ci int level = SkScalarFloorToInt(L); 752cb93a386Sopenharmony_ci if (level <= 0) { 753cb93a386Sopenharmony_ci return false; 754cb93a386Sopenharmony_ci } 755cb93a386Sopenharmony_ci 756cb93a386Sopenharmony_ci if (level > fCount) { 757cb93a386Sopenharmony_ci level = fCount; 758cb93a386Sopenharmony_ci } 759cb93a386Sopenharmony_ci if (levelPtr) { 760cb93a386Sopenharmony_ci *levelPtr = fLevels[level - 1]; 761cb93a386Sopenharmony_ci // need to augment with our colorspace 762cb93a386Sopenharmony_ci levelPtr->fPixmap.setColorSpace(fCS); 763cb93a386Sopenharmony_ci } 764cb93a386Sopenharmony_ci return true; 765cb93a386Sopenharmony_ci} 766cb93a386Sopenharmony_ci 767cb93a386Sopenharmony_cibool SkMipmap::validForRootLevel(const SkImageInfo& root) const { 768cb93a386Sopenharmony_ci if (nullptr == fLevels) { 769cb93a386Sopenharmony_ci return false; 770cb93a386Sopenharmony_ci } 771cb93a386Sopenharmony_ci 772cb93a386Sopenharmony_ci const SkISize dimension = root.dimensions(); 773cb93a386Sopenharmony_ci if (dimension.width() <= 1 && dimension.height() <= 1) { 774cb93a386Sopenharmony_ci return false; 775cb93a386Sopenharmony_ci } 776cb93a386Sopenharmony_ci 777cb93a386Sopenharmony_ci if (fLevels[0].fPixmap. width() != std::max(1, dimension. width() >> 1) || 778cb93a386Sopenharmony_ci fLevels[0].fPixmap.height() != std::max(1, dimension.height() >> 1)) { 779cb93a386Sopenharmony_ci return false; 780cb93a386Sopenharmony_ci } 781cb93a386Sopenharmony_ci 782cb93a386Sopenharmony_ci for (int i = 0; i < this->countLevels(); ++i) { 783cb93a386Sopenharmony_ci if (fLevels[i].fPixmap.colorType() != root.colorType() || 784cb93a386Sopenharmony_ci fLevels[i].fPixmap.alphaType() != root.alphaType()) { 785cb93a386Sopenharmony_ci return false; 786cb93a386Sopenharmony_ci } 787cb93a386Sopenharmony_ci } 788cb93a386Sopenharmony_ci return true; 789cb93a386Sopenharmony_ci} 790cb93a386Sopenharmony_ci 791cb93a386Sopenharmony_ci// Helper which extracts a pixmap from the src bitmap 792cb93a386Sopenharmony_ci// 793cb93a386Sopenharmony_ciSkMipmap* SkMipmap::Build(const SkBitmap& src, SkDiscardableFactoryProc fact) { 794cb93a386Sopenharmony_ci SkPixmap srcPixmap; 795cb93a386Sopenharmony_ci if (!src.peekPixels(&srcPixmap)) { 796cb93a386Sopenharmony_ci return nullptr; 797cb93a386Sopenharmony_ci } 798cb93a386Sopenharmony_ci return Build(srcPixmap, fact); 799cb93a386Sopenharmony_ci} 800cb93a386Sopenharmony_ci 801cb93a386Sopenharmony_ciint SkMipmap::countLevels() const { 802cb93a386Sopenharmony_ci return fCount; 803cb93a386Sopenharmony_ci} 804cb93a386Sopenharmony_ci 805cb93a386Sopenharmony_cibool SkMipmap::getLevel(int index, Level* levelPtr) const { 806cb93a386Sopenharmony_ci if (nullptr == fLevels) { 807cb93a386Sopenharmony_ci return false; 808cb93a386Sopenharmony_ci } 809cb93a386Sopenharmony_ci if (index < 0) { 810cb93a386Sopenharmony_ci return false; 811cb93a386Sopenharmony_ci } 812cb93a386Sopenharmony_ci if (index > fCount - 1) { 813cb93a386Sopenharmony_ci return false; 814cb93a386Sopenharmony_ci } 815cb93a386Sopenharmony_ci if (levelPtr) { 816cb93a386Sopenharmony_ci *levelPtr = fLevels[index]; 817cb93a386Sopenharmony_ci // need to augment with our colorspace 818cb93a386Sopenharmony_ci levelPtr->fPixmap.setColorSpace(fCS); 819cb93a386Sopenharmony_ci } 820cb93a386Sopenharmony_ci return true; 821cb93a386Sopenharmony_ci} 822cb93a386Sopenharmony_ci 823cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////////////////////// 824cb93a386Sopenharmony_ci 825cb93a386Sopenharmony_ci#include "include/core/SkImageGenerator.h" 826cb93a386Sopenharmony_ci#include "include/core/SkStream.h" 827cb93a386Sopenharmony_ci#include "include/encode/SkPngEncoder.h" 828cb93a386Sopenharmony_ci#include "src/core/SkReadBuffer.h" 829cb93a386Sopenharmony_ci#include "src/core/SkWriteBuffer.h" 830cb93a386Sopenharmony_ci 831cb93a386Sopenharmony_cistatic sk_sp<SkData> encode_to_data(const SkPixmap& pm) { 832cb93a386Sopenharmony_ci SkDynamicMemoryWStream stream; 833cb93a386Sopenharmony_ci if (SkPngEncoder::Encode(&stream, pm, SkPngEncoder::Options())) { 834cb93a386Sopenharmony_ci return stream.detachAsData(); 835cb93a386Sopenharmony_ci } 836cb93a386Sopenharmony_ci return nullptr; 837cb93a386Sopenharmony_ci} 838cb93a386Sopenharmony_ci 839cb93a386Sopenharmony_ci/* Format 840cb93a386Sopenharmony_ci count_levels:32 841cb93a386Sopenharmony_ci for each level, starting with the biggest (index 0 in our iterator) 842cb93a386Sopenharmony_ci encoded_size:32 843cb93a386Sopenharmony_ci encoded_data (padded) 844cb93a386Sopenharmony_ci */ 845cb93a386Sopenharmony_cisk_sp<SkData> SkMipmap::serialize() const { 846cb93a386Sopenharmony_ci const int count = this->countLevels(); 847cb93a386Sopenharmony_ci 848cb93a386Sopenharmony_ci SkBinaryWriteBuffer buffer; 849cb93a386Sopenharmony_ci buffer.write32(count); 850cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 851cb93a386Sopenharmony_ci Level level; 852cb93a386Sopenharmony_ci if (this->getLevel(i, &level)) { 853cb93a386Sopenharmony_ci buffer.writeDataAsByteArray(encode_to_data(level.fPixmap).get()); 854cb93a386Sopenharmony_ci } else { 855cb93a386Sopenharmony_ci return nullptr; 856cb93a386Sopenharmony_ci } 857cb93a386Sopenharmony_ci } 858cb93a386Sopenharmony_ci return buffer.snapshotAsData(); 859cb93a386Sopenharmony_ci} 860cb93a386Sopenharmony_ci 861cb93a386Sopenharmony_cibool SkMipmap::Deserialize(SkMipmapBuilder* builder, const void* data, size_t length) { 862cb93a386Sopenharmony_ci SkReadBuffer buffer(data, length); 863cb93a386Sopenharmony_ci 864cb93a386Sopenharmony_ci int count = buffer.read32(); 865cb93a386Sopenharmony_ci if (builder->countLevels() != count) { 866cb93a386Sopenharmony_ci return false; 867cb93a386Sopenharmony_ci } 868cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 869cb93a386Sopenharmony_ci size_t size = buffer.read32(); 870cb93a386Sopenharmony_ci const void* ptr = buffer.skip(size); 871cb93a386Sopenharmony_ci if (!ptr) { 872cb93a386Sopenharmony_ci return false; 873cb93a386Sopenharmony_ci } 874cb93a386Sopenharmony_ci auto gen = SkImageGenerator::MakeFromEncoded( 875cb93a386Sopenharmony_ci SkData::MakeWithProc(ptr, size, nullptr, nullptr)); 876cb93a386Sopenharmony_ci if (!gen) { 877cb93a386Sopenharmony_ci return false; 878cb93a386Sopenharmony_ci } 879cb93a386Sopenharmony_ci 880cb93a386Sopenharmony_ci SkPixmap pm = builder->level(i); 881cb93a386Sopenharmony_ci if (gen->getInfo().dimensions() != pm.dimensions()) { 882cb93a386Sopenharmony_ci return false; 883cb93a386Sopenharmony_ci } 884cb93a386Sopenharmony_ci if (!gen->getPixels(pm)) { 885cb93a386Sopenharmony_ci return false; 886cb93a386Sopenharmony_ci } 887cb93a386Sopenharmony_ci } 888cb93a386Sopenharmony_ci return buffer.isValid(); 889cb93a386Sopenharmony_ci} 890