Path: blob/master/3rdparty/libwebp/src/dsp/alpha_processing_neon.c
16348 views
// Copyright 2017 Google Inc. All Rights Reserved.1//2// Use of this source code is governed by a BSD-style license3// that can be found in the COPYING file in the root of the source4// tree. An additional intellectual property rights grant can be found5// in the file PATENTS. All contributing project authors may6// be found in the AUTHORS file in the root of the source tree.7// -----------------------------------------------------------------------------8//9// Utilities for processing transparent channel, NEON version.10//11// Author: Skal ([email protected])1213#include "src/dsp/dsp.h"1415#if defined(WEBP_USE_NEON)1617#include "src/dsp/neon.h"1819//------------------------------------------------------------------------------2021#define MULTIPLIER(a) ((a) * 0x8081)22#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)2324#define MULTIPLY_BY_ALPHA(V, ALPHA, OTHER) do { \25const uint8x8_t alpha = (V).val[(ALPHA)]; \26const uint16x8_t r1 = vmull_u8((V).val[1], alpha); \27const uint16x8_t g1 = vmull_u8((V).val[2], alpha); \28const uint16x8_t b1 = vmull_u8((V).val[(OTHER)], alpha); \29/* we use: v / 255 = (v + 1 + (v >> 8)) >> 8 */ \30const uint16x8_t r2 = vsraq_n_u16(r1, r1, 8); \31const uint16x8_t g2 = vsraq_n_u16(g1, g1, 8); \32const uint16x8_t b2 = vsraq_n_u16(b1, b1, 8); \33const uint16x8_t r3 = vaddq_u16(r2, kOne); \34const uint16x8_t g3 = vaddq_u16(g2, kOne); \35const uint16x8_t b3 = vaddq_u16(b2, kOne); \36(V).val[1] = vshrn_n_u16(r3, 8); \37(V).val[2] = vshrn_n_u16(g3, 8); \38(V).val[(OTHER)] = vshrn_n_u16(b3, 8); \39} while (0)4041static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first,42int w, int h, int stride) {43const uint16x8_t kOne = vdupq_n_u16(1u);44while (h-- > 0) {45uint32_t* const rgbx = (uint32_t*)rgba;46int i = 0;47if (alpha_first) {48for (; i + 8 <= w; i += 8) {49// load aaaa...|rrrr...|gggg...|bbbb...50uint8x8x4_t RGBX = vld4_u8((const uint8_t*)(rgbx + i));51MULTIPLY_BY_ALPHA(RGBX, 0, 3);52vst4_u8((uint8_t*)(rgbx + i), RGBX);53}54} else {55for (; i + 8 <= w; i += 8) {56uint8x8x4_t RGBX = vld4_u8((const uint8_t*)(rgbx + i));57MULTIPLY_BY_ALPHA(RGBX, 3, 0);58vst4_u8((uint8_t*)(rgbx + i), RGBX);59}60}61// Finish with left-overs.62for (; i < w; ++i) {63uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);64const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);65const uint32_t a = alpha[4 * i];66if (a != 0xff) {67const uint32_t mult = MULTIPLIER(a);68rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);69rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);70rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);71}72}73rgba += stride;74}75}76#undef MULTIPLY_BY_ALPHA77#undef MULTIPLIER78#undef PREMULTIPLY7980//------------------------------------------------------------------------------8182static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride,83int width, int height,84uint8_t* dst, int dst_stride) {85uint32_t alpha_mask = 0xffffffffu;86uint8x8_t mask8 = vdup_n_u8(0xff);87uint32_t tmp[2];88int i, j;89for (j = 0; j < height; ++j) {90// We don't know if alpha is first or last in dst[] (depending on rgbA/Argb91// mode). So we must be sure dst[4*i + 8 - 1] is writable for the store.92// Hence the test with 'width - 1' instead of just 'width'.93for (i = 0; i + 8 <= width - 1; i += 8) {94uint8x8x4_t rgbX = vld4_u8((const uint8_t*)(dst + 4 * i));95const uint8x8_t alphas = vld1_u8(alpha + i);96rgbX.val[0] = alphas;97vst4_u8((uint8_t*)(dst + 4 * i), rgbX);98mask8 = vand_u8(mask8, alphas);99}100for (; i < width; ++i) {101const uint32_t alpha_value = alpha[i];102dst[4 * i] = alpha_value;103alpha_mask &= alpha_value;104}105alpha += alpha_stride;106dst += dst_stride;107}108vst1_u8((uint8_t*)tmp, mask8);109alpha_mask &= tmp[0];110alpha_mask &= tmp[1];111return (alpha_mask != 0xffffffffu);112}113114static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride,115int width, int height,116uint32_t* dst, int dst_stride) {117int i, j;118uint8x8x4_t greens; // leave A/R/B channels zero'd.119greens.val[0] = vdup_n_u8(0);120greens.val[2] = vdup_n_u8(0);121greens.val[3] = vdup_n_u8(0);122for (j = 0; j < height; ++j) {123for (i = 0; i + 8 <= width; i += 8) {124greens.val[1] = vld1_u8(alpha + i);125vst4_u8((uint8_t*)(dst + i), greens);126}127for (; i < width; ++i) dst[i] = alpha[i] << 8;128alpha += alpha_stride;129dst += dst_stride;130}131}132133static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride,134int width, int height,135uint8_t* alpha, int alpha_stride) {136uint32_t alpha_mask = 0xffffffffu;137uint8x8_t mask8 = vdup_n_u8(0xff);138uint32_t tmp[2];139int i, j;140for (j = 0; j < height; ++j) {141// We don't know if alpha is first or last in dst[] (depending on rgbA/Argb142// mode). So we must be sure dst[4*i + 8 - 1] is writable for the store.143// Hence the test with 'width - 1' instead of just 'width'.144for (i = 0; i + 8 <= width - 1; i += 8) {145const uint8x8x4_t rgbX = vld4_u8((const uint8_t*)(argb + 4 * i));146const uint8x8_t alphas = rgbX.val[0];147vst1_u8((uint8_t*)(alpha + i), alphas);148mask8 = vand_u8(mask8, alphas);149}150for (; i < width; ++i) {151alpha[i] = argb[4 * i];152alpha_mask &= alpha[i];153}154argb += argb_stride;155alpha += alpha_stride;156}157vst1_u8((uint8_t*)tmp, mask8);158alpha_mask &= tmp[0];159alpha_mask &= tmp[1];160return (alpha_mask == 0xffffffffu);161}162163static void ExtractGreen_NEON(const uint32_t* argb,164uint8_t* alpha, int size) {165int i;166for (i = 0; i + 16 <= size; i += 16) {167const uint8x16x4_t rgbX = vld4q_u8((const uint8_t*)(argb + i));168const uint8x16_t greens = rgbX.val[1];169vst1q_u8(alpha + i, greens);170}171for (; i < size; ++i) alpha[i] = (argb[i] >> 8) & 0xff;172}173174//------------------------------------------------------------------------------175176extern void WebPInitAlphaProcessingNEON(void);177178WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingNEON(void) {179WebPApplyAlphaMultiply = ApplyAlphaMultiply_NEON;180WebPDispatchAlpha = DispatchAlpha_NEON;181WebPDispatchAlphaToGreen = DispatchAlphaToGreen_NEON;182WebPExtractAlpha = ExtractAlpha_NEON;183WebPExtractGreen = ExtractGreen_NEON;184}185186#else // !WEBP_USE_NEON187188WEBP_DSP_INIT_STUB(WebPInitAlphaProcessingNEON)189190#endif // WEBP_USE_NEON191192193