Path: blob/master/thirdparty/libwebp/src/dsp/alpha_processing_neon.c
9913 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* WEBP_RESTRICT alpha,83int alpha_stride, int width, int height,84uint8_t* WEBP_RESTRICT dst, int dst_stride) {85uint32_t alpha_mask = 0xffu;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 *= 0x01010101;110alpha_mask &= tmp[0];111alpha_mask &= tmp[1];112return (alpha_mask != 0xffffffffu);113}114115static void DispatchAlphaToGreen_NEON(const uint8_t* WEBP_RESTRICT alpha,116int alpha_stride, int width, int height,117uint32_t* WEBP_RESTRICT dst,118int dst_stride) {119int i, j;120uint8x8x4_t greens; // leave A/R/B channels zero'd.121greens.val[0] = vdup_n_u8(0);122greens.val[2] = vdup_n_u8(0);123greens.val[3] = vdup_n_u8(0);124for (j = 0; j < height; ++j) {125for (i = 0; i + 8 <= width; i += 8) {126greens.val[1] = vld1_u8(alpha + i);127vst4_u8((uint8_t*)(dst + i), greens);128}129for (; i < width; ++i) dst[i] = alpha[i] << 8;130alpha += alpha_stride;131dst += dst_stride;132}133}134135static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride,136int width, int height,137uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {138uint32_t alpha_mask = 0xffu;139uint8x8_t mask8 = vdup_n_u8(0xff);140uint32_t tmp[2];141int i, j;142for (j = 0; j < height; ++j) {143// We don't know if alpha is first or last in dst[] (depending on rgbA/Argb144// mode). So we must be sure dst[4*i + 8 - 1] is writable for the store.145// Hence the test with 'width - 1' instead of just 'width'.146for (i = 0; i + 8 <= width - 1; i += 8) {147const uint8x8x4_t rgbX = vld4_u8((const uint8_t*)(argb + 4 * i));148const uint8x8_t alphas = rgbX.val[0];149vst1_u8((uint8_t*)(alpha + i), alphas);150mask8 = vand_u8(mask8, alphas);151}152for (; i < width; ++i) {153alpha[i] = argb[4 * i];154alpha_mask &= alpha[i];155}156argb += argb_stride;157alpha += alpha_stride;158}159vst1_u8((uint8_t*)tmp, mask8);160alpha_mask *= 0x01010101;161alpha_mask &= tmp[0];162alpha_mask &= tmp[1];163return (alpha_mask == 0xffffffffu);164}165166static void ExtractGreen_NEON(const uint32_t* WEBP_RESTRICT argb,167uint8_t* WEBP_RESTRICT alpha, int size) {168int i;169for (i = 0; i + 16 <= size; i += 16) {170const uint8x16x4_t rgbX = vld4q_u8((const uint8_t*)(argb + i));171const uint8x16_t greens = rgbX.val[1];172vst1q_u8(alpha + i, greens);173}174for (; i < size; ++i) alpha[i] = (argb[i] >> 8) & 0xff;175}176177//------------------------------------------------------------------------------178179extern void WebPInitAlphaProcessingNEON(void);180181WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingNEON(void) {182WebPApplyAlphaMultiply = ApplyAlphaMultiply_NEON;183WebPDispatchAlpha = DispatchAlpha_NEON;184WebPDispatchAlphaToGreen = DispatchAlphaToGreen_NEON;185WebPExtractAlpha = ExtractAlpha_NEON;186WebPExtractGreen = ExtractGreen_NEON;187}188189#else // !WEBP_USE_NEON190191WEBP_DSP_INIT_STUB(WebPInitAlphaProcessingNEON)192193#endif // WEBP_USE_NEON194195196