xref: /aosp_15_r20/external/webp/src/dsp/alpha_processing_neon.c (revision b2055c353e87c8814eb2b6b1b11112a1562253bd)
1*b2055c35SXin Li // Copyright 2017 Google Inc. All Rights Reserved.
2*b2055c35SXin Li //
3*b2055c35SXin Li // Use of this source code is governed by a BSD-style license
4*b2055c35SXin Li // that can be found in the COPYING file in the root of the source
5*b2055c35SXin Li // tree. An additional intellectual property rights grant can be found
6*b2055c35SXin Li // in the file PATENTS. All contributing project authors may
7*b2055c35SXin Li // be found in the AUTHORS file in the root of the source tree.
8*b2055c35SXin Li // -----------------------------------------------------------------------------
9*b2055c35SXin Li //
10*b2055c35SXin Li // Utilities for processing transparent channel, NEON version.
11*b2055c35SXin Li //
12*b2055c35SXin Li // Author: Skal ([email protected])
13*b2055c35SXin Li 
14*b2055c35SXin Li #include "src/dsp/dsp.h"
15*b2055c35SXin Li 
16*b2055c35SXin Li #if defined(WEBP_USE_NEON)
17*b2055c35SXin Li 
18*b2055c35SXin Li #include "src/dsp/neon.h"
19*b2055c35SXin Li 
20*b2055c35SXin Li //------------------------------------------------------------------------------
21*b2055c35SXin Li 
22*b2055c35SXin Li #define MULTIPLIER(a) ((a) * 0x8081)
23*b2055c35SXin Li #define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
24*b2055c35SXin Li 
25*b2055c35SXin Li #define MULTIPLY_BY_ALPHA(V, ALPHA, OTHER) do {                        \
26*b2055c35SXin Li   const uint8x8_t alpha = (V).val[(ALPHA)];                            \
27*b2055c35SXin Li   const uint16x8_t r1 = vmull_u8((V).val[1], alpha);                   \
28*b2055c35SXin Li   const uint16x8_t g1 = vmull_u8((V).val[2], alpha);                   \
29*b2055c35SXin Li   const uint16x8_t b1 = vmull_u8((V).val[(OTHER)], alpha);             \
30*b2055c35SXin Li   /* we use: v / 255 = (v + 1 + (v >> 8)) >> 8 */                      \
31*b2055c35SXin Li   const uint16x8_t r2 = vsraq_n_u16(r1, r1, 8);                        \
32*b2055c35SXin Li   const uint16x8_t g2 = vsraq_n_u16(g1, g1, 8);                        \
33*b2055c35SXin Li   const uint16x8_t b2 = vsraq_n_u16(b1, b1, 8);                        \
34*b2055c35SXin Li   const uint16x8_t r3 = vaddq_u16(r2, kOne);                           \
35*b2055c35SXin Li   const uint16x8_t g3 = vaddq_u16(g2, kOne);                           \
36*b2055c35SXin Li   const uint16x8_t b3 = vaddq_u16(b2, kOne);                           \
37*b2055c35SXin Li   (V).val[1] = vshrn_n_u16(r3, 8);                                     \
38*b2055c35SXin Li   (V).val[2] = vshrn_n_u16(g3, 8);                                     \
39*b2055c35SXin Li   (V).val[(OTHER)] = vshrn_n_u16(b3, 8);                               \
40*b2055c35SXin Li } while (0)
41*b2055c35SXin Li 
ApplyAlphaMultiply_NEON(uint8_t * rgba,int alpha_first,int w,int h,int stride)42*b2055c35SXin Li static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first,
43*b2055c35SXin Li                                     int w, int h, int stride) {
44*b2055c35SXin Li   const uint16x8_t kOne = vdupq_n_u16(1u);
45*b2055c35SXin Li   while (h-- > 0) {
46*b2055c35SXin Li     uint32_t* const rgbx = (uint32_t*)rgba;
47*b2055c35SXin Li     int i = 0;
48*b2055c35SXin Li     if (alpha_first) {
49*b2055c35SXin Li       for (; i + 8 <= w; i += 8) {
50*b2055c35SXin Li         // load aaaa...|rrrr...|gggg...|bbbb...
51*b2055c35SXin Li         uint8x8x4_t RGBX = vld4_u8((const uint8_t*)(rgbx + i));
52*b2055c35SXin Li         MULTIPLY_BY_ALPHA(RGBX, 0, 3);
53*b2055c35SXin Li         vst4_u8((uint8_t*)(rgbx + i), RGBX);
54*b2055c35SXin Li       }
55*b2055c35SXin Li     } else {
56*b2055c35SXin Li       for (; i + 8 <= w; i += 8) {
57*b2055c35SXin Li         uint8x8x4_t RGBX = vld4_u8((const uint8_t*)(rgbx + i));
58*b2055c35SXin Li         MULTIPLY_BY_ALPHA(RGBX, 3, 0);
59*b2055c35SXin Li         vst4_u8((uint8_t*)(rgbx + i), RGBX);
60*b2055c35SXin Li       }
61*b2055c35SXin Li     }
62*b2055c35SXin Li     // Finish with left-overs.
63*b2055c35SXin Li     for (; i < w; ++i) {
64*b2055c35SXin Li       uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
65*b2055c35SXin Li       const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
66*b2055c35SXin Li       const uint32_t a = alpha[4 * i];
67*b2055c35SXin Li       if (a != 0xff) {
68*b2055c35SXin Li         const uint32_t mult = MULTIPLIER(a);
69*b2055c35SXin Li         rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
70*b2055c35SXin Li         rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
71*b2055c35SXin Li         rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
72*b2055c35SXin Li       }
73*b2055c35SXin Li     }
74*b2055c35SXin Li     rgba += stride;
75*b2055c35SXin Li   }
76*b2055c35SXin Li }
77*b2055c35SXin Li #undef MULTIPLY_BY_ALPHA
78*b2055c35SXin Li #undef MULTIPLIER
79*b2055c35SXin Li #undef PREMULTIPLY
80*b2055c35SXin Li 
81*b2055c35SXin Li //------------------------------------------------------------------------------
82*b2055c35SXin Li 
DispatchAlpha_NEON(const uint8_t * WEBP_RESTRICT alpha,int alpha_stride,int width,int height,uint8_t * WEBP_RESTRICT dst,int dst_stride)83*b2055c35SXin Li static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha,
84*b2055c35SXin Li                               int alpha_stride, int width, int height,
85*b2055c35SXin Li                               uint8_t* WEBP_RESTRICT dst, int dst_stride) {
86*b2055c35SXin Li   uint32_t alpha_mask = 0xffu;
87*b2055c35SXin Li   uint8x8_t mask8 = vdup_n_u8(0xff);
88*b2055c35SXin Li   uint32_t tmp[2];
89*b2055c35SXin Li   int i, j;
90*b2055c35SXin Li   for (j = 0; j < height; ++j) {
91*b2055c35SXin Li     // We don't know if alpha is first or last in dst[] (depending on rgbA/Argb
92*b2055c35SXin Li     // mode). So we must be sure dst[4*i + 8 - 1] is writable for the store.
93*b2055c35SXin Li     // Hence the test with 'width - 1' instead of just 'width'.
94*b2055c35SXin Li     for (i = 0; i + 8 <= width - 1; i += 8) {
95*b2055c35SXin Li       uint8x8x4_t rgbX = vld4_u8((const uint8_t*)(dst + 4 * i));
96*b2055c35SXin Li       const uint8x8_t alphas = vld1_u8(alpha + i);
97*b2055c35SXin Li       rgbX.val[0] = alphas;
98*b2055c35SXin Li       vst4_u8((uint8_t*)(dst + 4 * i), rgbX);
99*b2055c35SXin Li       mask8 = vand_u8(mask8, alphas);
100*b2055c35SXin Li     }
101*b2055c35SXin Li     for (; i < width; ++i) {
102*b2055c35SXin Li       const uint32_t alpha_value = alpha[i];
103*b2055c35SXin Li       dst[4 * i] = alpha_value;
104*b2055c35SXin Li       alpha_mask &= alpha_value;
105*b2055c35SXin Li     }
106*b2055c35SXin Li     alpha += alpha_stride;
107*b2055c35SXin Li     dst += dst_stride;
108*b2055c35SXin Li   }
109*b2055c35SXin Li   vst1_u8((uint8_t*)tmp, mask8);
110*b2055c35SXin Li   alpha_mask *= 0x01010101;
111*b2055c35SXin Li   alpha_mask &= tmp[0];
112*b2055c35SXin Li   alpha_mask &= tmp[1];
113*b2055c35SXin Li   return (alpha_mask != 0xffffffffu);
114*b2055c35SXin Li }
115*b2055c35SXin Li 
DispatchAlphaToGreen_NEON(const uint8_t * WEBP_RESTRICT alpha,int alpha_stride,int width,int height,uint32_t * WEBP_RESTRICT dst,int dst_stride)116*b2055c35SXin Li static void DispatchAlphaToGreen_NEON(const uint8_t* WEBP_RESTRICT alpha,
117*b2055c35SXin Li                                       int alpha_stride, int width, int height,
118*b2055c35SXin Li                                       uint32_t* WEBP_RESTRICT dst,
119*b2055c35SXin Li                                       int dst_stride) {
120*b2055c35SXin Li   int i, j;
121*b2055c35SXin Li   uint8x8x4_t greens;   // leave A/R/B channels zero'd.
122*b2055c35SXin Li   greens.val[0] = vdup_n_u8(0);
123*b2055c35SXin Li   greens.val[2] = vdup_n_u8(0);
124*b2055c35SXin Li   greens.val[3] = vdup_n_u8(0);
125*b2055c35SXin Li   for (j = 0; j < height; ++j) {
126*b2055c35SXin Li     for (i = 0; i + 8 <= width; i += 8) {
127*b2055c35SXin Li       greens.val[1] = vld1_u8(alpha + i);
128*b2055c35SXin Li       vst4_u8((uint8_t*)(dst + i), greens);
129*b2055c35SXin Li     }
130*b2055c35SXin Li     for (; i < width; ++i) dst[i] = alpha[i] << 8;
131*b2055c35SXin Li     alpha += alpha_stride;
132*b2055c35SXin Li     dst += dst_stride;
133*b2055c35SXin Li   }
134*b2055c35SXin Li }
135*b2055c35SXin Li 
ExtractAlpha_NEON(const uint8_t * WEBP_RESTRICT argb,int argb_stride,int width,int height,uint8_t * WEBP_RESTRICT alpha,int alpha_stride)136*b2055c35SXin Li static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
137*b2055c35SXin Li                              int width, int height,
138*b2055c35SXin Li                              uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
139*b2055c35SXin Li   uint32_t alpha_mask = 0xffu;
140*b2055c35SXin Li   uint8x8_t mask8 = vdup_n_u8(0xff);
141*b2055c35SXin Li   uint32_t tmp[2];
142*b2055c35SXin Li   int i, j;
143*b2055c35SXin Li   for (j = 0; j < height; ++j) {
144*b2055c35SXin Li     // We don't know if alpha is first or last in dst[] (depending on rgbA/Argb
145*b2055c35SXin Li     // mode). So we must be sure dst[4*i + 8 - 1] is writable for the store.
146*b2055c35SXin Li     // Hence the test with 'width - 1' instead of just 'width'.
147*b2055c35SXin Li     for (i = 0; i + 8 <= width - 1; i += 8) {
148*b2055c35SXin Li       const uint8x8x4_t rgbX = vld4_u8((const uint8_t*)(argb + 4 * i));
149*b2055c35SXin Li       const uint8x8_t alphas = rgbX.val[0];
150*b2055c35SXin Li       vst1_u8((uint8_t*)(alpha + i), alphas);
151*b2055c35SXin Li       mask8 = vand_u8(mask8, alphas);
152*b2055c35SXin Li     }
153*b2055c35SXin Li     for (; i < width; ++i) {
154*b2055c35SXin Li       alpha[i] = argb[4 * i];
155*b2055c35SXin Li       alpha_mask &= alpha[i];
156*b2055c35SXin Li     }
157*b2055c35SXin Li     argb += argb_stride;
158*b2055c35SXin Li     alpha += alpha_stride;
159*b2055c35SXin Li   }
160*b2055c35SXin Li   vst1_u8((uint8_t*)tmp, mask8);
161*b2055c35SXin Li   alpha_mask *= 0x01010101;
162*b2055c35SXin Li   alpha_mask &= tmp[0];
163*b2055c35SXin Li   alpha_mask &= tmp[1];
164*b2055c35SXin Li   return (alpha_mask == 0xffffffffu);
165*b2055c35SXin Li }
166*b2055c35SXin Li 
ExtractGreen_NEON(const uint32_t * WEBP_RESTRICT argb,uint8_t * WEBP_RESTRICT alpha,int size)167*b2055c35SXin Li static void ExtractGreen_NEON(const uint32_t* WEBP_RESTRICT argb,
168*b2055c35SXin Li                               uint8_t* WEBP_RESTRICT alpha, int size) {
169*b2055c35SXin Li   int i;
170*b2055c35SXin Li   for (i = 0; i + 16 <= size; i += 16) {
171*b2055c35SXin Li     const uint8x16x4_t rgbX = vld4q_u8((const uint8_t*)(argb + i));
172*b2055c35SXin Li     const uint8x16_t greens = rgbX.val[1];
173*b2055c35SXin Li     vst1q_u8(alpha + i, greens);
174*b2055c35SXin Li   }
175*b2055c35SXin Li   for (; i < size; ++i) alpha[i] = (argb[i] >> 8) & 0xff;
176*b2055c35SXin Li }
177*b2055c35SXin Li 
178*b2055c35SXin Li //------------------------------------------------------------------------------
179*b2055c35SXin Li 
180*b2055c35SXin Li extern void WebPInitAlphaProcessingNEON(void);
181*b2055c35SXin Li 
WebPInitAlphaProcessingNEON(void)182*b2055c35SXin Li WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingNEON(void) {
183*b2055c35SXin Li   WebPApplyAlphaMultiply = ApplyAlphaMultiply_NEON;
184*b2055c35SXin Li   WebPDispatchAlpha = DispatchAlpha_NEON;
185*b2055c35SXin Li   WebPDispatchAlphaToGreen = DispatchAlphaToGreen_NEON;
186*b2055c35SXin Li   WebPExtractAlpha = ExtractAlpha_NEON;
187*b2055c35SXin Li   WebPExtractGreen = ExtractGreen_NEON;
188*b2055c35SXin Li }
189*b2055c35SXin Li 
190*b2055c35SXin Li #else  // !WEBP_USE_NEON
191*b2055c35SXin Li 
192*b2055c35SXin Li WEBP_DSP_INIT_STUB(WebPInitAlphaProcessingNEON)
193*b2055c35SXin Li 
194*b2055c35SXin Li #endif  // WEBP_USE_NEON
195