| 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 #include "SkHalf.h" |
| 11 #include "SkMath.h" | 12 #include "SkMath.h" |
| 12 #include "SkNx.h" | 13 #include "SkNx.h" |
| 13 #include "SkTypes.h" | 14 #include "SkTypes.h" |
| 14 | 15 |
| 15 // | 16 // |
| 16 // ColorTypeFilter is the "Type" we pass to some downsample template functions. | 17 // ColorTypeFilter is the "Type" we pass to some downsample template functions. |
| 17 // It controls how we expand a pixel into a large type, with space between each
component, | 18 // It controls how we expand a pixel into a large type, with space between each
component, |
| 18 // so we can then perform our simple filter (either box or triangle) and store t
he intermediates | 19 // so we can then perform our simple filter (either box or triangle) and store t
he intermediates |
| 19 // in the expanded type. | 20 // in the expanded type. |
| 20 // | 21 // |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 struct ColorTypeFilter_8 { | 64 struct ColorTypeFilter_8 { |
| 64 typedef uint8_t Type; | 65 typedef uint8_t Type; |
| 65 static unsigned Expand(unsigned x) { | 66 static unsigned Expand(unsigned x) { |
| 66 return x; | 67 return x; |
| 67 } | 68 } |
| 68 static uint8_t Compact(unsigned x) { | 69 static uint8_t Compact(unsigned x) { |
| 69 return (uint8_t)x; | 70 return (uint8_t)x; |
| 70 } | 71 } |
| 71 }; | 72 }; |
| 72 | 73 |
| 74 struct ColorTypeFilter_F16 { |
| 75 typedef uint64_t Type; // SkHalf x4 |
| 76 static Sk4f Expand(uint64_t x) { |
| 77 return SkHalfToFloat_01(x); |
| 78 } |
| 79 static uint64_t Compact(const Sk4f& x) { |
| 80 return SkFloatToHalf_01(x); |
| 81 } |
| 82 }; |
| 83 |
| 73 template <typename T> T add_121(const T& a, const T& b, const T& c) { | 84 template <typename T> T add_121(const T& a, const T& b, const T& c) { |
| 74 return a + b + b + c; | 85 return a + b + b + c; |
| 75 } | 86 } |
| 76 | 87 |
| 88 template <typename T> T shift_right(const T& x, int bits) { |
| 89 return x >> bits; |
| 90 } |
| 91 |
| 92 Sk4f shift_right(const Sk4f& x, int bits) { |
| 93 return x * (1.0f / (1 << bits)); |
| 94 } |
| 95 |
| 96 template <typename T> T shift_left(const T& x, int bits) { |
| 97 return x << bits; |
| 98 } |
| 99 |
| 100 Sk4f shift_left(const Sk4f& x, int bits) { |
| 101 return x * (1 << bits); |
| 102 } |
| 103 |
| 77 // | 104 // |
| 78 // To produce each mip level, we need to filter down by 1/2 (e.g. 100x100 -> 50
,50) | 105 // To produce each mip level, we need to filter down by 1/2 (e.g. 100x100 -> 50
,50) |
| 79 // If the starting dimension is odd, we floor the size of the lower level (e.g.
101 -> 50) | 106 // If the starting dimension is odd, we floor the size of the lower level (e.g.
101 -> 50) |
| 80 // In those (odd) cases, we use a triangle filter, with 1-pixel overlap between
samplings, | 107 // In those (odd) cases, we use a triangle filter, with 1-pixel overlap between
samplings, |
| 81 // else for even cases, we just use a 2x box filter. | 108 // else for even cases, we just use a 2x box filter. |
| 82 // | 109 // |
| 83 // This produces 4 possible isotropic filters: 2x2 2x3 3x2 3x3 where WxH indica
tes the number of | 110 // This produces 4 possible isotropic filters: 2x2 2x3 3x2 3x3 where WxH indica
tes the number of |
| 84 // src pixels we need to sample in each dimension to produce 1 dst pixel. | 111 // src pixels we need to sample in each dimension to produce 1 dst pixel. |
| 85 // | 112 // |
| 86 // OpenGL expects a full mipmap stack to contain anisotropic space as well. | 113 // OpenGL expects a full mipmap stack to contain anisotropic space as well. |
| 87 // This means a 100x1 image would continue down to a 50x1 image, 25x1 image... | 114 // This means a 100x1 image would continue down to a 50x1 image, 25x1 image... |
| 88 // Because of this, we need 4 more anisotropic filters: 1x2, 1x3, 2x1, 3x1. | 115 // Because of this, we need 4 more anisotropic filters: 1x2, 1x3, 2x1, 3x1. |
| 89 | 116 |
| 90 template <typename F> void downsample_1_2(void* dst, const void* src, size_t src
RB, int count) { | 117 template <typename F> void downsample_1_2(void* dst, const void* src, size_t src
RB, int count) { |
| 91 SkASSERT(count > 0); | 118 SkASSERT(count > 0); |
| 92 auto p0 = static_cast<const typename F::Type*>(src); | 119 auto p0 = static_cast<const typename F::Type*>(src); |
| 93 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 120 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
| 94 auto d = static_cast<typename F::Type*>(dst); | 121 auto d = static_cast<typename F::Type*>(dst); |
| 95 | 122 |
| 96 for (int i = 0; i < count; ++i) { | 123 for (int i = 0; i < count; ++i) { |
| 97 auto c00 = F::Expand(p0[0]); | 124 auto c00 = F::Expand(p0[0]); |
| 98 auto c10 = F::Expand(p1[0]); | 125 auto c10 = F::Expand(p1[0]); |
| 99 | 126 |
| 100 auto c = c00 + c10; | 127 auto c = c00 + c10; |
| 101 d[i] = F::Compact(c >> 1); | 128 d[i] = F::Compact(shift_right(c, 1)); |
| 102 p0 += 2; | 129 p0 += 2; |
| 103 p1 += 2; | 130 p1 += 2; |
| 104 } | 131 } |
| 105 } | 132 } |
| 106 | 133 |
| 107 template <typename F> void downsample_1_3(void* dst, const void* src, size_t src
RB, int count) { | 134 template <typename F> void downsample_1_3(void* dst, const void* src, size_t src
RB, int count) { |
| 108 SkASSERT(count > 0); | 135 SkASSERT(count > 0); |
| 109 auto p0 = static_cast<const typename F::Type*>(src); | 136 auto p0 = static_cast<const typename F::Type*>(src); |
| 110 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 137 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
| 111 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); | 138 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); |
| 112 auto d = static_cast<typename F::Type*>(dst); | 139 auto d = static_cast<typename F::Type*>(dst); |
| 113 | 140 |
| 114 for (int i = 0; i < count; ++i) { | 141 for (int i = 0; i < count; ++i) { |
| 115 auto c00 = F::Expand(p0[0]); | 142 auto c00 = F::Expand(p0[0]); |
| 116 auto c10 = F::Expand(p1[0]); | 143 auto c10 = F::Expand(p1[0]); |
| 117 auto c20 = F::Expand(p2[0]); | 144 auto c20 = F::Expand(p2[0]); |
| 118 | 145 |
| 119 auto c = add_121(c00, c10, c20); | 146 auto c = add_121(c00, c10, c20); |
| 120 d[i] = F::Compact(c >> 2); | 147 d[i] = F::Compact(shift_right(c, 2)); |
| 121 p0 += 2; | 148 p0 += 2; |
| 122 p1 += 2; | 149 p1 += 2; |
| 123 p2 += 2; | 150 p2 += 2; |
| 124 } | 151 } |
| 125 } | 152 } |
| 126 | 153 |
| 127 template <typename F> void downsample_2_1(void* dst, const void* src, size_t src
RB, int count) { | 154 template <typename F> void downsample_2_1(void* dst, const void* src, size_t src
RB, int count) { |
| 128 SkASSERT(count > 0); | 155 SkASSERT(count > 0); |
| 129 auto p0 = static_cast<const typename F::Type*>(src); | 156 auto p0 = static_cast<const typename F::Type*>(src); |
| 130 auto d = static_cast<typename F::Type*>(dst); | 157 auto d = static_cast<typename F::Type*>(dst); |
| 131 | 158 |
| 132 for (int i = 0; i < count; ++i) { | 159 for (int i = 0; i < count; ++i) { |
| 133 auto c00 = F::Expand(p0[0]); | 160 auto c00 = F::Expand(p0[0]); |
| 134 auto c01 = F::Expand(p0[1]); | 161 auto c01 = F::Expand(p0[1]); |
| 135 | 162 |
| 136 auto c = c00 + c01; | 163 auto c = c00 + c01; |
| 137 d[i] = F::Compact(c >> 1); | 164 d[i] = F::Compact(shift_right(c, 1)); |
| 138 p0 += 2; | 165 p0 += 2; |
| 139 } | 166 } |
| 140 } | 167 } |
| 141 | 168 |
| 142 template <typename F> void downsample_2_2(void* dst, const void* src, size_t src
RB, int count) { | 169 template <typename F> void downsample_2_2(void* dst, const void* src, size_t src
RB, int count) { |
| 143 SkASSERT(count > 0); | 170 SkASSERT(count > 0); |
| 144 auto p0 = static_cast<const typename F::Type*>(src); | 171 auto p0 = static_cast<const typename F::Type*>(src); |
| 145 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 172 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
| 146 auto d = static_cast<typename F::Type*>(dst); | 173 auto d = static_cast<typename F::Type*>(dst); |
| 147 | 174 |
| 148 for (int i = 0; i < count; ++i) { | 175 for (int i = 0; i < count; ++i) { |
| 149 auto c00 = F::Expand(p0[0]); | 176 auto c00 = F::Expand(p0[0]); |
| 150 auto c01 = F::Expand(p0[1]); | 177 auto c01 = F::Expand(p0[1]); |
| 151 auto c10 = F::Expand(p1[0]); | 178 auto c10 = F::Expand(p1[0]); |
| 152 auto c11 = F::Expand(p1[1]); | 179 auto c11 = F::Expand(p1[1]); |
| 153 | 180 |
| 154 auto c = c00 + c10 + c01 + c11; | 181 auto c = c00 + c10 + c01 + c11; |
| 155 d[i] = F::Compact(c >> 2); | 182 d[i] = F::Compact(shift_right(c, 2)); |
| 156 p0 += 2; | 183 p0 += 2; |
| 157 p1 += 2; | 184 p1 += 2; |
| 158 } | 185 } |
| 159 } | 186 } |
| 160 | 187 |
| 161 template <typename F> void downsample_2_3(void* dst, const void* src, size_t src
RB, int count) { | 188 template <typename F> void downsample_2_3(void* dst, const void* src, size_t src
RB, int count) { |
| 162 SkASSERT(count > 0); | 189 SkASSERT(count > 0); |
| 163 auto p0 = static_cast<const typename F::Type*>(src); | 190 auto p0 = static_cast<const typename F::Type*>(src); |
| 164 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 191 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
| 165 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); | 192 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); |
| 166 auto d = static_cast<typename F::Type*>(dst); | 193 auto d = static_cast<typename F::Type*>(dst); |
| 167 | 194 |
| 168 for (int i = 0; i < count; ++i) { | 195 for (int i = 0; i < count; ++i) { |
| 169 auto c00 = F::Expand(p0[0]); | 196 auto c00 = F::Expand(p0[0]); |
| 170 auto c01 = F::Expand(p0[1]); | 197 auto c01 = F::Expand(p0[1]); |
| 171 auto c10 = F::Expand(p1[0]); | 198 auto c10 = F::Expand(p1[0]); |
| 172 auto c11 = F::Expand(p1[1]); | 199 auto c11 = F::Expand(p1[1]); |
| 173 auto c20 = F::Expand(p2[0]); | 200 auto c20 = F::Expand(p2[0]); |
| 174 auto c21 = F::Expand(p2[1]); | 201 auto c21 = F::Expand(p2[1]); |
| 175 | 202 |
| 176 auto c = add_121(c00, c10, c20) + add_121(c01, c11, c21); | 203 auto c = add_121(c00, c10, c20) + add_121(c01, c11, c21); |
| 177 d[i] = F::Compact(c >> 3); | 204 d[i] = F::Compact(shift_right(c, 3)); |
| 178 p0 += 2; | 205 p0 += 2; |
| 179 p1 += 2; | 206 p1 += 2; |
| 180 p2 += 2; | 207 p2 += 2; |
| 181 } | 208 } |
| 182 } | 209 } |
| 183 | 210 |
| 184 template <typename F> void downsample_3_1(void* dst, const void* src, size_t src
RB, int count) { | 211 template <typename F> void downsample_3_1(void* dst, const void* src, size_t src
RB, int count) { |
| 185 SkASSERT(count > 0); | 212 SkASSERT(count > 0); |
| 186 auto p0 = static_cast<const typename F::Type*>(src); | 213 auto p0 = static_cast<const typename F::Type*>(src); |
| 187 auto d = static_cast<typename F::Type*>(dst); | 214 auto d = static_cast<typename F::Type*>(dst); |
| 188 | 215 |
| 189 auto c02 = F::Expand(p0[0]); | 216 auto c02 = F::Expand(p0[0]); |
| 190 for (int i = 0; i < count; ++i) { | 217 for (int i = 0; i < count; ++i) { |
| 191 auto c00 = c02; | 218 auto c00 = c02; |
| 192 auto c01 = F::Expand(p0[1]); | 219 auto c01 = F::Expand(p0[1]); |
| 193 c02 = F::Expand(p0[2]); | 220 c02 = F::Expand(p0[2]); |
| 194 | 221 |
| 195 auto c = add_121(c00, c01, c02); | 222 auto c = add_121(c00, c01, c02); |
| 196 d[i] = F::Compact(c >> 2); | 223 d[i] = F::Compact(shift_right(c, 2)); |
| 197 p0 += 2; | 224 p0 += 2; |
| 198 } | 225 } |
| 199 } | 226 } |
| 200 | 227 |
| 201 template <typename F> void downsample_3_2(void* dst, const void* src, size_t src
RB, int count) { | 228 template <typename F> void downsample_3_2(void* dst, const void* src, size_t src
RB, int count) { |
| 202 SkASSERT(count > 0); | 229 SkASSERT(count > 0); |
| 203 auto p0 = static_cast<const typename F::Type*>(src); | 230 auto p0 = static_cast<const typename F::Type*>(src); |
| 204 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 231 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
| 205 auto d = static_cast<typename F::Type*>(dst); | 232 auto d = static_cast<typename F::Type*>(dst); |
| 206 | 233 |
| 207 auto c02 = F::Expand(p0[0]); | 234 auto c02 = F::Expand(p0[0]); |
| 208 auto c12 = F::Expand(p1[0]); | 235 auto c12 = F::Expand(p1[0]); |
| 209 for (int i = 0; i < count; ++i) { | 236 for (int i = 0; i < count; ++i) { |
| 210 auto c00 = c02; | 237 auto c00 = c02; |
| 211 auto c01 = F::Expand(p0[1]); | 238 auto c01 = F::Expand(p0[1]); |
| 212 c02 = F::Expand(p0[2]); | 239 c02 = F::Expand(p0[2]); |
| 213 auto c10 = c12; | 240 auto c10 = c12; |
| 214 auto c11 = F::Expand(p1[1]); | 241 auto c11 = F::Expand(p1[1]); |
| 215 c12 = F::Expand(p1[2]); | 242 c12 = F::Expand(p1[2]); |
| 216 | 243 |
| 217 auto c = add_121(c00, c01, c02) + add_121(c10, c11, c12); | 244 auto c = add_121(c00, c01, c02) + add_121(c10, c11, c12); |
| 218 d[i] = F::Compact(c >> 3); | 245 d[i] = F::Compact(shift_right(c, 3)); |
| 219 p0 += 2; | 246 p0 += 2; |
| 220 p1 += 2; | 247 p1 += 2; |
| 221 } | 248 } |
| 222 } | 249 } |
| 223 | 250 |
| 224 template <typename F> void downsample_3_3(void* dst, const void* src, size_t src
RB, int count) { | 251 template <typename F> void downsample_3_3(void* dst, const void* src, size_t src
RB, int count) { |
| 225 SkASSERT(count > 0); | 252 SkASSERT(count > 0); |
| 226 auto p0 = static_cast<const typename F::Type*>(src); | 253 auto p0 = static_cast<const typename F::Type*>(src); |
| 227 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 254 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
| 228 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); | 255 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); |
| 229 auto d = static_cast<typename F::Type*>(dst); | 256 auto d = static_cast<typename F::Type*>(dst); |
| 230 | 257 |
| 231 auto c02 = F::Expand(p0[0]); | 258 auto c02 = F::Expand(p0[0]); |
| 232 auto c12 = F::Expand(p1[0]); | 259 auto c12 = F::Expand(p1[0]); |
| 233 auto c22 = F::Expand(p2[0]); | 260 auto c22 = F::Expand(p2[0]); |
| 234 for (int i = 0; i < count; ++i) { | 261 for (int i = 0; i < count; ++i) { |
| 235 auto c00 = c02; | 262 auto c00 = c02; |
| 236 auto c01 = F::Expand(p0[1]); | 263 auto c01 = F::Expand(p0[1]); |
| 237 c02 = F::Expand(p0[2]); | 264 c02 = F::Expand(p0[2]); |
| 238 auto c10 = c12; | 265 auto c10 = c12; |
| 239 auto c11 = F::Expand(p1[1]); | 266 auto c11 = F::Expand(p1[1]); |
| 240 c12 = F::Expand(p1[2]); | 267 c12 = F::Expand(p1[2]); |
| 241 auto c20 = c22; | 268 auto c20 = c22; |
| 242 auto c21 = F::Expand(p2[1]); | 269 auto c21 = F::Expand(p2[1]); |
| 243 c22 = F::Expand(p2[2]); | 270 c22 = F::Expand(p2[2]); |
| 244 | 271 |
| 245 auto c = add_121(c00, c01, c02) + (add_121(c10, c11, c12) << 1) + add_12
1(c20, c21, c22); | 272 auto c = |
| 246 d[i] = F::Compact(c >> 4); | 273 add_121(c00, c01, c02) + |
| 274 shift_left(add_121(c10, c11, c12), 1) + |
| 275 add_121(c20, c21, c22); |
| 276 d[i] = F::Compact(shift_right(c, 4)); |
| 247 p0 += 2; | 277 p0 += 2; |
| 248 p1 += 2; | 278 p1 += 2; |
| 249 p2 += 2; | 279 p2 += 2; |
| 250 } | 280 } |
| 251 } | 281 } |
| 252 | 282 |
| 253 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 283 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 254 | 284 |
| 255 size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) { | 285 size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) { |
| 256 if (levelCount < 0) { | 286 if (levelCount < 0) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 case kGray_8_SkColorType: | 343 case kGray_8_SkColorType: |
| 314 proc_1_2 = downsample_1_2<ColorTypeFilter_8>; | 344 proc_1_2 = downsample_1_2<ColorTypeFilter_8>; |
| 315 proc_1_3 = downsample_1_3<ColorTypeFilter_8>; | 345 proc_1_3 = downsample_1_3<ColorTypeFilter_8>; |
| 316 proc_2_1 = downsample_2_1<ColorTypeFilter_8>; | 346 proc_2_1 = downsample_2_1<ColorTypeFilter_8>; |
| 317 proc_2_2 = downsample_2_2<ColorTypeFilter_8>; | 347 proc_2_2 = downsample_2_2<ColorTypeFilter_8>; |
| 318 proc_2_3 = downsample_2_3<ColorTypeFilter_8>; | 348 proc_2_3 = downsample_2_3<ColorTypeFilter_8>; |
| 319 proc_3_1 = downsample_3_1<ColorTypeFilter_8>; | 349 proc_3_1 = downsample_3_1<ColorTypeFilter_8>; |
| 320 proc_3_2 = downsample_3_2<ColorTypeFilter_8>; | 350 proc_3_2 = downsample_3_2<ColorTypeFilter_8>; |
| 321 proc_3_3 = downsample_3_3<ColorTypeFilter_8>; | 351 proc_3_3 = downsample_3_3<ColorTypeFilter_8>; |
| 322 break; | 352 break; |
| 353 case kRGBA_F16_SkColorType: |
| 354 proc_1_2 = downsample_1_2<ColorTypeFilter_F16>; |
| 355 proc_1_3 = downsample_1_3<ColorTypeFilter_F16>; |
| 356 proc_2_1 = downsample_2_1<ColorTypeFilter_F16>; |
| 357 proc_2_2 = downsample_2_2<ColorTypeFilter_F16>; |
| 358 proc_2_3 = downsample_2_3<ColorTypeFilter_F16>; |
| 359 proc_3_1 = downsample_3_1<ColorTypeFilter_F16>; |
| 360 proc_3_2 = downsample_3_2<ColorTypeFilter_F16>; |
| 361 proc_3_3 = downsample_3_3<ColorTypeFilter_F16>; |
| 362 break; |
| 323 default: | 363 default: |
| 324 // TODO: We could build miplevels for kIndex8 if the levels were in
8888. | 364 // TODO: We could build miplevels for kIndex8 if the levels were in
8888. |
| 325 // Means using more ram, but the quality would be fine. | 365 // Means using more ram, but the quality would be fine. |
| 326 return nullptr; | 366 return nullptr; |
| 327 } | 367 } |
| 328 | 368 |
| 329 if (src.width() <= 1 && src.height() <= 1) { | 369 if (src.width() <= 1 && src.height() <= 1) { |
| 330 return nullptr; | 370 return nullptr; |
| 331 } | 371 } |
| 332 // whip through our loop to compute the exact size needed | 372 // whip through our loop to compute the exact size needed |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 return false; | 580 return false; |
| 541 } | 581 } |
| 542 if (index > fCount - 1) { | 582 if (index > fCount - 1) { |
| 543 return false; | 583 return false; |
| 544 } | 584 } |
| 545 if (levelPtr) { | 585 if (levelPtr) { |
| 546 *levelPtr = fLevels[index]; | 586 *levelPtr = fLevels[index]; |
| 547 } | 587 } |
| 548 return true; | 588 return true; |
| 549 } | 589 } |
| OLD | NEW |