xref: /aosp_15_r20/external/skia/src/core/SkMipmapHQDownSampler.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2023 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 
8 #include "include/core/SkTypes.h"
9 
10 #ifndef SK_USE_DRAWING_MIPMAP_DOWNSAMPLER
11 
12 #include "include/private/SkColorData.h"
13 #include "src/base/SkHalf.h"
14 #include "src/base/SkVx.h"
15 #include "src/core/SkMipmap.h"
16 
17 namespace {
18 
19 struct ColorTypeFilter_8888 {
20     typedef uint32_t Type;
Expand__anon33863e050111::ColorTypeFilter_888821     static skvx::Vec<4, uint16_t> Expand(uint32_t x) {
22         return skvx::cast<uint16_t>(skvx::byte4::Load(&x));
23     }
Compact__anon33863e050111::ColorTypeFilter_888824     static uint32_t Compact(const skvx::Vec<4, uint16_t>& x) {
25         uint32_t r;
26         skvx::cast<uint8_t>(x).store(&r);
27         return r;
28     }
29 };
30 
31 struct ColorTypeFilter_565 {
32     typedef uint16_t Type;
Expand__anon33863e050111::ColorTypeFilter_56533     static uint32_t Expand(uint16_t x) {
34         return (x & ~SK_G16_MASK_IN_PLACE) | ((x & SK_G16_MASK_IN_PLACE) << 16);
35     }
Compact__anon33863e050111::ColorTypeFilter_56536     static uint16_t Compact(uint32_t x) {
37         return ((x & ~SK_G16_MASK_IN_PLACE) & 0xFFFF) | ((x >> 16) & SK_G16_MASK_IN_PLACE);
38     }
39 };
40 
41 struct ColorTypeFilter_4444 {
42     typedef uint16_t Type;
Expand__anon33863e050111::ColorTypeFilter_444443     static uint32_t Expand(uint16_t x) {
44         return (x & 0xF0F) | ((x & ~0xF0F) << 12);
45     }
Compact__anon33863e050111::ColorTypeFilter_444446     static uint16_t Compact(uint32_t x) {
47         return (x & 0xF0F) | ((x >> 12) & ~0xF0F);
48     }
49 };
50 
51 struct ColorTypeFilter_8 {
52     typedef uint8_t Type;
Expand__anon33863e050111::ColorTypeFilter_853     static unsigned Expand(unsigned x) {
54         return x;
55     }
Compact__anon33863e050111::ColorTypeFilter_856     static uint8_t Compact(unsigned x) {
57         return (uint8_t)x;
58     }
59 };
60 
61 struct ColorTypeFilter_Alpha_F16 {
62     typedef uint16_t Type;
Expand__anon33863e050111::ColorTypeFilter_Alpha_F1663     static skvx::float4 Expand(uint16_t x) {
64         uint64_t x4 = (uint64_t)x; // add 0s out to four lanes (0,0,0,x)
65         return from_half(skvx::half4::Load(&x4));
66     }
Compact__anon33863e050111::ColorTypeFilter_Alpha_F1667     static uint16_t Compact(const skvx::float4& x) {
68         uint64_t r;
69         to_half(x).store(&r);
70         return r & 0xFFFF;  // but ignore the extra 3 here
71     }
72 };
73 
74 struct ColorTypeFilter_RGBA_F16 {
75     typedef uint64_t Type; // SkHalf x4
Expand__anon33863e050111::ColorTypeFilter_RGBA_F1676     static skvx::float4 Expand(uint64_t x) {
77         return from_half(skvx::half4::Load(&x));
78     }
Compact__anon33863e050111::ColorTypeFilter_RGBA_F1679     static uint64_t Compact(const skvx::float4& x) {
80         uint64_t r;
81         to_half(x).store(&r);
82         return r;
83     }
84 };
85 
86 struct ColorTypeFilter_88 {
87     typedef uint16_t Type;
Expand__anon33863e050111::ColorTypeFilter_8888     static uint32_t Expand(uint16_t x) {
89         return (x & 0xFF) | ((x & ~0xFF) << 8);
90     }
Compact__anon33863e050111::ColorTypeFilter_8891     static uint16_t Compact(uint32_t x) {
92         return (x & 0xFF) | ((x >> 8) & ~0xFF);
93     }
94 };
95 
96 struct ColorTypeFilter_1616 {
97     typedef uint32_t Type;
Expand__anon33863e050111::ColorTypeFilter_161698     static uint64_t Expand(uint32_t x) {
99         return (x & 0xFFFF) | ((x & ~0xFFFF) << 16);
100     }
Compact__anon33863e050111::ColorTypeFilter_1616101     static uint16_t Compact(uint64_t x) {
102         return (x & 0xFFFF) | ((x >> 16) & ~0xFFFF);
103     }
104 };
105 
106 struct ColorTypeFilter_F16F16 {
107     typedef uint32_t Type;
Expand__anon33863e050111::ColorTypeFilter_F16F16108     static skvx::float4 Expand(uint32_t x) {
109         uint64_t x4 = (uint64_t)x; // // add 0s out to four lanes (0,0,x,x)
110         return from_half(skvx::half4::Load(&x4));
111     }
Compact__anon33863e050111::ColorTypeFilter_F16F16112     static uint32_t Compact(const skvx::float4& x) {
113         uint64_t r;
114         to_half(x).store(&r);
115         return (uint32_t) (r & 0xFFFFFFFF);  // but ignore the extra 2 here
116     }
117 };
118 
119 struct ColorTypeFilter_16161616 {
120     typedef uint64_t Type;
Expand__anon33863e050111::ColorTypeFilter_16161616121     static skvx::Vec<4, uint32_t> Expand(uint64_t x) {
122         return skvx::cast<uint32_t>(skvx::Vec<4, uint16_t>::Load(&x));
123     }
Compact__anon33863e050111::ColorTypeFilter_16161616124     static uint64_t Compact(const skvx::Vec<4, uint32_t>& x) {
125         uint64_t r;
126         skvx::cast<uint16_t>(x).store(&r);
127         return r;
128     }
129 };
130 
131 struct ColorTypeFilter_16 {
132     typedef uint16_t Type;
Expand__anon33863e050111::ColorTypeFilter_16133     static uint32_t Expand(uint16_t x) {
134         return x;
135     }
Compact__anon33863e050111::ColorTypeFilter_16136     static uint16_t Compact(uint32_t x) {
137         return (uint16_t) x;
138     }
139 };
140 
141 struct ColorTypeFilter_1010102 {
142     typedef uint32_t Type;
Expand__anon33863e050111::ColorTypeFilter_1010102143     static uint64_t Expand(uint64_t x) {
144         return (((x      ) & 0x3ff)      ) |
145         (((x >> 10) & 0x3ff) << 20) |
146         (((x >> 20) & 0x3ff) << 40) |
147         (((x >> 30) & 0x3  ) << 60);
148     }
Compact__anon33863e050111::ColorTypeFilter_1010102149     static uint32_t Compact(uint64_t x) {
150         return (((x      ) & 0x3ff)      ) |
151         (((x >> 20) & 0x3ff) << 10) |
152         (((x >> 40) & 0x3ff) << 20) |
153         (((x >> 60) & 0x3  ) << 30);
154     }
155 };
156 
add_121(const T & a,const T & b,const T & c)157 template <typename T> T add_121(const T& a, const T& b, const T& c) {
158     return a + b + b + c;
159 }
160 
shift_right(const T & x,int bits)161 template <typename T> T shift_right(const T& x, int bits) {
162     return x >> bits;
163 }
164 
shift_right(const skvx::float4 & x,int bits)165 skvx::float4 shift_right(const skvx::float4& x, int bits) {
166     return x * (1.0f / (1 << bits));
167 }
168 
shift_left(const T & x,int bits)169 template <typename T> T shift_left(const T& x, int bits) {
170     return x << bits;
171 }
172 
shift_left(const skvx::float4 & x,int bits)173 skvx::float4 shift_left(const skvx::float4& x, int bits) {
174     return x * (1 << bits);
175 }
176 
177 //
178 //  To produce each mip level, we need to filter down by 1/2 (e.g. 100x100 -> 50,50)
179 //  If the starting dimension is odd, we floor the size of the lower level (e.g. 101 -> 50)
180 //  In those (odd) cases, we use a triangle filter, with 1-pixel overlap between samplings,
181 //  else for even cases, we just use a 2x box filter.
182 //
183 //  This produces 4 possible isotropic filters: 2x2 2x3 3x2 3x3 where WxH indicates the number of
184 //  src pixels we need to sample in each dimension to produce 1 dst pixel.
185 //
186 //  OpenGL expects a full mipmap stack to contain anisotropic space as well.
187 //  This means a 100x1 image would continue down to a 50x1 image, 25x1 image...
188 //  Because of this, we need 4 more anisotropic filters: 1x2, 1x3, 2x1, 3x1.
189 
downsample_1_2(void * dst,const void * src,size_t srcRB,int count)190 template <typename F> void downsample_1_2(void* dst, const void* src, size_t srcRB, int count) {
191     SkASSERT(count > 0);
192     auto p0 = static_cast<const typename F::Type*>(src);
193     auto p1 = (const typename F::Type*)((const char*)p0 + srcRB);
194     auto d = static_cast<typename F::Type*>(dst);
195 
196     for (int i = 0; i < count; ++i) {
197         auto c00 = F::Expand(p0[0]);
198         auto c10 = F::Expand(p1[0]);
199 
200         auto c = c00 + c10;
201         d[i] = F::Compact(shift_right(c, 1));
202         p0 += 2;
203         p1 += 2;
204     }
205 }
206 
downsample_1_3(void * dst,const void * src,size_t srcRB,int count)207 template <typename F> void downsample_1_3(void* dst, const void* src, size_t srcRB, int count) {
208     SkASSERT(count > 0);
209     auto p0 = static_cast<const typename F::Type*>(src);
210     auto p1 = (const typename F::Type*)((const char*)p0 + srcRB);
211     auto p2 = (const typename F::Type*)((const char*)p1 + srcRB);
212     auto d = static_cast<typename F::Type*>(dst);
213 
214     for (int i = 0; i < count; ++i) {
215         auto c00 = F::Expand(p0[0]);
216         auto c10 = F::Expand(p1[0]);
217         auto c20 = F::Expand(p2[0]);
218 
219         auto c = add_121(c00, c10, c20);
220         d[i] = F::Compact(shift_right(c, 2));
221         p0 += 2;
222         p1 += 2;
223         p2 += 2;
224     }
225 }
226 
downsample_2_1(void * dst,const void * src,size_t srcRB,int count)227 template <typename F> void downsample_2_1(void* dst, const void* src, size_t srcRB, int count) {
228     SkASSERT(count > 0);
229     auto p0 = static_cast<const typename F::Type*>(src);
230     auto d = static_cast<typename F::Type*>(dst);
231 
232     for (int i = 0; i < count; ++i) {
233         auto c00 = F::Expand(p0[0]);
234         auto c01 = F::Expand(p0[1]);
235 
236         auto c = c00 + c01;
237         d[i] = F::Compact(shift_right(c, 1));
238         p0 += 2;
239     }
240 }
241 
downsample_2_2(void * dst,const void * src,size_t srcRB,int count)242 template <typename F> void downsample_2_2(void* dst, const void* src, size_t srcRB, int count) {
243     SkASSERT(count > 0);
244     auto p0 = static_cast<const typename F::Type*>(src);
245     auto p1 = (const typename F::Type*)((const char*)p0 + srcRB);
246     auto d = static_cast<typename F::Type*>(dst);
247 
248     for (int i = 0; i < count; ++i) {
249         auto c00 = F::Expand(p0[0]);
250         auto c01 = F::Expand(p0[1]);
251         auto c10 = F::Expand(p1[0]);
252         auto c11 = F::Expand(p1[1]);
253 
254         auto c = c00 + c10 + c01 + c11;
255         d[i] = F::Compact(shift_right(c, 2));
256         p0 += 2;
257         p1 += 2;
258     }
259 }
260 
downsample_2_3(void * dst,const void * src,size_t srcRB,int count)261 template <typename F> void downsample_2_3(void* dst, const void* src, size_t srcRB, int count) {
262     SkASSERT(count > 0);
263     auto p0 = static_cast<const typename F::Type*>(src);
264     auto p1 = (const typename F::Type*)((const char*)p0 + srcRB);
265     auto p2 = (const typename F::Type*)((const char*)p1 + srcRB);
266     auto d = static_cast<typename F::Type*>(dst);
267 
268     for (int i = 0; i < count; ++i) {
269         auto c00 = F::Expand(p0[0]);
270         auto c01 = F::Expand(p0[1]);
271         auto c10 = F::Expand(p1[0]);
272         auto c11 = F::Expand(p1[1]);
273         auto c20 = F::Expand(p2[0]);
274         auto c21 = F::Expand(p2[1]);
275 
276         auto c = add_121(c00, c10, c20) + add_121(c01, c11, c21);
277         d[i] = F::Compact(shift_right(c, 3));
278         p0 += 2;
279         p1 += 2;
280         p2 += 2;
281     }
282 }
283 
downsample_3_1(void * dst,const void * src,size_t srcRB,int count)284 template <typename F> void downsample_3_1(void* dst, const void* src, size_t srcRB, int count) {
285     SkASSERT(count > 0);
286     auto p0 = static_cast<const typename F::Type*>(src);
287     auto d = static_cast<typename F::Type*>(dst);
288 
289     auto c02 = F::Expand(p0[0]);
290     for (int i = 0; i < count; ++i) {
291         auto c00 = c02;
292         auto c01 = F::Expand(p0[1]);
293         c02 = F::Expand(p0[2]);
294 
295         auto c = add_121(c00, c01, c02);
296         d[i] = F::Compact(shift_right(c, 2));
297         p0 += 2;
298     }
299 }
300 
downsample_3_2(void * dst,const void * src,size_t srcRB,int count)301 template <typename F> void downsample_3_2(void* dst, const void* src, size_t srcRB, int count) {
302     SkASSERT(count > 0);
303     auto p0 = static_cast<const typename F::Type*>(src);
304     auto p1 = (const typename F::Type*)((const char*)p0 + srcRB);
305     auto d = static_cast<typename F::Type*>(dst);
306 
307     // Given pixels:
308     // a0 b0 c0 d0 e0 ...
309     // a1 b1 c1 d1 e1 ...
310     // We want:
311     // (a0 + 2*b0 + c0 + a1 + 2*b1 + c1) / 8
312     // (c0 + 2*d0 + e0 + c1 + 2*d1 + e1) / 8
313     // ...
314 
315     auto c0 = F::Expand(p0[0]);
316     auto c1 = F::Expand(p1[0]);
317     auto c = c0 + c1;
318     for (int i = 0; i < count; ++i) {
319         auto a = c;
320 
321         auto b0 = F::Expand(p0[1]);
322         auto b1 = F::Expand(p1[1]);
323         auto b = b0 + b0 + b1 + b1;
324 
325         c0 = F::Expand(p0[2]);
326         c1 = F::Expand(p1[2]);
327         c = c0 + c1;
328 
329         auto sum = a + b + c;
330         d[i] = F::Compact(shift_right(sum, 3));
331         p0 += 2;
332         p1 += 2;
333     }
334 }
335 
downsample_3_3(void * dst,const void * src,size_t srcRB,int count)336 template <typename F> void downsample_3_3(void* dst, const void* src, size_t srcRB, int count) {
337     SkASSERT(count > 0);
338     auto p0 = static_cast<const typename F::Type*>(src);
339     auto p1 = (const typename F::Type*)((const char*)p0 + srcRB);
340     auto p2 = (const typename F::Type*)((const char*)p1 + srcRB);
341     auto d = static_cast<typename F::Type*>(dst);
342 
343     // Given pixels:
344     // a0 b0 c0 d0 e0 ...
345     // a1 b1 c1 d1 e1 ...
346     // a2 b2 c2 d2 e2 ...
347     // We want:
348     // (a0 + 2*b0 + c0 + 2*a1 + 4*b1 + 2*c1 + a2 + 2*b2 + c2) / 16
349     // (c0 + 2*d0 + e0 + 2*c1 + 4*d1 + 2*e1 + c2 + 2*d2 + e2) / 16
350     // ...
351 
352     auto c0 = F::Expand(p0[0]);
353     auto c1 = F::Expand(p1[0]);
354     auto c2 = F::Expand(p2[0]);
355     auto c = add_121(c0, c1, c2);
356     for (int i = 0; i < count; ++i) {
357         auto a = c;
358 
359         auto b0 = F::Expand(p0[1]);
360         auto b1 = F::Expand(p1[1]);
361         auto b2 = F::Expand(p2[1]);
362         auto b = shift_left(add_121(b0, b1, b2), 1);
363 
364         c0 = F::Expand(p0[2]);
365         c1 = F::Expand(p1[2]);
366         c2 = F::Expand(p2[2]);
367         c = add_121(c0, c1, c2);
368 
369         auto sum = a + b + c;
370         d[i] = F::Compact(shift_right(sum, 4));
371         p0 += 2;
372         p1 += 2;
373         p2 += 2;
374     }
375 }
376 
377 
378 typedef void FilterProc(void*, const void* srcPtr, size_t srcRB, int count);
379 
380 struct HQDownSampler : SkMipmapDownSampler {
381     FilterProc* proc_1_2 = nullptr;
382     FilterProc* proc_1_3 = nullptr;
383     FilterProc* proc_2_1 = nullptr;
384     FilterProc* proc_2_2 = nullptr;
385     FilterProc* proc_2_3 = nullptr;
386     FilterProc* proc_3_1 = nullptr;
387     FilterProc* proc_3_2 = nullptr;
388     FilterProc* proc_3_3 = nullptr;
389 
390     void buildLevel(const SkPixmap& dst, const SkPixmap& src) override;
391 };
392 
buildLevel(const SkPixmap & dst,const SkPixmap & src)393 void HQDownSampler::buildLevel(const SkPixmap& dst, const SkPixmap& src) {
394     const int width = src.width();
395     const int height = src.height();
396 
397     FilterProc* proc;
398     if (height & 1) {
399         if (height == 1) {        // src-height is 1
400             if (width & 1) {      // src-width is 3
401                 proc = proc_3_1;
402             } else {              // src-width is 2
403                 proc = proc_2_1;
404             }
405         } else {                  // src-height is 3
406             if (width & 1) {
407                 if (width == 1) { // src-width is 1
408                     proc = proc_1_3;
409                 } else {          // src-width is 3
410                     proc = proc_3_3;
411                 }
412             } else {              // src-width is 2
413                 proc = proc_2_3;
414             }
415         }
416     } else {                      // src-height is 2
417         if (width & 1) {
418             if (width == 1) {     // src-width is 1
419                 proc = proc_1_2;
420             } else {              // src-width is 3
421                 proc = proc_3_2;
422             }
423         } else {                  // src-width is 2
424             proc = proc_2_2;
425         }
426     }
427 
428     const void* srcBasePtr = src.addr();
429     const size_t srcRB = src.rowBytes();
430     void* dstBasePtr = dst.writable_addr();
431 
432     for (int y = 0; y < dst.height(); y++) {
433         proc(dstBasePtr, srcBasePtr, srcRB, dst.width());
434         srcBasePtr = (const char*)srcBasePtr + srcRB * 2; // jump two rows
435         dstBasePtr = (      char*)dstBasePtr + dst.rowBytes();
436     }
437 }
438 
439 } // namespace
440 
MakeDownSampler(const SkPixmap & root)441 std::unique_ptr<SkMipmapDownSampler> SkMipmap::MakeDownSampler(const SkPixmap& root) {
442     FilterProc* proc_1_2 = nullptr;
443     FilterProc* proc_1_3 = nullptr;
444     FilterProc* proc_2_1 = nullptr;
445     FilterProc* proc_2_2 = nullptr;
446     FilterProc* proc_2_3 = nullptr;
447     FilterProc* proc_3_1 = nullptr;
448     FilterProc* proc_3_2 = nullptr;
449     FilterProc* proc_3_3 = nullptr;
450 
451     switch (root.colorType()) {
452         case kRGBA_8888_SkColorType:
453         case kBGRA_8888_SkColorType:
454             proc_1_2 = downsample_1_2<ColorTypeFilter_8888>;
455             proc_1_3 = downsample_1_3<ColorTypeFilter_8888>;
456             proc_2_1 = downsample_2_1<ColorTypeFilter_8888>;
457             proc_2_2 = downsample_2_2<ColorTypeFilter_8888>;
458             proc_2_3 = downsample_2_3<ColorTypeFilter_8888>;
459             proc_3_1 = downsample_3_1<ColorTypeFilter_8888>;
460             proc_3_2 = downsample_3_2<ColorTypeFilter_8888>;
461             proc_3_3 = downsample_3_3<ColorTypeFilter_8888>;
462             break;
463         case kRGB_565_SkColorType:
464             proc_1_2 = downsample_1_2<ColorTypeFilter_565>;
465             proc_1_3 = downsample_1_3<ColorTypeFilter_565>;
466             proc_2_1 = downsample_2_1<ColorTypeFilter_565>;
467             proc_2_2 = downsample_2_2<ColorTypeFilter_565>;
468             proc_2_3 = downsample_2_3<ColorTypeFilter_565>;
469             proc_3_1 = downsample_3_1<ColorTypeFilter_565>;
470             proc_3_2 = downsample_3_2<ColorTypeFilter_565>;
471             proc_3_3 = downsample_3_3<ColorTypeFilter_565>;
472             break;
473         case kARGB_4444_SkColorType:
474             proc_1_2 = downsample_1_2<ColorTypeFilter_4444>;
475             proc_1_3 = downsample_1_3<ColorTypeFilter_4444>;
476             proc_2_1 = downsample_2_1<ColorTypeFilter_4444>;
477             proc_2_2 = downsample_2_2<ColorTypeFilter_4444>;
478             proc_2_3 = downsample_2_3<ColorTypeFilter_4444>;
479             proc_3_1 = downsample_3_1<ColorTypeFilter_4444>;
480             proc_3_2 = downsample_3_2<ColorTypeFilter_4444>;
481             proc_3_3 = downsample_3_3<ColorTypeFilter_4444>;
482             break;
483         case kAlpha_8_SkColorType:
484         case kGray_8_SkColorType:
485         case kR8_unorm_SkColorType:
486             proc_1_2 = downsample_1_2<ColorTypeFilter_8>;
487             proc_1_3 = downsample_1_3<ColorTypeFilter_8>;
488             proc_2_1 = downsample_2_1<ColorTypeFilter_8>;
489             proc_2_2 = downsample_2_2<ColorTypeFilter_8>;
490             proc_2_3 = downsample_2_3<ColorTypeFilter_8>;
491             proc_3_1 = downsample_3_1<ColorTypeFilter_8>;
492             proc_3_2 = downsample_3_2<ColorTypeFilter_8>;
493             proc_3_3 = downsample_3_3<ColorTypeFilter_8>;
494             break;
495         case kRGBA_F16Norm_SkColorType:
496         case kRGBA_F16_SkColorType:
497             proc_1_2 = downsample_1_2<ColorTypeFilter_RGBA_F16>;
498             proc_1_3 = downsample_1_3<ColorTypeFilter_RGBA_F16>;
499             proc_2_1 = downsample_2_1<ColorTypeFilter_RGBA_F16>;
500             proc_2_2 = downsample_2_2<ColorTypeFilter_RGBA_F16>;
501             proc_2_3 = downsample_2_3<ColorTypeFilter_RGBA_F16>;
502             proc_3_1 = downsample_3_1<ColorTypeFilter_RGBA_F16>;
503             proc_3_2 = downsample_3_2<ColorTypeFilter_RGBA_F16>;
504             proc_3_3 = downsample_3_3<ColorTypeFilter_RGBA_F16>;
505             break;
506         case kR8G8_unorm_SkColorType:
507             proc_1_2 = downsample_1_2<ColorTypeFilter_88>;
508             proc_1_3 = downsample_1_3<ColorTypeFilter_88>;
509             proc_2_1 = downsample_2_1<ColorTypeFilter_88>;
510             proc_2_2 = downsample_2_2<ColorTypeFilter_88>;
511             proc_2_3 = downsample_2_3<ColorTypeFilter_88>;
512             proc_3_1 = downsample_3_1<ColorTypeFilter_88>;
513             proc_3_2 = downsample_3_2<ColorTypeFilter_88>;
514             proc_3_3 = downsample_3_3<ColorTypeFilter_88>;
515             break;
516         case kR16G16_unorm_SkColorType:
517             proc_1_2 = downsample_1_2<ColorTypeFilter_1616>;
518             proc_1_3 = downsample_1_3<ColorTypeFilter_1616>;
519             proc_2_1 = downsample_2_1<ColorTypeFilter_1616>;
520             proc_2_2 = downsample_2_2<ColorTypeFilter_1616>;
521             proc_2_3 = downsample_2_3<ColorTypeFilter_1616>;
522             proc_3_1 = downsample_3_1<ColorTypeFilter_1616>;
523             proc_3_2 = downsample_3_2<ColorTypeFilter_1616>;
524             proc_3_3 = downsample_3_3<ColorTypeFilter_1616>;
525             break;
526         case kA16_unorm_SkColorType:
527             proc_1_2 = downsample_1_2<ColorTypeFilter_16>;
528             proc_1_3 = downsample_1_3<ColorTypeFilter_16>;
529             proc_2_1 = downsample_2_1<ColorTypeFilter_16>;
530             proc_2_2 = downsample_2_2<ColorTypeFilter_16>;
531             proc_2_3 = downsample_2_3<ColorTypeFilter_16>;
532             proc_3_1 = downsample_3_1<ColorTypeFilter_16>;
533             proc_3_2 = downsample_3_2<ColorTypeFilter_16>;
534             proc_3_3 = downsample_3_3<ColorTypeFilter_16>;
535             break;
536         case kRGBA_1010102_SkColorType:
537         case kBGRA_1010102_SkColorType:
538             proc_1_2 = downsample_1_2<ColorTypeFilter_1010102>;
539             proc_1_3 = downsample_1_3<ColorTypeFilter_1010102>;
540             proc_2_1 = downsample_2_1<ColorTypeFilter_1010102>;
541             proc_2_2 = downsample_2_2<ColorTypeFilter_1010102>;
542             proc_2_3 = downsample_2_3<ColorTypeFilter_1010102>;
543             proc_3_1 = downsample_3_1<ColorTypeFilter_1010102>;
544             proc_3_2 = downsample_3_2<ColorTypeFilter_1010102>;
545             proc_3_3 = downsample_3_3<ColorTypeFilter_1010102>;
546             break;
547         case kA16_float_SkColorType:
548             proc_1_2 = downsample_1_2<ColorTypeFilter_Alpha_F16>;
549             proc_1_3 = downsample_1_3<ColorTypeFilter_Alpha_F16>;
550             proc_2_1 = downsample_2_1<ColorTypeFilter_Alpha_F16>;
551             proc_2_2 = downsample_2_2<ColorTypeFilter_Alpha_F16>;
552             proc_2_3 = downsample_2_3<ColorTypeFilter_Alpha_F16>;
553             proc_3_1 = downsample_3_1<ColorTypeFilter_Alpha_F16>;
554             proc_3_2 = downsample_3_2<ColorTypeFilter_Alpha_F16>;
555             proc_3_3 = downsample_3_3<ColorTypeFilter_Alpha_F16>;
556             break;
557         case kR16G16_float_SkColorType:
558             proc_1_2 = downsample_1_2<ColorTypeFilter_F16F16>;
559             proc_1_3 = downsample_1_3<ColorTypeFilter_F16F16>;
560             proc_2_1 = downsample_2_1<ColorTypeFilter_F16F16>;
561             proc_2_2 = downsample_2_2<ColorTypeFilter_F16F16>;
562             proc_2_3 = downsample_2_3<ColorTypeFilter_F16F16>;
563             proc_3_1 = downsample_3_1<ColorTypeFilter_F16F16>;
564             proc_3_2 = downsample_3_2<ColorTypeFilter_F16F16>;
565             proc_3_3 = downsample_3_3<ColorTypeFilter_F16F16>;
566             break;
567         case kR16G16B16A16_unorm_SkColorType:
568             proc_1_2 = downsample_1_2<ColorTypeFilter_16161616>;
569             proc_1_3 = downsample_1_3<ColorTypeFilter_16161616>;
570             proc_2_1 = downsample_2_1<ColorTypeFilter_16161616>;
571             proc_2_2 = downsample_2_2<ColorTypeFilter_16161616>;
572             proc_2_3 = downsample_2_3<ColorTypeFilter_16161616>;
573             proc_3_1 = downsample_3_1<ColorTypeFilter_16161616>;
574             proc_3_2 = downsample_3_2<ColorTypeFilter_16161616>;
575             proc_3_3 = downsample_3_3<ColorTypeFilter_16161616>;
576             break;
577 
578         case kUnknown_SkColorType:
579         case kRGB_888x_SkColorType:     // TODO: use 8888?
580         case kRGB_101010x_SkColorType:  // TODO: use 1010102?
581         case kBGR_101010x_SkColorType:  // TODO: use 1010102?
582         case kBGR_101010x_XR_SkColorType:  // TODO: use 1010102?
583         case kRGB_F16F16F16x_SkColorType:  // TODO: use F16?
584         case kBGRA_10101010_XR_SkColorType:
585         case kRGBA_10x6_SkColorType:
586         case kRGBA_F32_SkColorType:
587             return nullptr;
588 
589         case kSRGBA_8888_SkColorType:  // TODO: needs careful handling
590             return nullptr;
591     }
592 
593     auto sampler = std::make_unique<HQDownSampler>();
594     sampler->proc_1_2 = proc_1_2;
595     sampler->proc_1_3 = proc_1_3;
596     sampler->proc_2_1 = proc_2_1;
597     sampler->proc_2_2 = proc_2_2;
598     sampler->proc_2_3 = proc_2_3;
599     sampler->proc_3_1 = proc_3_1;
600     sampler->proc_3_2 = proc_3_2;
601     sampler->proc_3_3 = proc_3_3;
602     return sampler;
603 }
604 
605 #endif
606