(61d00a474) v0.9.7.1

This commit is contained in:
Regalis
2020-03-04 13:04:10 +01:00
parent 3c50efa5c9
commit 3c09ebe02f
5086 changed files with 786063 additions and 295871 deletions
@@ -0,0 +1,240 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include "./vpx_dsp_rtcd.h"
#include "./vpx_config.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/sum_neon.h"
uint32_t vpx_avg_4x4_neon(const uint8_t *a, int a_stride) {
const uint8x16_t b = load_unaligned_u8q(a, a_stride);
const uint16x8_t c = vaddl_u8(vget_low_u8(b), vget_high_u8(b));
const uint32x2_t d = horizontal_add_uint16x8(c);
return vget_lane_u32(vrshr_n_u32(d, 4), 0);
}
uint32_t vpx_avg_8x8_neon(const uint8_t *a, int a_stride) {
int i;
uint8x8_t b, c;
uint16x8_t sum;
uint32x2_t d;
b = vld1_u8(a);
a += a_stride;
c = vld1_u8(a);
a += a_stride;
sum = vaddl_u8(b, c);
for (i = 0; i < 6; ++i) {
const uint8x8_t d = vld1_u8(a);
a += a_stride;
sum = vaddw_u8(sum, d);
}
d = horizontal_add_uint16x8(sum);
return vget_lane_u32(vrshr_n_u32(d, 6), 0);
}
// coeff: 16 bits, dynamic range [-32640, 32640].
// length: value range {16, 64, 256, 1024}.
int vpx_satd_neon(const tran_low_t *coeff, int length) {
const int16x4_t zero = vdup_n_s16(0);
int32x4_t accum = vdupq_n_s32(0);
do {
const int16x8_t src0 = load_tran_low_to_s16q(coeff);
const int16x8_t src8 = load_tran_low_to_s16q(coeff + 8);
accum = vabal_s16(accum, vget_low_s16(src0), zero);
accum = vabal_s16(accum, vget_high_s16(src0), zero);
accum = vabal_s16(accum, vget_low_s16(src8), zero);
accum = vabal_s16(accum, vget_high_s16(src8), zero);
length -= 16;
coeff += 16;
} while (length != 0);
{
// satd: 26 bits, dynamic range [-32640 * 1024, 32640 * 1024]
const int64x2_t s0 = vpaddlq_s32(accum); // cascading summation of 'accum'.
const int32x2_t s1 = vadd_s32(vreinterpret_s32_s64(vget_low_s64(s0)),
vreinterpret_s32_s64(vget_high_s64(s0)));
const int satd = vget_lane_s32(s1, 0);
return satd;
}
}
void vpx_int_pro_row_neon(int16_t hbuf[16], uint8_t const *ref,
const int ref_stride, const int height) {
int i;
uint16x8_t vec_sum_lo = vdupq_n_u16(0);
uint16x8_t vec_sum_hi = vdupq_n_u16(0);
const int shift_factor = ((height >> 5) + 3) * -1;
const int16x8_t vec_shift = vdupq_n_s16(shift_factor);
for (i = 0; i < height; i += 8) {
const uint8x16_t vec_row1 = vld1q_u8(ref);
const uint8x16_t vec_row2 = vld1q_u8(ref + ref_stride);
const uint8x16_t vec_row3 = vld1q_u8(ref + ref_stride * 2);
const uint8x16_t vec_row4 = vld1q_u8(ref + ref_stride * 3);
const uint8x16_t vec_row5 = vld1q_u8(ref + ref_stride * 4);
const uint8x16_t vec_row6 = vld1q_u8(ref + ref_stride * 5);
const uint8x16_t vec_row7 = vld1q_u8(ref + ref_stride * 6);
const uint8x16_t vec_row8 = vld1q_u8(ref + ref_stride * 7);
vec_sum_lo = vaddw_u8(vec_sum_lo, vget_low_u8(vec_row1));
vec_sum_hi = vaddw_u8(vec_sum_hi, vget_high_u8(vec_row1));
vec_sum_lo = vaddw_u8(vec_sum_lo, vget_low_u8(vec_row2));
vec_sum_hi = vaddw_u8(vec_sum_hi, vget_high_u8(vec_row2));
vec_sum_lo = vaddw_u8(vec_sum_lo, vget_low_u8(vec_row3));
vec_sum_hi = vaddw_u8(vec_sum_hi, vget_high_u8(vec_row3));
vec_sum_lo = vaddw_u8(vec_sum_lo, vget_low_u8(vec_row4));
vec_sum_hi = vaddw_u8(vec_sum_hi, vget_high_u8(vec_row4));
vec_sum_lo = vaddw_u8(vec_sum_lo, vget_low_u8(vec_row5));
vec_sum_hi = vaddw_u8(vec_sum_hi, vget_high_u8(vec_row5));
vec_sum_lo = vaddw_u8(vec_sum_lo, vget_low_u8(vec_row6));
vec_sum_hi = vaddw_u8(vec_sum_hi, vget_high_u8(vec_row6));
vec_sum_lo = vaddw_u8(vec_sum_lo, vget_low_u8(vec_row7));
vec_sum_hi = vaddw_u8(vec_sum_hi, vget_high_u8(vec_row7));
vec_sum_lo = vaddw_u8(vec_sum_lo, vget_low_u8(vec_row8));
vec_sum_hi = vaddw_u8(vec_sum_hi, vget_high_u8(vec_row8));
ref += ref_stride * 8;
}
vec_sum_lo = vshlq_u16(vec_sum_lo, vec_shift);
vec_sum_hi = vshlq_u16(vec_sum_hi, vec_shift);
vst1q_s16(hbuf, vreinterpretq_s16_u16(vec_sum_lo));
hbuf += 8;
vst1q_s16(hbuf, vreinterpretq_s16_u16(vec_sum_hi));
}
int16_t vpx_int_pro_col_neon(uint8_t const *ref, const int width) {
int i;
uint16x8_t vec_sum = vdupq_n_u16(0);
for (i = 0; i < width; i += 16) {
const uint8x16_t vec_row = vld1q_u8(ref);
vec_sum = vaddw_u8(vec_sum, vget_low_u8(vec_row));
vec_sum = vaddw_u8(vec_sum, vget_high_u8(vec_row));
ref += 16;
}
return vget_lane_s16(vreinterpret_s16_u32(horizontal_add_uint16x8(vec_sum)),
0);
}
// ref, src = [0, 510] - max diff = 16-bits
// bwl = {2, 3, 4}, width = {16, 32, 64}
int vpx_vector_var_neon(int16_t const *ref, int16_t const *src, const int bwl) {
int width = 4 << bwl;
int32x4_t sse = vdupq_n_s32(0);
int16x8_t total = vdupq_n_s16(0);
assert(width >= 8);
assert((width % 8) == 0);
do {
const int16x8_t r = vld1q_s16(ref);
const int16x8_t s = vld1q_s16(src);
const int16x8_t diff = vsubq_s16(r, s); // [-510, 510], 10 bits.
const int16x4_t diff_lo = vget_low_s16(diff);
const int16x4_t diff_hi = vget_high_s16(diff);
sse = vmlal_s16(sse, diff_lo, diff_lo); // dynamic range 26 bits.
sse = vmlal_s16(sse, diff_hi, diff_hi);
total = vaddq_s16(total, diff); // dynamic range 16 bits.
ref += 8;
src += 8;
width -= 8;
} while (width != 0);
{
// Note: 'total''s pairwise addition could be implemented similarly to
// horizontal_add_uint16x8(), but one less vpaddl with 'total' when paired
// with the summation of 'sse' performed better on a Cortex-A15.
const int32x4_t t0 = vpaddlq_s16(total); // cascading summation of 'total'
const int32x2_t t1 = vadd_s32(vget_low_s32(t0), vget_high_s32(t0));
const int32x2_t t2 = vpadd_s32(t1, t1);
const int t = vget_lane_s32(t2, 0);
const int64x2_t s0 = vpaddlq_s32(sse); // cascading summation of 'sse'.
const int32x2_t s1 = vadd_s32(vreinterpret_s32_s64(vget_low_s64(s0)),
vreinterpret_s32_s64(vget_high_s64(s0)));
const int s = vget_lane_s32(s1, 0);
const int shift_factor = bwl + 2;
return s - ((t * t) >> shift_factor);
}
}
void vpx_minmax_8x8_neon(const uint8_t *a, int a_stride, const uint8_t *b,
int b_stride, int *min, int *max) {
// Load and concatenate.
const uint8x16_t a01 = vcombine_u8(vld1_u8(a), vld1_u8(a + a_stride));
const uint8x16_t a23 =
vcombine_u8(vld1_u8(a + 2 * a_stride), vld1_u8(a + 3 * a_stride));
const uint8x16_t a45 =
vcombine_u8(vld1_u8(a + 4 * a_stride), vld1_u8(a + 5 * a_stride));
const uint8x16_t a67 =
vcombine_u8(vld1_u8(a + 6 * a_stride), vld1_u8(a + 7 * a_stride));
const uint8x16_t b01 = vcombine_u8(vld1_u8(b), vld1_u8(b + b_stride));
const uint8x16_t b23 =
vcombine_u8(vld1_u8(b + 2 * b_stride), vld1_u8(b + 3 * b_stride));
const uint8x16_t b45 =
vcombine_u8(vld1_u8(b + 4 * b_stride), vld1_u8(b + 5 * b_stride));
const uint8x16_t b67 =
vcombine_u8(vld1_u8(b + 6 * b_stride), vld1_u8(b + 7 * b_stride));
// Absolute difference.
const uint8x16_t ab01_diff = vabdq_u8(a01, b01);
const uint8x16_t ab23_diff = vabdq_u8(a23, b23);
const uint8x16_t ab45_diff = vabdq_u8(a45, b45);
const uint8x16_t ab67_diff = vabdq_u8(a67, b67);
// Max values between the Q vectors.
const uint8x16_t ab0123_max = vmaxq_u8(ab01_diff, ab23_diff);
const uint8x16_t ab4567_max = vmaxq_u8(ab45_diff, ab67_diff);
const uint8x16_t ab0123_min = vminq_u8(ab01_diff, ab23_diff);
const uint8x16_t ab4567_min = vminq_u8(ab45_diff, ab67_diff);
const uint8x16_t ab07_max = vmaxq_u8(ab0123_max, ab4567_max);
const uint8x16_t ab07_min = vminq_u8(ab0123_min, ab4567_min);
// Split to D and start doing pairwise.
uint8x8_t ab_max = vmax_u8(vget_high_u8(ab07_max), vget_low_u8(ab07_max));
uint8x8_t ab_min = vmin_u8(vget_high_u8(ab07_min), vget_low_u8(ab07_min));
// Enough runs of vpmax/min propogate the max/min values to every position.
ab_max = vpmax_u8(ab_max, ab_max);
ab_min = vpmin_u8(ab_min, ab_min);
ab_max = vpmax_u8(ab_max, ab_max);
ab_min = vpmin_u8(ab_min, ab_min);
ab_max = vpmax_u8(ab_max, ab_max);
ab_min = vpmin_u8(ab_min, ab_min);
*min = *max = 0; // Clear high bits
// Store directly to avoid costly neon->gpr transfer.
vst1_lane_u8((uint8_t *)max, ab_max, 0);
vst1_lane_u8((uint8_t *)min, ab_min, 0);
}
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2017 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/mem_neon.h"
void vpx_comp_avg_pred_neon(uint8_t *comp, const uint8_t *pred, int width,
int height, const uint8_t *ref, int ref_stride) {
if (width > 8) {
int x, y = height;
do {
for (x = 0; x < width; x += 16) {
const uint8x16_t p = vld1q_u8(pred + x);
const uint8x16_t r = vld1q_u8(ref + x);
const uint8x16_t avg = vrhaddq_u8(p, r);
vst1q_u8(comp + x, avg);
}
comp += width;
pred += width;
ref += ref_stride;
} while (--y);
} else if (width == 8) {
int i = width * height;
do {
const uint8x16_t p = vld1q_u8(pred);
uint8x16_t r;
const uint8x8_t r_0 = vld1_u8(ref);
const uint8x8_t r_1 = vld1_u8(ref + ref_stride);
r = vcombine_u8(r_0, r_1);
ref += 2 * ref_stride;
r = vrhaddq_u8(r, p);
vst1q_u8(comp, r);
pred += 16;
comp += 16;
i -= 16;
} while (i);
} else {
int i = width * height;
assert(width == 4);
do {
const uint8x16_t p = vld1q_u8(pred);
uint8x16_t r;
r = load_unaligned_u8q(ref, ref_stride);
ref += 4 * ref_stride;
r = vrhaddq_u8(r, p);
vst1q_u8(comp, r);
pred += 16;
comp += 16;
i -= 16;
} while (i);
}
}
@@ -0,0 +1,480 @@
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/arm/transpose_neon.h"
extern const int16_t vpx_rv[];
static uint8x8_t average_k_out(const uint8x8_t a2, const uint8x8_t a1,
const uint8x8_t v0, const uint8x8_t b1,
const uint8x8_t b2) {
const uint8x8_t k1 = vrhadd_u8(a2, a1);
const uint8x8_t k2 = vrhadd_u8(b2, b1);
const uint8x8_t k3 = vrhadd_u8(k1, k2);
return vrhadd_u8(k3, v0);
}
static uint8x8_t generate_mask(const uint8x8_t a2, const uint8x8_t a1,
const uint8x8_t v0, const uint8x8_t b1,
const uint8x8_t b2, const uint8x8_t filter) {
const uint8x8_t a2_v0 = vabd_u8(a2, v0);
const uint8x8_t a1_v0 = vabd_u8(a1, v0);
const uint8x8_t b1_v0 = vabd_u8(b1, v0);
const uint8x8_t b2_v0 = vabd_u8(b2, v0);
uint8x8_t max = vmax_u8(a2_v0, a1_v0);
max = vmax_u8(b1_v0, max);
max = vmax_u8(b2_v0, max);
return vclt_u8(max, filter);
}
static uint8x8_t generate_output(const uint8x8_t a2, const uint8x8_t a1,
const uint8x8_t v0, const uint8x8_t b1,
const uint8x8_t b2, const uint8x8_t filter) {
const uint8x8_t k_out = average_k_out(a2, a1, v0, b1, b2);
const uint8x8_t mask = generate_mask(a2, a1, v0, b1, b2, filter);
return vbsl_u8(mask, k_out, v0);
}
// Same functions but for uint8x16_t.
static uint8x16_t average_k_outq(const uint8x16_t a2, const uint8x16_t a1,
const uint8x16_t v0, const uint8x16_t b1,
const uint8x16_t b2) {
const uint8x16_t k1 = vrhaddq_u8(a2, a1);
const uint8x16_t k2 = vrhaddq_u8(b2, b1);
const uint8x16_t k3 = vrhaddq_u8(k1, k2);
return vrhaddq_u8(k3, v0);
}
static uint8x16_t generate_maskq(const uint8x16_t a2, const uint8x16_t a1,
const uint8x16_t v0, const uint8x16_t b1,
const uint8x16_t b2, const uint8x16_t filter) {
const uint8x16_t a2_v0 = vabdq_u8(a2, v0);
const uint8x16_t a1_v0 = vabdq_u8(a1, v0);
const uint8x16_t b1_v0 = vabdq_u8(b1, v0);
const uint8x16_t b2_v0 = vabdq_u8(b2, v0);
uint8x16_t max = vmaxq_u8(a2_v0, a1_v0);
max = vmaxq_u8(b1_v0, max);
max = vmaxq_u8(b2_v0, max);
return vcltq_u8(max, filter);
}
static uint8x16_t generate_outputq(const uint8x16_t a2, const uint8x16_t a1,
const uint8x16_t v0, const uint8x16_t b1,
const uint8x16_t b2,
const uint8x16_t filter) {
const uint8x16_t k_out = average_k_outq(a2, a1, v0, b1, b2);
const uint8x16_t mask = generate_maskq(a2, a1, v0, b1, b2, filter);
return vbslq_u8(mask, k_out, v0);
}
void vpx_post_proc_down_and_across_mb_row_neon(uint8_t *src_ptr,
uint8_t *dst_ptr, int src_stride,
int dst_stride, int cols,
uint8_t *f, int size) {
uint8_t *src, *dst;
int row;
int col;
// While columns of length 16 can be processed, load them.
for (col = 0; col < cols - 8; col += 16) {
uint8x16_t a0, a1, a2, a3, a4, a5, a6, a7;
src = src_ptr - 2 * src_stride;
dst = dst_ptr;
a0 = vld1q_u8(src);
src += src_stride;
a1 = vld1q_u8(src);
src += src_stride;
a2 = vld1q_u8(src);
src += src_stride;
a3 = vld1q_u8(src);
src += src_stride;
for (row = 0; row < size; row += 4) {
uint8x16_t v_out_0, v_out_1, v_out_2, v_out_3;
const uint8x16_t filterq = vld1q_u8(f + col);
a4 = vld1q_u8(src);
src += src_stride;
a5 = vld1q_u8(src);
src += src_stride;
a6 = vld1q_u8(src);
src += src_stride;
a7 = vld1q_u8(src);
src += src_stride;
v_out_0 = generate_outputq(a0, a1, a2, a3, a4, filterq);
v_out_1 = generate_outputq(a1, a2, a3, a4, a5, filterq);
v_out_2 = generate_outputq(a2, a3, a4, a5, a6, filterq);
v_out_3 = generate_outputq(a3, a4, a5, a6, a7, filterq);
vst1q_u8(dst, v_out_0);
dst += dst_stride;
vst1q_u8(dst, v_out_1);
dst += dst_stride;
vst1q_u8(dst, v_out_2);
dst += dst_stride;
vst1q_u8(dst, v_out_3);
dst += dst_stride;
// Rotate over to the next slot.
a0 = a4;
a1 = a5;
a2 = a6;
a3 = a7;
}
src_ptr += 16;
dst_ptr += 16;
}
// Clean up any left over column of length 8.
if (col != cols) {
uint8x8_t a0, a1, a2, a3, a4, a5, a6, a7;
src = src_ptr - 2 * src_stride;
dst = dst_ptr;
a0 = vld1_u8(src);
src += src_stride;
a1 = vld1_u8(src);
src += src_stride;
a2 = vld1_u8(src);
src += src_stride;
a3 = vld1_u8(src);
src += src_stride;
for (row = 0; row < size; row += 4) {
uint8x8_t v_out_0, v_out_1, v_out_2, v_out_3;
const uint8x8_t filter = vld1_u8(f + col);
a4 = vld1_u8(src);
src += src_stride;
a5 = vld1_u8(src);
src += src_stride;
a6 = vld1_u8(src);
src += src_stride;
a7 = vld1_u8(src);
src += src_stride;
v_out_0 = generate_output(a0, a1, a2, a3, a4, filter);
v_out_1 = generate_output(a1, a2, a3, a4, a5, filter);
v_out_2 = generate_output(a2, a3, a4, a5, a6, filter);
v_out_3 = generate_output(a3, a4, a5, a6, a7, filter);
vst1_u8(dst, v_out_0);
dst += dst_stride;
vst1_u8(dst, v_out_1);
dst += dst_stride;
vst1_u8(dst, v_out_2);
dst += dst_stride;
vst1_u8(dst, v_out_3);
dst += dst_stride;
// Rotate over to the next slot.
a0 = a4;
a1 = a5;
a2 = a6;
a3 = a7;
}
// Not strictly necessary but makes resetting dst_ptr easier.
dst_ptr += 8;
}
dst_ptr -= cols;
for (row = 0; row < size; row += 8) {
uint8x8_t a0, a1, a2, a3;
uint8x8_t b0, b1, b2, b3, b4, b5, b6, b7;
src = dst_ptr;
dst = dst_ptr;
// Load 8 values, transpose 4 of them, and discard 2 because they will be
// reloaded later.
load_and_transpose_u8_4x8(src, dst_stride, &a0, &a1, &a2, &a3);
a3 = a1;
a2 = a1 = a0; // Extend left border.
src += 2;
for (col = 0; col < cols; col += 8) {
uint8x8_t v_out_0, v_out_1, v_out_2, v_out_3, v_out_4, v_out_5, v_out_6,
v_out_7;
// Although the filter is meant to be applied vertically and is instead
// being applied horizontally here it's OK because it's set in blocks of 8
// (or 16).
const uint8x8_t filter = vld1_u8(f + col);
load_and_transpose_u8_8x8(src, dst_stride, &b0, &b1, &b2, &b3, &b4, &b5,
&b6, &b7);
if (col + 8 == cols) {
// Last row. Extend border (b5).
b6 = b7 = b5;
}
v_out_0 = generate_output(a0, a1, a2, a3, b0, filter);
v_out_1 = generate_output(a1, a2, a3, b0, b1, filter);
v_out_2 = generate_output(a2, a3, b0, b1, b2, filter);
v_out_3 = generate_output(a3, b0, b1, b2, b3, filter);
v_out_4 = generate_output(b0, b1, b2, b3, b4, filter);
v_out_5 = generate_output(b1, b2, b3, b4, b5, filter);
v_out_6 = generate_output(b2, b3, b4, b5, b6, filter);
v_out_7 = generate_output(b3, b4, b5, b6, b7, filter);
transpose_and_store_u8_8x8(dst, dst_stride, v_out_0, v_out_1, v_out_2,
v_out_3, v_out_4, v_out_5, v_out_6, v_out_7);
a0 = b4;
a1 = b5;
a2 = b6;
a3 = b7;
src += 8;
dst += 8;
}
dst_ptr += 8 * dst_stride;
}
}
// sum += x;
// sumsq += x * y;
static void accumulate_sum_sumsq(const int16x4_t x, const int32x4_t xy,
int16x4_t *const sum, int32x4_t *const sumsq) {
const int16x4_t zero = vdup_n_s16(0);
const int32x4_t zeroq = vdupq_n_s32(0);
// Add in the first set because vext doesn't work with '0'.
*sum = vadd_s16(*sum, x);
*sumsq = vaddq_s32(*sumsq, xy);
// Shift x and xy to the right and sum. vext requires an immediate.
*sum = vadd_s16(*sum, vext_s16(zero, x, 1));
*sumsq = vaddq_s32(*sumsq, vextq_s32(zeroq, xy, 1));
*sum = vadd_s16(*sum, vext_s16(zero, x, 2));
*sumsq = vaddq_s32(*sumsq, vextq_s32(zeroq, xy, 2));
*sum = vadd_s16(*sum, vext_s16(zero, x, 3));
*sumsq = vaddq_s32(*sumsq, vextq_s32(zeroq, xy, 3));
}
// Generate mask based on (sumsq * 15 - sum * sum < flimit)
static uint16x4_t calculate_mask(const int16x4_t sum, const int32x4_t sumsq,
const int32x4_t f, const int32x4_t fifteen) {
const int32x4_t a = vmulq_s32(sumsq, fifteen);
const int32x4_t b = vmlsl_s16(a, sum, sum);
const uint32x4_t mask32 = vcltq_s32(b, f);
return vmovn_u32(mask32);
}
static uint8x8_t combine_mask(const int16x4_t sum_low, const int16x4_t sum_high,
const int32x4_t sumsq_low,
const int32x4_t sumsq_high, const int32x4_t f) {
const int32x4_t fifteen = vdupq_n_s32(15);
const uint16x4_t mask16_low = calculate_mask(sum_low, sumsq_low, f, fifteen);
const uint16x4_t mask16_high =
calculate_mask(sum_high, sumsq_high, f, fifteen);
return vmovn_u16(vcombine_u16(mask16_low, mask16_high));
}
// Apply filter of (8 + sum + s[c]) >> 4.
static uint8x8_t filter_pixels(const int16x8_t sum, const uint8x8_t s) {
const int16x8_t s16 = vreinterpretq_s16_u16(vmovl_u8(s));
const int16x8_t sum_s = vaddq_s16(sum, s16);
return vqrshrun_n_s16(sum_s, 4);
}
void vpx_mbpost_proc_across_ip_neon(uint8_t *src, int pitch, int rows, int cols,
int flimit) {
int row, col;
const int32x4_t f = vdupq_n_s32(flimit);
assert(cols % 8 == 0);
for (row = 0; row < rows; ++row) {
// Sum the first 8 elements, which are extended from s[0].
// sumsq gets primed with +16.
int sumsq = src[0] * src[0] * 9 + 16;
int sum = src[0] * 9;
uint8x8_t left_context, s, right_context;
int16x4_t sum_low, sum_high;
int32x4_t sumsq_low, sumsq_high;
// Sum (+square) the next 6 elements.
// Skip [0] because it's included above.
for (col = 1; col <= 6; ++col) {
sumsq += src[col] * src[col];
sum += src[col];
}
// Prime the sums. Later the loop uses the _high values to prime the new
// vectors.
sumsq_high = vdupq_n_s32(sumsq);
sum_high = vdup_n_s16(sum);
// Manually extend the left border.
left_context = vdup_n_u8(src[0]);
for (col = 0; col < cols; col += 8) {
uint8x8_t mask, output;
int16x8_t x, y;
int32x4_t xy_low, xy_high;
s = vld1_u8(src + col);
if (col + 8 == cols) {
// Last row. Extend border.
right_context = vdup_n_u8(src[col + 7]);
} else {
right_context = vld1_u8(src + col + 7);
}
x = vreinterpretq_s16_u16(vsubl_u8(right_context, left_context));
y = vreinterpretq_s16_u16(vaddl_u8(right_context, left_context));
xy_low = vmull_s16(vget_low_s16(x), vget_low_s16(y));
xy_high = vmull_s16(vget_high_s16(x), vget_high_s16(y));
// Catch up to the last sum'd value.
sum_low = vdup_lane_s16(sum_high, 3);
sumsq_low = vdupq_lane_s32(vget_high_s32(sumsq_high), 1);
accumulate_sum_sumsq(vget_low_s16(x), xy_low, &sum_low, &sumsq_low);
// Need to do this sequentially because we need the max value from
// sum_low.
sum_high = vdup_lane_s16(sum_low, 3);
sumsq_high = vdupq_lane_s32(vget_high_s32(sumsq_low), 1);
accumulate_sum_sumsq(vget_high_s16(x), xy_high, &sum_high, &sumsq_high);
mask = combine_mask(sum_low, sum_high, sumsq_low, sumsq_high, f);
output = filter_pixels(vcombine_s16(sum_low, sum_high), s);
output = vbsl_u8(mask, output, s);
vst1_u8(src + col, output);
left_context = s;
}
src += pitch;
}
}
// Apply filter of (vpx_rv + sum + s[c]) >> 4.
static uint8x8_t filter_pixels_rv(const int16x8_t sum, const uint8x8_t s,
const int16x8_t rv) {
const int16x8_t s16 = vreinterpretq_s16_u16(vmovl_u8(s));
const int16x8_t sum_s = vaddq_s16(sum, s16);
const int16x8_t rounded = vaddq_s16(sum_s, rv);
return vqshrun_n_s16(rounded, 4);
}
void vpx_mbpost_proc_down_neon(uint8_t *dst, int pitch, int rows, int cols,
int flimit) {
int row, col, i;
const int32x4_t f = vdupq_n_s32(flimit);
uint8x8_t below_context = vdup_n_u8(0);
// 8 columns are processed at a time.
// If rows is less than 8 the bottom border extension fails.
assert(cols % 8 == 0);
assert(rows >= 8);
// Load and keep the first 8 values in memory. Process a vertical stripe that
// is 8 wide.
for (col = 0; col < cols; col += 8) {
uint8x8_t s, above_context[8];
int16x8_t sum, sum_tmp;
int32x4_t sumsq_low, sumsq_high;
// Load and extend the top border.
s = vld1_u8(dst);
for (i = 0; i < 8; i++) {
above_context[i] = s;
}
sum_tmp = vreinterpretq_s16_u16(vmovl_u8(s));
// sum * 9
sum = vmulq_n_s16(sum_tmp, 9);
// (sum * 9) * sum == sum * sum * 9
sumsq_low = vmull_s16(vget_low_s16(sum), vget_low_s16(sum_tmp));
sumsq_high = vmull_s16(vget_high_s16(sum), vget_high_s16(sum_tmp));
// Load and discard the next 6 values to prime sum and sumsq.
for (i = 1; i <= 6; ++i) {
const uint8x8_t a = vld1_u8(dst + i * pitch);
const int16x8_t b = vreinterpretq_s16_u16(vmovl_u8(a));
sum = vaddq_s16(sum, b);
sumsq_low = vmlal_s16(sumsq_low, vget_low_s16(b), vget_low_s16(b));
sumsq_high = vmlal_s16(sumsq_high, vget_high_s16(b), vget_high_s16(b));
}
for (row = 0; row < rows; ++row) {
uint8x8_t mask, output;
int16x8_t x, y;
int32x4_t xy_low, xy_high;
s = vld1_u8(dst + row * pitch);
// Extend the bottom border.
if (row + 7 < rows) {
below_context = vld1_u8(dst + (row + 7) * pitch);
}
x = vreinterpretq_s16_u16(vsubl_u8(below_context, above_context[0]));
y = vreinterpretq_s16_u16(vaddl_u8(below_context, above_context[0]));
xy_low = vmull_s16(vget_low_s16(x), vget_low_s16(y));
xy_high = vmull_s16(vget_high_s16(x), vget_high_s16(y));
sum = vaddq_s16(sum, x);
sumsq_low = vaddq_s32(sumsq_low, xy_low);
sumsq_high = vaddq_s32(sumsq_high, xy_high);
mask = combine_mask(vget_low_s16(sum), vget_high_s16(sum), sumsq_low,
sumsq_high, f);
output = filter_pixels_rv(sum, s, vld1q_s16(vpx_rv + (row & 127)));
output = vbsl_u8(mask, output, s);
vst1_u8(dst + row * pitch, output);
above_context[0] = above_context[1];
above_context[1] = above_context[2];
above_context[2] = above_context[3];
above_context[3] = above_context[4];
above_context[4] = above_context[5];
above_context[5] = above_context[6];
above_context[6] = above_context[7];
above_context[7] = s;
}
dst += 8;
}
}
@@ -0,0 +1,387 @@
/*
* Copyright (c) 2017 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/txfm_common.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/transpose_neon.h"
// Some builds of gcc 4.9.2 and .3 have trouble with some of the inline
// functions.
#if !defined(__clang__) && !defined(__ANDROID__) && defined(__GNUC__) && \
__GNUC__ == 4 && __GNUC_MINOR__ == 9 && __GNUC_PATCHLEVEL__ < 4
void vpx_fdct16x16_neon(const int16_t *input, tran_low_t *output, int stride) {
vpx_fdct16x16_c(input, output, stride);
}
#else
static INLINE void load(const int16_t *a, int stride, int16x8_t *b /*[16]*/) {
b[0] = vld1q_s16(a);
a += stride;
b[1] = vld1q_s16(a);
a += stride;
b[2] = vld1q_s16(a);
a += stride;
b[3] = vld1q_s16(a);
a += stride;
b[4] = vld1q_s16(a);
a += stride;
b[5] = vld1q_s16(a);
a += stride;
b[6] = vld1q_s16(a);
a += stride;
b[7] = vld1q_s16(a);
a += stride;
b[8] = vld1q_s16(a);
a += stride;
b[9] = vld1q_s16(a);
a += stride;
b[10] = vld1q_s16(a);
a += stride;
b[11] = vld1q_s16(a);
a += stride;
b[12] = vld1q_s16(a);
a += stride;
b[13] = vld1q_s16(a);
a += stride;
b[14] = vld1q_s16(a);
a += stride;
b[15] = vld1q_s16(a);
}
// Store 8 16x8 values, assuming stride == 16.
static INLINE void store(tran_low_t *a, const int16x8_t *b /*[8]*/) {
store_s16q_to_tran_low(a, b[0]);
a += 16;
store_s16q_to_tran_low(a, b[1]);
a += 16;
store_s16q_to_tran_low(a, b[2]);
a += 16;
store_s16q_to_tran_low(a, b[3]);
a += 16;
store_s16q_to_tran_low(a, b[4]);
a += 16;
store_s16q_to_tran_low(a, b[5]);
a += 16;
store_s16q_to_tran_low(a, b[6]);
a += 16;
store_s16q_to_tran_low(a, b[7]);
}
// Load step of each pass. Add and subtract clear across the input, requiring
// all 16 values to be loaded. For the first pass it also multiplies by 4.
// To maybe reduce register usage this could be combined with the load() step to
// get the first 4 and last 4 values, cross those, then load the middle 8 values
// and cross them.
static INLINE void cross_input(const int16x8_t *a /*[16]*/,
int16x8_t *b /*[16]*/, const int pass) {
if (pass == 0) {
b[0] = vshlq_n_s16(vaddq_s16(a[0], a[15]), 2);
b[1] = vshlq_n_s16(vaddq_s16(a[1], a[14]), 2);
b[2] = vshlq_n_s16(vaddq_s16(a[2], a[13]), 2);
b[3] = vshlq_n_s16(vaddq_s16(a[3], a[12]), 2);
b[4] = vshlq_n_s16(vaddq_s16(a[4], a[11]), 2);
b[5] = vshlq_n_s16(vaddq_s16(a[5], a[10]), 2);
b[6] = vshlq_n_s16(vaddq_s16(a[6], a[9]), 2);
b[7] = vshlq_n_s16(vaddq_s16(a[7], a[8]), 2);
b[8] = vshlq_n_s16(vsubq_s16(a[7], a[8]), 2);
b[9] = vshlq_n_s16(vsubq_s16(a[6], a[9]), 2);
b[10] = vshlq_n_s16(vsubq_s16(a[5], a[10]), 2);
b[11] = vshlq_n_s16(vsubq_s16(a[4], a[11]), 2);
b[12] = vshlq_n_s16(vsubq_s16(a[3], a[12]), 2);
b[13] = vshlq_n_s16(vsubq_s16(a[2], a[13]), 2);
b[14] = vshlq_n_s16(vsubq_s16(a[1], a[14]), 2);
b[15] = vshlq_n_s16(vsubq_s16(a[0], a[15]), 2);
} else {
b[0] = vaddq_s16(a[0], a[15]);
b[1] = vaddq_s16(a[1], a[14]);
b[2] = vaddq_s16(a[2], a[13]);
b[3] = vaddq_s16(a[3], a[12]);
b[4] = vaddq_s16(a[4], a[11]);
b[5] = vaddq_s16(a[5], a[10]);
b[6] = vaddq_s16(a[6], a[9]);
b[7] = vaddq_s16(a[7], a[8]);
b[8] = vsubq_s16(a[7], a[8]);
b[9] = vsubq_s16(a[6], a[9]);
b[10] = vsubq_s16(a[5], a[10]);
b[11] = vsubq_s16(a[4], a[11]);
b[12] = vsubq_s16(a[3], a[12]);
b[13] = vsubq_s16(a[2], a[13]);
b[14] = vsubq_s16(a[1], a[14]);
b[15] = vsubq_s16(a[0], a[15]);
}
}
// Quarter round at the beginning of the second pass. Can't use vrshr (rounding)
// because this only adds 1, not 1 << 2.
static INLINE void partial_round_shift(int16x8_t *a /*[16]*/) {
const int16x8_t one = vdupq_n_s16(1);
a[0] = vshrq_n_s16(vaddq_s16(a[0], one), 2);
a[1] = vshrq_n_s16(vaddq_s16(a[1], one), 2);
a[2] = vshrq_n_s16(vaddq_s16(a[2], one), 2);
a[3] = vshrq_n_s16(vaddq_s16(a[3], one), 2);
a[4] = vshrq_n_s16(vaddq_s16(a[4], one), 2);
a[5] = vshrq_n_s16(vaddq_s16(a[5], one), 2);
a[6] = vshrq_n_s16(vaddq_s16(a[6], one), 2);
a[7] = vshrq_n_s16(vaddq_s16(a[7], one), 2);
a[8] = vshrq_n_s16(vaddq_s16(a[8], one), 2);
a[9] = vshrq_n_s16(vaddq_s16(a[9], one), 2);
a[10] = vshrq_n_s16(vaddq_s16(a[10], one), 2);
a[11] = vshrq_n_s16(vaddq_s16(a[11], one), 2);
a[12] = vshrq_n_s16(vaddq_s16(a[12], one), 2);
a[13] = vshrq_n_s16(vaddq_s16(a[13], one), 2);
a[14] = vshrq_n_s16(vaddq_s16(a[14], one), 2);
a[15] = vshrq_n_s16(vaddq_s16(a[15], one), 2);
}
// fdct_round_shift((a +/- b) * c)
static INLINE void butterfly_one_coeff(const int16x8_t a, const int16x8_t b,
const tran_high_t c, int16x8_t *add,
int16x8_t *sub) {
const int32x4_t a0 = vmull_n_s16(vget_low_s16(a), c);
const int32x4_t a1 = vmull_n_s16(vget_high_s16(a), c);
const int32x4_t sum0 = vmlal_n_s16(a0, vget_low_s16(b), c);
const int32x4_t sum1 = vmlal_n_s16(a1, vget_high_s16(b), c);
const int32x4_t diff0 = vmlsl_n_s16(a0, vget_low_s16(b), c);
const int32x4_t diff1 = vmlsl_n_s16(a1, vget_high_s16(b), c);
const int16x4_t rounded0 = vqrshrn_n_s32(sum0, 14);
const int16x4_t rounded1 = vqrshrn_n_s32(sum1, 14);
const int16x4_t rounded2 = vqrshrn_n_s32(diff0, 14);
const int16x4_t rounded3 = vqrshrn_n_s32(diff1, 14);
*add = vcombine_s16(rounded0, rounded1);
*sub = vcombine_s16(rounded2, rounded3);
}
// fdct_round_shift(a * c0 +/- b * c1)
static INLINE void butterfly_two_coeff(const int16x8_t a, const int16x8_t b,
const tran_coef_t c0,
const tran_coef_t c1, int16x8_t *add,
int16x8_t *sub) {
const int32x4_t a0 = vmull_n_s16(vget_low_s16(a), c0);
const int32x4_t a1 = vmull_n_s16(vget_high_s16(a), c0);
const int32x4_t a2 = vmull_n_s16(vget_low_s16(a), c1);
const int32x4_t a3 = vmull_n_s16(vget_high_s16(a), c1);
const int32x4_t sum0 = vmlal_n_s16(a2, vget_low_s16(b), c0);
const int32x4_t sum1 = vmlal_n_s16(a3, vget_high_s16(b), c0);
const int32x4_t diff0 = vmlsl_n_s16(a0, vget_low_s16(b), c1);
const int32x4_t diff1 = vmlsl_n_s16(a1, vget_high_s16(b), c1);
const int16x4_t rounded0 = vqrshrn_n_s32(sum0, 14);
const int16x4_t rounded1 = vqrshrn_n_s32(sum1, 14);
const int16x4_t rounded2 = vqrshrn_n_s32(diff0, 14);
const int16x4_t rounded3 = vqrshrn_n_s32(diff1, 14);
*add = vcombine_s16(rounded0, rounded1);
*sub = vcombine_s16(rounded2, rounded3);
}
// Transpose 8x8 to a new location. Don't use transpose_neon.h because those
// are all in-place.
static INLINE void transpose_8x8(const int16x8_t *a /*[8]*/,
int16x8_t *b /*[8]*/) {
// Swap 16 bit elements.
const int16x8x2_t c0 = vtrnq_s16(a[0], a[1]);
const int16x8x2_t c1 = vtrnq_s16(a[2], a[3]);
const int16x8x2_t c2 = vtrnq_s16(a[4], a[5]);
const int16x8x2_t c3 = vtrnq_s16(a[6], a[7]);
// Swap 32 bit elements.
const int32x4x2_t d0 = vtrnq_s32(vreinterpretq_s32_s16(c0.val[0]),
vreinterpretq_s32_s16(c1.val[0]));
const int32x4x2_t d1 = vtrnq_s32(vreinterpretq_s32_s16(c0.val[1]),
vreinterpretq_s32_s16(c1.val[1]));
const int32x4x2_t d2 = vtrnq_s32(vreinterpretq_s32_s16(c2.val[0]),
vreinterpretq_s32_s16(c3.val[0]));
const int32x4x2_t d3 = vtrnq_s32(vreinterpretq_s32_s16(c2.val[1]),
vreinterpretq_s32_s16(c3.val[1]));
// Swap 64 bit elements
const int16x8x2_t e0 = vpx_vtrnq_s64_to_s16(d0.val[0], d2.val[0]);
const int16x8x2_t e1 = vpx_vtrnq_s64_to_s16(d1.val[0], d3.val[0]);
const int16x8x2_t e2 = vpx_vtrnq_s64_to_s16(d0.val[1], d2.val[1]);
const int16x8x2_t e3 = vpx_vtrnq_s64_to_s16(d1.val[1], d3.val[1]);
b[0] = e0.val[0];
b[1] = e1.val[0];
b[2] = e2.val[0];
b[3] = e3.val[0];
b[4] = e0.val[1];
b[5] = e1.val[1];
b[6] = e2.val[1];
b[7] = e3.val[1];
}
// Main body of fdct16x16.
static void dct_body(const int16x8_t *in /*[16]*/, int16x8_t *out /*[16]*/) {
int16x8_t s[8];
int16x8_t x[4];
int16x8_t step[8];
// stage 1
// From fwd_txfm.c: Work on the first eight values; fdct8(input,
// even_results);"
s[0] = vaddq_s16(in[0], in[7]);
s[1] = vaddq_s16(in[1], in[6]);
s[2] = vaddq_s16(in[2], in[5]);
s[3] = vaddq_s16(in[3], in[4]);
s[4] = vsubq_s16(in[3], in[4]);
s[5] = vsubq_s16(in[2], in[5]);
s[6] = vsubq_s16(in[1], in[6]);
s[7] = vsubq_s16(in[0], in[7]);
// fdct4(step, step);
x[0] = vaddq_s16(s[0], s[3]);
x[1] = vaddq_s16(s[1], s[2]);
x[2] = vsubq_s16(s[1], s[2]);
x[3] = vsubq_s16(s[0], s[3]);
// out[0] = fdct_round_shift((x0 + x1) * cospi_16_64)
// out[8] = fdct_round_shift((x0 - x1) * cospi_16_64)
butterfly_one_coeff(x[0], x[1], cospi_16_64, &out[0], &out[8]);
// out[4] = fdct_round_shift(x3 * cospi_8_64 + x2 * cospi_24_64);
// out[12] = fdct_round_shift(x3 * cospi_24_64 - x2 * cospi_8_64);
butterfly_two_coeff(x[3], x[2], cospi_24_64, cospi_8_64, &out[4], &out[12]);
// Stage 2
// Re-using source s5/s6
// s5 = fdct_round_shift((s6 - s5) * cospi_16_64)
// s6 = fdct_round_shift((s6 + s5) * cospi_16_64)
butterfly_one_coeff(s[6], s[5], cospi_16_64, &s[6], &s[5]);
// Stage 3
x[0] = vaddq_s16(s[4], s[5]);
x[1] = vsubq_s16(s[4], s[5]);
x[2] = vsubq_s16(s[7], s[6]);
x[3] = vaddq_s16(s[7], s[6]);
// Stage 4
// out[2] = fdct_round_shift(x0 * cospi_28_64 + x3 * cospi_4_64)
// out[14] = fdct_round_shift(x3 * cospi_28_64 + x0 * -cospi_4_64)
butterfly_two_coeff(x[3], x[0], cospi_28_64, cospi_4_64, &out[2], &out[14]);
// out[6] = fdct_round_shift(x1 * cospi_12_64 + x2 * cospi_20_64)
// out[10] = fdct_round_shift(x2 * cospi_12_64 + x1 * -cospi_20_64)
butterfly_two_coeff(x[2], x[1], cospi_12_64, cospi_20_64, &out[10], &out[6]);
// step 2
// From fwd_txfm.c: Work on the next eight values; step1 -> odd_results"
// That file distinguished between "in_high" and "step1" but the only
// difference is that "in_high" is the first 8 values and "step 1" is the
// second. Here, since they are all in one array, "step1" values are += 8.
// step2[2] = fdct_round_shift((step1[5] - step1[2]) * cospi_16_64)
// step2[3] = fdct_round_shift((step1[4] - step1[3]) * cospi_16_64)
// step2[4] = fdct_round_shift((step1[4] + step1[3]) * cospi_16_64)
// step2[5] = fdct_round_shift((step1[5] + step1[2]) * cospi_16_64)
butterfly_one_coeff(in[13], in[10], cospi_16_64, &s[5], &s[2]);
butterfly_one_coeff(in[12], in[11], cospi_16_64, &s[4], &s[3]);
// step 3
s[0] = vaddq_s16(in[8], s[3]);
s[1] = vaddq_s16(in[9], s[2]);
x[0] = vsubq_s16(in[9], s[2]);
x[1] = vsubq_s16(in[8], s[3]);
x[2] = vsubq_s16(in[15], s[4]);
x[3] = vsubq_s16(in[14], s[5]);
s[6] = vaddq_s16(in[14], s[5]);
s[7] = vaddq_s16(in[15], s[4]);
// step 4
// step2[1] = fdct_round_shift(step3[1] *-cospi_8_64 + step3[6] * cospi_24_64)
// step2[6] = fdct_round_shift(step3[1] * cospi_24_64 + step3[6] * cospi_8_64)
butterfly_two_coeff(s[6], s[1], cospi_24_64, cospi_8_64, &s[6], &s[1]);
// step2[2] = fdct_round_shift(step3[2] * cospi_24_64 + step3[5] * cospi_8_64)
// step2[5] = fdct_round_shift(step3[2] * cospi_8_64 - step3[5] * cospi_24_64)
butterfly_two_coeff(x[0], x[3], cospi_8_64, cospi_24_64, &s[2], &s[5]);
// step 5
step[0] = vaddq_s16(s[0], s[1]);
step[1] = vsubq_s16(s[0], s[1]);
step[2] = vaddq_s16(x[1], s[2]);
step[3] = vsubq_s16(x[1], s[2]);
step[4] = vsubq_s16(x[2], s[5]);
step[5] = vaddq_s16(x[2], s[5]);
step[6] = vsubq_s16(s[7], s[6]);
step[7] = vaddq_s16(s[7], s[6]);
// step 6
// out[1] = fdct_round_shift(step1[0] * cospi_30_64 + step1[7] * cospi_2_64)
// out[9] = fdct_round_shift(step1[1] * cospi_14_64 + step1[6] * cospi_18_64)
// out[5] = fdct_round_shift(step1[2] * cospi_22_64 + step1[5] * cospi_10_64)
// out[13] = fdct_round_shift(step1[3] * cospi_6_64 + step1[4] * cospi_26_64)
// out[3] = fdct_round_shift(step1[3] * -cospi_26_64 + step1[4] * cospi_6_64)
// out[11] = fdct_round_shift(step1[2] * -cospi_10_64 + step1[5] *
// cospi_22_64)
// out[7] = fdct_round_shift(step1[1] * -cospi_18_64 + step1[6] * cospi_14_64)
// out[15] = fdct_round_shift(step1[0] * -cospi_2_64 + step1[7] * cospi_30_64)
butterfly_two_coeff(step[6], step[1], cospi_14_64, cospi_18_64, &out[9],
&out[7]);
butterfly_two_coeff(step[7], step[0], cospi_30_64, cospi_2_64, &out[1],
&out[15]);
butterfly_two_coeff(step[4], step[3], cospi_6_64, cospi_26_64, &out[13],
&out[3]);
butterfly_two_coeff(step[5], step[2], cospi_22_64, cospi_10_64, &out[5],
&out[11]);
}
void vpx_fdct16x16_neon(const int16_t *input, tran_low_t *output, int stride) {
int16x8_t temp0[16];
int16x8_t temp1[16];
int16x8_t temp2[16];
int16x8_t temp3[16];
// Left half.
load(input, stride, temp0);
cross_input(temp0, temp1, 0);
dct_body(temp1, temp0);
// Right half.
load(input + 8, stride, temp1);
cross_input(temp1, temp2, 0);
dct_body(temp2, temp1);
// Transpose top left and top right quarters into one contiguous location to
// process to the top half.
transpose_8x8(&temp0[0], &temp2[0]);
transpose_8x8(&temp1[0], &temp2[8]);
partial_round_shift(temp2);
cross_input(temp2, temp3, 1);
dct_body(temp3, temp2);
transpose_s16_8x8(&temp2[0], &temp2[1], &temp2[2], &temp2[3], &temp2[4],
&temp2[5], &temp2[6], &temp2[7]);
transpose_s16_8x8(&temp2[8], &temp2[9], &temp2[10], &temp2[11], &temp2[12],
&temp2[13], &temp2[14], &temp2[15]);
store(output, temp2);
store(output + 8, temp2 + 8);
output += 8 * 16;
// Transpose bottom left and bottom right quarters into one contiguous
// location to process to the bottom half.
transpose_8x8(&temp0[8], &temp1[0]);
transpose_s16_8x8(&temp1[8], &temp1[9], &temp1[10], &temp1[11], &temp1[12],
&temp1[13], &temp1[14], &temp1[15]);
partial_round_shift(temp1);
cross_input(temp1, temp0, 1);
dct_body(temp0, temp1);
transpose_s16_8x8(&temp1[0], &temp1[1], &temp1[2], &temp1[3], &temp1[4],
&temp1[5], &temp1[6], &temp1[7]);
transpose_s16_8x8(&temp1[8], &temp1[9], &temp1[10], &temp1[11], &temp1[12],
&temp1[13], &temp1[14], &temp1[15]);
store(output, temp1);
store(output + 8, temp1 + 8);
}
#endif // !defined(__clang__) && !defined(__ANDROID__) && defined(__GNUC__) &&
// __GNUC__ == 4 && __GNUC_MINOR__ == 9 && __GNUC_PATCHLEVEL__ < 4
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2017 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/txfm_common.h"
#include "vpx_dsp/vpx_dsp_common.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/transpose_neon.h"
void vpx_fdct4x4_neon(const int16_t *input, tran_low_t *final_output,
int stride) {
int i;
// input[M * stride] * 16
int16x4_t input_0 = vshl_n_s16(vld1_s16(input + 0 * stride), 4);
int16x4_t input_1 = vshl_n_s16(vld1_s16(input + 1 * stride), 4);
int16x4_t input_2 = vshl_n_s16(vld1_s16(input + 2 * stride), 4);
int16x4_t input_3 = vshl_n_s16(vld1_s16(input + 3 * stride), 4);
// If the very first value != 0, then add 1.
if (input[0] != 0) {
const int16x4_t one = vreinterpret_s16_s64(vdup_n_s64(1));
input_0 = vadd_s16(input_0, one);
}
for (i = 0; i < 2; ++i) {
const int16x8_t input_01 = vcombine_s16(input_0, input_1);
const int16x8_t input_32 = vcombine_s16(input_3, input_2);
// in_0 +/- in_3, in_1 +/- in_2
const int16x8_t s_01 = vaddq_s16(input_01, input_32);
const int16x8_t s_32 = vsubq_s16(input_01, input_32);
// step_0 +/- step_1, step_2 +/- step_3
const int16x4_t s_0 = vget_low_s16(s_01);
const int16x4_t s_1 = vget_high_s16(s_01);
const int16x4_t s_2 = vget_high_s16(s_32);
const int16x4_t s_3 = vget_low_s16(s_32);
// (s_0 +/- s_1) * cospi_16_64
// Must expand all elements to s32. See 'needs32' comment in fwd_txfm.c.
const int32x4_t s_0_p_s_1 = vaddl_s16(s_0, s_1);
const int32x4_t s_0_m_s_1 = vsubl_s16(s_0, s_1);
const int32x4_t temp1 = vmulq_n_s32(s_0_p_s_1, cospi_16_64);
const int32x4_t temp2 = vmulq_n_s32(s_0_m_s_1, cospi_16_64);
// fdct_round_shift
int16x4_t out_0 = vrshrn_n_s32(temp1, DCT_CONST_BITS);
int16x4_t out_2 = vrshrn_n_s32(temp2, DCT_CONST_BITS);
// s_3 * cospi_8_64 + s_2 * cospi_24_64
// s_3 * cospi_24_64 - s_2 * cospi_8_64
const int32x4_t s_3_cospi_8_64 = vmull_n_s16(s_3, cospi_8_64);
const int32x4_t s_3_cospi_24_64 = vmull_n_s16(s_3, cospi_24_64);
const int32x4_t temp3 = vmlal_n_s16(s_3_cospi_8_64, s_2, cospi_24_64);
const int32x4_t temp4 = vmlsl_n_s16(s_3_cospi_24_64, s_2, cospi_8_64);
// fdct_round_shift
int16x4_t out_1 = vrshrn_n_s32(temp3, DCT_CONST_BITS);
int16x4_t out_3 = vrshrn_n_s32(temp4, DCT_CONST_BITS);
transpose_s16_4x4d(&out_0, &out_1, &out_2, &out_3);
input_0 = out_0;
input_1 = out_1;
input_2 = out_2;
input_3 = out_3;
}
{
// Not quite a rounding shift. Only add 1 despite shifting by 2.
const int16x8_t one = vdupq_n_s16(1);
int16x8_t out_01 = vcombine_s16(input_0, input_1);
int16x8_t out_23 = vcombine_s16(input_2, input_3);
out_01 = vshrq_n_s16(vaddq_s16(out_01, one), 2);
out_23 = vshrq_n_s16(vaddq_s16(out_23, one), 2);
store_s16q_to_tran_low(final_output + 0 * 8, out_01);
store_s16q_to_tran_low(final_output + 1 * 8, out_23);
}
}
@@ -0,0 +1,113 @@
/*
* Copyright (c) 2017 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "./vpx_config.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/sum_neon.h"
static INLINE tran_low_t get_lane(const int32x2_t a) {
#if CONFIG_VP9_HIGHBITDEPTH
return vget_lane_s32(a, 0);
#else
return vget_lane_s16(vreinterpret_s16_s32(a), 0);
#endif // CONFIG_VP9_HIGHBITDETPH
}
void vpx_fdct4x4_1_neon(const int16_t *input, tran_low_t *output, int stride) {
int16x4_t a0, a1, a2, a3;
int16x8_t b0, b1;
int16x8_t c;
int32x2_t d;
a0 = vld1_s16(input);
input += stride;
a1 = vld1_s16(input);
input += stride;
a2 = vld1_s16(input);
input += stride;
a3 = vld1_s16(input);
b0 = vcombine_s16(a0, a1);
b1 = vcombine_s16(a2, a3);
c = vaddq_s16(b0, b1);
d = horizontal_add_int16x8(c);
output[0] = get_lane(vshl_n_s32(d, 1));
output[1] = 0;
}
void vpx_fdct8x8_1_neon(const int16_t *input, tran_low_t *output, int stride) {
int r;
int16x8_t sum = vld1q_s16(&input[0]);
for (r = 1; r < 8; ++r) {
const int16x8_t input_00 = vld1q_s16(&input[r * stride]);
sum = vaddq_s16(sum, input_00);
}
output[0] = get_lane(horizontal_add_int16x8(sum));
output[1] = 0;
}
void vpx_fdct16x16_1_neon(const int16_t *input, tran_low_t *output,
int stride) {
int r;
int16x8_t left = vld1q_s16(input);
int16x8_t right = vld1q_s16(input + 8);
int32x2_t sum;
input += stride;
for (r = 1; r < 16; ++r) {
const int16x8_t a = vld1q_s16(input);
const int16x8_t b = vld1q_s16(input + 8);
input += stride;
left = vaddq_s16(left, a);
right = vaddq_s16(right, b);
}
sum = vadd_s32(horizontal_add_int16x8(left), horizontal_add_int16x8(right));
output[0] = get_lane(vshr_n_s32(sum, 1));
output[1] = 0;
}
void vpx_fdct32x32_1_neon(const int16_t *input, tran_low_t *output,
int stride) {
int r;
int16x8_t a0 = vld1q_s16(input);
int16x8_t a1 = vld1q_s16(input + 8);
int16x8_t a2 = vld1q_s16(input + 16);
int16x8_t a3 = vld1q_s16(input + 24);
int32x2_t sum;
input += stride;
for (r = 1; r < 32; ++r) {
const int16x8_t b0 = vld1q_s16(input);
const int16x8_t b1 = vld1q_s16(input + 8);
const int16x8_t b2 = vld1q_s16(input + 16);
const int16x8_t b3 = vld1q_s16(input + 24);
input += stride;
a0 = vaddq_s16(a0, b0);
a1 = vaddq_s16(a1, b1);
a2 = vaddq_s16(a2, b2);
a3 = vaddq_s16(a3, b3);
}
sum = vadd_s32(horizontal_add_int16x8(a0), horizontal_add_int16x8(a1));
sum = vadd_s32(sum, horizontal_add_int16x8(a2));
sum = vadd_s32(sum, horizontal_add_int16x8(a3));
output[0] = get_lane(vshr_n_s32(sum, 3));
output[1] = 0;
}
@@ -0,0 +1,210 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/txfm_common.h"
#include "vpx_dsp/vpx_dsp_common.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/mem_neon.h"
void vpx_fdct8x8_neon(const int16_t *input, tran_low_t *final_output,
int stride) {
int i;
// stage 1
int16x8_t input_0 = vshlq_n_s16(vld1q_s16(&input[0 * stride]), 2);
int16x8_t input_1 = vshlq_n_s16(vld1q_s16(&input[1 * stride]), 2);
int16x8_t input_2 = vshlq_n_s16(vld1q_s16(&input[2 * stride]), 2);
int16x8_t input_3 = vshlq_n_s16(vld1q_s16(&input[3 * stride]), 2);
int16x8_t input_4 = vshlq_n_s16(vld1q_s16(&input[4 * stride]), 2);
int16x8_t input_5 = vshlq_n_s16(vld1q_s16(&input[5 * stride]), 2);
int16x8_t input_6 = vshlq_n_s16(vld1q_s16(&input[6 * stride]), 2);
int16x8_t input_7 = vshlq_n_s16(vld1q_s16(&input[7 * stride]), 2);
for (i = 0; i < 2; ++i) {
int16x8_t out_0, out_1, out_2, out_3, out_4, out_5, out_6, out_7;
const int16x8_t v_s0 = vaddq_s16(input_0, input_7);
const int16x8_t v_s1 = vaddq_s16(input_1, input_6);
const int16x8_t v_s2 = vaddq_s16(input_2, input_5);
const int16x8_t v_s3 = vaddq_s16(input_3, input_4);
const int16x8_t v_s4 = vsubq_s16(input_3, input_4);
const int16x8_t v_s5 = vsubq_s16(input_2, input_5);
const int16x8_t v_s6 = vsubq_s16(input_1, input_6);
const int16x8_t v_s7 = vsubq_s16(input_0, input_7);
// fdct4(step, step);
int16x8_t v_x0 = vaddq_s16(v_s0, v_s3);
int16x8_t v_x1 = vaddq_s16(v_s1, v_s2);
int16x8_t v_x2 = vsubq_s16(v_s1, v_s2);
int16x8_t v_x3 = vsubq_s16(v_s0, v_s3);
// fdct4(step, step);
int32x4_t v_t0_lo = vaddl_s16(vget_low_s16(v_x0), vget_low_s16(v_x1));
int32x4_t v_t0_hi = vaddl_s16(vget_high_s16(v_x0), vget_high_s16(v_x1));
int32x4_t v_t1_lo = vsubl_s16(vget_low_s16(v_x0), vget_low_s16(v_x1));
int32x4_t v_t1_hi = vsubl_s16(vget_high_s16(v_x0), vget_high_s16(v_x1));
int32x4_t v_t2_lo = vmull_n_s16(vget_low_s16(v_x2), cospi_24_64);
int32x4_t v_t2_hi = vmull_n_s16(vget_high_s16(v_x2), cospi_24_64);
int32x4_t v_t3_lo = vmull_n_s16(vget_low_s16(v_x3), cospi_24_64);
int32x4_t v_t3_hi = vmull_n_s16(vget_high_s16(v_x3), cospi_24_64);
v_t2_lo = vmlal_n_s16(v_t2_lo, vget_low_s16(v_x3), cospi_8_64);
v_t2_hi = vmlal_n_s16(v_t2_hi, vget_high_s16(v_x3), cospi_8_64);
v_t3_lo = vmlsl_n_s16(v_t3_lo, vget_low_s16(v_x2), cospi_8_64);
v_t3_hi = vmlsl_n_s16(v_t3_hi, vget_high_s16(v_x2), cospi_8_64);
v_t0_lo = vmulq_n_s32(v_t0_lo, cospi_16_64);
v_t0_hi = vmulq_n_s32(v_t0_hi, cospi_16_64);
v_t1_lo = vmulq_n_s32(v_t1_lo, cospi_16_64);
v_t1_hi = vmulq_n_s32(v_t1_hi, cospi_16_64);
{
const int16x4_t a = vrshrn_n_s32(v_t0_lo, DCT_CONST_BITS);
const int16x4_t b = vrshrn_n_s32(v_t0_hi, DCT_CONST_BITS);
const int16x4_t c = vrshrn_n_s32(v_t1_lo, DCT_CONST_BITS);
const int16x4_t d = vrshrn_n_s32(v_t1_hi, DCT_CONST_BITS);
const int16x4_t e = vrshrn_n_s32(v_t2_lo, DCT_CONST_BITS);
const int16x4_t f = vrshrn_n_s32(v_t2_hi, DCT_CONST_BITS);
const int16x4_t g = vrshrn_n_s32(v_t3_lo, DCT_CONST_BITS);
const int16x4_t h = vrshrn_n_s32(v_t3_hi, DCT_CONST_BITS);
out_0 = vcombine_s16(a, c); // 00 01 02 03 40 41 42 43
out_2 = vcombine_s16(e, g); // 20 21 22 23 60 61 62 63
out_4 = vcombine_s16(b, d); // 04 05 06 07 44 45 46 47
out_6 = vcombine_s16(f, h); // 24 25 26 27 64 65 66 67
}
// Stage 2
v_x0 = vsubq_s16(v_s6, v_s5);
v_x1 = vaddq_s16(v_s6, v_s5);
v_t0_lo = vmull_n_s16(vget_low_s16(v_x0), cospi_16_64);
v_t0_hi = vmull_n_s16(vget_high_s16(v_x0), cospi_16_64);
v_t1_lo = vmull_n_s16(vget_low_s16(v_x1), cospi_16_64);
v_t1_hi = vmull_n_s16(vget_high_s16(v_x1), cospi_16_64);
{
const int16x4_t a = vrshrn_n_s32(v_t0_lo, DCT_CONST_BITS);
const int16x4_t b = vrshrn_n_s32(v_t0_hi, DCT_CONST_BITS);
const int16x4_t c = vrshrn_n_s32(v_t1_lo, DCT_CONST_BITS);
const int16x4_t d = vrshrn_n_s32(v_t1_hi, DCT_CONST_BITS);
const int16x8_t ab = vcombine_s16(a, b);
const int16x8_t cd = vcombine_s16(c, d);
// Stage 3
v_x0 = vaddq_s16(v_s4, ab);
v_x1 = vsubq_s16(v_s4, ab);
v_x2 = vsubq_s16(v_s7, cd);
v_x3 = vaddq_s16(v_s7, cd);
}
// Stage 4
v_t0_lo = vmull_n_s16(vget_low_s16(v_x3), cospi_4_64);
v_t0_hi = vmull_n_s16(vget_high_s16(v_x3), cospi_4_64);
v_t0_lo = vmlal_n_s16(v_t0_lo, vget_low_s16(v_x0), cospi_28_64);
v_t0_hi = vmlal_n_s16(v_t0_hi, vget_high_s16(v_x0), cospi_28_64);
v_t1_lo = vmull_n_s16(vget_low_s16(v_x1), cospi_12_64);
v_t1_hi = vmull_n_s16(vget_high_s16(v_x1), cospi_12_64);
v_t1_lo = vmlal_n_s16(v_t1_lo, vget_low_s16(v_x2), cospi_20_64);
v_t1_hi = vmlal_n_s16(v_t1_hi, vget_high_s16(v_x2), cospi_20_64);
v_t2_lo = vmull_n_s16(vget_low_s16(v_x2), cospi_12_64);
v_t2_hi = vmull_n_s16(vget_high_s16(v_x2), cospi_12_64);
v_t2_lo = vmlsl_n_s16(v_t2_lo, vget_low_s16(v_x1), cospi_20_64);
v_t2_hi = vmlsl_n_s16(v_t2_hi, vget_high_s16(v_x1), cospi_20_64);
v_t3_lo = vmull_n_s16(vget_low_s16(v_x3), cospi_28_64);
v_t3_hi = vmull_n_s16(vget_high_s16(v_x3), cospi_28_64);
v_t3_lo = vmlsl_n_s16(v_t3_lo, vget_low_s16(v_x0), cospi_4_64);
v_t3_hi = vmlsl_n_s16(v_t3_hi, vget_high_s16(v_x0), cospi_4_64);
{
const int16x4_t a = vrshrn_n_s32(v_t0_lo, DCT_CONST_BITS);
const int16x4_t b = vrshrn_n_s32(v_t0_hi, DCT_CONST_BITS);
const int16x4_t c = vrshrn_n_s32(v_t1_lo, DCT_CONST_BITS);
const int16x4_t d = vrshrn_n_s32(v_t1_hi, DCT_CONST_BITS);
const int16x4_t e = vrshrn_n_s32(v_t2_lo, DCT_CONST_BITS);
const int16x4_t f = vrshrn_n_s32(v_t2_hi, DCT_CONST_BITS);
const int16x4_t g = vrshrn_n_s32(v_t3_lo, DCT_CONST_BITS);
const int16x4_t h = vrshrn_n_s32(v_t3_hi, DCT_CONST_BITS);
out_1 = vcombine_s16(a, c); // 10 11 12 13 50 51 52 53
out_3 = vcombine_s16(e, g); // 30 31 32 33 70 71 72 73
out_5 = vcombine_s16(b, d); // 14 15 16 17 54 55 56 57
out_7 = vcombine_s16(f, h); // 34 35 36 37 74 75 76 77
}
// transpose 8x8
// Can't use transpose_s16_8x8() because the values are arranged in two 4x8
// columns.
{
// 00 01 02 03 40 41 42 43
// 10 11 12 13 50 51 52 53
// 20 21 22 23 60 61 62 63
// 30 31 32 33 70 71 72 73
// 04 05 06 07 44 45 46 47
// 14 15 16 17 54 55 56 57
// 24 25 26 27 64 65 66 67
// 34 35 36 37 74 75 76 77
const int32x4x2_t r02_s32 =
vtrnq_s32(vreinterpretq_s32_s16(out_0), vreinterpretq_s32_s16(out_2));
const int32x4x2_t r13_s32 =
vtrnq_s32(vreinterpretq_s32_s16(out_1), vreinterpretq_s32_s16(out_3));
const int32x4x2_t r46_s32 =
vtrnq_s32(vreinterpretq_s32_s16(out_4), vreinterpretq_s32_s16(out_6));
const int32x4x2_t r57_s32 =
vtrnq_s32(vreinterpretq_s32_s16(out_5), vreinterpretq_s32_s16(out_7));
const int16x8x2_t r01_s16 =
vtrnq_s16(vreinterpretq_s16_s32(r02_s32.val[0]),
vreinterpretq_s16_s32(r13_s32.val[0]));
const int16x8x2_t r23_s16 =
vtrnq_s16(vreinterpretq_s16_s32(r02_s32.val[1]),
vreinterpretq_s16_s32(r13_s32.val[1]));
const int16x8x2_t r45_s16 =
vtrnq_s16(vreinterpretq_s16_s32(r46_s32.val[0]),
vreinterpretq_s16_s32(r57_s32.val[0]));
const int16x8x2_t r67_s16 =
vtrnq_s16(vreinterpretq_s16_s32(r46_s32.val[1]),
vreinterpretq_s16_s32(r57_s32.val[1]));
input_0 = r01_s16.val[0];
input_1 = r01_s16.val[1];
input_2 = r23_s16.val[0];
input_3 = r23_s16.val[1];
input_4 = r45_s16.val[0];
input_5 = r45_s16.val[1];
input_6 = r67_s16.val[0];
input_7 = r67_s16.val[1];
// 00 10 20 30 40 50 60 70
// 01 11 21 31 41 51 61 71
// 02 12 22 32 42 52 62 72
// 03 13 23 33 43 53 63 73
// 04 14 24 34 44 54 64 74
// 05 15 25 35 45 55 65 75
// 06 16 26 36 46 56 66 76
// 07 17 27 37 47 57 67 77
}
} // for
{
// from vpx_dct_sse2.c
// Post-condition (division by two)
// division of two 16 bits signed numbers using shifts
// n / 2 = (n - (n >> 15)) >> 1
const int16x8_t sign_in0 = vshrq_n_s16(input_0, 15);
const int16x8_t sign_in1 = vshrq_n_s16(input_1, 15);
const int16x8_t sign_in2 = vshrq_n_s16(input_2, 15);
const int16x8_t sign_in3 = vshrq_n_s16(input_3, 15);
const int16x8_t sign_in4 = vshrq_n_s16(input_4, 15);
const int16x8_t sign_in5 = vshrq_n_s16(input_5, 15);
const int16x8_t sign_in6 = vshrq_n_s16(input_6, 15);
const int16x8_t sign_in7 = vshrq_n_s16(input_7, 15);
input_0 = vhsubq_s16(input_0, sign_in0);
input_1 = vhsubq_s16(input_1, sign_in1);
input_2 = vhsubq_s16(input_2, sign_in2);
input_3 = vhsubq_s16(input_3, sign_in3);
input_4 = vhsubq_s16(input_4, sign_in4);
input_5 = vhsubq_s16(input_5, sign_in5);
input_6 = vhsubq_s16(input_6, sign_in6);
input_7 = vhsubq_s16(input_7, sign_in7);
// store results
store_s16q_to_tran_low(final_output + 0 * 8, input_0);
store_s16q_to_tran_low(final_output + 1 * 8, input_1);
store_s16q_to_tran_low(final_output + 2 * 8, input_2);
store_s16q_to_tran_low(final_output + 3 * 8, input_3);
store_s16q_to_tran_low(final_output + 4 * 8, input_4);
store_s16q_to_tran_low(final_output + 5 * 8, input_5);
store_s16q_to_tran_low(final_output + 6 * 8, input_6);
store_s16q_to_tran_low(final_output + 7 * 8, input_7);
}
}
@@ -0,0 +1,116 @@
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/transpose_neon.h"
static void hadamard8x8_one_pass(int16x8_t *a0, int16x8_t *a1, int16x8_t *a2,
int16x8_t *a3, int16x8_t *a4, int16x8_t *a5,
int16x8_t *a6, int16x8_t *a7) {
const int16x8_t b0 = vaddq_s16(*a0, *a1);
const int16x8_t b1 = vsubq_s16(*a0, *a1);
const int16x8_t b2 = vaddq_s16(*a2, *a3);
const int16x8_t b3 = vsubq_s16(*a2, *a3);
const int16x8_t b4 = vaddq_s16(*a4, *a5);
const int16x8_t b5 = vsubq_s16(*a4, *a5);
const int16x8_t b6 = vaddq_s16(*a6, *a7);
const int16x8_t b7 = vsubq_s16(*a6, *a7);
const int16x8_t c0 = vaddq_s16(b0, b2);
const int16x8_t c1 = vaddq_s16(b1, b3);
const int16x8_t c2 = vsubq_s16(b0, b2);
const int16x8_t c3 = vsubq_s16(b1, b3);
const int16x8_t c4 = vaddq_s16(b4, b6);
const int16x8_t c5 = vaddq_s16(b5, b7);
const int16x8_t c6 = vsubq_s16(b4, b6);
const int16x8_t c7 = vsubq_s16(b5, b7);
*a0 = vaddq_s16(c0, c4);
*a1 = vsubq_s16(c2, c6);
*a2 = vsubq_s16(c0, c4);
*a3 = vaddq_s16(c2, c6);
*a4 = vaddq_s16(c3, c7);
*a5 = vsubq_s16(c3, c7);
*a6 = vsubq_s16(c1, c5);
*a7 = vaddq_s16(c1, c5);
}
void vpx_hadamard_8x8_neon(const int16_t *src_diff, ptrdiff_t src_stride,
tran_low_t *coeff) {
int16x8_t a0 = vld1q_s16(src_diff);
int16x8_t a1 = vld1q_s16(src_diff + src_stride);
int16x8_t a2 = vld1q_s16(src_diff + 2 * src_stride);
int16x8_t a3 = vld1q_s16(src_diff + 3 * src_stride);
int16x8_t a4 = vld1q_s16(src_diff + 4 * src_stride);
int16x8_t a5 = vld1q_s16(src_diff + 5 * src_stride);
int16x8_t a6 = vld1q_s16(src_diff + 6 * src_stride);
int16x8_t a7 = vld1q_s16(src_diff + 7 * src_stride);
hadamard8x8_one_pass(&a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7);
transpose_s16_8x8(&a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7);
hadamard8x8_one_pass(&a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7);
// Skip the second transpose because it is not required.
store_s16q_to_tran_low(coeff + 0, a0);
store_s16q_to_tran_low(coeff + 8, a1);
store_s16q_to_tran_low(coeff + 16, a2);
store_s16q_to_tran_low(coeff + 24, a3);
store_s16q_to_tran_low(coeff + 32, a4);
store_s16q_to_tran_low(coeff + 40, a5);
store_s16q_to_tran_low(coeff + 48, a6);
store_s16q_to_tran_low(coeff + 56, a7);
}
void vpx_hadamard_16x16_neon(const int16_t *src_diff, ptrdiff_t src_stride,
tran_low_t *coeff) {
int i;
/* Rearrange 16x16 to 8x32 and remove stride.
* Top left first. */
vpx_hadamard_8x8_neon(src_diff + 0 + 0 * src_stride, src_stride, coeff + 0);
/* Top right. */
vpx_hadamard_8x8_neon(src_diff + 8 + 0 * src_stride, src_stride, coeff + 64);
/* Bottom left. */
vpx_hadamard_8x8_neon(src_diff + 0 + 8 * src_stride, src_stride, coeff + 128);
/* Bottom right. */
vpx_hadamard_8x8_neon(src_diff + 8 + 8 * src_stride, src_stride, coeff + 192);
for (i = 0; i < 64; i += 8) {
const int16x8_t a0 = load_tran_low_to_s16q(coeff + 0);
const int16x8_t a1 = load_tran_low_to_s16q(coeff + 64);
const int16x8_t a2 = load_tran_low_to_s16q(coeff + 128);
const int16x8_t a3 = load_tran_low_to_s16q(coeff + 192);
const int16x8_t b0 = vhaddq_s16(a0, a1);
const int16x8_t b1 = vhsubq_s16(a0, a1);
const int16x8_t b2 = vhaddq_s16(a2, a3);
const int16x8_t b3 = vhsubq_s16(a2, a3);
const int16x8_t c0 = vaddq_s16(b0, b2);
const int16x8_t c1 = vaddq_s16(b1, b3);
const int16x8_t c2 = vsubq_s16(b0, b2);
const int16x8_t c3 = vsubq_s16(b1, b3);
store_s16q_to_tran_low(coeff + 0, c0);
store_s16q_to_tran_low(coeff + 64, c1);
store_s16q_to_tran_low(coeff + 128, c2);
store_s16q_to_tran_low(coeff + 192, c3);
coeff += 8;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,640 @@
/*
* Copyright (c) 2017 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/transpose_neon.h"
#include "vpx_dsp/txfm_common.h"
static INLINE void load_from_transformed(const int32_t *const trans_buf,
const int first, const int second,
int32x4x2_t *const q0,
int32x4x2_t *const q1) {
q0->val[0] = vld1q_s32(trans_buf + first * 8);
q0->val[1] = vld1q_s32(trans_buf + first * 8 + 4);
q1->val[0] = vld1q_s32(trans_buf + second * 8);
q1->val[1] = vld1q_s32(trans_buf + second * 8 + 4);
}
static INLINE void load_from_output(const int32_t *const out, const int first,
const int second, int32x4x2_t *const q0,
int32x4x2_t *const q1) {
q0->val[0] = vld1q_s32(out + first * 32);
q0->val[1] = vld1q_s32(out + first * 32 + 4);
q1->val[0] = vld1q_s32(out + second * 32);
q1->val[1] = vld1q_s32(out + second * 32 + 4);
}
static INLINE void store_in_output(int32_t *const out, const int first,
const int second, const int32x4x2_t q0,
const int32x4x2_t q1) {
vst1q_s32(out + first * 32, q0.val[0]);
vst1q_s32(out + first * 32 + 4, q0.val[1]);
vst1q_s32(out + second * 32, q1.val[0]);
vst1q_s32(out + second * 32 + 4, q1.val[1]);
}
static INLINE void highbd_store_combine_results(
uint16_t *p1, uint16_t *p2, const int stride, const int32x4x2_t q0,
const int32x4x2_t q1, const int32x4x2_t q2, const int32x4x2_t q3,
const int16x8_t max) {
int16x8_t o[4];
uint16x8_t d[4];
d[0] = vld1q_u16(p1);
p1 += stride;
d[1] = vld1q_u16(p1);
d[3] = vld1q_u16(p2);
p2 -= stride;
d[2] = vld1q_u16(p2);
o[0] = vcombine_s16(vrshrn_n_s32(q0.val[0], 6), vrshrn_n_s32(q0.val[1], 6));
o[1] = vcombine_s16(vrshrn_n_s32(q1.val[0], 6), vrshrn_n_s32(q1.val[1], 6));
o[2] = vcombine_s16(vrshrn_n_s32(q2.val[0], 6), vrshrn_n_s32(q2.val[1], 6));
o[3] = vcombine_s16(vrshrn_n_s32(q3.val[0], 6), vrshrn_n_s32(q3.val[1], 6));
o[0] = vqaddq_s16(o[0], vreinterpretq_s16_u16(d[0]));
o[1] = vqaddq_s16(o[1], vreinterpretq_s16_u16(d[1]));
o[2] = vqaddq_s16(o[2], vreinterpretq_s16_u16(d[2]));
o[3] = vqaddq_s16(o[3], vreinterpretq_s16_u16(d[3]));
o[0] = vminq_s16(o[0], max);
o[1] = vminq_s16(o[1], max);
o[2] = vminq_s16(o[2], max);
o[3] = vminq_s16(o[3], max);
d[0] = vqshluq_n_s16(o[0], 0);
d[1] = vqshluq_n_s16(o[1], 0);
d[2] = vqshluq_n_s16(o[2], 0);
d[3] = vqshluq_n_s16(o[3], 0);
vst1q_u16(p1, d[1]);
p1 -= stride;
vst1q_u16(p1, d[0]);
vst1q_u16(p2, d[2]);
p2 += stride;
vst1q_u16(p2, d[3]);
}
static INLINE void do_butterfly(const int32x4x2_t qIn0, const int32x4x2_t qIn1,
const int32_t first_const,
const int32_t second_const,
int32x4x2_t *const qOut0,
int32x4x2_t *const qOut1) {
int64x2x2_t q[4];
int32x2_t d[6];
// Note: using v{mul, mla, mls}l_n_s32 here slows down 35% with gcc 4.9.
d[4] = vdup_n_s32(first_const);
d[5] = vdup_n_s32(second_const);
q[0].val[0] = vmull_s32(vget_low_s32(qIn0.val[0]), d[4]);
q[0].val[1] = vmull_s32(vget_high_s32(qIn0.val[0]), d[4]);
q[1].val[0] = vmull_s32(vget_low_s32(qIn0.val[1]), d[4]);
q[1].val[1] = vmull_s32(vget_high_s32(qIn0.val[1]), d[4]);
q[0].val[0] = vmlsl_s32(q[0].val[0], vget_low_s32(qIn1.val[0]), d[5]);
q[0].val[1] = vmlsl_s32(q[0].val[1], vget_high_s32(qIn1.val[0]), d[5]);
q[1].val[0] = vmlsl_s32(q[1].val[0], vget_low_s32(qIn1.val[1]), d[5]);
q[1].val[1] = vmlsl_s32(q[1].val[1], vget_high_s32(qIn1.val[1]), d[5]);
q[2].val[0] = vmull_s32(vget_low_s32(qIn0.val[0]), d[5]);
q[2].val[1] = vmull_s32(vget_high_s32(qIn0.val[0]), d[5]);
q[3].val[0] = vmull_s32(vget_low_s32(qIn0.val[1]), d[5]);
q[3].val[1] = vmull_s32(vget_high_s32(qIn0.val[1]), d[5]);
q[2].val[0] = vmlal_s32(q[2].val[0], vget_low_s32(qIn1.val[0]), d[4]);
q[2].val[1] = vmlal_s32(q[2].val[1], vget_high_s32(qIn1.val[0]), d[4]);
q[3].val[0] = vmlal_s32(q[3].val[0], vget_low_s32(qIn1.val[1]), d[4]);
q[3].val[1] = vmlal_s32(q[3].val[1], vget_high_s32(qIn1.val[1]), d[4]);
qOut0->val[0] = vcombine_s32(vrshrn_n_s64(q[0].val[0], DCT_CONST_BITS),
vrshrn_n_s64(q[0].val[1], DCT_CONST_BITS));
qOut0->val[1] = vcombine_s32(vrshrn_n_s64(q[1].val[0], DCT_CONST_BITS),
vrshrn_n_s64(q[1].val[1], DCT_CONST_BITS));
qOut1->val[0] = vcombine_s32(vrshrn_n_s64(q[2].val[0], DCT_CONST_BITS),
vrshrn_n_s64(q[2].val[1], DCT_CONST_BITS));
qOut1->val[1] = vcombine_s32(vrshrn_n_s64(q[3].val[0], DCT_CONST_BITS),
vrshrn_n_s64(q[3].val[1], DCT_CONST_BITS));
}
static INLINE void load_s32x4q_dual(const int32_t *in, int32x4x2_t *const s) {
s[0].val[0] = vld1q_s32(in);
s[0].val[1] = vld1q_s32(in + 4);
in += 32;
s[1].val[0] = vld1q_s32(in);
s[1].val[1] = vld1q_s32(in + 4);
in += 32;
s[2].val[0] = vld1q_s32(in);
s[2].val[1] = vld1q_s32(in + 4);
in += 32;
s[3].val[0] = vld1q_s32(in);
s[3].val[1] = vld1q_s32(in + 4);
in += 32;
s[4].val[0] = vld1q_s32(in);
s[4].val[1] = vld1q_s32(in + 4);
in += 32;
s[5].val[0] = vld1q_s32(in);
s[5].val[1] = vld1q_s32(in + 4);
in += 32;
s[6].val[0] = vld1q_s32(in);
s[6].val[1] = vld1q_s32(in + 4);
in += 32;
s[7].val[0] = vld1q_s32(in);
s[7].val[1] = vld1q_s32(in + 4);
}
static INLINE void transpose_and_store_s32_8x8(int32x4x2_t *const a,
int32_t **out) {
transpose_s32_8x8(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7]);
vst1q_s32(*out, a[0].val[0]);
*out += 4;
vst1q_s32(*out, a[0].val[1]);
*out += 4;
vst1q_s32(*out, a[1].val[0]);
*out += 4;
vst1q_s32(*out, a[1].val[1]);
*out += 4;
vst1q_s32(*out, a[2].val[0]);
*out += 4;
vst1q_s32(*out, a[2].val[1]);
*out += 4;
vst1q_s32(*out, a[3].val[0]);
*out += 4;
vst1q_s32(*out, a[3].val[1]);
*out += 4;
vst1q_s32(*out, a[4].val[0]);
*out += 4;
vst1q_s32(*out, a[4].val[1]);
*out += 4;
vst1q_s32(*out, a[5].val[0]);
*out += 4;
vst1q_s32(*out, a[5].val[1]);
*out += 4;
vst1q_s32(*out, a[6].val[0]);
*out += 4;
vst1q_s32(*out, a[6].val[1]);
*out += 4;
vst1q_s32(*out, a[7].val[0]);
*out += 4;
vst1q_s32(*out, a[7].val[1]);
*out += 4;
}
static INLINE void idct32_transpose_pair(const int32_t *input, int32_t *t_buf) {
int i;
int32x4x2_t s[8];
for (i = 0; i < 4; i++, input += 8) {
load_s32x4q_dual(input, s);
transpose_and_store_s32_8x8(s, &t_buf);
}
}
static INLINE void idct32_bands_end_1st_pass(int32_t *const out,
int32x4x2_t *const q) {
store_in_output(out, 16, 17, q[6], q[7]);
store_in_output(out, 14, 15, q[8], q[9]);
load_from_output(out, 30, 31, &q[0], &q[1]);
q[4] = highbd_idct_add_dual(q[2], q[1]);
q[5] = highbd_idct_add_dual(q[3], q[0]);
q[6] = highbd_idct_sub_dual(q[3], q[0]);
q[7] = highbd_idct_sub_dual(q[2], q[1]);
store_in_output(out, 30, 31, q[6], q[7]);
store_in_output(out, 0, 1, q[4], q[5]);
load_from_output(out, 12, 13, &q[0], &q[1]);
q[2] = highbd_idct_add_dual(q[10], q[1]);
q[3] = highbd_idct_add_dual(q[11], q[0]);
q[4] = highbd_idct_sub_dual(q[11], q[0]);
q[5] = highbd_idct_sub_dual(q[10], q[1]);
load_from_output(out, 18, 19, &q[0], &q[1]);
q[8] = highbd_idct_add_dual(q[4], q[1]);
q[9] = highbd_idct_add_dual(q[5], q[0]);
q[6] = highbd_idct_sub_dual(q[5], q[0]);
q[7] = highbd_idct_sub_dual(q[4], q[1]);
store_in_output(out, 18, 19, q[6], q[7]);
store_in_output(out, 12, 13, q[8], q[9]);
load_from_output(out, 28, 29, &q[0], &q[1]);
q[4] = highbd_idct_add_dual(q[2], q[1]);
q[5] = highbd_idct_add_dual(q[3], q[0]);
q[6] = highbd_idct_sub_dual(q[3], q[0]);
q[7] = highbd_idct_sub_dual(q[2], q[1]);
store_in_output(out, 28, 29, q[6], q[7]);
store_in_output(out, 2, 3, q[4], q[5]);
load_from_output(out, 10, 11, &q[0], &q[1]);
q[2] = highbd_idct_add_dual(q[12], q[1]);
q[3] = highbd_idct_add_dual(q[13], q[0]);
q[4] = highbd_idct_sub_dual(q[13], q[0]);
q[5] = highbd_idct_sub_dual(q[12], q[1]);
load_from_output(out, 20, 21, &q[0], &q[1]);
q[8] = highbd_idct_add_dual(q[4], q[1]);
q[9] = highbd_idct_add_dual(q[5], q[0]);
q[6] = highbd_idct_sub_dual(q[5], q[0]);
q[7] = highbd_idct_sub_dual(q[4], q[1]);
store_in_output(out, 20, 21, q[6], q[7]);
store_in_output(out, 10, 11, q[8], q[9]);
load_from_output(out, 26, 27, &q[0], &q[1]);
q[4] = highbd_idct_add_dual(q[2], q[1]);
q[5] = highbd_idct_add_dual(q[3], q[0]);
q[6] = highbd_idct_sub_dual(q[3], q[0]);
q[7] = highbd_idct_sub_dual(q[2], q[1]);
store_in_output(out, 26, 27, q[6], q[7]);
store_in_output(out, 4, 5, q[4], q[5]);
load_from_output(out, 8, 9, &q[0], &q[1]);
q[2] = highbd_idct_add_dual(q[14], q[1]);
q[3] = highbd_idct_add_dual(q[15], q[0]);
q[4] = highbd_idct_sub_dual(q[15], q[0]);
q[5] = highbd_idct_sub_dual(q[14], q[1]);
load_from_output(out, 22, 23, &q[0], &q[1]);
q[8] = highbd_idct_add_dual(q[4], q[1]);
q[9] = highbd_idct_add_dual(q[5], q[0]);
q[6] = highbd_idct_sub_dual(q[5], q[0]);
q[7] = highbd_idct_sub_dual(q[4], q[1]);
store_in_output(out, 22, 23, q[6], q[7]);
store_in_output(out, 8, 9, q[8], q[9]);
load_from_output(out, 24, 25, &q[0], &q[1]);
q[4] = highbd_idct_add_dual(q[2], q[1]);
q[5] = highbd_idct_add_dual(q[3], q[0]);
q[6] = highbd_idct_sub_dual(q[3], q[0]);
q[7] = highbd_idct_sub_dual(q[2], q[1]);
store_in_output(out, 24, 25, q[6], q[7]);
store_in_output(out, 6, 7, q[4], q[5]);
}
static INLINE void idct32_bands_end_2nd_pass(const int32_t *const out,
uint16_t *const dest,
const int stride,
const int16x8_t max,
int32x4x2_t *const q) {
uint16_t *dest0 = dest + 0 * stride;
uint16_t *dest1 = dest + 31 * stride;
uint16_t *dest2 = dest + 16 * stride;
uint16_t *dest3 = dest + 15 * stride;
const int str2 = stride << 1;
highbd_store_combine_results(dest2, dest3, stride, q[6], q[7], q[8], q[9],
max);
dest2 += str2;
dest3 -= str2;
load_from_output(out, 30, 31, &q[0], &q[1]);
q[4] = highbd_idct_add_dual(q[2], q[1]);
q[5] = highbd_idct_add_dual(q[3], q[0]);
q[6] = highbd_idct_sub_dual(q[3], q[0]);
q[7] = highbd_idct_sub_dual(q[2], q[1]);
highbd_store_combine_results(dest0, dest1, stride, q[4], q[5], q[6], q[7],
max);
dest0 += str2;
dest1 -= str2;
load_from_output(out, 12, 13, &q[0], &q[1]);
q[2] = highbd_idct_add_dual(q[10], q[1]);
q[3] = highbd_idct_add_dual(q[11], q[0]);
q[4] = highbd_idct_sub_dual(q[11], q[0]);
q[5] = highbd_idct_sub_dual(q[10], q[1]);
load_from_output(out, 18, 19, &q[0], &q[1]);
q[8] = highbd_idct_add_dual(q[4], q[1]);
q[9] = highbd_idct_add_dual(q[5], q[0]);
q[6] = highbd_idct_sub_dual(q[5], q[0]);
q[7] = highbd_idct_sub_dual(q[4], q[1]);
highbd_store_combine_results(dest2, dest3, stride, q[6], q[7], q[8], q[9],
max);
dest2 += str2;
dest3 -= str2;
load_from_output(out, 28, 29, &q[0], &q[1]);
q[4] = highbd_idct_add_dual(q[2], q[1]);
q[5] = highbd_idct_add_dual(q[3], q[0]);
q[6] = highbd_idct_sub_dual(q[3], q[0]);
q[7] = highbd_idct_sub_dual(q[2], q[1]);
highbd_store_combine_results(dest0, dest1, stride, q[4], q[5], q[6], q[7],
max);
dest0 += str2;
dest1 -= str2;
load_from_output(out, 10, 11, &q[0], &q[1]);
q[2] = highbd_idct_add_dual(q[12], q[1]);
q[3] = highbd_idct_add_dual(q[13], q[0]);
q[4] = highbd_idct_sub_dual(q[13], q[0]);
q[5] = highbd_idct_sub_dual(q[12], q[1]);
load_from_output(out, 20, 21, &q[0], &q[1]);
q[8] = highbd_idct_add_dual(q[4], q[1]);
q[9] = highbd_idct_add_dual(q[5], q[0]);
q[6] = highbd_idct_sub_dual(q[5], q[0]);
q[7] = highbd_idct_sub_dual(q[4], q[1]);
highbd_store_combine_results(dest2, dest3, stride, q[6], q[7], q[8], q[9],
max);
dest2 += str2;
dest3 -= str2;
load_from_output(out, 26, 27, &q[0], &q[1]);
q[4] = highbd_idct_add_dual(q[2], q[1]);
q[5] = highbd_idct_add_dual(q[3], q[0]);
q[6] = highbd_idct_sub_dual(q[3], q[0]);
q[7] = highbd_idct_sub_dual(q[2], q[1]);
highbd_store_combine_results(dest0, dest1, stride, q[4], q[5], q[6], q[7],
max);
dest0 += str2;
dest1 -= str2;
load_from_output(out, 8, 9, &q[0], &q[1]);
q[2] = highbd_idct_add_dual(q[14], q[1]);
q[3] = highbd_idct_add_dual(q[15], q[0]);
q[4] = highbd_idct_sub_dual(q[15], q[0]);
q[5] = highbd_idct_sub_dual(q[14], q[1]);
load_from_output(out, 22, 23, &q[0], &q[1]);
q[8] = highbd_idct_add_dual(q[4], q[1]);
q[9] = highbd_idct_add_dual(q[5], q[0]);
q[6] = highbd_idct_sub_dual(q[5], q[0]);
q[7] = highbd_idct_sub_dual(q[4], q[1]);
highbd_store_combine_results(dest2, dest3, stride, q[6], q[7], q[8], q[9],
max);
load_from_output(out, 24, 25, &q[0], &q[1]);
q[4] = highbd_idct_add_dual(q[2], q[1]);
q[5] = highbd_idct_add_dual(q[3], q[0]);
q[6] = highbd_idct_sub_dual(q[3], q[0]);
q[7] = highbd_idct_sub_dual(q[2], q[1]);
highbd_store_combine_results(dest0, dest1, stride, q[4], q[5], q[6], q[7],
max);
}
static INLINE void vpx_highbd_idct32_32_neon(const tran_low_t *input,
uint16_t *dst, const int stride,
const int bd) {
int i, idct32_pass_loop;
int32_t trans_buf[32 * 8];
int32_t pass1[32 * 32];
int32_t pass2[32 * 32];
int32_t *out;
int32x4x2_t q[16];
for (idct32_pass_loop = 0, out = pass1; idct32_pass_loop < 2;
idct32_pass_loop++, input = pass1, out = pass2) {
for (i = 0; i < 4; i++, out += 8) { // idct32_bands_loop
idct32_transpose_pair(input, trans_buf);
input += 32 * 8;
// -----------------------------------------
// BLOCK A: 16-19,28-31
// -----------------------------------------
// generate 16,17,30,31
// part of stage 1
load_from_transformed(trans_buf, 1, 31, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_31_64, cospi_1_64, &q[0], &q[2]);
load_from_transformed(trans_buf, 17, 15, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_15_64, cospi_17_64, &q[1], &q[3]);
// part of stage 2
q[4] = highbd_idct_add_dual(q[0], q[1]);
q[13] = highbd_idct_sub_dual(q[0], q[1]);
q[6] = highbd_idct_add_dual(q[2], q[3]);
q[14] = highbd_idct_sub_dual(q[2], q[3]);
// part of stage 3
do_butterfly(q[14], q[13], cospi_28_64, cospi_4_64, &q[5], &q[7]);
// generate 18,19,28,29
// part of stage 1
load_from_transformed(trans_buf, 9, 23, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_23_64, cospi_9_64, &q[0], &q[2]);
load_from_transformed(trans_buf, 25, 7, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_7_64, cospi_25_64, &q[1], &q[3]);
// part of stage 2
q[13] = highbd_idct_sub_dual(q[3], q[2]);
q[3] = highbd_idct_add_dual(q[3], q[2]);
q[14] = highbd_idct_sub_dual(q[1], q[0]);
q[2] = highbd_idct_add_dual(q[1], q[0]);
// part of stage 3
do_butterfly(q[14], q[13], -cospi_4_64, -cospi_28_64, &q[1], &q[0]);
// part of stage 4
q[8] = highbd_idct_add_dual(q[4], q[2]);
q[9] = highbd_idct_add_dual(q[5], q[0]);
q[10] = highbd_idct_add_dual(q[7], q[1]);
q[15] = highbd_idct_add_dual(q[6], q[3]);
q[13] = highbd_idct_sub_dual(q[5], q[0]);
q[14] = highbd_idct_sub_dual(q[7], q[1]);
store_in_output(out, 16, 31, q[8], q[15]);
store_in_output(out, 17, 30, q[9], q[10]);
// part of stage 5
do_butterfly(q[14], q[13], cospi_24_64, cospi_8_64, &q[0], &q[1]);
store_in_output(out, 29, 18, q[1], q[0]);
// part of stage 4
q[13] = highbd_idct_sub_dual(q[4], q[2]);
q[14] = highbd_idct_sub_dual(q[6], q[3]);
// part of stage 5
do_butterfly(q[14], q[13], cospi_24_64, cospi_8_64, &q[4], &q[6]);
store_in_output(out, 19, 28, q[4], q[6]);
// -----------------------------------------
// BLOCK B: 20-23,24-27
// -----------------------------------------
// generate 20,21,26,27
// part of stage 1
load_from_transformed(trans_buf, 5, 27, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_27_64, cospi_5_64, &q[0], &q[2]);
load_from_transformed(trans_buf, 21, 11, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_11_64, cospi_21_64, &q[1], &q[3]);
// part of stage 2
q[13] = highbd_idct_sub_dual(q[0], q[1]);
q[0] = highbd_idct_add_dual(q[0], q[1]);
q[14] = highbd_idct_sub_dual(q[2], q[3]);
q[2] = highbd_idct_add_dual(q[2], q[3]);
// part of stage 3
do_butterfly(q[14], q[13], cospi_12_64, cospi_20_64, &q[1], &q[3]);
// generate 22,23,24,25
// part of stage 1
load_from_transformed(trans_buf, 13, 19, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_19_64, cospi_13_64, &q[5], &q[7]);
load_from_transformed(trans_buf, 29, 3, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_3_64, cospi_29_64, &q[4], &q[6]);
// part of stage 2
q[14] = highbd_idct_sub_dual(q[4], q[5]);
q[5] = highbd_idct_add_dual(q[4], q[5]);
q[13] = highbd_idct_sub_dual(q[6], q[7]);
q[6] = highbd_idct_add_dual(q[6], q[7]);
// part of stage 3
do_butterfly(q[14], q[13], -cospi_20_64, -cospi_12_64, &q[4], &q[7]);
// part of stage 4
q[10] = highbd_idct_add_dual(q[7], q[1]);
q[11] = highbd_idct_add_dual(q[5], q[0]);
q[12] = highbd_idct_add_dual(q[6], q[2]);
q[15] = highbd_idct_add_dual(q[4], q[3]);
// part of stage 6
load_from_output(out, 16, 17, &q[14], &q[13]);
q[8] = highbd_idct_add_dual(q[14], q[11]);
q[9] = highbd_idct_add_dual(q[13], q[10]);
q[13] = highbd_idct_sub_dual(q[13], q[10]);
q[11] = highbd_idct_sub_dual(q[14], q[11]);
store_in_output(out, 17, 16, q[9], q[8]);
load_from_output(out, 30, 31, &q[14], &q[9]);
q[8] = highbd_idct_sub_dual(q[9], q[12]);
q[10] = highbd_idct_add_dual(q[14], q[15]);
q[14] = highbd_idct_sub_dual(q[14], q[15]);
q[12] = highbd_idct_add_dual(q[9], q[12]);
store_in_output(out, 30, 31, q[10], q[12]);
// part of stage 7
do_butterfly(q[14], q[13], cospi_16_64, cospi_16_64, &q[13], &q[14]);
store_in_output(out, 25, 22, q[14], q[13]);
do_butterfly(q[8], q[11], cospi_16_64, cospi_16_64, &q[13], &q[14]);
store_in_output(out, 24, 23, q[14], q[13]);
// part of stage 4
q[14] = highbd_idct_sub_dual(q[5], q[0]);
q[13] = highbd_idct_sub_dual(q[6], q[2]);
do_butterfly(q[14], q[13], -cospi_8_64, -cospi_24_64, &q[5], &q[6]);
q[14] = highbd_idct_sub_dual(q[7], q[1]);
q[13] = highbd_idct_sub_dual(q[4], q[3]);
do_butterfly(q[14], q[13], -cospi_8_64, -cospi_24_64, &q[0], &q[1]);
// part of stage 6
load_from_output(out, 18, 19, &q[14], &q[13]);
q[8] = highbd_idct_add_dual(q[14], q[1]);
q[9] = highbd_idct_add_dual(q[13], q[6]);
q[13] = highbd_idct_sub_dual(q[13], q[6]);
q[1] = highbd_idct_sub_dual(q[14], q[1]);
store_in_output(out, 18, 19, q[8], q[9]);
load_from_output(out, 28, 29, &q[8], &q[9]);
q[14] = highbd_idct_sub_dual(q[8], q[5]);
q[10] = highbd_idct_add_dual(q[8], q[5]);
q[11] = highbd_idct_add_dual(q[9], q[0]);
q[0] = highbd_idct_sub_dual(q[9], q[0]);
store_in_output(out, 28, 29, q[10], q[11]);
// part of stage 7
do_butterfly(q[14], q[13], cospi_16_64, cospi_16_64, &q[13], &q[14]);
store_in_output(out, 20, 27, q[13], q[14]);
do_butterfly(q[0], q[1], cospi_16_64, cospi_16_64, &q[1], &q[0]);
store_in_output(out, 21, 26, q[1], q[0]);
// -----------------------------------------
// BLOCK C: 8-10,11-15
// -----------------------------------------
// generate 8,9,14,15
// part of stage 2
load_from_transformed(trans_buf, 2, 30, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_30_64, cospi_2_64, &q[0], &q[2]);
load_from_transformed(trans_buf, 18, 14, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_14_64, cospi_18_64, &q[1], &q[3]);
// part of stage 3
q[13] = highbd_idct_sub_dual(q[0], q[1]);
q[0] = highbd_idct_add_dual(q[0], q[1]);
q[14] = highbd_idct_sub_dual(q[2], q[3]);
q[2] = highbd_idct_add_dual(q[2], q[3]);
// part of stage 4
do_butterfly(q[14], q[13], cospi_24_64, cospi_8_64, &q[1], &q[3]);
// generate 10,11,12,13
// part of stage 2
load_from_transformed(trans_buf, 10, 22, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_22_64, cospi_10_64, &q[5], &q[7]);
load_from_transformed(trans_buf, 26, 6, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_6_64, cospi_26_64, &q[4], &q[6]);
// part of stage 3
q[14] = highbd_idct_sub_dual(q[4], q[5]);
q[5] = highbd_idct_add_dual(q[4], q[5]);
q[13] = highbd_idct_sub_dual(q[6], q[7]);
q[6] = highbd_idct_add_dual(q[6], q[7]);
// part of stage 4
do_butterfly(q[14], q[13], -cospi_8_64, -cospi_24_64, &q[4], &q[7]);
// part of stage 5
q[8] = highbd_idct_add_dual(q[0], q[5]);
q[9] = highbd_idct_add_dual(q[1], q[7]);
q[13] = highbd_idct_sub_dual(q[1], q[7]);
q[14] = highbd_idct_sub_dual(q[3], q[4]);
q[10] = highbd_idct_add_dual(q[3], q[4]);
q[15] = highbd_idct_add_dual(q[2], q[6]);
store_in_output(out, 8, 15, q[8], q[15]);
store_in_output(out, 9, 14, q[9], q[10]);
// part of stage 6
do_butterfly(q[14], q[13], cospi_16_64, cospi_16_64, &q[1], &q[3]);
store_in_output(out, 13, 10, q[3], q[1]);
q[13] = highbd_idct_sub_dual(q[0], q[5]);
q[14] = highbd_idct_sub_dual(q[2], q[6]);
do_butterfly(q[14], q[13], cospi_16_64, cospi_16_64, &q[1], &q[3]);
store_in_output(out, 11, 12, q[1], q[3]);
// -----------------------------------------
// BLOCK D: 0-3,4-7
// -----------------------------------------
// generate 4,5,6,7
// part of stage 3
load_from_transformed(trans_buf, 4, 28, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_28_64, cospi_4_64, &q[0], &q[2]);
load_from_transformed(trans_buf, 20, 12, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_12_64, cospi_20_64, &q[1], &q[3]);
// part of stage 4
q[13] = highbd_idct_sub_dual(q[0], q[1]);
q[0] = highbd_idct_add_dual(q[0], q[1]);
q[14] = highbd_idct_sub_dual(q[2], q[3]);
q[2] = highbd_idct_add_dual(q[2], q[3]);
// part of stage 5
do_butterfly(q[14], q[13], cospi_16_64, cospi_16_64, &q[1], &q[3]);
// generate 0,1,2,3
// part of stage 4
load_from_transformed(trans_buf, 0, 16, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_16_64, cospi_16_64, &q[5], &q[7]);
load_from_transformed(trans_buf, 8, 24, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_24_64, cospi_8_64, &q[14], &q[6]);
// part of stage 5
q[4] = highbd_idct_add_dual(q[7], q[6]);
q[7] = highbd_idct_sub_dual(q[7], q[6]);
q[6] = highbd_idct_sub_dual(q[5], q[14]);
q[5] = highbd_idct_add_dual(q[5], q[14]);
// part of stage 6
q[8] = highbd_idct_add_dual(q[4], q[2]);
q[9] = highbd_idct_add_dual(q[5], q[3]);
q[10] = highbd_idct_add_dual(q[6], q[1]);
q[11] = highbd_idct_add_dual(q[7], q[0]);
q[12] = highbd_idct_sub_dual(q[7], q[0]);
q[13] = highbd_idct_sub_dual(q[6], q[1]);
q[14] = highbd_idct_sub_dual(q[5], q[3]);
q[15] = highbd_idct_sub_dual(q[4], q[2]);
// part of stage 7
load_from_output(out, 14, 15, &q[0], &q[1]);
q[2] = highbd_idct_add_dual(q[8], q[1]);
q[3] = highbd_idct_add_dual(q[9], q[0]);
q[4] = highbd_idct_sub_dual(q[9], q[0]);
q[5] = highbd_idct_sub_dual(q[8], q[1]);
load_from_output(out, 16, 17, &q[0], &q[1]);
q[8] = highbd_idct_add_dual(q[4], q[1]);
q[9] = highbd_idct_add_dual(q[5], q[0]);
q[6] = highbd_idct_sub_dual(q[5], q[0]);
q[7] = highbd_idct_sub_dual(q[4], q[1]);
if (idct32_pass_loop == 0) {
idct32_bands_end_1st_pass(out, q);
} else {
const int16x8_t max = vdupq_n_s16((1 << bd) - 1);
idct32_bands_end_2nd_pass(out, dst, stride, max, q);
dst += 8;
}
}
}
}
void vpx_highbd_idct32x32_1024_add_neon(const tran_low_t *input, uint16_t *dest,
int stride, int bd) {
if (bd == 8) {
vpx_idct32_32_neon(input, CAST_TO_BYTEPTR(dest), stride, 1);
} else {
vpx_highbd_idct32_32_neon(input, dest, stride, bd);
}
}
@@ -0,0 +1,757 @@
/*
* Copyright (c) 2017 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/highbd_idct_neon.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/transpose_neon.h"
#include "vpx_dsp/txfm_common.h"
static INLINE void load_8x8_s32_dual(
const tran_low_t *input, int32x4x2_t *const in0, int32x4x2_t *const in1,
int32x4x2_t *const in2, int32x4x2_t *const in3, int32x4x2_t *const in4,
int32x4x2_t *const in5, int32x4x2_t *const in6, int32x4x2_t *const in7) {
in0->val[0] = vld1q_s32(input);
in0->val[1] = vld1q_s32(input + 4);
input += 32;
in1->val[0] = vld1q_s32(input);
in1->val[1] = vld1q_s32(input + 4);
input += 32;
in2->val[0] = vld1q_s32(input);
in2->val[1] = vld1q_s32(input + 4);
input += 32;
in3->val[0] = vld1q_s32(input);
in3->val[1] = vld1q_s32(input + 4);
input += 32;
in4->val[0] = vld1q_s32(input);
in4->val[1] = vld1q_s32(input + 4);
input += 32;
in5->val[0] = vld1q_s32(input);
in5->val[1] = vld1q_s32(input + 4);
input += 32;
in6->val[0] = vld1q_s32(input);
in6->val[1] = vld1q_s32(input + 4);
input += 32;
in7->val[0] = vld1q_s32(input);
in7->val[1] = vld1q_s32(input + 4);
}
static INLINE void load_4x8_s32_dual(const tran_low_t *input,
int32x4_t *const in0, int32x4_t *const in1,
int32x4_t *const in2, int32x4_t *const in3,
int32x4_t *const in4, int32x4_t *const in5,
int32x4_t *const in6,
int32x4_t *const in7) {
*in0 = vld1q_s32(input);
input += 32;
*in1 = vld1q_s32(input);
input += 32;
*in2 = vld1q_s32(input);
input += 32;
*in3 = vld1q_s32(input);
input += 32;
*in4 = vld1q_s32(input);
input += 32;
*in5 = vld1q_s32(input);
input += 32;
*in6 = vld1q_s32(input);
input += 32;
*in7 = vld1q_s32(input);
}
// Only for the first pass of the _135_ variant. Since it only uses values from
// the top left 16x16 it can safely assume all the remaining values are 0 and
// skip an awful lot of calculations. In fact, only the first 12 columns make
// the cut. None of the elements in the 13th, 14th, 15th or 16th columns are
// used so it skips any calls to input[12|13|14|15] too.
// In C this does a single row of 32 for each call. Here it transposes the top
// left 12x8 to allow using SIMD.
// vp9/common/vp9_scan.c:vp9_default_iscan_32x32 arranges the first 135 non-zero
// coefficients as follows:
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// 0 0 2 5 10 17 25 38 47 62 83 101 121
// 1 1 4 8 15 22 30 45 58 74 92 112 133
// 2 3 7 12 18 28 36 52 64 82 102 118
// 3 6 11 16 23 31 43 60 73 90 109 126
// 4 9 14 19 29 37 50 65 78 98 116 134
// 5 13 20 26 35 44 54 72 85 105 123
// 6 21 27 33 42 53 63 80 94 113 132
// 7 24 32 39 48 57 71 88 104 120
// 8 34 40 46 56 68 81 96 111 130
// 9 41 49 55 67 77 91 107 124
// 10 51 59 66 76 89 99 119 131
// 11 61 69 75 87 100 114 129
// 12 70 79 86 97 108 122
// 13 84 93 103 110 125
// 14 98 106 115 127
// 15 117 128
static void vpx_highbd_idct32_12_neon(const tran_low_t *const input,
int32_t *output) {
int32x4x2_t in[12], s1[32], s2[32], s3[32], s4[32], s5[32], s6[32], s7[32],
s8[32];
load_8x8_s32_dual(input, &in[0], &in[1], &in[2], &in[3], &in[4], &in[5],
&in[6], &in[7]);
transpose_s32_8x8(&in[0], &in[1], &in[2], &in[3], &in[4], &in[5], &in[6],
&in[7]);
load_4x8_s32_dual(input + 8, &in[8].val[0], &in[8].val[1], &in[9].val[0],
&in[9].val[1], &in[10].val[0], &in[10].val[1],
&in[11].val[0], &in[11].val[1]);
transpose_s32_4x8(&in[8].val[0], &in[8].val[1], &in[9].val[0], &in[9].val[1],
&in[10].val[0], &in[10].val[1], &in[11].val[0],
&in[11].val[1]);
// stage 1
s1[16] = multiply_shift_and_narrow_s32_dual(in[1], cospi_31_64);
s1[31] = multiply_shift_and_narrow_s32_dual(in[1], cospi_1_64);
s1[18] = multiply_shift_and_narrow_s32_dual(in[9], cospi_23_64);
s1[29] = multiply_shift_and_narrow_s32_dual(in[9], cospi_9_64);
s1[19] = multiply_shift_and_narrow_s32_dual(in[7], -cospi_25_64);
s1[28] = multiply_shift_and_narrow_s32_dual(in[7], cospi_7_64);
s1[20] = multiply_shift_and_narrow_s32_dual(in[5], cospi_27_64);
s1[27] = multiply_shift_and_narrow_s32_dual(in[5], cospi_5_64);
s1[21] = multiply_shift_and_narrow_s32_dual(in[11], -cospi_21_64);
s1[26] = multiply_shift_and_narrow_s32_dual(in[11], cospi_11_64);
s1[23] = multiply_shift_and_narrow_s32_dual(in[3], -cospi_29_64);
s1[24] = multiply_shift_and_narrow_s32_dual(in[3], cospi_3_64);
// stage 2
s2[8] = multiply_shift_and_narrow_s32_dual(in[2], cospi_30_64);
s2[15] = multiply_shift_and_narrow_s32_dual(in[2], cospi_2_64);
s2[10] = multiply_shift_and_narrow_s32_dual(in[10], cospi_22_64);
s2[13] = multiply_shift_and_narrow_s32_dual(in[10], cospi_10_64);
s2[11] = multiply_shift_and_narrow_s32_dual(in[6], -cospi_26_64);
s2[12] = multiply_shift_and_narrow_s32_dual(in[6], cospi_6_64);
s2[18] = highbd_idct_sub_dual(s1[19], s1[18]);
s2[19] = highbd_idct_add_dual(s1[18], s1[19]);
s2[20] = highbd_idct_add_dual(s1[20], s1[21]);
s2[21] = highbd_idct_sub_dual(s1[20], s1[21]);
s2[26] = highbd_idct_sub_dual(s1[27], s1[26]);
s2[27] = highbd_idct_add_dual(s1[26], s1[27]);
s2[28] = highbd_idct_add_dual(s1[28], s1[29]);
s2[29] = highbd_idct_sub_dual(s1[28], s1[29]);
// stage 3
s3[4] = multiply_shift_and_narrow_s32_dual(in[4], cospi_28_64);
s3[7] = multiply_shift_and_narrow_s32_dual(in[4], cospi_4_64);
s3[10] = highbd_idct_sub_dual(s2[11], s2[10]);
s3[11] = highbd_idct_add_dual(s2[10], s2[11]);
s3[12] = highbd_idct_add_dual(s2[12], s2[13]);
s3[13] = highbd_idct_sub_dual(s2[12], s2[13]);
s3[17] = multiply_accumulate_shift_and_narrow_s32_dual(s1[16], -cospi_4_64,
s1[31], cospi_28_64);
s3[30] = multiply_accumulate_shift_and_narrow_s32_dual(s1[16], cospi_28_64,
s1[31], cospi_4_64);
s3[18] = multiply_accumulate_shift_and_narrow_s32_dual(s2[18], -cospi_28_64,
s2[29], -cospi_4_64);
s3[29] = multiply_accumulate_shift_and_narrow_s32_dual(s2[18], -cospi_4_64,
s2[29], cospi_28_64);
s3[21] = multiply_accumulate_shift_and_narrow_s32_dual(s2[21], -cospi_20_64,
s2[26], cospi_12_64);
s3[26] = multiply_accumulate_shift_and_narrow_s32_dual(s2[21], cospi_12_64,
s2[26], cospi_20_64);
s3[22] = multiply_accumulate_shift_and_narrow_s32_dual(s1[23], -cospi_12_64,
s1[24], -cospi_20_64);
s3[25] = multiply_accumulate_shift_and_narrow_s32_dual(s1[23], -cospi_20_64,
s1[24], cospi_12_64);
// stage 4
s4[0] = multiply_shift_and_narrow_s32_dual(in[0], cospi_16_64);
s4[2] = multiply_shift_and_narrow_s32_dual(in[8], cospi_24_64);
s4[3] = multiply_shift_and_narrow_s32_dual(in[8], cospi_8_64);
s4[9] = multiply_accumulate_shift_and_narrow_s32_dual(s2[8], -cospi_8_64,
s2[15], cospi_24_64);
s4[14] = multiply_accumulate_shift_and_narrow_s32_dual(s2[8], cospi_24_64,
s2[15], cospi_8_64);
s4[10] = multiply_accumulate_shift_and_narrow_s32_dual(s3[10], -cospi_24_64,
s3[13], -cospi_8_64);
s4[13] = multiply_accumulate_shift_and_narrow_s32_dual(s3[10], -cospi_8_64,
s3[13], cospi_24_64);
s4[16] = highbd_idct_add_dual(s1[16], s2[19]);
s4[17] = highbd_idct_add_dual(s3[17], s3[18]);
s4[18] = highbd_idct_sub_dual(s3[17], s3[18]);
s4[19] = highbd_idct_sub_dual(s1[16], s2[19]);
s4[20] = highbd_idct_sub_dual(s1[23], s2[20]);
s4[21] = highbd_idct_sub_dual(s3[22], s3[21]);
s4[22] = highbd_idct_add_dual(s3[21], s3[22]);
s4[23] = highbd_idct_add_dual(s2[20], s1[23]);
s4[24] = highbd_idct_add_dual(s1[24], s2[27]);
s4[25] = highbd_idct_add_dual(s3[25], s3[26]);
s4[26] = highbd_idct_sub_dual(s3[25], s3[26]);
s4[27] = highbd_idct_sub_dual(s1[24], s2[27]);
s4[28] = highbd_idct_sub_dual(s1[31], s2[28]);
s4[29] = highbd_idct_sub_dual(s3[30], s3[29]);
s4[30] = highbd_idct_add_dual(s3[29], s3[30]);
s4[31] = highbd_idct_add_dual(s2[28], s1[31]);
// stage 5
s5[0] = highbd_idct_add_dual(s4[0], s4[3]);
s5[1] = highbd_idct_add_dual(s4[0], s4[2]);
s5[2] = highbd_idct_sub_dual(s4[0], s4[2]);
s5[3] = highbd_idct_sub_dual(s4[0], s4[3]);
s5[5] = sub_multiply_shift_and_narrow_s32_dual(s3[7], s3[4], cospi_16_64);
s5[6] = add_multiply_shift_and_narrow_s32_dual(s3[4], s3[7], cospi_16_64);
s5[8] = highbd_idct_add_dual(s2[8], s3[11]);
s5[9] = highbd_idct_add_dual(s4[9], s4[10]);
s5[10] = highbd_idct_sub_dual(s4[9], s4[10]);
s5[11] = highbd_idct_sub_dual(s2[8], s3[11]);
s5[12] = highbd_idct_sub_dual(s2[15], s3[12]);
s5[13] = highbd_idct_sub_dual(s4[14], s4[13]);
s5[14] = highbd_idct_add_dual(s4[13], s4[14]);
s5[15] = highbd_idct_add_dual(s2[15], s3[12]);
s5[18] = multiply_accumulate_shift_and_narrow_s32_dual(s4[18], -cospi_8_64,
s4[29], cospi_24_64);
s5[29] = multiply_accumulate_shift_and_narrow_s32_dual(s4[18], cospi_24_64,
s4[29], cospi_8_64);
s5[19] = multiply_accumulate_shift_and_narrow_s32_dual(s4[19], -cospi_8_64,
s4[28], cospi_24_64);
s5[28] = multiply_accumulate_shift_and_narrow_s32_dual(s4[19], cospi_24_64,
s4[28], cospi_8_64);
s5[20] = multiply_accumulate_shift_and_narrow_s32_dual(s4[20], -cospi_24_64,
s4[27], -cospi_8_64);
s5[27] = multiply_accumulate_shift_and_narrow_s32_dual(s4[20], -cospi_8_64,
s4[27], cospi_24_64);
s5[21] = multiply_accumulate_shift_and_narrow_s32_dual(s4[21], -cospi_24_64,
s4[26], -cospi_8_64);
s5[26] = multiply_accumulate_shift_and_narrow_s32_dual(s4[21], -cospi_8_64,
s4[26], cospi_24_64);
// stage 6
s6[0] = highbd_idct_add_dual(s5[0], s3[7]);
s6[1] = highbd_idct_add_dual(s5[1], s5[6]);
s6[2] = highbd_idct_add_dual(s5[2], s5[5]);
s6[3] = highbd_idct_add_dual(s5[3], s3[4]);
s6[4] = highbd_idct_sub_dual(s5[3], s3[4]);
s6[5] = highbd_idct_sub_dual(s5[2], s5[5]);
s6[6] = highbd_idct_sub_dual(s5[1], s5[6]);
s6[7] = highbd_idct_sub_dual(s5[0], s3[7]);
s6[10] = sub_multiply_shift_and_narrow_s32_dual(s5[13], s5[10], cospi_16_64);
s6[13] = add_multiply_shift_and_narrow_s32_dual(s5[10], s5[13], cospi_16_64);
s6[11] = sub_multiply_shift_and_narrow_s32_dual(s5[12], s5[11], cospi_16_64);
s6[12] = add_multiply_shift_and_narrow_s32_dual(s5[11], s5[12], cospi_16_64);
s6[16] = highbd_idct_add_dual(s4[16], s4[23]);
s6[17] = highbd_idct_add_dual(s4[17], s4[22]);
s6[18] = highbd_idct_add_dual(s5[18], s5[21]);
s6[19] = highbd_idct_add_dual(s5[19], s5[20]);
s6[20] = highbd_idct_sub_dual(s5[19], s5[20]);
s6[21] = highbd_idct_sub_dual(s5[18], s5[21]);
s6[22] = highbd_idct_sub_dual(s4[17], s4[22]);
s6[23] = highbd_idct_sub_dual(s4[16], s4[23]);
s6[24] = highbd_idct_sub_dual(s4[31], s4[24]);
s6[25] = highbd_idct_sub_dual(s4[30], s4[25]);
s6[26] = highbd_idct_sub_dual(s5[29], s5[26]);
s6[27] = highbd_idct_sub_dual(s5[28], s5[27]);
s6[28] = highbd_idct_add_dual(s5[27], s5[28]);
s6[29] = highbd_idct_add_dual(s5[26], s5[29]);
s6[30] = highbd_idct_add_dual(s4[25], s4[30]);
s6[31] = highbd_idct_add_dual(s4[24], s4[31]);
// stage 7
s7[0] = highbd_idct_add_dual(s6[0], s5[15]);
s7[1] = highbd_idct_add_dual(s6[1], s5[14]);
s7[2] = highbd_idct_add_dual(s6[2], s6[13]);
s7[3] = highbd_idct_add_dual(s6[3], s6[12]);
s7[4] = highbd_idct_add_dual(s6[4], s6[11]);
s7[5] = highbd_idct_add_dual(s6[5], s6[10]);
s7[6] = highbd_idct_add_dual(s6[6], s5[9]);
s7[7] = highbd_idct_add_dual(s6[7], s5[8]);
s7[8] = highbd_idct_sub_dual(s6[7], s5[8]);
s7[9] = highbd_idct_sub_dual(s6[6], s5[9]);
s7[10] = highbd_idct_sub_dual(s6[5], s6[10]);
s7[11] = highbd_idct_sub_dual(s6[4], s6[11]);
s7[12] = highbd_idct_sub_dual(s6[3], s6[12]);
s7[13] = highbd_idct_sub_dual(s6[2], s6[13]);
s7[14] = highbd_idct_sub_dual(s6[1], s5[14]);
s7[15] = highbd_idct_sub_dual(s6[0], s5[15]);
s7[20] = sub_multiply_shift_and_narrow_s32_dual(s6[27], s6[20], cospi_16_64);
s7[27] = add_multiply_shift_and_narrow_s32_dual(s6[20], s6[27], cospi_16_64);
s7[21] = sub_multiply_shift_and_narrow_s32_dual(s6[26], s6[21], cospi_16_64);
s7[26] = add_multiply_shift_and_narrow_s32_dual(s6[21], s6[26], cospi_16_64);
s7[22] = sub_multiply_shift_and_narrow_s32_dual(s6[25], s6[22], cospi_16_64);
s7[25] = add_multiply_shift_and_narrow_s32_dual(s6[22], s6[25], cospi_16_64);
s7[23] = sub_multiply_shift_and_narrow_s32_dual(s6[24], s6[23], cospi_16_64);
s7[24] = add_multiply_shift_and_narrow_s32_dual(s6[23], s6[24], cospi_16_64);
// final stage
s8[0] = highbd_idct_add_dual(s7[0], s6[31]);
s8[1] = highbd_idct_add_dual(s7[1], s6[30]);
s8[2] = highbd_idct_add_dual(s7[2], s6[29]);
s8[3] = highbd_idct_add_dual(s7[3], s6[28]);
s8[4] = highbd_idct_add_dual(s7[4], s7[27]);
s8[5] = highbd_idct_add_dual(s7[5], s7[26]);
s8[6] = highbd_idct_add_dual(s7[6], s7[25]);
s8[7] = highbd_idct_add_dual(s7[7], s7[24]);
s8[8] = highbd_idct_add_dual(s7[8], s7[23]);
s8[9] = highbd_idct_add_dual(s7[9], s7[22]);
s8[10] = highbd_idct_add_dual(s7[10], s7[21]);
s8[11] = highbd_idct_add_dual(s7[11], s7[20]);
s8[12] = highbd_idct_add_dual(s7[12], s6[19]);
s8[13] = highbd_idct_add_dual(s7[13], s6[18]);
s8[14] = highbd_idct_add_dual(s7[14], s6[17]);
s8[15] = highbd_idct_add_dual(s7[15], s6[16]);
s8[16] = highbd_idct_sub_dual(s7[15], s6[16]);
s8[17] = highbd_idct_sub_dual(s7[14], s6[17]);
s8[18] = highbd_idct_sub_dual(s7[13], s6[18]);
s8[19] = highbd_idct_sub_dual(s7[12], s6[19]);
s8[20] = highbd_idct_sub_dual(s7[11], s7[20]);
s8[21] = highbd_idct_sub_dual(s7[10], s7[21]);
s8[22] = highbd_idct_sub_dual(s7[9], s7[22]);
s8[23] = highbd_idct_sub_dual(s7[8], s7[23]);
s8[24] = highbd_idct_sub_dual(s7[7], s7[24]);
s8[25] = highbd_idct_sub_dual(s7[6], s7[25]);
s8[26] = highbd_idct_sub_dual(s7[5], s7[26]);
s8[27] = highbd_idct_sub_dual(s7[4], s7[27]);
s8[28] = highbd_idct_sub_dual(s7[3], s6[28]);
s8[29] = highbd_idct_sub_dual(s7[2], s6[29]);
s8[30] = highbd_idct_sub_dual(s7[1], s6[30]);
s8[31] = highbd_idct_sub_dual(s7[0], s6[31]);
vst1q_s32(output + 0, s8[0].val[0]);
vst1q_s32(output + 4, s8[0].val[1]);
output += 16;
vst1q_s32(output + 0, s8[1].val[0]);
vst1q_s32(output + 4, s8[1].val[1]);
output += 16;
vst1q_s32(output + 0, s8[2].val[0]);
vst1q_s32(output + 4, s8[2].val[1]);
output += 16;
vst1q_s32(output + 0, s8[3].val[0]);
vst1q_s32(output + 4, s8[3].val[1]);
output += 16;
vst1q_s32(output + 0, s8[4].val[0]);
vst1q_s32(output + 4, s8[4].val[1]);
output += 16;
vst1q_s32(output + 0, s8[5].val[0]);
vst1q_s32(output + 4, s8[5].val[1]);
output += 16;
vst1q_s32(output + 0, s8[6].val[0]);
vst1q_s32(output + 4, s8[6].val[1]);
output += 16;
vst1q_s32(output + 0, s8[7].val[0]);
vst1q_s32(output + 4, s8[7].val[1]);
output += 16;
vst1q_s32(output + 0, s8[8].val[0]);
vst1q_s32(output + 4, s8[8].val[1]);
output += 16;
vst1q_s32(output + 0, s8[9].val[0]);
vst1q_s32(output + 4, s8[9].val[1]);
output += 16;
vst1q_s32(output + 0, s8[10].val[0]);
vst1q_s32(output + 4, s8[10].val[1]);
output += 16;
vst1q_s32(output + 0, s8[11].val[0]);
vst1q_s32(output + 4, s8[11].val[1]);
output += 16;
vst1q_s32(output + 0, s8[12].val[0]);
vst1q_s32(output + 4, s8[12].val[1]);
output += 16;
vst1q_s32(output + 0, s8[13].val[0]);
vst1q_s32(output + 4, s8[13].val[1]);
output += 16;
vst1q_s32(output + 0, s8[14].val[0]);
vst1q_s32(output + 4, s8[14].val[1]);
output += 16;
vst1q_s32(output + 0, s8[15].val[0]);
vst1q_s32(output + 4, s8[15].val[1]);
output += 16;
vst1q_s32(output + 0, s8[16].val[0]);
vst1q_s32(output + 4, s8[16].val[1]);
output += 16;
vst1q_s32(output + 0, s8[17].val[0]);
vst1q_s32(output + 4, s8[17].val[1]);
output += 16;
vst1q_s32(output + 0, s8[18].val[0]);
vst1q_s32(output + 4, s8[18].val[1]);
output += 16;
vst1q_s32(output + 0, s8[19].val[0]);
vst1q_s32(output + 4, s8[19].val[1]);
output += 16;
vst1q_s32(output + 0, s8[20].val[0]);
vst1q_s32(output + 4, s8[20].val[1]);
output += 16;
vst1q_s32(output + 0, s8[21].val[0]);
vst1q_s32(output + 4, s8[21].val[1]);
output += 16;
vst1q_s32(output + 0, s8[22].val[0]);
vst1q_s32(output + 4, s8[22].val[1]);
output += 16;
vst1q_s32(output + 0, s8[23].val[0]);
vst1q_s32(output + 4, s8[23].val[1]);
output += 16;
vst1q_s32(output + 0, s8[24].val[0]);
vst1q_s32(output + 4, s8[24].val[1]);
output += 16;
vst1q_s32(output + 0, s8[25].val[0]);
vst1q_s32(output + 4, s8[25].val[1]);
output += 16;
vst1q_s32(output + 0, s8[26].val[0]);
vst1q_s32(output + 4, s8[26].val[1]);
output += 16;
vst1q_s32(output + 0, s8[27].val[0]);
vst1q_s32(output + 4, s8[27].val[1]);
output += 16;
vst1q_s32(output + 0, s8[28].val[0]);
vst1q_s32(output + 4, s8[28].val[1]);
output += 16;
vst1q_s32(output + 0, s8[29].val[0]);
vst1q_s32(output + 4, s8[29].val[1]);
output += 16;
vst1q_s32(output + 0, s8[30].val[0]);
vst1q_s32(output + 4, s8[30].val[1]);
output += 16;
vst1q_s32(output + 0, s8[31].val[0]);
vst1q_s32(output + 4, s8[31].val[1]);
}
static void vpx_highbd_idct32_16_neon(const int32_t *const input,
uint16_t *const output, const int stride,
const int bd) {
int32x4x2_t in[16], s1[32], s2[32], s3[32], s4[32], s5[32], s6[32], s7[32],
out[32];
load_and_transpose_s32_8x8(input, 16, &in[0], &in[1], &in[2], &in[3], &in[4],
&in[5], &in[6], &in[7]);
load_and_transpose_s32_8x8(input + 8, 16, &in[8], &in[9], &in[10], &in[11],
&in[12], &in[13], &in[14], &in[15]);
// stage 1
s1[16] = multiply_shift_and_narrow_s32_dual(in[1], cospi_31_64);
s1[31] = multiply_shift_and_narrow_s32_dual(in[1], cospi_1_64);
s1[17] = multiply_shift_and_narrow_s32_dual(in[15], -cospi_17_64);
s1[30] = multiply_shift_and_narrow_s32_dual(in[15], cospi_15_64);
s1[18] = multiply_shift_and_narrow_s32_dual(in[9], cospi_23_64);
s1[29] = multiply_shift_and_narrow_s32_dual(in[9], cospi_9_64);
s1[19] = multiply_shift_and_narrow_s32_dual(in[7], -cospi_25_64);
s1[28] = multiply_shift_and_narrow_s32_dual(in[7], cospi_7_64);
s1[20] = multiply_shift_and_narrow_s32_dual(in[5], cospi_27_64);
s1[27] = multiply_shift_and_narrow_s32_dual(in[5], cospi_5_64);
s1[21] = multiply_shift_and_narrow_s32_dual(in[11], -cospi_21_64);
s1[26] = multiply_shift_and_narrow_s32_dual(in[11], cospi_11_64);
s1[22] = multiply_shift_and_narrow_s32_dual(in[13], cospi_19_64);
s1[25] = multiply_shift_and_narrow_s32_dual(in[13], cospi_13_64);
s1[23] = multiply_shift_and_narrow_s32_dual(in[3], -cospi_29_64);
s1[24] = multiply_shift_and_narrow_s32_dual(in[3], cospi_3_64);
// stage 2
s2[8] = multiply_shift_and_narrow_s32_dual(in[2], cospi_30_64);
s2[15] = multiply_shift_and_narrow_s32_dual(in[2], cospi_2_64);
s2[9] = multiply_shift_and_narrow_s32_dual(in[14], -cospi_18_64);
s2[14] = multiply_shift_and_narrow_s32_dual(in[14], cospi_14_64);
s2[10] = multiply_shift_and_narrow_s32_dual(in[10], cospi_22_64);
s2[13] = multiply_shift_and_narrow_s32_dual(in[10], cospi_10_64);
s2[11] = multiply_shift_and_narrow_s32_dual(in[6], -cospi_26_64);
s2[12] = multiply_shift_and_narrow_s32_dual(in[6], cospi_6_64);
s2[16] = highbd_idct_add_dual(s1[16], s1[17]);
s2[17] = highbd_idct_sub_dual(s1[16], s1[17]);
s2[18] = highbd_idct_sub_dual(s1[19], s1[18]);
s2[19] = highbd_idct_add_dual(s1[18], s1[19]);
s2[20] = highbd_idct_add_dual(s1[20], s1[21]);
s2[21] = highbd_idct_sub_dual(s1[20], s1[21]);
s2[22] = highbd_idct_sub_dual(s1[23], s1[22]);
s2[23] = highbd_idct_add_dual(s1[22], s1[23]);
s2[24] = highbd_idct_add_dual(s1[24], s1[25]);
s2[25] = highbd_idct_sub_dual(s1[24], s1[25]);
s2[26] = highbd_idct_sub_dual(s1[27], s1[26]);
s2[27] = highbd_idct_add_dual(s1[26], s1[27]);
s2[28] = highbd_idct_add_dual(s1[28], s1[29]);
s2[29] = highbd_idct_sub_dual(s1[28], s1[29]);
s2[30] = highbd_idct_sub_dual(s1[31], s1[30]);
s2[31] = highbd_idct_add_dual(s1[30], s1[31]);
// stage 3
s3[4] = multiply_shift_and_narrow_s32_dual(in[4], cospi_28_64);
s3[7] = multiply_shift_and_narrow_s32_dual(in[4], cospi_4_64);
s3[5] = multiply_shift_and_narrow_s32_dual(in[12], -cospi_20_64);
s3[6] = multiply_shift_and_narrow_s32_dual(in[12], cospi_12_64);
s3[8] = highbd_idct_add_dual(s2[8], s2[9]);
s3[9] = highbd_idct_sub_dual(s2[8], s2[9]);
s3[10] = highbd_idct_sub_dual(s2[11], s2[10]);
s3[11] = highbd_idct_add_dual(s2[10], s2[11]);
s3[12] = highbd_idct_add_dual(s2[12], s2[13]);
s3[13] = highbd_idct_sub_dual(s2[12], s2[13]);
s3[14] = highbd_idct_sub_dual(s2[15], s2[14]);
s3[15] = highbd_idct_add_dual(s2[14], s2[15]);
s3[17] = multiply_accumulate_shift_and_narrow_s32_dual(s2[17], -cospi_4_64,
s2[30], cospi_28_64);
s3[30] = multiply_accumulate_shift_and_narrow_s32_dual(s2[17], cospi_28_64,
s2[30], cospi_4_64);
s3[18] = multiply_accumulate_shift_and_narrow_s32_dual(s2[18], -cospi_28_64,
s2[29], -cospi_4_64);
s3[29] = multiply_accumulate_shift_and_narrow_s32_dual(s2[18], -cospi_4_64,
s2[29], cospi_28_64);
s3[21] = multiply_accumulate_shift_and_narrow_s32_dual(s2[21], -cospi_20_64,
s2[26], cospi_12_64);
s3[26] = multiply_accumulate_shift_and_narrow_s32_dual(s2[21], cospi_12_64,
s2[26], cospi_20_64);
s3[22] = multiply_accumulate_shift_and_narrow_s32_dual(s2[22], -cospi_12_64,
s2[25], -cospi_20_64);
s3[25] = multiply_accumulate_shift_and_narrow_s32_dual(s2[22], -cospi_20_64,
s2[25], cospi_12_64);
// stage 4
s4[0] = multiply_shift_and_narrow_s32_dual(in[0], cospi_16_64);
s4[2] = multiply_shift_and_narrow_s32_dual(in[8], cospi_24_64);
s4[3] = multiply_shift_and_narrow_s32_dual(in[8], cospi_8_64);
s4[4] = highbd_idct_add_dual(s3[4], s3[5]);
s4[5] = highbd_idct_sub_dual(s3[4], s3[5]);
s4[6] = highbd_idct_sub_dual(s3[7], s3[6]);
s4[7] = highbd_idct_add_dual(s3[6], s3[7]);
s4[9] = multiply_accumulate_shift_and_narrow_s32_dual(s3[9], -cospi_8_64,
s3[14], cospi_24_64);
s4[14] = multiply_accumulate_shift_and_narrow_s32_dual(s3[9], cospi_24_64,
s3[14], cospi_8_64);
s4[10] = multiply_accumulate_shift_and_narrow_s32_dual(s3[10], -cospi_24_64,
s3[13], -cospi_8_64);
s4[13] = multiply_accumulate_shift_and_narrow_s32_dual(s3[10], -cospi_8_64,
s3[13], cospi_24_64);
s4[16] = highbd_idct_add_dual(s2[16], s2[19]);
s4[17] = highbd_idct_add_dual(s3[17], s3[18]);
s4[18] = highbd_idct_sub_dual(s3[17], s3[18]);
s4[19] = highbd_idct_sub_dual(s2[16], s2[19]);
s4[20] = highbd_idct_sub_dual(s2[23], s2[20]);
s4[21] = highbd_idct_sub_dual(s3[22], s3[21]);
s4[22] = highbd_idct_add_dual(s3[21], s3[22]);
s4[23] = highbd_idct_add_dual(s2[20], s2[23]);
s4[24] = highbd_idct_add_dual(s2[24], s2[27]);
s4[25] = highbd_idct_add_dual(s3[25], s3[26]);
s4[26] = highbd_idct_sub_dual(s3[25], s3[26]);
s4[27] = highbd_idct_sub_dual(s2[24], s2[27]);
s4[28] = highbd_idct_sub_dual(s2[31], s2[28]);
s4[29] = highbd_idct_sub_dual(s3[30], s3[29]);
s4[30] = highbd_idct_add_dual(s3[29], s3[30]);
s4[31] = highbd_idct_add_dual(s2[28], s2[31]);
// stage 5
s5[0] = highbd_idct_add_dual(s4[0], s4[3]);
s5[1] = highbd_idct_add_dual(s4[0], s4[2]);
s5[2] = highbd_idct_sub_dual(s4[0], s4[2]);
s5[3] = highbd_idct_sub_dual(s4[0], s4[3]);
s5[5] = sub_multiply_shift_and_narrow_s32_dual(s4[6], s4[5], cospi_16_64);
s5[6] = add_multiply_shift_and_narrow_s32_dual(s4[5], s4[6], cospi_16_64);
s5[8] = highbd_idct_add_dual(s3[8], s3[11]);
s5[9] = highbd_idct_add_dual(s4[9], s4[10]);
s5[10] = highbd_idct_sub_dual(s4[9], s4[10]);
s5[11] = highbd_idct_sub_dual(s3[8], s3[11]);
s5[12] = highbd_idct_sub_dual(s3[15], s3[12]);
s5[13] = highbd_idct_sub_dual(s4[14], s4[13]);
s5[14] = highbd_idct_add_dual(s4[13], s4[14]);
s5[15] = highbd_idct_add_dual(s3[15], s3[12]);
s5[18] = multiply_accumulate_shift_and_narrow_s32_dual(s4[18], -cospi_8_64,
s4[29], cospi_24_64);
s5[29] = multiply_accumulate_shift_and_narrow_s32_dual(s4[18], cospi_24_64,
s4[29], cospi_8_64);
s5[19] = multiply_accumulate_shift_and_narrow_s32_dual(s4[19], -cospi_8_64,
s4[28], cospi_24_64);
s5[28] = multiply_accumulate_shift_and_narrow_s32_dual(s4[19], cospi_24_64,
s4[28], cospi_8_64);
s5[20] = multiply_accumulate_shift_and_narrow_s32_dual(s4[20], -cospi_24_64,
s4[27], -cospi_8_64);
s5[27] = multiply_accumulate_shift_and_narrow_s32_dual(s4[20], -cospi_8_64,
s4[27], cospi_24_64);
s5[21] = multiply_accumulate_shift_and_narrow_s32_dual(s4[21], -cospi_24_64,
s4[26], -cospi_8_64);
s5[26] = multiply_accumulate_shift_and_narrow_s32_dual(s4[21], -cospi_8_64,
s4[26], cospi_24_64);
// stage 6
s6[0] = highbd_idct_add_dual(s5[0], s4[7]);
s6[1] = highbd_idct_add_dual(s5[1], s5[6]);
s6[2] = highbd_idct_add_dual(s5[2], s5[5]);
s6[3] = highbd_idct_add_dual(s5[3], s4[4]);
s6[4] = highbd_idct_sub_dual(s5[3], s4[4]);
s6[5] = highbd_idct_sub_dual(s5[2], s5[5]);
s6[6] = highbd_idct_sub_dual(s5[1], s5[6]);
s6[7] = highbd_idct_sub_dual(s5[0], s4[7]);
s6[10] = sub_multiply_shift_and_narrow_s32_dual(s5[13], s5[10], cospi_16_64);
s6[13] = add_multiply_shift_and_narrow_s32_dual(s5[10], s5[13], cospi_16_64);
s6[11] = sub_multiply_shift_and_narrow_s32_dual(s5[12], s5[11], cospi_16_64);
s6[12] = add_multiply_shift_and_narrow_s32_dual(s5[11], s5[12], cospi_16_64);
s6[16] = highbd_idct_add_dual(s4[16], s4[23]);
s6[17] = highbd_idct_add_dual(s4[17], s4[22]);
s6[18] = highbd_idct_add_dual(s5[18], s5[21]);
s6[19] = highbd_idct_add_dual(s5[19], s5[20]);
s6[20] = highbd_idct_sub_dual(s5[19], s5[20]);
s6[21] = highbd_idct_sub_dual(s5[18], s5[21]);
s6[22] = highbd_idct_sub_dual(s4[17], s4[22]);
s6[23] = highbd_idct_sub_dual(s4[16], s4[23]);
s6[24] = highbd_idct_sub_dual(s4[31], s4[24]);
s6[25] = highbd_idct_sub_dual(s4[30], s4[25]);
s6[26] = highbd_idct_sub_dual(s5[29], s5[26]);
s6[27] = highbd_idct_sub_dual(s5[28], s5[27]);
s6[28] = highbd_idct_add_dual(s5[27], s5[28]);
s6[29] = highbd_idct_add_dual(s5[26], s5[29]);
s6[30] = highbd_idct_add_dual(s4[25], s4[30]);
s6[31] = highbd_idct_add_dual(s4[24], s4[31]);
// stage 7
s7[0] = highbd_idct_add_dual(s6[0], s5[15]);
s7[1] = highbd_idct_add_dual(s6[1], s5[14]);
s7[2] = highbd_idct_add_dual(s6[2], s6[13]);
s7[3] = highbd_idct_add_dual(s6[3], s6[12]);
s7[4] = highbd_idct_add_dual(s6[4], s6[11]);
s7[5] = highbd_idct_add_dual(s6[5], s6[10]);
s7[6] = highbd_idct_add_dual(s6[6], s5[9]);
s7[7] = highbd_idct_add_dual(s6[7], s5[8]);
s7[8] = highbd_idct_sub_dual(s6[7], s5[8]);
s7[9] = highbd_idct_sub_dual(s6[6], s5[9]);
s7[10] = highbd_idct_sub_dual(s6[5], s6[10]);
s7[11] = highbd_idct_sub_dual(s6[4], s6[11]);
s7[12] = highbd_idct_sub_dual(s6[3], s6[12]);
s7[13] = highbd_idct_sub_dual(s6[2], s6[13]);
s7[14] = highbd_idct_sub_dual(s6[1], s5[14]);
s7[15] = highbd_idct_sub_dual(s6[0], s5[15]);
s7[20] = sub_multiply_shift_and_narrow_s32_dual(s6[27], s6[20], cospi_16_64);
s7[27] = add_multiply_shift_and_narrow_s32_dual(s6[20], s6[27], cospi_16_64);
s7[21] = sub_multiply_shift_and_narrow_s32_dual(s6[26], s6[21], cospi_16_64);
s7[26] = add_multiply_shift_and_narrow_s32_dual(s6[21], s6[26], cospi_16_64);
s7[22] = sub_multiply_shift_and_narrow_s32_dual(s6[25], s6[22], cospi_16_64);
s7[25] = add_multiply_shift_and_narrow_s32_dual(s6[22], s6[25], cospi_16_64);
s7[23] = sub_multiply_shift_and_narrow_s32_dual(s6[24], s6[23], cospi_16_64);
s7[24] = add_multiply_shift_and_narrow_s32_dual(s6[23], s6[24], cospi_16_64);
// final stage
out[0] = highbd_idct_add_dual(s7[0], s6[31]);
out[1] = highbd_idct_add_dual(s7[1], s6[30]);
out[2] = highbd_idct_add_dual(s7[2], s6[29]);
out[3] = highbd_idct_add_dual(s7[3], s6[28]);
out[4] = highbd_idct_add_dual(s7[4], s7[27]);
out[5] = highbd_idct_add_dual(s7[5], s7[26]);
out[6] = highbd_idct_add_dual(s7[6], s7[25]);
out[7] = highbd_idct_add_dual(s7[7], s7[24]);
out[8] = highbd_idct_add_dual(s7[8], s7[23]);
out[9] = highbd_idct_add_dual(s7[9], s7[22]);
out[10] = highbd_idct_add_dual(s7[10], s7[21]);
out[11] = highbd_idct_add_dual(s7[11], s7[20]);
out[12] = highbd_idct_add_dual(s7[12], s6[19]);
out[13] = highbd_idct_add_dual(s7[13], s6[18]);
out[14] = highbd_idct_add_dual(s7[14], s6[17]);
out[15] = highbd_idct_add_dual(s7[15], s6[16]);
out[16] = highbd_idct_sub_dual(s7[15], s6[16]);
out[17] = highbd_idct_sub_dual(s7[14], s6[17]);
out[18] = highbd_idct_sub_dual(s7[13], s6[18]);
out[19] = highbd_idct_sub_dual(s7[12], s6[19]);
out[20] = highbd_idct_sub_dual(s7[11], s7[20]);
out[21] = highbd_idct_sub_dual(s7[10], s7[21]);
out[22] = highbd_idct_sub_dual(s7[9], s7[22]);
out[23] = highbd_idct_sub_dual(s7[8], s7[23]);
out[24] = highbd_idct_sub_dual(s7[7], s7[24]);
out[25] = highbd_idct_sub_dual(s7[6], s7[25]);
out[26] = highbd_idct_sub_dual(s7[5], s7[26]);
out[27] = highbd_idct_sub_dual(s7[4], s7[27]);
out[28] = highbd_idct_sub_dual(s7[3], s6[28]);
out[29] = highbd_idct_sub_dual(s7[2], s6[29]);
out[30] = highbd_idct_sub_dual(s7[1], s6[30]);
out[31] = highbd_idct_sub_dual(s7[0], s6[31]);
highbd_idct16x16_add_store(out, output, stride, bd);
highbd_idct16x16_add_store(out + 16, output + 16 * stride, stride, bd);
}
void vpx_highbd_idct32x32_135_add_neon(const tran_low_t *input, uint16_t *dest,
int stride, int bd) {
int i;
if (bd == 8) {
int16_t temp[32 * 16];
int16_t *t = temp;
vpx_idct32_12_neon(input, temp);
vpx_idct32_12_neon(input + 32 * 8, temp + 8);
for (i = 0; i < 32; i += 8) {
vpx_idct32_16_neon(t, dest, stride, 1);
t += (16 * 8);
dest += 8;
}
} else {
int32_t temp[32 * 16];
int32_t *t = temp;
vpx_highbd_idct32_12_neon(input, temp);
vpx_highbd_idct32_12_neon(input + 32 * 8, temp + 8);
for (i = 0; i < 32; i += 8) {
vpx_highbd_idct32_16_neon(t, dest, stride, bd);
t += (16 * 8);
dest += 8;
}
}
}
@@ -0,0 +1,625 @@
/*
* Copyright (c) 2017 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/highbd_idct_neon.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/transpose_neon.h"
#include "vpx_dsp/txfm_common.h"
// Only for the first pass of the _34_ variant. Since it only uses values from
// the top left 8x8 it can safely assume all the remaining values are 0 and skip
// an awful lot of calculations. In fact, only the first 6 columns make the cut.
// None of the elements in the 7th or 8th column are used so it skips any calls
// to input[67] too.
// In C this does a single row of 32 for each call. Here it transposes the top
// left 8x8 to allow using SIMD.
// vp9/common/vp9_scan.c:vp9_default_iscan_32x32 arranges the first 34 non-zero
// coefficients as follows:
// 0 1 2 3 4 5 6 7
// 0 0 2 5 10 17 25
// 1 1 4 8 15 22 30
// 2 3 7 12 18 28
// 3 6 11 16 23 31
// 4 9 14 19 29
// 5 13 20 26
// 6 21 27 33
// 7 24 32
static void vpx_highbd_idct32_6_neon(const tran_low_t *input, int32_t *output) {
int32x4x2_t in[8], s1[32], s2[32], s3[32];
in[0].val[0] = vld1q_s32(input);
in[0].val[1] = vld1q_s32(input + 4);
input += 32;
in[1].val[0] = vld1q_s32(input);
in[1].val[1] = vld1q_s32(input + 4);
input += 32;
in[2].val[0] = vld1q_s32(input);
in[2].val[1] = vld1q_s32(input + 4);
input += 32;
in[3].val[0] = vld1q_s32(input);
in[3].val[1] = vld1q_s32(input + 4);
input += 32;
in[4].val[0] = vld1q_s32(input);
in[4].val[1] = vld1q_s32(input + 4);
input += 32;
in[5].val[0] = vld1q_s32(input);
in[5].val[1] = vld1q_s32(input + 4);
input += 32;
in[6].val[0] = vld1q_s32(input);
in[6].val[1] = vld1q_s32(input + 4);
input += 32;
in[7].val[0] = vld1q_s32(input);
in[7].val[1] = vld1q_s32(input + 4);
transpose_s32_8x8(&in[0], &in[1], &in[2], &in[3], &in[4], &in[5], &in[6],
&in[7]);
// stage 1
// input[1] * cospi_31_64 - input[31] * cospi_1_64 (but input[31] == 0)
s1[16] = multiply_shift_and_narrow_s32_dual(in[1], cospi_31_64);
// input[1] * cospi_1_64 + input[31] * cospi_31_64 (but input[31] == 0)
s1[31] = multiply_shift_and_narrow_s32_dual(in[1], cospi_1_64);
s1[20] = multiply_shift_and_narrow_s32_dual(in[5], cospi_27_64);
s1[27] = multiply_shift_and_narrow_s32_dual(in[5], cospi_5_64);
s1[23] = multiply_shift_and_narrow_s32_dual(in[3], -cospi_29_64);
s1[24] = multiply_shift_and_narrow_s32_dual(in[3], cospi_3_64);
// stage 2
s2[8] = multiply_shift_and_narrow_s32_dual(in[2], cospi_30_64);
s2[15] = multiply_shift_and_narrow_s32_dual(in[2], cospi_2_64);
// stage 3
s1[4] = multiply_shift_and_narrow_s32_dual(in[4], cospi_28_64);
s1[7] = multiply_shift_and_narrow_s32_dual(in[4], cospi_4_64);
s1[17] = multiply_accumulate_shift_and_narrow_s32_dual(s1[16], -cospi_4_64,
s1[31], cospi_28_64);
s1[30] = multiply_accumulate_shift_and_narrow_s32_dual(s1[16], cospi_28_64,
s1[31], cospi_4_64);
s1[21] = multiply_accumulate_shift_and_narrow_s32_dual(s1[20], -cospi_20_64,
s1[27], cospi_12_64);
s1[26] = multiply_accumulate_shift_and_narrow_s32_dual(s1[20], cospi_12_64,
s1[27], cospi_20_64);
s1[22] = multiply_accumulate_shift_and_narrow_s32_dual(s1[23], -cospi_12_64,
s1[24], -cospi_20_64);
s1[25] = multiply_accumulate_shift_and_narrow_s32_dual(s1[23], -cospi_20_64,
s1[24], cospi_12_64);
// stage 4
s1[0] = multiply_shift_and_narrow_s32_dual(in[0], cospi_16_64);
s2[9] = multiply_accumulate_shift_and_narrow_s32_dual(s2[8], -cospi_8_64,
s2[15], cospi_24_64);
s2[14] = multiply_accumulate_shift_and_narrow_s32_dual(s2[8], cospi_24_64,
s2[15], cospi_8_64);
s2[20] = highbd_idct_sub_dual(s1[23], s1[20]);
s2[21] = highbd_idct_sub_dual(s1[22], s1[21]);
s2[22] = highbd_idct_add_dual(s1[21], s1[22]);
s2[23] = highbd_idct_add_dual(s1[20], s1[23]);
s2[24] = highbd_idct_add_dual(s1[24], s1[27]);
s2[25] = highbd_idct_add_dual(s1[25], s1[26]);
s2[26] = highbd_idct_sub_dual(s1[25], s1[26]);
s2[27] = highbd_idct_sub_dual(s1[24], s1[27]);
// stage 5
s1[5] = sub_multiply_shift_and_narrow_s32_dual(s1[7], s1[4], cospi_16_64);
s1[6] = add_multiply_shift_and_narrow_s32_dual(s1[4], s1[7], cospi_16_64);
s1[18] = multiply_accumulate_shift_and_narrow_s32_dual(s1[17], -cospi_8_64,
s1[30], cospi_24_64);
s1[29] = multiply_accumulate_shift_and_narrow_s32_dual(s1[17], cospi_24_64,
s1[30], cospi_8_64);
s1[19] = multiply_accumulate_shift_and_narrow_s32_dual(s1[16], -cospi_8_64,
s1[31], cospi_24_64);
s1[28] = multiply_accumulate_shift_and_narrow_s32_dual(s1[16], cospi_24_64,
s1[31], cospi_8_64);
s1[20] = multiply_accumulate_shift_and_narrow_s32_dual(s2[20], -cospi_24_64,
s2[27], -cospi_8_64);
s1[27] = multiply_accumulate_shift_and_narrow_s32_dual(s2[20], -cospi_8_64,
s2[27], cospi_24_64);
s1[21] = multiply_accumulate_shift_and_narrow_s32_dual(s2[21], -cospi_24_64,
s2[26], -cospi_8_64);
s1[26] = multiply_accumulate_shift_and_narrow_s32_dual(s2[21], -cospi_8_64,
s2[26], cospi_24_64);
// stage 6
s2[0] = highbd_idct_add_dual(s1[0], s1[7]);
s2[1] = highbd_idct_add_dual(s1[0], s1[6]);
s2[2] = highbd_idct_add_dual(s1[0], s1[5]);
s2[3] = highbd_idct_add_dual(s1[0], s1[4]);
s2[4] = highbd_idct_sub_dual(s1[0], s1[4]);
s2[5] = highbd_idct_sub_dual(s1[0], s1[5]);
s2[6] = highbd_idct_sub_dual(s1[0], s1[6]);
s2[7] = highbd_idct_sub_dual(s1[0], s1[7]);
s2[10] = sub_multiply_shift_and_narrow_s32_dual(s2[14], s2[9], cospi_16_64);
s2[13] = add_multiply_shift_and_narrow_s32_dual(s2[9], s2[14], cospi_16_64);
s2[11] = sub_multiply_shift_and_narrow_s32_dual(s2[15], s2[8], cospi_16_64);
s2[12] = add_multiply_shift_and_narrow_s32_dual(s2[8], s2[15], cospi_16_64);
s2[16] = highbd_idct_add_dual(s1[16], s2[23]);
s2[17] = highbd_idct_add_dual(s1[17], s2[22]);
s2[18] = highbd_idct_add_dual(s1[18], s1[21]);
s2[19] = highbd_idct_add_dual(s1[19], s1[20]);
s2[20] = highbd_idct_sub_dual(s1[19], s1[20]);
s2[21] = highbd_idct_sub_dual(s1[18], s1[21]);
s2[22] = highbd_idct_sub_dual(s1[17], s2[22]);
s2[23] = highbd_idct_sub_dual(s1[16], s2[23]);
s3[24] = highbd_idct_sub_dual(s1[31], s2[24]);
s3[25] = highbd_idct_sub_dual(s1[30], s2[25]);
s3[26] = highbd_idct_sub_dual(s1[29], s1[26]);
s3[27] = highbd_idct_sub_dual(s1[28], s1[27]);
s2[28] = highbd_idct_add_dual(s1[27], s1[28]);
s2[29] = highbd_idct_add_dual(s1[26], s1[29]);
s2[30] = highbd_idct_add_dual(s2[25], s1[30]);
s2[31] = highbd_idct_add_dual(s2[24], s1[31]);
// stage 7
s1[0] = highbd_idct_add_dual(s2[0], s2[15]);
s1[1] = highbd_idct_add_dual(s2[1], s2[14]);
s1[2] = highbd_idct_add_dual(s2[2], s2[13]);
s1[3] = highbd_idct_add_dual(s2[3], s2[12]);
s1[4] = highbd_idct_add_dual(s2[4], s2[11]);
s1[5] = highbd_idct_add_dual(s2[5], s2[10]);
s1[6] = highbd_idct_add_dual(s2[6], s2[9]);
s1[7] = highbd_idct_add_dual(s2[7], s2[8]);
s1[8] = highbd_idct_sub_dual(s2[7], s2[8]);
s1[9] = highbd_idct_sub_dual(s2[6], s2[9]);
s1[10] = highbd_idct_sub_dual(s2[5], s2[10]);
s1[11] = highbd_idct_sub_dual(s2[4], s2[11]);
s1[12] = highbd_idct_sub_dual(s2[3], s2[12]);
s1[13] = highbd_idct_sub_dual(s2[2], s2[13]);
s1[14] = highbd_idct_sub_dual(s2[1], s2[14]);
s1[15] = highbd_idct_sub_dual(s2[0], s2[15]);
s1[20] = sub_multiply_shift_and_narrow_s32_dual(s3[27], s2[20], cospi_16_64);
s1[27] = add_multiply_shift_and_narrow_s32_dual(s2[20], s3[27], cospi_16_64);
s1[21] = sub_multiply_shift_and_narrow_s32_dual(s3[26], s2[21], cospi_16_64);
s1[26] = add_multiply_shift_and_narrow_s32_dual(s2[21], s3[26], cospi_16_64);
s1[22] = sub_multiply_shift_and_narrow_s32_dual(s3[25], s2[22], cospi_16_64);
s1[25] = add_multiply_shift_and_narrow_s32_dual(s2[22], s3[25], cospi_16_64);
s1[23] = sub_multiply_shift_and_narrow_s32_dual(s3[24], s2[23], cospi_16_64);
s1[24] = add_multiply_shift_and_narrow_s32_dual(s2[23], s3[24], cospi_16_64);
// final stage
s3[0] = highbd_idct_add_dual(s1[0], s2[31]);
s3[1] = highbd_idct_add_dual(s1[1], s2[30]);
s3[2] = highbd_idct_add_dual(s1[2], s2[29]);
s3[3] = highbd_idct_add_dual(s1[3], s2[28]);
s3[4] = highbd_idct_add_dual(s1[4], s1[27]);
s3[5] = highbd_idct_add_dual(s1[5], s1[26]);
s3[6] = highbd_idct_add_dual(s1[6], s1[25]);
s3[7] = highbd_idct_add_dual(s1[7], s1[24]);
s3[8] = highbd_idct_add_dual(s1[8], s1[23]);
s3[9] = highbd_idct_add_dual(s1[9], s1[22]);
s3[10] = highbd_idct_add_dual(s1[10], s1[21]);
s3[11] = highbd_idct_add_dual(s1[11], s1[20]);
s3[12] = highbd_idct_add_dual(s1[12], s2[19]);
s3[13] = highbd_idct_add_dual(s1[13], s2[18]);
s3[14] = highbd_idct_add_dual(s1[14], s2[17]);
s3[15] = highbd_idct_add_dual(s1[15], s2[16]);
s3[16] = highbd_idct_sub_dual(s1[15], s2[16]);
s3[17] = highbd_idct_sub_dual(s1[14], s2[17]);
s3[18] = highbd_idct_sub_dual(s1[13], s2[18]);
s3[19] = highbd_idct_sub_dual(s1[12], s2[19]);
s3[20] = highbd_idct_sub_dual(s1[11], s1[20]);
s3[21] = highbd_idct_sub_dual(s1[10], s1[21]);
s3[22] = highbd_idct_sub_dual(s1[9], s1[22]);
s3[23] = highbd_idct_sub_dual(s1[8], s1[23]);
s3[24] = highbd_idct_sub_dual(s1[7], s1[24]);
s3[25] = highbd_idct_sub_dual(s1[6], s1[25]);
s3[26] = highbd_idct_sub_dual(s1[5], s1[26]);
s3[27] = highbd_idct_sub_dual(s1[4], s1[27]);
s3[28] = highbd_idct_sub_dual(s1[3], s2[28]);
s3[29] = highbd_idct_sub_dual(s1[2], s2[29]);
s3[30] = highbd_idct_sub_dual(s1[1], s2[30]);
s3[31] = highbd_idct_sub_dual(s1[0], s2[31]);
vst1q_s32(output, s3[0].val[0]);
output += 4;
vst1q_s32(output, s3[0].val[1]);
output += 4;
vst1q_s32(output, s3[1].val[0]);
output += 4;
vst1q_s32(output, s3[1].val[1]);
output += 4;
vst1q_s32(output, s3[2].val[0]);
output += 4;
vst1q_s32(output, s3[2].val[1]);
output += 4;
vst1q_s32(output, s3[3].val[0]);
output += 4;
vst1q_s32(output, s3[3].val[1]);
output += 4;
vst1q_s32(output, s3[4].val[0]);
output += 4;
vst1q_s32(output, s3[4].val[1]);
output += 4;
vst1q_s32(output, s3[5].val[0]);
output += 4;
vst1q_s32(output, s3[5].val[1]);
output += 4;
vst1q_s32(output, s3[6].val[0]);
output += 4;
vst1q_s32(output, s3[6].val[1]);
output += 4;
vst1q_s32(output, s3[7].val[0]);
output += 4;
vst1q_s32(output, s3[7].val[1]);
output += 4;
vst1q_s32(output, s3[8].val[0]);
output += 4;
vst1q_s32(output, s3[8].val[1]);
output += 4;
vst1q_s32(output, s3[9].val[0]);
output += 4;
vst1q_s32(output, s3[9].val[1]);
output += 4;
vst1q_s32(output, s3[10].val[0]);
output += 4;
vst1q_s32(output, s3[10].val[1]);
output += 4;
vst1q_s32(output, s3[11].val[0]);
output += 4;
vst1q_s32(output, s3[11].val[1]);
output += 4;
vst1q_s32(output, s3[12].val[0]);
output += 4;
vst1q_s32(output, s3[12].val[1]);
output += 4;
vst1q_s32(output, s3[13].val[0]);
output += 4;
vst1q_s32(output, s3[13].val[1]);
output += 4;
vst1q_s32(output, s3[14].val[0]);
output += 4;
vst1q_s32(output, s3[14].val[1]);
output += 4;
vst1q_s32(output, s3[15].val[0]);
output += 4;
vst1q_s32(output, s3[15].val[1]);
output += 4;
vst1q_s32(output, s3[16].val[0]);
output += 4;
vst1q_s32(output, s3[16].val[1]);
output += 4;
vst1q_s32(output, s3[17].val[0]);
output += 4;
vst1q_s32(output, s3[17].val[1]);
output += 4;
vst1q_s32(output, s3[18].val[0]);
output += 4;
vst1q_s32(output, s3[18].val[1]);
output += 4;
vst1q_s32(output, s3[19].val[0]);
output += 4;
vst1q_s32(output, s3[19].val[1]);
output += 4;
vst1q_s32(output, s3[20].val[0]);
output += 4;
vst1q_s32(output, s3[20].val[1]);
output += 4;
vst1q_s32(output, s3[21].val[0]);
output += 4;
vst1q_s32(output, s3[21].val[1]);
output += 4;
vst1q_s32(output, s3[22].val[0]);
output += 4;
vst1q_s32(output, s3[22].val[1]);
output += 4;
vst1q_s32(output, s3[23].val[0]);
output += 4;
vst1q_s32(output, s3[23].val[1]);
output += 4;
vst1q_s32(output, s3[24].val[0]);
output += 4;
vst1q_s32(output, s3[24].val[1]);
output += 4;
vst1q_s32(output, s3[25].val[0]);
output += 4;
vst1q_s32(output, s3[25].val[1]);
output += 4;
vst1q_s32(output, s3[26].val[0]);
output += 4;
vst1q_s32(output, s3[26].val[1]);
output += 4;
vst1q_s32(output, s3[27].val[0]);
output += 4;
vst1q_s32(output, s3[27].val[1]);
output += 4;
vst1q_s32(output, s3[28].val[0]);
output += 4;
vst1q_s32(output, s3[28].val[1]);
output += 4;
vst1q_s32(output, s3[29].val[0]);
output += 4;
vst1q_s32(output, s3[29].val[1]);
output += 4;
vst1q_s32(output, s3[30].val[0]);
output += 4;
vst1q_s32(output, s3[30].val[1]);
output += 4;
vst1q_s32(output, s3[31].val[0]);
output += 4;
vst1q_s32(output, s3[31].val[1]);
}
static void vpx_highbd_idct32_8_neon(const int32_t *input, uint16_t *output,
int stride, const int bd) {
int32x4x2_t in[8], s1[32], s2[32], s3[32], out[32];
load_and_transpose_s32_8x8(input, 8, &in[0], &in[1], &in[2], &in[3], &in[4],
&in[5], &in[6], &in[7]);
// stage 1
s1[16] = multiply_shift_and_narrow_s32_dual(in[1], cospi_31_64);
s1[31] = multiply_shift_and_narrow_s32_dual(in[1], cospi_1_64);
// Different for _8_
s1[19] = multiply_shift_and_narrow_s32_dual(in[7], -cospi_25_64);
s1[28] = multiply_shift_and_narrow_s32_dual(in[7], cospi_7_64);
s1[20] = multiply_shift_and_narrow_s32_dual(in[5], cospi_27_64);
s1[27] = multiply_shift_and_narrow_s32_dual(in[5], cospi_5_64);
s1[23] = multiply_shift_and_narrow_s32_dual(in[3], -cospi_29_64);
s1[24] = multiply_shift_and_narrow_s32_dual(in[3], cospi_3_64);
// stage 2
s2[8] = multiply_shift_and_narrow_s32_dual(in[2], cospi_30_64);
s2[15] = multiply_shift_and_narrow_s32_dual(in[2], cospi_2_64);
s2[11] = multiply_shift_and_narrow_s32_dual(in[6], -cospi_26_64);
s2[12] = multiply_shift_and_narrow_s32_dual(in[6], cospi_6_64);
// stage 3
s1[4] = multiply_shift_and_narrow_s32_dual(in[4], cospi_28_64);
s1[7] = multiply_shift_and_narrow_s32_dual(in[4], cospi_4_64);
s1[17] = multiply_accumulate_shift_and_narrow_s32_dual(s1[16], -cospi_4_64,
s1[31], cospi_28_64);
s1[30] = multiply_accumulate_shift_and_narrow_s32_dual(s1[16], cospi_28_64,
s1[31], cospi_4_64);
// Different for _8_
s1[18] = multiply_accumulate_shift_and_narrow_s32_dual(s1[19], -cospi_28_64,
s1[28], -cospi_4_64);
s1[29] = multiply_accumulate_shift_and_narrow_s32_dual(s1[19], -cospi_4_64,
s1[28], cospi_28_64);
s1[21] = multiply_accumulate_shift_and_narrow_s32_dual(s1[20], -cospi_20_64,
s1[27], cospi_12_64);
s1[26] = multiply_accumulate_shift_and_narrow_s32_dual(s1[20], cospi_12_64,
s1[27], cospi_20_64);
s1[22] = multiply_accumulate_shift_and_narrow_s32_dual(s1[23], -cospi_12_64,
s1[24], -cospi_20_64);
s1[25] = multiply_accumulate_shift_and_narrow_s32_dual(s1[23], -cospi_20_64,
s1[24], cospi_12_64);
// stage 4
s1[0] = multiply_shift_and_narrow_s32_dual(in[0], cospi_16_64);
s2[9] = multiply_accumulate_shift_and_narrow_s32_dual(s2[8], -cospi_8_64,
s2[15], cospi_24_64);
s2[14] = multiply_accumulate_shift_and_narrow_s32_dual(s2[8], cospi_24_64,
s2[15], cospi_8_64);
s2[10] = multiply_accumulate_shift_and_narrow_s32_dual(s2[11], -cospi_24_64,
s2[12], -cospi_8_64);
s2[13] = multiply_accumulate_shift_and_narrow_s32_dual(s2[11], -cospi_8_64,
s2[12], cospi_24_64);
s2[16] = highbd_idct_add_dual(s1[16], s1[19]);
s2[17] = highbd_idct_add_dual(s1[17], s1[18]);
s2[18] = highbd_idct_sub_dual(s1[17], s1[18]);
s2[19] = highbd_idct_sub_dual(s1[16], s1[19]);
s2[20] = highbd_idct_sub_dual(s1[23], s1[20]);
s2[21] = highbd_idct_sub_dual(s1[22], s1[21]);
s2[22] = highbd_idct_add_dual(s1[21], s1[22]);
s2[23] = highbd_idct_add_dual(s1[20], s1[23]);
s2[24] = highbd_idct_add_dual(s1[24], s1[27]);
s2[25] = highbd_idct_add_dual(s1[25], s1[26]);
s2[26] = highbd_idct_sub_dual(s1[25], s1[26]);
s2[27] = highbd_idct_sub_dual(s1[24], s1[27]);
s2[28] = highbd_idct_sub_dual(s1[31], s1[28]);
s2[29] = highbd_idct_sub_dual(s1[30], s1[29]);
s2[30] = highbd_idct_add_dual(s1[29], s1[30]);
s2[31] = highbd_idct_add_dual(s1[28], s1[31]);
// stage 5
s1[5] = sub_multiply_shift_and_narrow_s32_dual(s1[7], s1[4], cospi_16_64);
s1[6] = add_multiply_shift_and_narrow_s32_dual(s1[4], s1[7], cospi_16_64);
s1[8] = highbd_idct_add_dual(s2[8], s2[11]);
s1[9] = highbd_idct_add_dual(s2[9], s2[10]);
s1[10] = highbd_idct_sub_dual(s2[9], s2[10]);
s1[11] = highbd_idct_sub_dual(s2[8], s2[11]);
s1[12] = highbd_idct_sub_dual(s2[15], s2[12]);
s1[13] = highbd_idct_sub_dual(s2[14], s2[13]);
s1[14] = highbd_idct_add_dual(s2[13], s2[14]);
s1[15] = highbd_idct_add_dual(s2[12], s2[15]);
s1[18] = multiply_accumulate_shift_and_narrow_s32_dual(s2[18], -cospi_8_64,
s2[29], cospi_24_64);
s1[29] = multiply_accumulate_shift_and_narrow_s32_dual(s2[18], cospi_24_64,
s2[29], cospi_8_64);
s1[19] = multiply_accumulate_shift_and_narrow_s32_dual(s2[19], -cospi_8_64,
s2[28], cospi_24_64);
s1[28] = multiply_accumulate_shift_and_narrow_s32_dual(s2[19], cospi_24_64,
s2[28], cospi_8_64);
s1[20] = multiply_accumulate_shift_and_narrow_s32_dual(s2[20], -cospi_24_64,
s2[27], -cospi_8_64);
s1[27] = multiply_accumulate_shift_and_narrow_s32_dual(s2[20], -cospi_8_64,
s2[27], cospi_24_64);
s1[21] = multiply_accumulate_shift_and_narrow_s32_dual(s2[21], -cospi_24_64,
s2[26], -cospi_8_64);
s1[26] = multiply_accumulate_shift_and_narrow_s32_dual(s2[21], -cospi_8_64,
s2[26], cospi_24_64);
// stage 6
s2[0] = highbd_idct_add_dual(s1[0], s1[7]);
s2[1] = highbd_idct_add_dual(s1[0], s1[6]);
s2[2] = highbd_idct_add_dual(s1[0], s1[5]);
s2[3] = highbd_idct_add_dual(s1[0], s1[4]);
s2[4] = highbd_idct_sub_dual(s1[0], s1[4]);
s2[5] = highbd_idct_sub_dual(s1[0], s1[5]);
s2[6] = highbd_idct_sub_dual(s1[0], s1[6]);
s2[7] = highbd_idct_sub_dual(s1[0], s1[7]);
s2[10] = sub_multiply_shift_and_narrow_s32_dual(s1[13], s1[10], cospi_16_64);
s2[13] = add_multiply_shift_and_narrow_s32_dual(s1[10], s1[13], cospi_16_64);
s2[11] = sub_multiply_shift_and_narrow_s32_dual(s1[12], s1[11], cospi_16_64);
s2[12] = add_multiply_shift_and_narrow_s32_dual(s1[11], s1[12], cospi_16_64);
s1[16] = highbd_idct_add_dual(s2[16], s2[23]);
s1[17] = highbd_idct_add_dual(s2[17], s2[22]);
s2[18] = highbd_idct_add_dual(s1[18], s1[21]);
s2[19] = highbd_idct_add_dual(s1[19], s1[20]);
s2[20] = highbd_idct_sub_dual(s1[19], s1[20]);
s2[21] = highbd_idct_sub_dual(s1[18], s1[21]);
s1[22] = highbd_idct_sub_dual(s2[17], s2[22]);
s1[23] = highbd_idct_sub_dual(s2[16], s2[23]);
s3[24] = highbd_idct_sub_dual(s2[31], s2[24]);
s3[25] = highbd_idct_sub_dual(s2[30], s2[25]);
s3[26] = highbd_idct_sub_dual(s1[29], s1[26]);
s3[27] = highbd_idct_sub_dual(s1[28], s1[27]);
s2[28] = highbd_idct_add_dual(s1[27], s1[28]);
s2[29] = highbd_idct_add_dual(s1[26], s1[29]);
s2[30] = highbd_idct_add_dual(s2[25], s2[30]);
s2[31] = highbd_idct_add_dual(s2[24], s2[31]);
// stage 7
s1[0] = highbd_idct_add_dual(s2[0], s1[15]);
s1[1] = highbd_idct_add_dual(s2[1], s1[14]);
s1[2] = highbd_idct_add_dual(s2[2], s2[13]);
s1[3] = highbd_idct_add_dual(s2[3], s2[12]);
s1[4] = highbd_idct_add_dual(s2[4], s2[11]);
s1[5] = highbd_idct_add_dual(s2[5], s2[10]);
s1[6] = highbd_idct_add_dual(s2[6], s1[9]);
s1[7] = highbd_idct_add_dual(s2[7], s1[8]);
s1[8] = highbd_idct_sub_dual(s2[7], s1[8]);
s1[9] = highbd_idct_sub_dual(s2[6], s1[9]);
s1[10] = highbd_idct_sub_dual(s2[5], s2[10]);
s1[11] = highbd_idct_sub_dual(s2[4], s2[11]);
s1[12] = highbd_idct_sub_dual(s2[3], s2[12]);
s1[13] = highbd_idct_sub_dual(s2[2], s2[13]);
s1[14] = highbd_idct_sub_dual(s2[1], s1[14]);
s1[15] = highbd_idct_sub_dual(s2[0], s1[15]);
s1[20] = sub_multiply_shift_and_narrow_s32_dual(s3[27], s2[20], cospi_16_64);
s1[27] = add_multiply_shift_and_narrow_s32_dual(s2[20], s3[27], cospi_16_64);
s1[21] = sub_multiply_shift_and_narrow_s32_dual(s3[26], s2[21], cospi_16_64);
s1[26] = add_multiply_shift_and_narrow_s32_dual(s2[21], s3[26], cospi_16_64);
s2[22] = sub_multiply_shift_and_narrow_s32_dual(s3[25], s1[22], cospi_16_64);
s1[25] = add_multiply_shift_and_narrow_s32_dual(s1[22], s3[25], cospi_16_64);
s2[23] = sub_multiply_shift_and_narrow_s32_dual(s3[24], s1[23], cospi_16_64);
s1[24] = add_multiply_shift_and_narrow_s32_dual(s1[23], s3[24], cospi_16_64);
// final stage
out[0] = highbd_idct_add_dual(s1[0], s2[31]);
out[1] = highbd_idct_add_dual(s1[1], s2[30]);
out[2] = highbd_idct_add_dual(s1[2], s2[29]);
out[3] = highbd_idct_add_dual(s1[3], s2[28]);
out[4] = highbd_idct_add_dual(s1[4], s1[27]);
out[5] = highbd_idct_add_dual(s1[5], s1[26]);
out[6] = highbd_idct_add_dual(s1[6], s1[25]);
out[7] = highbd_idct_add_dual(s1[7], s1[24]);
out[8] = highbd_idct_add_dual(s1[8], s2[23]);
out[9] = highbd_idct_add_dual(s1[9], s2[22]);
out[10] = highbd_idct_add_dual(s1[10], s1[21]);
out[11] = highbd_idct_add_dual(s1[11], s1[20]);
out[12] = highbd_idct_add_dual(s1[12], s2[19]);
out[13] = highbd_idct_add_dual(s1[13], s2[18]);
out[14] = highbd_idct_add_dual(s1[14], s1[17]);
out[15] = highbd_idct_add_dual(s1[15], s1[16]);
out[16] = highbd_idct_sub_dual(s1[15], s1[16]);
out[17] = highbd_idct_sub_dual(s1[14], s1[17]);
out[18] = highbd_idct_sub_dual(s1[13], s2[18]);
out[19] = highbd_idct_sub_dual(s1[12], s2[19]);
out[20] = highbd_idct_sub_dual(s1[11], s1[20]);
out[21] = highbd_idct_sub_dual(s1[10], s1[21]);
out[22] = highbd_idct_sub_dual(s1[9], s2[22]);
out[23] = highbd_idct_sub_dual(s1[8], s2[23]);
out[24] = highbd_idct_sub_dual(s1[7], s1[24]);
out[25] = highbd_idct_sub_dual(s1[6], s1[25]);
out[26] = highbd_idct_sub_dual(s1[5], s1[26]);
out[27] = highbd_idct_sub_dual(s1[4], s1[27]);
out[28] = highbd_idct_sub_dual(s1[3], s2[28]);
out[29] = highbd_idct_sub_dual(s1[2], s2[29]);
out[30] = highbd_idct_sub_dual(s1[1], s2[30]);
out[31] = highbd_idct_sub_dual(s1[0], s2[31]);
highbd_idct16x16_add_store(out, output, stride, bd);
highbd_idct16x16_add_store(out + 16, output + 16 * stride, stride, bd);
}
void vpx_highbd_idct32x32_34_add_neon(const tran_low_t *input, uint16_t *dest,
int stride, int bd) {
int i;
if (bd == 8) {
int16_t temp[32 * 8];
int16_t *t = temp;
vpx_idct32_6_neon(input, t);
for (i = 0; i < 32; i += 8) {
vpx_idct32_8_neon(t, dest, stride, 1);
t += (8 * 8);
dest += 8;
}
} else {
int32_t temp[32 * 8];
int32_t *t = temp;
vpx_highbd_idct32_6_neon(input, t);
for (i = 0; i < 32; i += 8) {
vpx_highbd_idct32_8_neon(t, dest, stride, bd);
t += (8 * 8);
dest += 8;
}
}
}
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2017 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/inv_txfm.h"
static INLINE void highbd_idct32x32_1_add_pos_kernel(uint16_t **dest,
const int stride,
const int16x8_t res,
const int16x8_t max) {
const uint16x8_t a0 = vld1q_u16(*dest);
const uint16x8_t a1 = vld1q_u16(*dest + 8);
const uint16x8_t a2 = vld1q_u16(*dest + 16);
const uint16x8_t a3 = vld1q_u16(*dest + 24);
const int16x8_t b0 = vaddq_s16(res, vreinterpretq_s16_u16(a0));
const int16x8_t b1 = vaddq_s16(res, vreinterpretq_s16_u16(a1));
const int16x8_t b2 = vaddq_s16(res, vreinterpretq_s16_u16(a2));
const int16x8_t b3 = vaddq_s16(res, vreinterpretq_s16_u16(a3));
const int16x8_t c0 = vminq_s16(b0, max);
const int16x8_t c1 = vminq_s16(b1, max);
const int16x8_t c2 = vminq_s16(b2, max);
const int16x8_t c3 = vminq_s16(b3, max);
vst1q_u16(*dest, vreinterpretq_u16_s16(c0));
vst1q_u16(*dest + 8, vreinterpretq_u16_s16(c1));
vst1q_u16(*dest + 16, vreinterpretq_u16_s16(c2));
vst1q_u16(*dest + 24, vreinterpretq_u16_s16(c3));
*dest += stride;
}
static INLINE void highbd_idct32x32_1_add_neg_kernel(uint16_t **dest,
const int stride,
const int16x8_t res) {
const uint16x8_t a0 = vld1q_u16(*dest);
const uint16x8_t a1 = vld1q_u16(*dest + 8);
const uint16x8_t a2 = vld1q_u16(*dest + 16);
const uint16x8_t a3 = vld1q_u16(*dest + 24);
const int16x8_t b0 = vaddq_s16(res, vreinterpretq_s16_u16(a0));
const int16x8_t b1 = vaddq_s16(res, vreinterpretq_s16_u16(a1));
const int16x8_t b2 = vaddq_s16(res, vreinterpretq_s16_u16(a2));
const int16x8_t b3 = vaddq_s16(res, vreinterpretq_s16_u16(a3));
const uint16x8_t c0 = vqshluq_n_s16(b0, 0);
const uint16x8_t c1 = vqshluq_n_s16(b1, 0);
const uint16x8_t c2 = vqshluq_n_s16(b2, 0);
const uint16x8_t c3 = vqshluq_n_s16(b3, 0);
vst1q_u16(*dest, c0);
vst1q_u16(*dest + 8, c1);
vst1q_u16(*dest + 16, c2);
vst1q_u16(*dest + 24, c3);
*dest += stride;
}
void vpx_highbd_idct32x32_1_add_neon(const tran_low_t *input, uint16_t *dest,
int stride, int bd) {
const tran_low_t out0 = HIGHBD_WRAPLOW(
dct_const_round_shift(input[0] * (tran_high_t)cospi_16_64), bd);
const tran_low_t out1 = HIGHBD_WRAPLOW(
dct_const_round_shift(out0 * (tran_high_t)cospi_16_64), bd);
const int16_t a1 = ROUND_POWER_OF_TWO(out1, 6);
const int16x8_t dc = vdupq_n_s16(a1);
int i;
if (a1 >= 0) {
const int16x8_t max = vdupq_n_s16((1 << bd) - 1);
for (i = 0; i < 8; ++i) {
highbd_idct32x32_1_add_pos_kernel(&dest, stride, dc, max);
highbd_idct32x32_1_add_pos_kernel(&dest, stride, dc, max);
highbd_idct32x32_1_add_pos_kernel(&dest, stride, dc, max);
highbd_idct32x32_1_add_pos_kernel(&dest, stride, dc, max);
}
} else {
for (i = 0; i < 8; ++i) {
highbd_idct32x32_1_add_neg_kernel(&dest, stride, dc);
highbd_idct32x32_1_add_neg_kernel(&dest, stride, dc);
highbd_idct32x32_1_add_neg_kernel(&dest, stride, dc);
highbd_idct32x32_1_add_neg_kernel(&dest, stride, dc);
}
}
}
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/highbd_idct_neon.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/inv_txfm.h"
// res is in reverse row order
static INLINE void highbd_idct4x4_1_add_kernel2(uint16_t **dest,
const int stride,
const int16x8_t res,
const int16x8_t max) {
const uint16x4_t a0 = vld1_u16(*dest);
const uint16x4_t a1 = vld1_u16(*dest + stride);
const int16x8_t a = vreinterpretq_s16_u16(vcombine_u16(a1, a0));
// Note: In some profile tests, res is quite close to +/-32767.
// We use saturating addition.
const int16x8_t b = vqaddq_s16(res, a);
const int16x8_t c = vminq_s16(b, max);
const uint16x8_t d = vqshluq_n_s16(c, 0);
vst1_u16(*dest, vget_high_u16(d));
*dest += stride;
vst1_u16(*dest, vget_low_u16(d));
*dest += stride;
}
void vpx_highbd_idct4x4_1_add_neon(const tran_low_t *input, uint16_t *dest,
int stride, int bd) {
const int16x8_t max = vdupq_n_s16((1 << bd) - 1);
const tran_low_t out0 = HIGHBD_WRAPLOW(
dct_const_round_shift(input[0] * (tran_high_t)cospi_16_64), bd);
const tran_low_t out1 = HIGHBD_WRAPLOW(
dct_const_round_shift(out0 * (tran_high_t)cospi_16_64), bd);
const int16_t a1 = ROUND_POWER_OF_TWO(out1, 4);
const int16x8_t dc = vdupq_n_s16(a1);
highbd_idct4x4_1_add_kernel1(&dest, stride, dc, max);
highbd_idct4x4_1_add_kernel1(&dest, stride, dc, max);
}
void vpx_highbd_idct4x4_16_add_neon(const tran_low_t *input, uint16_t *dest,
int stride, int bd) {
const int16x8_t max = vdupq_n_s16((1 << bd) - 1);
int16x8_t a[2];
int32x4_t c[4];
c[0] = vld1q_s32(input);
c[1] = vld1q_s32(input + 4);
c[2] = vld1q_s32(input + 8);
c[3] = vld1q_s32(input + 12);
if (bd == 8) {
// Rows
a[0] = vcombine_s16(vmovn_s32(c[0]), vmovn_s32(c[1]));
a[1] = vcombine_s16(vmovn_s32(c[2]), vmovn_s32(c[3]));
transpose_idct4x4_16_bd8(a);
// Columns
a[1] = vcombine_s16(vget_high_s16(a[1]), vget_low_s16(a[1]));
transpose_idct4x4_16_bd8(a);
a[0] = vrshrq_n_s16(a[0], 4);
a[1] = vrshrq_n_s16(a[1], 4);
} else {
const int32x4_t cospis = vld1q_s32(kCospi32);
if (bd == 10) {
idct4x4_16_kernel_bd10(cospis, c);
idct4x4_16_kernel_bd10(cospis, c);
} else {
idct4x4_16_kernel_bd12(cospis, c);
idct4x4_16_kernel_bd12(cospis, c);
}
a[0] = vcombine_s16(vqrshrn_n_s32(c[0], 4), vqrshrn_n_s32(c[1], 4));
a[1] = vcombine_s16(vqrshrn_n_s32(c[3], 4), vqrshrn_n_s32(c[2], 4));
}
highbd_idct4x4_1_add_kernel1(&dest, stride, a[0], max);
highbd_idct4x4_1_add_kernel2(&dest, stride, a[1], max);
}
@@ -0,0 +1,371 @@
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/highbd_idct_neon.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/transpose_neon.h"
#include "vpx_dsp/inv_txfm.h"
static INLINE void highbd_idct8x8_1_add_pos_kernel(uint16_t **dest,
const int stride,
const int16x8_t res,
const int16x8_t max) {
const uint16x8_t a = vld1q_u16(*dest);
const int16x8_t b = vaddq_s16(res, vreinterpretq_s16_u16(a));
const int16x8_t c = vminq_s16(b, max);
vst1q_u16(*dest, vreinterpretq_u16_s16(c));
*dest += stride;
}
static INLINE void highbd_idct8x8_1_add_neg_kernel(uint16_t **dest,
const int stride,
const int16x8_t res) {
const uint16x8_t a = vld1q_u16(*dest);
const int16x8_t b = vaddq_s16(res, vreinterpretq_s16_u16(a));
const uint16x8_t c = vqshluq_n_s16(b, 0);
vst1q_u16(*dest, c);
*dest += stride;
}
void vpx_highbd_idct8x8_1_add_neon(const tran_low_t *input, uint16_t *dest,
int stride, int bd) {
const tran_low_t out0 = HIGHBD_WRAPLOW(
dct_const_round_shift(input[0] * (tran_high_t)cospi_16_64), bd);
const tran_low_t out1 = HIGHBD_WRAPLOW(
dct_const_round_shift(out0 * (tran_high_t)cospi_16_64), bd);
const int16_t a1 = ROUND_POWER_OF_TWO(out1, 5);
const int16x8_t dc = vdupq_n_s16(a1);
if (a1 >= 0) {
const int16x8_t max = vdupq_n_s16((1 << bd) - 1);
highbd_idct8x8_1_add_pos_kernel(&dest, stride, dc, max);
highbd_idct8x8_1_add_pos_kernel(&dest, stride, dc, max);
highbd_idct8x8_1_add_pos_kernel(&dest, stride, dc, max);
highbd_idct8x8_1_add_pos_kernel(&dest, stride, dc, max);
highbd_idct8x8_1_add_pos_kernel(&dest, stride, dc, max);
highbd_idct8x8_1_add_pos_kernel(&dest, stride, dc, max);
highbd_idct8x8_1_add_pos_kernel(&dest, stride, dc, max);
highbd_idct8x8_1_add_pos_kernel(&dest, stride, dc, max);
} else {
highbd_idct8x8_1_add_neg_kernel(&dest, stride, dc);
highbd_idct8x8_1_add_neg_kernel(&dest, stride, dc);
highbd_idct8x8_1_add_neg_kernel(&dest, stride, dc);
highbd_idct8x8_1_add_neg_kernel(&dest, stride, dc);
highbd_idct8x8_1_add_neg_kernel(&dest, stride, dc);
highbd_idct8x8_1_add_neg_kernel(&dest, stride, dc);
highbd_idct8x8_1_add_neg_kernel(&dest, stride, dc);
highbd_idct8x8_1_add_neg_kernel(&dest, stride, dc);
}
}
static INLINE void idct8x8_12_half1d_bd10(
const int32x4_t cospis0, const int32x4_t cospis1, int32x4_t *const io0,
int32x4_t *const io1, int32x4_t *const io2, int32x4_t *const io3,
int32x4_t *const io4, int32x4_t *const io5, int32x4_t *const io6,
int32x4_t *const io7) {
int32x4_t step1[8], step2[8];
transpose_s32_4x4(io0, io1, io2, io3);
// stage 1
step1[4] = vmulq_lane_s32(*io1, vget_high_s32(cospis1), 1);
step1[5] = vmulq_lane_s32(*io3, vget_high_s32(cospis1), 0);
step1[6] = vmulq_lane_s32(*io3, vget_low_s32(cospis1), 1);
step1[7] = vmulq_lane_s32(*io1, vget_low_s32(cospis1), 0);
step1[4] = vrshrq_n_s32(step1[4], DCT_CONST_BITS);
step1[5] = vrshrq_n_s32(step1[5], DCT_CONST_BITS);
step1[6] = vrshrq_n_s32(step1[6], DCT_CONST_BITS);
step1[7] = vrshrq_n_s32(step1[7], DCT_CONST_BITS);
// stage 2
step2[1] = vmulq_lane_s32(*io0, vget_high_s32(cospis0), 0);
step2[2] = vmulq_lane_s32(*io2, vget_high_s32(cospis0), 1);
step2[3] = vmulq_lane_s32(*io2, vget_low_s32(cospis0), 1);
step2[1] = vrshrq_n_s32(step2[1], DCT_CONST_BITS);
step2[2] = vrshrq_n_s32(step2[2], DCT_CONST_BITS);
step2[3] = vrshrq_n_s32(step2[3], DCT_CONST_BITS);
step2[4] = vaddq_s32(step1[4], step1[5]);
step2[5] = vsubq_s32(step1[4], step1[5]);
step2[6] = vsubq_s32(step1[7], step1[6]);
step2[7] = vaddq_s32(step1[7], step1[6]);
// stage 3
step1[0] = vaddq_s32(step2[1], step2[3]);
step1[1] = vaddq_s32(step2[1], step2[2]);
step1[2] = vsubq_s32(step2[1], step2[2]);
step1[3] = vsubq_s32(step2[1], step2[3]);
step1[6] = vmulq_lane_s32(step2[6], vget_high_s32(cospis0), 0);
step1[5] = vmlsq_lane_s32(step1[6], step2[5], vget_high_s32(cospis0), 0);
step1[6] = vmlaq_lane_s32(step1[6], step2[5], vget_high_s32(cospis0), 0);
step1[5] = vrshrq_n_s32(step1[5], DCT_CONST_BITS);
step1[6] = vrshrq_n_s32(step1[6], DCT_CONST_BITS);
// stage 4
*io0 = vaddq_s32(step1[0], step2[7]);
*io1 = vaddq_s32(step1[1], step1[6]);
*io2 = vaddq_s32(step1[2], step1[5]);
*io3 = vaddq_s32(step1[3], step2[4]);
*io4 = vsubq_s32(step1[3], step2[4]);
*io5 = vsubq_s32(step1[2], step1[5]);
*io6 = vsubq_s32(step1[1], step1[6]);
*io7 = vsubq_s32(step1[0], step2[7]);
}
static INLINE void idct8x8_12_half1d_bd12(
const int32x4_t cospis0, const int32x4_t cospis1, int32x4_t *const io0,
int32x4_t *const io1, int32x4_t *const io2, int32x4_t *const io3,
int32x4_t *const io4, int32x4_t *const io5, int32x4_t *const io6,
int32x4_t *const io7) {
int32x2_t input1l, input1h, input3l, input3h;
int32x2_t step1l[2], step1h[2];
int32x4_t step1[8], step2[8];
int64x2_t t64[8];
int32x2_t t32[8];
transpose_s32_4x4(io0, io1, io2, io3);
// stage 1
input1l = vget_low_s32(*io1);
input1h = vget_high_s32(*io1);
input3l = vget_low_s32(*io3);
input3h = vget_high_s32(*io3);
step1l[0] = vget_low_s32(*io0);
step1h[0] = vget_high_s32(*io0);
step1l[1] = vget_low_s32(*io2);
step1h[1] = vget_high_s32(*io2);
t64[0] = vmull_lane_s32(input1l, vget_high_s32(cospis1), 1);
t64[1] = vmull_lane_s32(input1h, vget_high_s32(cospis1), 1);
t64[2] = vmull_lane_s32(input3l, vget_high_s32(cospis1), 0);
t64[3] = vmull_lane_s32(input3h, vget_high_s32(cospis1), 0);
t64[4] = vmull_lane_s32(input3l, vget_low_s32(cospis1), 1);
t64[5] = vmull_lane_s32(input3h, vget_low_s32(cospis1), 1);
t64[6] = vmull_lane_s32(input1l, vget_low_s32(cospis1), 0);
t64[7] = vmull_lane_s32(input1h, vget_low_s32(cospis1), 0);
t32[0] = vrshrn_n_s64(t64[0], DCT_CONST_BITS);
t32[1] = vrshrn_n_s64(t64[1], DCT_CONST_BITS);
t32[2] = vrshrn_n_s64(t64[2], DCT_CONST_BITS);
t32[3] = vrshrn_n_s64(t64[3], DCT_CONST_BITS);
t32[4] = vrshrn_n_s64(t64[4], DCT_CONST_BITS);
t32[5] = vrshrn_n_s64(t64[5], DCT_CONST_BITS);
t32[6] = vrshrn_n_s64(t64[6], DCT_CONST_BITS);
t32[7] = vrshrn_n_s64(t64[7], DCT_CONST_BITS);
step1[4] = vcombine_s32(t32[0], t32[1]);
step1[5] = vcombine_s32(t32[2], t32[3]);
step1[6] = vcombine_s32(t32[4], t32[5]);
step1[7] = vcombine_s32(t32[6], t32[7]);
// stage 2
t64[2] = vmull_lane_s32(step1l[0], vget_high_s32(cospis0), 0);
t64[3] = vmull_lane_s32(step1h[0], vget_high_s32(cospis0), 0);
t64[4] = vmull_lane_s32(step1l[1], vget_high_s32(cospis0), 1);
t64[5] = vmull_lane_s32(step1h[1], vget_high_s32(cospis0), 1);
t64[6] = vmull_lane_s32(step1l[1], vget_low_s32(cospis0), 1);
t64[7] = vmull_lane_s32(step1h[1], vget_low_s32(cospis0), 1);
t32[2] = vrshrn_n_s64(t64[2], DCT_CONST_BITS);
t32[3] = vrshrn_n_s64(t64[3], DCT_CONST_BITS);
t32[4] = vrshrn_n_s64(t64[4], DCT_CONST_BITS);
t32[5] = vrshrn_n_s64(t64[5], DCT_CONST_BITS);
t32[6] = vrshrn_n_s64(t64[6], DCT_CONST_BITS);
t32[7] = vrshrn_n_s64(t64[7], DCT_CONST_BITS);
step2[1] = vcombine_s32(t32[2], t32[3]);
step2[2] = vcombine_s32(t32[4], t32[5]);
step2[3] = vcombine_s32(t32[6], t32[7]);
step2[4] = vaddq_s32(step1[4], step1[5]);
step2[5] = vsubq_s32(step1[4], step1[5]);
step2[6] = vsubq_s32(step1[7], step1[6]);
step2[7] = vaddq_s32(step1[7], step1[6]);
// stage 3
step1[0] = vaddq_s32(step2[1], step2[3]);
step1[1] = vaddq_s32(step2[1], step2[2]);
step1[2] = vsubq_s32(step2[1], step2[2]);
step1[3] = vsubq_s32(step2[1], step2[3]);
t64[2] = vmull_lane_s32(vget_low_s32(step2[6]), vget_high_s32(cospis0), 0);
t64[3] = vmull_lane_s32(vget_high_s32(step2[6]), vget_high_s32(cospis0), 0);
t64[0] =
vmlsl_lane_s32(t64[2], vget_low_s32(step2[5]), vget_high_s32(cospis0), 0);
t64[1] = vmlsl_lane_s32(t64[3], vget_high_s32(step2[5]),
vget_high_s32(cospis0), 0);
t64[2] =
vmlal_lane_s32(t64[2], vget_low_s32(step2[5]), vget_high_s32(cospis0), 0);
t64[3] = vmlal_lane_s32(t64[3], vget_high_s32(step2[5]),
vget_high_s32(cospis0), 0);
t32[0] = vrshrn_n_s64(t64[0], DCT_CONST_BITS);
t32[1] = vrshrn_n_s64(t64[1], DCT_CONST_BITS);
t32[2] = vrshrn_n_s64(t64[2], DCT_CONST_BITS);
t32[3] = vrshrn_n_s64(t64[3], DCT_CONST_BITS);
step1[5] = vcombine_s32(t32[0], t32[1]);
step1[6] = vcombine_s32(t32[2], t32[3]);
// stage 4
*io0 = vaddq_s32(step1[0], step2[7]);
*io1 = vaddq_s32(step1[1], step1[6]);
*io2 = vaddq_s32(step1[2], step1[5]);
*io3 = vaddq_s32(step1[3], step2[4]);
*io4 = vsubq_s32(step1[3], step2[4]);
*io5 = vsubq_s32(step1[2], step1[5]);
*io6 = vsubq_s32(step1[1], step1[6]);
*io7 = vsubq_s32(step1[0], step2[7]);
}
void vpx_highbd_idct8x8_12_add_neon(const tran_low_t *input, uint16_t *dest,
int stride, int bd) {
int32x4_t a[16];
int16x8_t c[8];
a[0] = vld1q_s32(input);
a[1] = vld1q_s32(input + 8);
a[2] = vld1q_s32(input + 16);
a[3] = vld1q_s32(input + 24);
if (bd == 8) {
const int16x8_t cospis = vld1q_s16(kCospi);
const int16x8_t cospisd = vaddq_s16(cospis, cospis);
const int16x4_t cospis0 = vget_low_s16(cospis); // cospi 0, 8, 16, 24
const int16x4_t cospisd0 = vget_low_s16(cospisd); // doubled 0, 8, 16, 24
const int16x4_t cospisd1 = vget_high_s16(cospisd); // doubled 4, 12, 20, 28
int16x4_t b[8];
b[0] = vmovn_s32(a[0]);
b[1] = vmovn_s32(a[1]);
b[2] = vmovn_s32(a[2]);
b[3] = vmovn_s32(a[3]);
idct8x8_12_pass1_bd8(cospis0, cospisd0, cospisd1, b);
idct8x8_12_pass2_bd8(cospis0, cospisd0, cospisd1, b, c);
c[0] = vrshrq_n_s16(c[0], 5);
c[1] = vrshrq_n_s16(c[1], 5);
c[2] = vrshrq_n_s16(c[2], 5);
c[3] = vrshrq_n_s16(c[3], 5);
c[4] = vrshrq_n_s16(c[4], 5);
c[5] = vrshrq_n_s16(c[5], 5);
c[6] = vrshrq_n_s16(c[6], 5);
c[7] = vrshrq_n_s16(c[7], 5);
} else {
const int32x4_t cospis0 = vld1q_s32(kCospi32); // cospi 0, 8, 16, 24
const int32x4_t cospis1 = vld1q_s32(kCospi32 + 4); // cospi 4, 12, 20, 28
if (bd == 10) {
idct8x8_12_half1d_bd10(cospis0, cospis1, &a[0], &a[1], &a[2], &a[3],
&a[4], &a[5], &a[6], &a[7]);
idct8x8_12_half1d_bd10(cospis0, cospis1, &a[0], &a[1], &a[2], &a[3],
&a[8], &a[9], &a[10], &a[11]);
idct8x8_12_half1d_bd10(cospis0, cospis1, &a[4], &a[5], &a[6], &a[7],
&a[12], &a[13], &a[14], &a[15]);
} else {
idct8x8_12_half1d_bd12(cospis0, cospis1, &a[0], &a[1], &a[2], &a[3],
&a[4], &a[5], &a[6], &a[7]);
idct8x8_12_half1d_bd12(cospis0, cospis1, &a[0], &a[1], &a[2], &a[3],
&a[8], &a[9], &a[10], &a[11]);
idct8x8_12_half1d_bd12(cospis0, cospis1, &a[4], &a[5], &a[6], &a[7],
&a[12], &a[13], &a[14], &a[15]);
}
c[0] = vcombine_s16(vrshrn_n_s32(a[0], 5), vrshrn_n_s32(a[4], 5));
c[1] = vcombine_s16(vrshrn_n_s32(a[1], 5), vrshrn_n_s32(a[5], 5));
c[2] = vcombine_s16(vrshrn_n_s32(a[2], 5), vrshrn_n_s32(a[6], 5));
c[3] = vcombine_s16(vrshrn_n_s32(a[3], 5), vrshrn_n_s32(a[7], 5));
c[4] = vcombine_s16(vrshrn_n_s32(a[8], 5), vrshrn_n_s32(a[12], 5));
c[5] = vcombine_s16(vrshrn_n_s32(a[9], 5), vrshrn_n_s32(a[13], 5));
c[6] = vcombine_s16(vrshrn_n_s32(a[10], 5), vrshrn_n_s32(a[14], 5));
c[7] = vcombine_s16(vrshrn_n_s32(a[11], 5), vrshrn_n_s32(a[15], 5));
}
highbd_add8x8(c, dest, stride, bd);
}
void vpx_highbd_idct8x8_64_add_neon(const tran_low_t *input, uint16_t *dest,
int stride, int bd) {
int32x4_t a[16];
int16x8_t c[8];
a[0] = vld1q_s32(input);
a[1] = vld1q_s32(input + 4);
a[2] = vld1q_s32(input + 8);
a[3] = vld1q_s32(input + 12);
a[4] = vld1q_s32(input + 16);
a[5] = vld1q_s32(input + 20);
a[6] = vld1q_s32(input + 24);
a[7] = vld1q_s32(input + 28);
a[8] = vld1q_s32(input + 32);
a[9] = vld1q_s32(input + 36);
a[10] = vld1q_s32(input + 40);
a[11] = vld1q_s32(input + 44);
a[12] = vld1q_s32(input + 48);
a[13] = vld1q_s32(input + 52);
a[14] = vld1q_s32(input + 56);
a[15] = vld1q_s32(input + 60);
if (bd == 8) {
const int16x8_t cospis = vld1q_s16(kCospi);
const int16x4_t cospis0 = vget_low_s16(cospis); // cospi 0, 8, 16, 24
const int16x4_t cospis1 = vget_high_s16(cospis); // cospi 4, 12, 20, 28
int16x8_t b[8];
b[0] = vcombine_s16(vmovn_s32(a[0]), vmovn_s32(a[1]));
b[1] = vcombine_s16(vmovn_s32(a[2]), vmovn_s32(a[3]));
b[2] = vcombine_s16(vmovn_s32(a[4]), vmovn_s32(a[5]));
b[3] = vcombine_s16(vmovn_s32(a[6]), vmovn_s32(a[7]));
b[4] = vcombine_s16(vmovn_s32(a[8]), vmovn_s32(a[9]));
b[5] = vcombine_s16(vmovn_s32(a[10]), vmovn_s32(a[11]));
b[6] = vcombine_s16(vmovn_s32(a[12]), vmovn_s32(a[13]));
b[7] = vcombine_s16(vmovn_s32(a[14]), vmovn_s32(a[15]));
idct8x8_64_1d_bd8(cospis0, cospis1, b);
idct8x8_64_1d_bd8(cospis0, cospis1, b);
c[0] = vrshrq_n_s16(b[0], 5);
c[1] = vrshrq_n_s16(b[1], 5);
c[2] = vrshrq_n_s16(b[2], 5);
c[3] = vrshrq_n_s16(b[3], 5);
c[4] = vrshrq_n_s16(b[4], 5);
c[5] = vrshrq_n_s16(b[5], 5);
c[6] = vrshrq_n_s16(b[6], 5);
c[7] = vrshrq_n_s16(b[7], 5);
} else {
const int32x4_t cospis0 = vld1q_s32(kCospi32); // cospi 0, 8, 16, 24
const int32x4_t cospis1 = vld1q_s32(kCospi32 + 4); // cospi 4, 12, 20, 28
if (bd == 10) {
idct8x8_64_half1d_bd10(cospis0, cospis1, &a[0], &a[1], &a[2], &a[3],
&a[4], &a[5], &a[6], &a[7]);
idct8x8_64_half1d_bd10(cospis0, cospis1, &a[8], &a[9], &a[10], &a[11],
&a[12], &a[13], &a[14], &a[15]);
idct8x8_64_half1d_bd10(cospis0, cospis1, &a[0], &a[8], &a[1], &a[9],
&a[2], &a[10], &a[3], &a[11]);
idct8x8_64_half1d_bd10(cospis0, cospis1, &a[4], &a[12], &a[5], &a[13],
&a[6], &a[14], &a[7], &a[15]);
} else {
idct8x8_64_half1d_bd12(cospis0, cospis1, &a[0], &a[1], &a[2], &a[3],
&a[4], &a[5], &a[6], &a[7]);
idct8x8_64_half1d_bd12(cospis0, cospis1, &a[8], &a[9], &a[10], &a[11],
&a[12], &a[13], &a[14], &a[15]);
idct8x8_64_half1d_bd12(cospis0, cospis1, &a[0], &a[8], &a[1], &a[9],
&a[2], &a[10], &a[3], &a[11]);
idct8x8_64_half1d_bd12(cospis0, cospis1, &a[4], &a[12], &a[5], &a[13],
&a[6], &a[14], &a[7], &a[15]);
}
c[0] = vcombine_s16(vrshrn_n_s32(a[0], 5), vrshrn_n_s32(a[4], 5));
c[1] = vcombine_s16(vrshrn_n_s32(a[8], 5), vrshrn_n_s32(a[12], 5));
c[2] = vcombine_s16(vrshrn_n_s32(a[1], 5), vrshrn_n_s32(a[5], 5));
c[3] = vcombine_s16(vrshrn_n_s32(a[9], 5), vrshrn_n_s32(a[13], 5));
c[4] = vcombine_s16(vrshrn_n_s32(a[2], 5), vrshrn_n_s32(a[6], 5));
c[5] = vcombine_s16(vrshrn_n_s32(a[10], 5), vrshrn_n_s32(a[14], 5));
c[6] = vcombine_s16(vrshrn_n_s32(a[3], 5), vrshrn_n_s32(a[7], 5));
c[7] = vcombine_s16(vrshrn_n_s32(a[11], 5), vrshrn_n_s32(a[15], 5));
}
highbd_add8x8(c, dest, stride, bd);
}
@@ -0,0 +1,474 @@
/*
* Copyright (c) 2018 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VPX_VPX_DSP_ARM_HIGHBD_IDCT_NEON_H_
#define VPX_VPX_DSP_ARM_HIGHBD_IDCT_NEON_H_
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/inv_txfm.h"
static INLINE void highbd_idct4x4_1_add_kernel1(uint16_t **dest,
const int stride,
const int16x8_t res,
const int16x8_t max) {
const uint16x4_t a0 = vld1_u16(*dest);
const uint16x4_t a1 = vld1_u16(*dest + stride);
const int16x8_t a = vreinterpretq_s16_u16(vcombine_u16(a0, a1));
// Note: In some profile tests, res is quite close to +/-32767.
// We use saturating addition.
const int16x8_t b = vqaddq_s16(res, a);
const int16x8_t c = vminq_s16(b, max);
const uint16x8_t d = vqshluq_n_s16(c, 0);
vst1_u16(*dest, vget_low_u16(d));
*dest += stride;
vst1_u16(*dest, vget_high_u16(d));
*dest += stride;
}
static INLINE void idct4x4_16_kernel_bd10(const int32x4_t cospis,
int32x4_t *const a) {
int32x4_t b0, b1, b2, b3;
transpose_s32_4x4(&a[0], &a[1], &a[2], &a[3]);
b0 = vaddq_s32(a[0], a[2]);
b1 = vsubq_s32(a[0], a[2]);
b0 = vmulq_lane_s32(b0, vget_high_s32(cospis), 0);
b1 = vmulq_lane_s32(b1, vget_high_s32(cospis), 0);
b2 = vmulq_lane_s32(a[1], vget_high_s32(cospis), 1);
b3 = vmulq_lane_s32(a[1], vget_low_s32(cospis), 1);
b2 = vmlsq_lane_s32(b2, a[3], vget_low_s32(cospis), 1);
b3 = vmlaq_lane_s32(b3, a[3], vget_high_s32(cospis), 1);
b0 = vrshrq_n_s32(b0, DCT_CONST_BITS);
b1 = vrshrq_n_s32(b1, DCT_CONST_BITS);
b2 = vrshrq_n_s32(b2, DCT_CONST_BITS);
b3 = vrshrq_n_s32(b3, DCT_CONST_BITS);
a[0] = vaddq_s32(b0, b3);
a[1] = vaddq_s32(b1, b2);
a[2] = vsubq_s32(b1, b2);
a[3] = vsubq_s32(b0, b3);
}
static INLINE void idct4x4_16_kernel_bd12(const int32x4_t cospis,
int32x4_t *const a) {
int32x4_t b0, b1, b2, b3;
int64x2_t c[12];
transpose_s32_4x4(&a[0], &a[1], &a[2], &a[3]);
b0 = vaddq_s32(a[0], a[2]);
b1 = vsubq_s32(a[0], a[2]);
c[0] = vmull_lane_s32(vget_low_s32(b0), vget_high_s32(cospis), 0);
c[1] = vmull_lane_s32(vget_high_s32(b0), vget_high_s32(cospis), 0);
c[2] = vmull_lane_s32(vget_low_s32(b1), vget_high_s32(cospis), 0);
c[3] = vmull_lane_s32(vget_high_s32(b1), vget_high_s32(cospis), 0);
c[4] = vmull_lane_s32(vget_low_s32(a[1]), vget_high_s32(cospis), 1);
c[5] = vmull_lane_s32(vget_high_s32(a[1]), vget_high_s32(cospis), 1);
c[6] = vmull_lane_s32(vget_low_s32(a[1]), vget_low_s32(cospis), 1);
c[7] = vmull_lane_s32(vget_high_s32(a[1]), vget_low_s32(cospis), 1);
c[8] = vmull_lane_s32(vget_low_s32(a[3]), vget_low_s32(cospis), 1);
c[9] = vmull_lane_s32(vget_high_s32(a[3]), vget_low_s32(cospis), 1);
c[10] = vmull_lane_s32(vget_low_s32(a[3]), vget_high_s32(cospis), 1);
c[11] = vmull_lane_s32(vget_high_s32(a[3]), vget_high_s32(cospis), 1);
c[4] = vsubq_s64(c[4], c[8]);
c[5] = vsubq_s64(c[5], c[9]);
c[6] = vaddq_s64(c[6], c[10]);
c[7] = vaddq_s64(c[7], c[11]);
b0 = vcombine_s32(vrshrn_n_s64(c[0], DCT_CONST_BITS),
vrshrn_n_s64(c[1], DCT_CONST_BITS));
b1 = vcombine_s32(vrshrn_n_s64(c[2], DCT_CONST_BITS),
vrshrn_n_s64(c[3], DCT_CONST_BITS));
b2 = vcombine_s32(vrshrn_n_s64(c[4], DCT_CONST_BITS),
vrshrn_n_s64(c[5], DCT_CONST_BITS));
b3 = vcombine_s32(vrshrn_n_s64(c[6], DCT_CONST_BITS),
vrshrn_n_s64(c[7], DCT_CONST_BITS));
a[0] = vaddq_s32(b0, b3);
a[1] = vaddq_s32(b1, b2);
a[2] = vsubq_s32(b1, b2);
a[3] = vsubq_s32(b0, b3);
}
static INLINE void highbd_add8x8(int16x8_t *const a, uint16_t *dest,
const int stride, const int bd) {
const int16x8_t max = vdupq_n_s16((1 << bd) - 1);
const uint16_t *dst = dest;
uint16x8_t d0, d1, d2, d3, d4, d5, d6, d7;
uint16x8_t d0_u16, d1_u16, d2_u16, d3_u16, d4_u16, d5_u16, d6_u16, d7_u16;
int16x8_t d0_s16, d1_s16, d2_s16, d3_s16, d4_s16, d5_s16, d6_s16, d7_s16;
d0 = vld1q_u16(dst);
dst += stride;
d1 = vld1q_u16(dst);
dst += stride;
d2 = vld1q_u16(dst);
dst += stride;
d3 = vld1q_u16(dst);
dst += stride;
d4 = vld1q_u16(dst);
dst += stride;
d5 = vld1q_u16(dst);
dst += stride;
d6 = vld1q_u16(dst);
dst += stride;
d7 = vld1q_u16(dst);
d0_s16 = vqaddq_s16(a[0], vreinterpretq_s16_u16(d0));
d1_s16 = vqaddq_s16(a[1], vreinterpretq_s16_u16(d1));
d2_s16 = vqaddq_s16(a[2], vreinterpretq_s16_u16(d2));
d3_s16 = vqaddq_s16(a[3], vreinterpretq_s16_u16(d3));
d4_s16 = vqaddq_s16(a[4], vreinterpretq_s16_u16(d4));
d5_s16 = vqaddq_s16(a[5], vreinterpretq_s16_u16(d5));
d6_s16 = vqaddq_s16(a[6], vreinterpretq_s16_u16(d6));
d7_s16 = vqaddq_s16(a[7], vreinterpretq_s16_u16(d7));
d0_s16 = vminq_s16(d0_s16, max);
d1_s16 = vminq_s16(d1_s16, max);
d2_s16 = vminq_s16(d2_s16, max);
d3_s16 = vminq_s16(d3_s16, max);
d4_s16 = vminq_s16(d4_s16, max);
d5_s16 = vminq_s16(d5_s16, max);
d6_s16 = vminq_s16(d6_s16, max);
d7_s16 = vminq_s16(d7_s16, max);
d0_u16 = vqshluq_n_s16(d0_s16, 0);
d1_u16 = vqshluq_n_s16(d1_s16, 0);
d2_u16 = vqshluq_n_s16(d2_s16, 0);
d3_u16 = vqshluq_n_s16(d3_s16, 0);
d4_u16 = vqshluq_n_s16(d4_s16, 0);
d5_u16 = vqshluq_n_s16(d5_s16, 0);
d6_u16 = vqshluq_n_s16(d6_s16, 0);
d7_u16 = vqshluq_n_s16(d7_s16, 0);
vst1q_u16(dest, d0_u16);
dest += stride;
vst1q_u16(dest, d1_u16);
dest += stride;
vst1q_u16(dest, d2_u16);
dest += stride;
vst1q_u16(dest, d3_u16);
dest += stride;
vst1q_u16(dest, d4_u16);
dest += stride;
vst1q_u16(dest, d5_u16);
dest += stride;
vst1q_u16(dest, d6_u16);
dest += stride;
vst1q_u16(dest, d7_u16);
}
static INLINE void idct8x8_64_half1d_bd10(
const int32x4_t cospis0, const int32x4_t cospis1, int32x4_t *const io0,
int32x4_t *const io1, int32x4_t *const io2, int32x4_t *const io3,
int32x4_t *const io4, int32x4_t *const io5, int32x4_t *const io6,
int32x4_t *const io7) {
int32x4_t step1[8], step2[8];
transpose_s32_8x4(io0, io1, io2, io3, io4, io5, io6, io7);
// stage 1
step1[4] = vmulq_lane_s32(*io1, vget_high_s32(cospis1), 1);
step1[5] = vmulq_lane_s32(*io3, vget_high_s32(cospis1), 0);
step1[6] = vmulq_lane_s32(*io3, vget_low_s32(cospis1), 1);
step1[7] = vmulq_lane_s32(*io1, vget_low_s32(cospis1), 0);
step1[4] = vmlsq_lane_s32(step1[4], *io7, vget_low_s32(cospis1), 0);
step1[5] = vmlaq_lane_s32(step1[5], *io5, vget_low_s32(cospis1), 1);
step1[6] = vmlsq_lane_s32(step1[6], *io5, vget_high_s32(cospis1), 0);
step1[7] = vmlaq_lane_s32(step1[7], *io7, vget_high_s32(cospis1), 1);
step1[4] = vrshrq_n_s32(step1[4], DCT_CONST_BITS);
step1[5] = vrshrq_n_s32(step1[5], DCT_CONST_BITS);
step1[6] = vrshrq_n_s32(step1[6], DCT_CONST_BITS);
step1[7] = vrshrq_n_s32(step1[7], DCT_CONST_BITS);
// stage 2
step2[1] = vmulq_lane_s32(*io0, vget_high_s32(cospis0), 0);
step2[2] = vmulq_lane_s32(*io2, vget_high_s32(cospis0), 1);
step2[3] = vmulq_lane_s32(*io2, vget_low_s32(cospis0), 1);
step2[0] = vmlaq_lane_s32(step2[1], *io4, vget_high_s32(cospis0), 0);
step2[1] = vmlsq_lane_s32(step2[1], *io4, vget_high_s32(cospis0), 0);
step2[2] = vmlsq_lane_s32(step2[2], *io6, vget_low_s32(cospis0), 1);
step2[3] = vmlaq_lane_s32(step2[3], *io6, vget_high_s32(cospis0), 1);
step2[0] = vrshrq_n_s32(step2[0], DCT_CONST_BITS);
step2[1] = vrshrq_n_s32(step2[1], DCT_CONST_BITS);
step2[2] = vrshrq_n_s32(step2[2], DCT_CONST_BITS);
step2[3] = vrshrq_n_s32(step2[3], DCT_CONST_BITS);
step2[4] = vaddq_s32(step1[4], step1[5]);
step2[5] = vsubq_s32(step1[4], step1[5]);
step2[6] = vsubq_s32(step1[7], step1[6]);
step2[7] = vaddq_s32(step1[7], step1[6]);
// stage 3
step1[0] = vaddq_s32(step2[0], step2[3]);
step1[1] = vaddq_s32(step2[1], step2[2]);
step1[2] = vsubq_s32(step2[1], step2[2]);
step1[3] = vsubq_s32(step2[0], step2[3]);
step1[6] = vmulq_lane_s32(step2[6], vget_high_s32(cospis0), 0);
step1[5] = vmlsq_lane_s32(step1[6], step2[5], vget_high_s32(cospis0), 0);
step1[6] = vmlaq_lane_s32(step1[6], step2[5], vget_high_s32(cospis0), 0);
step1[5] = vrshrq_n_s32(step1[5], DCT_CONST_BITS);
step1[6] = vrshrq_n_s32(step1[6], DCT_CONST_BITS);
// stage 4
*io0 = vaddq_s32(step1[0], step2[7]);
*io1 = vaddq_s32(step1[1], step1[6]);
*io2 = vaddq_s32(step1[2], step1[5]);
*io3 = vaddq_s32(step1[3], step2[4]);
*io4 = vsubq_s32(step1[3], step2[4]);
*io5 = vsubq_s32(step1[2], step1[5]);
*io6 = vsubq_s32(step1[1], step1[6]);
*io7 = vsubq_s32(step1[0], step2[7]);
}
static INLINE void idct8x8_64_half1d_bd12(
const int32x4_t cospis0, const int32x4_t cospis1, int32x4_t *const io0,
int32x4_t *const io1, int32x4_t *const io2, int32x4_t *const io3,
int32x4_t *const io4, int32x4_t *const io5, int32x4_t *const io6,
int32x4_t *const io7) {
int32x2_t input1l, input1h, input3l, input3h, input5l, input5h, input7l,
input7h;
int32x2_t step1l[4], step1h[4];
int32x4_t step1[8], step2[8];
int64x2_t t64[8];
int32x2_t t32[8];
transpose_s32_8x4(io0, io1, io2, io3, io4, io5, io6, io7);
// stage 1
input1l = vget_low_s32(*io1);
input1h = vget_high_s32(*io1);
input3l = vget_low_s32(*io3);
input3h = vget_high_s32(*io3);
input5l = vget_low_s32(*io5);
input5h = vget_high_s32(*io5);
input7l = vget_low_s32(*io7);
input7h = vget_high_s32(*io7);
step1l[0] = vget_low_s32(*io0);
step1h[0] = vget_high_s32(*io0);
step1l[1] = vget_low_s32(*io2);
step1h[1] = vget_high_s32(*io2);
step1l[2] = vget_low_s32(*io4);
step1h[2] = vget_high_s32(*io4);
step1l[3] = vget_low_s32(*io6);
step1h[3] = vget_high_s32(*io6);
t64[0] = vmull_lane_s32(input1l, vget_high_s32(cospis1), 1);
t64[1] = vmull_lane_s32(input1h, vget_high_s32(cospis1), 1);
t64[2] = vmull_lane_s32(input3l, vget_high_s32(cospis1), 0);
t64[3] = vmull_lane_s32(input3h, vget_high_s32(cospis1), 0);
t64[4] = vmull_lane_s32(input3l, vget_low_s32(cospis1), 1);
t64[5] = vmull_lane_s32(input3h, vget_low_s32(cospis1), 1);
t64[6] = vmull_lane_s32(input1l, vget_low_s32(cospis1), 0);
t64[7] = vmull_lane_s32(input1h, vget_low_s32(cospis1), 0);
t64[0] = vmlsl_lane_s32(t64[0], input7l, vget_low_s32(cospis1), 0);
t64[1] = vmlsl_lane_s32(t64[1], input7h, vget_low_s32(cospis1), 0);
t64[2] = vmlal_lane_s32(t64[2], input5l, vget_low_s32(cospis1), 1);
t64[3] = vmlal_lane_s32(t64[3], input5h, vget_low_s32(cospis1), 1);
t64[4] = vmlsl_lane_s32(t64[4], input5l, vget_high_s32(cospis1), 0);
t64[5] = vmlsl_lane_s32(t64[5], input5h, vget_high_s32(cospis1), 0);
t64[6] = vmlal_lane_s32(t64[6], input7l, vget_high_s32(cospis1), 1);
t64[7] = vmlal_lane_s32(t64[7], input7h, vget_high_s32(cospis1), 1);
t32[0] = vrshrn_n_s64(t64[0], DCT_CONST_BITS);
t32[1] = vrshrn_n_s64(t64[1], DCT_CONST_BITS);
t32[2] = vrshrn_n_s64(t64[2], DCT_CONST_BITS);
t32[3] = vrshrn_n_s64(t64[3], DCT_CONST_BITS);
t32[4] = vrshrn_n_s64(t64[4], DCT_CONST_BITS);
t32[5] = vrshrn_n_s64(t64[5], DCT_CONST_BITS);
t32[6] = vrshrn_n_s64(t64[6], DCT_CONST_BITS);
t32[7] = vrshrn_n_s64(t64[7], DCT_CONST_BITS);
step1[4] = vcombine_s32(t32[0], t32[1]);
step1[5] = vcombine_s32(t32[2], t32[3]);
step1[6] = vcombine_s32(t32[4], t32[5]);
step1[7] = vcombine_s32(t32[6], t32[7]);
// stage 2
t64[2] = vmull_lane_s32(step1l[0], vget_high_s32(cospis0), 0);
t64[3] = vmull_lane_s32(step1h[0], vget_high_s32(cospis0), 0);
t64[4] = vmull_lane_s32(step1l[1], vget_high_s32(cospis0), 1);
t64[5] = vmull_lane_s32(step1h[1], vget_high_s32(cospis0), 1);
t64[6] = vmull_lane_s32(step1l[1], vget_low_s32(cospis0), 1);
t64[7] = vmull_lane_s32(step1h[1], vget_low_s32(cospis0), 1);
t64[0] = vmlal_lane_s32(t64[2], step1l[2], vget_high_s32(cospis0), 0);
t64[1] = vmlal_lane_s32(t64[3], step1h[2], vget_high_s32(cospis0), 0);
t64[2] = vmlsl_lane_s32(t64[2], step1l[2], vget_high_s32(cospis0), 0);
t64[3] = vmlsl_lane_s32(t64[3], step1h[2], vget_high_s32(cospis0), 0);
t64[4] = vmlsl_lane_s32(t64[4], step1l[3], vget_low_s32(cospis0), 1);
t64[5] = vmlsl_lane_s32(t64[5], step1h[3], vget_low_s32(cospis0), 1);
t64[6] = vmlal_lane_s32(t64[6], step1l[3], vget_high_s32(cospis0), 1);
t64[7] = vmlal_lane_s32(t64[7], step1h[3], vget_high_s32(cospis0), 1);
t32[0] = vrshrn_n_s64(t64[0], DCT_CONST_BITS);
t32[1] = vrshrn_n_s64(t64[1], DCT_CONST_BITS);
t32[2] = vrshrn_n_s64(t64[2], DCT_CONST_BITS);
t32[3] = vrshrn_n_s64(t64[3], DCT_CONST_BITS);
t32[4] = vrshrn_n_s64(t64[4], DCT_CONST_BITS);
t32[5] = vrshrn_n_s64(t64[5], DCT_CONST_BITS);
t32[6] = vrshrn_n_s64(t64[6], DCT_CONST_BITS);
t32[7] = vrshrn_n_s64(t64[7], DCT_CONST_BITS);
step2[0] = vcombine_s32(t32[0], t32[1]);
step2[1] = vcombine_s32(t32[2], t32[3]);
step2[2] = vcombine_s32(t32[4], t32[5]);
step2[3] = vcombine_s32(t32[6], t32[7]);
step2[4] = vaddq_s32(step1[4], step1[5]);
step2[5] = vsubq_s32(step1[4], step1[5]);
step2[6] = vsubq_s32(step1[7], step1[6]);
step2[7] = vaddq_s32(step1[7], step1[6]);
// stage 3
step1[0] = vaddq_s32(step2[0], step2[3]);
step1[1] = vaddq_s32(step2[1], step2[2]);
step1[2] = vsubq_s32(step2[1], step2[2]);
step1[3] = vsubq_s32(step2[0], step2[3]);
t64[2] = vmull_lane_s32(vget_low_s32(step2[6]), vget_high_s32(cospis0), 0);
t64[3] = vmull_lane_s32(vget_high_s32(step2[6]), vget_high_s32(cospis0), 0);
t64[0] =
vmlsl_lane_s32(t64[2], vget_low_s32(step2[5]), vget_high_s32(cospis0), 0);
t64[1] = vmlsl_lane_s32(t64[3], vget_high_s32(step2[5]),
vget_high_s32(cospis0), 0);
t64[2] =
vmlal_lane_s32(t64[2], vget_low_s32(step2[5]), vget_high_s32(cospis0), 0);
t64[3] = vmlal_lane_s32(t64[3], vget_high_s32(step2[5]),
vget_high_s32(cospis0), 0);
t32[0] = vrshrn_n_s64(t64[0], DCT_CONST_BITS);
t32[1] = vrshrn_n_s64(t64[1], DCT_CONST_BITS);
t32[2] = vrshrn_n_s64(t64[2], DCT_CONST_BITS);
t32[3] = vrshrn_n_s64(t64[3], DCT_CONST_BITS);
step1[5] = vcombine_s32(t32[0], t32[1]);
step1[6] = vcombine_s32(t32[2], t32[3]);
// stage 4
*io0 = vaddq_s32(step1[0], step2[7]);
*io1 = vaddq_s32(step1[1], step1[6]);
*io2 = vaddq_s32(step1[2], step1[5]);
*io3 = vaddq_s32(step1[3], step2[4]);
*io4 = vsubq_s32(step1[3], step2[4]);
*io5 = vsubq_s32(step1[2], step1[5]);
*io6 = vsubq_s32(step1[1], step1[6]);
*io7 = vsubq_s32(step1[0], step2[7]);
}
static INLINE void highbd_idct16x16_store_pass1(const int32x4x2_t *const out,
int32_t *output) {
// Save the result into output
vst1q_s32(output + 0, out[0].val[0]);
vst1q_s32(output + 4, out[0].val[1]);
output += 16;
vst1q_s32(output + 0, out[1].val[0]);
vst1q_s32(output + 4, out[1].val[1]);
output += 16;
vst1q_s32(output + 0, out[2].val[0]);
vst1q_s32(output + 4, out[2].val[1]);
output += 16;
vst1q_s32(output + 0, out[3].val[0]);
vst1q_s32(output + 4, out[3].val[1]);
output += 16;
vst1q_s32(output + 0, out[4].val[0]);
vst1q_s32(output + 4, out[4].val[1]);
output += 16;
vst1q_s32(output + 0, out[5].val[0]);
vst1q_s32(output + 4, out[5].val[1]);
output += 16;
vst1q_s32(output + 0, out[6].val[0]);
vst1q_s32(output + 4, out[6].val[1]);
output += 16;
vst1q_s32(output + 0, out[7].val[0]);
vst1q_s32(output + 4, out[7].val[1]);
output += 16;
vst1q_s32(output + 0, out[8].val[0]);
vst1q_s32(output + 4, out[8].val[1]);
output += 16;
vst1q_s32(output + 0, out[9].val[0]);
vst1q_s32(output + 4, out[9].val[1]);
output += 16;
vst1q_s32(output + 0, out[10].val[0]);
vst1q_s32(output + 4, out[10].val[1]);
output += 16;
vst1q_s32(output + 0, out[11].val[0]);
vst1q_s32(output + 4, out[11].val[1]);
output += 16;
vst1q_s32(output + 0, out[12].val[0]);
vst1q_s32(output + 4, out[12].val[1]);
output += 16;
vst1q_s32(output + 0, out[13].val[0]);
vst1q_s32(output + 4, out[13].val[1]);
output += 16;
vst1q_s32(output + 0, out[14].val[0]);
vst1q_s32(output + 4, out[14].val[1]);
output += 16;
vst1q_s32(output + 0, out[15].val[0]);
vst1q_s32(output + 4, out[15].val[1]);
}
static INLINE void highbd_idct16x16_add_store(const int32x4x2_t *const out,
uint16_t *dest, const int stride,
const int bd) {
// Add the result to dest
const int16x8_t max = vdupq_n_s16((1 << bd) - 1);
int16x8_t o[16];
o[0] = vcombine_s16(vrshrn_n_s32(out[0].val[0], 6),
vrshrn_n_s32(out[0].val[1], 6));
o[1] = vcombine_s16(vrshrn_n_s32(out[1].val[0], 6),
vrshrn_n_s32(out[1].val[1], 6));
o[2] = vcombine_s16(vrshrn_n_s32(out[2].val[0], 6),
vrshrn_n_s32(out[2].val[1], 6));
o[3] = vcombine_s16(vrshrn_n_s32(out[3].val[0], 6),
vrshrn_n_s32(out[3].val[1], 6));
o[4] = vcombine_s16(vrshrn_n_s32(out[4].val[0], 6),
vrshrn_n_s32(out[4].val[1], 6));
o[5] = vcombine_s16(vrshrn_n_s32(out[5].val[0], 6),
vrshrn_n_s32(out[5].val[1], 6));
o[6] = vcombine_s16(vrshrn_n_s32(out[6].val[0], 6),
vrshrn_n_s32(out[6].val[1], 6));
o[7] = vcombine_s16(vrshrn_n_s32(out[7].val[0], 6),
vrshrn_n_s32(out[7].val[1], 6));
o[8] = vcombine_s16(vrshrn_n_s32(out[8].val[0], 6),
vrshrn_n_s32(out[8].val[1], 6));
o[9] = vcombine_s16(vrshrn_n_s32(out[9].val[0], 6),
vrshrn_n_s32(out[9].val[1], 6));
o[10] = vcombine_s16(vrshrn_n_s32(out[10].val[0], 6),
vrshrn_n_s32(out[10].val[1], 6));
o[11] = vcombine_s16(vrshrn_n_s32(out[11].val[0], 6),
vrshrn_n_s32(out[11].val[1], 6));
o[12] = vcombine_s16(vrshrn_n_s32(out[12].val[0], 6),
vrshrn_n_s32(out[12].val[1], 6));
o[13] = vcombine_s16(vrshrn_n_s32(out[13].val[0], 6),
vrshrn_n_s32(out[13].val[1], 6));
o[14] = vcombine_s16(vrshrn_n_s32(out[14].val[0], 6),
vrshrn_n_s32(out[14].val[1], 6));
o[15] = vcombine_s16(vrshrn_n_s32(out[15].val[0], 6),
vrshrn_n_s32(out[15].val[1], 6));
highbd_idct16x16_add8x1(o[0], max, &dest, stride);
highbd_idct16x16_add8x1(o[1], max, &dest, stride);
highbd_idct16x16_add8x1(o[2], max, &dest, stride);
highbd_idct16x16_add8x1(o[3], max, &dest, stride);
highbd_idct16x16_add8x1(o[4], max, &dest, stride);
highbd_idct16x16_add8x1(o[5], max, &dest, stride);
highbd_idct16x16_add8x1(o[6], max, &dest, stride);
highbd_idct16x16_add8x1(o[7], max, &dest, stride);
highbd_idct16x16_add8x1(o[8], max, &dest, stride);
highbd_idct16x16_add8x1(o[9], max, &dest, stride);
highbd_idct16x16_add8x1(o[10], max, &dest, stride);
highbd_idct16x16_add8x1(o[11], max, &dest, stride);
highbd_idct16x16_add8x1(o[12], max, &dest, stride);
highbd_idct16x16_add8x1(o[13], max, &dest, stride);
highbd_idct16x16_add8x1(o[14], max, &dest, stride);
highbd_idct16x16_add8x1(o[15], max, &dest, stride);
}
void vpx_highbd_idct16x16_256_add_half1d(const int32_t *input, int32_t *output,
uint16_t *dest, const int stride,
const int bd);
#endif // VPX_VPX_DSP_ARM_HIGHBD_IDCT_NEON_H_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,761 @@
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/transpose_neon.h"
static INLINE void load_thresh(const uint8_t *blimit, const uint8_t *limit,
const uint8_t *thresh, uint16x8_t *blimit_vec,
uint16x8_t *limit_vec, uint16x8_t *thresh_vec,
const int bd) {
const int16x8_t shift = vdupq_n_s16(bd - 8);
*blimit_vec = vmovl_u8(vld1_dup_u8(blimit));
*limit_vec = vmovl_u8(vld1_dup_u8(limit));
*thresh_vec = vmovl_u8(vld1_dup_u8(thresh));
*blimit_vec = vshlq_u16(*blimit_vec, shift);
*limit_vec = vshlq_u16(*limit_vec, shift);
*thresh_vec = vshlq_u16(*thresh_vec, shift);
}
// Here flat is 128-bit long, with each 16-bit chunk being a mask of
// a pixel. When used to control filter branches, we only detect whether it is
// all 0s or all 1s. We pairwise add flat to a 32-bit long number flat_status.
// flat equals 0 if and only if flat_status equals 0.
// flat equals -1 (all 1s) if and only if flat_status equals -4. (This is true
// because each mask occupies more than 1 bit.)
static INLINE uint32_t calc_flat_status(const uint16x8_t flat) {
const uint64x1_t t0 = vadd_u64(vreinterpret_u64_u16(vget_low_u16(flat)),
vreinterpret_u64_u16(vget_high_u16(flat)));
const uint64x1_t t1 = vpaddl_u32(vreinterpret_u32_u64(t0));
return vget_lane_u32(vreinterpret_u32_u64(t1), 0);
}
static INLINE uint16x8_t
filter_hev_mask4(const uint16x8_t limit, const uint16x8_t blimit,
const uint16x8_t thresh, const uint16x8_t p3,
const uint16x8_t p2, const uint16x8_t p1, const uint16x8_t p0,
const uint16x8_t q0, const uint16x8_t q1, const uint16x8_t q2,
const uint16x8_t q3, uint16x8_t *hev, uint16x8_t *mask) {
uint16x8_t max, t0, t1;
max = vabdq_u16(p1, p0);
max = vmaxq_u16(max, vabdq_u16(q1, q0));
*hev = vcgtq_u16(max, thresh);
*mask = vmaxq_u16(max, vabdq_u16(p3, p2));
*mask = vmaxq_u16(*mask, vabdq_u16(p2, p1));
*mask = vmaxq_u16(*mask, vabdq_u16(q2, q1));
*mask = vmaxq_u16(*mask, vabdq_u16(q3, q2));
t0 = vabdq_u16(p0, q0);
t1 = vabdq_u16(p1, q1);
t0 = vaddq_u16(t0, t0);
t1 = vshrq_n_u16(t1, 1);
t0 = vaddq_u16(t0, t1);
*mask = vcleq_u16(*mask, limit);
t0 = vcleq_u16(t0, blimit);
*mask = vandq_u16(*mask, t0);
return max;
}
static INLINE uint16x8_t filter_flat_hev_mask(
const uint16x8_t limit, const uint16x8_t blimit, const uint16x8_t thresh,
const uint16x8_t p3, const uint16x8_t p2, const uint16x8_t p1,
const uint16x8_t p0, const uint16x8_t q0, const uint16x8_t q1,
const uint16x8_t q2, const uint16x8_t q3, uint16x8_t *flat,
uint32_t *flat_status, uint16x8_t *hev, const int bd) {
uint16x8_t mask;
const uint16x8_t max = filter_hev_mask4(limit, blimit, thresh, p3, p2, p1, p0,
q0, q1, q2, q3, hev, &mask);
*flat = vmaxq_u16(max, vabdq_u16(p2, p0));
*flat = vmaxq_u16(*flat, vabdq_u16(q2, q0));
*flat = vmaxq_u16(*flat, vabdq_u16(p3, p0));
*flat = vmaxq_u16(*flat, vabdq_u16(q3, q0));
*flat = vcleq_u16(*flat, vdupq_n_u16(1 << (bd - 8))); /* flat_mask4() */
*flat = vandq_u16(*flat, mask);
*flat_status = calc_flat_status(*flat);
return mask;
}
static INLINE uint16x8_t flat_mask5(const uint16x8_t p4, const uint16x8_t p3,
const uint16x8_t p2, const uint16x8_t p1,
const uint16x8_t p0, const uint16x8_t q0,
const uint16x8_t q1, const uint16x8_t q2,
const uint16x8_t q3, const uint16x8_t q4,
const uint16x8_t flat,
uint32_t *flat2_status, const int bd) {
uint16x8_t flat2 = vabdq_u16(p4, p0);
flat2 = vmaxq_u16(flat2, vabdq_u16(p3, p0));
flat2 = vmaxq_u16(flat2, vabdq_u16(p2, p0));
flat2 = vmaxq_u16(flat2, vabdq_u16(p1, p0));
flat2 = vmaxq_u16(flat2, vabdq_u16(q1, q0));
flat2 = vmaxq_u16(flat2, vabdq_u16(q2, q0));
flat2 = vmaxq_u16(flat2, vabdq_u16(q3, q0));
flat2 = vmaxq_u16(flat2, vabdq_u16(q4, q0));
flat2 = vcleq_u16(flat2, vdupq_n_u16(1 << (bd - 8)));
flat2 = vandq_u16(flat2, flat);
*flat2_status = calc_flat_status(flat2);
return flat2;
}
static INLINE int16x8_t flip_sign(const uint16x8_t v, const int bd) {
const uint16x8_t offset = vdupq_n_u16(0x80 << (bd - 8));
return vreinterpretq_s16_u16(vsubq_u16(v, offset));
}
static INLINE uint16x8_t flip_sign_back(const int16x8_t v, const int bd) {
const int16x8_t offset = vdupq_n_s16(0x80 << (bd - 8));
return vreinterpretq_u16_s16(vaddq_s16(v, offset));
}
static INLINE void filter_update(const uint16x8_t sub0, const uint16x8_t sub1,
const uint16x8_t add0, const uint16x8_t add1,
uint16x8_t *sum) {
*sum = vsubq_u16(*sum, sub0);
*sum = vsubq_u16(*sum, sub1);
*sum = vaddq_u16(*sum, add0);
*sum = vaddq_u16(*sum, add1);
}
static INLINE uint16x8_t calc_7_tap_filter_kernel(const uint16x8_t sub0,
const uint16x8_t sub1,
const uint16x8_t add0,
const uint16x8_t add1,
uint16x8_t *sum) {
filter_update(sub0, sub1, add0, add1, sum);
return vrshrq_n_u16(*sum, 3);
}
static INLINE uint16x8_t apply_15_tap_filter_kernel(
const uint16x8_t flat, const uint16x8_t sub0, const uint16x8_t sub1,
const uint16x8_t add0, const uint16x8_t add1, const uint16x8_t in,
uint16x8_t *sum) {
filter_update(sub0, sub1, add0, add1, sum);
return vbslq_u16(flat, vrshrq_n_u16(*sum, 4), in);
}
// 7-tap filter [1, 1, 1, 2, 1, 1, 1]
static INLINE void calc_7_tap_filter(const uint16x8_t p3, const uint16x8_t p2,
const uint16x8_t p1, const uint16x8_t p0,
const uint16x8_t q0, const uint16x8_t q1,
const uint16x8_t q2, const uint16x8_t q3,
uint16x8_t *op2, uint16x8_t *op1,
uint16x8_t *op0, uint16x8_t *oq0,
uint16x8_t *oq1, uint16x8_t *oq2) {
uint16x8_t sum;
sum = vaddq_u16(p3, p3); // 2*p3
sum = vaddq_u16(sum, p3); // 3*p3
sum = vaddq_u16(sum, p2); // 3*p3+p2
sum = vaddq_u16(sum, p2); // 3*p3+2*p2
sum = vaddq_u16(sum, p1); // 3*p3+2*p2+p1
sum = vaddq_u16(sum, p0); // 3*p3+2*p2+p1+p0
sum = vaddq_u16(sum, q0); // 3*p3+2*p2+p1+p0+q0
*op2 = vrshrq_n_u16(sum, 3);
*op1 = calc_7_tap_filter_kernel(p3, p2, p1, q1, &sum);
*op0 = calc_7_tap_filter_kernel(p3, p1, p0, q2, &sum);
*oq0 = calc_7_tap_filter_kernel(p3, p0, q0, q3, &sum);
*oq1 = calc_7_tap_filter_kernel(p2, q0, q1, q3, &sum);
*oq2 = calc_7_tap_filter_kernel(p1, q1, q2, q3, &sum);
}
static INLINE void apply_7_tap_filter(const uint16x8_t flat,
const uint16x8_t p3, const uint16x8_t p2,
const uint16x8_t p1, const uint16x8_t p0,
const uint16x8_t q0, const uint16x8_t q1,
const uint16x8_t q2, const uint16x8_t q3,
uint16x8_t *op2, uint16x8_t *op1,
uint16x8_t *op0, uint16x8_t *oq0,
uint16x8_t *oq1, uint16x8_t *oq2) {
uint16x8_t tp1, tp0, tq0, tq1;
calc_7_tap_filter(p3, p2, p1, p0, q0, q1, q2, q3, op2, &tp1, &tp0, &tq0, &tq1,
oq2);
*op2 = vbslq_u16(flat, *op2, p2);
*op1 = vbslq_u16(flat, tp1, *op1);
*op0 = vbslq_u16(flat, tp0, *op0);
*oq0 = vbslq_u16(flat, tq0, *oq0);
*oq1 = vbslq_u16(flat, tq1, *oq1);
*oq2 = vbslq_u16(flat, *oq2, q2);
}
// 15-tap filter [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1]
static INLINE void apply_15_tap_filter(
const uint16x8_t flat2, const uint16x8_t p7, const uint16x8_t p6,
const uint16x8_t p5, const uint16x8_t p4, const uint16x8_t p3,
const uint16x8_t p2, const uint16x8_t p1, const uint16x8_t p0,
const uint16x8_t q0, const uint16x8_t q1, const uint16x8_t q2,
const uint16x8_t q3, const uint16x8_t q4, const uint16x8_t q5,
const uint16x8_t q6, const uint16x8_t q7, uint16x8_t *op6, uint16x8_t *op5,
uint16x8_t *op4, uint16x8_t *op3, uint16x8_t *op2, uint16x8_t *op1,
uint16x8_t *op0, uint16x8_t *oq0, uint16x8_t *oq1, uint16x8_t *oq2,
uint16x8_t *oq3, uint16x8_t *oq4, uint16x8_t *oq5, uint16x8_t *oq6) {
uint16x8_t sum;
sum = vshlq_n_u16(p7, 3); // 8*p7
sum = vsubq_u16(sum, p7); // 7*p7
sum = vaddq_u16(sum, p6); // 7*p7+p6
sum = vaddq_u16(sum, p6); // 7*p7+2*p6
sum = vaddq_u16(sum, p5); // 7*p7+2*p6+p5
sum = vaddq_u16(sum, p4); // 7*p7+2*p6+p5+p4
sum = vaddq_u16(sum, p3); // 7*p7+2*p6+p5+p4+p3
sum = vaddq_u16(sum, p2); // 7*p7+2*p6+p5+p4+p3+p2
sum = vaddq_u16(sum, p1); // 7*p7+2*p6+p5+p4+p3+p2+p1
sum = vaddq_u16(sum, p0); // 7*p7+2*p6+p5+p4+p3+p2+p1+p0
sum = vaddq_u16(sum, q0); // 7*p7+2*p6+p5+p4+p3+p2+p1+p0+q0
*op6 = vbslq_u16(flat2, vrshrq_n_u16(sum, 4), p6);
*op5 = apply_15_tap_filter_kernel(flat2, p7, p6, p5, q1, p5, &sum);
*op4 = apply_15_tap_filter_kernel(flat2, p7, p5, p4, q2, p4, &sum);
*op3 = apply_15_tap_filter_kernel(flat2, p7, p4, p3, q3, p3, &sum);
*op2 = apply_15_tap_filter_kernel(flat2, p7, p3, p2, q4, *op2, &sum);
*op1 = apply_15_tap_filter_kernel(flat2, p7, p2, p1, q5, *op1, &sum);
*op0 = apply_15_tap_filter_kernel(flat2, p7, p1, p0, q6, *op0, &sum);
*oq0 = apply_15_tap_filter_kernel(flat2, p7, p0, q0, q7, *oq0, &sum);
*oq1 = apply_15_tap_filter_kernel(flat2, p6, q0, q1, q7, *oq1, &sum);
*oq2 = apply_15_tap_filter_kernel(flat2, p5, q1, q2, q7, *oq2, &sum);
*oq3 = apply_15_tap_filter_kernel(flat2, p4, q2, q3, q7, q3, &sum);
*oq4 = apply_15_tap_filter_kernel(flat2, p3, q3, q4, q7, q4, &sum);
*oq5 = apply_15_tap_filter_kernel(flat2, p2, q4, q5, q7, q5, &sum);
*oq6 = apply_15_tap_filter_kernel(flat2, p1, q5, q6, q7, q6, &sum);
}
static INLINE void filter4(const uint16x8_t mask, const uint16x8_t hev,
const uint16x8_t p1, const uint16x8_t p0,
const uint16x8_t q0, const uint16x8_t q1,
uint16x8_t *op1, uint16x8_t *op0, uint16x8_t *oq0,
uint16x8_t *oq1, const int bd) {
const int16x8_t max = vdupq_n_s16((1 << (bd - 1)) - 1);
const int16x8_t min = vdupq_n_s16((int16_t)(((uint32_t)-1) << (bd - 1)));
int16x8_t filter, filter1, filter2, t;
int16x8_t ps1 = flip_sign(p1, bd);
int16x8_t ps0 = flip_sign(p0, bd);
int16x8_t qs0 = flip_sign(q0, bd);
int16x8_t qs1 = flip_sign(q1, bd);
/* add outer taps if we have high edge variance */
filter = vsubq_s16(ps1, qs1);
filter = vmaxq_s16(filter, min);
filter = vminq_s16(filter, max);
filter = vandq_s16(filter, vreinterpretq_s16_u16(hev));
t = vsubq_s16(qs0, ps0);
/* inner taps */
filter = vaddq_s16(filter, t);
filter = vaddq_s16(filter, t);
filter = vaddq_s16(filter, t);
filter = vmaxq_s16(filter, min);
filter = vminq_s16(filter, max);
filter = vandq_s16(filter, vreinterpretq_s16_u16(mask));
/* save bottom 3 bits so that we round one side +4 and the other +3 */
/* if it equals 4 we'll set it to adjust by -1 to account for the fact */
/* we'd round it by 3 the other way */
t = vaddq_s16(filter, vdupq_n_s16(4));
t = vminq_s16(t, max);
filter1 = vshrq_n_s16(t, 3);
t = vaddq_s16(filter, vdupq_n_s16(3));
t = vminq_s16(t, max);
filter2 = vshrq_n_s16(t, 3);
qs0 = vsubq_s16(qs0, filter1);
qs0 = vmaxq_s16(qs0, min);
qs0 = vminq_s16(qs0, max);
ps0 = vaddq_s16(ps0, filter2);
ps0 = vmaxq_s16(ps0, min);
ps0 = vminq_s16(ps0, max);
*oq0 = flip_sign_back(qs0, bd);
*op0 = flip_sign_back(ps0, bd);
/* outer tap adjustments */
filter = vrshrq_n_s16(filter1, 1);
filter = vbicq_s16(filter, vreinterpretq_s16_u16(hev));
qs1 = vsubq_s16(qs1, filter);
qs1 = vmaxq_s16(qs1, min);
qs1 = vminq_s16(qs1, max);
ps1 = vaddq_s16(ps1, filter);
ps1 = vmaxq_s16(ps1, min);
ps1 = vminq_s16(ps1, max);
*oq1 = flip_sign_back(qs1, bd);
*op1 = flip_sign_back(ps1, bd);
}
static INLINE void filter8(const uint16x8_t mask, const uint16x8_t flat,
const uint32_t flat_status, const uint16x8_t hev,
const uint16x8_t p3, const uint16x8_t p2,
const uint16x8_t p1, const uint16x8_t p0,
const uint16x8_t q0, const uint16x8_t q1,
const uint16x8_t q2, const uint16x8_t q3,
uint16x8_t *op2, uint16x8_t *op1, uint16x8_t *op0,
uint16x8_t *oq0, uint16x8_t *oq1, uint16x8_t *oq2,
const int bd) {
if (flat_status != (uint32_t)-4) {
filter4(mask, hev, p1, p0, q0, q1, op1, op0, oq0, oq1, bd);
*op2 = p2;
*oq2 = q2;
if (flat_status) {
apply_7_tap_filter(flat, p3, p2, p1, p0, q0, q1, q2, q3, op2, op1, op0,
oq0, oq1, oq2);
}
} else {
calc_7_tap_filter(p3, p2, p1, p0, q0, q1, q2, q3, op2, op1, op0, oq0, oq1,
oq2);
}
}
static INLINE void filter16(
const uint16x8_t mask, const uint16x8_t flat, const uint32_t flat_status,
const uint16x8_t flat2, const uint32_t flat2_status, const uint16x8_t hev,
const uint16x8_t p7, const uint16x8_t p6, const uint16x8_t p5,
const uint16x8_t p4, const uint16x8_t p3, const uint16x8_t p2,
const uint16x8_t p1, const uint16x8_t p0, const uint16x8_t q0,
const uint16x8_t q1, const uint16x8_t q2, const uint16x8_t q3,
const uint16x8_t q4, const uint16x8_t q5, const uint16x8_t q6,
const uint16x8_t q7, uint16x8_t *op6, uint16x8_t *op5, uint16x8_t *op4,
uint16x8_t *op3, uint16x8_t *op2, uint16x8_t *op1, uint16x8_t *op0,
uint16x8_t *oq0, uint16x8_t *oq1, uint16x8_t *oq2, uint16x8_t *oq3,
uint16x8_t *oq4, uint16x8_t *oq5, uint16x8_t *oq6, const int bd) {
if (flat_status != (uint32_t)-4) {
filter4(mask, hev, p1, p0, q0, q1, op1, op0, oq0, oq1, bd);
}
if (flat_status) {
*op2 = p2;
*oq2 = q2;
if (flat2_status != (uint32_t)-4) {
apply_7_tap_filter(flat, p3, p2, p1, p0, q0, q1, q2, q3, op2, op1, op0,
oq0, oq1, oq2);
}
if (flat2_status) {
apply_15_tap_filter(flat2, p7, p6, p5, p4, p3, p2, p1, p0, q0, q1, q2, q3,
q4, q5, q6, q7, op6, op5, op4, op3, op2, op1, op0,
oq0, oq1, oq2, oq3, oq4, oq5, oq6);
}
}
}
static INLINE void load_8x8(const uint16_t *s, const int p, uint16x8_t *p3,
uint16x8_t *p2, uint16x8_t *p1, uint16x8_t *p0,
uint16x8_t *q0, uint16x8_t *q1, uint16x8_t *q2,
uint16x8_t *q3) {
*p3 = vld1q_u16(s);
s += p;
*p2 = vld1q_u16(s);
s += p;
*p1 = vld1q_u16(s);
s += p;
*p0 = vld1q_u16(s);
s += p;
*q0 = vld1q_u16(s);
s += p;
*q1 = vld1q_u16(s);
s += p;
*q2 = vld1q_u16(s);
s += p;
*q3 = vld1q_u16(s);
}
static INLINE void load_8x16(const uint16_t *s, const int p, uint16x8_t *s0,
uint16x8_t *s1, uint16x8_t *s2, uint16x8_t *s3,
uint16x8_t *s4, uint16x8_t *s5, uint16x8_t *s6,
uint16x8_t *s7, uint16x8_t *s8, uint16x8_t *s9,
uint16x8_t *s10, uint16x8_t *s11, uint16x8_t *s12,
uint16x8_t *s13, uint16x8_t *s14,
uint16x8_t *s15) {
*s0 = vld1q_u16(s);
s += p;
*s1 = vld1q_u16(s);
s += p;
*s2 = vld1q_u16(s);
s += p;
*s3 = vld1q_u16(s);
s += p;
*s4 = vld1q_u16(s);
s += p;
*s5 = vld1q_u16(s);
s += p;
*s6 = vld1q_u16(s);
s += p;
*s7 = vld1q_u16(s);
s += p;
*s8 = vld1q_u16(s);
s += p;
*s9 = vld1q_u16(s);
s += p;
*s10 = vld1q_u16(s);
s += p;
*s11 = vld1q_u16(s);
s += p;
*s12 = vld1q_u16(s);
s += p;
*s13 = vld1q_u16(s);
s += p;
*s14 = vld1q_u16(s);
s += p;
*s15 = vld1q_u16(s);
}
static INLINE void store_8x4(uint16_t *s, const int p, const uint16x8_t s0,
const uint16x8_t s1, const uint16x8_t s2,
const uint16x8_t s3) {
vst1q_u16(s, s0);
s += p;
vst1q_u16(s, s1);
s += p;
vst1q_u16(s, s2);
s += p;
vst1q_u16(s, s3);
}
static INLINE void store_8x6(uint16_t *s, const int p, const uint16x8_t s0,
const uint16x8_t s1, const uint16x8_t s2,
const uint16x8_t s3, const uint16x8_t s4,
const uint16x8_t s5) {
vst1q_u16(s, s0);
s += p;
vst1q_u16(s, s1);
s += p;
vst1q_u16(s, s2);
s += p;
vst1q_u16(s, s3);
s += p;
vst1q_u16(s, s4);
s += p;
vst1q_u16(s, s5);
}
static INLINE void store_4x8(uint16_t *s, const int p, const uint16x8_t p1,
const uint16x8_t p0, const uint16x8_t q0,
const uint16x8_t q1) {
uint16x8x4_t o;
o.val[0] = p1;
o.val[1] = p0;
o.val[2] = q0;
o.val[3] = q1;
vst4q_lane_u16(s, o, 0);
s += p;
vst4q_lane_u16(s, o, 1);
s += p;
vst4q_lane_u16(s, o, 2);
s += p;
vst4q_lane_u16(s, o, 3);
s += p;
vst4q_lane_u16(s, o, 4);
s += p;
vst4q_lane_u16(s, o, 5);
s += p;
vst4q_lane_u16(s, o, 6);
s += p;
vst4q_lane_u16(s, o, 7);
}
static INLINE void store_6x8(uint16_t *s, const int p, const uint16x8_t s0,
const uint16x8_t s1, const uint16x8_t s2,
const uint16x8_t s3, const uint16x8_t s4,
const uint16x8_t s5) {
uint16x8x3_t o0, o1;
o0.val[0] = s0;
o0.val[1] = s1;
o0.val[2] = s2;
o1.val[0] = s3;
o1.val[1] = s4;
o1.val[2] = s5;
vst3q_lane_u16(s - 3, o0, 0);
vst3q_lane_u16(s + 0, o1, 0);
s += p;
vst3q_lane_u16(s - 3, o0, 1);
vst3q_lane_u16(s + 0, o1, 1);
s += p;
vst3q_lane_u16(s - 3, o0, 2);
vst3q_lane_u16(s + 0, o1, 2);
s += p;
vst3q_lane_u16(s - 3, o0, 3);
vst3q_lane_u16(s + 0, o1, 3);
s += p;
vst3q_lane_u16(s - 3, o0, 4);
vst3q_lane_u16(s + 0, o1, 4);
s += p;
vst3q_lane_u16(s - 3, o0, 5);
vst3q_lane_u16(s + 0, o1, 5);
s += p;
vst3q_lane_u16(s - 3, o0, 6);
vst3q_lane_u16(s + 0, o1, 6);
s += p;
vst3q_lane_u16(s - 3, o0, 7);
vst3q_lane_u16(s + 0, o1, 7);
}
static INLINE void store_7x8(uint16_t *s, const int p, const uint16x8_t s0,
const uint16x8_t s1, const uint16x8_t s2,
const uint16x8_t s3, const uint16x8_t s4,
const uint16x8_t s5, const uint16x8_t s6) {
uint16x8x4_t o0;
uint16x8x3_t o1;
o0.val[0] = s0;
o0.val[1] = s1;
o0.val[2] = s2;
o0.val[3] = s3;
o1.val[0] = s4;
o1.val[1] = s5;
o1.val[2] = s6;
vst4q_lane_u16(s - 4, o0, 0);
vst3q_lane_u16(s + 0, o1, 0);
s += p;
vst4q_lane_u16(s - 4, o0, 1);
vst3q_lane_u16(s + 0, o1, 1);
s += p;
vst4q_lane_u16(s - 4, o0, 2);
vst3q_lane_u16(s + 0, o1, 2);
s += p;
vst4q_lane_u16(s - 4, o0, 3);
vst3q_lane_u16(s + 0, o1, 3);
s += p;
vst4q_lane_u16(s - 4, o0, 4);
vst3q_lane_u16(s + 0, o1, 4);
s += p;
vst4q_lane_u16(s - 4, o0, 5);
vst3q_lane_u16(s + 0, o1, 5);
s += p;
vst4q_lane_u16(s - 4, o0, 6);
vst3q_lane_u16(s + 0, o1, 6);
s += p;
vst4q_lane_u16(s - 4, o0, 7);
vst3q_lane_u16(s + 0, o1, 7);
}
static INLINE void store_8x14(uint16_t *s, const int p, const uint16x8_t p6,
const uint16x8_t p5, const uint16x8_t p4,
const uint16x8_t p3, const uint16x8_t p2,
const uint16x8_t p1, const uint16x8_t p0,
const uint16x8_t q0, const uint16x8_t q1,
const uint16x8_t q2, const uint16x8_t q3,
const uint16x8_t q4, const uint16x8_t q5,
const uint16x8_t q6, const uint32_t flat_status,
const uint32_t flat2_status) {
if (flat_status) {
if (flat2_status) {
vst1q_u16(s - 7 * p, p6);
vst1q_u16(s - 6 * p, p5);
vst1q_u16(s - 5 * p, p4);
vst1q_u16(s - 4 * p, p3);
vst1q_u16(s + 3 * p, q3);
vst1q_u16(s + 4 * p, q4);
vst1q_u16(s + 5 * p, q5);
vst1q_u16(s + 6 * p, q6);
}
vst1q_u16(s - 3 * p, p2);
vst1q_u16(s + 2 * p, q2);
}
vst1q_u16(s - 2 * p, p1);
vst1q_u16(s - 1 * p, p0);
vst1q_u16(s + 0 * p, q0);
vst1q_u16(s + 1 * p, q1);
}
void vpx_highbd_lpf_horizontal_4_neon(uint16_t *s, int p, const uint8_t *blimit,
const uint8_t *limit,
const uint8_t *thresh, int bd) {
uint16x8_t blimit_vec, limit_vec, thresh_vec, p3, p2, p1, p0, q0, q1, q2, q3,
mask, hev;
load_thresh(blimit, limit, thresh, &blimit_vec, &limit_vec, &thresh_vec, bd);
load_8x8(s - 4 * p, p, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
filter_hev_mask4(limit_vec, blimit_vec, thresh_vec, p3, p2, p1, p0, q0, q1,
q2, q3, &hev, &mask);
filter4(mask, hev, p1, p0, q0, q1, &p1, &p0, &q0, &q1, bd);
store_8x4(s - 2 * p, p, p1, p0, q0, q1);
}
void vpx_highbd_lpf_horizontal_4_dual_neon(
uint16_t *s, int p, const uint8_t *blimit0, const uint8_t *limit0,
const uint8_t *thresh0, const uint8_t *blimit1, const uint8_t *limit1,
const uint8_t *thresh1, int bd) {
vpx_highbd_lpf_horizontal_4_neon(s, p, blimit0, limit0, thresh0, bd);
vpx_highbd_lpf_horizontal_4_neon(s + 8, p, blimit1, limit1, thresh1, bd);
}
void vpx_highbd_lpf_vertical_4_neon(uint16_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int bd) {
uint16x8_t blimit_vec, limit_vec, thresh_vec, p3, p2, p1, p0, q0, q1, q2, q3,
mask, hev;
load_8x8(s - 4, p, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
transpose_s16_8x8((int16x8_t *)&p3, (int16x8_t *)&p2, (int16x8_t *)&p1,
(int16x8_t *)&p0, (int16x8_t *)&q0, (int16x8_t *)&q1,
(int16x8_t *)&q2, (int16x8_t *)&q3);
load_thresh(blimit, limit, thresh, &blimit_vec, &limit_vec, &thresh_vec, bd);
filter_hev_mask4(limit_vec, blimit_vec, thresh_vec, p3, p2, p1, p0, q0, q1,
q2, q3, &hev, &mask);
filter4(mask, hev, p1, p0, q0, q1, &p1, &p0, &q0, &q1, bd);
store_4x8(s - 2, p, p1, p0, q0, q1);
}
void vpx_highbd_lpf_vertical_4_dual_neon(
uint16_t *s, int p, const uint8_t *blimit0, const uint8_t *limit0,
const uint8_t *thresh0, const uint8_t *blimit1, const uint8_t *limit1,
const uint8_t *thresh1, int bd) {
vpx_highbd_lpf_vertical_4_neon(s, p, blimit0, limit0, thresh0, bd);
vpx_highbd_lpf_vertical_4_neon(s + 8 * p, p, blimit1, limit1, thresh1, bd);
}
void vpx_highbd_lpf_horizontal_8_neon(uint16_t *s, int p, const uint8_t *blimit,
const uint8_t *limit,
const uint8_t *thresh, int bd) {
uint16x8_t blimit_vec, limit_vec, thresh_vec, p3, p2, p1, p0, q0, q1, q2, q3,
op2, op1, op0, oq0, oq1, oq2, mask, flat, hev;
uint32_t flat_status;
load_thresh(blimit, limit, thresh, &blimit_vec, &limit_vec, &thresh_vec, bd);
load_8x8(s - 4 * p, p, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
mask = filter_flat_hev_mask(limit_vec, blimit_vec, thresh_vec, p3, p2, p1, p0,
q0, q1, q2, q3, &flat, &flat_status, &hev, bd);
filter8(mask, flat, flat_status, hev, p3, p2, p1, p0, q0, q1, q2, q3, &op2,
&op1, &op0, &oq0, &oq1, &oq2, bd);
store_8x6(s - 3 * p, p, op2, op1, op0, oq0, oq1, oq2);
}
void vpx_highbd_lpf_horizontal_8_dual_neon(
uint16_t *s, int p, const uint8_t *blimit0, const uint8_t *limit0,
const uint8_t *thresh0, const uint8_t *blimit1, const uint8_t *limit1,
const uint8_t *thresh1, int bd) {
vpx_highbd_lpf_horizontal_8_neon(s, p, blimit0, limit0, thresh0, bd);
vpx_highbd_lpf_horizontal_8_neon(s + 8, p, blimit1, limit1, thresh1, bd);
}
void vpx_highbd_lpf_vertical_8_neon(uint16_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int bd) {
uint16x8_t blimit_vec, limit_vec, thresh_vec, p3, p2, p1, p0, q0, q1, q2, q3,
op2, op1, op0, oq0, oq1, oq2, mask, flat, hev;
uint32_t flat_status;
load_8x8(s - 4, p, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
transpose_s16_8x8((int16x8_t *)&p3, (int16x8_t *)&p2, (int16x8_t *)&p1,
(int16x8_t *)&p0, (int16x8_t *)&q0, (int16x8_t *)&q1,
(int16x8_t *)&q2, (int16x8_t *)&q3);
load_thresh(blimit, limit, thresh, &blimit_vec, &limit_vec, &thresh_vec, bd);
mask = filter_flat_hev_mask(limit_vec, blimit_vec, thresh_vec, p3, p2, p1, p0,
q0, q1, q2, q3, &flat, &flat_status, &hev, bd);
filter8(mask, flat, flat_status, hev, p3, p2, p1, p0, q0, q1, q2, q3, &op2,
&op1, &op0, &oq0, &oq1, &oq2, bd);
// Note: store_6x8() is faster than transpose + store_8x8().
store_6x8(s, p, op2, op1, op0, oq0, oq1, oq2);
}
void vpx_highbd_lpf_vertical_8_dual_neon(
uint16_t *s, int p, const uint8_t *blimit0, const uint8_t *limit0,
const uint8_t *thresh0, const uint8_t *blimit1, const uint8_t *limit1,
const uint8_t *thresh1, int bd) {
vpx_highbd_lpf_vertical_8_neon(s, p, blimit0, limit0, thresh0, bd);
vpx_highbd_lpf_vertical_8_neon(s + 8 * p, p, blimit1, limit1, thresh1, bd);
}
static void lpf_horizontal_16_kernel(uint16_t *s, int p,
const uint16x8_t blimit_vec,
const uint16x8_t limit_vec,
const uint16x8_t thresh_vec,
const int bd) {
uint16x8_t mask, flat, flat2, hev, p7, p6, p5, p4, p3, p2, p1, p0, q0, q1, q2,
q3, q4, q5, q6, q7, op6, op5, op4, op3, op2, op1, op0, oq0, oq1, oq2, oq3,
oq4, oq5, oq6;
uint32_t flat_status, flat2_status;
load_8x16(s - 8 * p, p, &p7, &p6, &p5, &p4, &p3, &p2, &p1, &p0, &q0, &q1, &q2,
&q3, &q4, &q5, &q6, &q7);
mask = filter_flat_hev_mask(limit_vec, blimit_vec, thresh_vec, p3, p2, p1, p0,
q0, q1, q2, q3, &flat, &flat_status, &hev, bd);
flat2 = flat_mask5(p7, p6, p5, p4, p0, q0, q4, q5, q6, q7, flat,
&flat2_status, bd);
filter16(mask, flat, flat_status, flat2, flat2_status, hev, p7, p6, p5, p4,
p3, p2, p1, p0, q0, q1, q2, q3, q4, q5, q6, q7, &op6, &op5, &op4,
&op3, &op2, &op1, &op0, &oq0, &oq1, &oq2, &oq3, &oq4, &oq5, &oq6,
bd);
store_8x14(s, p, op6, op5, op4, op3, op2, op1, op0, oq0, oq1, oq2, oq3, oq4,
oq5, oq6, flat_status, flat2_status);
}
static void lpf_vertical_16_kernel(uint16_t *s, int p,
const uint16x8_t blimit_vec,
const uint16x8_t limit_vec,
const uint16x8_t thresh_vec, const int bd) {
uint16x8_t mask, flat, flat2, hev, p7, p6, p5, p4, p3, p2, p1, p0, q0, q1, q2,
q3, q4, q5, q6, q7, op6, op5, op4, op3, op2, op1, op0, oq0, oq1, oq2, oq3,
oq4, oq5, oq6;
uint32_t flat_status, flat2_status;
load_8x8(s - 8, p, &p7, &p6, &p5, &p4, &p3, &p2, &p1, &p0);
transpose_s16_8x8((int16x8_t *)&p7, (int16x8_t *)&p6, (int16x8_t *)&p5,
(int16x8_t *)&p4, (int16x8_t *)&p3, (int16x8_t *)&p2,
(int16x8_t *)&p1, (int16x8_t *)&p0);
load_8x8(s, p, &q0, &q1, &q2, &q3, &q4, &q5, &q6, &q7);
transpose_s16_8x8((int16x8_t *)&q0, (int16x8_t *)&q1, (int16x8_t *)&q2,
(int16x8_t *)&q3, (int16x8_t *)&q4, (int16x8_t *)&q5,
(int16x8_t *)&q6, (int16x8_t *)&q7);
mask = filter_flat_hev_mask(limit_vec, blimit_vec, thresh_vec, p3, p2, p1, p0,
q0, q1, q2, q3, &flat, &flat_status, &hev, bd);
flat2 = flat_mask5(p7, p6, p5, p4, p0, q0, q4, q5, q6, q7, flat,
&flat2_status, bd);
filter16(mask, flat, flat_status, flat2, flat2_status, hev, p7, p6, p5, p4,
p3, p2, p1, p0, q0, q1, q2, q3, q4, q5, q6, q7, &op6, &op5, &op4,
&op3, &op2, &op1, &op0, &oq0, &oq1, &oq2, &oq3, &oq4, &oq5, &oq6,
bd);
if (flat_status) {
if (flat2_status) {
store_7x8(s - 3, p, op6, op5, op4, op3, op2, op1, op0);
store_7x8(s + 4, p, oq0, oq1, oq2, oq3, oq4, oq5, oq6);
} else {
// Note: store_6x8() is faster than transpose + store_8x8().
store_6x8(s, p, op2, op1, op0, oq0, oq1, oq2);
}
} else {
store_4x8(s - 2, p, op1, op0, oq0, oq1);
}
}
void vpx_highbd_lpf_horizontal_16_neon(uint16_t *s, int p,
const uint8_t *blimit,
const uint8_t *limit,
const uint8_t *thresh, int bd) {
uint16x8_t blimit_vec, limit_vec, thresh_vec;
load_thresh(blimit, limit, thresh, &blimit_vec, &limit_vec, &thresh_vec, bd);
lpf_horizontal_16_kernel(s, p, blimit_vec, limit_vec, thresh_vec, bd);
}
void vpx_highbd_lpf_horizontal_16_dual_neon(uint16_t *s, int p,
const uint8_t *blimit,
const uint8_t *limit,
const uint8_t *thresh, int bd) {
uint16x8_t blimit_vec, limit_vec, thresh_vec;
load_thresh(blimit, limit, thresh, &blimit_vec, &limit_vec, &thresh_vec, bd);
lpf_horizontal_16_kernel(s, p, blimit_vec, limit_vec, thresh_vec, bd);
lpf_horizontal_16_kernel(s + 8, p, blimit_vec, limit_vec, thresh_vec, bd);
}
void vpx_highbd_lpf_vertical_16_neon(uint16_t *s, int p, const uint8_t *blimit,
const uint8_t *limit,
const uint8_t *thresh, int bd) {
uint16x8_t blimit_vec, limit_vec, thresh_vec;
load_thresh(blimit, limit, thresh, &blimit_vec, &limit_vec, &thresh_vec, bd);
lpf_vertical_16_kernel(s, p, blimit_vec, limit_vec, thresh_vec, bd);
}
void vpx_highbd_lpf_vertical_16_dual_neon(uint16_t *s, int p,
const uint8_t *blimit,
const uint8_t *limit,
const uint8_t *thresh, int bd) {
uint16x8_t blimit_vec, limit_vec, thresh_vec;
load_thresh(blimit, limit, thresh, &blimit_vec, &limit_vec, &thresh_vec, bd);
lpf_vertical_16_kernel(s, p, blimit_vec, limit_vec, thresh_vec, bd);
lpf_vertical_16_kernel(s + 8 * p, p, blimit_vec, limit_vec, thresh_vec, bd);
}
@@ -0,0 +1,931 @@
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/arm/transpose_neon.h"
#include "vpx_ports/mem.h"
static INLINE void load_4x4(const int16_t *s, const ptrdiff_t p,
int16x4_t *const s0, int16x4_t *const s1,
int16x4_t *const s2, int16x4_t *const s3) {
*s0 = vld1_s16(s);
s += p;
*s1 = vld1_s16(s);
s += p;
*s2 = vld1_s16(s);
s += p;
*s3 = vld1_s16(s);
}
static INLINE void load_8x4(const uint16_t *s, const ptrdiff_t p,
uint16x8_t *const s0, uint16x8_t *const s1,
uint16x8_t *const s2, uint16x8_t *const s3) {
*s0 = vld1q_u16(s);
s += p;
*s1 = vld1q_u16(s);
s += p;
*s2 = vld1q_u16(s);
s += p;
*s3 = vld1q_u16(s);
}
static INLINE void load_8x8(const int16_t *s, const ptrdiff_t p,
int16x8_t *const s0, int16x8_t *const s1,
int16x8_t *const s2, int16x8_t *const s3,
int16x8_t *const s4, int16x8_t *const s5,
int16x8_t *const s6, int16x8_t *const s7) {
*s0 = vld1q_s16(s);
s += p;
*s1 = vld1q_s16(s);
s += p;
*s2 = vld1q_s16(s);
s += p;
*s3 = vld1q_s16(s);
s += p;
*s4 = vld1q_s16(s);
s += p;
*s5 = vld1q_s16(s);
s += p;
*s6 = vld1q_s16(s);
s += p;
*s7 = vld1q_s16(s);
}
static INLINE void store_8x8(uint16_t *s, const ptrdiff_t p,
const uint16x8_t s0, const uint16x8_t s1,
const uint16x8_t s2, const uint16x8_t s3,
const uint16x8_t s4, const uint16x8_t s5,
const uint16x8_t s6, const uint16x8_t s7) {
vst1q_u16(s, s0);
s += p;
vst1q_u16(s, s1);
s += p;
vst1q_u16(s, s2);
s += p;
vst1q_u16(s, s3);
s += p;
vst1q_u16(s, s4);
s += p;
vst1q_u16(s, s5);
s += p;
vst1q_u16(s, s6);
s += p;
vst1q_u16(s, s7);
}
static INLINE int32x4_t highbd_convolve8_4(
const int16x4_t s0, const int16x4_t s1, const int16x4_t s2,
const int16x4_t s3, const int16x4_t s4, const int16x4_t s5,
const int16x4_t s6, const int16x4_t s7, const int16x8_t filters) {
const int16x4_t filters_lo = vget_low_s16(filters);
const int16x4_t filters_hi = vget_high_s16(filters);
int32x4_t sum;
sum = vmull_lane_s16(s0, filters_lo, 0);
sum = vmlal_lane_s16(sum, s1, filters_lo, 1);
sum = vmlal_lane_s16(sum, s2, filters_lo, 2);
sum = vmlal_lane_s16(sum, s3, filters_lo, 3);
sum = vmlal_lane_s16(sum, s4, filters_hi, 0);
sum = vmlal_lane_s16(sum, s5, filters_hi, 1);
sum = vmlal_lane_s16(sum, s6, filters_hi, 2);
sum = vmlal_lane_s16(sum, s7, filters_hi, 3);
return sum;
}
static INLINE uint16x8_t
highbd_convolve8_8(const int16x8_t s0, const int16x8_t s1, const int16x8_t s2,
const int16x8_t s3, const int16x8_t s4, const int16x8_t s5,
const int16x8_t s6, const int16x8_t s7,
const int16x8_t filters, const uint16x8_t max) {
const int16x4_t filters_lo = vget_low_s16(filters);
const int16x4_t filters_hi = vget_high_s16(filters);
int32x4_t sum0, sum1;
uint16x8_t d;
sum0 = vmull_lane_s16(vget_low_s16(s0), filters_lo, 0);
sum0 = vmlal_lane_s16(sum0, vget_low_s16(s1), filters_lo, 1);
sum0 = vmlal_lane_s16(sum0, vget_low_s16(s2), filters_lo, 2);
sum0 = vmlal_lane_s16(sum0, vget_low_s16(s3), filters_lo, 3);
sum0 = vmlal_lane_s16(sum0, vget_low_s16(s4), filters_hi, 0);
sum0 = vmlal_lane_s16(sum0, vget_low_s16(s5), filters_hi, 1);
sum0 = vmlal_lane_s16(sum0, vget_low_s16(s6), filters_hi, 2);
sum0 = vmlal_lane_s16(sum0, vget_low_s16(s7), filters_hi, 3);
sum1 = vmull_lane_s16(vget_high_s16(s0), filters_lo, 0);
sum1 = vmlal_lane_s16(sum1, vget_high_s16(s1), filters_lo, 1);
sum1 = vmlal_lane_s16(sum1, vget_high_s16(s2), filters_lo, 2);
sum1 = vmlal_lane_s16(sum1, vget_high_s16(s3), filters_lo, 3);
sum1 = vmlal_lane_s16(sum1, vget_high_s16(s4), filters_hi, 0);
sum1 = vmlal_lane_s16(sum1, vget_high_s16(s5), filters_hi, 1);
sum1 = vmlal_lane_s16(sum1, vget_high_s16(s6), filters_hi, 2);
sum1 = vmlal_lane_s16(sum1, vget_high_s16(s7), filters_hi, 3);
d = vcombine_u16(vqrshrun_n_s32(sum0, 7), vqrshrun_n_s32(sum1, 7));
d = vminq_u16(d, max);
return d;
}
void vpx_highbd_convolve8_horiz_neon(const uint16_t *src, ptrdiff_t src_stride,
uint16_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4,
int w, int h, int bd) {
if (x_step_q4 != 16) {
vpx_highbd_convolve8_horiz_c(src, src_stride, dst, dst_stride, filter,
x0_q4, x_step_q4, y0_q4, y_step_q4, w, h, bd);
} else {
const int16x8_t filters = vld1q_s16(filter[x0_q4]);
const uint16x8_t max = vdupq_n_u16((1 << bd) - 1);
uint16x8_t t0, t1, t2, t3;
assert(!((intptr_t)dst & 3));
assert(!(dst_stride & 3));
src -= 3;
if (h == 4) {
int16x4_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
int32x4_t d0, d1, d2, d3;
uint16x8_t d01, d23;
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
load_8x4(src, src_stride, &t0, &t1, &t2, &t3);
transpose_u16_8x4(&t0, &t1, &t2, &t3);
s0 = vreinterpret_s16_u16(vget_low_u16(t0));
s1 = vreinterpret_s16_u16(vget_low_u16(t1));
s2 = vreinterpret_s16_u16(vget_low_u16(t2));
s3 = vreinterpret_s16_u16(vget_low_u16(t3));
s4 = vreinterpret_s16_u16(vget_high_u16(t0));
s5 = vreinterpret_s16_u16(vget_high_u16(t1));
s6 = vreinterpret_s16_u16(vget_high_u16(t2));
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
src += 7;
do {
load_4x4((const int16_t *)src, src_stride, &s7, &s8, &s9, &s10);
transpose_s16_4x4d(&s7, &s8, &s9, &s10);
d0 = highbd_convolve8_4(s0, s1, s2, s3, s4, s5, s6, s7, filters);
d1 = highbd_convolve8_4(s1, s2, s3, s4, s5, s6, s7, s8, filters);
d2 = highbd_convolve8_4(s2, s3, s4, s5, s6, s7, s8, s9, filters);
d3 = highbd_convolve8_4(s3, s4, s5, s6, s7, s8, s9, s10, filters);
d01 = vcombine_u16(vqrshrun_n_s32(d0, 7), vqrshrun_n_s32(d1, 7));
d23 = vcombine_u16(vqrshrun_n_s32(d2, 7), vqrshrun_n_s32(d3, 7));
d01 = vminq_u16(d01, max);
d23 = vminq_u16(d23, max);
transpose_u16_4x4q(&d01, &d23);
vst1_u16(dst + 0 * dst_stride, vget_low_u16(d01));
vst1_u16(dst + 1 * dst_stride, vget_low_u16(d23));
vst1_u16(dst + 2 * dst_stride, vget_high_u16(d01));
vst1_u16(dst + 3 * dst_stride, vget_high_u16(d23));
s0 = s4;
s1 = s5;
s2 = s6;
s3 = s7;
s4 = s8;
s5 = s9;
s6 = s10;
src += 4;
dst += 4;
w -= 4;
} while (w > 0);
} else {
int16x8_t t4, t5, t6, t7;
int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
uint16x8_t d0, d1, d2, d3;
if (w == 4) {
do {
load_8x8((const int16_t *)src, src_stride, &s0, &s1, &s2, &s3, &s4,
&s5, &s6, &s7);
transpose_s16_8x8(&s0, &s1, &s2, &s3, &s4, &s5, &s6, &s7);
load_8x8((const int16_t *)(src + 7), src_stride, &s7, &s8, &s9, &s10,
&t4, &t5, &t6, &t7);
src += 8 * src_stride;
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
__builtin_prefetch(dst + 4 * dst_stride);
__builtin_prefetch(dst + 5 * dst_stride);
__builtin_prefetch(dst + 6 * dst_stride);
__builtin_prefetch(dst + 7 * dst_stride);
transpose_s16_8x8(&s7, &s8, &s9, &s10, &t4, &t5, &t6, &t7);
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
__builtin_prefetch(src + 4 * src_stride);
__builtin_prefetch(src + 5 * src_stride);
__builtin_prefetch(src + 6 * src_stride);
__builtin_prefetch(src + 7 * src_stride);
d0 = highbd_convolve8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters, max);
d1 = highbd_convolve8_8(s1, s2, s3, s4, s5, s6, s7, s8, filters, max);
d2 = highbd_convolve8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters, max);
d3 =
highbd_convolve8_8(s3, s4, s5, s6, s7, s8, s9, s10, filters, max);
transpose_u16_8x4(&d0, &d1, &d2, &d3);
vst1_u16(dst, vget_low_u16(d0));
dst += dst_stride;
vst1_u16(dst, vget_low_u16(d1));
dst += dst_stride;
vst1_u16(dst, vget_low_u16(d2));
dst += dst_stride;
vst1_u16(dst, vget_low_u16(d3));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d0));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d1));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d2));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d3));
dst += dst_stride;
h -= 8;
} while (h > 0);
} else {
int width;
const uint16_t *s;
uint16_t *d;
int16x8_t s11, s12, s13, s14;
uint16x8_t d4, d5, d6, d7;
do {
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
__builtin_prefetch(src + 4 * src_stride);
__builtin_prefetch(src + 5 * src_stride);
__builtin_prefetch(src + 6 * src_stride);
__builtin_prefetch(src + 7 * src_stride);
load_8x8((const int16_t *)src, src_stride, &s0, &s1, &s2, &s3, &s4,
&s5, &s6, &s7);
transpose_s16_8x8(&s0, &s1, &s2, &s3, &s4, &s5, &s6, &s7);
width = w;
s = src + 7;
d = dst;
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
__builtin_prefetch(dst + 4 * dst_stride);
__builtin_prefetch(dst + 5 * dst_stride);
__builtin_prefetch(dst + 6 * dst_stride);
__builtin_prefetch(dst + 7 * dst_stride);
do {
load_8x8((const int16_t *)s, src_stride, &s7, &s8, &s9, &s10, &s11,
&s12, &s13, &s14);
transpose_s16_8x8(&s7, &s8, &s9, &s10, &s11, &s12, &s13, &s14);
d0 = highbd_convolve8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters,
max);
d1 = highbd_convolve8_8(s1, s2, s3, s4, s5, s6, s7, s8, filters,
max);
d2 = highbd_convolve8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters,
max);
d3 = highbd_convolve8_8(s3, s4, s5, s6, s7, s8, s9, s10, filters,
max);
d4 = highbd_convolve8_8(s4, s5, s6, s7, s8, s9, s10, s11, filters,
max);
d5 = highbd_convolve8_8(s5, s6, s7, s8, s9, s10, s11, s12, filters,
max);
d6 = highbd_convolve8_8(s6, s7, s8, s9, s10, s11, s12, s13, filters,
max);
d7 = highbd_convolve8_8(s7, s8, s9, s10, s11, s12, s13, s14,
filters, max);
transpose_u16_8x8(&d0, &d1, &d2, &d3, &d4, &d5, &d6, &d7);
store_8x8(d, dst_stride, d0, d1, d2, d3, d4, d5, d6, d7);
s0 = s8;
s1 = s9;
s2 = s10;
s3 = s11;
s4 = s12;
s5 = s13;
s6 = s14;
s += 8;
d += 8;
width -= 8;
} while (width > 0);
src += 8 * src_stride;
dst += 8 * dst_stride;
h -= 8;
} while (h > 0);
}
}
}
}
void vpx_highbd_convolve8_avg_horiz_neon(const uint16_t *src,
ptrdiff_t src_stride, uint16_t *dst,
ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4,
int y_step_q4, int w, int h, int bd) {
if (x_step_q4 != 16) {
vpx_highbd_convolve8_avg_horiz_c(src, src_stride, dst, dst_stride, filter,
x0_q4, x_step_q4, y0_q4, y_step_q4, w, h,
bd);
} else {
const int16x8_t filters = vld1q_s16(filter[x0_q4]);
const uint16x8_t max = vdupq_n_u16((1 << bd) - 1);
uint16x8_t t0, t1, t2, t3;
assert(!((intptr_t)dst & 3));
assert(!(dst_stride & 3));
src -= 3;
if (h == 4) {
int16x4_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
int32x4_t d0, d1, d2, d3;
uint16x8_t d01, d23, t01, t23;
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
load_8x4(src, src_stride, &t0, &t1, &t2, &t3);
transpose_u16_8x4(&t0, &t1, &t2, &t3);
s0 = vreinterpret_s16_u16(vget_low_u16(t0));
s1 = vreinterpret_s16_u16(vget_low_u16(t1));
s2 = vreinterpret_s16_u16(vget_low_u16(t2));
s3 = vreinterpret_s16_u16(vget_low_u16(t3));
s4 = vreinterpret_s16_u16(vget_high_u16(t0));
s5 = vreinterpret_s16_u16(vget_high_u16(t1));
s6 = vreinterpret_s16_u16(vget_high_u16(t2));
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
src += 7;
do {
load_4x4((const int16_t *)src, src_stride, &s7, &s8, &s9, &s10);
transpose_s16_4x4d(&s7, &s8, &s9, &s10);
d0 = highbd_convolve8_4(s0, s1, s2, s3, s4, s5, s6, s7, filters);
d1 = highbd_convolve8_4(s1, s2, s3, s4, s5, s6, s7, s8, filters);
d2 = highbd_convolve8_4(s2, s3, s4, s5, s6, s7, s8, s9, filters);
d3 = highbd_convolve8_4(s3, s4, s5, s6, s7, s8, s9, s10, filters);
t01 = vcombine_u16(vqrshrun_n_s32(d0, 7), vqrshrun_n_s32(d1, 7));
t23 = vcombine_u16(vqrshrun_n_s32(d2, 7), vqrshrun_n_s32(d3, 7));
t01 = vminq_u16(t01, max);
t23 = vminq_u16(t23, max);
transpose_u16_4x4q(&t01, &t23);
d01 = vcombine_u16(vld1_u16(dst + 0 * dst_stride),
vld1_u16(dst + 2 * dst_stride));
d23 = vcombine_u16(vld1_u16(dst + 1 * dst_stride),
vld1_u16(dst + 3 * dst_stride));
d01 = vrhaddq_u16(d01, t01);
d23 = vrhaddq_u16(d23, t23);
vst1_u16(dst + 0 * dst_stride, vget_low_u16(d01));
vst1_u16(dst + 1 * dst_stride, vget_low_u16(d23));
vst1_u16(dst + 2 * dst_stride, vget_high_u16(d01));
vst1_u16(dst + 3 * dst_stride, vget_high_u16(d23));
s0 = s4;
s1 = s5;
s2 = s6;
s3 = s7;
s4 = s8;
s5 = s9;
s6 = s10;
src += 4;
dst += 4;
w -= 4;
} while (w > 0);
} else {
int16x8_t t4, t5, t6, t7;
int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
uint16x8_t d0, d1, d2, d3, t0, t1, t2, t3;
if (w == 4) {
do {
load_8x8((const int16_t *)src, src_stride, &s0, &s1, &s2, &s3, &s4,
&s5, &s6, &s7);
transpose_s16_8x8(&s0, &s1, &s2, &s3, &s4, &s5, &s6, &s7);
load_8x8((const int16_t *)(src + 7), src_stride, &s7, &s8, &s9, &s10,
&t4, &t5, &t6, &t7);
src += 8 * src_stride;
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
__builtin_prefetch(dst + 4 * dst_stride);
__builtin_prefetch(dst + 5 * dst_stride);
__builtin_prefetch(dst + 6 * dst_stride);
__builtin_prefetch(dst + 7 * dst_stride);
transpose_s16_8x8(&s7, &s8, &s9, &s10, &t4, &t5, &t6, &t7);
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
__builtin_prefetch(src + 4 * src_stride);
__builtin_prefetch(src + 5 * src_stride);
__builtin_prefetch(src + 6 * src_stride);
__builtin_prefetch(src + 7 * src_stride);
t0 = highbd_convolve8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters, max);
t1 = highbd_convolve8_8(s1, s2, s3, s4, s5, s6, s7, s8, filters, max);
t2 = highbd_convolve8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters, max);
t3 =
highbd_convolve8_8(s3, s4, s5, s6, s7, s8, s9, s10, filters, max);
transpose_u16_8x4(&t0, &t1, &t2, &t3);
d0 = vcombine_u16(vld1_u16(dst + 0 * dst_stride),
vld1_u16(dst + 4 * dst_stride));
d1 = vcombine_u16(vld1_u16(dst + 1 * dst_stride),
vld1_u16(dst + 5 * dst_stride));
d2 = vcombine_u16(vld1_u16(dst + 2 * dst_stride),
vld1_u16(dst + 6 * dst_stride));
d3 = vcombine_u16(vld1_u16(dst + 3 * dst_stride),
vld1_u16(dst + 7 * dst_stride));
d0 = vrhaddq_u16(d0, t0);
d1 = vrhaddq_u16(d1, t1);
d2 = vrhaddq_u16(d2, t2);
d3 = vrhaddq_u16(d3, t3);
vst1_u16(dst, vget_low_u16(d0));
dst += dst_stride;
vst1_u16(dst, vget_low_u16(d1));
dst += dst_stride;
vst1_u16(dst, vget_low_u16(d2));
dst += dst_stride;
vst1_u16(dst, vget_low_u16(d3));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d0));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d1));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d2));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d3));
dst += dst_stride;
h -= 8;
} while (h > 0);
} else {
int width;
const uint16_t *s;
uint16_t *d;
int16x8_t s11, s12, s13, s14;
uint16x8_t d4, d5, d6, d7;
do {
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
__builtin_prefetch(src + 4 * src_stride);
__builtin_prefetch(src + 5 * src_stride);
__builtin_prefetch(src + 6 * src_stride);
__builtin_prefetch(src + 7 * src_stride);
load_8x8((const int16_t *)src, src_stride, &s0, &s1, &s2, &s3, &s4,
&s5, &s6, &s7);
transpose_s16_8x8(&s0, &s1, &s2, &s3, &s4, &s5, &s6, &s7);
width = w;
s = src + 7;
d = dst;
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
__builtin_prefetch(dst + 4 * dst_stride);
__builtin_prefetch(dst + 5 * dst_stride);
__builtin_prefetch(dst + 6 * dst_stride);
__builtin_prefetch(dst + 7 * dst_stride);
do {
load_8x8((const int16_t *)s, src_stride, &s7, &s8, &s9, &s10, &s11,
&s12, &s13, &s14);
transpose_s16_8x8(&s7, &s8, &s9, &s10, &s11, &s12, &s13, &s14);
d0 = highbd_convolve8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters,
max);
d1 = highbd_convolve8_8(s1, s2, s3, s4, s5, s6, s7, s8, filters,
max);
d2 = highbd_convolve8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters,
max);
d3 = highbd_convolve8_8(s3, s4, s5, s6, s7, s8, s9, s10, filters,
max);
d4 = highbd_convolve8_8(s4, s5, s6, s7, s8, s9, s10, s11, filters,
max);
d5 = highbd_convolve8_8(s5, s6, s7, s8, s9, s10, s11, s12, filters,
max);
d6 = highbd_convolve8_8(s6, s7, s8, s9, s10, s11, s12, s13, filters,
max);
d7 = highbd_convolve8_8(s7, s8, s9, s10, s11, s12, s13, s14,
filters, max);
transpose_u16_8x8(&d0, &d1, &d2, &d3, &d4, &d5, &d6, &d7);
d0 = vrhaddq_u16(d0, vld1q_u16(d + 0 * dst_stride));
d1 = vrhaddq_u16(d1, vld1q_u16(d + 1 * dst_stride));
d2 = vrhaddq_u16(d2, vld1q_u16(d + 2 * dst_stride));
d3 = vrhaddq_u16(d3, vld1q_u16(d + 3 * dst_stride));
d4 = vrhaddq_u16(d4, vld1q_u16(d + 4 * dst_stride));
d5 = vrhaddq_u16(d5, vld1q_u16(d + 5 * dst_stride));
d6 = vrhaddq_u16(d6, vld1q_u16(d + 6 * dst_stride));
d7 = vrhaddq_u16(d7, vld1q_u16(d + 7 * dst_stride));
store_8x8(d, dst_stride, d0, d1, d2, d3, d4, d5, d6, d7);
s0 = s8;
s1 = s9;
s2 = s10;
s3 = s11;
s4 = s12;
s5 = s13;
s6 = s14;
s += 8;
d += 8;
width -= 8;
} while (width > 0);
src += 8 * src_stride;
dst += 8 * dst_stride;
h -= 8;
} while (h > 0);
}
}
}
}
void vpx_highbd_convolve8_vert_neon(const uint16_t *src, ptrdiff_t src_stride,
uint16_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4,
int w, int h, int bd) {
if (y_step_q4 != 16) {
vpx_highbd_convolve8_vert_c(src, src_stride, dst, dst_stride, filter, x0_q4,
x_step_q4, y0_q4, y_step_q4, w, h, bd);
} else {
const int16x8_t filters = vld1q_s16(filter[y0_q4]);
const uint16x8_t max = vdupq_n_u16((1 << bd) - 1);
assert(!((intptr_t)dst & 3));
assert(!(dst_stride & 3));
src -= 3 * src_stride;
if (w == 4) {
int16x4_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
int32x4_t d0, d1, d2, d3;
uint16x8_t d01, d23;
s0 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s1 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s2 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s3 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s4 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s5 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s6 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
do {
s7 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s8 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s9 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s10 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
d0 = highbd_convolve8_4(s0, s1, s2, s3, s4, s5, s6, s7, filters);
d1 = highbd_convolve8_4(s1, s2, s3, s4, s5, s6, s7, s8, filters);
d2 = highbd_convolve8_4(s2, s3, s4, s5, s6, s7, s8, s9, filters);
d3 = highbd_convolve8_4(s3, s4, s5, s6, s7, s8, s9, s10, filters);
d01 = vcombine_u16(vqrshrun_n_s32(d0, 7), vqrshrun_n_s32(d1, 7));
d23 = vcombine_u16(vqrshrun_n_s32(d2, 7), vqrshrun_n_s32(d3, 7));
d01 = vminq_u16(d01, max);
d23 = vminq_u16(d23, max);
vst1_u16(dst, vget_low_u16(d01));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d01));
dst += dst_stride;
vst1_u16(dst, vget_low_u16(d23));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d23));
dst += dst_stride;
s0 = s4;
s1 = s5;
s2 = s6;
s3 = s7;
s4 = s8;
s5 = s9;
s6 = s10;
h -= 4;
} while (h > 0);
} else {
int height;
const uint16_t *s;
uint16_t *d;
int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
uint16x8_t d0, d1, d2, d3;
do {
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
__builtin_prefetch(src + 4 * src_stride);
__builtin_prefetch(src + 5 * src_stride);
__builtin_prefetch(src + 6 * src_stride);
s = src;
s0 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s1 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s2 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s3 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s4 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s5 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s6 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
d = dst;
height = h;
do {
s7 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s8 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s9 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s10 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
__builtin_prefetch(d + 0 * dst_stride);
__builtin_prefetch(d + 1 * dst_stride);
__builtin_prefetch(d + 2 * dst_stride);
__builtin_prefetch(d + 3 * dst_stride);
__builtin_prefetch(s + 0 * src_stride);
__builtin_prefetch(s + 1 * src_stride);
__builtin_prefetch(s + 2 * src_stride);
__builtin_prefetch(s + 3 * src_stride);
d0 = highbd_convolve8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters, max);
d1 = highbd_convolve8_8(s1, s2, s3, s4, s5, s6, s7, s8, filters, max);
d2 = highbd_convolve8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters, max);
d3 =
highbd_convolve8_8(s3, s4, s5, s6, s7, s8, s9, s10, filters, max);
vst1q_u16(d, d0);
d += dst_stride;
vst1q_u16(d, d1);
d += dst_stride;
vst1q_u16(d, d2);
d += dst_stride;
vst1q_u16(d, d3);
d += dst_stride;
s0 = s4;
s1 = s5;
s2 = s6;
s3 = s7;
s4 = s8;
s5 = s9;
s6 = s10;
height -= 4;
} while (height > 0);
src += 8;
dst += 8;
w -= 8;
} while (w > 0);
}
}
}
void vpx_highbd_convolve8_avg_vert_neon(const uint16_t *src,
ptrdiff_t src_stride, uint16_t *dst,
ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4,
int w, int h, int bd) {
if (y_step_q4 != 16) {
vpx_highbd_convolve8_avg_vert_c(src, src_stride, dst, dst_stride, filter,
x0_q4, x_step_q4, y0_q4, y_step_q4, w, h,
bd);
} else {
const int16x8_t filters = vld1q_s16(filter[y0_q4]);
const uint16x8_t max = vdupq_n_u16((1 << bd) - 1);
assert(!((intptr_t)dst & 3));
assert(!(dst_stride & 3));
src -= 3 * src_stride;
if (w == 4) {
int16x4_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
int32x4_t d0, d1, d2, d3;
uint16x8_t d01, d23, t01, t23;
s0 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s1 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s2 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s3 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s4 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s5 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s6 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
do {
s7 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s8 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s9 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
s10 = vreinterpret_s16_u16(vld1_u16(src));
src += src_stride;
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
d0 = highbd_convolve8_4(s0, s1, s2, s3, s4, s5, s6, s7, filters);
d1 = highbd_convolve8_4(s1, s2, s3, s4, s5, s6, s7, s8, filters);
d2 = highbd_convolve8_4(s2, s3, s4, s5, s6, s7, s8, s9, filters);
d3 = highbd_convolve8_4(s3, s4, s5, s6, s7, s8, s9, s10, filters);
t01 = vcombine_u16(vqrshrun_n_s32(d0, 7), vqrshrun_n_s32(d1, 7));
t23 = vcombine_u16(vqrshrun_n_s32(d2, 7), vqrshrun_n_s32(d3, 7));
t01 = vminq_u16(t01, max);
t23 = vminq_u16(t23, max);
d01 = vcombine_u16(vld1_u16(dst + 0 * dst_stride),
vld1_u16(dst + 1 * dst_stride));
d23 = vcombine_u16(vld1_u16(dst + 2 * dst_stride),
vld1_u16(dst + 3 * dst_stride));
d01 = vrhaddq_u16(d01, t01);
d23 = vrhaddq_u16(d23, t23);
vst1_u16(dst, vget_low_u16(d01));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d01));
dst += dst_stride;
vst1_u16(dst, vget_low_u16(d23));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d23));
dst += dst_stride;
s0 = s4;
s1 = s5;
s2 = s6;
s3 = s7;
s4 = s8;
s5 = s9;
s6 = s10;
h -= 4;
} while (h > 0);
} else {
int height;
const uint16_t *s;
uint16_t *d;
int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
uint16x8_t d0, d1, d2, d3, t0, t1, t2, t3;
do {
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
__builtin_prefetch(src + 4 * src_stride);
__builtin_prefetch(src + 5 * src_stride);
__builtin_prefetch(src + 6 * src_stride);
s = src;
s0 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s1 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s2 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s3 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s4 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s5 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s6 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
d = dst;
height = h;
do {
s7 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s8 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s9 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
s10 = vreinterpretq_s16_u16(vld1q_u16(s));
s += src_stride;
__builtin_prefetch(d + 0 * dst_stride);
__builtin_prefetch(d + 1 * dst_stride);
__builtin_prefetch(d + 2 * dst_stride);
__builtin_prefetch(d + 3 * dst_stride);
__builtin_prefetch(s + 0 * src_stride);
__builtin_prefetch(s + 1 * src_stride);
__builtin_prefetch(s + 2 * src_stride);
__builtin_prefetch(s + 3 * src_stride);
t0 = highbd_convolve8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters, max);
t1 = highbd_convolve8_8(s1, s2, s3, s4, s5, s6, s7, s8, filters, max);
t2 = highbd_convolve8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters, max);
t3 =
highbd_convolve8_8(s3, s4, s5, s6, s7, s8, s9, s10, filters, max);
d0 = vld1q_u16(d + 0 * dst_stride);
d1 = vld1q_u16(d + 1 * dst_stride);
d2 = vld1q_u16(d + 2 * dst_stride);
d3 = vld1q_u16(d + 3 * dst_stride);
d0 = vrhaddq_u16(d0, t0);
d1 = vrhaddq_u16(d1, t1);
d2 = vrhaddq_u16(d2, t2);
d3 = vrhaddq_u16(d3, t3);
vst1q_u16(d, d0);
d += dst_stride;
vst1q_u16(d, d1);
d += dst_stride;
vst1q_u16(d, d2);
d += dst_stride;
vst1q_u16(d, d3);
d += dst_stride;
s0 = s4;
s1 = s5;
s2 = s6;
s3 = s7;
s4 = s8;
s5 = s9;
s6 = s10;
height -= 4;
} while (height > 0);
src += 8;
dst += 8;
w -= 8;
} while (w > 0);
}
}
}
@@ -0,0 +1,183 @@
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
void vpx_highbd_convolve_avg_neon(const uint16_t *src, ptrdiff_t src_stride,
uint16_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4,
int w, int h, int bd) {
(void)filter;
(void)x0_q4;
(void)x_step_q4;
(void)y0_q4;
(void)y_step_q4;
(void)bd;
if (w < 8) { // avg4
uint16x4_t s0, s1, d0, d1;
uint16x8_t s01, d01;
do {
s0 = vld1_u16(src);
d0 = vld1_u16(dst);
src += src_stride;
s1 = vld1_u16(src);
d1 = vld1_u16(dst + dst_stride);
src += src_stride;
s01 = vcombine_u16(s0, s1);
d01 = vcombine_u16(d0, d1);
d01 = vrhaddq_u16(s01, d01);
vst1_u16(dst, vget_low_u16(d01));
dst += dst_stride;
vst1_u16(dst, vget_high_u16(d01));
dst += dst_stride;
h -= 2;
} while (h > 0);
} else if (w == 8) { // avg8
uint16x8_t s0, s1, d0, d1;
do {
s0 = vld1q_u16(src);
d0 = vld1q_u16(dst);
src += src_stride;
s1 = vld1q_u16(src);
d1 = vld1q_u16(dst + dst_stride);
src += src_stride;
d0 = vrhaddq_u16(s0, d0);
d1 = vrhaddq_u16(s1, d1);
vst1q_u16(dst, d0);
dst += dst_stride;
vst1q_u16(dst, d1);
dst += dst_stride;
h -= 2;
} while (h > 0);
} else if (w < 32) { // avg16
uint16x8_t s0l, s0h, s1l, s1h, d0l, d0h, d1l, d1h;
do {
s0l = vld1q_u16(src);
s0h = vld1q_u16(src + 8);
d0l = vld1q_u16(dst);
d0h = vld1q_u16(dst + 8);
src += src_stride;
s1l = vld1q_u16(src);
s1h = vld1q_u16(src + 8);
d1l = vld1q_u16(dst + dst_stride);
d1h = vld1q_u16(dst + dst_stride + 8);
src += src_stride;
d0l = vrhaddq_u16(s0l, d0l);
d0h = vrhaddq_u16(s0h, d0h);
d1l = vrhaddq_u16(s1l, d1l);
d1h = vrhaddq_u16(s1h, d1h);
vst1q_u16(dst, d0l);
vst1q_u16(dst + 8, d0h);
dst += dst_stride;
vst1q_u16(dst, d1l);
vst1q_u16(dst + 8, d1h);
dst += dst_stride;
h -= 2;
} while (h > 0);
} else if (w == 32) { // avg32
uint16x8_t s0, s1, s2, s3, d0, d1, d2, d3;
do {
s0 = vld1q_u16(src);
s1 = vld1q_u16(src + 8);
s2 = vld1q_u16(src + 16);
s3 = vld1q_u16(src + 24);
d0 = vld1q_u16(dst);
d1 = vld1q_u16(dst + 8);
d2 = vld1q_u16(dst + 16);
d3 = vld1q_u16(dst + 24);
src += src_stride;
d0 = vrhaddq_u16(s0, d0);
d1 = vrhaddq_u16(s1, d1);
d2 = vrhaddq_u16(s2, d2);
d3 = vrhaddq_u16(s3, d3);
vst1q_u16(dst, d0);
vst1q_u16(dst + 8, d1);
vst1q_u16(dst + 16, d2);
vst1q_u16(dst + 24, d3);
dst += dst_stride;
s0 = vld1q_u16(src);
s1 = vld1q_u16(src + 8);
s2 = vld1q_u16(src + 16);
s3 = vld1q_u16(src + 24);
d0 = vld1q_u16(dst);
d1 = vld1q_u16(dst + 8);
d2 = vld1q_u16(dst + 16);
d3 = vld1q_u16(dst + 24);
src += src_stride;
d0 = vrhaddq_u16(s0, d0);
d1 = vrhaddq_u16(s1, d1);
d2 = vrhaddq_u16(s2, d2);
d3 = vrhaddq_u16(s3, d3);
vst1q_u16(dst, d0);
vst1q_u16(dst + 8, d1);
vst1q_u16(dst + 16, d2);
vst1q_u16(dst + 24, d3);
dst += dst_stride;
h -= 2;
} while (h > 0);
} else { // avg64
uint16x8_t s0, s1, s2, s3, d0, d1, d2, d3;
do {
s0 = vld1q_u16(src);
s1 = vld1q_u16(src + 8);
s2 = vld1q_u16(src + 16);
s3 = vld1q_u16(src + 24);
d0 = vld1q_u16(dst);
d1 = vld1q_u16(dst + 8);
d2 = vld1q_u16(dst + 16);
d3 = vld1q_u16(dst + 24);
d0 = vrhaddq_u16(s0, d0);
d1 = vrhaddq_u16(s1, d1);
d2 = vrhaddq_u16(s2, d2);
d3 = vrhaddq_u16(s3, d3);
vst1q_u16(dst, d0);
vst1q_u16(dst + 8, d1);
vst1q_u16(dst + 16, d2);
vst1q_u16(dst + 24, d3);
s0 = vld1q_u16(src + 32);
s1 = vld1q_u16(src + 40);
s2 = vld1q_u16(src + 48);
s3 = vld1q_u16(src + 56);
d0 = vld1q_u16(dst + 32);
d1 = vld1q_u16(dst + 40);
d2 = vld1q_u16(dst + 48);
d3 = vld1q_u16(dst + 56);
d0 = vrhaddq_u16(s0, d0);
d1 = vrhaddq_u16(s1, d1);
d2 = vrhaddq_u16(s2, d2);
d3 = vrhaddq_u16(s3, d3);
vst1q_u16(dst + 32, d0);
vst1q_u16(dst + 40, d1);
vst1q_u16(dst + 48, d2);
vst1q_u16(dst + 56, d3);
src += src_stride;
dst += dst_stride;
} while (--h);
}
}
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
void vpx_highbd_convolve_copy_neon(const uint16_t *src, ptrdiff_t src_stride,
uint16_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4,
int w, int h, int bd) {
(void)filter;
(void)x0_q4;
(void)x_step_q4;
(void)y0_q4;
(void)y_step_q4;
(void)bd;
if (w < 8) { // copy4
do {
vst1_u16(dst, vld1_u16(src));
src += src_stride;
dst += dst_stride;
vst1_u16(dst, vld1_u16(src));
src += src_stride;
dst += dst_stride;
h -= 2;
} while (h > 0);
} else if (w == 8) { // copy8
do {
vst1q_u16(dst, vld1q_u16(src));
src += src_stride;
dst += dst_stride;
vst1q_u16(dst, vld1q_u16(src));
src += src_stride;
dst += dst_stride;
h -= 2;
} while (h > 0);
} else if (w < 32) { // copy16
do {
vst2q_u16(dst, vld2q_u16(src));
src += src_stride;
dst += dst_stride;
vst2q_u16(dst, vld2q_u16(src));
src += src_stride;
dst += dst_stride;
vst2q_u16(dst, vld2q_u16(src));
src += src_stride;
dst += dst_stride;
vst2q_u16(dst, vld2q_u16(src));
src += src_stride;
dst += dst_stride;
h -= 4;
} while (h > 0);
} else if (w == 32) { // copy32
do {
vst4q_u16(dst, vld4q_u16(src));
src += src_stride;
dst += dst_stride;
vst4q_u16(dst, vld4q_u16(src));
src += src_stride;
dst += dst_stride;
vst4q_u16(dst, vld4q_u16(src));
src += src_stride;
dst += dst_stride;
vst4q_u16(dst, vld4q_u16(src));
src += src_stride;
dst += dst_stride;
h -= 4;
} while (h > 0);
} else { // copy64
do {
vst4q_u16(dst, vld4q_u16(src));
vst4q_u16(dst + 32, vld4q_u16(src + 32));
src += src_stride;
dst += dst_stride;
vst4q_u16(dst, vld4q_u16(src));
vst4q_u16(dst + 32, vld4q_u16(src + 32));
src += src_stride;
dst += dst_stride;
vst4q_u16(dst, vld4q_u16(src));
vst4q_u16(dst + 32, vld4q_u16(src + 32));
src += src_stride;
dst += dst_stride;
vst4q_u16(dst, vld4q_u16(src));
vst4q_u16(dst + 32, vld4q_u16(src + 32));
src += src_stride;
dst += dst_stride;
h -= 4;
} while (h > 0);
}
}
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/vpx_dsp_common.h"
#include "vpx_dsp/vpx_filter.h"
#include "vpx_ports/mem.h"
void vpx_highbd_convolve8_neon(const uint16_t *src, ptrdiff_t src_stride,
uint16_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4, int w,
int h, int bd) {
// + 1 to make it divisible by 4
uint16_t temp[64 * 136];
const int intermediate_height =
(((h - 1) * y_step_q4 + y0_q4) >> SUBPEL_BITS) + SUBPEL_TAPS;
/* Filter starting 3 lines back. The neon implementation will ignore the given
* height and filter a multiple of 4 lines. Since this goes in to the temp
* buffer which has lots of extra room and is subsequently discarded this is
* safe if somewhat less than ideal. */
vpx_highbd_convolve8_horiz_neon(src - src_stride * 3, src_stride, temp, w,
filter, x0_q4, x_step_q4, y0_q4, y_step_q4, w,
intermediate_height, bd);
/* Step into the temp buffer 3 lines to get the actual frame data */
vpx_highbd_convolve8_vert_neon(temp + w * 3, w, dst, dst_stride, filter,
x0_q4, x_step_q4, y0_q4, y_step_q4, w, h, bd);
}
void vpx_highbd_convolve8_avg_neon(const uint16_t *src, ptrdiff_t src_stride,
uint16_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4,
int w, int h, int bd) {
// + 1 to make it divisible by 4
uint16_t temp[64 * 136];
const int intermediate_height =
(((h - 1) * y_step_q4 + y0_q4) >> SUBPEL_BITS) + SUBPEL_TAPS;
/* This implementation has the same issues as above. In addition, we only want
* to average the values after both passes.
*/
vpx_highbd_convolve8_horiz_neon(src - src_stride * 3, src_stride, temp, w,
filter, x0_q4, x_step_q4, y0_q4, y_step_q4, w,
intermediate_height, bd);
vpx_highbd_convolve8_avg_vert_neon(temp + w * 3, w, dst, dst_stride, filter,
x0_q4, x_step_q4, y0_q4, y_step_q4, w, h,
bd);
}
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/inv_txfm.h"
static INLINE void idct16x16_1_add_pos_kernel(uint8_t **dest, const int stride,
const uint8x16_t res) {
const uint8x16_t a = vld1q_u8(*dest);
const uint8x16_t b = vqaddq_u8(a, res);
vst1q_u8(*dest, b);
*dest += stride;
}
static INLINE void idct16x16_1_add_neg_kernel(uint8_t **dest, const int stride,
const uint8x16_t res) {
const uint8x16_t a = vld1q_u8(*dest);
const uint8x16_t b = vqsubq_u8(a, res);
vst1q_u8(*dest, b);
*dest += stride;
}
void vpx_idct16x16_1_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
const int16_t out0 =
WRAPLOW(dct_const_round_shift((int16_t)input[0] * cospi_16_64));
const int16_t out1 = WRAPLOW(dct_const_round_shift(out0 * cospi_16_64));
const int16_t a1 = ROUND_POWER_OF_TWO(out1, 6);
if (a1 >= 0) {
const uint8x16_t dc = create_dcq(a1);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
idct16x16_1_add_pos_kernel(&dest, stride, dc);
} else {
const uint8x16_t dc = create_dcq(-a1);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
idct16x16_1_add_neg_kernel(&dest, stride, dc);
}
}
@@ -0,0 +1,764 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/txfm_common.h"
static INLINE void wrap_low_4x2(const int32x4_t *const t32, int16x4_t *const d0,
int16x4_t *const d1) {
*d0 = vrshrn_n_s32(t32[0], DCT_CONST_BITS);
*d1 = vrshrn_n_s32(t32[1], DCT_CONST_BITS);
}
static INLINE void idct_cospi_8_24_d_kernel(const int16x4_t s0,
const int16x4_t s1,
const int16x4_t cospi_0_8_16_24,
int32x4_t *const t32) {
t32[0] = vmull_lane_s16(s0, cospi_0_8_16_24, 3);
t32[1] = vmull_lane_s16(s1, cospi_0_8_16_24, 3);
t32[0] = vmlsl_lane_s16(t32[0], s1, cospi_0_8_16_24, 1);
t32[1] = vmlal_lane_s16(t32[1], s0, cospi_0_8_16_24, 1);
}
static INLINE void idct_cospi_8_24_d(const int16x4_t s0, const int16x4_t s1,
const int16x4_t cospi_0_8_16_24,
int16x4_t *const d0, int16x4_t *const d1) {
int32x4_t t32[2];
idct_cospi_8_24_d_kernel(s0, s1, cospi_0_8_16_24, t32);
wrap_low_4x2(t32, d0, d1);
}
static INLINE void idct_cospi_8_24_neg_d(const int16x4_t s0, const int16x4_t s1,
const int16x4_t cospi_0_8_16_24,
int16x4_t *const d0,
int16x4_t *const d1) {
int32x4_t t32[2];
idct_cospi_8_24_d_kernel(s0, s1, cospi_0_8_16_24, t32);
t32[1] = vnegq_s32(t32[1]);
wrap_low_4x2(t32, d0, d1);
}
static INLINE void idct_cospi_16_16_d(const int16x4_t s0, const int16x4_t s1,
const int16x4_t cospi_0_8_16_24,
int16x4_t *const d0,
int16x4_t *const d1) {
int32x4_t t32[3];
t32[2] = vmull_lane_s16(s1, cospi_0_8_16_24, 2);
t32[0] = vmlsl_lane_s16(t32[2], s0, cospi_0_8_16_24, 2);
t32[1] = vmlal_lane_s16(t32[2], s0, cospi_0_8_16_24, 2);
wrap_low_4x2(t32, d0, d1);
}
void vpx_idct16x16_256_add_half1d(const void *const input, int16_t *output,
void *const dest, const int stride,
const int highbd_flag) {
const int16x8_t cospis0 = vld1q_s16(kCospi);
const int16x8_t cospis1 = vld1q_s16(kCospi + 8);
const int16x4_t cospi_0_8_16_24 = vget_low_s16(cospis0);
const int16x4_t cospi_4_12_20N_28 = vget_high_s16(cospis0);
const int16x4_t cospi_2_30_10_22 = vget_low_s16(cospis1);
const int16x4_t cospi_6_26N_14_18N = vget_high_s16(cospis1);
int16x8_t in[16], step1[16], step2[16], out[16];
// Load input (16x8)
if (output) {
const tran_low_t *inputT = (const tran_low_t *)input;
in[0] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[8] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[1] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[9] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[2] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[10] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[3] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[11] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[4] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[12] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[5] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[13] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[6] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[14] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[7] = load_tran_low_to_s16q(inputT);
inputT += 8;
in[15] = load_tran_low_to_s16q(inputT);
} else {
const int16_t *inputT = (const int16_t *)input;
in[0] = vld1q_s16(inputT);
inputT += 8;
in[8] = vld1q_s16(inputT);
inputT += 8;
in[1] = vld1q_s16(inputT);
inputT += 8;
in[9] = vld1q_s16(inputT);
inputT += 8;
in[2] = vld1q_s16(inputT);
inputT += 8;
in[10] = vld1q_s16(inputT);
inputT += 8;
in[3] = vld1q_s16(inputT);
inputT += 8;
in[11] = vld1q_s16(inputT);
inputT += 8;
in[4] = vld1q_s16(inputT);
inputT += 8;
in[12] = vld1q_s16(inputT);
inputT += 8;
in[5] = vld1q_s16(inputT);
inputT += 8;
in[13] = vld1q_s16(inputT);
inputT += 8;
in[6] = vld1q_s16(inputT);
inputT += 8;
in[14] = vld1q_s16(inputT);
inputT += 8;
in[7] = vld1q_s16(inputT);
inputT += 8;
in[15] = vld1q_s16(inputT);
}
// Transpose
transpose_s16_8x8(&in[0], &in[1], &in[2], &in[3], &in[4], &in[5], &in[6],
&in[7]);
transpose_s16_8x8(&in[8], &in[9], &in[10], &in[11], &in[12], &in[13], &in[14],
&in[15]);
// stage 1
step1[0] = in[0 / 2];
step1[1] = in[16 / 2];
step1[2] = in[8 / 2];
step1[3] = in[24 / 2];
step1[4] = in[4 / 2];
step1[5] = in[20 / 2];
step1[6] = in[12 / 2];
step1[7] = in[28 / 2];
step1[8] = in[2 / 2];
step1[9] = in[18 / 2];
step1[10] = in[10 / 2];
step1[11] = in[26 / 2];
step1[12] = in[6 / 2];
step1[13] = in[22 / 2];
step1[14] = in[14 / 2];
step1[15] = in[30 / 2];
// stage 2
step2[0] = step1[0];
step2[1] = step1[1];
step2[2] = step1[2];
step2[3] = step1[3];
step2[4] = step1[4];
step2[5] = step1[5];
step2[6] = step1[6];
step2[7] = step1[7];
idct_cospi_2_30(step1[8], step1[15], cospi_2_30_10_22, &step2[8], &step2[15]);
idct_cospi_14_18(step1[9], step1[14], cospi_6_26N_14_18N, &step2[9],
&step2[14]);
idct_cospi_10_22(step1[10], step1[13], cospi_2_30_10_22, &step2[10],
&step2[13]);
idct_cospi_6_26(step1[11], step1[12], cospi_6_26N_14_18N, &step2[11],
&step2[12]);
// stage 3
step1[0] = step2[0];
step1[1] = step2[1];
step1[2] = step2[2];
step1[3] = step2[3];
idct_cospi_4_28(step2[4], step2[7], cospi_4_12_20N_28, &step1[4], &step1[7]);
idct_cospi_12_20(step2[5], step2[6], cospi_4_12_20N_28, &step1[5], &step1[6]);
step1[8] = vaddq_s16(step2[8], step2[9]);
step1[9] = vsubq_s16(step2[8], step2[9]);
step1[10] = vsubq_s16(step2[11], step2[10]);
step1[11] = vaddq_s16(step2[11], step2[10]);
step1[12] = vaddq_s16(step2[12], step2[13]);
step1[13] = vsubq_s16(step2[12], step2[13]);
step1[14] = vsubq_s16(step2[15], step2[14]);
step1[15] = vaddq_s16(step2[15], step2[14]);
// stage 4
idct_cospi_16_16_q(step1[1], step1[0], cospi_0_8_16_24, &step2[1], &step2[0]);
idct_cospi_8_24_q(step1[2], step1[3], cospi_0_8_16_24, &step2[2], &step2[3]);
step2[4] = vaddq_s16(step1[4], step1[5]);
step2[5] = vsubq_s16(step1[4], step1[5]);
step2[6] = vsubq_s16(step1[7], step1[6]);
step2[7] = vaddq_s16(step1[7], step1[6]);
step2[8] = step1[8];
idct_cospi_8_24_q(step1[14], step1[9], cospi_0_8_16_24, &step2[9],
&step2[14]);
idct_cospi_8_24_neg_q(step1[13], step1[10], cospi_0_8_16_24, &step2[13],
&step2[10]);
step2[11] = step1[11];
step2[12] = step1[12];
step2[15] = step1[15];
// stage 5
step1[0] = vaddq_s16(step2[0], step2[3]);
step1[1] = vaddq_s16(step2[1], step2[2]);
step1[2] = vsubq_s16(step2[1], step2[2]);
step1[3] = vsubq_s16(step2[0], step2[3]);
step1[4] = step2[4];
idct_cospi_16_16_q(step2[5], step2[6], cospi_0_8_16_24, &step1[5], &step1[6]);
step1[7] = step2[7];
step1[8] = vaddq_s16(step2[8], step2[11]);
step1[9] = vaddq_s16(step2[9], step2[10]);
step1[10] = vsubq_s16(step2[9], step2[10]);
step1[11] = vsubq_s16(step2[8], step2[11]);
step1[12] = vsubq_s16(step2[15], step2[12]);
step1[13] = vsubq_s16(step2[14], step2[13]);
step1[14] = vaddq_s16(step2[14], step2[13]);
step1[15] = vaddq_s16(step2[15], step2[12]);
// stage 6
step2[0] = vaddq_s16(step1[0], step1[7]);
step2[1] = vaddq_s16(step1[1], step1[6]);
step2[2] = vaddq_s16(step1[2], step1[5]);
step2[3] = vaddq_s16(step1[3], step1[4]);
step2[4] = vsubq_s16(step1[3], step1[4]);
step2[5] = vsubq_s16(step1[2], step1[5]);
step2[6] = vsubq_s16(step1[1], step1[6]);
step2[7] = vsubq_s16(step1[0], step1[7]);
idct_cospi_16_16_q(step1[10], step1[13], cospi_0_8_16_24, &step2[10],
&step2[13]);
idct_cospi_16_16_q(step1[11], step1[12], cospi_0_8_16_24, &step2[11],
&step2[12]);
step2[8] = step1[8];
step2[9] = step1[9];
step2[14] = step1[14];
step2[15] = step1[15];
// stage 7
idct16x16_add_stage7(step2, out);
if (output) {
idct16x16_store_pass1(out, output);
} else {
if (highbd_flag) {
idct16x16_add_store_bd8(out, dest, stride);
} else {
idct16x16_add_store(out, dest, stride);
}
}
}
void vpx_idct16x16_38_add_half1d(const void *const input, int16_t *const output,
void *const dest, const int stride,
const int highbd_flag) {
const int16x8_t cospis0 = vld1q_s16(kCospi);
const int16x8_t cospis1 = vld1q_s16(kCospi + 8);
const int16x8_t cospisd0 = vaddq_s16(cospis0, cospis0);
const int16x8_t cospisd1 = vaddq_s16(cospis1, cospis1);
const int16x4_t cospi_0_8_16_24 = vget_low_s16(cospis0);
const int16x4_t cospid_0_8_16_24 = vget_low_s16(cospisd0);
const int16x4_t cospid_4_12_20N_28 = vget_high_s16(cospisd0);
const int16x4_t cospid_2_30_10_22 = vget_low_s16(cospisd1);
const int16x4_t cospid_6_26_14_18N = vget_high_s16(cospisd1);
int16x8_t in[8], step1[16], step2[16], out[16];
// Load input (8x8)
if (output) {
const tran_low_t *inputT = (const tran_low_t *)input;
in[0] = load_tran_low_to_s16q(inputT);
inputT += 16;
in[1] = load_tran_low_to_s16q(inputT);
inputT += 16;
in[2] = load_tran_low_to_s16q(inputT);
inputT += 16;
in[3] = load_tran_low_to_s16q(inputT);
inputT += 16;
in[4] = load_tran_low_to_s16q(inputT);
inputT += 16;
in[5] = load_tran_low_to_s16q(inputT);
inputT += 16;
in[6] = load_tran_low_to_s16q(inputT);
inputT += 16;
in[7] = load_tran_low_to_s16q(inputT);
} else {
const int16_t *inputT = (const int16_t *)input;
in[0] = vld1q_s16(inputT);
inputT += 16;
in[1] = vld1q_s16(inputT);
inputT += 16;
in[2] = vld1q_s16(inputT);
inputT += 16;
in[3] = vld1q_s16(inputT);
inputT += 16;
in[4] = vld1q_s16(inputT);
inputT += 16;
in[5] = vld1q_s16(inputT);
inputT += 16;
in[6] = vld1q_s16(inputT);
inputT += 16;
in[7] = vld1q_s16(inputT);
}
// Transpose
transpose_s16_8x8(&in[0], &in[1], &in[2], &in[3], &in[4], &in[5], &in[6],
&in[7]);
// stage 1
step1[0] = in[0 / 2];
step1[2] = in[8 / 2];
step1[4] = in[4 / 2];
step1[6] = in[12 / 2];
step1[8] = in[2 / 2];
step1[10] = in[10 / 2];
step1[12] = in[6 / 2];
step1[14] = in[14 / 2]; // 0 in pass 1
// stage 2
step2[0] = step1[0];
step2[2] = step1[2];
step2[4] = step1[4];
step2[6] = step1[6];
step2[8] = vqrdmulhq_lane_s16(step1[8], cospid_2_30_10_22, 1);
step2[9] = vqrdmulhq_lane_s16(step1[14], cospid_6_26_14_18N, 3);
step2[10] = vqrdmulhq_lane_s16(step1[10], cospid_2_30_10_22, 3);
step2[11] = vqrdmulhq_lane_s16(step1[12], cospid_6_26_14_18N, 1);
step2[12] = vqrdmulhq_lane_s16(step1[12], cospid_6_26_14_18N, 0);
step2[13] = vqrdmulhq_lane_s16(step1[10], cospid_2_30_10_22, 2);
step2[14] = vqrdmulhq_lane_s16(step1[14], cospid_6_26_14_18N, 2);
step2[15] = vqrdmulhq_lane_s16(step1[8], cospid_2_30_10_22, 0);
// stage 3
step1[0] = step2[0];
step1[2] = step2[2];
step1[4] = vqrdmulhq_lane_s16(step2[4], cospid_4_12_20N_28, 3);
step1[5] = vqrdmulhq_lane_s16(step2[6], cospid_4_12_20N_28, 2);
step1[6] = vqrdmulhq_lane_s16(step2[6], cospid_4_12_20N_28, 1);
step1[7] = vqrdmulhq_lane_s16(step2[4], cospid_4_12_20N_28, 0);
step1[8] = vaddq_s16(step2[8], step2[9]);
step1[9] = vsubq_s16(step2[8], step2[9]);
step1[10] = vsubq_s16(step2[11], step2[10]);
step1[11] = vaddq_s16(step2[11], step2[10]);
step1[12] = vaddq_s16(step2[12], step2[13]);
step1[13] = vsubq_s16(step2[12], step2[13]);
step1[14] = vsubq_s16(step2[15], step2[14]);
step1[15] = vaddq_s16(step2[15], step2[14]);
// stage 4
step2[0] = step2[1] = vqrdmulhq_lane_s16(step1[0], cospid_0_8_16_24, 2);
step2[2] = vqrdmulhq_lane_s16(step1[2], cospid_0_8_16_24, 3);
step2[3] = vqrdmulhq_lane_s16(step1[2], cospid_0_8_16_24, 1);
step2[4] = vaddq_s16(step1[4], step1[5]);
step2[5] = vsubq_s16(step1[4], step1[5]);
step2[6] = vsubq_s16(step1[7], step1[6]);
step2[7] = vaddq_s16(step1[7], step1[6]);
step2[8] = step1[8];
idct_cospi_8_24_q(step1[14], step1[9], cospi_0_8_16_24, &step2[9],
&step2[14]);
idct_cospi_8_24_neg_q(step1[13], step1[10], cospi_0_8_16_24, &step2[13],
&step2[10]);
step2[11] = step1[11];
step2[12] = step1[12];
step2[15] = step1[15];
// stage 5
step1[0] = vaddq_s16(step2[0], step2[3]);
step1[1] = vaddq_s16(step2[1], step2[2]);
step1[2] = vsubq_s16(step2[1], step2[2]);
step1[3] = vsubq_s16(step2[0], step2[3]);
step1[4] = step2[4];
idct_cospi_16_16_q(step2[5], step2[6], cospi_0_8_16_24, &step1[5], &step1[6]);
step1[7] = step2[7];
step1[8] = vaddq_s16(step2[8], step2[11]);
step1[9] = vaddq_s16(step2[9], step2[10]);
step1[10] = vsubq_s16(step2[9], step2[10]);
step1[11] = vsubq_s16(step2[8], step2[11]);
step1[12] = vsubq_s16(step2[15], step2[12]);
step1[13] = vsubq_s16(step2[14], step2[13]);
step1[14] = vaddq_s16(step2[14], step2[13]);
step1[15] = vaddq_s16(step2[15], step2[12]);
// stage 6
step2[0] = vaddq_s16(step1[0], step1[7]);
step2[1] = vaddq_s16(step1[1], step1[6]);
step2[2] = vaddq_s16(step1[2], step1[5]);
step2[3] = vaddq_s16(step1[3], step1[4]);
step2[4] = vsubq_s16(step1[3], step1[4]);
step2[5] = vsubq_s16(step1[2], step1[5]);
step2[6] = vsubq_s16(step1[1], step1[6]);
step2[7] = vsubq_s16(step1[0], step1[7]);
idct_cospi_16_16_q(step1[10], step1[13], cospi_0_8_16_24, &step2[10],
&step2[13]);
idct_cospi_16_16_q(step1[11], step1[12], cospi_0_8_16_24, &step2[11],
&step2[12]);
step2[8] = step1[8];
step2[9] = step1[9];
step2[14] = step1[14];
step2[15] = step1[15];
// stage 7
idct16x16_add_stage7(step2, out);
if (output) {
idct16x16_store_pass1(out, output);
} else {
if (highbd_flag) {
idct16x16_add_store_bd8(out, dest, stride);
} else {
idct16x16_add_store(out, dest, stride);
}
}
}
void vpx_idct16x16_10_add_half1d_pass1(const tran_low_t *input,
int16_t *output) {
const int16x8_t cospis0 = vld1q_s16(kCospi);
const int16x8_t cospis1 = vld1q_s16(kCospi + 8);
const int16x8_t cospisd0 = vaddq_s16(cospis0, cospis0);
const int16x8_t cospisd1 = vaddq_s16(cospis1, cospis1);
const int16x4_t cospi_0_8_16_24 = vget_low_s16(cospis0);
const int16x4_t cospid_0_8_16_24 = vget_low_s16(cospisd0);
const int16x4_t cospid_4_12_20N_28 = vget_high_s16(cospisd0);
const int16x4_t cospid_2_30_10_22 = vget_low_s16(cospisd1);
const int16x4_t cospid_6_26_14_18N = vget_high_s16(cospisd1);
int16x4_t in[4], step1[16], step2[16], out[16];
// Load input (4x4)
in[0] = load_tran_low_to_s16d(input);
input += 16;
in[1] = load_tran_low_to_s16d(input);
input += 16;
in[2] = load_tran_low_to_s16d(input);
input += 16;
in[3] = load_tran_low_to_s16d(input);
// Transpose
transpose_s16_4x4d(&in[0], &in[1], &in[2], &in[3]);
// stage 1
step1[0] = in[0 / 2];
step1[4] = in[4 / 2];
step1[8] = in[2 / 2];
step1[12] = in[6 / 2];
// stage 2
step2[0] = step1[0];
step2[4] = step1[4];
step2[8] = vqrdmulh_lane_s16(step1[8], cospid_2_30_10_22, 1);
step2[11] = vqrdmulh_lane_s16(step1[12], cospid_6_26_14_18N, 1);
step2[12] = vqrdmulh_lane_s16(step1[12], cospid_6_26_14_18N, 0);
step2[15] = vqrdmulh_lane_s16(step1[8], cospid_2_30_10_22, 0);
// stage 3
step1[0] = step2[0];
step1[4] = vqrdmulh_lane_s16(step2[4], cospid_4_12_20N_28, 3);
step1[7] = vqrdmulh_lane_s16(step2[4], cospid_4_12_20N_28, 0);
step1[8] = step2[8];
step1[9] = step2[8];
step1[10] = step2[11];
step1[11] = step2[11];
step1[12] = step2[12];
step1[13] = step2[12];
step1[14] = step2[15];
step1[15] = step2[15];
// stage 4
step2[0] = step2[1] = vqrdmulh_lane_s16(step1[0], cospid_0_8_16_24, 2);
step2[4] = step1[4];
step2[5] = step1[4];
step2[6] = step1[7];
step2[7] = step1[7];
step2[8] = step1[8];
idct_cospi_8_24_d(step1[14], step1[9], cospi_0_8_16_24, &step2[9],
&step2[14]);
idct_cospi_8_24_neg_d(step1[13], step1[10], cospi_0_8_16_24, &step2[13],
&step2[10]);
step2[11] = step1[11];
step2[12] = step1[12];
step2[15] = step1[15];
// stage 5
step1[0] = step2[0];
step1[1] = step2[1];
step1[2] = step2[1];
step1[3] = step2[0];
step1[4] = step2[4];
idct_cospi_16_16_d(step2[5], step2[6], cospi_0_8_16_24, &step1[5], &step1[6]);
step1[7] = step2[7];
step1[8] = vadd_s16(step2[8], step2[11]);
step1[9] = vadd_s16(step2[9], step2[10]);
step1[10] = vsub_s16(step2[9], step2[10]);
step1[11] = vsub_s16(step2[8], step2[11]);
step1[12] = vsub_s16(step2[15], step2[12]);
step1[13] = vsub_s16(step2[14], step2[13]);
step1[14] = vadd_s16(step2[14], step2[13]);
step1[15] = vadd_s16(step2[15], step2[12]);
// stage 6
step2[0] = vadd_s16(step1[0], step1[7]);
step2[1] = vadd_s16(step1[1], step1[6]);
step2[2] = vadd_s16(step1[2], step1[5]);
step2[3] = vadd_s16(step1[3], step1[4]);
step2[4] = vsub_s16(step1[3], step1[4]);
step2[5] = vsub_s16(step1[2], step1[5]);
step2[6] = vsub_s16(step1[1], step1[6]);
step2[7] = vsub_s16(step1[0], step1[7]);
idct_cospi_16_16_d(step1[10], step1[13], cospi_0_8_16_24, &step2[10],
&step2[13]);
idct_cospi_16_16_d(step1[11], step1[12], cospi_0_8_16_24, &step2[11],
&step2[12]);
step2[8] = step1[8];
step2[9] = step1[9];
step2[14] = step1[14];
step2[15] = step1[15];
// stage 7
out[0] = vadd_s16(step2[0], step2[15]);
out[1] = vadd_s16(step2[1], step2[14]);
out[2] = vadd_s16(step2[2], step2[13]);
out[3] = vadd_s16(step2[3], step2[12]);
out[4] = vadd_s16(step2[4], step2[11]);
out[5] = vadd_s16(step2[5], step2[10]);
out[6] = vadd_s16(step2[6], step2[9]);
out[7] = vadd_s16(step2[7], step2[8]);
out[8] = vsub_s16(step2[7], step2[8]);
out[9] = vsub_s16(step2[6], step2[9]);
out[10] = vsub_s16(step2[5], step2[10]);
out[11] = vsub_s16(step2[4], step2[11]);
out[12] = vsub_s16(step2[3], step2[12]);
out[13] = vsub_s16(step2[2], step2[13]);
out[14] = vsub_s16(step2[1], step2[14]);
out[15] = vsub_s16(step2[0], step2[15]);
// pass 1: save the result into output
vst1_s16(output, out[0]);
output += 4;
vst1_s16(output, out[1]);
output += 4;
vst1_s16(output, out[2]);
output += 4;
vst1_s16(output, out[3]);
output += 4;
vst1_s16(output, out[4]);
output += 4;
vst1_s16(output, out[5]);
output += 4;
vst1_s16(output, out[6]);
output += 4;
vst1_s16(output, out[7]);
output += 4;
vst1_s16(output, out[8]);
output += 4;
vst1_s16(output, out[9]);
output += 4;
vst1_s16(output, out[10]);
output += 4;
vst1_s16(output, out[11]);
output += 4;
vst1_s16(output, out[12]);
output += 4;
vst1_s16(output, out[13]);
output += 4;
vst1_s16(output, out[14]);
output += 4;
vst1_s16(output, out[15]);
}
void vpx_idct16x16_10_add_half1d_pass2(const int16_t *input,
int16_t *const output, void *const dest,
const int stride,
const int highbd_flag) {
const int16x8_t cospis0 = vld1q_s16(kCospi);
const int16x8_t cospis1 = vld1q_s16(kCospi + 8);
const int16x8_t cospisd0 = vaddq_s16(cospis0, cospis0);
const int16x8_t cospisd1 = vaddq_s16(cospis1, cospis1);
const int16x4_t cospi_0_8_16_24 = vget_low_s16(cospis0);
const int16x4_t cospid_0_8_16_24 = vget_low_s16(cospisd0);
const int16x4_t cospid_4_12_20N_28 = vget_high_s16(cospisd0);
const int16x4_t cospid_2_30_10_22 = vget_low_s16(cospisd1);
const int16x4_t cospid_6_26_14_18N = vget_high_s16(cospisd1);
int16x4_t ind[8];
int16x8_t in[4], step1[16], step2[16], out[16];
// Load input (4x8)
ind[0] = vld1_s16(input);
input += 4;
ind[1] = vld1_s16(input);
input += 4;
ind[2] = vld1_s16(input);
input += 4;
ind[3] = vld1_s16(input);
input += 4;
ind[4] = vld1_s16(input);
input += 4;
ind[5] = vld1_s16(input);
input += 4;
ind[6] = vld1_s16(input);
input += 4;
ind[7] = vld1_s16(input);
// Transpose
transpose_s16_4x8(ind[0], ind[1], ind[2], ind[3], ind[4], ind[5], ind[6],
ind[7], &in[0], &in[1], &in[2], &in[3]);
// stage 1
step1[0] = in[0 / 2];
step1[4] = in[4 / 2];
step1[8] = in[2 / 2];
step1[12] = in[6 / 2];
// stage 2
step2[0] = step1[0];
step2[4] = step1[4];
step2[8] = vqrdmulhq_lane_s16(step1[8], cospid_2_30_10_22, 1);
step2[11] = vqrdmulhq_lane_s16(step1[12], cospid_6_26_14_18N, 1);
step2[12] = vqrdmulhq_lane_s16(step1[12], cospid_6_26_14_18N, 0);
step2[15] = vqrdmulhq_lane_s16(step1[8], cospid_2_30_10_22, 0);
// stage 3
step1[0] = step2[0];
step1[4] = vqrdmulhq_lane_s16(step2[4], cospid_4_12_20N_28, 3);
step1[7] = vqrdmulhq_lane_s16(step2[4], cospid_4_12_20N_28, 0);
step1[8] = step2[8];
step1[9] = step2[8];
step1[10] = step2[11];
step1[11] = step2[11];
step1[12] = step2[12];
step1[13] = step2[12];
step1[14] = step2[15];
step1[15] = step2[15];
// stage 4
step2[0] = step2[1] = vqrdmulhq_lane_s16(step1[0], cospid_0_8_16_24, 2);
step2[4] = step1[4];
step2[5] = step1[4];
step2[6] = step1[7];
step2[7] = step1[7];
step2[8] = step1[8];
idct_cospi_8_24_q(step1[14], step1[9], cospi_0_8_16_24, &step2[9],
&step2[14]);
idct_cospi_8_24_neg_q(step1[13], step1[10], cospi_0_8_16_24, &step2[13],
&step2[10]);
step2[11] = step1[11];
step2[12] = step1[12];
step2[15] = step1[15];
// stage 5
step1[0] = step2[0];
step1[1] = step2[1];
step1[2] = step2[1];
step1[3] = step2[0];
step1[4] = step2[4];
idct_cospi_16_16_q(step2[5], step2[6], cospi_0_8_16_24, &step1[5], &step1[6]);
step1[7] = step2[7];
step1[8] = vaddq_s16(step2[8], step2[11]);
step1[9] = vaddq_s16(step2[9], step2[10]);
step1[10] = vsubq_s16(step2[9], step2[10]);
step1[11] = vsubq_s16(step2[8], step2[11]);
step1[12] = vsubq_s16(step2[15], step2[12]);
step1[13] = vsubq_s16(step2[14], step2[13]);
step1[14] = vaddq_s16(step2[14], step2[13]);
step1[15] = vaddq_s16(step2[15], step2[12]);
// stage 6
step2[0] = vaddq_s16(step1[0], step1[7]);
step2[1] = vaddq_s16(step1[1], step1[6]);
step2[2] = vaddq_s16(step1[2], step1[5]);
step2[3] = vaddq_s16(step1[3], step1[4]);
step2[4] = vsubq_s16(step1[3], step1[4]);
step2[5] = vsubq_s16(step1[2], step1[5]);
step2[6] = vsubq_s16(step1[1], step1[6]);
step2[7] = vsubq_s16(step1[0], step1[7]);
idct_cospi_16_16_q(step1[10], step1[13], cospi_0_8_16_24, &step2[10],
&step2[13]);
idct_cospi_16_16_q(step1[11], step1[12], cospi_0_8_16_24, &step2[11],
&step2[12]);
step2[8] = step1[8];
step2[9] = step1[9];
step2[14] = step1[14];
step2[15] = step1[15];
// stage 7
idct16x16_add_stage7(step2, out);
if (output) {
idct16x16_store_pass1(out, output);
} else {
if (highbd_flag) {
idct16x16_add_store_bd8(out, dest, stride);
} else {
idct16x16_add_store(out, dest, stride);
}
}
}
void vpx_idct16x16_256_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
int16_t row_idct_output[16 * 16];
// pass 1
// Parallel idct on the upper 8 rows
vpx_idct16x16_256_add_half1d(input, row_idct_output, dest, stride, 0);
// Parallel idct on the lower 8 rows
vpx_idct16x16_256_add_half1d(input + 8 * 16, row_idct_output + 8, dest,
stride, 0);
// pass 2
// Parallel idct to get the left 8 columns
vpx_idct16x16_256_add_half1d(row_idct_output, NULL, dest, stride, 0);
// Parallel idct to get the right 8 columns
vpx_idct16x16_256_add_half1d(row_idct_output + 16 * 8, NULL, dest + 8, stride,
0);
}
void vpx_idct16x16_38_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
int16_t row_idct_output[16 * 16];
// pass 1
// Parallel idct on the upper 8 rows
vpx_idct16x16_38_add_half1d(input, row_idct_output, dest, stride, 0);
// pass 2
// Parallel idct to get the left 8 columns
vpx_idct16x16_38_add_half1d(row_idct_output, NULL, dest, stride, 0);
// Parallel idct to get the right 8 columns
vpx_idct16x16_38_add_half1d(row_idct_output + 16 * 8, NULL, dest + 8, stride,
0);
}
void vpx_idct16x16_10_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
int16_t row_idct_output[4 * 16];
// pass 1
// Parallel idct on the upper 8 rows
vpx_idct16x16_10_add_half1d_pass1(input, row_idct_output);
// pass 2
// Parallel idct to get the left 8 columns
vpx_idct16x16_10_add_half1d_pass2(row_idct_output, NULL, dest, stride, 0);
// Parallel idct to get the right 8 columns
vpx_idct16x16_10_add_half1d_pass2(row_idct_output + 4 * 8, NULL, dest + 8,
stride, 0);
}
@@ -0,0 +1,674 @@
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/transpose_neon.h"
#include "vpx_dsp/txfm_common.h"
static INLINE void load_8x8_s16(const tran_low_t *input, int16x8_t *const in0,
int16x8_t *const in1, int16x8_t *const in2,
int16x8_t *const in3, int16x8_t *const in4,
int16x8_t *const in5, int16x8_t *const in6,
int16x8_t *const in7) {
*in0 = load_tran_low_to_s16q(input);
input += 32;
*in1 = load_tran_low_to_s16q(input);
input += 32;
*in2 = load_tran_low_to_s16q(input);
input += 32;
*in3 = load_tran_low_to_s16q(input);
input += 32;
*in4 = load_tran_low_to_s16q(input);
input += 32;
*in5 = load_tran_low_to_s16q(input);
input += 32;
*in6 = load_tran_low_to_s16q(input);
input += 32;
*in7 = load_tran_low_to_s16q(input);
}
static INLINE void load_4x8_s16(const tran_low_t *input, int16x4_t *const in0,
int16x4_t *const in1, int16x4_t *const in2,
int16x4_t *const in3, int16x4_t *const in4,
int16x4_t *const in5, int16x4_t *const in6,
int16x4_t *const in7) {
*in0 = load_tran_low_to_s16d(input);
input += 32;
*in1 = load_tran_low_to_s16d(input);
input += 32;
*in2 = load_tran_low_to_s16d(input);
input += 32;
*in3 = load_tran_low_to_s16d(input);
input += 32;
*in4 = load_tran_low_to_s16d(input);
input += 32;
*in5 = load_tran_low_to_s16d(input);
input += 32;
*in6 = load_tran_low_to_s16d(input);
input += 32;
*in7 = load_tran_low_to_s16d(input);
}
// Only for the first pass of the _135_ variant. Since it only uses values from
// the top left 16x16 it can safely assume all the remaining values are 0 and
// skip an awful lot of calculations. In fact, only the first 12 columns make
// the cut. None of the elements in the 13th, 14th, 15th or 16th columns are
// used so it skips any calls to input[12|13|14|15] too.
// In C this does a single row of 32 for each call. Here it transposes the top
// left 12x8 to allow using SIMD.
// vp9/common/vp9_scan.c:vp9_default_iscan_32x32 arranges the first 135 non-zero
// coefficients as follows:
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// 0 0 2 5 10 17 25 38 47 62 83 101 121
// 1 1 4 8 15 22 30 45 58 74 92 112 133
// 2 3 7 12 18 28 36 52 64 82 102 118
// 3 6 11 16 23 31 43 60 73 90 109 126
// 4 9 14 19 29 37 50 65 78 98 116 134
// 5 13 20 26 35 44 54 72 85 105 123
// 6 21 27 33 42 53 63 80 94 113 132
// 7 24 32 39 48 57 71 88 104 120
// 8 34 40 46 56 68 81 96 111 130
// 9 41 49 55 67 77 91 107 124
// 10 51 59 66 76 89 99 119 131
// 11 61 69 75 87 100 114 129
// 12 70 79 86 97 108 122
// 13 84 93 103 110 125
// 14 98 106 115 127
// 15 117 128
void vpx_idct32_12_neon(const tran_low_t *const input, int16_t *output) {
int16x4_t tmp[8];
int16x8_t in[12], s1[32], s2[32], s3[32], s4[32], s5[32], s6[32], s7[32];
load_8x8_s16(input, &in[0], &in[1], &in[2], &in[3], &in[4], &in[5], &in[6],
&in[7]);
transpose_s16_8x8(&in[0], &in[1], &in[2], &in[3], &in[4], &in[5], &in[6],
&in[7]);
load_4x8_s16(input + 8, &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5],
&tmp[6], &tmp[7]);
transpose_s16_4x8(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6],
tmp[7], &in[8], &in[9], &in[10], &in[11]);
// stage 1
s1[16] = multiply_shift_and_narrow_s16(in[1], cospi_31_64);
s1[31] = multiply_shift_and_narrow_s16(in[1], cospi_1_64);
s1[18] = multiply_shift_and_narrow_s16(in[9], cospi_23_64);
s1[29] = multiply_shift_and_narrow_s16(in[9], cospi_9_64);
s1[19] = multiply_shift_and_narrow_s16(in[7], -cospi_25_64);
s1[28] = multiply_shift_and_narrow_s16(in[7], cospi_7_64);
s1[20] = multiply_shift_and_narrow_s16(in[5], cospi_27_64);
s1[27] = multiply_shift_and_narrow_s16(in[5], cospi_5_64);
s1[21] = multiply_shift_and_narrow_s16(in[11], -cospi_21_64);
s1[26] = multiply_shift_and_narrow_s16(in[11], cospi_11_64);
s1[23] = multiply_shift_and_narrow_s16(in[3], -cospi_29_64);
s1[24] = multiply_shift_and_narrow_s16(in[3], cospi_3_64);
// stage 2
s2[8] = multiply_shift_and_narrow_s16(in[2], cospi_30_64);
s2[15] = multiply_shift_and_narrow_s16(in[2], cospi_2_64);
s2[10] = multiply_shift_and_narrow_s16(in[10], cospi_22_64);
s2[13] = multiply_shift_and_narrow_s16(in[10], cospi_10_64);
s2[11] = multiply_shift_and_narrow_s16(in[6], -cospi_26_64);
s2[12] = multiply_shift_and_narrow_s16(in[6], cospi_6_64);
s2[18] = vsubq_s16(s1[19], s1[18]);
s2[19] = vaddq_s16(s1[18], s1[19]);
s2[20] = vaddq_s16(s1[20], s1[21]);
s2[21] = vsubq_s16(s1[20], s1[21]);
s2[26] = vsubq_s16(s1[27], s1[26]);
s2[27] = vaddq_s16(s1[26], s1[27]);
s2[28] = vaddq_s16(s1[28], s1[29]);
s2[29] = vsubq_s16(s1[28], s1[29]);
// stage 3
s3[4] = multiply_shift_and_narrow_s16(in[4], cospi_28_64);
s3[7] = multiply_shift_and_narrow_s16(in[4], cospi_4_64);
s3[10] = vsubq_s16(s2[11], s2[10]);
s3[11] = vaddq_s16(s2[10], s2[11]);
s3[12] = vaddq_s16(s2[12], s2[13]);
s3[13] = vsubq_s16(s2[12], s2[13]);
s3[17] = multiply_accumulate_shift_and_narrow_s16(s1[16], -cospi_4_64, s1[31],
cospi_28_64);
s3[30] = multiply_accumulate_shift_and_narrow_s16(s1[16], cospi_28_64, s1[31],
cospi_4_64);
s3[18] = multiply_accumulate_shift_and_narrow_s16(s2[18], -cospi_28_64,
s2[29], -cospi_4_64);
s3[29] = multiply_accumulate_shift_and_narrow_s16(s2[18], -cospi_4_64, s2[29],
cospi_28_64);
s3[21] = multiply_accumulate_shift_and_narrow_s16(s2[21], -cospi_20_64,
s2[26], cospi_12_64);
s3[26] = multiply_accumulate_shift_and_narrow_s16(s2[21], cospi_12_64, s2[26],
cospi_20_64);
s3[22] = multiply_accumulate_shift_and_narrow_s16(s1[23], -cospi_12_64,
s1[24], -cospi_20_64);
s3[25] = multiply_accumulate_shift_and_narrow_s16(s1[23], -cospi_20_64,
s1[24], cospi_12_64);
// stage 4
s4[0] = multiply_shift_and_narrow_s16(in[0], cospi_16_64);
s4[2] = multiply_shift_and_narrow_s16(in[8], cospi_24_64);
s4[3] = multiply_shift_and_narrow_s16(in[8], cospi_8_64);
s4[9] = multiply_accumulate_shift_and_narrow_s16(s2[8], -cospi_8_64, s2[15],
cospi_24_64);
s4[14] = multiply_accumulate_shift_and_narrow_s16(s2[8], cospi_24_64, s2[15],
cospi_8_64);
s4[10] = multiply_accumulate_shift_and_narrow_s16(s3[10], -cospi_24_64,
s3[13], -cospi_8_64);
s4[13] = multiply_accumulate_shift_and_narrow_s16(s3[10], -cospi_8_64, s3[13],
cospi_24_64);
s4[16] = vaddq_s16(s1[16], s2[19]);
s4[17] = vaddq_s16(s3[17], s3[18]);
s4[18] = vsubq_s16(s3[17], s3[18]);
s4[19] = vsubq_s16(s1[16], s2[19]);
s4[20] = vsubq_s16(s1[23], s2[20]);
s4[21] = vsubq_s16(s3[22], s3[21]);
s4[22] = vaddq_s16(s3[21], s3[22]);
s4[23] = vaddq_s16(s2[20], s1[23]);
s4[24] = vaddq_s16(s1[24], s2[27]);
s4[25] = vaddq_s16(s3[25], s3[26]);
s4[26] = vsubq_s16(s3[25], s3[26]);
s4[27] = vsubq_s16(s1[24], s2[27]);
s4[28] = vsubq_s16(s1[31], s2[28]);
s4[29] = vsubq_s16(s3[30], s3[29]);
s4[30] = vaddq_s16(s3[29], s3[30]);
s4[31] = vaddq_s16(s2[28], s1[31]);
// stage 5
s5[0] = vaddq_s16(s4[0], s4[3]);
s5[1] = vaddq_s16(s4[0], s4[2]);
s5[2] = vsubq_s16(s4[0], s4[2]);
s5[3] = vsubq_s16(s4[0], s4[3]);
s5[5] = sub_multiply_shift_and_narrow_s16(s3[7], s3[4], cospi_16_64);
s5[6] = add_multiply_shift_and_narrow_s16(s3[4], s3[7], cospi_16_64);
s5[8] = vaddq_s16(s2[8], s3[11]);
s5[9] = vaddq_s16(s4[9], s4[10]);
s5[10] = vsubq_s16(s4[9], s4[10]);
s5[11] = vsubq_s16(s2[8], s3[11]);
s5[12] = vsubq_s16(s2[15], s3[12]);
s5[13] = vsubq_s16(s4[14], s4[13]);
s5[14] = vaddq_s16(s4[13], s4[14]);
s5[15] = vaddq_s16(s2[15], s3[12]);
s5[18] = multiply_accumulate_shift_and_narrow_s16(s4[18], -cospi_8_64, s4[29],
cospi_24_64);
s5[29] = multiply_accumulate_shift_and_narrow_s16(s4[18], cospi_24_64, s4[29],
cospi_8_64);
s5[19] = multiply_accumulate_shift_and_narrow_s16(s4[19], -cospi_8_64, s4[28],
cospi_24_64);
s5[28] = multiply_accumulate_shift_and_narrow_s16(s4[19], cospi_24_64, s4[28],
cospi_8_64);
s5[20] = multiply_accumulate_shift_and_narrow_s16(s4[20], -cospi_24_64,
s4[27], -cospi_8_64);
s5[27] = multiply_accumulate_shift_and_narrow_s16(s4[20], -cospi_8_64, s4[27],
cospi_24_64);
s5[21] = multiply_accumulate_shift_and_narrow_s16(s4[21], -cospi_24_64,
s4[26], -cospi_8_64);
s5[26] = multiply_accumulate_shift_and_narrow_s16(s4[21], -cospi_8_64, s4[26],
cospi_24_64);
// stage 6
s6[0] = vaddq_s16(s5[0], s3[7]);
s6[1] = vaddq_s16(s5[1], s5[6]);
s6[2] = vaddq_s16(s5[2], s5[5]);
s6[3] = vaddq_s16(s5[3], s3[4]);
s6[4] = vsubq_s16(s5[3], s3[4]);
s6[5] = vsubq_s16(s5[2], s5[5]);
s6[6] = vsubq_s16(s5[1], s5[6]);
s6[7] = vsubq_s16(s5[0], s3[7]);
s6[10] = sub_multiply_shift_and_narrow_s16(s5[13], s5[10], cospi_16_64);
s6[13] = add_multiply_shift_and_narrow_s16(s5[10], s5[13], cospi_16_64);
s6[11] = sub_multiply_shift_and_narrow_s16(s5[12], s5[11], cospi_16_64);
s6[12] = add_multiply_shift_and_narrow_s16(s5[11], s5[12], cospi_16_64);
s6[16] = vaddq_s16(s4[16], s4[23]);
s6[17] = vaddq_s16(s4[17], s4[22]);
s6[18] = vaddq_s16(s5[18], s5[21]);
s6[19] = vaddq_s16(s5[19], s5[20]);
s6[20] = vsubq_s16(s5[19], s5[20]);
s6[21] = vsubq_s16(s5[18], s5[21]);
s6[22] = vsubq_s16(s4[17], s4[22]);
s6[23] = vsubq_s16(s4[16], s4[23]);
s6[24] = vsubq_s16(s4[31], s4[24]);
s6[25] = vsubq_s16(s4[30], s4[25]);
s6[26] = vsubq_s16(s5[29], s5[26]);
s6[27] = vsubq_s16(s5[28], s5[27]);
s6[28] = vaddq_s16(s5[27], s5[28]);
s6[29] = vaddq_s16(s5[26], s5[29]);
s6[30] = vaddq_s16(s4[25], s4[30]);
s6[31] = vaddq_s16(s4[24], s4[31]);
// stage 7
s7[0] = vaddq_s16(s6[0], s5[15]);
s7[1] = vaddq_s16(s6[1], s5[14]);
s7[2] = vaddq_s16(s6[2], s6[13]);
s7[3] = vaddq_s16(s6[3], s6[12]);
s7[4] = vaddq_s16(s6[4], s6[11]);
s7[5] = vaddq_s16(s6[5], s6[10]);
s7[6] = vaddq_s16(s6[6], s5[9]);
s7[7] = vaddq_s16(s6[7], s5[8]);
s7[8] = vsubq_s16(s6[7], s5[8]);
s7[9] = vsubq_s16(s6[6], s5[9]);
s7[10] = vsubq_s16(s6[5], s6[10]);
s7[11] = vsubq_s16(s6[4], s6[11]);
s7[12] = vsubq_s16(s6[3], s6[12]);
s7[13] = vsubq_s16(s6[2], s6[13]);
s7[14] = vsubq_s16(s6[1], s5[14]);
s7[15] = vsubq_s16(s6[0], s5[15]);
s7[20] = sub_multiply_shift_and_narrow_s16(s6[27], s6[20], cospi_16_64);
s7[27] = add_multiply_shift_and_narrow_s16(s6[20], s6[27], cospi_16_64);
s7[21] = sub_multiply_shift_and_narrow_s16(s6[26], s6[21], cospi_16_64);
s7[26] = add_multiply_shift_and_narrow_s16(s6[21], s6[26], cospi_16_64);
s7[22] = sub_multiply_shift_and_narrow_s16(s6[25], s6[22], cospi_16_64);
s7[25] = add_multiply_shift_and_narrow_s16(s6[22], s6[25], cospi_16_64);
s7[23] = sub_multiply_shift_and_narrow_s16(s6[24], s6[23], cospi_16_64);
s7[24] = add_multiply_shift_and_narrow_s16(s6[23], s6[24], cospi_16_64);
// final stage
vst1q_s16(output, vaddq_s16(s7[0], s6[31]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[1], s6[30]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[2], s6[29]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[3], s6[28]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[4], s7[27]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[5], s7[26]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[6], s7[25]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[7], s7[24]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[8], s7[23]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[9], s7[22]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[10], s7[21]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[11], s7[20]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[12], s6[19]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[13], s6[18]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[14], s6[17]));
output += 16;
vst1q_s16(output, vaddq_s16(s7[15], s6[16]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[15], s6[16]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[14], s6[17]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[13], s6[18]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[12], s6[19]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[11], s7[20]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[10], s7[21]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[9], s7[22]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[8], s7[23]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[7], s7[24]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[6], s7[25]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[5], s7[26]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[4], s7[27]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[3], s6[28]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[2], s6[29]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[1], s6[30]));
output += 16;
vst1q_s16(output, vsubq_s16(s7[0], s6[31]));
}
void vpx_idct32_16_neon(const int16_t *const input, void *const output,
const int stride, const int highbd_flag) {
int16x8_t in[16], s1[32], s2[32], s3[32], s4[32], s5[32], s6[32], s7[32],
out[32];
load_and_transpose_s16_8x8(input, 16, &in[0], &in[1], &in[2], &in[3], &in[4],
&in[5], &in[6], &in[7]);
load_and_transpose_s16_8x8(input + 8, 16, &in[8], &in[9], &in[10], &in[11],
&in[12], &in[13], &in[14], &in[15]);
// stage 1
s1[16] = multiply_shift_and_narrow_s16(in[1], cospi_31_64);
s1[31] = multiply_shift_and_narrow_s16(in[1], cospi_1_64);
s1[17] = multiply_shift_and_narrow_s16(in[15], -cospi_17_64);
s1[30] = multiply_shift_and_narrow_s16(in[15], cospi_15_64);
s1[18] = multiply_shift_and_narrow_s16(in[9], cospi_23_64);
s1[29] = multiply_shift_and_narrow_s16(in[9], cospi_9_64);
s1[19] = multiply_shift_and_narrow_s16(in[7], -cospi_25_64);
s1[28] = multiply_shift_and_narrow_s16(in[7], cospi_7_64);
s1[20] = multiply_shift_and_narrow_s16(in[5], cospi_27_64);
s1[27] = multiply_shift_and_narrow_s16(in[5], cospi_5_64);
s1[21] = multiply_shift_and_narrow_s16(in[11], -cospi_21_64);
s1[26] = multiply_shift_and_narrow_s16(in[11], cospi_11_64);
s1[22] = multiply_shift_and_narrow_s16(in[13], cospi_19_64);
s1[25] = multiply_shift_and_narrow_s16(in[13], cospi_13_64);
s1[23] = multiply_shift_and_narrow_s16(in[3], -cospi_29_64);
s1[24] = multiply_shift_and_narrow_s16(in[3], cospi_3_64);
// stage 2
s2[8] = multiply_shift_and_narrow_s16(in[2], cospi_30_64);
s2[15] = multiply_shift_and_narrow_s16(in[2], cospi_2_64);
s2[9] = multiply_shift_and_narrow_s16(in[14], -cospi_18_64);
s2[14] = multiply_shift_and_narrow_s16(in[14], cospi_14_64);
s2[10] = multiply_shift_and_narrow_s16(in[10], cospi_22_64);
s2[13] = multiply_shift_and_narrow_s16(in[10], cospi_10_64);
s2[11] = multiply_shift_and_narrow_s16(in[6], -cospi_26_64);
s2[12] = multiply_shift_and_narrow_s16(in[6], cospi_6_64);
s2[16] = vaddq_s16(s1[16], s1[17]);
s2[17] = vsubq_s16(s1[16], s1[17]);
s2[18] = vsubq_s16(s1[19], s1[18]);
s2[19] = vaddq_s16(s1[18], s1[19]);
s2[20] = vaddq_s16(s1[20], s1[21]);
s2[21] = vsubq_s16(s1[20], s1[21]);
s2[22] = vsubq_s16(s1[23], s1[22]);
s2[23] = vaddq_s16(s1[22], s1[23]);
s2[24] = vaddq_s16(s1[24], s1[25]);
s2[25] = vsubq_s16(s1[24], s1[25]);
s2[26] = vsubq_s16(s1[27], s1[26]);
s2[27] = vaddq_s16(s1[26], s1[27]);
s2[28] = vaddq_s16(s1[28], s1[29]);
s2[29] = vsubq_s16(s1[28], s1[29]);
s2[30] = vsubq_s16(s1[31], s1[30]);
s2[31] = vaddq_s16(s1[30], s1[31]);
// stage 3
s3[4] = multiply_shift_and_narrow_s16(in[4], cospi_28_64);
s3[7] = multiply_shift_and_narrow_s16(in[4], cospi_4_64);
s3[5] = multiply_shift_and_narrow_s16(in[12], -cospi_20_64);
s3[6] = multiply_shift_and_narrow_s16(in[12], cospi_12_64);
s3[8] = vaddq_s16(s2[8], s2[9]);
s3[9] = vsubq_s16(s2[8], s2[9]);
s3[10] = vsubq_s16(s2[11], s2[10]);
s3[11] = vaddq_s16(s2[10], s2[11]);
s3[12] = vaddq_s16(s2[12], s2[13]);
s3[13] = vsubq_s16(s2[12], s2[13]);
s3[14] = vsubq_s16(s2[15], s2[14]);
s3[15] = vaddq_s16(s2[14], s2[15]);
s3[17] = multiply_accumulate_shift_and_narrow_s16(s2[17], -cospi_4_64, s2[30],
cospi_28_64);
s3[30] = multiply_accumulate_shift_and_narrow_s16(s2[17], cospi_28_64, s2[30],
cospi_4_64);
s3[18] = multiply_accumulate_shift_and_narrow_s16(s2[18], -cospi_28_64,
s2[29], -cospi_4_64);
s3[29] = multiply_accumulate_shift_and_narrow_s16(s2[18], -cospi_4_64, s2[29],
cospi_28_64);
s3[21] = multiply_accumulate_shift_and_narrow_s16(s2[21], -cospi_20_64,
s2[26], cospi_12_64);
s3[26] = multiply_accumulate_shift_and_narrow_s16(s2[21], cospi_12_64, s2[26],
cospi_20_64);
s3[22] = multiply_accumulate_shift_and_narrow_s16(s2[22], -cospi_12_64,
s2[25], -cospi_20_64);
s3[25] = multiply_accumulate_shift_and_narrow_s16(s2[22], -cospi_20_64,
s2[25], cospi_12_64);
// stage 4
s4[0] = multiply_shift_and_narrow_s16(in[0], cospi_16_64);
s4[2] = multiply_shift_and_narrow_s16(in[8], cospi_24_64);
s4[3] = multiply_shift_and_narrow_s16(in[8], cospi_8_64);
s4[4] = vaddq_s16(s3[4], s3[5]);
s4[5] = vsubq_s16(s3[4], s3[5]);
s4[6] = vsubq_s16(s3[7], s3[6]);
s4[7] = vaddq_s16(s3[6], s3[7]);
s4[9] = multiply_accumulate_shift_and_narrow_s16(s3[9], -cospi_8_64, s3[14],
cospi_24_64);
s4[14] = multiply_accumulate_shift_and_narrow_s16(s3[9], cospi_24_64, s3[14],
cospi_8_64);
s4[10] = multiply_accumulate_shift_and_narrow_s16(s3[10], -cospi_24_64,
s3[13], -cospi_8_64);
s4[13] = multiply_accumulate_shift_and_narrow_s16(s3[10], -cospi_8_64, s3[13],
cospi_24_64);
s4[16] = vaddq_s16(s2[16], s2[19]);
s4[17] = vaddq_s16(s3[17], s3[18]);
s4[18] = vsubq_s16(s3[17], s3[18]);
s4[19] = vsubq_s16(s2[16], s2[19]);
s4[20] = vsubq_s16(s2[23], s2[20]);
s4[21] = vsubq_s16(s3[22], s3[21]);
s4[22] = vaddq_s16(s3[21], s3[22]);
s4[23] = vaddq_s16(s2[20], s2[23]);
s4[24] = vaddq_s16(s2[24], s2[27]);
s4[25] = vaddq_s16(s3[25], s3[26]);
s4[26] = vsubq_s16(s3[25], s3[26]);
s4[27] = vsubq_s16(s2[24], s2[27]);
s4[28] = vsubq_s16(s2[31], s2[28]);
s4[29] = vsubq_s16(s3[30], s3[29]);
s4[30] = vaddq_s16(s3[29], s3[30]);
s4[31] = vaddq_s16(s2[28], s2[31]);
// stage 5
s5[0] = vaddq_s16(s4[0], s4[3]);
s5[1] = vaddq_s16(s4[0], s4[2]);
s5[2] = vsubq_s16(s4[0], s4[2]);
s5[3] = vsubq_s16(s4[0], s4[3]);
s5[5] = sub_multiply_shift_and_narrow_s16(s4[6], s4[5], cospi_16_64);
s5[6] = add_multiply_shift_and_narrow_s16(s4[5], s4[6], cospi_16_64);
s5[8] = vaddq_s16(s3[8], s3[11]);
s5[9] = vaddq_s16(s4[9], s4[10]);
s5[10] = vsubq_s16(s4[9], s4[10]);
s5[11] = vsubq_s16(s3[8], s3[11]);
s5[12] = vsubq_s16(s3[15], s3[12]);
s5[13] = vsubq_s16(s4[14], s4[13]);
s5[14] = vaddq_s16(s4[13], s4[14]);
s5[15] = vaddq_s16(s3[15], s3[12]);
s5[18] = multiply_accumulate_shift_and_narrow_s16(s4[18], -cospi_8_64, s4[29],
cospi_24_64);
s5[29] = multiply_accumulate_shift_and_narrow_s16(s4[18], cospi_24_64, s4[29],
cospi_8_64);
s5[19] = multiply_accumulate_shift_and_narrow_s16(s4[19], -cospi_8_64, s4[28],
cospi_24_64);
s5[28] = multiply_accumulate_shift_and_narrow_s16(s4[19], cospi_24_64, s4[28],
cospi_8_64);
s5[20] = multiply_accumulate_shift_and_narrow_s16(s4[20], -cospi_24_64,
s4[27], -cospi_8_64);
s5[27] = multiply_accumulate_shift_and_narrow_s16(s4[20], -cospi_8_64, s4[27],
cospi_24_64);
s5[21] = multiply_accumulate_shift_and_narrow_s16(s4[21], -cospi_24_64,
s4[26], -cospi_8_64);
s5[26] = multiply_accumulate_shift_and_narrow_s16(s4[21], -cospi_8_64, s4[26],
cospi_24_64);
// stage 6
s6[0] = vaddq_s16(s5[0], s4[7]);
s6[1] = vaddq_s16(s5[1], s5[6]);
s6[2] = vaddq_s16(s5[2], s5[5]);
s6[3] = vaddq_s16(s5[3], s4[4]);
s6[4] = vsubq_s16(s5[3], s4[4]);
s6[5] = vsubq_s16(s5[2], s5[5]);
s6[6] = vsubq_s16(s5[1], s5[6]);
s6[7] = vsubq_s16(s5[0], s4[7]);
s6[10] = sub_multiply_shift_and_narrow_s16(s5[13], s5[10], cospi_16_64);
s6[13] = add_multiply_shift_and_narrow_s16(s5[10], s5[13], cospi_16_64);
s6[11] = sub_multiply_shift_and_narrow_s16(s5[12], s5[11], cospi_16_64);
s6[12] = add_multiply_shift_and_narrow_s16(s5[11], s5[12], cospi_16_64);
s6[16] = vaddq_s16(s4[16], s4[23]);
s6[17] = vaddq_s16(s4[17], s4[22]);
s6[18] = vaddq_s16(s5[18], s5[21]);
s6[19] = vaddq_s16(s5[19], s5[20]);
s6[20] = vsubq_s16(s5[19], s5[20]);
s6[21] = vsubq_s16(s5[18], s5[21]);
s6[22] = vsubq_s16(s4[17], s4[22]);
s6[23] = vsubq_s16(s4[16], s4[23]);
s6[24] = vsubq_s16(s4[31], s4[24]);
s6[25] = vsubq_s16(s4[30], s4[25]);
s6[26] = vsubq_s16(s5[29], s5[26]);
s6[27] = vsubq_s16(s5[28], s5[27]);
s6[28] = vaddq_s16(s5[27], s5[28]);
s6[29] = vaddq_s16(s5[26], s5[29]);
s6[30] = vaddq_s16(s4[25], s4[30]);
s6[31] = vaddq_s16(s4[24], s4[31]);
// stage 7
s7[0] = vaddq_s16(s6[0], s5[15]);
s7[1] = vaddq_s16(s6[1], s5[14]);
s7[2] = vaddq_s16(s6[2], s6[13]);
s7[3] = vaddq_s16(s6[3], s6[12]);
s7[4] = vaddq_s16(s6[4], s6[11]);
s7[5] = vaddq_s16(s6[5], s6[10]);
s7[6] = vaddq_s16(s6[6], s5[9]);
s7[7] = vaddq_s16(s6[7], s5[8]);
s7[8] = vsubq_s16(s6[7], s5[8]);
s7[9] = vsubq_s16(s6[6], s5[9]);
s7[10] = vsubq_s16(s6[5], s6[10]);
s7[11] = vsubq_s16(s6[4], s6[11]);
s7[12] = vsubq_s16(s6[3], s6[12]);
s7[13] = vsubq_s16(s6[2], s6[13]);
s7[14] = vsubq_s16(s6[1], s5[14]);
s7[15] = vsubq_s16(s6[0], s5[15]);
s7[20] = sub_multiply_shift_and_narrow_s16(s6[27], s6[20], cospi_16_64);
s7[27] = add_multiply_shift_and_narrow_s16(s6[20], s6[27], cospi_16_64);
s7[21] = sub_multiply_shift_and_narrow_s16(s6[26], s6[21], cospi_16_64);
s7[26] = add_multiply_shift_and_narrow_s16(s6[21], s6[26], cospi_16_64);
s7[22] = sub_multiply_shift_and_narrow_s16(s6[25], s6[22], cospi_16_64);
s7[25] = add_multiply_shift_and_narrow_s16(s6[22], s6[25], cospi_16_64);
s7[23] = sub_multiply_shift_and_narrow_s16(s6[24], s6[23], cospi_16_64);
s7[24] = add_multiply_shift_and_narrow_s16(s6[23], s6[24], cospi_16_64);
// final stage
out[0] = final_add(s7[0], s6[31]);
out[1] = final_add(s7[1], s6[30]);
out[2] = final_add(s7[2], s6[29]);
out[3] = final_add(s7[3], s6[28]);
out[4] = final_add(s7[4], s7[27]);
out[5] = final_add(s7[5], s7[26]);
out[6] = final_add(s7[6], s7[25]);
out[7] = final_add(s7[7], s7[24]);
out[8] = final_add(s7[8], s7[23]);
out[9] = final_add(s7[9], s7[22]);
out[10] = final_add(s7[10], s7[21]);
out[11] = final_add(s7[11], s7[20]);
out[12] = final_add(s7[12], s6[19]);
out[13] = final_add(s7[13], s6[18]);
out[14] = final_add(s7[14], s6[17]);
out[15] = final_add(s7[15], s6[16]);
out[16] = final_sub(s7[15], s6[16]);
out[17] = final_sub(s7[14], s6[17]);
out[18] = final_sub(s7[13], s6[18]);
out[19] = final_sub(s7[12], s6[19]);
out[20] = final_sub(s7[11], s7[20]);
out[21] = final_sub(s7[10], s7[21]);
out[22] = final_sub(s7[9], s7[22]);
out[23] = final_sub(s7[8], s7[23]);
out[24] = final_sub(s7[7], s7[24]);
out[25] = final_sub(s7[6], s7[25]);
out[26] = final_sub(s7[5], s7[26]);
out[27] = final_sub(s7[4], s7[27]);
out[28] = final_sub(s7[3], s6[28]);
out[29] = final_sub(s7[2], s6[29]);
out[30] = final_sub(s7[1], s6[30]);
out[31] = final_sub(s7[0], s6[31]);
if (highbd_flag) {
highbd_add_and_store_bd8(out, output, stride);
} else {
uint8_t *const outputT = (uint8_t *)output;
add_and_store_u8_s16(out + 0, outputT, stride);
add_and_store_u8_s16(out + 8, outputT + (8 * stride), stride);
add_and_store_u8_s16(out + 16, outputT + (16 * stride), stride);
add_and_store_u8_s16(out + 24, outputT + (24 * stride), stride);
}
}
void vpx_idct32x32_135_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
int i;
int16_t temp[32 * 16];
int16_t *t = temp;
vpx_idct32_12_neon(input, temp);
vpx_idct32_12_neon(input + 32 * 8, temp + 8);
for (i = 0; i < 32; i += 8) {
vpx_idct32_16_neon(t, dest, stride, 0);
t += (16 * 8);
dest += 8;
}
}
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/inv_txfm.h"
static INLINE void idct32x32_1_add_pos_kernel(uint8_t **dest, const int stride,
const uint8x16_t res) {
const uint8x16_t a0 = vld1q_u8(*dest);
const uint8x16_t a1 = vld1q_u8(*dest + 16);
const uint8x16_t b0 = vqaddq_u8(a0, res);
const uint8x16_t b1 = vqaddq_u8(a1, res);
vst1q_u8(*dest, b0);
vst1q_u8(*dest + 16, b1);
*dest += stride;
}
static INLINE void idct32x32_1_add_neg_kernel(uint8_t **dest, const int stride,
const uint8x16_t res) {
const uint8x16_t a0 = vld1q_u8(*dest);
const uint8x16_t a1 = vld1q_u8(*dest + 16);
const uint8x16_t b0 = vqsubq_u8(a0, res);
const uint8x16_t b1 = vqsubq_u8(a1, res);
vst1q_u8(*dest, b0);
vst1q_u8(*dest + 16, b1);
*dest += stride;
}
void vpx_idct32x32_1_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
int i;
const int16_t out0 =
WRAPLOW(dct_const_round_shift((int16_t)input[0] * cospi_16_64));
const int16_t out1 = WRAPLOW(dct_const_round_shift(out0 * cospi_16_64));
const int16_t a1 = ROUND_POWER_OF_TWO(out1, 6);
if (a1 >= 0) {
const uint8x16_t dc = create_dcq(a1);
for (i = 0; i < 32; i++) {
idct32x32_1_add_pos_kernel(&dest, stride, dc);
}
} else {
const uint8x16_t dc = create_dcq(-a1);
for (i = 0; i < 32; i++) {
idct32x32_1_add_neg_kernel(&dest, stride, dc);
}
}
}
@@ -0,0 +1,513 @@
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/transpose_neon.h"
#include "vpx_dsp/txfm_common.h"
// Only for the first pass of the _34_ variant. Since it only uses values from
// the top left 8x8 it can safely assume all the remaining values are 0 and skip
// an awful lot of calculations. In fact, only the first 6 columns make the cut.
// None of the elements in the 7th or 8th column are used so it skips any calls
// to input[67] too.
// In C this does a single row of 32 for each call. Here it transposes the top
// left 8x8 to allow using SIMD.
// vp9/common/vp9_scan.c:vp9_default_iscan_32x32 arranges the first 34 non-zero
// coefficients as follows:
// 0 1 2 3 4 5 6 7
// 0 0 2 5 10 17 25
// 1 1 4 8 15 22 30
// 2 3 7 12 18 28
// 3 6 11 16 23 31
// 4 9 14 19 29
// 5 13 20 26
// 6 21 27 33
// 7 24 32
void vpx_idct32_6_neon(const tran_low_t *input, int16_t *output) {
int16x8_t in[8], s1[32], s2[32], s3[32];
in[0] = load_tran_low_to_s16q(input);
input += 32;
in[1] = load_tran_low_to_s16q(input);
input += 32;
in[2] = load_tran_low_to_s16q(input);
input += 32;
in[3] = load_tran_low_to_s16q(input);
input += 32;
in[4] = load_tran_low_to_s16q(input);
input += 32;
in[5] = load_tran_low_to_s16q(input);
input += 32;
in[6] = load_tran_low_to_s16q(input);
input += 32;
in[7] = load_tran_low_to_s16q(input);
transpose_s16_8x8(&in[0], &in[1], &in[2], &in[3], &in[4], &in[5], &in[6],
&in[7]);
// stage 1
// input[1] * cospi_31_64 - input[31] * cospi_1_64 (but input[31] == 0)
s1[16] = multiply_shift_and_narrow_s16(in[1], cospi_31_64);
// input[1] * cospi_1_64 + input[31] * cospi_31_64 (but input[31] == 0)
s1[31] = multiply_shift_and_narrow_s16(in[1], cospi_1_64);
s1[20] = multiply_shift_and_narrow_s16(in[5], cospi_27_64);
s1[27] = multiply_shift_and_narrow_s16(in[5], cospi_5_64);
s1[23] = multiply_shift_and_narrow_s16(in[3], -cospi_29_64);
s1[24] = multiply_shift_and_narrow_s16(in[3], cospi_3_64);
// stage 2
s2[8] = multiply_shift_and_narrow_s16(in[2], cospi_30_64);
s2[15] = multiply_shift_and_narrow_s16(in[2], cospi_2_64);
// stage 3
s1[4] = multiply_shift_and_narrow_s16(in[4], cospi_28_64);
s1[7] = multiply_shift_and_narrow_s16(in[4], cospi_4_64);
s1[17] = multiply_accumulate_shift_and_narrow_s16(s1[16], -cospi_4_64, s1[31],
cospi_28_64);
s1[30] = multiply_accumulate_shift_and_narrow_s16(s1[16], cospi_28_64, s1[31],
cospi_4_64);
s1[21] = multiply_accumulate_shift_and_narrow_s16(s1[20], -cospi_20_64,
s1[27], cospi_12_64);
s1[26] = multiply_accumulate_shift_and_narrow_s16(s1[20], cospi_12_64, s1[27],
cospi_20_64);
s1[22] = multiply_accumulate_shift_and_narrow_s16(s1[23], -cospi_12_64,
s1[24], -cospi_20_64);
s1[25] = multiply_accumulate_shift_and_narrow_s16(s1[23], -cospi_20_64,
s1[24], cospi_12_64);
// stage 4
s1[0] = multiply_shift_and_narrow_s16(in[0], cospi_16_64);
s2[9] = multiply_accumulate_shift_and_narrow_s16(s2[8], -cospi_8_64, s2[15],
cospi_24_64);
s2[14] = multiply_accumulate_shift_and_narrow_s16(s2[8], cospi_24_64, s2[15],
cospi_8_64);
s2[20] = vsubq_s16(s1[23], s1[20]);
s2[21] = vsubq_s16(s1[22], s1[21]);
s2[22] = vaddq_s16(s1[21], s1[22]);
s2[23] = vaddq_s16(s1[20], s1[23]);
s2[24] = vaddq_s16(s1[24], s1[27]);
s2[25] = vaddq_s16(s1[25], s1[26]);
s2[26] = vsubq_s16(s1[25], s1[26]);
s2[27] = vsubq_s16(s1[24], s1[27]);
// stage 5
s1[5] = sub_multiply_shift_and_narrow_s16(s1[7], s1[4], cospi_16_64);
s1[6] = add_multiply_shift_and_narrow_s16(s1[4], s1[7], cospi_16_64);
s1[18] = multiply_accumulate_shift_and_narrow_s16(s1[17], -cospi_8_64, s1[30],
cospi_24_64);
s1[29] = multiply_accumulate_shift_and_narrow_s16(s1[17], cospi_24_64, s1[30],
cospi_8_64);
s1[19] = multiply_accumulate_shift_and_narrow_s16(s1[16], -cospi_8_64, s1[31],
cospi_24_64);
s1[28] = multiply_accumulate_shift_and_narrow_s16(s1[16], cospi_24_64, s1[31],
cospi_8_64);
s1[20] = multiply_accumulate_shift_and_narrow_s16(s2[20], -cospi_24_64,
s2[27], -cospi_8_64);
s1[27] = multiply_accumulate_shift_and_narrow_s16(s2[20], -cospi_8_64, s2[27],
cospi_24_64);
s1[21] = multiply_accumulate_shift_and_narrow_s16(s2[21], -cospi_24_64,
s2[26], -cospi_8_64);
s1[26] = multiply_accumulate_shift_and_narrow_s16(s2[21], -cospi_8_64, s2[26],
cospi_24_64);
// stage 6
s2[0] = vaddq_s16(s1[0], s1[7]);
s2[1] = vaddq_s16(s1[0], s1[6]);
s2[2] = vaddq_s16(s1[0], s1[5]);
s2[3] = vaddq_s16(s1[0], s1[4]);
s2[4] = vsubq_s16(s1[0], s1[4]);
s2[5] = vsubq_s16(s1[0], s1[5]);
s2[6] = vsubq_s16(s1[0], s1[6]);
s2[7] = vsubq_s16(s1[0], s1[7]);
s2[10] = sub_multiply_shift_and_narrow_s16(s2[14], s2[9], cospi_16_64);
s2[13] = add_multiply_shift_and_narrow_s16(s2[9], s2[14], cospi_16_64);
s2[11] = sub_multiply_shift_and_narrow_s16(s2[15], s2[8], cospi_16_64);
s2[12] = add_multiply_shift_and_narrow_s16(s2[8], s2[15], cospi_16_64);
s2[16] = vaddq_s16(s1[16], s2[23]);
s2[17] = vaddq_s16(s1[17], s2[22]);
s2[18] = vaddq_s16(s1[18], s1[21]);
s2[19] = vaddq_s16(s1[19], s1[20]);
s2[20] = vsubq_s16(s1[19], s1[20]);
s2[21] = vsubq_s16(s1[18], s1[21]);
s2[22] = vsubq_s16(s1[17], s2[22]);
s2[23] = vsubq_s16(s1[16], s2[23]);
s3[24] = vsubq_s16(s1[31], s2[24]);
s3[25] = vsubq_s16(s1[30], s2[25]);
s3[26] = vsubq_s16(s1[29], s1[26]);
s3[27] = vsubq_s16(s1[28], s1[27]);
s2[28] = vaddq_s16(s1[27], s1[28]);
s2[29] = vaddq_s16(s1[26], s1[29]);
s2[30] = vaddq_s16(s2[25], s1[30]);
s2[31] = vaddq_s16(s2[24], s1[31]);
// stage 7
s1[0] = vaddq_s16(s2[0], s2[15]);
s1[1] = vaddq_s16(s2[1], s2[14]);
s1[2] = vaddq_s16(s2[2], s2[13]);
s1[3] = vaddq_s16(s2[3], s2[12]);
s1[4] = vaddq_s16(s2[4], s2[11]);
s1[5] = vaddq_s16(s2[5], s2[10]);
s1[6] = vaddq_s16(s2[6], s2[9]);
s1[7] = vaddq_s16(s2[7], s2[8]);
s1[8] = vsubq_s16(s2[7], s2[8]);
s1[9] = vsubq_s16(s2[6], s2[9]);
s1[10] = vsubq_s16(s2[5], s2[10]);
s1[11] = vsubq_s16(s2[4], s2[11]);
s1[12] = vsubq_s16(s2[3], s2[12]);
s1[13] = vsubq_s16(s2[2], s2[13]);
s1[14] = vsubq_s16(s2[1], s2[14]);
s1[15] = vsubq_s16(s2[0], s2[15]);
s1[20] = sub_multiply_shift_and_narrow_s16(s3[27], s2[20], cospi_16_64);
s1[27] = add_multiply_shift_and_narrow_s16(s2[20], s3[27], cospi_16_64);
s1[21] = sub_multiply_shift_and_narrow_s16(s3[26], s2[21], cospi_16_64);
s1[26] = add_multiply_shift_and_narrow_s16(s2[21], s3[26], cospi_16_64);
s1[22] = sub_multiply_shift_and_narrow_s16(s3[25], s2[22], cospi_16_64);
s1[25] = add_multiply_shift_and_narrow_s16(s2[22], s3[25], cospi_16_64);
s1[23] = sub_multiply_shift_and_narrow_s16(s3[24], s2[23], cospi_16_64);
s1[24] = add_multiply_shift_and_narrow_s16(s2[23], s3[24], cospi_16_64);
// final stage
vst1q_s16(output, vaddq_s16(s1[0], s2[31]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[1], s2[30]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[2], s2[29]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[3], s2[28]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[4], s1[27]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[5], s1[26]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[6], s1[25]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[7], s1[24]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[8], s1[23]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[9], s1[22]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[10], s1[21]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[11], s1[20]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[12], s2[19]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[13], s2[18]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[14], s2[17]));
output += 8;
vst1q_s16(output, vaddq_s16(s1[15], s2[16]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[15], s2[16]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[14], s2[17]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[13], s2[18]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[12], s2[19]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[11], s1[20]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[10], s1[21]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[9], s1[22]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[8], s1[23]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[7], s1[24]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[6], s1[25]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[5], s1[26]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[4], s1[27]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[3], s2[28]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[2], s2[29]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[1], s2[30]));
output += 8;
vst1q_s16(output, vsubq_s16(s1[0], s2[31]));
}
void vpx_idct32_8_neon(const int16_t *input, void *const output, int stride,
const int highbd_flag) {
int16x8_t in[8], s1[32], s2[32], s3[32], out[32];
load_and_transpose_s16_8x8(input, 8, &in[0], &in[1], &in[2], &in[3], &in[4],
&in[5], &in[6], &in[7]);
// stage 1
s1[16] = multiply_shift_and_narrow_s16(in[1], cospi_31_64);
s1[31] = multiply_shift_and_narrow_s16(in[1], cospi_1_64);
// Different for _8_
s1[19] = multiply_shift_and_narrow_s16(in[7], -cospi_25_64);
s1[28] = multiply_shift_and_narrow_s16(in[7], cospi_7_64);
s1[20] = multiply_shift_and_narrow_s16(in[5], cospi_27_64);
s1[27] = multiply_shift_and_narrow_s16(in[5], cospi_5_64);
s1[23] = multiply_shift_and_narrow_s16(in[3], -cospi_29_64);
s1[24] = multiply_shift_and_narrow_s16(in[3], cospi_3_64);
// stage 2
s2[8] = multiply_shift_and_narrow_s16(in[2], cospi_30_64);
s2[15] = multiply_shift_and_narrow_s16(in[2], cospi_2_64);
s2[11] = multiply_shift_and_narrow_s16(in[6], -cospi_26_64);
s2[12] = multiply_shift_and_narrow_s16(in[6], cospi_6_64);
// stage 3
s1[4] = multiply_shift_and_narrow_s16(in[4], cospi_28_64);
s1[7] = multiply_shift_and_narrow_s16(in[4], cospi_4_64);
s1[17] = multiply_accumulate_shift_and_narrow_s16(s1[16], -cospi_4_64, s1[31],
cospi_28_64);
s1[30] = multiply_accumulate_shift_and_narrow_s16(s1[16], cospi_28_64, s1[31],
cospi_4_64);
// Different for _8_
s1[18] = multiply_accumulate_shift_and_narrow_s16(s1[19], -cospi_28_64,
s1[28], -cospi_4_64);
s1[29] = multiply_accumulate_shift_and_narrow_s16(s1[19], -cospi_4_64, s1[28],
cospi_28_64);
s1[21] = multiply_accumulate_shift_and_narrow_s16(s1[20], -cospi_20_64,
s1[27], cospi_12_64);
s1[26] = multiply_accumulate_shift_and_narrow_s16(s1[20], cospi_12_64, s1[27],
cospi_20_64);
s1[22] = multiply_accumulate_shift_and_narrow_s16(s1[23], -cospi_12_64,
s1[24], -cospi_20_64);
s1[25] = multiply_accumulate_shift_and_narrow_s16(s1[23], -cospi_20_64,
s1[24], cospi_12_64);
// stage 4
s1[0] = multiply_shift_and_narrow_s16(in[0], cospi_16_64);
s2[9] = multiply_accumulate_shift_and_narrow_s16(s2[8], -cospi_8_64, s2[15],
cospi_24_64);
s2[14] = multiply_accumulate_shift_and_narrow_s16(s2[8], cospi_24_64, s2[15],
cospi_8_64);
s2[10] = multiply_accumulate_shift_and_narrow_s16(s2[11], -cospi_24_64,
s2[12], -cospi_8_64);
s2[13] = multiply_accumulate_shift_and_narrow_s16(s2[11], -cospi_8_64, s2[12],
cospi_24_64);
s2[16] = vaddq_s16(s1[16], s1[19]);
s2[17] = vaddq_s16(s1[17], s1[18]);
s2[18] = vsubq_s16(s1[17], s1[18]);
s2[19] = vsubq_s16(s1[16], s1[19]);
s2[20] = vsubq_s16(s1[23], s1[20]);
s2[21] = vsubq_s16(s1[22], s1[21]);
s2[22] = vaddq_s16(s1[21], s1[22]);
s2[23] = vaddq_s16(s1[20], s1[23]);
s2[24] = vaddq_s16(s1[24], s1[27]);
s2[25] = vaddq_s16(s1[25], s1[26]);
s2[26] = vsubq_s16(s1[25], s1[26]);
s2[27] = vsubq_s16(s1[24], s1[27]);
s2[28] = vsubq_s16(s1[31], s1[28]);
s2[29] = vsubq_s16(s1[30], s1[29]);
s2[30] = vaddq_s16(s1[29], s1[30]);
s2[31] = vaddq_s16(s1[28], s1[31]);
// stage 5
s1[5] = sub_multiply_shift_and_narrow_s16(s1[7], s1[4], cospi_16_64);
s1[6] = add_multiply_shift_and_narrow_s16(s1[4], s1[7], cospi_16_64);
s1[8] = vaddq_s16(s2[8], s2[11]);
s1[9] = vaddq_s16(s2[9], s2[10]);
s1[10] = vsubq_s16(s2[9], s2[10]);
s1[11] = vsubq_s16(s2[8], s2[11]);
s1[12] = vsubq_s16(s2[15], s2[12]);
s1[13] = vsubq_s16(s2[14], s2[13]);
s1[14] = vaddq_s16(s2[13], s2[14]);
s1[15] = vaddq_s16(s2[12], s2[15]);
s1[18] = multiply_accumulate_shift_and_narrow_s16(s2[18], -cospi_8_64, s2[29],
cospi_24_64);
s1[29] = multiply_accumulate_shift_and_narrow_s16(s2[18], cospi_24_64, s2[29],
cospi_8_64);
s1[19] = multiply_accumulate_shift_and_narrow_s16(s2[19], -cospi_8_64, s2[28],
cospi_24_64);
s1[28] = multiply_accumulate_shift_and_narrow_s16(s2[19], cospi_24_64, s2[28],
cospi_8_64);
s1[20] = multiply_accumulate_shift_and_narrow_s16(s2[20], -cospi_24_64,
s2[27], -cospi_8_64);
s1[27] = multiply_accumulate_shift_and_narrow_s16(s2[20], -cospi_8_64, s2[27],
cospi_24_64);
s1[21] = multiply_accumulate_shift_and_narrow_s16(s2[21], -cospi_24_64,
s2[26], -cospi_8_64);
s1[26] = multiply_accumulate_shift_and_narrow_s16(s2[21], -cospi_8_64, s2[26],
cospi_24_64);
// stage 6
s2[0] = vaddq_s16(s1[0], s1[7]);
s2[1] = vaddq_s16(s1[0], s1[6]);
s2[2] = vaddq_s16(s1[0], s1[5]);
s2[3] = vaddq_s16(s1[0], s1[4]);
s2[4] = vsubq_s16(s1[0], s1[4]);
s2[5] = vsubq_s16(s1[0], s1[5]);
s2[6] = vsubq_s16(s1[0], s1[6]);
s2[7] = vsubq_s16(s1[0], s1[7]);
s2[10] = sub_multiply_shift_and_narrow_s16(s1[13], s1[10], cospi_16_64);
s2[13] = add_multiply_shift_and_narrow_s16(s1[10], s1[13], cospi_16_64);
s2[11] = sub_multiply_shift_and_narrow_s16(s1[12], s1[11], cospi_16_64);
s2[12] = add_multiply_shift_and_narrow_s16(s1[11], s1[12], cospi_16_64);
s1[16] = vaddq_s16(s2[16], s2[23]);
s1[17] = vaddq_s16(s2[17], s2[22]);
s2[18] = vaddq_s16(s1[18], s1[21]);
s2[19] = vaddq_s16(s1[19], s1[20]);
s2[20] = vsubq_s16(s1[19], s1[20]);
s2[21] = vsubq_s16(s1[18], s1[21]);
s1[22] = vsubq_s16(s2[17], s2[22]);
s1[23] = vsubq_s16(s2[16], s2[23]);
s3[24] = vsubq_s16(s2[31], s2[24]);
s3[25] = vsubq_s16(s2[30], s2[25]);
s3[26] = vsubq_s16(s1[29], s1[26]);
s3[27] = vsubq_s16(s1[28], s1[27]);
s2[28] = vaddq_s16(s1[27], s1[28]);
s2[29] = vaddq_s16(s1[26], s1[29]);
s2[30] = vaddq_s16(s2[25], s2[30]);
s2[31] = vaddq_s16(s2[24], s2[31]);
// stage 7
s1[0] = vaddq_s16(s2[0], s1[15]);
s1[1] = vaddq_s16(s2[1], s1[14]);
s1[2] = vaddq_s16(s2[2], s2[13]);
s1[3] = vaddq_s16(s2[3], s2[12]);
s1[4] = vaddq_s16(s2[4], s2[11]);
s1[5] = vaddq_s16(s2[5], s2[10]);
s1[6] = vaddq_s16(s2[6], s1[9]);
s1[7] = vaddq_s16(s2[7], s1[8]);
s1[8] = vsubq_s16(s2[7], s1[8]);
s1[9] = vsubq_s16(s2[6], s1[9]);
s1[10] = vsubq_s16(s2[5], s2[10]);
s1[11] = vsubq_s16(s2[4], s2[11]);
s1[12] = vsubq_s16(s2[3], s2[12]);
s1[13] = vsubq_s16(s2[2], s2[13]);
s1[14] = vsubq_s16(s2[1], s1[14]);
s1[15] = vsubq_s16(s2[0], s1[15]);
s1[20] = sub_multiply_shift_and_narrow_s16(s3[27], s2[20], cospi_16_64);
s1[27] = add_multiply_shift_and_narrow_s16(s2[20], s3[27], cospi_16_64);
s1[21] = sub_multiply_shift_and_narrow_s16(s3[26], s2[21], cospi_16_64);
s1[26] = add_multiply_shift_and_narrow_s16(s2[21], s3[26], cospi_16_64);
s2[22] = sub_multiply_shift_and_narrow_s16(s3[25], s1[22], cospi_16_64);
s1[25] = add_multiply_shift_and_narrow_s16(s1[22], s3[25], cospi_16_64);
s2[23] = sub_multiply_shift_and_narrow_s16(s3[24], s1[23], cospi_16_64);
s1[24] = add_multiply_shift_and_narrow_s16(s1[23], s3[24], cospi_16_64);
// final stage
out[0] = final_add(s1[0], s2[31]);
out[1] = final_add(s1[1], s2[30]);
out[2] = final_add(s1[2], s2[29]);
out[3] = final_add(s1[3], s2[28]);
out[4] = final_add(s1[4], s1[27]);
out[5] = final_add(s1[5], s1[26]);
out[6] = final_add(s1[6], s1[25]);
out[7] = final_add(s1[7], s1[24]);
out[8] = final_add(s1[8], s2[23]);
out[9] = final_add(s1[9], s2[22]);
out[10] = final_add(s1[10], s1[21]);
out[11] = final_add(s1[11], s1[20]);
out[12] = final_add(s1[12], s2[19]);
out[13] = final_add(s1[13], s2[18]);
out[14] = final_add(s1[14], s1[17]);
out[15] = final_add(s1[15], s1[16]);
out[16] = final_sub(s1[15], s1[16]);
out[17] = final_sub(s1[14], s1[17]);
out[18] = final_sub(s1[13], s2[18]);
out[19] = final_sub(s1[12], s2[19]);
out[20] = final_sub(s1[11], s1[20]);
out[21] = final_sub(s1[10], s1[21]);
out[22] = final_sub(s1[9], s2[22]);
out[23] = final_sub(s1[8], s2[23]);
out[24] = final_sub(s1[7], s1[24]);
out[25] = final_sub(s1[6], s1[25]);
out[26] = final_sub(s1[5], s1[26]);
out[27] = final_sub(s1[4], s1[27]);
out[28] = final_sub(s1[3], s2[28]);
out[29] = final_sub(s1[2], s2[29]);
out[30] = final_sub(s1[1], s2[30]);
out[31] = final_sub(s1[0], s2[31]);
if (highbd_flag) {
highbd_add_and_store_bd8(out, output, stride);
} else {
uint8_t *const outputT = (uint8_t *)output;
add_and_store_u8_s16(out + 0, outputT, stride);
add_and_store_u8_s16(out + 8, outputT + (8 * stride), stride);
add_and_store_u8_s16(out + 16, outputT + (16 * stride), stride);
add_and_store_u8_s16(out + 24, outputT + (24 * stride), stride);
}
}
void vpx_idct32x32_34_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
int i;
int16_t temp[32 * 8];
int16_t *t = temp;
vpx_idct32_6_neon(input, t);
for (i = 0; i < 32; i += 8) {
vpx_idct32_8_neon(t, dest, stride, 0);
t += (8 * 8);
dest += 8;
}
}
@@ -0,0 +1,776 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/transpose_neon.h"
#include "vpx_dsp/txfm_common.h"
static INLINE void load_from_transformed(const int16_t *const trans_buf,
const int first, const int second,
int16x8_t *const q0,
int16x8_t *const q1) {
*q0 = vld1q_s16(trans_buf + first * 8);
*q1 = vld1q_s16(trans_buf + second * 8);
}
static INLINE void load_from_output(const int16_t *const out, const int first,
const int second, int16x8_t *const q0,
int16x8_t *const q1) {
*q0 = vld1q_s16(out + first * 32);
*q1 = vld1q_s16(out + second * 32);
}
static INLINE void store_in_output(int16_t *const out, const int first,
const int second, const int16x8_t q0,
const int16x8_t q1) {
vst1q_s16(out + first * 32, q0);
vst1q_s16(out + second * 32, q1);
}
static INLINE void store_combine_results(uint8_t *p1, uint8_t *p2,
const int stride, int16x8_t q0,
int16x8_t q1, int16x8_t q2,
int16x8_t q3) {
uint8x8_t d[4];
d[0] = vld1_u8(p1);
p1 += stride;
d[1] = vld1_u8(p1);
d[3] = vld1_u8(p2);
p2 -= stride;
d[2] = vld1_u8(p2);
q0 = vrshrq_n_s16(q0, 6);
q1 = vrshrq_n_s16(q1, 6);
q2 = vrshrq_n_s16(q2, 6);
q3 = vrshrq_n_s16(q3, 6);
q0 = vreinterpretq_s16_u16(vaddw_u8(vreinterpretq_u16_s16(q0), d[0]));
q1 = vreinterpretq_s16_u16(vaddw_u8(vreinterpretq_u16_s16(q1), d[1]));
q2 = vreinterpretq_s16_u16(vaddw_u8(vreinterpretq_u16_s16(q2), d[2]));
q3 = vreinterpretq_s16_u16(vaddw_u8(vreinterpretq_u16_s16(q3), d[3]));
d[0] = vqmovun_s16(q0);
d[1] = vqmovun_s16(q1);
d[2] = vqmovun_s16(q2);
d[3] = vqmovun_s16(q3);
vst1_u8(p1, d[1]);
p1 -= stride;
vst1_u8(p1, d[0]);
vst1_u8(p2, d[2]);
p2 += stride;
vst1_u8(p2, d[3]);
}
static INLINE void highbd_store_combine_results_bd8(uint16_t *p1, uint16_t *p2,
const int stride,
int16x8_t q0, int16x8_t q1,
int16x8_t q2,
int16x8_t q3) {
uint16x8_t d[4];
d[0] = vld1q_u16(p1);
p1 += stride;
d[1] = vld1q_u16(p1);
d[3] = vld1q_u16(p2);
p2 -= stride;
d[2] = vld1q_u16(p2);
q0 = vrshrq_n_s16(q0, 6);
q1 = vrshrq_n_s16(q1, 6);
q2 = vrshrq_n_s16(q2, 6);
q3 = vrshrq_n_s16(q3, 6);
q0 = vaddq_s16(q0, vreinterpretq_s16_u16(d[0]));
q1 = vaddq_s16(q1, vreinterpretq_s16_u16(d[1]));
q2 = vaddq_s16(q2, vreinterpretq_s16_u16(d[2]));
q3 = vaddq_s16(q3, vreinterpretq_s16_u16(d[3]));
d[0] = vmovl_u8(vqmovun_s16(q0));
d[1] = vmovl_u8(vqmovun_s16(q1));
d[2] = vmovl_u8(vqmovun_s16(q2));
d[3] = vmovl_u8(vqmovun_s16(q3));
vst1q_u16(p1, d[1]);
p1 -= stride;
vst1q_u16(p1, d[0]);
vst1q_u16(p2, d[2]);
p2 += stride;
vst1q_u16(p2, d[3]);
}
static INLINE void do_butterfly(const int16x8_t qIn0, const int16x8_t qIn1,
const int16_t first_const,
const int16_t second_const,
int16x8_t *const qOut0,
int16x8_t *const qOut1) {
int32x4_t q[4];
int16x4_t d[6];
d[0] = vget_low_s16(qIn0);
d[1] = vget_high_s16(qIn0);
d[2] = vget_low_s16(qIn1);
d[3] = vget_high_s16(qIn1);
// Note: using v{mul, mla, mls}l_n_s16 here slows down 35% with gcc 4.9.
d[4] = vdup_n_s16(first_const);
d[5] = vdup_n_s16(second_const);
q[0] = vmull_s16(d[0], d[4]);
q[1] = vmull_s16(d[1], d[4]);
q[0] = vmlsl_s16(q[0], d[2], d[5]);
q[1] = vmlsl_s16(q[1], d[3], d[5]);
q[2] = vmull_s16(d[0], d[5]);
q[3] = vmull_s16(d[1], d[5]);
q[2] = vmlal_s16(q[2], d[2], d[4]);
q[3] = vmlal_s16(q[3], d[3], d[4]);
*qOut0 = vcombine_s16(vrshrn_n_s32(q[0], DCT_CONST_BITS),
vrshrn_n_s32(q[1], DCT_CONST_BITS));
*qOut1 = vcombine_s16(vrshrn_n_s32(q[2], DCT_CONST_BITS),
vrshrn_n_s32(q[3], DCT_CONST_BITS));
}
static INLINE void load_s16x8q(const int16_t *in, int16x8_t *const s0,
int16x8_t *const s1, int16x8_t *const s2,
int16x8_t *const s3, int16x8_t *const s4,
int16x8_t *const s5, int16x8_t *const s6,
int16x8_t *const s7) {
*s0 = vld1q_s16(in);
in += 32;
*s1 = vld1q_s16(in);
in += 32;
*s2 = vld1q_s16(in);
in += 32;
*s3 = vld1q_s16(in);
in += 32;
*s4 = vld1q_s16(in);
in += 32;
*s5 = vld1q_s16(in);
in += 32;
*s6 = vld1q_s16(in);
in += 32;
*s7 = vld1q_s16(in);
}
static INLINE void transpose_and_store_s16_8x8(int16x8_t a0, int16x8_t a1,
int16x8_t a2, int16x8_t a3,
int16x8_t a4, int16x8_t a5,
int16x8_t a6, int16x8_t a7,
int16_t **out) {
transpose_s16_8x8(&a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7);
vst1q_s16(*out, a0);
*out += 8;
vst1q_s16(*out, a1);
*out += 8;
vst1q_s16(*out, a2);
*out += 8;
vst1q_s16(*out, a3);
*out += 8;
vst1q_s16(*out, a4);
*out += 8;
vst1q_s16(*out, a5);
*out += 8;
vst1q_s16(*out, a6);
*out += 8;
vst1q_s16(*out, a7);
*out += 8;
}
static INLINE void idct32_transpose_pair(const int16_t *input, int16_t *t_buf) {
int i;
int16x8_t s0, s1, s2, s3, s4, s5, s6, s7;
for (i = 0; i < 4; i++, input += 8) {
load_s16x8q(input, &s0, &s1, &s2, &s3, &s4, &s5, &s6, &s7);
transpose_and_store_s16_8x8(s0, s1, s2, s3, s4, s5, s6, s7, &t_buf);
}
}
#if CONFIG_VP9_HIGHBITDEPTH
static INLINE void load_s16x8q_tran_low(
const tran_low_t *in, int16x8_t *const s0, int16x8_t *const s1,
int16x8_t *const s2, int16x8_t *const s3, int16x8_t *const s4,
int16x8_t *const s5, int16x8_t *const s6, int16x8_t *const s7) {
*s0 = load_tran_low_to_s16q(in);
in += 32;
*s1 = load_tran_low_to_s16q(in);
in += 32;
*s2 = load_tran_low_to_s16q(in);
in += 32;
*s3 = load_tran_low_to_s16q(in);
in += 32;
*s4 = load_tran_low_to_s16q(in);
in += 32;
*s5 = load_tran_low_to_s16q(in);
in += 32;
*s6 = load_tran_low_to_s16q(in);
in += 32;
*s7 = load_tran_low_to_s16q(in);
}
static INLINE void idct32_transpose_pair_tran_low(const tran_low_t *input,
int16_t *t_buf) {
int i;
int16x8_t s0, s1, s2, s3, s4, s5, s6, s7;
for (i = 0; i < 4; i++, input += 8) {
load_s16x8q_tran_low(input, &s0, &s1, &s2, &s3, &s4, &s5, &s6, &s7);
transpose_and_store_s16_8x8(s0, s1, s2, s3, s4, s5, s6, s7, &t_buf);
}
}
#else // !CONFIG_VP9_HIGHBITDEPTH
#define idct32_transpose_pair_tran_low idct32_transpose_pair
#endif // CONFIG_VP9_HIGHBITDEPTH
static INLINE void idct32_bands_end_1st_pass(int16_t *const out,
int16x8_t *const q) {
store_in_output(out, 16, 17, q[6], q[7]);
store_in_output(out, 14, 15, q[8], q[9]);
load_from_output(out, 30, 31, &q[0], &q[1]);
q[4] = vaddq_s16(q[2], q[1]);
q[5] = vaddq_s16(q[3], q[0]);
q[6] = vsubq_s16(q[3], q[0]);
q[7] = vsubq_s16(q[2], q[1]);
store_in_output(out, 30, 31, q[6], q[7]);
store_in_output(out, 0, 1, q[4], q[5]);
load_from_output(out, 12, 13, &q[0], &q[1]);
q[2] = vaddq_s16(q[10], q[1]);
q[3] = vaddq_s16(q[11], q[0]);
q[4] = vsubq_s16(q[11], q[0]);
q[5] = vsubq_s16(q[10], q[1]);
load_from_output(out, 18, 19, &q[0], &q[1]);
q[8] = vaddq_s16(q[4], q[1]);
q[9] = vaddq_s16(q[5], q[0]);
q[6] = vsubq_s16(q[5], q[0]);
q[7] = vsubq_s16(q[4], q[1]);
store_in_output(out, 18, 19, q[6], q[7]);
store_in_output(out, 12, 13, q[8], q[9]);
load_from_output(out, 28, 29, &q[0], &q[1]);
q[4] = vaddq_s16(q[2], q[1]);
q[5] = vaddq_s16(q[3], q[0]);
q[6] = vsubq_s16(q[3], q[0]);
q[7] = vsubq_s16(q[2], q[1]);
store_in_output(out, 28, 29, q[6], q[7]);
store_in_output(out, 2, 3, q[4], q[5]);
load_from_output(out, 10, 11, &q[0], &q[1]);
q[2] = vaddq_s16(q[12], q[1]);
q[3] = vaddq_s16(q[13], q[0]);
q[4] = vsubq_s16(q[13], q[0]);
q[5] = vsubq_s16(q[12], q[1]);
load_from_output(out, 20, 21, &q[0], &q[1]);
q[8] = vaddq_s16(q[4], q[1]);
q[9] = vaddq_s16(q[5], q[0]);
q[6] = vsubq_s16(q[5], q[0]);
q[7] = vsubq_s16(q[4], q[1]);
store_in_output(out, 20, 21, q[6], q[7]);
store_in_output(out, 10, 11, q[8], q[9]);
load_from_output(out, 26, 27, &q[0], &q[1]);
q[4] = vaddq_s16(q[2], q[1]);
q[5] = vaddq_s16(q[3], q[0]);
q[6] = vsubq_s16(q[3], q[0]);
q[7] = vsubq_s16(q[2], q[1]);
store_in_output(out, 26, 27, q[6], q[7]);
store_in_output(out, 4, 5, q[4], q[5]);
load_from_output(out, 8, 9, &q[0], &q[1]);
q[2] = vaddq_s16(q[14], q[1]);
q[3] = vaddq_s16(q[15], q[0]);
q[4] = vsubq_s16(q[15], q[0]);
q[5] = vsubq_s16(q[14], q[1]);
load_from_output(out, 22, 23, &q[0], &q[1]);
q[8] = vaddq_s16(q[4], q[1]);
q[9] = vaddq_s16(q[5], q[0]);
q[6] = vsubq_s16(q[5], q[0]);
q[7] = vsubq_s16(q[4], q[1]);
store_in_output(out, 22, 23, q[6], q[7]);
store_in_output(out, 8, 9, q[8], q[9]);
load_from_output(out, 24, 25, &q[0], &q[1]);
q[4] = vaddq_s16(q[2], q[1]);
q[5] = vaddq_s16(q[3], q[0]);
q[6] = vsubq_s16(q[3], q[0]);
q[7] = vsubq_s16(q[2], q[1]);
store_in_output(out, 24, 25, q[6], q[7]);
store_in_output(out, 6, 7, q[4], q[5]);
}
static INLINE void idct32_bands_end_2nd_pass(const int16_t *const out,
uint8_t *const dest,
const int stride,
int16x8_t *const q) {
uint8_t *dest0 = dest + 0 * stride;
uint8_t *dest1 = dest + 31 * stride;
uint8_t *dest2 = dest + 16 * stride;
uint8_t *dest3 = dest + 15 * stride;
const int str2 = stride << 1;
store_combine_results(dest2, dest3, stride, q[6], q[7], q[8], q[9]);
dest2 += str2;
dest3 -= str2;
load_from_output(out, 30, 31, &q[0], &q[1]);
q[4] = final_add(q[2], q[1]);
q[5] = final_add(q[3], q[0]);
q[6] = final_sub(q[3], q[0]);
q[7] = final_sub(q[2], q[1]);
store_combine_results(dest0, dest1, stride, q[4], q[5], q[6], q[7]);
dest0 += str2;
dest1 -= str2;
load_from_output(out, 12, 13, &q[0], &q[1]);
q[2] = vaddq_s16(q[10], q[1]);
q[3] = vaddq_s16(q[11], q[0]);
q[4] = vsubq_s16(q[11], q[0]);
q[5] = vsubq_s16(q[10], q[1]);
load_from_output(out, 18, 19, &q[0], &q[1]);
q[8] = final_add(q[4], q[1]);
q[9] = final_add(q[5], q[0]);
q[6] = final_sub(q[5], q[0]);
q[7] = final_sub(q[4], q[1]);
store_combine_results(dest2, dest3, stride, q[6], q[7], q[8], q[9]);
dest2 += str2;
dest3 -= str2;
load_from_output(out, 28, 29, &q[0], &q[1]);
q[4] = final_add(q[2], q[1]);
q[5] = final_add(q[3], q[0]);
q[6] = final_sub(q[3], q[0]);
q[7] = final_sub(q[2], q[1]);
store_combine_results(dest0, dest1, stride, q[4], q[5], q[6], q[7]);
dest0 += str2;
dest1 -= str2;
load_from_output(out, 10, 11, &q[0], &q[1]);
q[2] = vaddq_s16(q[12], q[1]);
q[3] = vaddq_s16(q[13], q[0]);
q[4] = vsubq_s16(q[13], q[0]);
q[5] = vsubq_s16(q[12], q[1]);
load_from_output(out, 20, 21, &q[0], &q[1]);
q[8] = final_add(q[4], q[1]);
q[9] = final_add(q[5], q[0]);
q[6] = final_sub(q[5], q[0]);
q[7] = final_sub(q[4], q[1]);
store_combine_results(dest2, dest3, stride, q[6], q[7], q[8], q[9]);
dest2 += str2;
dest3 -= str2;
load_from_output(out, 26, 27, &q[0], &q[1]);
q[4] = final_add(q[2], q[1]);
q[5] = final_add(q[3], q[0]);
q[6] = final_sub(q[3], q[0]);
q[7] = final_sub(q[2], q[1]);
store_combine_results(dest0, dest1, stride, q[4], q[5], q[6], q[7]);
dest0 += str2;
dest1 -= str2;
load_from_output(out, 8, 9, &q[0], &q[1]);
q[2] = vaddq_s16(q[14], q[1]);
q[3] = vaddq_s16(q[15], q[0]);
q[4] = vsubq_s16(q[15], q[0]);
q[5] = vsubq_s16(q[14], q[1]);
load_from_output(out, 22, 23, &q[0], &q[1]);
q[8] = final_add(q[4], q[1]);
q[9] = final_add(q[5], q[0]);
q[6] = final_sub(q[5], q[0]);
q[7] = final_sub(q[4], q[1]);
store_combine_results(dest2, dest3, stride, q[6], q[7], q[8], q[9]);
load_from_output(out, 24, 25, &q[0], &q[1]);
q[4] = final_add(q[2], q[1]);
q[5] = final_add(q[3], q[0]);
q[6] = final_sub(q[3], q[0]);
q[7] = final_sub(q[2], q[1]);
store_combine_results(dest0, dest1, stride, q[4], q[5], q[6], q[7]);
}
static INLINE void highbd_idct32_bands_end_2nd_pass_bd8(
const int16_t *const out, uint16_t *const dest, const int stride,
int16x8_t *const q) {
uint16_t *dest0 = dest + 0 * stride;
uint16_t *dest1 = dest + 31 * stride;
uint16_t *dest2 = dest + 16 * stride;
uint16_t *dest3 = dest + 15 * stride;
const int str2 = stride << 1;
highbd_store_combine_results_bd8(dest2, dest3, stride, q[6], q[7], q[8],
q[9]);
dest2 += str2;
dest3 -= str2;
load_from_output(out, 30, 31, &q[0], &q[1]);
q[4] = final_add(q[2], q[1]);
q[5] = final_add(q[3], q[0]);
q[6] = final_sub(q[3], q[0]);
q[7] = final_sub(q[2], q[1]);
highbd_store_combine_results_bd8(dest0, dest1, stride, q[4], q[5], q[6],
q[7]);
dest0 += str2;
dest1 -= str2;
load_from_output(out, 12, 13, &q[0], &q[1]);
q[2] = vaddq_s16(q[10], q[1]);
q[3] = vaddq_s16(q[11], q[0]);
q[4] = vsubq_s16(q[11], q[0]);
q[5] = vsubq_s16(q[10], q[1]);
load_from_output(out, 18, 19, &q[0], &q[1]);
q[8] = final_add(q[4], q[1]);
q[9] = final_add(q[5], q[0]);
q[6] = final_sub(q[5], q[0]);
q[7] = final_sub(q[4], q[1]);
highbd_store_combine_results_bd8(dest2, dest3, stride, q[6], q[7], q[8],
q[9]);
dest2 += str2;
dest3 -= str2;
load_from_output(out, 28, 29, &q[0], &q[1]);
q[4] = final_add(q[2], q[1]);
q[5] = final_add(q[3], q[0]);
q[6] = final_sub(q[3], q[0]);
q[7] = final_sub(q[2], q[1]);
highbd_store_combine_results_bd8(dest0, dest1, stride, q[4], q[5], q[6],
q[7]);
dest0 += str2;
dest1 -= str2;
load_from_output(out, 10, 11, &q[0], &q[1]);
q[2] = vaddq_s16(q[12], q[1]);
q[3] = vaddq_s16(q[13], q[0]);
q[4] = vsubq_s16(q[13], q[0]);
q[5] = vsubq_s16(q[12], q[1]);
load_from_output(out, 20, 21, &q[0], &q[1]);
q[8] = final_add(q[4], q[1]);
q[9] = final_add(q[5], q[0]);
q[6] = final_sub(q[5], q[0]);
q[7] = final_sub(q[4], q[1]);
highbd_store_combine_results_bd8(dest2, dest3, stride, q[6], q[7], q[8],
q[9]);
dest2 += str2;
dest3 -= str2;
load_from_output(out, 26, 27, &q[0], &q[1]);
q[4] = final_add(q[2], q[1]);
q[5] = final_add(q[3], q[0]);
q[6] = final_sub(q[3], q[0]);
q[7] = final_sub(q[2], q[1]);
highbd_store_combine_results_bd8(dest0, dest1, stride, q[4], q[5], q[6],
q[7]);
dest0 += str2;
dest1 -= str2;
load_from_output(out, 8, 9, &q[0], &q[1]);
q[2] = vaddq_s16(q[14], q[1]);
q[3] = vaddq_s16(q[15], q[0]);
q[4] = vsubq_s16(q[15], q[0]);
q[5] = vsubq_s16(q[14], q[1]);
load_from_output(out, 22, 23, &q[0], &q[1]);
q[8] = final_add(q[4], q[1]);
q[9] = final_add(q[5], q[0]);
q[6] = final_sub(q[5], q[0]);
q[7] = final_sub(q[4], q[1]);
highbd_store_combine_results_bd8(dest2, dest3, stride, q[6], q[7], q[8],
q[9]);
load_from_output(out, 24, 25, &q[0], &q[1]);
q[4] = final_add(q[2], q[1]);
q[5] = final_add(q[3], q[0]);
q[6] = final_sub(q[3], q[0]);
q[7] = final_sub(q[2], q[1]);
highbd_store_combine_results_bd8(dest0, dest1, stride, q[4], q[5], q[6],
q[7]);
}
void vpx_idct32_32_neon(const tran_low_t *input, uint8_t *dest,
const int stride, const int highbd_flag) {
int i, idct32_pass_loop;
int16_t trans_buf[32 * 8];
int16_t pass1[32 * 32];
int16_t pass2[32 * 32];
const int16_t *input_pass2 = pass1; // input of pass2 is the result of pass1
int16_t *out;
int16x8_t q[16];
uint16_t *dst = CAST_TO_SHORTPTR(dest);
for (idct32_pass_loop = 0, out = pass1; idct32_pass_loop < 2;
idct32_pass_loop++, out = pass2) {
for (i = 0; i < 4; i++, out += 8) { // idct32_bands_loop
if (idct32_pass_loop == 0) {
idct32_transpose_pair_tran_low(input, trans_buf);
input += 32 * 8;
} else {
idct32_transpose_pair(input_pass2, trans_buf);
input_pass2 += 32 * 8;
}
// -----------------------------------------
// BLOCK A: 16-19,28-31
// -----------------------------------------
// generate 16,17,30,31
// part of stage 1
load_from_transformed(trans_buf, 1, 31, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_31_64, cospi_1_64, &q[0], &q[2]);
load_from_transformed(trans_buf, 17, 15, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_15_64, cospi_17_64, &q[1], &q[3]);
// part of stage 2
q[4] = vaddq_s16(q[0], q[1]);
q[13] = vsubq_s16(q[0], q[1]);
q[6] = vaddq_s16(q[2], q[3]);
q[14] = vsubq_s16(q[2], q[3]);
// part of stage 3
do_butterfly(q[14], q[13], cospi_28_64, cospi_4_64, &q[5], &q[7]);
// generate 18,19,28,29
// part of stage 1
load_from_transformed(trans_buf, 9, 23, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_23_64, cospi_9_64, &q[0], &q[2]);
load_from_transformed(trans_buf, 25, 7, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_7_64, cospi_25_64, &q[1], &q[3]);
// part of stage 2
q[13] = vsubq_s16(q[3], q[2]);
q[3] = vaddq_s16(q[3], q[2]);
q[14] = vsubq_s16(q[1], q[0]);
q[2] = vaddq_s16(q[1], q[0]);
// part of stage 3
do_butterfly(q[14], q[13], -cospi_4_64, -cospi_28_64, &q[1], &q[0]);
// part of stage 4
q[8] = vaddq_s16(q[4], q[2]);
q[9] = vaddq_s16(q[5], q[0]);
q[10] = vaddq_s16(q[7], q[1]);
q[15] = vaddq_s16(q[6], q[3]);
q[13] = vsubq_s16(q[5], q[0]);
q[14] = vsubq_s16(q[7], q[1]);
store_in_output(out, 16, 31, q[8], q[15]);
store_in_output(out, 17, 30, q[9], q[10]);
// part of stage 5
do_butterfly(q[14], q[13], cospi_24_64, cospi_8_64, &q[0], &q[1]);
store_in_output(out, 29, 18, q[1], q[0]);
// part of stage 4
q[13] = vsubq_s16(q[4], q[2]);
q[14] = vsubq_s16(q[6], q[3]);
// part of stage 5
do_butterfly(q[14], q[13], cospi_24_64, cospi_8_64, &q[4], &q[6]);
store_in_output(out, 19, 28, q[4], q[6]);
// -----------------------------------------
// BLOCK B: 20-23,24-27
// -----------------------------------------
// generate 20,21,26,27
// part of stage 1
load_from_transformed(trans_buf, 5, 27, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_27_64, cospi_5_64, &q[0], &q[2]);
load_from_transformed(trans_buf, 21, 11, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_11_64, cospi_21_64, &q[1], &q[3]);
// part of stage 2
q[13] = vsubq_s16(q[0], q[1]);
q[0] = vaddq_s16(q[0], q[1]);
q[14] = vsubq_s16(q[2], q[3]);
q[2] = vaddq_s16(q[2], q[3]);
// part of stage 3
do_butterfly(q[14], q[13], cospi_12_64, cospi_20_64, &q[1], &q[3]);
// generate 22,23,24,25
// part of stage 1
load_from_transformed(trans_buf, 13, 19, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_19_64, cospi_13_64, &q[5], &q[7]);
load_from_transformed(trans_buf, 29, 3, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_3_64, cospi_29_64, &q[4], &q[6]);
// part of stage 2
q[14] = vsubq_s16(q[4], q[5]);
q[5] = vaddq_s16(q[4], q[5]);
q[13] = vsubq_s16(q[6], q[7]);
q[6] = vaddq_s16(q[6], q[7]);
// part of stage 3
do_butterfly(q[14], q[13], -cospi_20_64, -cospi_12_64, &q[4], &q[7]);
// part of stage 4
q[10] = vaddq_s16(q[7], q[1]);
q[11] = vaddq_s16(q[5], q[0]);
q[12] = vaddq_s16(q[6], q[2]);
q[15] = vaddq_s16(q[4], q[3]);
// part of stage 6
load_from_output(out, 16, 17, &q[14], &q[13]);
q[8] = vaddq_s16(q[14], q[11]);
q[9] = vaddq_s16(q[13], q[10]);
q[13] = vsubq_s16(q[13], q[10]);
q[11] = vsubq_s16(q[14], q[11]);
store_in_output(out, 17, 16, q[9], q[8]);
load_from_output(out, 30, 31, &q[14], &q[9]);
q[8] = vsubq_s16(q[9], q[12]);
q[10] = vaddq_s16(q[14], q[15]);
q[14] = vsubq_s16(q[14], q[15]);
q[12] = vaddq_s16(q[9], q[12]);
store_in_output(out, 30, 31, q[10], q[12]);
// part of stage 7
do_butterfly(q[14], q[13], cospi_16_64, cospi_16_64, &q[13], &q[14]);
store_in_output(out, 25, 22, q[14], q[13]);
do_butterfly(q[8], q[11], cospi_16_64, cospi_16_64, &q[13], &q[14]);
store_in_output(out, 24, 23, q[14], q[13]);
// part of stage 4
q[14] = vsubq_s16(q[5], q[0]);
q[13] = vsubq_s16(q[6], q[2]);
do_butterfly(q[14], q[13], -cospi_8_64, -cospi_24_64, &q[5], &q[6]);
q[14] = vsubq_s16(q[7], q[1]);
q[13] = vsubq_s16(q[4], q[3]);
do_butterfly(q[14], q[13], -cospi_8_64, -cospi_24_64, &q[0], &q[1]);
// part of stage 6
load_from_output(out, 18, 19, &q[14], &q[13]);
q[8] = vaddq_s16(q[14], q[1]);
q[9] = vaddq_s16(q[13], q[6]);
q[13] = vsubq_s16(q[13], q[6]);
q[1] = vsubq_s16(q[14], q[1]);
store_in_output(out, 18, 19, q[8], q[9]);
load_from_output(out, 28, 29, &q[8], &q[9]);
q[14] = vsubq_s16(q[8], q[5]);
q[10] = vaddq_s16(q[8], q[5]);
q[11] = vaddq_s16(q[9], q[0]);
q[0] = vsubq_s16(q[9], q[0]);
store_in_output(out, 28, 29, q[10], q[11]);
// part of stage 7
do_butterfly(q[14], q[13], cospi_16_64, cospi_16_64, &q[13], &q[14]);
store_in_output(out, 20, 27, q[13], q[14]);
do_butterfly(q[0], q[1], cospi_16_64, cospi_16_64, &q[1], &q[0]);
store_in_output(out, 21, 26, q[1], q[0]);
// -----------------------------------------
// BLOCK C: 8-10,11-15
// -----------------------------------------
// generate 8,9,14,15
// part of stage 2
load_from_transformed(trans_buf, 2, 30, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_30_64, cospi_2_64, &q[0], &q[2]);
load_from_transformed(trans_buf, 18, 14, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_14_64, cospi_18_64, &q[1], &q[3]);
// part of stage 3
q[13] = vsubq_s16(q[0], q[1]);
q[0] = vaddq_s16(q[0], q[1]);
q[14] = vsubq_s16(q[2], q[3]);
q[2] = vaddq_s16(q[2], q[3]);
// part of stage 4
do_butterfly(q[14], q[13], cospi_24_64, cospi_8_64, &q[1], &q[3]);
// generate 10,11,12,13
// part of stage 2
load_from_transformed(trans_buf, 10, 22, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_22_64, cospi_10_64, &q[5], &q[7]);
load_from_transformed(trans_buf, 26, 6, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_6_64, cospi_26_64, &q[4], &q[6]);
// part of stage 3
q[14] = vsubq_s16(q[4], q[5]);
q[5] = vaddq_s16(q[4], q[5]);
q[13] = vsubq_s16(q[6], q[7]);
q[6] = vaddq_s16(q[6], q[7]);
// part of stage 4
do_butterfly(q[14], q[13], -cospi_8_64, -cospi_24_64, &q[4], &q[7]);
// part of stage 5
q[8] = vaddq_s16(q[0], q[5]);
q[9] = vaddq_s16(q[1], q[7]);
q[13] = vsubq_s16(q[1], q[7]);
q[14] = vsubq_s16(q[3], q[4]);
q[10] = vaddq_s16(q[3], q[4]);
q[15] = vaddq_s16(q[2], q[6]);
store_in_output(out, 8, 15, q[8], q[15]);
store_in_output(out, 9, 14, q[9], q[10]);
// part of stage 6
do_butterfly(q[14], q[13], cospi_16_64, cospi_16_64, &q[1], &q[3]);
store_in_output(out, 13, 10, q[3], q[1]);
q[13] = vsubq_s16(q[0], q[5]);
q[14] = vsubq_s16(q[2], q[6]);
do_butterfly(q[14], q[13], cospi_16_64, cospi_16_64, &q[1], &q[3]);
store_in_output(out, 11, 12, q[1], q[3]);
// -----------------------------------------
// BLOCK D: 0-3,4-7
// -----------------------------------------
// generate 4,5,6,7
// part of stage 3
load_from_transformed(trans_buf, 4, 28, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_28_64, cospi_4_64, &q[0], &q[2]);
load_from_transformed(trans_buf, 20, 12, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_12_64, cospi_20_64, &q[1], &q[3]);
// part of stage 4
q[13] = vsubq_s16(q[0], q[1]);
q[0] = vaddq_s16(q[0], q[1]);
q[14] = vsubq_s16(q[2], q[3]);
q[2] = vaddq_s16(q[2], q[3]);
// part of stage 5
do_butterfly(q[14], q[13], cospi_16_64, cospi_16_64, &q[1], &q[3]);
// generate 0,1,2,3
// part of stage 4
load_from_transformed(trans_buf, 0, 16, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_16_64, cospi_16_64, &q[5], &q[7]);
load_from_transformed(trans_buf, 8, 24, &q[14], &q[13]);
do_butterfly(q[14], q[13], cospi_24_64, cospi_8_64, &q[14], &q[6]);
// part of stage 5
q[4] = vaddq_s16(q[7], q[6]);
q[7] = vsubq_s16(q[7], q[6]);
q[6] = vsubq_s16(q[5], q[14]);
q[5] = vaddq_s16(q[5], q[14]);
// part of stage 6
q[8] = vaddq_s16(q[4], q[2]);
q[9] = vaddq_s16(q[5], q[3]);
q[10] = vaddq_s16(q[6], q[1]);
q[11] = vaddq_s16(q[7], q[0]);
q[12] = vsubq_s16(q[7], q[0]);
q[13] = vsubq_s16(q[6], q[1]);
q[14] = vsubq_s16(q[5], q[3]);
q[15] = vsubq_s16(q[4], q[2]);
// part of stage 7
load_from_output(out, 14, 15, &q[0], &q[1]);
q[2] = vaddq_s16(q[8], q[1]);
q[3] = vaddq_s16(q[9], q[0]);
q[4] = vsubq_s16(q[9], q[0]);
q[5] = vsubq_s16(q[8], q[1]);
load_from_output(out, 16, 17, &q[0], &q[1]);
q[8] = final_add(q[4], q[1]);
q[9] = final_add(q[5], q[0]);
q[6] = final_sub(q[5], q[0]);
q[7] = final_sub(q[4], q[1]);
if (idct32_pass_loop == 0) {
idct32_bands_end_1st_pass(out, q);
} else {
if (highbd_flag) {
highbd_idct32_bands_end_2nd_pass_bd8(out, dst, stride, q);
dst += 8;
} else {
idct32_bands_end_2nd_pass(out, dest, stride, q);
dest += 8;
}
}
}
}
}
void vpx_idct32x32_1024_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
vpx_idct32_32_neon(input, dest, stride, 0);
}
@@ -0,0 +1,66 @@
;
; Copyright (c) 2013 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license and patent
; grant that can be found in the LICENSE file in the root of the source
; tree. All contributing project authors may be found in the AUTHORS
; file in the root of the source tree.
;
EXPORT |vpx_idct4x4_1_add_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
;void vpx_idct4x4_1_add_neon(int16_t *input, uint8_t *dest, int stride)
;
; r0 int16_t input
; r1 uint8_t *dest
; r2 int stride)
|vpx_idct4x4_1_add_neon| PROC
ldrsh r0, [r0]
; cospi_16_64 = 11585
movw r12, #0x2d41
; out = dct_const_round_shift(input[0] * cospi_16_64)
mul r0, r0, r12 ; input[0] * cospi_16_64
add r0, r0, #0x2000 ; +(1 << ((DCT_CONST_BITS) - 1))
asr r0, r0, #14 ; >> DCT_CONST_BITS
; out = dct_const_round_shift(out * cospi_16_64)
mul r0, r0, r12 ; out * cospi_16_64
mov r12, r1 ; save dest
add r0, r0, #0x2000 ; +(1 << ((DCT_CONST_BITS) - 1))
asr r0, r0, #14 ; >> DCT_CONST_BITS
; a1 = ROUND_POWER_OF_TWO(out, 4)
add r0, r0, #8 ; + (1 <<((4) - 1))
asr r0, r0, #4 ; >> 4
vdup.s16 q0, r0 ; duplicate a1
vld1.32 {d2[0]}, [r1], r2
vld1.32 {d2[1]}, [r1], r2
vld1.32 {d4[0]}, [r1], r2
vld1.32 {d4[1]}, [r1]
vaddw.u8 q8, q0, d2 ; dest[x] + a1
vaddw.u8 q9, q0, d4
vqmovun.s16 d6, q8 ; clip_pixel
vqmovun.s16 d7, q9
vst1.32 {d6[0]}, [r12], r2
vst1.32 {d6[1]}, [r12], r2
vst1.32 {d7[0]}, [r12], r2
vst1.32 {d7[1]}, [r12]
bx lr
ENDP ; |vpx_idct4x4_1_add_neon|
END
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/inv_txfm.h"
static INLINE void idct4x4_1_add_kernel(uint8_t **dest, const int stride,
const int16x8_t res,
uint32x2_t *const d) {
uint16x8_t a;
uint8x8_t b;
*d = vld1_lane_u32((const uint32_t *)*dest, *d, 0);
*d = vld1_lane_u32((const uint32_t *)(*dest + stride), *d, 1);
a = vaddw_u8(vreinterpretq_u16_s16(res), vreinterpret_u8_u32(*d));
b = vqmovun_s16(vreinterpretq_s16_u16(a));
vst1_lane_u32((uint32_t *)*dest, vreinterpret_u32_u8(b), 0);
*dest += stride;
vst1_lane_u32((uint32_t *)*dest, vreinterpret_u32_u8(b), 1);
*dest += stride;
}
void vpx_idct4x4_1_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
const int16_t out0 =
WRAPLOW(dct_const_round_shift((int16_t)input[0] * cospi_16_64));
const int16_t out1 = WRAPLOW(dct_const_round_shift(out0 * cospi_16_64));
const int16_t a1 = ROUND_POWER_OF_TWO(out1, 4);
const int16x8_t dc = vdupq_n_s16(a1);
uint32x2_t d = vdup_n_u32(0);
assert(!((intptr_t)dest % sizeof(uint32_t)));
assert(!(stride % sizeof(uint32_t)));
idct4x4_1_add_kernel(&dest, stride, dc, &d);
idct4x4_1_add_kernel(&dest, stride, dc, &d);
}
@@ -0,0 +1,188 @@
;
; Copyright (c) 2013 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
EXPORT |vpx_idct4x4_16_add_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
INCLUDE vpx_dsp/arm/idct_neon.asm.S
AREA Block, CODE, READONLY ; name this block of code
;void vpx_idct4x4_16_add_neon(int16_t *input, uint8_t *dest, int stride)
;
; r0 int16_t input
; r1 uint8_t *dest
; r2 int stride)
|vpx_idct4x4_16_add_neon| PROC
; The 2D transform is done with two passes which are actually pretty
; similar. We first transform the rows. This is done by transposing
; the inputs, doing an SIMD column transform (the columns are the
; transposed rows) and then transpose the results (so that it goes back
; in normal/row positions). Then, we transform the columns by doing
; another SIMD column transform.
; So, two passes of a transpose followed by a column transform.
; load the inputs into q8-q9, d16-d19
LOAD_TRAN_LOW_TO_S16 d16, d17, d18, d19, r0
; generate scalar constants
; cospi_8_64 = 15137
movw r0, #0x3b21
; cospi_16_64 = 11585
movw r3, #0x2d41
; cospi_24_64 = 6270
movw r12, #0x187e
; transpose the input data
; 00 01 02 03 d16
; 10 11 12 13 d17
; 20 21 22 23 d18
; 30 31 32 33 d19
vtrn.16 d16, d17
vtrn.16 d18, d19
; generate constant vectors
vdup.16 d20, r0 ; replicate cospi_8_64
vdup.16 d21, r3 ; replicate cospi_16_64
; 00 10 02 12 d16
; 01 11 03 13 d17
; 20 30 22 32 d18
; 21 31 23 33 d19
vtrn.32 q8, q9
; 00 10 20 30 d16
; 01 11 21 31 d17
; 02 12 22 32 d18
; 03 13 23 33 d19
vdup.16 d22, r12 ; replicate cospi_24_64
; do the transform on transposed rows
; stage 1
vmull.s16 q15, d17, d22 ; input[1] * cospi_24_64
vmull.s16 q1, d17, d20 ; input[1] * cospi_8_64
; (input[0] + input[2]) * cospi_16_64;
; (input[0] - input[2]) * cospi_16_64;
vmull.s16 q8, d16, d21
vmull.s16 q14, d18, d21
vadd.s32 q13, q8, q14
vsub.s32 q14, q8, q14
; input[1] * cospi_24_64 - input[3] * cospi_8_64;
; input[1] * cospi_8_64 + input[3] * cospi_24_64;
vmlsl.s16 q15, d19, d20
vmlal.s16 q1, d19, d22
; dct_const_round_shift
vrshrn.s32 d26, q13, #14
vrshrn.s32 d27, q14, #14
vrshrn.s32 d29, q15, #14
vrshrn.s32 d28, q1, #14
; stage 2
; output[0] = step[0] + step[3];
; output[1] = step[1] + step[2];
; output[3] = step[0] - step[3];
; output[2] = step[1] - step[2];
vadd.s16 q8, q13, q14
vsub.s16 q9, q13, q14
vswp d18, d19
; transpose the results
; 00 01 02 03 d16
; 10 11 12 13 d17
; 20 21 22 23 d18
; 30 31 32 33 d19
vtrn.16 d16, d17
vtrn.16 d18, d19
; 00 10 02 12 d16
; 01 11 03 13 d17
; 20 30 22 32 d18
; 21 31 23 33 d19
vtrn.32 q8, q9
; 00 10 20 30 d16
; 01 11 21 31 d17
; 02 12 22 32 d18
; 03 13 23 33 d19
; do the transform on columns
; stage 1
vadd.s16 d23, d16, d18 ; (input[0] + input[2])
vsub.s16 d24, d16, d18 ; (input[0] - input[2])
vmull.s16 q15, d17, d22 ; input[1] * cospi_24_64
vmull.s16 q1, d17, d20 ; input[1] * cospi_8_64
; (input[0] + input[2]) * cospi_16_64;
; (input[0] - input[2]) * cospi_16_64;
vmull.s16 q13, d23, d21
vmull.s16 q14, d24, d21
; input[1] * cospi_24_64 - input[3] * cospi_8_64;
; input[1] * cospi_8_64 + input[3] * cospi_24_64;
vmlsl.s16 q15, d19, d20
vmlal.s16 q1, d19, d22
; dct_const_round_shift
vrshrn.s32 d26, q13, #14
vrshrn.s32 d27, q14, #14
vrshrn.s32 d29, q15, #14
vrshrn.s32 d28, q1, #14
; stage 2
; output[0] = step[0] + step[3];
; output[1] = step[1] + step[2];
; output[3] = step[0] - step[3];
; output[2] = step[1] - step[2];
vadd.s16 q8, q13, q14
vsub.s16 q9, q13, q14
; The results are in two registers, one of them being swapped. This will
; be taken care of by loading the 'dest' value in a swapped fashion and
; also storing them in the same swapped fashion.
; temp_out[0, 1] = d16, d17 = q8
; temp_out[2, 3] = d19, d18 = q9 swapped
; ROUND_POWER_OF_TWO(temp_out[j], 4)
vrshr.s16 q8, q8, #4
vrshr.s16 q9, q9, #4
vld1.32 {d26[0]}, [r1], r2
vld1.32 {d26[1]}, [r1], r2
vld1.32 {d27[1]}, [r1], r2
vld1.32 {d27[0]}, [r1] ; no post-increment
; ROUND_POWER_OF_TWO(temp_out[j], 4) + dest[j * stride + i]
vaddw.u8 q8, q8, d26
vaddw.u8 q9, q9, d27
; clip_pixel
vqmovun.s16 d26, q8
vqmovun.s16 d27, q9
; do the stores in reverse order with negative post-increment, by changing
; the sign of the stride
rsb r2, r2, #0
vst1.32 {d27[0]}, [r1], r2
vst1.32 {d27[1]}, [r1], r2
vst1.32 {d26[1]}, [r1], r2
vst1.32 {d26[0]}, [r1] ; no post-increment
bx lr
ENDP ; |vpx_idct4x4_16_add_neon|
END
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/txfm_common.h"
void vpx_idct4x4_16_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
const uint8_t *dst = dest;
uint32x2_t s32 = vdup_n_u32(0);
int16x8_t a[2];
uint8x8_t s, d[2];
uint16x8_t sum[2];
assert(!((intptr_t)dest % sizeof(uint32_t)));
assert(!(stride % sizeof(uint32_t)));
// Rows
a[0] = load_tran_low_to_s16q(input);
a[1] = load_tran_low_to_s16q(input + 8);
transpose_idct4x4_16_bd8(a);
// Columns
a[1] = vcombine_s16(vget_high_s16(a[1]), vget_low_s16(a[1]));
transpose_idct4x4_16_bd8(a);
a[0] = vrshrq_n_s16(a[0], 4);
a[1] = vrshrq_n_s16(a[1], 4);
s = load_u8(dst, stride);
dst += 2 * stride;
// The elements are loaded in reverse order.
s32 = vld1_lane_u32((const uint32_t *)dst, s32, 1);
dst += stride;
s32 = vld1_lane_u32((const uint32_t *)dst, s32, 0);
sum[0] = vaddw_u8(vreinterpretq_u16_s16(a[0]), s);
sum[1] = vaddw_u8(vreinterpretq_u16_s16(a[1]), vreinterpret_u8_u32(s32));
d[0] = vqmovun_s16(vreinterpretq_s16_u16(sum[0]));
d[1] = vqmovun_s16(vreinterpretq_s16_u16(sum[1]));
store_u8(dest, stride, d[0]);
dest += 2 * stride;
// The elements are stored in reverse order.
vst1_lane_u32((uint32_t *)dest, vreinterpret_u32_u8(d[1]), 1);
dest += stride;
vst1_lane_u32((uint32_t *)dest, vreinterpret_u32_u8(d[1]), 0);
}
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/inv_txfm.h"
static INLINE uint8x8_t create_dcd(const int16_t dc) {
int16x8_t t = vdupq_n_s16(dc);
return vqmovun_s16(t);
}
static INLINE void idct8x8_1_add_pos_kernel(uint8_t **dest, const int stride,
const uint8x8_t res) {
const uint8x8_t a = vld1_u8(*dest);
const uint8x8_t b = vqadd_u8(a, res);
vst1_u8(*dest, b);
*dest += stride;
}
static INLINE void idct8x8_1_add_neg_kernel(uint8_t **dest, const int stride,
const uint8x8_t res) {
const uint8x8_t a = vld1_u8(*dest);
const uint8x8_t b = vqsub_u8(a, res);
vst1_u8(*dest, b);
*dest += stride;
}
void vpx_idct8x8_1_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
const int16_t out0 =
WRAPLOW(dct_const_round_shift((int16_t)input[0] * cospi_16_64));
const int16_t out1 = WRAPLOW(dct_const_round_shift(out0 * cospi_16_64));
const int16_t a1 = ROUND_POWER_OF_TWO(out1, 5);
if (a1 >= 0) {
const uint8x8_t dc = create_dcd(a1);
idct8x8_1_add_pos_kernel(&dest, stride, dc);
idct8x8_1_add_pos_kernel(&dest, stride, dc);
idct8x8_1_add_pos_kernel(&dest, stride, dc);
idct8x8_1_add_pos_kernel(&dest, stride, dc);
idct8x8_1_add_pos_kernel(&dest, stride, dc);
idct8x8_1_add_pos_kernel(&dest, stride, dc);
idct8x8_1_add_pos_kernel(&dest, stride, dc);
idct8x8_1_add_pos_kernel(&dest, stride, dc);
} else {
const uint8x8_t dc = create_dcd(-a1);
idct8x8_1_add_neg_kernel(&dest, stride, dc);
idct8x8_1_add_neg_kernel(&dest, stride, dc);
idct8x8_1_add_neg_kernel(&dest, stride, dc);
idct8x8_1_add_neg_kernel(&dest, stride, dc);
idct8x8_1_add_neg_kernel(&dest, stride, dc);
idct8x8_1_add_neg_kernel(&dest, stride, dc);
idct8x8_1_add_neg_kernel(&dest, stride, dc);
idct8x8_1_add_neg_kernel(&dest, stride, dc);
}
}
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/idct_neon.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/transpose_neon.h"
#include "vpx_dsp/txfm_common.h"
void vpx_idct8x8_64_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
const int16x8_t cospis = vld1q_s16(kCospi);
const int16x4_t cospis0 = vget_low_s16(cospis); // cospi 0, 8, 16, 24
const int16x4_t cospis1 = vget_high_s16(cospis); // cospi 4, 12, 20, 28
int16x8_t a[8];
a[0] = load_tran_low_to_s16q(input);
a[1] = load_tran_low_to_s16q(input + 8);
a[2] = load_tran_low_to_s16q(input + 16);
a[3] = load_tran_low_to_s16q(input + 24);
a[4] = load_tran_low_to_s16q(input + 32);
a[5] = load_tran_low_to_s16q(input + 40);
a[6] = load_tran_low_to_s16q(input + 48);
a[7] = load_tran_low_to_s16q(input + 56);
idct8x8_64_1d_bd8(cospis0, cospis1, a);
idct8x8_64_1d_bd8(cospis0, cospis1, a);
idct8x8_add8x8_neon(a, dest, stride);
}
void vpx_idct8x8_12_add_neon(const tran_low_t *input, uint8_t *dest,
int stride) {
const int16x8_t cospis = vld1q_s16(kCospi);
const int16x8_t cospisd = vaddq_s16(cospis, cospis);
const int16x4_t cospis0 = vget_low_s16(cospis); // cospi 0, 8, 16, 24
const int16x4_t cospisd0 = vget_low_s16(cospisd); // doubled 0, 8, 16, 24
const int16x4_t cospisd1 = vget_high_s16(cospisd); // doubled 4, 12, 20, 28
int16x4_t a[8];
int16x8_t b[8];
a[0] = load_tran_low_to_s16d(input);
a[1] = load_tran_low_to_s16d(input + 8);
a[2] = load_tran_low_to_s16d(input + 16);
a[3] = load_tran_low_to_s16d(input + 24);
idct8x8_12_pass1_bd8(cospis0, cospisd0, cospisd1, a);
idct8x8_12_pass2_bd8(cospis0, cospisd0, cospisd1, a, b);
idct8x8_add8x8_neon(b, dest, stride);
}
@@ -0,0 +1,46 @@
;
; Copyright (c) 2016 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
INCLUDE ./vpx_config.asm
; Helper functions used to load tran_low_t into int16, narrowing if
; necessary.
; $dst0..3 are d registers with the pairs assumed to be contiguous in
; non-high-bitdepth builds. q0-q3 are used as temporaries in high-bitdepth.
MACRO
LOAD_TRAN_LOW_TO_S16 $dst0, $dst1, $dst2, $dst3, $src
IF CONFIG_VP9_HIGHBITDEPTH
vld1.s32 {q0,q1}, [$src]!
vld1.s32 {q2,q3}, [$src]!
vmovn.i32 $dst0, q0
vmovn.i32 $dst1, q1
vmovn.i32 $dst2, q2
vmovn.i32 $dst3, q3
ELSE
vld1.s16 {$dst0-$dst1,$dst2-$dst3}, [$src]!
ENDIF
MEND
; $dst0..3 are d registers. q0-q3 are used as temporaries in high-bitdepth.
MACRO
LOAD_TRAN_LOW_TO_S16X2 $dst0, $dst1, $dst2, $dst3, $src
IF CONFIG_VP9_HIGHBITDEPTH
vld2.s32 {q0,q1}, [$src]!
vld2.s32 {q2,q3}, [$src]!
vmovn.i32 $dst0, q0
vmovn.i32 $dst1, q2
vmovn.i32 $dst2, q1
vmovn.i32 $dst3, q3
ELSE
vld2.s16 {$dst0,$dst1,$dst2,$dst3}, [$src]!
ENDIF
MEND
END
@@ -0,0 +1,919 @@
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VPX_VPX_DSP_ARM_IDCT_NEON_H_
#define VPX_VPX_DSP_ARM_IDCT_NEON_H_
#include <arm_neon.h>
#include "./vpx_config.h"
#include "vpx_dsp/arm/transpose_neon.h"
#include "vpx_dsp/txfm_common.h"
#include "vpx_dsp/vpx_dsp_common.h"
static const int16_t kCospi[16] = {
16384 /* cospi_0_64 */, 15137 /* cospi_8_64 */,
11585 /* cospi_16_64 */, 6270 /* cospi_24_64 */,
16069 /* cospi_4_64 */, 13623 /* cospi_12_64 */,
-9102 /* -cospi_20_64 */, 3196 /* cospi_28_64 */,
16305 /* cospi_2_64 */, 1606 /* cospi_30_64 */,
14449 /* cospi_10_64 */, 7723 /* cospi_22_64 */,
15679 /* cospi_6_64 */, -4756 /* -cospi_26_64 */,
12665 /* cospi_14_64 */, -10394 /* -cospi_18_64 */
};
static const int32_t kCospi32[16] = {
16384 /* cospi_0_64 */, 15137 /* cospi_8_64 */,
11585 /* cospi_16_64 */, 6270 /* cospi_24_64 */,
16069 /* cospi_4_64 */, 13623 /* cospi_12_64 */,
-9102 /* -cospi_20_64 */, 3196 /* cospi_28_64 */,
16305 /* cospi_2_64 */, 1606 /* cospi_30_64 */,
14449 /* cospi_10_64 */, 7723 /* cospi_22_64 */,
15679 /* cospi_6_64 */, -4756 /* -cospi_26_64 */,
12665 /* cospi_14_64 */, -10394 /* -cospi_18_64 */
};
//------------------------------------------------------------------------------
// Use saturating add/sub to avoid overflow in 2nd pass in high bit-depth
static INLINE int16x8_t final_add(const int16x8_t a, const int16x8_t b) {
#if CONFIG_VP9_HIGHBITDEPTH
return vqaddq_s16(a, b);
#else
return vaddq_s16(a, b);
#endif
}
static INLINE int16x8_t final_sub(const int16x8_t a, const int16x8_t b) {
#if CONFIG_VP9_HIGHBITDEPTH
return vqsubq_s16(a, b);
#else
return vsubq_s16(a, b);
#endif
}
//------------------------------------------------------------------------------
static INLINE int32x4x2_t highbd_idct_add_dual(const int32x4x2_t s0,
const int32x4x2_t s1) {
int32x4x2_t t;
t.val[0] = vaddq_s32(s0.val[0], s1.val[0]);
t.val[1] = vaddq_s32(s0.val[1], s1.val[1]);
return t;
}
static INLINE int32x4x2_t highbd_idct_sub_dual(const int32x4x2_t s0,
const int32x4x2_t s1) {
int32x4x2_t t;
t.val[0] = vsubq_s32(s0.val[0], s1.val[0]);
t.val[1] = vsubq_s32(s0.val[1], s1.val[1]);
return t;
}
//------------------------------------------------------------------------------
static INLINE int16x8_t dct_const_round_shift_low_8(const int32x4_t *const in) {
return vcombine_s16(vrshrn_n_s32(in[0], DCT_CONST_BITS),
vrshrn_n_s32(in[1], DCT_CONST_BITS));
}
static INLINE void dct_const_round_shift_low_8_dual(const int32x4_t *const t32,
int16x8_t *const d0,
int16x8_t *const d1) {
*d0 = dct_const_round_shift_low_8(t32 + 0);
*d1 = dct_const_round_shift_low_8(t32 + 2);
}
static INLINE int32x4x2_t
dct_const_round_shift_high_4x2(const int64x2_t *const in) {
int32x4x2_t out;
out.val[0] = vcombine_s32(vrshrn_n_s64(in[0], DCT_CONST_BITS),
vrshrn_n_s64(in[1], DCT_CONST_BITS));
out.val[1] = vcombine_s32(vrshrn_n_s64(in[2], DCT_CONST_BITS),
vrshrn_n_s64(in[3], DCT_CONST_BITS));
return out;
}
// Multiply a by a_const. Saturate, shift and narrow by DCT_CONST_BITS.
static INLINE int16x8_t multiply_shift_and_narrow_s16(const int16x8_t a,
const int16_t a_const) {
// Shift by DCT_CONST_BITS + rounding will be within 16 bits for well formed
// streams. See WRAPLOW and dct_const_round_shift for details.
// This instruction doubles the result and returns the high half, essentially
// resulting in a right shift by 15. By multiplying the constant first that
// becomes a right shift by DCT_CONST_BITS.
// The largest possible value used here is
// vpx_dsp/txfm_common.h:cospi_1_64 = 16364 (* 2 = 32728) a which falls *just*
// within the range of int16_t (+32767 / -32768) even when negated.
return vqrdmulhq_n_s16(a, a_const * 2);
}
// Add a and b, then multiply by ab_const. Shift and narrow by DCT_CONST_BITS.
static INLINE int16x8_t add_multiply_shift_and_narrow_s16(
const int16x8_t a, const int16x8_t b, const int16_t ab_const) {
// In both add_ and it's pair, sub_, the input for well-formed streams will be
// well within 16 bits (input to the idct is the difference between two frames
// and will be within -255 to 255, or 9 bits)
// However, for inputs over about 25,000 (valid for int16_t, but not for idct
// input) this function can not use vaddq_s16.
// In order to match existing behavior and intentionally out of range tests,
// expand the addition up to 32 bits to prevent truncation.
int32x4_t t[2];
t[0] = vaddl_s16(vget_low_s16(a), vget_low_s16(b));
t[1] = vaddl_s16(vget_high_s16(a), vget_high_s16(b));
t[0] = vmulq_n_s32(t[0], ab_const);
t[1] = vmulq_n_s32(t[1], ab_const);
return dct_const_round_shift_low_8(t);
}
// Subtract b from a, then multiply by ab_const. Shift and narrow by
// DCT_CONST_BITS.
static INLINE int16x8_t sub_multiply_shift_and_narrow_s16(
const int16x8_t a, const int16x8_t b, const int16_t ab_const) {
int32x4_t t[2];
t[0] = vsubl_s16(vget_low_s16(a), vget_low_s16(b));
t[1] = vsubl_s16(vget_high_s16(a), vget_high_s16(b));
t[0] = vmulq_n_s32(t[0], ab_const);
t[1] = vmulq_n_s32(t[1], ab_const);
return dct_const_round_shift_low_8(t);
}
// Multiply a by a_const and b by b_const, then accumulate. Shift and narrow by
// DCT_CONST_BITS.
static INLINE int16x8_t multiply_accumulate_shift_and_narrow_s16(
const int16x8_t a, const int16_t a_const, const int16x8_t b,
const int16_t b_const) {
int32x4_t t[2];
t[0] = vmull_n_s16(vget_low_s16(a), a_const);
t[1] = vmull_n_s16(vget_high_s16(a), a_const);
t[0] = vmlal_n_s16(t[0], vget_low_s16(b), b_const);
t[1] = vmlal_n_s16(t[1], vget_high_s16(b), b_const);
return dct_const_round_shift_low_8(t);
}
//------------------------------------------------------------------------------
// Note: The following 4 functions could use 32-bit operations for bit-depth 10.
// However, although it's 20% faster with gcc, it's 20% slower with clang.
// Use 64-bit operations for now.
// Multiply a by a_const. Saturate, shift and narrow by DCT_CONST_BITS.
static INLINE int32x4x2_t
multiply_shift_and_narrow_s32_dual(const int32x4x2_t a, const int32_t a_const) {
int64x2_t b[4];
b[0] = vmull_n_s32(vget_low_s32(a.val[0]), a_const);
b[1] = vmull_n_s32(vget_high_s32(a.val[0]), a_const);
b[2] = vmull_n_s32(vget_low_s32(a.val[1]), a_const);
b[3] = vmull_n_s32(vget_high_s32(a.val[1]), a_const);
return dct_const_round_shift_high_4x2(b);
}
// Add a and b, then multiply by ab_const. Shift and narrow by DCT_CONST_BITS.
static INLINE int32x4x2_t add_multiply_shift_and_narrow_s32_dual(
const int32x4x2_t a, const int32x4x2_t b, const int32_t ab_const) {
int32x4_t t[2];
int64x2_t c[4];
t[0] = vaddq_s32(a.val[0], b.val[0]);
t[1] = vaddq_s32(a.val[1], b.val[1]);
c[0] = vmull_n_s32(vget_low_s32(t[0]), ab_const);
c[1] = vmull_n_s32(vget_high_s32(t[0]), ab_const);
c[2] = vmull_n_s32(vget_low_s32(t[1]), ab_const);
c[3] = vmull_n_s32(vget_high_s32(t[1]), ab_const);
return dct_const_round_shift_high_4x2(c);
}
// Subtract b from a, then multiply by ab_const. Shift and narrow by
// DCT_CONST_BITS.
static INLINE int32x4x2_t sub_multiply_shift_and_narrow_s32_dual(
const int32x4x2_t a, const int32x4x2_t b, const int32_t ab_const) {
int32x4_t t[2];
int64x2_t c[4];
t[0] = vsubq_s32(a.val[0], b.val[0]);
t[1] = vsubq_s32(a.val[1], b.val[1]);
c[0] = vmull_n_s32(vget_low_s32(t[0]), ab_const);
c[1] = vmull_n_s32(vget_high_s32(t[0]), ab_const);
c[2] = vmull_n_s32(vget_low_s32(t[1]), ab_const);
c[3] = vmull_n_s32(vget_high_s32(t[1]), ab_const);
return dct_const_round_shift_high_4x2(c);
}
// Multiply a by a_const and b by b_const, then accumulate. Shift and narrow by
// DCT_CONST_BITS.
static INLINE int32x4x2_t multiply_accumulate_shift_and_narrow_s32_dual(
const int32x4x2_t a, const int32_t a_const, const int32x4x2_t b,
const int32_t b_const) {
int64x2_t c[4];
c[0] = vmull_n_s32(vget_low_s32(a.val[0]), a_const);
c[1] = vmull_n_s32(vget_high_s32(a.val[0]), a_const);
c[2] = vmull_n_s32(vget_low_s32(a.val[1]), a_const);
c[3] = vmull_n_s32(vget_high_s32(a.val[1]), a_const);
c[0] = vmlal_n_s32(c[0], vget_low_s32(b.val[0]), b_const);
c[1] = vmlal_n_s32(c[1], vget_high_s32(b.val[0]), b_const);
c[2] = vmlal_n_s32(c[2], vget_low_s32(b.val[1]), b_const);
c[3] = vmlal_n_s32(c[3], vget_high_s32(b.val[1]), b_const);
return dct_const_round_shift_high_4x2(c);
}
// Shift the output down by 6 and add it to the destination buffer.
static INLINE void add_and_store_u8_s16(const int16x8_t *const a, uint8_t *d,
const int stride) {
uint8x8_t b[8];
int16x8_t c[8];
b[0] = vld1_u8(d);
d += stride;
b[1] = vld1_u8(d);
d += stride;
b[2] = vld1_u8(d);
d += stride;
b[3] = vld1_u8(d);
d += stride;
b[4] = vld1_u8(d);
d += stride;
b[5] = vld1_u8(d);
d += stride;
b[6] = vld1_u8(d);
d += stride;
b[7] = vld1_u8(d);
d -= (7 * stride);
// c = b + (a >> 6)
c[0] = vrsraq_n_s16(vreinterpretq_s16_u16(vmovl_u8(b[0])), a[0], 6);
c[1] = vrsraq_n_s16(vreinterpretq_s16_u16(vmovl_u8(b[1])), a[1], 6);
c[2] = vrsraq_n_s16(vreinterpretq_s16_u16(vmovl_u8(b[2])), a[2], 6);
c[3] = vrsraq_n_s16(vreinterpretq_s16_u16(vmovl_u8(b[3])), a[3], 6);
c[4] = vrsraq_n_s16(vreinterpretq_s16_u16(vmovl_u8(b[4])), a[4], 6);
c[5] = vrsraq_n_s16(vreinterpretq_s16_u16(vmovl_u8(b[5])), a[5], 6);
c[6] = vrsraq_n_s16(vreinterpretq_s16_u16(vmovl_u8(b[6])), a[6], 6);
c[7] = vrsraq_n_s16(vreinterpretq_s16_u16(vmovl_u8(b[7])), a[7], 6);
b[0] = vqmovun_s16(c[0]);
b[1] = vqmovun_s16(c[1]);
b[2] = vqmovun_s16(c[2]);
b[3] = vqmovun_s16(c[3]);
b[4] = vqmovun_s16(c[4]);
b[5] = vqmovun_s16(c[5]);
b[6] = vqmovun_s16(c[6]);
b[7] = vqmovun_s16(c[7]);
vst1_u8(d, b[0]);
d += stride;
vst1_u8(d, b[1]);
d += stride;
vst1_u8(d, b[2]);
d += stride;
vst1_u8(d, b[3]);
d += stride;
vst1_u8(d, b[4]);
d += stride;
vst1_u8(d, b[5]);
d += stride;
vst1_u8(d, b[6]);
d += stride;
vst1_u8(d, b[7]);
}
static INLINE uint8x16_t create_dcq(const int16_t dc) {
// Clip both sides and gcc may compile to assembly 'usat'.
const int16_t t = (dc < 0) ? 0 : ((dc > 255) ? 255 : dc);
return vdupq_n_u8((uint8_t)t);
}
static INLINE void idct4x4_16_kernel_bd8(int16x8_t *const a) {
const int16x4_t cospis = vld1_s16(kCospi);
int16x4_t b[4];
int32x4_t c[4];
int16x8_t d[2];
b[0] = vget_low_s16(a[0]);
b[1] = vget_high_s16(a[0]);
b[2] = vget_low_s16(a[1]);
b[3] = vget_high_s16(a[1]);
c[0] = vmull_lane_s16(b[0], cospis, 2);
c[2] = vmull_lane_s16(b[1], cospis, 2);
c[1] = vsubq_s32(c[0], c[2]);
c[0] = vaddq_s32(c[0], c[2]);
c[3] = vmull_lane_s16(b[2], cospis, 3);
c[2] = vmull_lane_s16(b[2], cospis, 1);
c[3] = vmlsl_lane_s16(c[3], b[3], cospis, 1);
c[2] = vmlal_lane_s16(c[2], b[3], cospis, 3);
dct_const_round_shift_low_8_dual(c, &d[0], &d[1]);
a[0] = vaddq_s16(d[0], d[1]);
a[1] = vsubq_s16(d[0], d[1]);
}
static INLINE void transpose_idct4x4_16_bd8(int16x8_t *const a) {
transpose_s16_4x4q(&a[0], &a[1]);
idct4x4_16_kernel_bd8(a);
}
static INLINE void idct8x8_12_pass1_bd8(const int16x4_t cospis0,
const int16x4_t cospisd0,
const int16x4_t cospisd1,
int16x4_t *const io) {
int16x4_t step1[8], step2[8];
int32x4_t t32[2];
transpose_s16_4x4d(&io[0], &io[1], &io[2], &io[3]);
// stage 1
step1[4] = vqrdmulh_lane_s16(io[1], cospisd1, 3);
step1[5] = vqrdmulh_lane_s16(io[3], cospisd1, 2);
step1[6] = vqrdmulh_lane_s16(io[3], cospisd1, 1);
step1[7] = vqrdmulh_lane_s16(io[1], cospisd1, 0);
// stage 2
step2[1] = vqrdmulh_lane_s16(io[0], cospisd0, 2);
step2[2] = vqrdmulh_lane_s16(io[2], cospisd0, 3);
step2[3] = vqrdmulh_lane_s16(io[2], cospisd0, 1);
step2[4] = vadd_s16(step1[4], step1[5]);
step2[5] = vsub_s16(step1[4], step1[5]);
step2[6] = vsub_s16(step1[7], step1[6]);
step2[7] = vadd_s16(step1[7], step1[6]);
// stage 3
step1[0] = vadd_s16(step2[1], step2[3]);
step1[1] = vadd_s16(step2[1], step2[2]);
step1[2] = vsub_s16(step2[1], step2[2]);
step1[3] = vsub_s16(step2[1], step2[3]);
t32[1] = vmull_lane_s16(step2[6], cospis0, 2);
t32[0] = vmlsl_lane_s16(t32[1], step2[5], cospis0, 2);
t32[1] = vmlal_lane_s16(t32[1], step2[5], cospis0, 2);
step1[5] = vrshrn_n_s32(t32[0], DCT_CONST_BITS);
step1[6] = vrshrn_n_s32(t32[1], DCT_CONST_BITS);
// stage 4
io[0] = vadd_s16(step1[0], step2[7]);
io[1] = vadd_s16(step1[1], step1[6]);
io[2] = vadd_s16(step1[2], step1[5]);
io[3] = vadd_s16(step1[3], step2[4]);
io[4] = vsub_s16(step1[3], step2[4]);
io[5] = vsub_s16(step1[2], step1[5]);
io[6] = vsub_s16(step1[1], step1[6]);
io[7] = vsub_s16(step1[0], step2[7]);
}
static INLINE void idct8x8_12_pass2_bd8(const int16x4_t cospis0,
const int16x4_t cospisd0,
const int16x4_t cospisd1,
const int16x4_t *const input,
int16x8_t *const output) {
int16x8_t in[4];
int16x8_t step1[8], step2[8];
int32x4_t t32[8];
transpose_s16_4x8(input[0], input[1], input[2], input[3], input[4], input[5],
input[6], input[7], &in[0], &in[1], &in[2], &in[3]);
// stage 1
step1[4] = vqrdmulhq_lane_s16(in[1], cospisd1, 3);
step1[5] = vqrdmulhq_lane_s16(in[3], cospisd1, 2);
step1[6] = vqrdmulhq_lane_s16(in[3], cospisd1, 1);
step1[7] = vqrdmulhq_lane_s16(in[1], cospisd1, 0);
// stage 2
step2[1] = vqrdmulhq_lane_s16(in[0], cospisd0, 2);
step2[2] = vqrdmulhq_lane_s16(in[2], cospisd0, 3);
step2[3] = vqrdmulhq_lane_s16(in[2], cospisd0, 1);
step2[4] = vaddq_s16(step1[4], step1[5]);
step2[5] = vsubq_s16(step1[4], step1[5]);
step2[6] = vsubq_s16(step1[7], step1[6]);
step2[7] = vaddq_s16(step1[7], step1[6]);
// stage 3
step1[0] = vaddq_s16(step2[1], step2[3]);
step1[1] = vaddq_s16(step2[1], step2[2]);
step1[2] = vsubq_s16(step2[1], step2[2]);
step1[3] = vsubq_s16(step2[1], step2[3]);
t32[2] = vmull_lane_s16(vget_low_s16(step2[6]), cospis0, 2);
t32[3] = vmull_lane_s16(vget_high_s16(step2[6]), cospis0, 2);
t32[0] = vmlsl_lane_s16(t32[2], vget_low_s16(step2[5]), cospis0, 2);
t32[1] = vmlsl_lane_s16(t32[3], vget_high_s16(step2[5]), cospis0, 2);
t32[2] = vmlal_lane_s16(t32[2], vget_low_s16(step2[5]), cospis0, 2);
t32[3] = vmlal_lane_s16(t32[3], vget_high_s16(step2[5]), cospis0, 2);
dct_const_round_shift_low_8_dual(t32, &step1[5], &step1[6]);
// stage 4
output[0] = vaddq_s16(step1[0], step2[7]);
output[1] = vaddq_s16(step1[1], step1[6]);
output[2] = vaddq_s16(step1[2], step1[5]);
output[3] = vaddq_s16(step1[3], step2[4]);
output[4] = vsubq_s16(step1[3], step2[4]);
output[5] = vsubq_s16(step1[2], step1[5]);
output[6] = vsubq_s16(step1[1], step1[6]);
output[7] = vsubq_s16(step1[0], step2[7]);
}
static INLINE void idct8x8_64_1d_bd8_kernel(const int16x4_t cospis0,
const int16x4_t cospis1,
int16x8_t *const io) {
int16x4_t input1l, input1h, input3l, input3h, input5l, input5h, input7l,
input7h;
int16x4_t step1l[4], step1h[4];
int16x8_t step1[8], step2[8];
int32x4_t t32[8];
// stage 1
input1l = vget_low_s16(io[1]);
input1h = vget_high_s16(io[1]);
input3l = vget_low_s16(io[3]);
input3h = vget_high_s16(io[3]);
input5l = vget_low_s16(io[5]);
input5h = vget_high_s16(io[5]);
input7l = vget_low_s16(io[7]);
input7h = vget_high_s16(io[7]);
step1l[0] = vget_low_s16(io[0]);
step1h[0] = vget_high_s16(io[0]);
step1l[1] = vget_low_s16(io[2]);
step1h[1] = vget_high_s16(io[2]);
step1l[2] = vget_low_s16(io[4]);
step1h[2] = vget_high_s16(io[4]);
step1l[3] = vget_low_s16(io[6]);
step1h[3] = vget_high_s16(io[6]);
t32[0] = vmull_lane_s16(input1l, cospis1, 3);
t32[1] = vmull_lane_s16(input1h, cospis1, 3);
t32[2] = vmull_lane_s16(input3l, cospis1, 2);
t32[3] = vmull_lane_s16(input3h, cospis1, 2);
t32[4] = vmull_lane_s16(input3l, cospis1, 1);
t32[5] = vmull_lane_s16(input3h, cospis1, 1);
t32[6] = vmull_lane_s16(input1l, cospis1, 0);
t32[7] = vmull_lane_s16(input1h, cospis1, 0);
t32[0] = vmlsl_lane_s16(t32[0], input7l, cospis1, 0);
t32[1] = vmlsl_lane_s16(t32[1], input7h, cospis1, 0);
t32[2] = vmlal_lane_s16(t32[2], input5l, cospis1, 1);
t32[3] = vmlal_lane_s16(t32[3], input5h, cospis1, 1);
t32[4] = vmlsl_lane_s16(t32[4], input5l, cospis1, 2);
t32[5] = vmlsl_lane_s16(t32[5], input5h, cospis1, 2);
t32[6] = vmlal_lane_s16(t32[6], input7l, cospis1, 3);
t32[7] = vmlal_lane_s16(t32[7], input7h, cospis1, 3);
dct_const_round_shift_low_8_dual(&t32[0], &step1[4], &step1[5]);
dct_const_round_shift_low_8_dual(&t32[4], &step1[6], &step1[7]);
// stage 2
t32[2] = vmull_lane_s16(step1l[0], cospis0, 2);
t32[3] = vmull_lane_s16(step1h[0], cospis0, 2);
t32[4] = vmull_lane_s16(step1l[1], cospis0, 3);
t32[5] = vmull_lane_s16(step1h[1], cospis0, 3);
t32[6] = vmull_lane_s16(step1l[1], cospis0, 1);
t32[7] = vmull_lane_s16(step1h[1], cospis0, 1);
t32[0] = vmlal_lane_s16(t32[2], step1l[2], cospis0, 2);
t32[1] = vmlal_lane_s16(t32[3], step1h[2], cospis0, 2);
t32[2] = vmlsl_lane_s16(t32[2], step1l[2], cospis0, 2);
t32[3] = vmlsl_lane_s16(t32[3], step1h[2], cospis0, 2);
t32[4] = vmlsl_lane_s16(t32[4], step1l[3], cospis0, 1);
t32[5] = vmlsl_lane_s16(t32[5], step1h[3], cospis0, 1);
t32[6] = vmlal_lane_s16(t32[6], step1l[3], cospis0, 3);
t32[7] = vmlal_lane_s16(t32[7], step1h[3], cospis0, 3);
dct_const_round_shift_low_8_dual(&t32[0], &step2[0], &step2[1]);
dct_const_round_shift_low_8_dual(&t32[4], &step2[2], &step2[3]);
step2[4] = vaddq_s16(step1[4], step1[5]);
step2[5] = vsubq_s16(step1[4], step1[5]);
step2[6] = vsubq_s16(step1[7], step1[6]);
step2[7] = vaddq_s16(step1[7], step1[6]);
// stage 3
step1[0] = vaddq_s16(step2[0], step2[3]);
step1[1] = vaddq_s16(step2[1], step2[2]);
step1[2] = vsubq_s16(step2[1], step2[2]);
step1[3] = vsubq_s16(step2[0], step2[3]);
t32[2] = vmull_lane_s16(vget_low_s16(step2[6]), cospis0, 2);
t32[3] = vmull_lane_s16(vget_high_s16(step2[6]), cospis0, 2);
t32[0] = vmlsl_lane_s16(t32[2], vget_low_s16(step2[5]), cospis0, 2);
t32[1] = vmlsl_lane_s16(t32[3], vget_high_s16(step2[5]), cospis0, 2);
t32[2] = vmlal_lane_s16(t32[2], vget_low_s16(step2[5]), cospis0, 2);
t32[3] = vmlal_lane_s16(t32[3], vget_high_s16(step2[5]), cospis0, 2);
dct_const_round_shift_low_8_dual(t32, &step1[5], &step1[6]);
// stage 4
io[0] = vaddq_s16(step1[0], step2[7]);
io[1] = vaddq_s16(step1[1], step1[6]);
io[2] = vaddq_s16(step1[2], step1[5]);
io[3] = vaddq_s16(step1[3], step2[4]);
io[4] = vsubq_s16(step1[3], step2[4]);
io[5] = vsubq_s16(step1[2], step1[5]);
io[6] = vsubq_s16(step1[1], step1[6]);
io[7] = vsubq_s16(step1[0], step2[7]);
}
static INLINE void idct8x8_64_1d_bd8(const int16x4_t cospis0,
const int16x4_t cospis1,
int16x8_t *const io) {
transpose_s16_8x8(&io[0], &io[1], &io[2], &io[3], &io[4], &io[5], &io[6],
&io[7]);
idct8x8_64_1d_bd8_kernel(cospis0, cospis1, io);
}
static INLINE void idct_cospi_8_24_q_kernel(const int16x8_t s0,
const int16x8_t s1,
const int16x4_t cospi_0_8_16_24,
int32x4_t *const t32) {
t32[0] = vmull_lane_s16(vget_low_s16(s0), cospi_0_8_16_24, 3);
t32[1] = vmull_lane_s16(vget_high_s16(s0), cospi_0_8_16_24, 3);
t32[2] = vmull_lane_s16(vget_low_s16(s1), cospi_0_8_16_24, 3);
t32[3] = vmull_lane_s16(vget_high_s16(s1), cospi_0_8_16_24, 3);
t32[0] = vmlsl_lane_s16(t32[0], vget_low_s16(s1), cospi_0_8_16_24, 1);
t32[1] = vmlsl_lane_s16(t32[1], vget_high_s16(s1), cospi_0_8_16_24, 1);
t32[2] = vmlal_lane_s16(t32[2], vget_low_s16(s0), cospi_0_8_16_24, 1);
t32[3] = vmlal_lane_s16(t32[3], vget_high_s16(s0), cospi_0_8_16_24, 1);
}
static INLINE void idct_cospi_8_24_q(const int16x8_t s0, const int16x8_t s1,
const int16x4_t cospi_0_8_16_24,
int16x8_t *const d0, int16x8_t *const d1) {
int32x4_t t32[4];
idct_cospi_8_24_q_kernel(s0, s1, cospi_0_8_16_24, t32);
dct_const_round_shift_low_8_dual(t32, d0, d1);
}
static INLINE void idct_cospi_8_24_neg_q(const int16x8_t s0, const int16x8_t s1,
const int16x4_t cospi_0_8_16_24,
int16x8_t *const d0,
int16x8_t *const d1) {
int32x4_t t32[4];
idct_cospi_8_24_q_kernel(s0, s1, cospi_0_8_16_24, t32);
t32[2] = vnegq_s32(t32[2]);
t32[3] = vnegq_s32(t32[3]);
dct_const_round_shift_low_8_dual(t32, d0, d1);
}
static INLINE void idct_cospi_16_16_q(const int16x8_t s0, const int16x8_t s1,
const int16x4_t cospi_0_8_16_24,
int16x8_t *const d0,
int16x8_t *const d1) {
int32x4_t t32[6];
t32[4] = vmull_lane_s16(vget_low_s16(s1), cospi_0_8_16_24, 2);
t32[5] = vmull_lane_s16(vget_high_s16(s1), cospi_0_8_16_24, 2);
t32[0] = vmlsl_lane_s16(t32[4], vget_low_s16(s0), cospi_0_8_16_24, 2);
t32[1] = vmlsl_lane_s16(t32[5], vget_high_s16(s0), cospi_0_8_16_24, 2);
t32[2] = vmlal_lane_s16(t32[4], vget_low_s16(s0), cospi_0_8_16_24, 2);
t32[3] = vmlal_lane_s16(t32[5], vget_high_s16(s0), cospi_0_8_16_24, 2);
dct_const_round_shift_low_8_dual(t32, d0, d1);
}
static INLINE void idct_cospi_2_30(const int16x8_t s0, const int16x8_t s1,
const int16x4_t cospi_2_30_10_22,
int16x8_t *const d0, int16x8_t *const d1) {
int32x4_t t32[4];
t32[0] = vmull_lane_s16(vget_low_s16(s0), cospi_2_30_10_22, 1);
t32[1] = vmull_lane_s16(vget_high_s16(s0), cospi_2_30_10_22, 1);
t32[2] = vmull_lane_s16(vget_low_s16(s1), cospi_2_30_10_22, 1);
t32[3] = vmull_lane_s16(vget_high_s16(s1), cospi_2_30_10_22, 1);
t32[0] = vmlsl_lane_s16(t32[0], vget_low_s16(s1), cospi_2_30_10_22, 0);
t32[1] = vmlsl_lane_s16(t32[1], vget_high_s16(s1), cospi_2_30_10_22, 0);
t32[2] = vmlal_lane_s16(t32[2], vget_low_s16(s0), cospi_2_30_10_22, 0);
t32[3] = vmlal_lane_s16(t32[3], vget_high_s16(s0), cospi_2_30_10_22, 0);
dct_const_round_shift_low_8_dual(t32, d0, d1);
}
static INLINE void idct_cospi_4_28(const int16x8_t s0, const int16x8_t s1,
const int16x4_t cospi_4_12_20N_28,
int16x8_t *const d0, int16x8_t *const d1) {
int32x4_t t32[4];
t32[0] = vmull_lane_s16(vget_low_s16(s0), cospi_4_12_20N_28, 3);
t32[1] = vmull_lane_s16(vget_high_s16(s0), cospi_4_12_20N_28, 3);
t32[2] = vmull_lane_s16(vget_low_s16(s1), cospi_4_12_20N_28, 3);
t32[3] = vmull_lane_s16(vget_high_s16(s1), cospi_4_12_20N_28, 3);
t32[0] = vmlsl_lane_s16(t32[0], vget_low_s16(s1), cospi_4_12_20N_28, 0);
t32[1] = vmlsl_lane_s16(t32[1], vget_high_s16(s1), cospi_4_12_20N_28, 0);
t32[2] = vmlal_lane_s16(t32[2], vget_low_s16(s0), cospi_4_12_20N_28, 0);
t32[3] = vmlal_lane_s16(t32[3], vget_high_s16(s0), cospi_4_12_20N_28, 0);
dct_const_round_shift_low_8_dual(t32, d0, d1);
}
static INLINE void idct_cospi_6_26(const int16x8_t s0, const int16x8_t s1,
const int16x4_t cospi_6_26N_14_18N,
int16x8_t *const d0, int16x8_t *const d1) {
int32x4_t t32[4];
t32[0] = vmull_lane_s16(vget_low_s16(s0), cospi_6_26N_14_18N, 0);
t32[1] = vmull_lane_s16(vget_high_s16(s0), cospi_6_26N_14_18N, 0);
t32[2] = vmull_lane_s16(vget_low_s16(s1), cospi_6_26N_14_18N, 0);
t32[3] = vmull_lane_s16(vget_high_s16(s1), cospi_6_26N_14_18N, 0);
t32[0] = vmlal_lane_s16(t32[0], vget_low_s16(s1), cospi_6_26N_14_18N, 1);
t32[1] = vmlal_lane_s16(t32[1], vget_high_s16(s1), cospi_6_26N_14_18N, 1);
t32[2] = vmlsl_lane_s16(t32[2], vget_low_s16(s0), cospi_6_26N_14_18N, 1);
t32[3] = vmlsl_lane_s16(t32[3], vget_high_s16(s0), cospi_6_26N_14_18N, 1);
dct_const_round_shift_low_8_dual(t32, d0, d1);
}
static INLINE void idct_cospi_10_22(const int16x8_t s0, const int16x8_t s1,
const int16x4_t cospi_2_30_10_22,
int16x8_t *const d0, int16x8_t *const d1) {
int32x4_t t32[4];
t32[0] = vmull_lane_s16(vget_low_s16(s0), cospi_2_30_10_22, 3);
t32[1] = vmull_lane_s16(vget_high_s16(s0), cospi_2_30_10_22, 3);
t32[2] = vmull_lane_s16(vget_low_s16(s1), cospi_2_30_10_22, 3);
t32[3] = vmull_lane_s16(vget_high_s16(s1), cospi_2_30_10_22, 3);
t32[0] = vmlsl_lane_s16(t32[0], vget_low_s16(s1), cospi_2_30_10_22, 2);
t32[1] = vmlsl_lane_s16(t32[1], vget_high_s16(s1), cospi_2_30_10_22, 2);
t32[2] = vmlal_lane_s16(t32[2], vget_low_s16(s0), cospi_2_30_10_22, 2);
t32[3] = vmlal_lane_s16(t32[3], vget_high_s16(s0), cospi_2_30_10_22, 2);
dct_const_round_shift_low_8_dual(t32, d0, d1);
}
static INLINE void idct_cospi_12_20(const int16x8_t s0, const int16x8_t s1,
const int16x4_t cospi_4_12_20N_28,
int16x8_t *const d0, int16x8_t *const d1) {
int32x4_t t32[4];
t32[0] = vmull_lane_s16(vget_low_s16(s0), cospi_4_12_20N_28, 1);
t32[1] = vmull_lane_s16(vget_high_s16(s0), cospi_4_12_20N_28, 1);
t32[2] = vmull_lane_s16(vget_low_s16(s1), cospi_4_12_20N_28, 1);
t32[3] = vmull_lane_s16(vget_high_s16(s1), cospi_4_12_20N_28, 1);
t32[0] = vmlal_lane_s16(t32[0], vget_low_s16(s1), cospi_4_12_20N_28, 2);
t32[1] = vmlal_lane_s16(t32[1], vget_high_s16(s1), cospi_4_12_20N_28, 2);
t32[2] = vmlsl_lane_s16(t32[2], vget_low_s16(s0), cospi_4_12_20N_28, 2);
t32[3] = vmlsl_lane_s16(t32[3], vget_high_s16(s0), cospi_4_12_20N_28, 2);
dct_const_round_shift_low_8_dual(t32, d0, d1);
}
static INLINE void idct_cospi_14_18(const int16x8_t s0, const int16x8_t s1,
const int16x4_t cospi_6_26N_14_18N,
int16x8_t *const d0, int16x8_t *const d1) {
int32x4_t t32[4];
t32[0] = vmull_lane_s16(vget_low_s16(s0), cospi_6_26N_14_18N, 2);
t32[1] = vmull_lane_s16(vget_high_s16(s0), cospi_6_26N_14_18N, 2);
t32[2] = vmull_lane_s16(vget_low_s16(s1), cospi_6_26N_14_18N, 2);
t32[3] = vmull_lane_s16(vget_high_s16(s1), cospi_6_26N_14_18N, 2);
t32[0] = vmlal_lane_s16(t32[0], vget_low_s16(s1), cospi_6_26N_14_18N, 3);
t32[1] = vmlal_lane_s16(t32[1], vget_high_s16(s1), cospi_6_26N_14_18N, 3);
t32[2] = vmlsl_lane_s16(t32[2], vget_low_s16(s0), cospi_6_26N_14_18N, 3);
t32[3] = vmlsl_lane_s16(t32[3], vget_high_s16(s0), cospi_6_26N_14_18N, 3);
dct_const_round_shift_low_8_dual(t32, d0, d1);
}
static INLINE void idct16x16_add_stage7(const int16x8_t *const step2,
int16x8_t *const out) {
#if CONFIG_VP9_HIGHBITDEPTH
// Use saturating add/sub to avoid overflow in 2nd pass
out[0] = vqaddq_s16(step2[0], step2[15]);
out[1] = vqaddq_s16(step2[1], step2[14]);
out[2] = vqaddq_s16(step2[2], step2[13]);
out[3] = vqaddq_s16(step2[3], step2[12]);
out[4] = vqaddq_s16(step2[4], step2[11]);
out[5] = vqaddq_s16(step2[5], step2[10]);
out[6] = vqaddq_s16(step2[6], step2[9]);
out[7] = vqaddq_s16(step2[7], step2[8]);
out[8] = vqsubq_s16(step2[7], step2[8]);
out[9] = vqsubq_s16(step2[6], step2[9]);
out[10] = vqsubq_s16(step2[5], step2[10]);
out[11] = vqsubq_s16(step2[4], step2[11]);
out[12] = vqsubq_s16(step2[3], step2[12]);
out[13] = vqsubq_s16(step2[2], step2[13]);
out[14] = vqsubq_s16(step2[1], step2[14]);
out[15] = vqsubq_s16(step2[0], step2[15]);
#else
out[0] = vaddq_s16(step2[0], step2[15]);
out[1] = vaddq_s16(step2[1], step2[14]);
out[2] = vaddq_s16(step2[2], step2[13]);
out[3] = vaddq_s16(step2[3], step2[12]);
out[4] = vaddq_s16(step2[4], step2[11]);
out[5] = vaddq_s16(step2[5], step2[10]);
out[6] = vaddq_s16(step2[6], step2[9]);
out[7] = vaddq_s16(step2[7], step2[8]);
out[8] = vsubq_s16(step2[7], step2[8]);
out[9] = vsubq_s16(step2[6], step2[9]);
out[10] = vsubq_s16(step2[5], step2[10]);
out[11] = vsubq_s16(step2[4], step2[11]);
out[12] = vsubq_s16(step2[3], step2[12]);
out[13] = vsubq_s16(step2[2], step2[13]);
out[14] = vsubq_s16(step2[1], step2[14]);
out[15] = vsubq_s16(step2[0], step2[15]);
#endif
}
static INLINE void idct16x16_store_pass1(const int16x8_t *const out,
int16_t *output) {
// Save the result into output
vst1q_s16(output, out[0]);
output += 16;
vst1q_s16(output, out[1]);
output += 16;
vst1q_s16(output, out[2]);
output += 16;
vst1q_s16(output, out[3]);
output += 16;
vst1q_s16(output, out[4]);
output += 16;
vst1q_s16(output, out[5]);
output += 16;
vst1q_s16(output, out[6]);
output += 16;
vst1q_s16(output, out[7]);
output += 16;
vst1q_s16(output, out[8]);
output += 16;
vst1q_s16(output, out[9]);
output += 16;
vst1q_s16(output, out[10]);
output += 16;
vst1q_s16(output, out[11]);
output += 16;
vst1q_s16(output, out[12]);
output += 16;
vst1q_s16(output, out[13]);
output += 16;
vst1q_s16(output, out[14]);
output += 16;
vst1q_s16(output, out[15]);
}
static INLINE void idct8x8_add8x1(const int16x8_t a, uint8_t **const dest,
const int stride) {
const uint8x8_t s = vld1_u8(*dest);
const int16x8_t res = vrshrq_n_s16(a, 5);
const uint16x8_t q = vaddw_u8(vreinterpretq_u16_s16(res), s);
const uint8x8_t d = vqmovun_s16(vreinterpretq_s16_u16(q));
vst1_u8(*dest, d);
*dest += stride;
}
static INLINE void idct8x8_add8x8_neon(int16x8_t *const out, uint8_t *dest,
const int stride) {
idct8x8_add8x1(out[0], &dest, stride);
idct8x8_add8x1(out[1], &dest, stride);
idct8x8_add8x1(out[2], &dest, stride);
idct8x8_add8x1(out[3], &dest, stride);
idct8x8_add8x1(out[4], &dest, stride);
idct8x8_add8x1(out[5], &dest, stride);
idct8x8_add8x1(out[6], &dest, stride);
idct8x8_add8x1(out[7], &dest, stride);
}
static INLINE void idct16x16_add8x1(const int16x8_t a, uint8_t **const dest,
const int stride) {
const uint8x8_t s = vld1_u8(*dest);
const int16x8_t res = vrshrq_n_s16(a, 6);
const uint16x8_t q = vaddw_u8(vreinterpretq_u16_s16(res), s);
const uint8x8_t d = vqmovun_s16(vreinterpretq_s16_u16(q));
vst1_u8(*dest, d);
*dest += stride;
}
static INLINE void idct16x16_add_store(const int16x8_t *const out,
uint8_t *dest, const int stride) {
// Add the result to dest
idct16x16_add8x1(out[0], &dest, stride);
idct16x16_add8x1(out[1], &dest, stride);
idct16x16_add8x1(out[2], &dest, stride);
idct16x16_add8x1(out[3], &dest, stride);
idct16x16_add8x1(out[4], &dest, stride);
idct16x16_add8x1(out[5], &dest, stride);
idct16x16_add8x1(out[6], &dest, stride);
idct16x16_add8x1(out[7], &dest, stride);
idct16x16_add8x1(out[8], &dest, stride);
idct16x16_add8x1(out[9], &dest, stride);
idct16x16_add8x1(out[10], &dest, stride);
idct16x16_add8x1(out[11], &dest, stride);
idct16x16_add8x1(out[12], &dest, stride);
idct16x16_add8x1(out[13], &dest, stride);
idct16x16_add8x1(out[14], &dest, stride);
idct16x16_add8x1(out[15], &dest, stride);
}
static INLINE void highbd_idct16x16_add8x1(const int16x8_t a,
const int16x8_t max,
uint16_t **const dest,
const int stride) {
const uint16x8_t s = vld1q_u16(*dest);
const int16x8_t res0 = vqaddq_s16(a, vreinterpretq_s16_u16(s));
const int16x8_t res1 = vminq_s16(res0, max);
const uint16x8_t d = vqshluq_n_s16(res1, 0);
vst1q_u16(*dest, d);
*dest += stride;
}
static INLINE void idct16x16_add_store_bd8(int16x8_t *const out, uint16_t *dest,
const int stride) {
// Add the result to dest
const int16x8_t max = vdupq_n_s16((1 << 8) - 1);
out[0] = vrshrq_n_s16(out[0], 6);
out[1] = vrshrq_n_s16(out[1], 6);
out[2] = vrshrq_n_s16(out[2], 6);
out[3] = vrshrq_n_s16(out[3], 6);
out[4] = vrshrq_n_s16(out[4], 6);
out[5] = vrshrq_n_s16(out[5], 6);
out[6] = vrshrq_n_s16(out[6], 6);
out[7] = vrshrq_n_s16(out[7], 6);
out[8] = vrshrq_n_s16(out[8], 6);
out[9] = vrshrq_n_s16(out[9], 6);
out[10] = vrshrq_n_s16(out[10], 6);
out[11] = vrshrq_n_s16(out[11], 6);
out[12] = vrshrq_n_s16(out[12], 6);
out[13] = vrshrq_n_s16(out[13], 6);
out[14] = vrshrq_n_s16(out[14], 6);
out[15] = vrshrq_n_s16(out[15], 6);
highbd_idct16x16_add8x1(out[0], max, &dest, stride);
highbd_idct16x16_add8x1(out[1], max, &dest, stride);
highbd_idct16x16_add8x1(out[2], max, &dest, stride);
highbd_idct16x16_add8x1(out[3], max, &dest, stride);
highbd_idct16x16_add8x1(out[4], max, &dest, stride);
highbd_idct16x16_add8x1(out[5], max, &dest, stride);
highbd_idct16x16_add8x1(out[6], max, &dest, stride);
highbd_idct16x16_add8x1(out[7], max, &dest, stride);
highbd_idct16x16_add8x1(out[8], max, &dest, stride);
highbd_idct16x16_add8x1(out[9], max, &dest, stride);
highbd_idct16x16_add8x1(out[10], max, &dest, stride);
highbd_idct16x16_add8x1(out[11], max, &dest, stride);
highbd_idct16x16_add8x1(out[12], max, &dest, stride);
highbd_idct16x16_add8x1(out[13], max, &dest, stride);
highbd_idct16x16_add8x1(out[14], max, &dest, stride);
highbd_idct16x16_add8x1(out[15], max, &dest, stride);
}
static INLINE void highbd_idct16x16_add8x1_bd8(const int16x8_t a,
uint16_t **const dest,
const int stride) {
const uint16x8_t s = vld1q_u16(*dest);
const int16x8_t res = vrsraq_n_s16(vreinterpretq_s16_u16(s), a, 6);
const uint16x8_t d = vmovl_u8(vqmovun_s16(res));
vst1q_u16(*dest, d);
*dest += stride;
}
static INLINE void highbd_add_and_store_bd8(const int16x8_t *const a,
uint16_t *out, const int stride) {
highbd_idct16x16_add8x1_bd8(a[0], &out, stride);
highbd_idct16x16_add8x1_bd8(a[1], &out, stride);
highbd_idct16x16_add8x1_bd8(a[2], &out, stride);
highbd_idct16x16_add8x1_bd8(a[3], &out, stride);
highbd_idct16x16_add8x1_bd8(a[4], &out, stride);
highbd_idct16x16_add8x1_bd8(a[5], &out, stride);
highbd_idct16x16_add8x1_bd8(a[6], &out, stride);
highbd_idct16x16_add8x1_bd8(a[7], &out, stride);
highbd_idct16x16_add8x1_bd8(a[8], &out, stride);
highbd_idct16x16_add8x1_bd8(a[9], &out, stride);
highbd_idct16x16_add8x1_bd8(a[10], &out, stride);
highbd_idct16x16_add8x1_bd8(a[11], &out, stride);
highbd_idct16x16_add8x1_bd8(a[12], &out, stride);
highbd_idct16x16_add8x1_bd8(a[13], &out, stride);
highbd_idct16x16_add8x1_bd8(a[14], &out, stride);
highbd_idct16x16_add8x1_bd8(a[15], &out, stride);
highbd_idct16x16_add8x1_bd8(a[16], &out, stride);
highbd_idct16x16_add8x1_bd8(a[17], &out, stride);
highbd_idct16x16_add8x1_bd8(a[18], &out, stride);
highbd_idct16x16_add8x1_bd8(a[19], &out, stride);
highbd_idct16x16_add8x1_bd8(a[20], &out, stride);
highbd_idct16x16_add8x1_bd8(a[21], &out, stride);
highbd_idct16x16_add8x1_bd8(a[22], &out, stride);
highbd_idct16x16_add8x1_bd8(a[23], &out, stride);
highbd_idct16x16_add8x1_bd8(a[24], &out, stride);
highbd_idct16x16_add8x1_bd8(a[25], &out, stride);
highbd_idct16x16_add8x1_bd8(a[26], &out, stride);
highbd_idct16x16_add8x1_bd8(a[27], &out, stride);
highbd_idct16x16_add8x1_bd8(a[28], &out, stride);
highbd_idct16x16_add8x1_bd8(a[29], &out, stride);
highbd_idct16x16_add8x1_bd8(a[30], &out, stride);
highbd_idct16x16_add8x1_bd8(a[31], &out, stride);
}
void vpx_idct16x16_256_add_half1d(const void *const input, int16_t *output,
void *const dest, const int stride,
const int highbd_flag);
void vpx_idct16x16_38_add_half1d(const void *const input, int16_t *const output,
void *const dest, const int stride,
const int highbd_flag);
void vpx_idct16x16_10_add_half1d_pass1(const tran_low_t *input,
int16_t *output);
void vpx_idct16x16_10_add_half1d_pass2(const int16_t *input,
int16_t *const output, void *const dest,
const int stride, const int highbd_flag);
void vpx_idct32_32_neon(const tran_low_t *input, uint8_t *dest,
const int stride, const int highbd_flag);
void vpx_idct32_12_neon(const tran_low_t *const input, int16_t *output);
void vpx_idct32_16_neon(const int16_t *const input, void *const output,
const int stride, const int highbd_flag);
void vpx_idct32_6_neon(const tran_low_t *input, int16_t *output);
void vpx_idct32_8_neon(const int16_t *input, void *const output, int stride,
const int highbd_flag);
#endif // VPX_VPX_DSP_ARM_IDCT_NEON_H_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,630 @@
;
; Copyright (c) 2014 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
EXPORT |vpx_v_predictor_4x4_neon|
EXPORT |vpx_v_predictor_8x8_neon|
EXPORT |vpx_v_predictor_16x16_neon|
EXPORT |vpx_v_predictor_32x32_neon|
EXPORT |vpx_h_predictor_4x4_neon|
EXPORT |vpx_h_predictor_8x8_neon|
EXPORT |vpx_h_predictor_16x16_neon|
EXPORT |vpx_h_predictor_32x32_neon|
EXPORT |vpx_tm_predictor_4x4_neon|
EXPORT |vpx_tm_predictor_8x8_neon|
EXPORT |vpx_tm_predictor_16x16_neon|
EXPORT |vpx_tm_predictor_32x32_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
;void vpx_v_predictor_4x4_neon(uint8_t *dst, ptrdiff_t y_stride,
; const uint8_t *above,
; const uint8_t *left)
; r0 uint8_t *dst
; r1 ptrdiff_t y_stride
; r2 const uint8_t *above
; r3 const uint8_t *left
|vpx_v_predictor_4x4_neon| PROC
vld1.32 {d0[0]}, [r2]
vst1.32 {d0[0]}, [r0], r1
vst1.32 {d0[0]}, [r0], r1
vst1.32 {d0[0]}, [r0], r1
vst1.32 {d0[0]}, [r0], r1
bx lr
ENDP ; |vpx_v_predictor_4x4_neon|
;void vpx_v_predictor_8x8_neon(uint8_t *dst, ptrdiff_t y_stride,
; const uint8_t *above,
; const uint8_t *left)
; r0 uint8_t *dst
; r1 ptrdiff_t y_stride
; r2 const uint8_t *above
; r3 const uint8_t *left
|vpx_v_predictor_8x8_neon| PROC
vld1.8 {d0}, [r2]
vst1.8 {d0}, [r0], r1
vst1.8 {d0}, [r0], r1
vst1.8 {d0}, [r0], r1
vst1.8 {d0}, [r0], r1
vst1.8 {d0}, [r0], r1
vst1.8 {d0}, [r0], r1
vst1.8 {d0}, [r0], r1
vst1.8 {d0}, [r0], r1
bx lr
ENDP ; |vpx_v_predictor_8x8_neon|
;void vpx_v_predictor_16x16_neon(uint8_t *dst, ptrdiff_t y_stride,
; const uint8_t *above,
; const uint8_t *left)
; r0 uint8_t *dst
; r1 ptrdiff_t y_stride
; r2 const uint8_t *above
; r3 const uint8_t *left
|vpx_v_predictor_16x16_neon| PROC
vld1.8 {q0}, [r2]
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
vst1.8 {q0}, [r0], r1
bx lr
ENDP ; |vpx_v_predictor_16x16_neon|
;void vpx_v_predictor_32x32_neon(uint8_t *dst, ptrdiff_t y_stride,
; const uint8_t *above,
; const uint8_t *left)
; r0 uint8_t *dst
; r1 ptrdiff_t y_stride
; r2 const uint8_t *above
; r3 const uint8_t *left
|vpx_v_predictor_32x32_neon| PROC
vld1.8 {q0, q1}, [r2]
mov r2, #2
loop_v
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
vst1.8 {q0, q1}, [r0], r1
subs r2, r2, #1
bgt loop_v
bx lr
ENDP ; |vpx_v_predictor_32x32_neon|
;void vpx_h_predictor_4x4_neon(uint8_t *dst, ptrdiff_t y_stride,
; const uint8_t *above,
; const uint8_t *left)
; r0 uint8_t *dst
; r1 ptrdiff_t y_stride
; r2 const uint8_t *above
; r3 const uint8_t *left
|vpx_h_predictor_4x4_neon| PROC
vld1.32 {d1[0]}, [r3]
vdup.8 d0, d1[0]
vst1.32 {d0[0]}, [r0], r1
vdup.8 d0, d1[1]
vst1.32 {d0[0]}, [r0], r1
vdup.8 d0, d1[2]
vst1.32 {d0[0]}, [r0], r1
vdup.8 d0, d1[3]
vst1.32 {d0[0]}, [r0], r1
bx lr
ENDP ; |vpx_h_predictor_4x4_neon|
;void vpx_h_predictor_8x8_neon(uint8_t *dst, ptrdiff_t y_stride,
; const uint8_t *above,
; const uint8_t *left)
; r0 uint8_t *dst
; r1 ptrdiff_t y_stride
; r2 const uint8_t *above
; r3 const uint8_t *left
|vpx_h_predictor_8x8_neon| PROC
vld1.64 {d1}, [r3]
vdup.8 d0, d1[0]
vst1.64 {d0}, [r0], r1
vdup.8 d0, d1[1]
vst1.64 {d0}, [r0], r1
vdup.8 d0, d1[2]
vst1.64 {d0}, [r0], r1
vdup.8 d0, d1[3]
vst1.64 {d0}, [r0], r1
vdup.8 d0, d1[4]
vst1.64 {d0}, [r0], r1
vdup.8 d0, d1[5]
vst1.64 {d0}, [r0], r1
vdup.8 d0, d1[6]
vst1.64 {d0}, [r0], r1
vdup.8 d0, d1[7]
vst1.64 {d0}, [r0], r1
bx lr
ENDP ; |vpx_h_predictor_8x8_neon|
;void vpx_h_predictor_16x16_neon(uint8_t *dst, ptrdiff_t y_stride,
; const uint8_t *above,
; const uint8_t *left)
; r0 uint8_t *dst
; r1 ptrdiff_t y_stride
; r2 const uint8_t *above
; r3 const uint8_t *left
|vpx_h_predictor_16x16_neon| PROC
vld1.8 {q1}, [r3]
vdup.8 q0, d2[0]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[1]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[2]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[3]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[4]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[5]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[6]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[7]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[0]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[1]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[2]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[3]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[4]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[5]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[6]
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[7]
vst1.8 {q0}, [r0], r1
bx lr
ENDP ; |vpx_h_predictor_16x16_neon|
;void vpx_h_predictor_32x32_neon(uint8_t *dst, ptrdiff_t y_stride,
; const uint8_t *above,
; const uint8_t *left)
; r0 uint8_t *dst
; r1 ptrdiff_t y_stride
; r2 const uint8_t *above
; r3 const uint8_t *left
|vpx_h_predictor_32x32_neon| PROC
sub r1, r1, #16
mov r2, #2
loop_h
vld1.8 {q1}, [r3]!
vdup.8 q0, d2[0]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[1]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[2]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[3]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[4]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[5]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[6]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d2[7]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[0]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[1]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[2]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[3]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[4]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[5]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[6]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
vdup.8 q0, d3[7]
vst1.8 {q0}, [r0]!
vst1.8 {q0}, [r0], r1
subs r2, r2, #1
bgt loop_h
bx lr
ENDP ; |vpx_h_predictor_32x32_neon|
;void vpx_tm_predictor_4x4_neon (uint8_t *dst, ptrdiff_t y_stride,
; const uint8_t *above,
; const uint8_t *left)
; r0 uint8_t *dst
; r1 ptrdiff_t y_stride
; r2 const uint8_t *above
; r3 const uint8_t *left
|vpx_tm_predictor_4x4_neon| PROC
; Load ytop_left = above[-1];
sub r12, r2, #1
vld1.u8 {d0[]}, [r12]
; Load above 4 pixels
vld1.32 {d2[0]}, [r2]
; Compute above - ytop_left
vsubl.u8 q3, d2, d0
; Load left row by row and compute left + (above - ytop_left)
; 1st row and 2nd row
vld1.u8 {d2[]}, [r3]!
vld1.u8 {d4[]}, [r3]!
vmovl.u8 q1, d2
vmovl.u8 q2, d4
vadd.s16 q1, q1, q3
vadd.s16 q2, q2, q3
vqmovun.s16 d0, q1
vqmovun.s16 d1, q2
vst1.32 {d0[0]}, [r0], r1
vst1.32 {d1[0]}, [r0], r1
; 3rd row and 4th row
vld1.u8 {d2[]}, [r3]!
vld1.u8 {d4[]}, [r3]
vmovl.u8 q1, d2
vmovl.u8 q2, d4
vadd.s16 q1, q1, q3
vadd.s16 q2, q2, q3
vqmovun.s16 d0, q1
vqmovun.s16 d1, q2
vst1.32 {d0[0]}, [r0], r1
vst1.32 {d1[0]}, [r0], r1
bx lr
ENDP ; |vpx_tm_predictor_4x4_neon|
;void vpx_tm_predictor_8x8_neon (uint8_t *dst, ptrdiff_t y_stride,
; const uint8_t *above,
; const uint8_t *left)
; r0 uint8_t *dst
; r1 ptrdiff_t y_stride
; r2 const uint8_t *above
; r3 const uint8_t *left
|vpx_tm_predictor_8x8_neon| PROC
; Load ytop_left = above[-1];
sub r12, r2, #1
vld1.8 {d0[]}, [r12]
; preload 8 left
vld1.8 {d30}, [r3]
; Load above 8 pixels
vld1.64 {d2}, [r2]
vmovl.u8 q10, d30
; Compute above - ytop_left
vsubl.u8 q3, d2, d0
; Load left row by row and compute left + (above - ytop_left)
; 1st row and 2nd row
vdup.16 q0, d20[0]
vdup.16 q1, d20[1]
vadd.s16 q0, q3, q0
vadd.s16 q1, q3, q1
; 3rd row and 4th row
vdup.16 q8, d20[2]
vdup.16 q9, d20[3]
vadd.s16 q8, q3, q8
vadd.s16 q9, q3, q9
vqmovun.s16 d0, q0
vqmovun.s16 d1, q1
vqmovun.s16 d2, q8
vqmovun.s16 d3, q9
vst1.64 {d0}, [r0], r1
vst1.64 {d1}, [r0], r1
vst1.64 {d2}, [r0], r1
vst1.64 {d3}, [r0], r1
; 5th row and 6th row
vdup.16 q0, d21[0]
vdup.16 q1, d21[1]
vadd.s16 q0, q3, q0
vadd.s16 q1, q3, q1
; 7th row and 8th row
vdup.16 q8, d21[2]
vdup.16 q9, d21[3]
vadd.s16 q8, q3, q8
vadd.s16 q9, q3, q9
vqmovun.s16 d0, q0
vqmovun.s16 d1, q1
vqmovun.s16 d2, q8
vqmovun.s16 d3, q9
vst1.64 {d0}, [r0], r1
vst1.64 {d1}, [r0], r1
vst1.64 {d2}, [r0], r1
vst1.64 {d3}, [r0], r1
bx lr
ENDP ; |vpx_tm_predictor_8x8_neon|
;void vpx_tm_predictor_16x16_neon (uint8_t *dst, ptrdiff_t y_stride,
; const uint8_t *above,
; const uint8_t *left)
; r0 uint8_t *dst
; r1 ptrdiff_t y_stride
; r2 const uint8_t *above
; r3 const uint8_t *left
|vpx_tm_predictor_16x16_neon| PROC
; Load ytop_left = above[-1];
sub r12, r2, #1
vld1.8 {d0[]}, [r12]
; Load above 8 pixels
vld1.8 {q1}, [r2]
; preload 8 left into r12
vld1.8 {d18}, [r3]!
; Compute above - ytop_left
vsubl.u8 q2, d2, d0
vsubl.u8 q3, d3, d0
vmovl.u8 q10, d18
; Load left row by row and compute left + (above - ytop_left)
; Process 8 rows in each single loop and loop 2 times to process 16 rows.
mov r2, #2
loop_16x16_neon
; Process two rows.
vdup.16 q0, d20[0]
vdup.16 q8, d20[1]
vadd.s16 q1, q0, q2
vadd.s16 q0, q0, q3
vadd.s16 q11, q8, q2
vadd.s16 q8, q8, q3
vqmovun.s16 d2, q1
vqmovun.s16 d3, q0
vqmovun.s16 d22, q11
vqmovun.s16 d23, q8
vdup.16 q0, d20[2] ; proload next 2 rows data
vdup.16 q8, d20[3]
vst1.64 {d2,d3}, [r0], r1
vst1.64 {d22,d23}, [r0], r1
; Process two rows.
vadd.s16 q1, q0, q2
vadd.s16 q0, q0, q3
vadd.s16 q11, q8, q2
vadd.s16 q8, q8, q3
vqmovun.s16 d2, q1
vqmovun.s16 d3, q0
vqmovun.s16 d22, q11
vqmovun.s16 d23, q8
vdup.16 q0, d21[0] ; proload next 2 rows data
vdup.16 q8, d21[1]
vst1.64 {d2,d3}, [r0], r1
vst1.64 {d22,d23}, [r0], r1
vadd.s16 q1, q0, q2
vadd.s16 q0, q0, q3
vadd.s16 q11, q8, q2
vadd.s16 q8, q8, q3
vqmovun.s16 d2, q1
vqmovun.s16 d3, q0
vqmovun.s16 d22, q11
vqmovun.s16 d23, q8
vdup.16 q0, d21[2] ; proload next 2 rows data
vdup.16 q8, d21[3]
vst1.64 {d2,d3}, [r0], r1
vst1.64 {d22,d23}, [r0], r1
vadd.s16 q1, q0, q2
vadd.s16 q0, q0, q3
vadd.s16 q11, q8, q2
vadd.s16 q8, q8, q3
vqmovun.s16 d2, q1
vqmovun.s16 d3, q0
vqmovun.s16 d22, q11
vqmovun.s16 d23, q8
vld1.8 {d18}, [r3]! ; preload 8 left into r12
vmovl.u8 q10, d18
vst1.64 {d2,d3}, [r0], r1
vst1.64 {d22,d23}, [r0], r1
subs r2, r2, #1
bgt loop_16x16_neon
bx lr
ENDP ; |vpx_tm_predictor_16x16_neon|
;void vpx_tm_predictor_32x32_neon (uint8_t *dst, ptrdiff_t y_stride,
; const uint8_t *above,
; const uint8_t *left)
; r0 uint8_t *dst
; r1 ptrdiff_t y_stride
; r2 const uint8_t *above
; r3 const uint8_t *left
|vpx_tm_predictor_32x32_neon| PROC
; Load ytop_left = above[-1];
sub r12, r2, #1
vld1.8 {d0[]}, [r12]
; Load above 32 pixels
vld1.8 {q1}, [r2]!
vld1.8 {q2}, [r2]
; preload 8 left pixels
vld1.8 {d26}, [r3]!
; Compute above - ytop_left
vsubl.u8 q8, d2, d0
vsubl.u8 q9, d3, d0
vsubl.u8 q10, d4, d0
vsubl.u8 q11, d5, d0
vmovl.u8 q3, d26
; Load left row by row and compute left + (above - ytop_left)
; Process 8 rows in each single loop and loop 4 times to process 32 rows.
mov r2, #4
loop_32x32_neon
; Process two rows.
vdup.16 q0, d6[0]
vdup.16 q2, d6[1]
vadd.s16 q12, q0, q8
vadd.s16 q13, q0, q9
vadd.s16 q14, q0, q10
vadd.s16 q15, q0, q11
vqmovun.s16 d0, q12
vqmovun.s16 d1, q13
vadd.s16 q12, q2, q8
vadd.s16 q13, q2, q9
vqmovun.s16 d2, q14
vqmovun.s16 d3, q15
vadd.s16 q14, q2, q10
vadd.s16 q15, q2, q11
vst1.64 {d0-d3}, [r0], r1
vqmovun.s16 d24, q12
vqmovun.s16 d25, q13
vqmovun.s16 d26, q14
vqmovun.s16 d27, q15
vdup.16 q1, d6[2]
vdup.16 q2, d6[3]
vst1.64 {d24-d27}, [r0], r1
; Process two rows.
vadd.s16 q12, q1, q8
vadd.s16 q13, q1, q9
vadd.s16 q14, q1, q10
vadd.s16 q15, q1, q11
vqmovun.s16 d0, q12
vqmovun.s16 d1, q13
vadd.s16 q12, q2, q8
vadd.s16 q13, q2, q9
vqmovun.s16 d2, q14
vqmovun.s16 d3, q15
vadd.s16 q14, q2, q10
vadd.s16 q15, q2, q11
vst1.64 {d0-d3}, [r0], r1
vqmovun.s16 d24, q12
vqmovun.s16 d25, q13
vqmovun.s16 d26, q14
vqmovun.s16 d27, q15
vdup.16 q0, d7[0]
vdup.16 q2, d7[1]
vst1.64 {d24-d27}, [r0], r1
; Process two rows.
vadd.s16 q12, q0, q8
vadd.s16 q13, q0, q9
vadd.s16 q14, q0, q10
vadd.s16 q15, q0, q11
vqmovun.s16 d0, q12
vqmovun.s16 d1, q13
vadd.s16 q12, q2, q8
vadd.s16 q13, q2, q9
vqmovun.s16 d2, q14
vqmovun.s16 d3, q15
vadd.s16 q14, q2, q10
vadd.s16 q15, q2, q11
vst1.64 {d0-d3}, [r0], r1
vqmovun.s16 d24, q12
vqmovun.s16 d25, q13
vqmovun.s16 d26, q14
vqmovun.s16 d27, q15
vdup.16 q0, d7[2]
vdup.16 q2, d7[3]
vst1.64 {d24-d27}, [r0], r1
; Process two rows.
vadd.s16 q12, q0, q8
vadd.s16 q13, q0, q9
vadd.s16 q14, q0, q10
vadd.s16 q15, q0, q11
vqmovun.s16 d0, q12
vqmovun.s16 d1, q13
vadd.s16 q12, q2, q8
vadd.s16 q13, q2, q9
vqmovun.s16 d2, q14
vqmovun.s16 d3, q15
vadd.s16 q14, q2, q10
vadd.s16 q15, q2, q11
vst1.64 {d0-d3}, [r0], r1
vqmovun.s16 d24, q12
vqmovun.s16 d25, q13
vld1.8 {d0}, [r3]! ; preload 8 left pixels
vqmovun.s16 d26, q14
vqmovun.s16 d27, q15
vmovl.u8 q3, d0
vst1.64 {d24-d27}, [r0], r1
subs r2, r2, #1
bgt loop_32x32_neon
bx lr
ENDP ; |vpx_tm_predictor_32x32_neon|
END
@@ -0,0 +1,666 @@
;
; Copyright (c) 2013 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
EXPORT |vpx_lpf_horizontal_16_neon|
EXPORT |vpx_lpf_horizontal_16_dual_neon|
EXPORT |vpx_lpf_vertical_16_neon|
EXPORT |vpx_lpf_vertical_16_dual_neon|
ARM
AREA ||.text||, CODE, READONLY, ALIGN=2
; void mb_lpf_horizontal_edge(uint8_t *s, int p,
; const uint8_t *blimit,
; const uint8_t *limit,
; const uint8_t *thresh,
; int count)
; r0 uint8_t *s,
; r1 int p, /* pitch */
; r2 const uint8_t *blimit,
; r3 const uint8_t *limit,
; sp const uint8_t *thresh,
; r12 int count
|mb_lpf_horizontal_edge| PROC
push {r4-r8, lr}
vpush {d8-d15}
ldr r4, [sp, #88] ; load thresh
h_count
vld1.8 {d16[]}, [r2] ; load *blimit
vld1.8 {d17[]}, [r3] ; load *limit
vld1.8 {d18[]}, [r4] ; load *thresh
sub r8, r0, r1, lsl #3 ; move src pointer down by 8 lines
vld1.u8 {d0}, [r8@64], r1 ; p7
vld1.u8 {d1}, [r8@64], r1 ; p6
vld1.u8 {d2}, [r8@64], r1 ; p5
vld1.u8 {d3}, [r8@64], r1 ; p4
vld1.u8 {d4}, [r8@64], r1 ; p3
vld1.u8 {d5}, [r8@64], r1 ; p2
vld1.u8 {d6}, [r8@64], r1 ; p1
vld1.u8 {d7}, [r8@64], r1 ; p0
vld1.u8 {d8}, [r8@64], r1 ; q0
vld1.u8 {d9}, [r8@64], r1 ; q1
vld1.u8 {d10}, [r8@64], r1 ; q2
vld1.u8 {d11}, [r8@64], r1 ; q3
vld1.u8 {d12}, [r8@64], r1 ; q4
vld1.u8 {d13}, [r8@64], r1 ; q5
vld1.u8 {d14}, [r8@64], r1 ; q6
vld1.u8 {d15}, [r8@64], r1 ; q7
bl vpx_wide_mbfilter_neon
tst r7, #1
beq h_mbfilter
; flat && mask were not set for any of the channels. Just store the values
; from filter.
sub r8, r0, r1, lsl #1
vst1.u8 {d25}, [r8@64], r1 ; store op1
vst1.u8 {d24}, [r8@64], r1 ; store op0
vst1.u8 {d23}, [r8@64], r1 ; store oq0
vst1.u8 {d26}, [r8@64], r1 ; store oq1
b h_next
h_mbfilter
tst r7, #2
beq h_wide_mbfilter
; flat2 was not set for any of the channels. Just store the values from
; mbfilter.
sub r8, r0, r1, lsl #1
sub r8, r8, r1
vst1.u8 {d18}, [r8@64], r1 ; store op2
vst1.u8 {d19}, [r8@64], r1 ; store op1
vst1.u8 {d20}, [r8@64], r1 ; store op0
vst1.u8 {d21}, [r8@64], r1 ; store oq0
vst1.u8 {d22}, [r8@64], r1 ; store oq1
vst1.u8 {d23}, [r8@64], r1 ; store oq2
b h_next
h_wide_mbfilter
sub r8, r0, r1, lsl #3
add r8, r8, r1
vst1.u8 {d16}, [r8@64], r1 ; store op6
vst1.u8 {d24}, [r8@64], r1 ; store op5
vst1.u8 {d25}, [r8@64], r1 ; store op4
vst1.u8 {d26}, [r8@64], r1 ; store op3
vst1.u8 {d27}, [r8@64], r1 ; store op2
vst1.u8 {d18}, [r8@64], r1 ; store op1
vst1.u8 {d19}, [r8@64], r1 ; store op0
vst1.u8 {d20}, [r8@64], r1 ; store oq0
vst1.u8 {d21}, [r8@64], r1 ; store oq1
vst1.u8 {d22}, [r8@64], r1 ; store oq2
vst1.u8 {d23}, [r8@64], r1 ; store oq3
vst1.u8 {d1}, [r8@64], r1 ; store oq4
vst1.u8 {d2}, [r8@64], r1 ; store oq5
vst1.u8 {d3}, [r8@64], r1 ; store oq6
h_next
add r0, r0, #8
subs r12, r12, #1
bne h_count
vpop {d8-d15}
pop {r4-r8, pc}
ENDP ; |mb_lpf_horizontal_edge|
; void vpx_lpf_horizontal_16_neon(uint8_t *s, int pitch,
; const uint8_t *blimit,
; const uint8_t *limit,
; const uint8_t *thresh)
; r0 uint8_t *s,
; r1 int pitch,
; r2 const uint8_t *blimit,
; r3 const uint8_t *limit,
; sp const uint8_t *thresh
|vpx_lpf_horizontal_16_neon| PROC
mov r12, #1
b mb_lpf_horizontal_edge
ENDP ; |vpx_lpf_horizontal_16_neon|
; void vpx_lpf_horizontal_16_dual_neon(uint8_t *s, int pitch,
; const uint8_t *blimit,
; const uint8_t *limit,
; const uint8_t *thresh)
; r0 uint8_t *s,
; r1 int pitch,
; r2 const uint8_t *blimit,
; r3 const uint8_t *limit,
; sp const uint8_t *thresh
|vpx_lpf_horizontal_16_dual_neon| PROC
mov r12, #2
b mb_lpf_horizontal_edge
ENDP ; |vpx_lpf_horizontal_16_dual_neon|
; void mb_lpf_vertical_edge_w(uint8_t *s, int p, const uint8_t *blimit,
; const uint8_t *limit, const uint8_t *thresh,
; int count) {
; r0 uint8_t *s,
; r1 int p, /* pitch */
; r2 const uint8_t *blimit,
; r3 const uint8_t *limit,
; sp const uint8_t *thresh,
; r12 int count
|mb_lpf_vertical_edge_w| PROC
push {r4-r8, lr}
vpush {d8-d15}
ldr r4, [sp, #88] ; load thresh
v_count
vld1.8 {d16[]}, [r2] ; load *blimit
vld1.8 {d17[]}, [r3] ; load *limit
vld1.8 {d18[]}, [r4] ; load *thresh
sub r8, r0, #8
vld1.8 {d0}, [r8@64], r1
vld1.8 {d8}, [r0@64], r1
vld1.8 {d1}, [r8@64], r1
vld1.8 {d9}, [r0@64], r1
vld1.8 {d2}, [r8@64], r1
vld1.8 {d10}, [r0@64], r1
vld1.8 {d3}, [r8@64], r1
vld1.8 {d11}, [r0@64], r1
vld1.8 {d4}, [r8@64], r1
vld1.8 {d12}, [r0@64], r1
vld1.8 {d5}, [r8@64], r1
vld1.8 {d13}, [r0@64], r1
vld1.8 {d6}, [r8@64], r1
vld1.8 {d14}, [r0@64], r1
vld1.8 {d7}, [r8@64], r1
vld1.8 {d15}, [r0@64], r1
sub r0, r0, r1, lsl #3
vtrn.32 q0, q2
vtrn.32 q1, q3
vtrn.32 q4, q6
vtrn.32 q5, q7
vtrn.16 q0, q1
vtrn.16 q2, q3
vtrn.16 q4, q5
vtrn.16 q6, q7
vtrn.8 d0, d1
vtrn.8 d2, d3
vtrn.8 d4, d5
vtrn.8 d6, d7
vtrn.8 d8, d9
vtrn.8 d10, d11
vtrn.8 d12, d13
vtrn.8 d14, d15
bl vpx_wide_mbfilter_neon
tst r7, #1
beq v_mbfilter
; flat && mask were not set for any of the channels. Just store the values
; from filter.
sub r0, #2
vswp d23, d25
vst4.8 {d23[0], d24[0], d25[0], d26[0]}, [r0], r1
vst4.8 {d23[1], d24[1], d25[1], d26[1]}, [r0], r1
vst4.8 {d23[2], d24[2], d25[2], d26[2]}, [r0], r1
vst4.8 {d23[3], d24[3], d25[3], d26[3]}, [r0], r1
vst4.8 {d23[4], d24[4], d25[4], d26[4]}, [r0], r1
vst4.8 {d23[5], d24[5], d25[5], d26[5]}, [r0], r1
vst4.8 {d23[6], d24[6], d25[6], d26[6]}, [r0], r1
vst4.8 {d23[7], d24[7], d25[7], d26[7]}, [r0], r1
add r0, #2
b v_next
v_mbfilter
tst r7, #2
beq v_wide_mbfilter
; flat2 was not set for any of the channels. Just store the values from
; mbfilter.
sub r8, r0, #3
vst3.8 {d18[0], d19[0], d20[0]}, [r8], r1
vst3.8 {d21[0], d22[0], d23[0]}, [r0], r1
vst3.8 {d18[1], d19[1], d20[1]}, [r8], r1
vst3.8 {d21[1], d22[1], d23[1]}, [r0], r1
vst3.8 {d18[2], d19[2], d20[2]}, [r8], r1
vst3.8 {d21[2], d22[2], d23[2]}, [r0], r1
vst3.8 {d18[3], d19[3], d20[3]}, [r8], r1
vst3.8 {d21[3], d22[3], d23[3]}, [r0], r1
vst3.8 {d18[4], d19[4], d20[4]}, [r8], r1
vst3.8 {d21[4], d22[4], d23[4]}, [r0], r1
vst3.8 {d18[5], d19[5], d20[5]}, [r8], r1
vst3.8 {d21[5], d22[5], d23[5]}, [r0], r1
vst3.8 {d18[6], d19[6], d20[6]}, [r8], r1
vst3.8 {d21[6], d22[6], d23[6]}, [r0], r1
vst3.8 {d18[7], d19[7], d20[7]}, [r8], r1
vst3.8 {d21[7], d22[7], d23[7]}, [r0], r1
b v_next
v_wide_mbfilter
sub r8, r0, #8
vtrn.32 d0, d26
vtrn.32 d16, d27
vtrn.32 d24, d18
vtrn.32 d25, d19
vtrn.16 d0, d24
vtrn.16 d16, d25
vtrn.16 d26, d18
vtrn.16 d27, d19
vtrn.8 d0, d16
vtrn.8 d24, d25
vtrn.8 d26, d27
vtrn.8 d18, d19
vtrn.32 d20, d1
vtrn.32 d21, d2
vtrn.32 d22, d3
vtrn.32 d23, d15
vtrn.16 d20, d22
vtrn.16 d21, d23
vtrn.16 d1, d3
vtrn.16 d2, d15
vtrn.8 d20, d21
vtrn.8 d22, d23
vtrn.8 d1, d2
vtrn.8 d3, d15
vst1.8 {d0}, [r8@64], r1
vst1.8 {d20}, [r0@64], r1
vst1.8 {d16}, [r8@64], r1
vst1.8 {d21}, [r0@64], r1
vst1.8 {d24}, [r8@64], r1
vst1.8 {d22}, [r0@64], r1
vst1.8 {d25}, [r8@64], r1
vst1.8 {d23}, [r0@64], r1
vst1.8 {d26}, [r8@64], r1
vst1.8 {d1}, [r0@64], r1
vst1.8 {d27}, [r8@64], r1
vst1.8 {d2}, [r0@64], r1
vst1.8 {d18}, [r8@64], r1
vst1.8 {d3}, [r0@64], r1
vst1.8 {d19}, [r8@64], r1
vst1.8 {d15}, [r0@64], r1
v_next
subs r12, #1
bne v_count
vpop {d8-d15}
pop {r4-r8, pc}
ENDP ; |mb_lpf_vertical_edge_w|
; void vpx_lpf_vertical_16_neon(uint8_t *s, int p, const uint8_t *blimit,
; const uint8_t *limit, const uint8_t *thresh)
; r0 uint8_t *s,
; r1 int p, /* pitch */
; r2 const uint8_t *blimit,
; r3 const uint8_t *limit,
; sp const uint8_t *thresh
|vpx_lpf_vertical_16_neon| PROC
mov r12, #1
b mb_lpf_vertical_edge_w
ENDP ; |vpx_lpf_vertical_16_neon|
; void vpx_lpf_vertical_16_dual_neon(uint8_t *s, int p, const uint8_t *blimit,
; const uint8_t *limit,
; const uint8_t *thresh)
; r0 uint8_t *s,
; r1 int p, /* pitch */
; r2 const uint8_t *blimit,
; r3 const uint8_t *limit,
; sp const uint8_t *thresh
|vpx_lpf_vertical_16_dual_neon| PROC
mov r12, #2
b mb_lpf_vertical_edge_w
ENDP ; |vpx_lpf_vertical_16_dual_neon|
; void vpx_wide_mbfilter_neon();
; This is a helper function for the loopfilters. The invidual functions do the
; necessary load, transpose (if necessary) and store.
;
; r0-r3 PRESERVE
; d16 blimit
; d17 limit
; d18 thresh
; d0 p7
; d1 p6
; d2 p5
; d3 p4
; d4 p3
; d5 p2
; d6 p1
; d7 p0
; d8 q0
; d9 q1
; d10 q2
; d11 q3
; d12 q4
; d13 q5
; d14 q6
; d15 q7
|vpx_wide_mbfilter_neon| PROC
mov r7, #0
; filter_mask
vabd.u8 d19, d4, d5 ; abs(p3 - p2)
vabd.u8 d20, d5, d6 ; abs(p2 - p1)
vabd.u8 d21, d6, d7 ; abs(p1 - p0)
vabd.u8 d22, d9, d8 ; abs(q1 - q0)
vabd.u8 d23, d10, d9 ; abs(q2 - q1)
vabd.u8 d24, d11, d10 ; abs(q3 - q2)
; only compare the largest value to limit
vmax.u8 d19, d19, d20 ; max(abs(p3 - p2), abs(p2 - p1))
vmax.u8 d20, d21, d22 ; max(abs(p1 - p0), abs(q1 - q0))
vmax.u8 d23, d23, d24 ; max(abs(q2 - q1), abs(q3 - q2))
vmax.u8 d19, d19, d20
vabd.u8 d24, d7, d8 ; abs(p0 - q0)
vmax.u8 d19, d19, d23
vabd.u8 d23, d6, d9 ; a = abs(p1 - q1)
vqadd.u8 d24, d24, d24 ; b = abs(p0 - q0) * 2
; abs () > limit
vcge.u8 d19, d17, d19
; flatmask4
vabd.u8 d25, d7, d5 ; abs(p0 - p2)
vabd.u8 d26, d8, d10 ; abs(q0 - q2)
vabd.u8 d27, d4, d7 ; abs(p3 - p0)
vabd.u8 d28, d11, d8 ; abs(q3 - q0)
; only compare the largest value to thresh
vmax.u8 d25, d25, d26 ; max(abs(p0 - p2), abs(q0 - q2))
vmax.u8 d26, d27, d28 ; max(abs(p3 - p0), abs(q3 - q0))
vmax.u8 d25, d25, d26
vmax.u8 d20, d20, d25
vshr.u8 d23, d23, #1 ; a = a / 2
vqadd.u8 d24, d24, d23 ; a = b + a
vmov.u8 d30, #1
vcge.u8 d24, d16, d24 ; (a > blimit * 2 + limit) * -1
vcge.u8 d20, d30, d20 ; flat
vand d19, d19, d24 ; mask
; hevmask
vcgt.u8 d21, d21, d18 ; (abs(p1 - p0) > thresh)*-1
vcgt.u8 d22, d22, d18 ; (abs(q1 - q0) > thresh)*-1
vorr d21, d21, d22 ; hev
vand d16, d20, d19 ; flat && mask
vmov r5, r6, d16
; flatmask5(1, p7, p6, p5, p4, p0, q0, q4, q5, q6, q7)
vabd.u8 d22, d3, d7 ; abs(p4 - p0)
vabd.u8 d23, d12, d8 ; abs(q4 - q0)
vabd.u8 d24, d7, d2 ; abs(p0 - p5)
vabd.u8 d25, d8, d13 ; abs(q0 - q5)
vabd.u8 d26, d1, d7 ; abs(p6 - p0)
vabd.u8 d27, d14, d8 ; abs(q6 - q0)
vabd.u8 d28, d0, d7 ; abs(p7 - p0)
vabd.u8 d29, d15, d8 ; abs(q7 - q0)
; only compare the largest value to thresh
vmax.u8 d22, d22, d23 ; max(abs(p4 - p0), abs(q4 - q0))
vmax.u8 d23, d24, d25 ; max(abs(p0 - p5), abs(q0 - q5))
vmax.u8 d24, d26, d27 ; max(abs(p6 - p0), abs(q6 - q0))
vmax.u8 d25, d28, d29 ; max(abs(p7 - p0), abs(q7 - q0))
vmax.u8 d26, d22, d23
vmax.u8 d27, d24, d25
vmax.u8 d23, d26, d27
vcge.u8 d18, d30, d23 ; flat2
vmov.u8 d22, #0x80
orrs r5, r5, r6 ; Check for 0
orreq r7, r7, #1 ; Only do filter branch
vand d17, d18, d16 ; flat2 && flat && mask
vmov r5, r6, d17
; mbfilter() function
; filter() function
; convert to signed
veor d23, d8, d22 ; qs0
veor d24, d7, d22 ; ps0
veor d25, d6, d22 ; ps1
veor d26, d9, d22 ; qs1
vmov.u8 d27, #3
vsub.s8 d28, d23, d24 ; ( qs0 - ps0)
vqsub.s8 d29, d25, d26 ; filter = clamp(ps1-qs1)
vmull.s8 q15, d28, d27 ; 3 * ( qs0 - ps0)
vand d29, d29, d21 ; filter &= hev
vaddw.s8 q15, q15, d29 ; filter + 3 * (qs0 - ps0)
vmov.u8 d29, #4
; filter = clamp(filter + 3 * ( qs0 - ps0))
vqmovn.s16 d28, q15
vand d28, d28, d19 ; filter &= mask
vqadd.s8 d30, d28, d27 ; filter2 = clamp(filter+3)
vqadd.s8 d29, d28, d29 ; filter1 = clamp(filter+4)
vshr.s8 d30, d30, #3 ; filter2 >>= 3
vshr.s8 d29, d29, #3 ; filter1 >>= 3
vqadd.s8 d24, d24, d30 ; op0 = clamp(ps0 + filter2)
vqsub.s8 d23, d23, d29 ; oq0 = clamp(qs0 - filter1)
; outer tap adjustments: ++filter1 >> 1
vrshr.s8 d29, d29, #1
vbic d29, d29, d21 ; filter &= ~hev
vqadd.s8 d25, d25, d29 ; op1 = clamp(ps1 + filter)
vqsub.s8 d26, d26, d29 ; oq1 = clamp(qs1 - filter)
veor d24, d24, d22 ; *f_op0 = u^0x80
veor d23, d23, d22 ; *f_oq0 = u^0x80
veor d25, d25, d22 ; *f_op1 = u^0x80
veor d26, d26, d22 ; *f_oq1 = u^0x80
tst r7, #1
bxne lr
orrs r5, r5, r6 ; Check for 0
orreq r7, r7, #2 ; Only do mbfilter branch
; mbfilter flat && mask branch
; TODO(fgalligan): Can I decrease the cycles shifting to consective d's
; and using vibt on the q's?
vmov.u8 d29, #2
vaddl.u8 q15, d7, d8 ; op2 = p0 + q0
vmlal.u8 q15, d4, d27 ; op2 = p0 + q0 + p3 * 3
vmlal.u8 q15, d5, d29 ; op2 = p0 + q0 + p3 * 3 + p2 * 2
vaddl.u8 q10, d4, d5
vaddw.u8 q15, d6 ; op2=p1 + p0 + q0 + p3 * 3 + p2 *2
vaddl.u8 q14, d6, d9
vqrshrn.u16 d18, q15, #3 ; r_op2
vsub.i16 q15, q10
vaddl.u8 q10, d4, d6
vadd.i16 q15, q14
vaddl.u8 q14, d7, d10
vqrshrn.u16 d19, q15, #3 ; r_op1
vsub.i16 q15, q10
vadd.i16 q15, q14
vaddl.u8 q14, d8, d11
vqrshrn.u16 d20, q15, #3 ; r_op0
vsubw.u8 q15, d4 ; oq0 = op0 - p3
vsubw.u8 q15, d7 ; oq0 -= p0
vadd.i16 q15, q14
vaddl.u8 q14, d9, d11
vqrshrn.u16 d21, q15, #3 ; r_oq0
vsubw.u8 q15, d5 ; oq1 = oq0 - p2
vsubw.u8 q15, d8 ; oq1 -= q0
vadd.i16 q15, q14
vaddl.u8 q14, d10, d11
vqrshrn.u16 d22, q15, #3 ; r_oq1
vsubw.u8 q15, d6 ; oq2 = oq0 - p1
vsubw.u8 q15, d9 ; oq2 -= q1
vadd.i16 q15, q14
vqrshrn.u16 d27, q15, #3 ; r_oq2
; Filter does not set op2 or oq2, so use p2 and q2.
vbif d18, d5, d16 ; t_op2 |= p2 & ~(flat & mask)
vbif d19, d25, d16 ; t_op1 |= f_op1 & ~(flat & mask)
vbif d20, d24, d16 ; t_op0 |= f_op0 & ~(flat & mask)
vbif d21, d23, d16 ; t_oq0 |= f_oq0 & ~(flat & mask)
vbif d22, d26, d16 ; t_oq1 |= f_oq1 & ~(flat & mask)
vbit d23, d27, d16 ; t_oq2 |= r_oq2 & (flat & mask)
vbif d23, d10, d16 ; t_oq2 |= q2 & ~(flat & mask)
tst r7, #2
bxne lr
; wide_mbfilter flat2 && flat && mask branch
vmov.u8 d16, #7
vaddl.u8 q15, d7, d8 ; op6 = p0 + q0
vaddl.u8 q12, d2, d3
vaddl.u8 q13, d4, d5
vaddl.u8 q14, d1, d6
vmlal.u8 q15, d0, d16 ; op6 += p7 * 3
vadd.i16 q12, q13
vadd.i16 q15, q14
vaddl.u8 q14, d2, d9
vadd.i16 q15, q12
vaddl.u8 q12, d0, d1
vaddw.u8 q15, d1
vaddl.u8 q13, d0, d2
vadd.i16 q14, q15, q14
vqrshrn.u16 d16, q15, #4 ; w_op6
vsub.i16 q15, q14, q12
vaddl.u8 q14, d3, d10
vqrshrn.u16 d24, q15, #4 ; w_op5
vsub.i16 q15, q13
vaddl.u8 q13, d0, d3
vadd.i16 q15, q14
vaddl.u8 q14, d4, d11
vqrshrn.u16 d25, q15, #4 ; w_op4
vadd.i16 q15, q14
vaddl.u8 q14, d0, d4
vsub.i16 q15, q13
vsub.i16 q14, q15, q14
vqrshrn.u16 d26, q15, #4 ; w_op3
vaddw.u8 q15, q14, d5 ; op2 += p2
vaddl.u8 q14, d0, d5
vaddw.u8 q15, d12 ; op2 += q4
vbif d26, d4, d17 ; op3 |= p3 & ~(f2 & f & m)
vqrshrn.u16 d27, q15, #4 ; w_op2
vsub.i16 q15, q14
vaddl.u8 q14, d0, d6
vaddw.u8 q15, d6 ; op1 += p1
vaddw.u8 q15, d13 ; op1 += q5
vbif d27, d18, d17 ; op2 |= t_op2 & ~(f2 & f & m)
vqrshrn.u16 d18, q15, #4 ; w_op1
vsub.i16 q15, q14
vaddl.u8 q14, d0, d7
vaddw.u8 q15, d7 ; op0 += p0
vaddw.u8 q15, d14 ; op0 += q6
vbif d18, d19, d17 ; op1 |= t_op1 & ~(f2 & f & m)
vqrshrn.u16 d19, q15, #4 ; w_op0
vsub.i16 q15, q14
vaddl.u8 q14, d1, d8
vaddw.u8 q15, d8 ; oq0 += q0
vaddw.u8 q15, d15 ; oq0 += q7
vbif d19, d20, d17 ; op0 |= t_op0 & ~(f2 & f & m)
vqrshrn.u16 d20, q15, #4 ; w_oq0
vsub.i16 q15, q14
vaddl.u8 q14, d2, d9
vaddw.u8 q15, d9 ; oq1 += q1
vaddl.u8 q4, d10, d15
vaddw.u8 q15, d15 ; oq1 += q7
vbif d20, d21, d17 ; oq0 |= t_oq0 & ~(f2 & f & m)
vqrshrn.u16 d21, q15, #4 ; w_oq1
vsub.i16 q15, q14
vaddl.u8 q14, d3, d10
vadd.i16 q15, q4
vaddl.u8 q4, d11, d15
vbif d21, d22, d17 ; oq1 |= t_oq1 & ~(f2 & f & m)
vqrshrn.u16 d22, q15, #4 ; w_oq2
vsub.i16 q15, q14
vaddl.u8 q14, d4, d11
vadd.i16 q15, q4
vaddl.u8 q4, d12, d15
vbif d22, d23, d17 ; oq2 |= t_oq2 & ~(f2 & f & m)
vqrshrn.u16 d23, q15, #4 ; w_oq3
vsub.i16 q15, q14
vaddl.u8 q14, d5, d12
vadd.i16 q15, q4
vaddl.u8 q4, d13, d15
vbif d16, d1, d17 ; op6 |= p6 & ~(f2 & f & m)
vqrshrn.u16 d1, q15, #4 ; w_oq4
vsub.i16 q15, q14
vaddl.u8 q14, d6, d13
vadd.i16 q15, q4
vaddl.u8 q4, d14, d15
vbif d24, d2, d17 ; op5 |= p5 & ~(f2 & f & m)
vqrshrn.u16 d2, q15, #4 ; w_oq5
vsub.i16 q15, q14
vbif d25, d3, d17 ; op4 |= p4 & ~(f2 & f & m)
vadd.i16 q15, q4
vbif d23, d11, d17 ; oq3 |= q3 & ~(f2 & f & m)
vqrshrn.u16 d3, q15, #4 ; w_oq6
vbif d1, d12, d17 ; oq4 |= q4 & ~(f2 & f & m)
vbif d2, d13, d17 ; oq5 |= q5 & ~(f2 & f & m)
vbif d3, d14, d17 ; oq6 |= q6 & ~(f2 & f & m)
bx lr
ENDP ; |vpx_wide_mbfilter_neon|
END
@@ -0,0 +1,549 @@
;
; Copyright (c) 2013 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
EXPORT |vpx_lpf_horizontal_4_neon|
EXPORT |vpx_lpf_vertical_4_neon|
EXPORT |vpx_lpf_horizontal_4_dual_neon|
EXPORT |vpx_lpf_vertical_4_dual_neon|
ARM
AREA ||.text||, CODE, READONLY, ALIGN=2
; Currently vpx only works on iterations 8 at a time. The vp8 loop filter
; works on 16 iterations at a time.
;
; void vpx_lpf_horizontal_4_neon(uint8_t *s,
; int p /* pitch */,
; const uint8_t *blimit,
; const uint8_t *limit,
; const uint8_t *thresh)
;
; r0 uint8_t *s,
; r1 int p, /* pitch */
; r2 const uint8_t *blimit,
; r3 const uint8_t *limit,
; sp const uint8_t *thresh,
|vpx_lpf_horizontal_4_neon| PROC
push {lr}
vld1.8 {d0[]}, [r2] ; duplicate *blimit
ldr r2, [sp, #4] ; load thresh
add r1, r1, r1 ; double pitch
vld1.8 {d1[]}, [r3] ; duplicate *limit
vld1.8 {d2[]}, [r2] ; duplicate *thresh
sub r2, r0, r1, lsl #1 ; move src pointer down by 4 lines
add r3, r2, r1, lsr #1 ; set to 3 lines down
vld1.u8 {d3}, [r2@64], r1 ; p3
vld1.u8 {d4}, [r3@64], r1 ; p2
vld1.u8 {d5}, [r2@64], r1 ; p1
vld1.u8 {d6}, [r3@64], r1 ; p0
vld1.u8 {d7}, [r2@64], r1 ; q0
vld1.u8 {d16}, [r3@64], r1 ; q1
vld1.u8 {d17}, [r2@64] ; q2
vld1.u8 {d18}, [r3@64] ; q3
sub r2, r2, r1, lsl #1
sub r3, r3, r1, lsl #1
bl filter4_8
vst1.u8 {d4}, [r2@64], r1 ; store op1
vst1.u8 {d5}, [r3@64], r1 ; store op0
vst1.u8 {d6}, [r2@64], r1 ; store oq0
vst1.u8 {d7}, [r3@64], r1 ; store oq1
pop {pc}
ENDP ; |vpx_lpf_horizontal_4_neon|
; Currently vpx only works on iterations 8 at a time. The vp8 loop filter
; works on 16 iterations at a time.
;
; void vpx_lpf_vertical_4_neon(uint8_t *s,
; int p /* pitch */,
; const uint8_t *blimit,
; const uint8_t *limit,
; const uint8_t *thresh)
;
; r0 uint8_t *s,
; r1 int p, /* pitch */
; r2 const uint8_t *blimit,
; r3 const uint8_t *limit,
; sp const uint8_t *thresh,
|vpx_lpf_vertical_4_neon| PROC
push {lr}
vld1.8 {d0[]}, [r2] ; duplicate *blimit
vld1.8 {d1[]}, [r3] ; duplicate *limit
ldr r3, [sp, #4] ; load thresh
sub r2, r0, #4 ; move s pointer down by 4 columns
vld1.8 {d2[]}, [r3] ; duplicate *thresh
vld1.u8 {d3}, [r2], r1 ; load s data
vld1.u8 {d4}, [r2], r1
vld1.u8 {d5}, [r2], r1
vld1.u8 {d6}, [r2], r1
vld1.u8 {d7}, [r2], r1
vld1.u8 {d16}, [r2], r1
vld1.u8 {d17}, [r2], r1
vld1.u8 {d18}, [r2]
;transpose to 8x16 matrix
vtrn.32 d3, d7
vtrn.32 d4, d16
vtrn.32 d5, d17
vtrn.32 d6, d18
vtrn.16 d3, d5
vtrn.16 d4, d6
vtrn.16 d7, d17
vtrn.16 d16, d18
vtrn.8 d3, d4
vtrn.8 d5, d6
vtrn.8 d7, d16
vtrn.8 d17, d18
bl filter4_8
sub r0, r0, #2
;store op1, op0, oq0, oq1
vst4.8 {d4[0], d5[0], d6[0], d7[0]}, [r0], r1
vst4.8 {d4[1], d5[1], d6[1], d7[1]}, [r0], r1
vst4.8 {d4[2], d5[2], d6[2], d7[2]}, [r0], r1
vst4.8 {d4[3], d5[3], d6[3], d7[3]}, [r0], r1
vst4.8 {d4[4], d5[4], d6[4], d7[4]}, [r0], r1
vst4.8 {d4[5], d5[5], d6[5], d7[5]}, [r0], r1
vst4.8 {d4[6], d5[6], d6[6], d7[6]}, [r0], r1
vst4.8 {d4[7], d5[7], d6[7], d7[7]}, [r0]
pop {pc}
ENDP ; |vpx_lpf_vertical_4_neon|
; void filter4_8();
; This is a helper function for the loopfilters. The invidual functions do the
; necessary load, transpose (if necessary) and store. The function does not use
; registers d8-d15.
;
; Inputs:
; r0-r3, r12 PRESERVE
; d0 blimit
; d1 limit
; d2 thresh
; d3 p3
; d4 p2
; d5 p1
; d6 p0
; d7 q0
; d16 q1
; d17 q2
; d18 q3
;
; Outputs:
; d4 op1
; d5 op0
; d6 oq0
; d7 oq1
|filter4_8| PROC
; filter_mask
vabd.u8 d19, d3, d4 ; m1 = abs(p3 - p2)
vabd.u8 d20, d4, d5 ; m2 = abs(p2 - p1)
vabd.u8 d21, d5, d6 ; m3 = abs(p1 - p0)
vabd.u8 d22, d16, d7 ; m4 = abs(q1 - q0)
vabd.u8 d3, d17, d16 ; m5 = abs(q2 - q1)
vabd.u8 d4, d18, d17 ; m6 = abs(q3 - q2)
; only compare the largest value to limit
vmax.u8 d19, d19, d20 ; m1 = max(m1, m2)
vmax.u8 d20, d21, d22 ; m2 = max(m3, m4)
vabd.u8 d17, d6, d7 ; abs(p0 - q0)
vmax.u8 d3, d3, d4 ; m3 = max(m5, m6)
vmov.u8 d18, #0x80
vmax.u8 d23, d19, d20 ; m1 = max(m1, m2)
; hevmask
vcgt.u8 d21, d21, d2 ; (abs(p1 - p0) > thresh)*-1
vcgt.u8 d22, d22, d2 ; (abs(q1 - q0) > thresh)*-1
vmax.u8 d23, d23, d3 ; m1 = max(m1, m3)
vabd.u8 d28, d5, d16 ; a = abs(p1 - q1)
vqadd.u8 d17, d17, d17 ; b = abs(p0 - q0) * 2
veor d7, d7, d18 ; qs0
vcge.u8 d23, d1, d23 ; abs(m1) > limit
; filter() function
; convert to signed
vshr.u8 d28, d28, #1 ; a = a / 2
veor d6, d6, d18 ; ps0
veor d5, d5, d18 ; ps1
vqadd.u8 d17, d17, d28 ; a = b + a
veor d16, d16, d18 ; qs1
vmov.u8 d19, #3
vsub.s8 d28, d7, d6 ; ( qs0 - ps0)
vcge.u8 d17, d0, d17 ; a > blimit
vqsub.s8 d27, d5, d16 ; filter = clamp(ps1-qs1)
vorr d22, d21, d22 ; hevmask
vmull.s8 q12, d28, d19 ; 3 * ( qs0 - ps0)
vand d27, d27, d22 ; filter &= hev
vand d23, d23, d17 ; filter_mask
vaddw.s8 q12, q12, d27 ; filter + 3 * (qs0 - ps0)
vmov.u8 d17, #4
; filter = clamp(filter + 3 * ( qs0 - ps0))
vqmovn.s16 d27, q12
vand d27, d27, d23 ; filter &= mask
vqadd.s8 d28, d27, d19 ; filter2 = clamp(filter+3)
vqadd.s8 d27, d27, d17 ; filter1 = clamp(filter+4)
vshr.s8 d28, d28, #3 ; filter2 >>= 3
vshr.s8 d27, d27, #3 ; filter1 >>= 3
vqadd.s8 d19, d6, d28 ; u = clamp(ps0 + filter2)
vqsub.s8 d26, d7, d27 ; u = clamp(qs0 - filter1)
; outer tap adjustments
vrshr.s8 d27, d27, #1 ; filter = ++filter1 >> 1
veor d6, d26, d18 ; *oq0 = u^0x80
vbic d27, d27, d22 ; filter &= ~hev
vqadd.s8 d21, d5, d27 ; u = clamp(ps1 + filter)
vqsub.s8 d20, d16, d27 ; u = clamp(qs1 - filter)
veor d5, d19, d18 ; *op0 = u^0x80
veor d4, d21, d18 ; *op1 = u^0x80
veor d7, d20, d18 ; *oq1 = u^0x80
bx lr
ENDP ; |filter4_8|
;void vpx_lpf_horizontal_4_dual_neon(uint8_t *s, int p,
; const uint8_t *blimit0,
; const uint8_t *limit0,
; const uint8_t *thresh0,
; const uint8_t *blimit1,
; const uint8_t *limit1,
; const uint8_t *thresh1)
; r0 uint8_t *s,
; r1 int p,
; r2 const uint8_t *blimit0,
; r3 const uint8_t *limit0,
; sp const uint8_t *thresh0,
; sp+4 const uint8_t *blimit1,
; sp+8 const uint8_t *limit1,
; sp+12 const uint8_t *thresh1,
|vpx_lpf_horizontal_4_dual_neon| PROC
push {lr}
ldr r12, [sp, #4] ; load thresh0
vld1.8 {d0}, [r2] ; load blimit0 to first half q
vld1.8 {d2}, [r3] ; load limit0 to first half q
add r1, r1, r1 ; double pitch
ldr r2, [sp, #8] ; load blimit1
vld1.8 {d4}, [r12] ; load thresh0 to first half q
ldr r3, [sp, #12] ; load limit1
ldr r12, [sp, #16] ; load thresh1
vld1.8 {d1}, [r2] ; load blimit1 to 2nd half q
sub r2, r0, r1, lsl #1 ; s[-4 * p]
vld1.8 {d3}, [r3] ; load limit1 to 2nd half q
vld1.8 {d5}, [r12] ; load thresh1 to 2nd half q
vpush {d8-d15} ; save neon registers
add r3, r2, r1, lsr #1 ; s[-3 * p]
vld1.u8 {q3}, [r2@64], r1 ; p3
vld1.u8 {q4}, [r3@64], r1 ; p2
vld1.u8 {q5}, [r2@64], r1 ; p1
vld1.u8 {q6}, [r3@64], r1 ; p0
vld1.u8 {q7}, [r2@64], r1 ; q0
vld1.u8 {q8}, [r3@64], r1 ; q1
vld1.u8 {q9}, [r2@64] ; q2
vld1.u8 {q10}, [r3@64] ; q3
sub r2, r2, r1, lsl #1
sub r3, r3, r1, lsl #1
bl filter4_16
vst1.u8 {q5}, [r2@64], r1 ; store op1
vst1.u8 {q6}, [r3@64], r1 ; store op0
vst1.u8 {q7}, [r2@64], r1 ; store oq0
vst1.u8 {q8}, [r3@64], r1 ; store oq1
vpop {d8-d15} ; restore neon registers
pop {pc}
ENDP ; |vpx_lpf_horizontal_4_dual_neon|
;void vpx_lpf_vertical_4_dual_neon(uint8_t *s, int p,
; const uint8_t *blimit0,
; const uint8_t *limit0,
; const uint8_t *thresh0,
; const uint8_t *blimit1,
; const uint8_t *limit1,
; const uint8_t *thresh1)
; r0 uint8_t *s,
; r1 int p,
; r2 const uint8_t *blimit0,
; r3 const uint8_t *limit0,
; sp const uint8_t *thresh0,
; sp+4 const uint8_t *blimit1,
; sp+8 const uint8_t *limit1,
; sp+12 const uint8_t *thresh1,
|vpx_lpf_vertical_4_dual_neon| PROC
push {lr}
ldr r12, [sp, #4] ; load thresh0
vld1.8 {d0}, [r2] ; load blimit0 to first half q
vld1.8 {d2}, [r3] ; load limit0 to first half q
ldr r2, [sp, #8] ; load blimit1
vld1.8 {d4}, [r12] ; load thresh0 to first half q
ldr r3, [sp, #12] ; load limit1
ldr r12, [sp, #16] ; load thresh1
vld1.8 {d1}, [r2] ; load blimit1 to 2nd half q
sub r2, r0, #4 ; s[-4]
vld1.8 {d3}, [r3] ; load limit1 to 2nd half q
vld1.8 {d5}, [r12] ; load thresh1 to 2nd half q
vpush {d8-d15} ; save neon registers
vld1.u8 {d6}, [r2], r1 ; 00 01 02 03 04 05 06 07
vld1.u8 {d8}, [r2], r1 ; 10 11 12 13 14 15 16 17
vld1.u8 {d10}, [r2], r1 ; 20 21 22 23 24 25 26 27
vld1.u8 {d12}, [r2], r1 ; 30 31 32 33 34 35 36 37
vld1.u8 {d14}, [r2], r1 ; 40 41 42 43 44 45 46 47
vld1.u8 {d16}, [r2], r1 ; 50 51 52 53 54 55 56 57
vld1.u8 {d18}, [r2], r1 ; 60 61 62 63 64 65 66 67
vld1.u8 {d20}, [r2], r1 ; 70 71 72 73 74 75 76 77
vld1.u8 {d7}, [r2], r1 ; 80 81 82 83 84 85 86 87
vld1.u8 {d9}, [r2], r1 ; 90 91 92 93 94 95 96 97
vld1.u8 {d11}, [r2], r1 ; A0 A1 A2 A3 A4 A5 A6 A7
vld1.u8 {d13}, [r2], r1 ; B0 B1 B2 B3 B4 B5 B6 B7
vld1.u8 {d15}, [r2], r1 ; C0 C1 C2 C3 C4 C5 C6 C7
vld1.u8 {d17}, [r2], r1 ; D0 D1 D2 D3 D4 D5 D6 D7
vld1.u8 {d19}, [r2], r1 ; E0 E1 E2 E3 E4 E5 E6 E7
vld1.u8 {d21}, [r2] ; F0 F1 F2 F3 F4 F5 F6 F7
vtrn.8 q3, q4 ; q3 : 00 10 02 12 04 14 06 16 80 90 82 92 84 94 86 96
; q4 : 01 11 03 13 05 15 07 17 81 91 83 93 85 95 87 97
vtrn.8 q5, q6 ; q5 : 20 30 22 32 24 34 26 36 A0 B0 A2 B2 A4 B4 A6 B6
; q6 : 21 31 23 33 25 35 27 37 A1 B1 A3 B3 A5 B5 A7 B7
vtrn.8 q7, q8 ; q7 : 40 50 42 52 44 54 46 56 C0 D0 C2 D2 C4 D4 C6 D6
; q8 : 41 51 43 53 45 55 47 57 C1 D1 C3 D3 C5 D5 C7 D7
vtrn.8 q9, q10 ; q9 : 60 70 62 72 64 74 66 76 E0 F0 E2 F2 E4 F4 E6 F6
; q10: 61 71 63 73 65 75 67 77 E1 F1 E3 F3 E5 F5 E7 F7
vtrn.16 q3, q5 ; q3 : 00 10 20 30 04 14 24 34 80 90 A0 B0 84 94 A4 B4
; q5 : 02 12 22 32 06 16 26 36 82 92 A2 B2 86 96 A6 B6
vtrn.16 q4, q6 ; q4 : 01 11 21 31 05 15 25 35 81 91 A1 B1 85 95 A5 B5
; q6 : 03 13 23 33 07 17 27 37 83 93 A3 B3 87 97 A7 B7
vtrn.16 q7, q9 ; q7 : 40 50 60 70 44 54 64 74 C0 D0 E0 F0 C4 D4 E4 F4
; q9 : 42 52 62 72 46 56 66 76 C2 D2 E2 F2 C6 D6 E6 F6
vtrn.16 q8, q10 ; q8 : 41 51 61 71 45 55 65 75 C1 D1 E1 F1 C5 D5 E5 F5
; q10: 43 53 63 73 47 57 67 77 C3 D3 E3 F3 C7 D7 E7 F7
vtrn.32 q3, q7 ; q3 : 00 10 20 30 40 50 60 70 80 90 A0 B0 C0 D0 E0 F0
; q7 : 04 14 24 34 44 54 64 74 84 94 A4 B4 C4 D4 E4 F4
vtrn.32 q5, q9 ; q5 : 02 12 22 32 42 52 62 72 82 92 A2 B2 C2 D2 E2 F2
; q9 : 06 16 26 36 46 56 66 76 86 96 A6 B6 C6 D6 E6 F6
vtrn.32 q4, q8 ; q4 : 01 11 21 31 41 51 61 71 81 91 A1 B1 C1 D1 E1 F1
; q8 : 05 15 25 35 45 55 65 75 85 95 A5 B5 C5 D5 E5 F5
vtrn.32 q6, q10 ; q6 : 03 13 23 33 43 53 63 73 83 93 A3 B3 C3 D3 E3 F3
; q10: 07 17 27 37 47 57 67 77 87 97 A7 B7 C7 D7 E7 F7
bl filter4_16
sub r0, #2
vmov d0, d11
vmov d1, d13
vmov d2, d15
vmov d3, d17
vmov d11, d12
vmov d12, d14
vmov d13, d16
vst4.8 {d10[0], d11[0], d12[0], d13[0]}, [r0], r1
vst4.8 {d10[1], d11[1], d12[1], d13[1]}, [r0], r1
vst4.8 {d10[2], d11[2], d12[2], d13[2]}, [r0], r1
vst4.8 {d10[3], d11[3], d12[3], d13[3]}, [r0], r1
vst4.8 {d10[4], d11[4], d12[4], d13[4]}, [r0], r1
vst4.8 {d10[5], d11[5], d12[5], d13[5]}, [r0], r1
vst4.8 {d10[6], d11[6], d12[6], d13[6]}, [r0], r1
vst4.8 {d10[7], d11[7], d12[7], d13[7]}, [r0], r1
vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0], r1
vst4.8 {d0[1], d1[1], d2[1], d3[1]}, [r0], r1
vst4.8 {d0[2], d1[2], d2[2], d3[2]}, [r0], r1
vst4.8 {d0[3], d1[3], d2[3], d3[3]}, [r0], r1
vst4.8 {d0[4], d1[4], d2[4], d3[4]}, [r0], r1
vst4.8 {d0[5], d1[5], d2[5], d3[5]}, [r0], r1
vst4.8 {d0[6], d1[6], d2[6], d3[6]}, [r0], r1
vst4.8 {d0[7], d1[7], d2[7], d3[7]}, [r0]
vpop {d8-d15} ; restore neon registers
pop {pc}
ENDP ; |vpx_lpf_vertical_4_dual_neon|
; void filter4_16();
; This is a helper function for the loopfilters. The invidual functions do the
; necessary load, transpose (if necessary) and store. This function uses
; registers d8-d15, so the calling function must save those registers.
;
; r0-r3, r12 PRESERVE
; q0 blimit
; q1 limit
; q2 thresh
; q3 p3
; q4 p2
; q5 p1
; q6 p0
; q7 q0
; q8 q1
; q9 q2
; q10 q3
;
; Outputs:
; q5 op1
; q6 op0
; q7 oq0
; q8 oq1
|filter4_16| PROC
; filter_mask
vabd.u8 q11, q3, q4 ; m1 = abs(p3 - p2)
vabd.u8 q12, q4, q5 ; m2 = abs(p2 - p1)
vabd.u8 q13, q5, q6 ; m3 = abs(p1 - p0)
vabd.u8 q14, q8, q7 ; m4 = abs(q1 - q0)
vabd.u8 q3, q9, q8 ; m5 = abs(q2 - q1)
vabd.u8 q4, q10, q9 ; m6 = abs(q3 - q2)
; only compare the largest value to limit
vmax.u8 q11, q11, q12 ; m7 = max(m1, m2)
vmax.u8 q12, q13, q14 ; m8 = max(m3, m4)
vabd.u8 q9, q6, q7 ; abs(p0 - q0)
vmax.u8 q3, q3, q4 ; m9 = max(m5, m6)
vmov.u8 q10, #0x80
vmax.u8 q15, q11, q12 ; m10 = max(m7, m8)
vcgt.u8 q13, q13, q2 ; (abs(p1 - p0) > thresh)*-1
vcgt.u8 q14, q14, q2 ; (abs(q1 - q0) > thresh)*-1
vmax.u8 q15, q15, q3 ; m11 = max(m10, m9)
vabd.u8 q2, q5, q8 ; a = abs(p1 - q1)
vqadd.u8 q9, q9, q9 ; b = abs(p0 - q0) * 2
veor q7, q7, q10 ; qs0
vcge.u8 q15, q1, q15 ; abs(m11) > limit
vshr.u8 q2, q2, #1 ; a = a / 2
veor q6, q6, q10 ; ps0
veor q5, q5, q10 ; ps1
vqadd.u8 q9, q9, q2 ; a = b + a
veor q8, q8, q10 ; qs1
vmov.u16 q4, #3
vsubl.s8 q2, d14, d12 ; ( qs0 - ps0)
vsubl.s8 q11, d15, d13
vcge.u8 q9, q0, q9 ; a > blimit
vqsub.s8 q1, q5, q8 ; filter = clamp(ps1-qs1)
vorr q14, q13, q14 ; hev
vmul.i16 q2, q2, q4 ; 3 * ( qs0 - ps0)
vmul.i16 q11, q11, q4
vand q1, q1, q14 ; filter &= hev
vand q15, q15, q9 ; mask
vmov.u8 q4, #3
vaddw.s8 q2, q2, d2 ; filter + 3 * (qs0 - ps0)
vaddw.s8 q11, q11, d3
vmov.u8 q9, #4
; filter = clamp(filter + 3 * ( qs0 - ps0))
vqmovn.s16 d2, q2
vqmovn.s16 d3, q11
vand q1, q1, q15 ; filter &= mask
vqadd.s8 q2, q1, q4 ; filter2 = clamp(filter+3)
vqadd.s8 q1, q1, q9 ; filter1 = clamp(filter+4)
vshr.s8 q2, q2, #3 ; filter2 >>= 3
vshr.s8 q1, q1, #3 ; filter1 >>= 3
vqadd.s8 q11, q6, q2 ; u = clamp(ps0 + filter2)
vqsub.s8 q0, q7, q1 ; u = clamp(qs0 - filter1)
; outer tap adjustments
vrshr.s8 q1, q1, #1 ; filter = ++filter1 >> 1
veor q7, q0, q10 ; *oq0 = u^0x80
vbic q1, q1, q14 ; filter &= ~hev
vqadd.s8 q13, q5, q1 ; u = clamp(ps1 + filter)
vqsub.s8 q12, q8, q1 ; u = clamp(qs1 - filter)
veor q6, q11, q10 ; *op0 = u^0x80
veor q5, q13, q10 ; *op1 = u^0x80
veor q8, q12, q10 ; *oq1 = u^0x80
bx lr
ENDP ; |filter4_16|
END
@@ -0,0 +1,491 @@
;
; Copyright (c) 2013 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
EXPORT |vpx_lpf_horizontal_8_neon|
EXPORT |vpx_lpf_horizontal_8_dual_neon|
EXPORT |vpx_lpf_vertical_8_neon|
EXPORT |vpx_lpf_vertical_8_dual_neon|
ARM
AREA ||.text||, CODE, READONLY, ALIGN=2
; Currently vpx only works on iterations 8 at a time. The vp8 loop filter
; works on 16 iterations at a time.
;
; void vpx_lpf_horizontal_8_neon(uint8_t *s, int p,
; const uint8_t *blimit,
; const uint8_t *limit,
; const uint8_t *thresh)
; r0 uint8_t *s,
; r1 int p, /* pitch */
; r2 const uint8_t *blimit,
; r3 const uint8_t *limit,
; sp const uint8_t *thresh,
|vpx_lpf_horizontal_8_neon| PROC
push {r4-r5, lr}
vld1.8 {d0[]}, [r2] ; duplicate *blimit
ldr r2, [sp, #12] ; load thresh
add r1, r1, r1 ; double pitch
vld1.8 {d1[]}, [r3] ; duplicate *limit
vld1.8 {d2[]}, [r2] ; duplicate *thresh
sub r3, r0, r1, lsl #1 ; move src pointer down by 4 lines
add r2, r3, r1, lsr #1 ; set to 3 lines down
vld1.u8 {d3}, [r3@64], r1 ; p3
vld1.u8 {d4}, [r2@64], r1 ; p2
vld1.u8 {d5}, [r3@64], r1 ; p1
vld1.u8 {d6}, [r2@64], r1 ; p0
vld1.u8 {d7}, [r3@64], r1 ; q0
vld1.u8 {d16}, [r2@64], r1 ; q1
vld1.u8 {d17}, [r3@64] ; q2
vld1.u8 {d18}, [r2@64], r1 ; q3
sub r3, r3, r1, lsl #1
sub r2, r2, r1, lsl #2
bl vpx_mbloop_filter_neon
vst1.u8 {d0}, [r2@64], r1 ; store op2
vst1.u8 {d1}, [r3@64], r1 ; store op1
vst1.u8 {d2}, [r2@64], r1 ; store op0
vst1.u8 {d3}, [r3@64], r1 ; store oq0
vst1.u8 {d4}, [r2@64], r1 ; store oq1
vst1.u8 {d5}, [r3@64], r1 ; store oq2
pop {r4-r5, pc}
ENDP ; |vpx_lpf_horizontal_8_neon|
;void vpx_lpf_horizontal_8_dual_neon(uint8_t *s,
; int p,
; const uint8_t *blimit0,
; const uint8_t *limit0,
; const uint8_t *thresh0,
; const uint8_t *blimit1,
; const uint8_t *limit1,
; const uint8_t *thresh1)
; r0 uint8_t *s,
; r1 int p, /* pitch */
; r2 const uint8_t *blimit0,
; r3 const uint8_t *limit0,
; sp const uint8_t *thresh0,
; sp + 4 const uint8_t *blimit1,
; sp + 8 const uint8_t *limit1,
; sp + 12 const uint8_t *thresh1,
|vpx_lpf_horizontal_8_dual_neon| PROC
push {r0-r1, lr}
ldr lr, [sp, #12]
push {lr} ; thresh0
bl vpx_lpf_horizontal_8_neon
ldr r2, [sp, #20] ; blimit1
ldr r3, [sp, #24] ; limit1
ldr lr, [sp, #28]
str lr, [sp, #16] ; thresh1
add sp, #4
pop {r0-r1, lr}
add r0, #8 ; s + 8
b vpx_lpf_horizontal_8_neon
ENDP ; |vpx_lpf_horizontal_8_dual_neon|
; void vpx_lpf_vertical_8_neon(uint8_t *s,
; int pitch,
; const uint8_t *blimit,
; const uint8_t *limit,
; const uint8_t *thresh)
;
; r0 uint8_t *s,
; r1 int pitch,
; r2 const uint8_t *blimit,
; r3 const uint8_t *limit,
; sp const uint8_t *thresh,
|vpx_lpf_vertical_8_neon| PROC
push {r4-r5, lr}
vld1.8 {d0[]}, [r2] ; duplicate *blimit
vld1.8 {d1[]}, [r3] ; duplicate *limit
ldr r3, [sp, #12] ; load thresh
sub r2, r0, #4 ; move s pointer down by 4 columns
vld1.8 {d2[]}, [r3] ; duplicate *thresh
vld1.u8 {d3}, [r2], r1 ; load s data
vld1.u8 {d4}, [r2], r1
vld1.u8 {d5}, [r2], r1
vld1.u8 {d6}, [r2], r1
vld1.u8 {d7}, [r2], r1
vld1.u8 {d16}, [r2], r1
vld1.u8 {d17}, [r2], r1
vld1.u8 {d18}, [r2]
;transpose to 8x16 matrix
vtrn.32 d3, d7
vtrn.32 d4, d16
vtrn.32 d5, d17
vtrn.32 d6, d18
vtrn.16 d3, d5
vtrn.16 d4, d6
vtrn.16 d7, d17
vtrn.16 d16, d18
vtrn.8 d3, d4
vtrn.8 d5, d6
vtrn.8 d7, d16
vtrn.8 d17, d18
sub r2, r0, #3
add r3, r0, #1
bl vpx_mbloop_filter_neon
;store op2, op1, op0, oq0
vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r2], r1
vst4.8 {d0[1], d1[1], d2[1], d3[1]}, [r2], r1
vst4.8 {d0[2], d1[2], d2[2], d3[2]}, [r2], r1
vst4.8 {d0[3], d1[3], d2[3], d3[3]}, [r2], r1
vst4.8 {d0[4], d1[4], d2[4], d3[4]}, [r2], r1
vst4.8 {d0[5], d1[5], d2[5], d3[5]}, [r2], r1
vst4.8 {d0[6], d1[6], d2[6], d3[6]}, [r2], r1
vst4.8 {d0[7], d1[7], d2[7], d3[7]}, [r2]
;store oq1, oq2
vst2.8 {d4[0], d5[0]}, [r3], r1
vst2.8 {d4[1], d5[1]}, [r3], r1
vst2.8 {d4[2], d5[2]}, [r3], r1
vst2.8 {d4[3], d5[3]}, [r3], r1
vst2.8 {d4[4], d5[4]}, [r3], r1
vst2.8 {d4[5], d5[5]}, [r3], r1
vst2.8 {d4[6], d5[6]}, [r3], r1
vst2.8 {d4[7], d5[7]}, [r3]
pop {r4-r5, pc}
ENDP ; |vpx_lpf_vertical_8_neon|
;void vpx_lpf_vertical_8_dual_neon(uint8_t *s,
; int pitch,
; const uint8_t *blimit0,
; const uint8_t *limit0,
; const uint8_t *thresh0,
; const uint8_t *blimit1,
; const uint8_t *limit1,
; const uint8_t *thresh1)
; r0 uint8_t *s,
; r1 int pitch
; r2 const uint8_t *blimit0,
; r3 const uint8_t *limit0,
; sp const uint8_t *thresh0,
; sp + 4 const uint8_t *blimit1,
; sp + 8 const uint8_t *limit1,
; sp + 12 const uint8_t *thresh1,
|vpx_lpf_vertical_8_dual_neon| PROC
push {r0-r1, lr}
ldr lr, [sp, #12]
push {lr} ; thresh0
bl vpx_lpf_vertical_8_neon
ldr r2, [sp, #20] ; blimit1
ldr r3, [sp, #24] ; limit1
ldr lr, [sp, #28]
str lr, [sp, #16] ; thresh1
add sp, #4
pop {r0-r1, lr}
add r0, r0, r1, lsl #3 ; s + 8 * pitch
b vpx_lpf_vertical_8_neon
ENDP ; |vpx_lpf_vertical_8_dual_neon|
; void vpx_mbloop_filter_neon();
; This is a helper function for the loopfilters. The invidual functions do the
; necessary load, transpose (if necessary) and store. The function does not use
; registers d8-d15.
;
; Inputs:
; r0-r3, r12 PRESERVE
; d0 blimit
; d1 limit
; d2 thresh
; d3 p3
; d4 p2
; d5 p1
; d6 p0
; d7 q0
; d16 q1
; d17 q2
; d18 q3
;
; Outputs:
; d0 op2
; d1 op1
; d2 op0
; d3 oq0
; d4 oq1
; d5 oq2
|vpx_mbloop_filter_neon| PROC
; filter_mask
vabd.u8 d19, d3, d4 ; m1 = abs(p3 - p2)
vabd.u8 d20, d4, d5 ; m2 = abs(p2 - p1)
vabd.u8 d21, d5, d6 ; m3 = abs(p1 - p0)
vabd.u8 d22, d16, d7 ; m4 = abs(q1 - q0)
vabd.u8 d23, d17, d16 ; m5 = abs(q2 - q1)
vabd.u8 d24, d18, d17 ; m6 = abs(q3 - q2)
; only compare the largest value to limit
vmax.u8 d19, d19, d20 ; m1 = max(m1, m2)
vmax.u8 d20, d21, d22 ; m2 = max(m3, m4)
vabd.u8 d25, d6, d4 ; m7 = abs(p0 - p2)
vmax.u8 d23, d23, d24 ; m3 = max(m5, m6)
vabd.u8 d26, d7, d17 ; m8 = abs(q0 - q2)
vmax.u8 d19, d19, d20
vabd.u8 d24, d6, d7 ; m9 = abs(p0 - q0)
vabd.u8 d27, d3, d6 ; m10 = abs(p3 - p0)
vabd.u8 d28, d18, d7 ; m11 = abs(q3 - q0)
vmax.u8 d19, d19, d23
vabd.u8 d23, d5, d16 ; a = abs(p1 - q1)
vqadd.u8 d24, d24, d24 ; b = abs(p0 - q0) * 2
; abs () > limit
vcge.u8 d19, d1, d19
; only compare the largest value to thresh
vmax.u8 d25, d25, d26 ; m4 = max(m7, m8)
vmax.u8 d26, d27, d28 ; m5 = max(m10, m11)
vshr.u8 d23, d23, #1 ; a = a / 2
vmax.u8 d25, d25, d26 ; m4 = max(m4, m5)
vqadd.u8 d24, d24, d23 ; a = b + a
vmax.u8 d20, d20, d25 ; m2 = max(m2, m4)
vmov.u8 d23, #1
vcge.u8 d24, d0, d24 ; a > blimit
vcgt.u8 d21, d21, d2 ; (abs(p1 - p0) > thresh)*-1
vcge.u8 d20, d23, d20 ; flat
vand d19, d19, d24 ; mask
vcgt.u8 d23, d22, d2 ; (abs(q1 - q0) > thresh)*-1
vand d20, d20, d19 ; flat & mask
vmov.u8 d22, #0x80
vorr d23, d21, d23 ; hev
; This instruction will truncate the "flat & mask" masks down to 4 bits
; each to fit into one 32 bit arm register. The values are stored in
; q10.64[0].
vshrn.u16 d30, q10, #4
vmov.u32 r4, d30[0] ; flat & mask 4bits
adds r5, r4, #1 ; Check for all 1's
; If mask and flat are 1's for all vectors, then we only need to execute
; the power branch for all vectors.
beq power_branch_only
cmp r4, #0 ; Check for 0, set flag for later
; mbfilter() function
; filter() function
; convert to signed
veor d21, d7, d22 ; qs0
veor d24, d6, d22 ; ps0
veor d25, d5, d22 ; ps1
veor d26, d16, d22 ; qs1
vmov.u8 d27, #3
vsub.s8 d28, d21, d24 ; ( qs0 - ps0)
vqsub.s8 d29, d25, d26 ; filter = clamp(ps1-qs1)
vmull.s8 q15, d28, d27 ; 3 * ( qs0 - ps0)
vand d29, d29, d23 ; filter &= hev
vaddw.s8 q15, q15, d29 ; filter + 3 * (qs0 - ps0)
vmov.u8 d29, #4
; filter = clamp(filter + 3 * ( qs0 - ps0))
vqmovn.s16 d28, q15
vand d28, d28, d19 ; filter &= mask
vqadd.s8 d30, d28, d27 ; filter2 = clamp(filter+3)
vqadd.s8 d29, d28, d29 ; filter1 = clamp(filter+4)
vshr.s8 d30, d30, #3 ; filter2 >>= 3
vshr.s8 d29, d29, #3 ; filter1 >>= 3
vqadd.s8 d24, d24, d30 ; op0 = clamp(ps0 + filter2)
vqsub.s8 d21, d21, d29 ; oq0 = clamp(qs0 - filter1)
; outer tap adjustments: ++filter1 >> 1
vrshr.s8 d29, d29, #1
vbic d29, d29, d23 ; filter &= ~hev
vqadd.s8 d25, d25, d29 ; op1 = clamp(ps1 + filter)
vqsub.s8 d26, d26, d29 ; oq1 = clamp(qs1 - filter)
; If mask and flat are 0's for all vectors, then we only need to execute
; the filter branch for all vectors.
beq filter_branch_only
; If mask and flat are mixed then we must perform both branches and
; combine the data.
veor d24, d24, d22 ; *f_op0 = u^0x80
veor d21, d21, d22 ; *f_oq0 = u^0x80
veor d25, d25, d22 ; *f_op1 = u^0x80
veor d26, d26, d22 ; *f_oq1 = u^0x80
; At this point we have already executed the filter branch. The filter
; branch does not set op2 or oq2, so use p2 and q2. Execute the power
; branch and combine the data.
vmov.u8 d23, #2
vaddl.u8 q14, d6, d7 ; r_op2 = p0 + q0
vmlal.u8 q14, d3, d27 ; r_op2 += p3 * 3
vmlal.u8 q14, d4, d23 ; r_op2 += p2 * 2
vbif d0, d4, d20 ; op2 |= p2 & ~(flat & mask)
vaddw.u8 q14, d5 ; r_op2 += p1
vbif d1, d25, d20 ; op1 |= f_op1 & ~(flat & mask)
vqrshrn.u16 d30, q14, #3 ; r_op2
vsubw.u8 q14, d3 ; r_op1 = r_op2 - p3
vsubw.u8 q14, d4 ; r_op1 -= p2
vaddw.u8 q14, d5 ; r_op1 += p1
vaddw.u8 q14, d16 ; r_op1 += q1
vbif d2, d24, d20 ; op0 |= f_op0 & ~(flat & mask)
vqrshrn.u16 d31, q14, #3 ; r_op1
vsubw.u8 q14, d3 ; r_op0 = r_op1 - p3
vsubw.u8 q14, d5 ; r_op0 -= p1
vaddw.u8 q14, d6 ; r_op0 += p0
vaddw.u8 q14, d17 ; r_op0 += q2
vbit d0, d30, d20 ; op2 |= r_op2 & (flat & mask)
vqrshrn.u16 d23, q14, #3 ; r_op0
vsubw.u8 q14, d3 ; r_oq0 = r_op0 - p3
vsubw.u8 q14, d6 ; r_oq0 -= p0
vaddw.u8 q14, d7 ; r_oq0 += q0
vbit d1, d31, d20 ; op1 |= r_op1 & (flat & mask)
vaddw.u8 q14, d18 ; oq0 += q3
vbit d2, d23, d20 ; op0 |= r_op0 & (flat & mask)
vqrshrn.u16 d22, q14, #3 ; r_oq0
vsubw.u8 q14, d4 ; r_oq1 = r_oq0 - p2
vsubw.u8 q14, d7 ; r_oq1 -= q0
vaddw.u8 q14, d16 ; r_oq1 += q1
vbif d3, d21, d20 ; oq0 |= f_oq0 & ~(flat & mask)
vaddw.u8 q14, d18 ; r_oq1 += q3
vbif d4, d26, d20 ; oq1 |= f_oq1 & ~(flat & mask)
vqrshrn.u16 d6, q14, #3 ; r_oq1
vsubw.u8 q14, d5 ; r_oq2 = r_oq1 - p1
vsubw.u8 q14, d16 ; r_oq2 -= q1
vaddw.u8 q14, d17 ; r_oq2 += q2
vaddw.u8 q14, d18 ; r_oq2 += q3
vbif d5, d17, d20 ; oq2 |= q2 & ~(flat & mask)
vqrshrn.u16 d7, q14, #3 ; r_oq2
vbit d3, d22, d20 ; oq0 |= r_oq0 & (flat & mask)
vbit d4, d6, d20 ; oq1 |= r_oq1 & (flat & mask)
vbit d5, d7, d20 ; oq2 |= r_oq2 & (flat & mask)
bx lr
power_branch_only
vmov.u8 d27, #3
vmov.u8 d21, #2
vaddl.u8 q14, d6, d7 ; op2 = p0 + q0
vmlal.u8 q14, d3, d27 ; op2 += p3 * 3
vmlal.u8 q14, d4, d21 ; op2 += p2 * 2
vaddw.u8 q14, d5 ; op2 += p1
vqrshrn.u16 d0, q14, #3 ; op2
vsubw.u8 q14, d3 ; op1 = op2 - p3
vsubw.u8 q14, d4 ; op1 -= p2
vaddw.u8 q14, d5 ; op1 += p1
vaddw.u8 q14, d16 ; op1 += q1
vqrshrn.u16 d1, q14, #3 ; op1
vsubw.u8 q14, d3 ; op0 = op1 - p3
vsubw.u8 q14, d5 ; op0 -= p1
vaddw.u8 q14, d6 ; op0 += p0
vaddw.u8 q14, d17 ; op0 += q2
vqrshrn.u16 d2, q14, #3 ; op0
vsubw.u8 q14, d3 ; oq0 = op0 - p3
vsubw.u8 q14, d6 ; oq0 -= p0
vaddw.u8 q14, d7 ; oq0 += q0
vaddw.u8 q14, d18 ; oq0 += q3
vqrshrn.u16 d3, q14, #3 ; oq0
vsubw.u8 q14, d4 ; oq1 = oq0 - p2
vsubw.u8 q14, d7 ; oq1 -= q0
vaddw.u8 q14, d16 ; oq1 += q1
vaddw.u8 q14, d18 ; oq1 += q3
vqrshrn.u16 d4, q14, #3 ; oq1
vsubw.u8 q14, d5 ; oq2 = oq1 - p1
vsubw.u8 q14, d16 ; oq2 -= q1
vaddw.u8 q14, d17 ; oq2 += q2
vaddw.u8 q14, d18 ; oq2 += q3
vqrshrn.u16 d5, q14, #3 ; oq2
bx lr
filter_branch_only
; TODO(fgalligan): See if we can rearange registers so we do not need to
; do the 2 vswp.
vswp d0, d4 ; op2
vswp d5, d17 ; oq2
veor d2, d24, d22 ; *op0 = u^0x80
veor d3, d21, d22 ; *oq0 = u^0x80
veor d1, d25, d22 ; *op1 = u^0x80
veor d4, d26, d22 ; *oq1 = u^0x80
bx lr
ENDP ; |vpx_mbloop_filter_neon|
END
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,184 @@
/*
* Copyright (c) 2017 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VPX_VPX_DSP_ARM_MEM_NEON_H_
#define VPX_VPX_DSP_ARM_MEM_NEON_H_
#include <arm_neon.h>
#include <assert.h>
#include <string.h>
#include "./vpx_config.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/vpx_dsp_common.h"
static INLINE int16x4_t create_s16x4_neon(const int16_t c0, const int16_t c1,
const int16_t c2, const int16_t c3) {
return vcreate_s16((uint16_t)c0 | ((uint32_t)c1 << 16) |
((int64_t)(uint16_t)c2 << 32) | ((int64_t)c3 << 48));
}
static INLINE int32x2_t create_s32x2_neon(const int32_t c0, const int32_t c1) {
return vcreate_s32((uint32_t)c0 | ((int64_t)(uint32_t)c1 << 32));
}
static INLINE int32x4_t create_s32x4_neon(const int32_t c0, const int32_t c1,
const int32_t c2, const int32_t c3) {
return vcombine_s32(create_s32x2_neon(c0, c1), create_s32x2_neon(c2, c3));
}
// Helper functions used to load tran_low_t into int16, narrowing if necessary.
static INLINE int16x8x2_t load_tran_low_to_s16x2q(const tran_low_t *buf) {
#if CONFIG_VP9_HIGHBITDEPTH
const int32x4x2_t v0 = vld2q_s32(buf);
const int32x4x2_t v1 = vld2q_s32(buf + 8);
const int16x4_t s0 = vmovn_s32(v0.val[0]);
const int16x4_t s1 = vmovn_s32(v0.val[1]);
const int16x4_t s2 = vmovn_s32(v1.val[0]);
const int16x4_t s3 = vmovn_s32(v1.val[1]);
int16x8x2_t res;
res.val[0] = vcombine_s16(s0, s2);
res.val[1] = vcombine_s16(s1, s3);
return res;
#else
return vld2q_s16(buf);
#endif
}
static INLINE int16x8_t load_tran_low_to_s16q(const tran_low_t *buf) {
#if CONFIG_VP9_HIGHBITDEPTH
const int32x4_t v0 = vld1q_s32(buf);
const int32x4_t v1 = vld1q_s32(buf + 4);
const int16x4_t s0 = vmovn_s32(v0);
const int16x4_t s1 = vmovn_s32(v1);
return vcombine_s16(s0, s1);
#else
return vld1q_s16(buf);
#endif
}
static INLINE int16x4_t load_tran_low_to_s16d(const tran_low_t *buf) {
#if CONFIG_VP9_HIGHBITDEPTH
const int32x4_t v0 = vld1q_s32(buf);
return vmovn_s32(v0);
#else
return vld1_s16(buf);
#endif
}
static INLINE void store_s16q_to_tran_low(tran_low_t *buf, const int16x8_t a) {
#if CONFIG_VP9_HIGHBITDEPTH
const int32x4_t v0 = vmovl_s16(vget_low_s16(a));
const int32x4_t v1 = vmovl_s16(vget_high_s16(a));
vst1q_s32(buf, v0);
vst1q_s32(buf + 4, v1);
#else
vst1q_s16(buf, a);
#endif
}
// Propagate type information to the compiler. Without this the compiler may
// assume the required alignment of uint32_t (4 bytes) and add alignment hints
// to the memory access.
//
// This is used for functions operating on uint8_t which wish to load or store 4
// values at a time but which may not be on 4 byte boundaries.
static INLINE void uint32_to_mem(uint8_t *buf, uint32_t a) {
memcpy(buf, &a, 4);
}
// Load 2 sets of 4 bytes when alignment is not guaranteed.
static INLINE uint8x8_t load_unaligned_u8(const uint8_t *buf, int stride) {
uint32_t a;
uint32x2_t a_u32 = vdup_n_u32(0);
if (stride == 4) return vld1_u8(buf);
memcpy(&a, buf, 4);
buf += stride;
a_u32 = vset_lane_u32(a, a_u32, 0);
memcpy(&a, buf, 4);
a_u32 = vset_lane_u32(a, a_u32, 1);
return vreinterpret_u8_u32(a_u32);
}
// Store 2 sets of 4 bytes when alignment is not guaranteed.
static INLINE void store_unaligned_u8(uint8_t *buf, int stride,
const uint8x8_t a) {
const uint32x2_t a_u32 = vreinterpret_u32_u8(a);
if (stride == 4) {
vst1_u8(buf, a);
return;
}
uint32_to_mem(buf, vget_lane_u32(a_u32, 0));
buf += stride;
uint32_to_mem(buf, vget_lane_u32(a_u32, 1));
}
// Load 4 sets of 4 bytes when alignment is not guaranteed.
static INLINE uint8x16_t load_unaligned_u8q(const uint8_t *buf, int stride) {
uint32_t a;
uint32x4_t a_u32 = vdupq_n_u32(0);
if (stride == 4) return vld1q_u8(buf);
memcpy(&a, buf, 4);
buf += stride;
a_u32 = vsetq_lane_u32(a, a_u32, 0);
memcpy(&a, buf, 4);
buf += stride;
a_u32 = vsetq_lane_u32(a, a_u32, 1);
memcpy(&a, buf, 4);
buf += stride;
a_u32 = vsetq_lane_u32(a, a_u32, 2);
memcpy(&a, buf, 4);
buf += stride;
a_u32 = vsetq_lane_u32(a, a_u32, 3);
return vreinterpretq_u8_u32(a_u32);
}
// Store 4 sets of 4 bytes when alignment is not guaranteed.
static INLINE void store_unaligned_u8q(uint8_t *buf, int stride,
const uint8x16_t a) {
const uint32x4_t a_u32 = vreinterpretq_u32_u8(a);
if (stride == 4) {
vst1q_u8(buf, a);
return;
}
uint32_to_mem(buf, vgetq_lane_u32(a_u32, 0));
buf += stride;
uint32_to_mem(buf, vgetq_lane_u32(a_u32, 1));
buf += stride;
uint32_to_mem(buf, vgetq_lane_u32(a_u32, 2));
buf += stride;
uint32_to_mem(buf, vgetq_lane_u32(a_u32, 3));
}
// Load 2 sets of 4 bytes when alignment is guaranteed.
static INLINE uint8x8_t load_u8(const uint8_t *buf, int stride) {
uint32x2_t a = vdup_n_u32(0);
assert(!((intptr_t)buf % sizeof(uint32_t)));
assert(!(stride % sizeof(uint32_t)));
a = vld1_lane_u32((const uint32_t *)buf, a, 0);
buf += stride;
a = vld1_lane_u32((const uint32_t *)buf, a, 1);
return vreinterpret_u8_u32(a);
}
// Store 2 sets of 4 bytes when alignment is guaranteed.
static INLINE void store_u8(uint8_t *buf, int stride, const uint8x8_t a) {
uint32x2_t a_u32 = vreinterpret_u32_u8(a);
assert(!((intptr_t)buf % sizeof(uint32_t)));
assert(!(stride % sizeof(uint32_t)));
vst1_lane_u32((uint32_t *)buf, a_u32, 0);
buf += stride;
vst1_lane_u32((uint32_t *)buf, a_u32, 1);
}
#endif // VPX_VPX_DSP_ARM_MEM_NEON_H_
@@ -0,0 +1,317 @@
/*
* Copyright (c) 2017 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/mem_neon.h"
static INLINE void calculate_dqcoeff_and_store(const int16x8_t qcoeff,
const int16x8_t dequant,
tran_low_t *dqcoeff) {
const int32x4_t dqcoeff_0 =
vmull_s16(vget_low_s16(qcoeff), vget_low_s16(dequant));
const int32x4_t dqcoeff_1 =
vmull_s16(vget_high_s16(qcoeff), vget_high_s16(dequant));
#if CONFIG_VP9_HIGHBITDEPTH
vst1q_s32(dqcoeff, dqcoeff_0);
vst1q_s32(dqcoeff + 4, dqcoeff_1);
#else
vst1q_s16(dqcoeff, vcombine_s16(vmovn_s32(dqcoeff_0), vmovn_s32(dqcoeff_1)));
#endif // CONFIG_VP9_HIGHBITDEPTH
}
void vpx_quantize_b_neon(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
int skip_block, const int16_t *zbin_ptr,
const int16_t *round_ptr, const int16_t *quant_ptr,
const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr,
tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr,
uint16_t *eob_ptr, const int16_t *scan,
const int16_t *iscan) {
const int16x8_t one = vdupq_n_s16(1);
const int16x8_t neg_one = vdupq_n_s16(-1);
uint16x8_t eob_max;
(void)scan;
(void)skip_block;
assert(!skip_block);
// Process first 8 values which include a dc component.
{
// Only the first element of each vector is DC.
const int16x8_t zbin = vld1q_s16(zbin_ptr);
const int16x8_t round = vld1q_s16(round_ptr);
const int16x8_t quant = vld1q_s16(quant_ptr);
const int16x8_t quant_shift = vld1q_s16(quant_shift_ptr);
const int16x8_t dequant = vld1q_s16(dequant_ptr);
// Add one because the eob does not index from 0.
const uint16x8_t v_iscan =
vreinterpretq_u16_s16(vaddq_s16(vld1q_s16(iscan), one));
const int16x8_t coeff = load_tran_low_to_s16q(coeff_ptr);
const int16x8_t coeff_sign = vshrq_n_s16(coeff, 15);
const int16x8_t coeff_abs = vabsq_s16(coeff);
const int16x8_t zbin_mask =
vreinterpretq_s16_u16(vcgeq_s16(coeff_abs, zbin));
const int16x8_t rounded = vqaddq_s16(coeff_abs, round);
// (round * quant * 2) >> 16 >> 1 == (round * quant) >> 16
int16x8_t qcoeff = vshrq_n_s16(vqdmulhq_s16(rounded, quant), 1);
qcoeff = vaddq_s16(qcoeff, rounded);
// (qcoeff * quant_shift * 2) >> 16 >> 1 == (qcoeff * quant_shift) >> 16
qcoeff = vshrq_n_s16(vqdmulhq_s16(qcoeff, quant_shift), 1);
// Restore the sign bit.
qcoeff = veorq_s16(qcoeff, coeff_sign);
qcoeff = vsubq_s16(qcoeff, coeff_sign);
qcoeff = vandq_s16(qcoeff, zbin_mask);
// Set non-zero elements to -1 and use that to extract values for eob.
eob_max = vandq_u16(vtstq_s16(qcoeff, neg_one), v_iscan);
coeff_ptr += 8;
iscan += 8;
store_s16q_to_tran_low(qcoeff_ptr, qcoeff);
qcoeff_ptr += 8;
calculate_dqcoeff_and_store(qcoeff, dequant, dqcoeff_ptr);
dqcoeff_ptr += 8;
}
n_coeffs -= 8;
{
const int16x8_t zbin = vdupq_n_s16(zbin_ptr[1]);
const int16x8_t round = vdupq_n_s16(round_ptr[1]);
const int16x8_t quant = vdupq_n_s16(quant_ptr[1]);
const int16x8_t quant_shift = vdupq_n_s16(quant_shift_ptr[1]);
const int16x8_t dequant = vdupq_n_s16(dequant_ptr[1]);
do {
// Add one because the eob is not its index.
const uint16x8_t v_iscan =
vreinterpretq_u16_s16(vaddq_s16(vld1q_s16(iscan), one));
const int16x8_t coeff = load_tran_low_to_s16q(coeff_ptr);
const int16x8_t coeff_sign = vshrq_n_s16(coeff, 15);
const int16x8_t coeff_abs = vabsq_s16(coeff);
const int16x8_t zbin_mask =
vreinterpretq_s16_u16(vcgeq_s16(coeff_abs, zbin));
const int16x8_t rounded = vqaddq_s16(coeff_abs, round);
// (round * quant * 2) >> 16 >> 1 == (round * quant) >> 16
int16x8_t qcoeff = vshrq_n_s16(vqdmulhq_s16(rounded, quant), 1);
qcoeff = vaddq_s16(qcoeff, rounded);
// (qcoeff * quant_shift * 2) >> 16 >> 1 == (qcoeff * quant_shift) >> 16
qcoeff = vshrq_n_s16(vqdmulhq_s16(qcoeff, quant_shift), 1);
// Restore the sign bit.
qcoeff = veorq_s16(qcoeff, coeff_sign);
qcoeff = vsubq_s16(qcoeff, coeff_sign);
qcoeff = vandq_s16(qcoeff, zbin_mask);
// Set non-zero elements to -1 and use that to extract values for eob.
eob_max =
vmaxq_u16(eob_max, vandq_u16(vtstq_s16(qcoeff, neg_one), v_iscan));
coeff_ptr += 8;
iscan += 8;
store_s16q_to_tran_low(qcoeff_ptr, qcoeff);
qcoeff_ptr += 8;
calculate_dqcoeff_and_store(qcoeff, dequant, dqcoeff_ptr);
dqcoeff_ptr += 8;
n_coeffs -= 8;
} while (n_coeffs > 0);
}
#ifdef __aarch64__
*eob_ptr = vmaxvq_u16(eob_max);
#else
{
const uint16x4_t eob_max_0 =
vmax_u16(vget_low_u16(eob_max), vget_high_u16(eob_max));
const uint16x4_t eob_max_1 = vpmax_u16(eob_max_0, eob_max_0);
const uint16x4_t eob_max_2 = vpmax_u16(eob_max_1, eob_max_1);
vst1_lane_u16(eob_ptr, eob_max_2, 0);
}
#endif // __aarch64__
}
static INLINE int32x4_t extract_sign_bit(int32x4_t a) {
return vreinterpretq_s32_u32(vshrq_n_u32(vreinterpretq_u32_s32(a), 31));
}
static INLINE void calculate_dqcoeff_and_store_32x32(const int16x8_t qcoeff,
const int16x8_t dequant,
tran_low_t *dqcoeff) {
int32x4_t dqcoeff_0 = vmull_s16(vget_low_s16(qcoeff), vget_low_s16(dequant));
int32x4_t dqcoeff_1 =
vmull_s16(vget_high_s16(qcoeff), vget_high_s16(dequant));
// Add 1 if negative to round towards zero because the C uses division.
dqcoeff_0 = vaddq_s32(dqcoeff_0, extract_sign_bit(dqcoeff_0));
dqcoeff_1 = vaddq_s32(dqcoeff_1, extract_sign_bit(dqcoeff_1));
#if CONFIG_VP9_HIGHBITDEPTH
dqcoeff_0 = vshrq_n_s32(dqcoeff_0, 1);
dqcoeff_1 = vshrq_n_s32(dqcoeff_1, 1);
vst1q_s32(dqcoeff, dqcoeff_0);
vst1q_s32(dqcoeff + 4, dqcoeff_1);
#else
vst1q_s16(dqcoeff,
vcombine_s16(vshrn_n_s32(dqcoeff_0, 1), vshrn_n_s32(dqcoeff_1, 1)));
#endif // CONFIG_VP9_HIGHBITDEPTH
}
// Main difference is that zbin values are halved before comparison and dqcoeff
// values are divided by 2. zbin is rounded but dqcoeff is not.
void vpx_quantize_b_32x32_neon(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
int skip_block, const int16_t *zbin_ptr,
const int16_t *round_ptr,
const int16_t *quant_ptr,
const int16_t *quant_shift_ptr,
tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
const int16_t *dequant_ptr, uint16_t *eob_ptr,
const int16_t *scan, const int16_t *iscan) {
const int16x8_t one = vdupq_n_s16(1);
const int16x8_t neg_one = vdupq_n_s16(-1);
uint16x8_t eob_max;
int i;
(void)scan;
(void)n_coeffs; // Because we will always calculate 32*32.
(void)skip_block;
assert(!skip_block);
// Process first 8 values which include a dc component.
{
// Only the first element of each vector is DC.
const int16x8_t zbin = vrshrq_n_s16(vld1q_s16(zbin_ptr), 1);
const int16x8_t round = vrshrq_n_s16(vld1q_s16(round_ptr), 1);
const int16x8_t quant = vld1q_s16(quant_ptr);
const int16x8_t quant_shift = vld1q_s16(quant_shift_ptr);
const int16x8_t dequant = vld1q_s16(dequant_ptr);
// Add one because the eob does not index from 0.
const uint16x8_t v_iscan =
vreinterpretq_u16_s16(vaddq_s16(vld1q_s16(iscan), one));
const int16x8_t coeff = load_tran_low_to_s16q(coeff_ptr);
const int16x8_t coeff_sign = vshrq_n_s16(coeff, 15);
const int16x8_t coeff_abs = vabsq_s16(coeff);
const int16x8_t zbin_mask =
vreinterpretq_s16_u16(vcgeq_s16(coeff_abs, zbin));
const int16x8_t rounded = vqaddq_s16(coeff_abs, round);
// (round * quant * 2) >> 16 >> 1 == (round * quant) >> 16
int16x8_t qcoeff = vshrq_n_s16(vqdmulhq_s16(rounded, quant), 1);
qcoeff = vaddq_s16(qcoeff, rounded);
// (qcoeff * quant_shift * 2) >> 16 == (qcoeff * quant_shift) >> 15
qcoeff = vqdmulhq_s16(qcoeff, quant_shift);
// Restore the sign bit.
qcoeff = veorq_s16(qcoeff, coeff_sign);
qcoeff = vsubq_s16(qcoeff, coeff_sign);
qcoeff = vandq_s16(qcoeff, zbin_mask);
// Set non-zero elements to -1 and use that to extract values for eob.
eob_max = vandq_u16(vtstq_s16(qcoeff, neg_one), v_iscan);
coeff_ptr += 8;
iscan += 8;
store_s16q_to_tran_low(qcoeff_ptr, qcoeff);
qcoeff_ptr += 8;
calculate_dqcoeff_and_store_32x32(qcoeff, dequant, dqcoeff_ptr);
dqcoeff_ptr += 8;
}
{
const int16x8_t zbin = vrshrq_n_s16(vdupq_n_s16(zbin_ptr[1]), 1);
const int16x8_t round = vrshrq_n_s16(vdupq_n_s16(round_ptr[1]), 1);
const int16x8_t quant = vdupq_n_s16(quant_ptr[1]);
const int16x8_t quant_shift = vdupq_n_s16(quant_shift_ptr[1]);
const int16x8_t dequant = vdupq_n_s16(dequant_ptr[1]);
for (i = 1; i < 32 * 32 / 8; ++i) {
// Add one because the eob is not its index.
const uint16x8_t v_iscan =
vreinterpretq_u16_s16(vaddq_s16(vld1q_s16(iscan), one));
const int16x8_t coeff = load_tran_low_to_s16q(coeff_ptr);
const int16x8_t coeff_sign = vshrq_n_s16(coeff, 15);
const int16x8_t coeff_abs = vabsq_s16(coeff);
const int16x8_t zbin_mask =
vreinterpretq_s16_u16(vcgeq_s16(coeff_abs, zbin));
const int16x8_t rounded = vqaddq_s16(coeff_abs, round);
// (round * quant * 2) >> 16 >> 1 == (round * quant) >> 16
int16x8_t qcoeff = vshrq_n_s16(vqdmulhq_s16(rounded, quant), 1);
qcoeff = vaddq_s16(qcoeff, rounded);
// (qcoeff * quant_shift * 2) >> 16 == (qcoeff * quant_shift) >> 15
qcoeff = vqdmulhq_s16(qcoeff, quant_shift);
// Restore the sign bit.
qcoeff = veorq_s16(qcoeff, coeff_sign);
qcoeff = vsubq_s16(qcoeff, coeff_sign);
qcoeff = vandq_s16(qcoeff, zbin_mask);
// Set non-zero elements to -1 and use that to extract values for eob.
eob_max =
vmaxq_u16(eob_max, vandq_u16(vtstq_s16(qcoeff, neg_one), v_iscan));
coeff_ptr += 8;
iscan += 8;
store_s16q_to_tran_low(qcoeff_ptr, qcoeff);
qcoeff_ptr += 8;
calculate_dqcoeff_and_store_32x32(qcoeff, dequant, dqcoeff_ptr);
dqcoeff_ptr += 8;
}
}
#ifdef __aarch64__
*eob_ptr = vmaxvq_u16(eob_max);
#else
{
const uint16x4_t eob_max_0 =
vmax_u16(vget_low_u16(eob_max), vget_high_u16(eob_max));
const uint16x4_t eob_max_1 = vpmax_u16(eob_max_0, eob_max_0);
const uint16x4_t eob_max_2 = vpmax_u16(eob_max_1, eob_max_1);
vst1_lane_u16(eob_ptr, eob_max_2, 0);
}
#endif // __aarch64__
}
@@ -0,0 +1,380 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/sum_neon.h"
static INLINE uint8x8_t load_unaligned_2_buffers(const void *const buf0,
const void *const buf1) {
uint32_t a;
uint32x2_t aa = vdup_n_u32(0);
memcpy(&a, buf0, 4);
aa = vset_lane_u32(a, aa, 0);
memcpy(&a, buf1, 4);
aa = vset_lane_u32(a, aa, 1);
return vreinterpret_u8_u32(aa);
}
static INLINE void sad4x_4d(const uint8_t *const src_ptr, const int src_stride,
const uint8_t *const ref_array[4],
const int ref_stride, const int height,
uint32_t *const res) {
int i;
uint16x8_t abs[2] = { vdupq_n_u16(0), vdupq_n_u16(0) };
uint16x4_t a[2];
uint32x4_t r;
assert(!((intptr_t)src_ptr % sizeof(uint32_t)));
assert(!(src_stride % sizeof(uint32_t)));
for (i = 0; i < height; ++i) {
const uint8x8_t s = vreinterpret_u8_u32(
vld1_dup_u32((const uint32_t *)(src_ptr + i * src_stride)));
const uint8x8_t ref01 = load_unaligned_2_buffers(
ref_array[0] + i * ref_stride, ref_array[1] + i * ref_stride);
const uint8x8_t ref23 = load_unaligned_2_buffers(
ref_array[2] + i * ref_stride, ref_array[3] + i * ref_stride);
abs[0] = vabal_u8(abs[0], s, ref01);
abs[1] = vabal_u8(abs[1], s, ref23);
}
a[0] = vpadd_u16(vget_low_u16(abs[0]), vget_high_u16(abs[0]));
a[1] = vpadd_u16(vget_low_u16(abs[1]), vget_high_u16(abs[1]));
r = vpaddlq_u16(vcombine_u16(a[0], a[1]));
vst1q_u32(res, r);
}
void vpx_sad4x4x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
sad4x_4d(src_ptr, src_stride, ref_array, ref_stride, 4, res);
}
void vpx_sad4x8x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
sad4x_4d(src_ptr, src_stride, ref_array, ref_stride, 8, res);
}
////////////////////////////////////////////////////////////////////////////////
// Can handle 512 pixels' sad sum (such as 16x32 or 32x16)
static INLINE void sad_512_pel_final_neon(const uint16x8_t *sum /*[4]*/,
uint32_t *const res) {
const uint16x4_t a0 = vadd_u16(vget_low_u16(sum[0]), vget_high_u16(sum[0]));
const uint16x4_t a1 = vadd_u16(vget_low_u16(sum[1]), vget_high_u16(sum[1]));
const uint16x4_t a2 = vadd_u16(vget_low_u16(sum[2]), vget_high_u16(sum[2]));
const uint16x4_t a3 = vadd_u16(vget_low_u16(sum[3]), vget_high_u16(sum[3]));
const uint16x4_t b0 = vpadd_u16(a0, a1);
const uint16x4_t b1 = vpadd_u16(a2, a3);
const uint32x4_t r = vpaddlq_u16(vcombine_u16(b0, b1));
vst1q_u32(res, r);
}
// Can handle 1024 pixels' sad sum (such as 32x32)
static INLINE void sad_1024_pel_final_neon(const uint16x8_t *sum /*[4]*/,
uint32_t *const res) {
const uint16x4_t a0 = vpadd_u16(vget_low_u16(sum[0]), vget_high_u16(sum[0]));
const uint16x4_t a1 = vpadd_u16(vget_low_u16(sum[1]), vget_high_u16(sum[1]));
const uint16x4_t a2 = vpadd_u16(vget_low_u16(sum[2]), vget_high_u16(sum[2]));
const uint16x4_t a3 = vpadd_u16(vget_low_u16(sum[3]), vget_high_u16(sum[3]));
const uint32x4_t b0 = vpaddlq_u16(vcombine_u16(a0, a1));
const uint32x4_t b1 = vpaddlq_u16(vcombine_u16(a2, a3));
const uint32x2_t c0 = vpadd_u32(vget_low_u32(b0), vget_high_u32(b0));
const uint32x2_t c1 = vpadd_u32(vget_low_u32(b1), vget_high_u32(b1));
vst1q_u32(res, vcombine_u32(c0, c1));
}
// Can handle 2048 pixels' sad sum (such as 32x64 or 64x32)
static INLINE void sad_2048_pel_final_neon(const uint16x8_t *sum /*[4]*/,
uint32_t *const res) {
const uint32x4_t a0 = vpaddlq_u16(sum[0]);
const uint32x4_t a1 = vpaddlq_u16(sum[1]);
const uint32x4_t a2 = vpaddlq_u16(sum[2]);
const uint32x4_t a3 = vpaddlq_u16(sum[3]);
const uint32x2_t b0 = vadd_u32(vget_low_u32(a0), vget_high_u32(a0));
const uint32x2_t b1 = vadd_u32(vget_low_u32(a1), vget_high_u32(a1));
const uint32x2_t b2 = vadd_u32(vget_low_u32(a2), vget_high_u32(a2));
const uint32x2_t b3 = vadd_u32(vget_low_u32(a3), vget_high_u32(a3));
const uint32x2_t c0 = vpadd_u32(b0, b1);
const uint32x2_t c1 = vpadd_u32(b2, b3);
vst1q_u32(res, vcombine_u32(c0, c1));
}
// Can handle 4096 pixels' sad sum (such as 64x64)
static INLINE void sad_4096_pel_final_neon(const uint16x8_t *sum /*[8]*/,
uint32_t *const res) {
const uint32x4_t a0 = vpaddlq_u16(sum[0]);
const uint32x4_t a1 = vpaddlq_u16(sum[1]);
const uint32x4_t a2 = vpaddlq_u16(sum[2]);
const uint32x4_t a3 = vpaddlq_u16(sum[3]);
const uint32x4_t a4 = vpaddlq_u16(sum[4]);
const uint32x4_t a5 = vpaddlq_u16(sum[5]);
const uint32x4_t a6 = vpaddlq_u16(sum[6]);
const uint32x4_t a7 = vpaddlq_u16(sum[7]);
const uint32x4_t b0 = vaddq_u32(a0, a1);
const uint32x4_t b1 = vaddq_u32(a2, a3);
const uint32x4_t b2 = vaddq_u32(a4, a5);
const uint32x4_t b3 = vaddq_u32(a6, a7);
const uint32x2_t c0 = vadd_u32(vget_low_u32(b0), vget_high_u32(b0));
const uint32x2_t c1 = vadd_u32(vget_low_u32(b1), vget_high_u32(b1));
const uint32x2_t c2 = vadd_u32(vget_low_u32(b2), vget_high_u32(b2));
const uint32x2_t c3 = vadd_u32(vget_low_u32(b3), vget_high_u32(b3));
const uint32x2_t d0 = vpadd_u32(c0, c1);
const uint32x2_t d1 = vpadd_u32(c2, c3);
vst1q_u32(res, vcombine_u32(d0, d1));
}
static INLINE void sad8x_4d(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res, const int height) {
int i, j;
const uint8_t *ref_loop[4] = { ref_array[0], ref_array[1], ref_array[2],
ref_array[3] };
uint16x8_t sum[4] = { vdupq_n_u16(0), vdupq_n_u16(0), vdupq_n_u16(0),
vdupq_n_u16(0) };
for (i = 0; i < height; ++i) {
const uint8x8_t s = vld1_u8(src_ptr);
src_ptr += src_stride;
for (j = 0; j < 4; ++j) {
const uint8x8_t b_u8 = vld1_u8(ref_loop[j]);
ref_loop[j] += ref_stride;
sum[j] = vabal_u8(sum[j], s, b_u8);
}
}
sad_512_pel_final_neon(sum, res);
}
void vpx_sad8x4x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
sad8x_4d(src_ptr, src_stride, ref_array, ref_stride, res, 4);
}
void vpx_sad8x8x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
sad8x_4d(src_ptr, src_stride, ref_array, ref_stride, res, 8);
}
void vpx_sad8x16x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
sad8x_4d(src_ptr, src_stride, ref_array, ref_stride, res, 16);
}
////////////////////////////////////////////////////////////////////////////////
static INLINE void sad16_neon(const uint8_t *ref_ptr, const uint8x16_t src_ptr,
uint16x8_t *const sum) {
const uint8x16_t r = vld1q_u8(ref_ptr);
*sum = vabal_u8(*sum, vget_low_u8(src_ptr), vget_low_u8(r));
*sum = vabal_u8(*sum, vget_high_u8(src_ptr), vget_high_u8(r));
}
static INLINE void sad16x_4d(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res, const int height) {
int i, j;
const uint8_t *ref_loop[4] = { ref_array[0], ref_array[1], ref_array[2],
ref_array[3] };
uint16x8_t sum[4] = { vdupq_n_u16(0), vdupq_n_u16(0), vdupq_n_u16(0),
vdupq_n_u16(0) };
for (i = 0; i < height; ++i) {
const uint8x16_t s = vld1q_u8(src_ptr);
src_ptr += src_stride;
for (j = 0; j < 4; ++j) {
sad16_neon(ref_loop[j], s, &sum[j]);
ref_loop[j] += ref_stride;
}
}
sad_512_pel_final_neon(sum, res);
}
void vpx_sad16x8x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
sad16x_4d(src_ptr, src_stride, ref_array, ref_stride, res, 8);
}
void vpx_sad16x16x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
sad16x_4d(src_ptr, src_stride, ref_array, ref_stride, res, 16);
}
void vpx_sad16x32x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
sad16x_4d(src_ptr, src_stride, ref_array, ref_stride, res, 32);
}
////////////////////////////////////////////////////////////////////////////////
static INLINE void sad32x_4d(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
const int height, uint16x8_t *const sum) {
int i;
const uint8_t *ref_loop[4] = { ref_array[0], ref_array[1], ref_array[2],
ref_array[3] };
sum[0] = sum[1] = sum[2] = sum[3] = vdupq_n_u16(0);
for (i = 0; i < height; ++i) {
uint8x16_t s;
s = vld1q_u8(src_ptr + 0 * 16);
sad16_neon(ref_loop[0] + 0 * 16, s, &sum[0]);
sad16_neon(ref_loop[1] + 0 * 16, s, &sum[1]);
sad16_neon(ref_loop[2] + 0 * 16, s, &sum[2]);
sad16_neon(ref_loop[3] + 0 * 16, s, &sum[3]);
s = vld1q_u8(src_ptr + 1 * 16);
sad16_neon(ref_loop[0] + 1 * 16, s, &sum[0]);
sad16_neon(ref_loop[1] + 1 * 16, s, &sum[1]);
sad16_neon(ref_loop[2] + 1 * 16, s, &sum[2]);
sad16_neon(ref_loop[3] + 1 * 16, s, &sum[3]);
src_ptr += src_stride;
ref_loop[0] += ref_stride;
ref_loop[1] += ref_stride;
ref_loop[2] += ref_stride;
ref_loop[3] += ref_stride;
}
}
void vpx_sad32x16x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
uint16x8_t sum[4];
sad32x_4d(src_ptr, src_stride, ref_array, ref_stride, 16, sum);
sad_512_pel_final_neon(sum, res);
}
void vpx_sad32x32x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
uint16x8_t sum[4];
sad32x_4d(src_ptr, src_stride, ref_array, ref_stride, 32, sum);
sad_1024_pel_final_neon(sum, res);
}
void vpx_sad32x64x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
uint16x8_t sum[4];
sad32x_4d(src_ptr, src_stride, ref_array, ref_stride, 64, sum);
sad_2048_pel_final_neon(sum, res);
}
////////////////////////////////////////////////////////////////////////////////
void vpx_sad64x32x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
int i;
const uint8_t *ref_loop[4] = { ref_array[0], ref_array[1], ref_array[2],
ref_array[3] };
uint16x8_t sum[4] = { vdupq_n_u16(0), vdupq_n_u16(0), vdupq_n_u16(0),
vdupq_n_u16(0) };
for (i = 0; i < 32; ++i) {
uint8x16_t s;
s = vld1q_u8(src_ptr + 0 * 16);
sad16_neon(ref_loop[0] + 0 * 16, s, &sum[0]);
sad16_neon(ref_loop[1] + 0 * 16, s, &sum[1]);
sad16_neon(ref_loop[2] + 0 * 16, s, &sum[2]);
sad16_neon(ref_loop[3] + 0 * 16, s, &sum[3]);
s = vld1q_u8(src_ptr + 1 * 16);
sad16_neon(ref_loop[0] + 1 * 16, s, &sum[0]);
sad16_neon(ref_loop[1] + 1 * 16, s, &sum[1]);
sad16_neon(ref_loop[2] + 1 * 16, s, &sum[2]);
sad16_neon(ref_loop[3] + 1 * 16, s, &sum[3]);
s = vld1q_u8(src_ptr + 2 * 16);
sad16_neon(ref_loop[0] + 2 * 16, s, &sum[0]);
sad16_neon(ref_loop[1] + 2 * 16, s, &sum[1]);
sad16_neon(ref_loop[2] + 2 * 16, s, &sum[2]);
sad16_neon(ref_loop[3] + 2 * 16, s, &sum[3]);
s = vld1q_u8(src_ptr + 3 * 16);
sad16_neon(ref_loop[0] + 3 * 16, s, &sum[0]);
sad16_neon(ref_loop[1] + 3 * 16, s, &sum[1]);
sad16_neon(ref_loop[2] + 3 * 16, s, &sum[2]);
sad16_neon(ref_loop[3] + 3 * 16, s, &sum[3]);
src_ptr += src_stride;
ref_loop[0] += ref_stride;
ref_loop[1] += ref_stride;
ref_loop[2] += ref_stride;
ref_loop[3] += ref_stride;
}
sad_2048_pel_final_neon(sum, res);
}
void vpx_sad64x64x4d_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *const ref_array[4], int ref_stride,
uint32_t *res) {
int i;
const uint8_t *ref_loop[4] = { ref_array[0], ref_array[1], ref_array[2],
ref_array[3] };
uint16x8_t sum[8] = { vdupq_n_u16(0), vdupq_n_u16(0), vdupq_n_u16(0),
vdupq_n_u16(0), vdupq_n_u16(0), vdupq_n_u16(0),
vdupq_n_u16(0), vdupq_n_u16(0) };
for (i = 0; i < 64; ++i) {
uint8x16_t s;
s = vld1q_u8(src_ptr + 0 * 16);
sad16_neon(ref_loop[0] + 0 * 16, s, &sum[0]);
sad16_neon(ref_loop[1] + 0 * 16, s, &sum[2]);
sad16_neon(ref_loop[2] + 0 * 16, s, &sum[4]);
sad16_neon(ref_loop[3] + 0 * 16, s, &sum[6]);
s = vld1q_u8(src_ptr + 1 * 16);
sad16_neon(ref_loop[0] + 1 * 16, s, &sum[0]);
sad16_neon(ref_loop[1] + 1 * 16, s, &sum[2]);
sad16_neon(ref_loop[2] + 1 * 16, s, &sum[4]);
sad16_neon(ref_loop[3] + 1 * 16, s, &sum[6]);
s = vld1q_u8(src_ptr + 2 * 16);
sad16_neon(ref_loop[0] + 2 * 16, s, &sum[1]);
sad16_neon(ref_loop[1] + 2 * 16, s, &sum[3]);
sad16_neon(ref_loop[2] + 2 * 16, s, &sum[5]);
sad16_neon(ref_loop[3] + 2 * 16, s, &sum[7]);
s = vld1q_u8(src_ptr + 3 * 16);
sad16_neon(ref_loop[0] + 3 * 16, s, &sum[1]);
sad16_neon(ref_loop[1] + 3 * 16, s, &sum[3]);
sad16_neon(ref_loop[2] + 3 * 16, s, &sum[5]);
sad16_neon(ref_loop[3] + 3 * 16, s, &sum[7]);
src_ptr += src_stride;
ref_loop[0] += ref_stride;
ref_loop[1] += ref_stride;
ref_loop[2] += ref_stride;
ref_loop[3] += ref_stride;
}
sad_4096_pel_final_neon(sum, res);
}
@@ -0,0 +1,353 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/sum_neon.h"
uint32_t vpx_sad4x4_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride) {
const uint8x16_t src_u8 = load_unaligned_u8q(src_ptr, src_stride);
const uint8x16_t ref_u8 = load_unaligned_u8q(ref_ptr, ref_stride);
uint16x8_t abs = vabdl_u8(vget_low_u8(src_u8), vget_low_u8(ref_u8));
abs = vabal_u8(abs, vget_high_u8(src_u8), vget_high_u8(ref_u8));
return vget_lane_u32(horizontal_add_uint16x8(abs), 0);
}
uint32_t vpx_sad4x4_avg_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
const uint8_t *second_pred) {
const uint8x16_t src_u8 = load_unaligned_u8q(src_ptr, src_stride);
const uint8x16_t ref_u8 = load_unaligned_u8q(ref_ptr, ref_stride);
const uint8x16_t second_pred_u8 = vld1q_u8(second_pred);
const uint8x16_t avg = vrhaddq_u8(ref_u8, second_pred_u8);
uint16x8_t abs = vabdl_u8(vget_low_u8(src_u8), vget_low_u8(avg));
abs = vabal_u8(abs, vget_high_u8(src_u8), vget_high_u8(avg));
return vget_lane_u32(horizontal_add_uint16x8(abs), 0);
}
uint32_t vpx_sad4x8_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride) {
int i;
uint16x8_t abs = vdupq_n_u16(0);
for (i = 0; i < 8; i += 4) {
const uint8x16_t src_u8 = load_unaligned_u8q(src_ptr, src_stride);
const uint8x16_t ref_u8 = load_unaligned_u8q(ref_ptr, ref_stride);
src_ptr += 4 * src_stride;
ref_ptr += 4 * ref_stride;
abs = vabal_u8(abs, vget_low_u8(src_u8), vget_low_u8(ref_u8));
abs = vabal_u8(abs, vget_high_u8(src_u8), vget_high_u8(ref_u8));
}
return vget_lane_u32(horizontal_add_uint16x8(abs), 0);
}
uint32_t vpx_sad4x8_avg_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
const uint8_t *second_pred) {
int i;
uint16x8_t abs = vdupq_n_u16(0);
for (i = 0; i < 8; i += 4) {
const uint8x16_t src_u8 = load_unaligned_u8q(src_ptr, src_stride);
const uint8x16_t ref_u8 = load_unaligned_u8q(ref_ptr, ref_stride);
const uint8x16_t second_pred_u8 = vld1q_u8(second_pred);
const uint8x16_t avg = vrhaddq_u8(ref_u8, second_pred_u8);
src_ptr += 4 * src_stride;
ref_ptr += 4 * ref_stride;
second_pred += 16;
abs = vabal_u8(abs, vget_low_u8(src_u8), vget_low_u8(avg));
abs = vabal_u8(abs, vget_high_u8(src_u8), vget_high_u8(avg));
}
return vget_lane_u32(horizontal_add_uint16x8(abs), 0);
}
static INLINE uint16x8_t sad8x(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
const int height) {
int i;
uint16x8_t abs = vdupq_n_u16(0);
for (i = 0; i < height; ++i) {
const uint8x8_t a_u8 = vld1_u8(src_ptr);
const uint8x8_t b_u8 = vld1_u8(ref_ptr);
src_ptr += src_stride;
ref_ptr += ref_stride;
abs = vabal_u8(abs, a_u8, b_u8);
}
return abs;
}
static INLINE uint16x8_t sad8x_avg(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
const uint8_t *second_pred,
const int height) {
int i;
uint16x8_t abs = vdupq_n_u16(0);
for (i = 0; i < height; ++i) {
const uint8x8_t a_u8 = vld1_u8(src_ptr);
const uint8x8_t b_u8 = vld1_u8(ref_ptr);
const uint8x8_t c_u8 = vld1_u8(second_pred);
const uint8x8_t avg = vrhadd_u8(b_u8, c_u8);
src_ptr += src_stride;
ref_ptr += ref_stride;
second_pred += 8;
abs = vabal_u8(abs, a_u8, avg);
}
return abs;
}
#define sad8xN(n) \
uint32_t vpx_sad8x##n##_neon(const uint8_t *src_ptr, int src_stride, \
const uint8_t *ref_ptr, int ref_stride) { \
const uint16x8_t abs = sad8x(src_ptr, src_stride, ref_ptr, ref_stride, n); \
return vget_lane_u32(horizontal_add_uint16x8(abs), 0); \
} \
\
uint32_t vpx_sad8x##n##_avg_neon(const uint8_t *src_ptr, int src_stride, \
const uint8_t *ref_ptr, int ref_stride, \
const uint8_t *second_pred) { \
const uint16x8_t abs = \
sad8x_avg(src_ptr, src_stride, ref_ptr, ref_stride, second_pred, n); \
return vget_lane_u32(horizontal_add_uint16x8(abs), 0); \
}
sad8xN(4);
sad8xN(8);
sad8xN(16);
static INLINE uint16x8_t sad16x(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
const int height) {
int i;
uint16x8_t abs = vdupq_n_u16(0);
for (i = 0; i < height; ++i) {
const uint8x16_t a_u8 = vld1q_u8(src_ptr);
const uint8x16_t b_u8 = vld1q_u8(ref_ptr);
src_ptr += src_stride;
ref_ptr += ref_stride;
abs = vabal_u8(abs, vget_low_u8(a_u8), vget_low_u8(b_u8));
abs = vabal_u8(abs, vget_high_u8(a_u8), vget_high_u8(b_u8));
}
return abs;
}
static INLINE uint16x8_t sad16x_avg(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
const uint8_t *second_pred,
const int height) {
int i;
uint16x8_t abs = vdupq_n_u16(0);
for (i = 0; i < height; ++i) {
const uint8x16_t a_u8 = vld1q_u8(src_ptr);
const uint8x16_t b_u8 = vld1q_u8(ref_ptr);
const uint8x16_t c_u8 = vld1q_u8(second_pred);
const uint8x16_t avg = vrhaddq_u8(b_u8, c_u8);
src_ptr += src_stride;
ref_ptr += ref_stride;
second_pred += 16;
abs = vabal_u8(abs, vget_low_u8(a_u8), vget_low_u8(avg));
abs = vabal_u8(abs, vget_high_u8(a_u8), vget_high_u8(avg));
}
return abs;
}
#define sad16xN(n) \
uint32_t vpx_sad16x##n##_neon(const uint8_t *src_ptr, int src_stride, \
const uint8_t *ref_ptr, int ref_stride) { \
const uint16x8_t abs = \
sad16x(src_ptr, src_stride, ref_ptr, ref_stride, n); \
return vget_lane_u32(horizontal_add_uint16x8(abs), 0); \
} \
\
uint32_t vpx_sad16x##n##_avg_neon(const uint8_t *src_ptr, int src_stride, \
const uint8_t *ref_ptr, int ref_stride, \
const uint8_t *second_pred) { \
const uint16x8_t abs = \
sad16x_avg(src_ptr, src_stride, ref_ptr, ref_stride, second_pred, n); \
return vget_lane_u32(horizontal_add_uint16x8(abs), 0); \
}
sad16xN(8);
sad16xN(16);
sad16xN(32);
static INLINE uint16x8_t sad32x(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
const int height) {
int i;
uint16x8_t abs = vdupq_n_u16(0);
for (i = 0; i < height; ++i) {
const uint8x16_t a_lo = vld1q_u8(src_ptr);
const uint8x16_t a_hi = vld1q_u8(src_ptr + 16);
const uint8x16_t b_lo = vld1q_u8(ref_ptr);
const uint8x16_t b_hi = vld1q_u8(ref_ptr + 16);
src_ptr += src_stride;
ref_ptr += ref_stride;
abs = vabal_u8(abs, vget_low_u8(a_lo), vget_low_u8(b_lo));
abs = vabal_u8(abs, vget_high_u8(a_lo), vget_high_u8(b_lo));
abs = vabal_u8(abs, vget_low_u8(a_hi), vget_low_u8(b_hi));
abs = vabal_u8(abs, vget_high_u8(a_hi), vget_high_u8(b_hi));
}
return abs;
}
static INLINE uint16x8_t sad32x_avg(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
const uint8_t *second_pred,
const int height) {
int i;
uint16x8_t abs = vdupq_n_u16(0);
for (i = 0; i < height; ++i) {
const uint8x16_t a_lo = vld1q_u8(src_ptr);
const uint8x16_t a_hi = vld1q_u8(src_ptr + 16);
const uint8x16_t b_lo = vld1q_u8(ref_ptr);
const uint8x16_t b_hi = vld1q_u8(ref_ptr + 16);
const uint8x16_t c_lo = vld1q_u8(second_pred);
const uint8x16_t c_hi = vld1q_u8(second_pred + 16);
const uint8x16_t avg_lo = vrhaddq_u8(b_lo, c_lo);
const uint8x16_t avg_hi = vrhaddq_u8(b_hi, c_hi);
src_ptr += src_stride;
ref_ptr += ref_stride;
second_pred += 32;
abs = vabal_u8(abs, vget_low_u8(a_lo), vget_low_u8(avg_lo));
abs = vabal_u8(abs, vget_high_u8(a_lo), vget_high_u8(avg_lo));
abs = vabal_u8(abs, vget_low_u8(a_hi), vget_low_u8(avg_hi));
abs = vabal_u8(abs, vget_high_u8(a_hi), vget_high_u8(avg_hi));
}
return abs;
}
#define sad32xN(n) \
uint32_t vpx_sad32x##n##_neon(const uint8_t *src_ptr, int src_stride, \
const uint8_t *ref_ptr, int ref_stride) { \
const uint16x8_t abs = \
sad32x(src_ptr, src_stride, ref_ptr, ref_stride, n); \
return vget_lane_u32(horizontal_add_uint16x8(abs), 0); \
} \
\
uint32_t vpx_sad32x##n##_avg_neon(const uint8_t *src_ptr, int src_stride, \
const uint8_t *ref_ptr, int ref_stride, \
const uint8_t *second_pred) { \
const uint16x8_t abs = \
sad32x_avg(src_ptr, src_stride, ref_ptr, ref_stride, second_pred, n); \
return vget_lane_u32(horizontal_add_uint16x8(abs), 0); \
}
sad32xN(16);
sad32xN(32);
sad32xN(64);
static INLINE uint32x4_t sad64x(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
const int height) {
int i;
uint16x8_t abs_0 = vdupq_n_u16(0);
uint16x8_t abs_1 = vdupq_n_u16(0);
for (i = 0; i < height; ++i) {
const uint8x16_t a_0 = vld1q_u8(src_ptr);
const uint8x16_t a_1 = vld1q_u8(src_ptr + 16);
const uint8x16_t a_2 = vld1q_u8(src_ptr + 32);
const uint8x16_t a_3 = vld1q_u8(src_ptr + 48);
const uint8x16_t b_0 = vld1q_u8(ref_ptr);
const uint8x16_t b_1 = vld1q_u8(ref_ptr + 16);
const uint8x16_t b_2 = vld1q_u8(ref_ptr + 32);
const uint8x16_t b_3 = vld1q_u8(ref_ptr + 48);
src_ptr += src_stride;
ref_ptr += ref_stride;
abs_0 = vabal_u8(abs_0, vget_low_u8(a_0), vget_low_u8(b_0));
abs_0 = vabal_u8(abs_0, vget_high_u8(a_0), vget_high_u8(b_0));
abs_0 = vabal_u8(abs_0, vget_low_u8(a_1), vget_low_u8(b_1));
abs_0 = vabal_u8(abs_0, vget_high_u8(a_1), vget_high_u8(b_1));
abs_1 = vabal_u8(abs_1, vget_low_u8(a_2), vget_low_u8(b_2));
abs_1 = vabal_u8(abs_1, vget_high_u8(a_2), vget_high_u8(b_2));
abs_1 = vabal_u8(abs_1, vget_low_u8(a_3), vget_low_u8(b_3));
abs_1 = vabal_u8(abs_1, vget_high_u8(a_3), vget_high_u8(b_3));
}
{
const uint32x4_t sum = vpaddlq_u16(abs_0);
return vpadalq_u16(sum, abs_1);
}
}
static INLINE uint32x4_t sad64x_avg(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
const uint8_t *second_pred,
const int height) {
int i;
uint16x8_t abs_0 = vdupq_n_u16(0);
uint16x8_t abs_1 = vdupq_n_u16(0);
for (i = 0; i < height; ++i) {
const uint8x16_t a_0 = vld1q_u8(src_ptr);
const uint8x16_t a_1 = vld1q_u8(src_ptr + 16);
const uint8x16_t a_2 = vld1q_u8(src_ptr + 32);
const uint8x16_t a_3 = vld1q_u8(src_ptr + 48);
const uint8x16_t b_0 = vld1q_u8(ref_ptr);
const uint8x16_t b_1 = vld1q_u8(ref_ptr + 16);
const uint8x16_t b_2 = vld1q_u8(ref_ptr + 32);
const uint8x16_t b_3 = vld1q_u8(ref_ptr + 48);
const uint8x16_t c_0 = vld1q_u8(second_pred);
const uint8x16_t c_1 = vld1q_u8(second_pred + 16);
const uint8x16_t c_2 = vld1q_u8(second_pred + 32);
const uint8x16_t c_3 = vld1q_u8(second_pred + 48);
const uint8x16_t avg_0 = vrhaddq_u8(b_0, c_0);
const uint8x16_t avg_1 = vrhaddq_u8(b_1, c_1);
const uint8x16_t avg_2 = vrhaddq_u8(b_2, c_2);
const uint8x16_t avg_3 = vrhaddq_u8(b_3, c_3);
src_ptr += src_stride;
ref_ptr += ref_stride;
second_pred += 64;
abs_0 = vabal_u8(abs_0, vget_low_u8(a_0), vget_low_u8(avg_0));
abs_0 = vabal_u8(abs_0, vget_high_u8(a_0), vget_high_u8(avg_0));
abs_0 = vabal_u8(abs_0, vget_low_u8(a_1), vget_low_u8(avg_1));
abs_0 = vabal_u8(abs_0, vget_high_u8(a_1), vget_high_u8(avg_1));
abs_1 = vabal_u8(abs_1, vget_low_u8(a_2), vget_low_u8(avg_2));
abs_1 = vabal_u8(abs_1, vget_high_u8(a_2), vget_high_u8(avg_2));
abs_1 = vabal_u8(abs_1, vget_low_u8(a_3), vget_low_u8(avg_3));
abs_1 = vabal_u8(abs_1, vget_high_u8(a_3), vget_high_u8(avg_3));
}
{
const uint32x4_t sum = vpaddlq_u16(abs_0);
return vpadalq_u16(sum, abs_1);
}
}
#define sad64xN(n) \
uint32_t vpx_sad64x##n##_neon(const uint8_t *src_ptr, int src_stride, \
const uint8_t *ref_ptr, int ref_stride) { \
const uint32x4_t abs = \
sad64x(src_ptr, src_stride, ref_ptr, ref_stride, n); \
return vget_lane_u32(horizontal_add_uint32x4(abs), 0); \
} \
\
uint32_t vpx_sad64x##n##_avg_neon(const uint8_t *src_ptr, int src_stride, \
const uint8_t *ref_ptr, int ref_stride, \
const uint8_t *second_pred) { \
const uint32x4_t abs = \
sad64x_avg(src_ptr, src_stride, ref_ptr, ref_stride, second_pred, n); \
return vget_lane_u32(horizontal_add_uint32x4(abs), 0); \
}
sad64xN(32);
sad64xN(64);
@@ -0,0 +1,34 @@
;
; Copyright (c) 2010 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
EXPORT |vpx_push_neon|
EXPORT |vpx_pop_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
|vpx_push_neon| PROC
vstm r0!, {d8-d15}
bx lr
ENDP
|vpx_pop_neon| PROC
vldm r0!, {d8-d15}
bx lr
ENDP
END
@@ -0,0 +1,184 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "./vpx_config.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/variance.h"
#include "vpx_dsp/arm/mem_neon.h"
static const uint8_t bilinear_filters[8][2] = {
{ 128, 0 }, { 112, 16 }, { 96, 32 }, { 80, 48 },
{ 64, 64 }, { 48, 80 }, { 32, 96 }, { 16, 112 },
};
// Process a block exactly 4 wide and a multiple of 2 high.
static void var_filter_block2d_bil_w4(const uint8_t *src_ptr,
uint8_t *output_ptr,
unsigned int src_pixels_per_line,
int pixel_step,
unsigned int output_height,
const uint8_t *filter) {
const uint8x8_t f0 = vdup_n_u8(filter[0]);
const uint8x8_t f1 = vdup_n_u8(filter[1]);
unsigned int i;
for (i = 0; i < output_height; i += 2) {
const uint8x8_t src_0 = load_unaligned_u8(src_ptr, src_pixels_per_line);
const uint8x8_t src_1 =
load_unaligned_u8(src_ptr + pixel_step, src_pixels_per_line);
const uint16x8_t a = vmull_u8(src_0, f0);
const uint16x8_t b = vmlal_u8(a, src_1, f1);
const uint8x8_t out = vrshrn_n_u16(b, FILTER_BITS);
vst1_u8(output_ptr, out);
src_ptr += 2 * src_pixels_per_line;
output_ptr += 8;
}
}
// Process a block exactly 8 wide and any height.
static void var_filter_block2d_bil_w8(const uint8_t *src_ptr,
uint8_t *output_ptr,
unsigned int src_pixels_per_line,
int pixel_step,
unsigned int output_height,
const uint8_t *filter) {
const uint8x8_t f0 = vdup_n_u8(filter[0]);
const uint8x8_t f1 = vdup_n_u8(filter[1]);
unsigned int i;
for (i = 0; i < output_height; ++i) {
const uint8x8_t src_0 = vld1_u8(&src_ptr[0]);
const uint8x8_t src_1 = vld1_u8(&src_ptr[pixel_step]);
const uint16x8_t a = vmull_u8(src_0, f0);
const uint16x8_t b = vmlal_u8(a, src_1, f1);
const uint8x8_t out = vrshrn_n_u16(b, FILTER_BITS);
vst1_u8(output_ptr, out);
src_ptr += src_pixels_per_line;
output_ptr += 8;
}
}
// Process a block which is a mutiple of 16 wide and any height.
static void var_filter_block2d_bil_w16(const uint8_t *src_ptr,
uint8_t *output_ptr,
unsigned int src_pixels_per_line,
int pixel_step,
unsigned int output_height,
unsigned int output_width,
const uint8_t *filter) {
const uint8x8_t f0 = vdup_n_u8(filter[0]);
const uint8x8_t f1 = vdup_n_u8(filter[1]);
unsigned int i, j;
for (i = 0; i < output_height; ++i) {
for (j = 0; j < output_width; j += 16) {
const uint8x16_t src_0 = vld1q_u8(&src_ptr[j]);
const uint8x16_t src_1 = vld1q_u8(&src_ptr[j + pixel_step]);
const uint16x8_t a = vmull_u8(vget_low_u8(src_0), f0);
const uint16x8_t b = vmlal_u8(a, vget_low_u8(src_1), f1);
const uint8x8_t out_lo = vrshrn_n_u16(b, FILTER_BITS);
const uint16x8_t c = vmull_u8(vget_high_u8(src_0), f0);
const uint16x8_t d = vmlal_u8(c, vget_high_u8(src_1), f1);
const uint8x8_t out_hi = vrshrn_n_u16(d, FILTER_BITS);
vst1q_u8(output_ptr + j, vcombine_u8(out_lo, out_hi));
}
src_ptr += src_pixels_per_line;
output_ptr += output_width;
}
}
// 4xM filter writes an extra row to fdata because it processes two rows at a
// time.
#define sub_pixel_varianceNxM(n, m) \
uint32_t vpx_sub_pixel_variance##n##x##m##_neon( \
const uint8_t *src_ptr, int src_stride, int x_offset, int y_offset, \
const uint8_t *ref_ptr, int ref_stride, uint32_t *sse) { \
uint8_t temp0[n * (m + (n == 4 ? 2 : 1))]; \
uint8_t temp1[n * m]; \
\
if (n == 4) { \
var_filter_block2d_bil_w4(src_ptr, temp0, src_stride, 1, (m + 2), \
bilinear_filters[x_offset]); \
var_filter_block2d_bil_w4(temp0, temp1, n, n, m, \
bilinear_filters[y_offset]); \
} else if (n == 8) { \
var_filter_block2d_bil_w8(src_ptr, temp0, src_stride, 1, (m + 1), \
bilinear_filters[x_offset]); \
var_filter_block2d_bil_w8(temp0, temp1, n, n, m, \
bilinear_filters[y_offset]); \
} else { \
var_filter_block2d_bil_w16(src_ptr, temp0, src_stride, 1, (m + 1), n, \
bilinear_filters[x_offset]); \
var_filter_block2d_bil_w16(temp0, temp1, n, n, m, n, \
bilinear_filters[y_offset]); \
} \
return vpx_variance##n##x##m(temp1, n, ref_ptr, ref_stride, sse); \
}
sub_pixel_varianceNxM(4, 4);
sub_pixel_varianceNxM(4, 8);
sub_pixel_varianceNxM(8, 4);
sub_pixel_varianceNxM(8, 8);
sub_pixel_varianceNxM(8, 16);
sub_pixel_varianceNxM(16, 8);
sub_pixel_varianceNxM(16, 16);
sub_pixel_varianceNxM(16, 32);
sub_pixel_varianceNxM(32, 16);
sub_pixel_varianceNxM(32, 32);
sub_pixel_varianceNxM(32, 64);
sub_pixel_varianceNxM(64, 32);
sub_pixel_varianceNxM(64, 64);
// 4xM filter writes an extra row to fdata because it processes two rows at a
// time.
#define sub_pixel_avg_varianceNxM(n, m) \
uint32_t vpx_sub_pixel_avg_variance##n##x##m##_neon( \
const uint8_t *src_ptr, int src_stride, int x_offset, int y_offset, \
const uint8_t *ref_ptr, int ref_stride, uint32_t *sse, \
const uint8_t *second_pred) { \
uint8_t temp0[n * (m + (n == 4 ? 2 : 1))]; \
uint8_t temp1[n * m]; \
\
if (n == 4) { \
var_filter_block2d_bil_w4(src_ptr, temp0, src_stride, 1, (m + 2), \
bilinear_filters[x_offset]); \
var_filter_block2d_bil_w4(temp0, temp1, n, n, m, \
bilinear_filters[y_offset]); \
} else if (n == 8) { \
var_filter_block2d_bil_w8(src_ptr, temp0, src_stride, 1, (m + 1), \
bilinear_filters[x_offset]); \
var_filter_block2d_bil_w8(temp0, temp1, n, n, m, \
bilinear_filters[y_offset]); \
} else { \
var_filter_block2d_bil_w16(src_ptr, temp0, src_stride, 1, (m + 1), n, \
bilinear_filters[x_offset]); \
var_filter_block2d_bil_w16(temp0, temp1, n, n, m, n, \
bilinear_filters[y_offset]); \
} \
\
vpx_comp_avg_pred(temp0, second_pred, n, m, temp1, n); \
\
return vpx_variance##n##x##m(temp0, n, ref_ptr, ref_stride, sse); \
}
sub_pixel_avg_varianceNxM(4, 4);
sub_pixel_avg_varianceNxM(4, 8);
sub_pixel_avg_varianceNxM(8, 4);
sub_pixel_avg_varianceNxM(8, 8);
sub_pixel_avg_varianceNxM(8, 16);
sub_pixel_avg_varianceNxM(16, 8);
sub_pixel_avg_varianceNxM(16, 16);
sub_pixel_avg_varianceNxM(16, 32);
sub_pixel_avg_varianceNxM(32, 16);
sub_pixel_avg_varianceNxM(32, 32);
sub_pixel_avg_varianceNxM(32, 64);
sub_pixel_avg_varianceNxM(64, 32);
sub_pixel_avg_varianceNxM(64, 64);
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/arm/mem_neon.h"
void vpx_subtract_block_neon(int rows, int cols, int16_t *diff,
ptrdiff_t diff_stride, const uint8_t *src,
ptrdiff_t src_stride, const uint8_t *pred,
ptrdiff_t pred_stride) {
int r = rows, c;
if (cols > 16) {
do {
for (c = 0; c < cols; c += 32) {
const uint8x16_t s0 = vld1q_u8(&src[c + 0]);
const uint8x16_t s1 = vld1q_u8(&src[c + 16]);
const uint8x16_t p0 = vld1q_u8(&pred[c + 0]);
const uint8x16_t p1 = vld1q_u8(&pred[c + 16]);
const uint16x8_t d0 = vsubl_u8(vget_low_u8(s0), vget_low_u8(p0));
const uint16x8_t d1 = vsubl_u8(vget_high_u8(s0), vget_high_u8(p0));
const uint16x8_t d2 = vsubl_u8(vget_low_u8(s1), vget_low_u8(p1));
const uint16x8_t d3 = vsubl_u8(vget_high_u8(s1), vget_high_u8(p1));
vst1q_s16(&diff[c + 0], vreinterpretq_s16_u16(d0));
vst1q_s16(&diff[c + 8], vreinterpretq_s16_u16(d1));
vst1q_s16(&diff[c + 16], vreinterpretq_s16_u16(d2));
vst1q_s16(&diff[c + 24], vreinterpretq_s16_u16(d3));
}
diff += diff_stride;
pred += pred_stride;
src += src_stride;
} while (--r);
} else if (cols > 8) {
do {
const uint8x16_t s = vld1q_u8(&src[0]);
const uint8x16_t p = vld1q_u8(&pred[0]);
const uint16x8_t d0 = vsubl_u8(vget_low_u8(s), vget_low_u8(p));
const uint16x8_t d1 = vsubl_u8(vget_high_u8(s), vget_high_u8(p));
vst1q_s16(&diff[0], vreinterpretq_s16_u16(d0));
vst1q_s16(&diff[8], vreinterpretq_s16_u16(d1));
diff += diff_stride;
pred += pred_stride;
src += src_stride;
} while (--r);
} else if (cols > 4) {
do {
const uint8x8_t s = vld1_u8(&src[0]);
const uint8x8_t p = vld1_u8(&pred[0]);
const uint16x8_t v_diff = vsubl_u8(s, p);
vst1q_s16(&diff[0], vreinterpretq_s16_u16(v_diff));
diff += diff_stride;
pred += pred_stride;
src += src_stride;
} while (--r);
} else {
assert(cols == 4);
do {
const uint8x8_t s = load_unaligned_u8(src, (int)src_stride);
const uint8x8_t p = load_unaligned_u8(pred, (int)pred_stride);
const uint16x8_t d = vsubl_u8(s, p);
vst1_s16(diff + 0 * diff_stride, vreinterpret_s16_u16(vget_low_u16(d)));
vst1_s16(diff + 1 * diff_stride, vreinterpret_s16_u16(vget_high_u16(d)));
diff += 2 * diff_stride;
pred += 2 * pred_stride;
src += 2 * src_stride;
r -= 2;
} while (r);
}
}
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2017 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VPX_VPX_DSP_ARM_SUM_NEON_H_
#define VPX_VPX_DSP_ARM_SUM_NEON_H_
#include <arm_neon.h>
#include "./vpx_config.h"
#include "vpx/vpx_integer.h"
static INLINE int32x2_t horizontal_add_int16x8(const int16x8_t a) {
const int32x4_t b = vpaddlq_s16(a);
const int64x2_t c = vpaddlq_s32(b);
return vadd_s32(vreinterpret_s32_s64(vget_low_s64(c)),
vreinterpret_s32_s64(vget_high_s64(c)));
}
static INLINE uint32x2_t horizontal_add_uint16x8(const uint16x8_t a) {
const uint32x4_t b = vpaddlq_u16(a);
const uint64x2_t c = vpaddlq_u32(b);
return vadd_u32(vreinterpret_u32_u64(vget_low_u64(c)),
vreinterpret_u32_u64(vget_high_u64(c)));
}
static INLINE uint32x2_t horizontal_add_uint32x4(const uint32x4_t a) {
const uint64x2_t b = vpaddlq_u32(a);
return vadd_u32(vreinterpret_u32_u64(vget_low_u64(b)),
vreinterpret_u32_u64(vget_high_u64(b)));
}
#endif // VPX_VPX_DSP_ARM_SUM_NEON_H_
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2018 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include "./vpx_dsp_rtcd.h"
uint64_t vpx_sum_squares_2d_i16_neon(const int16_t *src, int stride, int size) {
uint64x1_t s2;
if (size == 4) {
int16x4_t s[4];
int32x4_t s0;
uint32x2_t s1;
s[0] = vld1_s16(src + 0 * stride);
s[1] = vld1_s16(src + 1 * stride);
s[2] = vld1_s16(src + 2 * stride);
s[3] = vld1_s16(src + 3 * stride);
s0 = vmull_s16(s[0], s[0]);
s0 = vmlal_s16(s0, s[1], s[1]);
s0 = vmlal_s16(s0, s[2], s[2]);
s0 = vmlal_s16(s0, s[3], s[3]);
s1 = vpadd_u32(vget_low_u32(vreinterpretq_u32_s32(s0)),
vget_high_u32(vreinterpretq_u32_s32(s0)));
s2 = vpaddl_u32(s1);
} else {
int r = size;
uint64x2_t s1 = vdupq_n_u64(0);
do {
int c = size;
int32x4_t s0 = vdupq_n_s32(0);
const int16_t *src_t = src;
do {
int16x8_t s[8];
s[0] = vld1q_s16(src_t + 0 * stride);
s[1] = vld1q_s16(src_t + 1 * stride);
s[2] = vld1q_s16(src_t + 2 * stride);
s[3] = vld1q_s16(src_t + 3 * stride);
s[4] = vld1q_s16(src_t + 4 * stride);
s[5] = vld1q_s16(src_t + 5 * stride);
s[6] = vld1q_s16(src_t + 6 * stride);
s[7] = vld1q_s16(src_t + 7 * stride);
s0 = vmlal_s16(s0, vget_low_s16(s[0]), vget_low_s16(s[0]));
s0 = vmlal_s16(s0, vget_low_s16(s[1]), vget_low_s16(s[1]));
s0 = vmlal_s16(s0, vget_low_s16(s[2]), vget_low_s16(s[2]));
s0 = vmlal_s16(s0, vget_low_s16(s[3]), vget_low_s16(s[3]));
s0 = vmlal_s16(s0, vget_low_s16(s[4]), vget_low_s16(s[4]));
s0 = vmlal_s16(s0, vget_low_s16(s[5]), vget_low_s16(s[5]));
s0 = vmlal_s16(s0, vget_low_s16(s[6]), vget_low_s16(s[6]));
s0 = vmlal_s16(s0, vget_low_s16(s[7]), vget_low_s16(s[7]));
s0 = vmlal_s16(s0, vget_high_s16(s[0]), vget_high_s16(s[0]));
s0 = vmlal_s16(s0, vget_high_s16(s[1]), vget_high_s16(s[1]));
s0 = vmlal_s16(s0, vget_high_s16(s[2]), vget_high_s16(s[2]));
s0 = vmlal_s16(s0, vget_high_s16(s[3]), vget_high_s16(s[3]));
s0 = vmlal_s16(s0, vget_high_s16(s[4]), vget_high_s16(s[4]));
s0 = vmlal_s16(s0, vget_high_s16(s[5]), vget_high_s16(s[5]));
s0 = vmlal_s16(s0, vget_high_s16(s[6]), vget_high_s16(s[6]));
s0 = vmlal_s16(s0, vget_high_s16(s[7]), vget_high_s16(s[7]));
src_t += 8;
c -= 8;
} while (c);
s1 = vaddw_u32(s1, vget_low_u32(vreinterpretq_u32_s32(s0)));
s1 = vaddw_u32(s1, vget_high_u32(vreinterpretq_u32_s32(s0)));
src += 8 * stride;
r -= 8;
} while (r);
s2 = vadd_u64(vget_low_u64(s1), vget_high_u64(s1));
}
return vget_lane_u64(s2, 0);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,380 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include "./vpx_dsp_rtcd.h"
#include "./vpx_config.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/sum_neon.h"
#include "vpx_ports/mem.h"
// The variance helper functions use int16_t for sum. 8 values are accumulated
// and then added (at which point they expand up to int32_t). To avoid overflow,
// there can be no more than 32767 / 255 ~= 128 values accumulated in each
// column. For a 32x32 buffer, this results in 32 / 8 = 4 values per row * 32
// rows = 128. Asserts have been added to each function to warn against reaching
// this limit.
// Process a block of width 4 four rows at a time.
static void variance_neon_w4x4(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride, int h,
uint32_t *sse, int *sum) {
int i;
int16x8_t sum_s16 = vdupq_n_s16(0);
int32x4_t sse_lo_s32 = vdupq_n_s32(0);
int32x4_t sse_hi_s32 = vdupq_n_s32(0);
// Since width is only 4, sum_s16 only loads a half row per loop.
assert(h <= 256);
for (i = 0; i < h; i += 4) {
const uint8x16_t a_u8 = load_unaligned_u8q(src_ptr, src_stride);
const uint8x16_t b_u8 = load_unaligned_u8q(ref_ptr, ref_stride);
const uint16x8_t diff_lo_u16 =
vsubl_u8(vget_low_u8(a_u8), vget_low_u8(b_u8));
const uint16x8_t diff_hi_u16 =
vsubl_u8(vget_high_u8(a_u8), vget_high_u8(b_u8));
const int16x8_t diff_lo_s16 = vreinterpretq_s16_u16(diff_lo_u16);
const int16x8_t diff_hi_s16 = vreinterpretq_s16_u16(diff_hi_u16);
sum_s16 = vaddq_s16(sum_s16, diff_lo_s16);
sum_s16 = vaddq_s16(sum_s16, diff_hi_s16);
sse_lo_s32 = vmlal_s16(sse_lo_s32, vget_low_s16(diff_lo_s16),
vget_low_s16(diff_lo_s16));
sse_lo_s32 = vmlal_s16(sse_lo_s32, vget_high_s16(diff_lo_s16),
vget_high_s16(diff_lo_s16));
sse_hi_s32 = vmlal_s16(sse_hi_s32, vget_low_s16(diff_hi_s16),
vget_low_s16(diff_hi_s16));
sse_hi_s32 = vmlal_s16(sse_hi_s32, vget_high_s16(diff_hi_s16),
vget_high_s16(diff_hi_s16));
src_ptr += 4 * src_stride;
ref_ptr += 4 * ref_stride;
}
*sum = vget_lane_s32(horizontal_add_int16x8(sum_s16), 0);
*sse = vget_lane_u32(horizontal_add_uint32x4(vreinterpretq_u32_s32(
vaddq_s32(sse_lo_s32, sse_hi_s32))),
0);
}
// Process a block of any size where the width is divisible by 16.
static void variance_neon_w16(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride, int w,
int h, uint32_t *sse, int *sum) {
int i, j;
int16x8_t sum_s16 = vdupq_n_s16(0);
int32x4_t sse_lo_s32 = vdupq_n_s32(0);
int32x4_t sse_hi_s32 = vdupq_n_s32(0);
// The loop loads 16 values at a time but doubles them up when accumulating
// into sum_s16.
assert(w / 8 * h <= 128);
for (i = 0; i < h; ++i) {
for (j = 0; j < w; j += 16) {
const uint8x16_t a_u8 = vld1q_u8(src_ptr + j);
const uint8x16_t b_u8 = vld1q_u8(ref_ptr + j);
const uint16x8_t diff_lo_u16 =
vsubl_u8(vget_low_u8(a_u8), vget_low_u8(b_u8));
const uint16x8_t diff_hi_u16 =
vsubl_u8(vget_high_u8(a_u8), vget_high_u8(b_u8));
const int16x8_t diff_lo_s16 = vreinterpretq_s16_u16(diff_lo_u16);
const int16x8_t diff_hi_s16 = vreinterpretq_s16_u16(diff_hi_u16);
sum_s16 = vaddq_s16(sum_s16, diff_lo_s16);
sum_s16 = vaddq_s16(sum_s16, diff_hi_s16);
sse_lo_s32 = vmlal_s16(sse_lo_s32, vget_low_s16(diff_lo_s16),
vget_low_s16(diff_lo_s16));
sse_lo_s32 = vmlal_s16(sse_lo_s32, vget_high_s16(diff_lo_s16),
vget_high_s16(diff_lo_s16));
sse_hi_s32 = vmlal_s16(sse_hi_s32, vget_low_s16(diff_hi_s16),
vget_low_s16(diff_hi_s16));
sse_hi_s32 = vmlal_s16(sse_hi_s32, vget_high_s16(diff_hi_s16),
vget_high_s16(diff_hi_s16));
}
src_ptr += src_stride;
ref_ptr += ref_stride;
}
*sum = vget_lane_s32(horizontal_add_int16x8(sum_s16), 0);
*sse = vget_lane_u32(horizontal_add_uint32x4(vreinterpretq_u32_s32(
vaddq_s32(sse_lo_s32, sse_hi_s32))),
0);
}
// Process a block of width 8 two rows at a time.
static void variance_neon_w8x2(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride, int h,
uint32_t *sse, int *sum) {
int i = 0;
int16x8_t sum_s16 = vdupq_n_s16(0);
int32x4_t sse_lo_s32 = vdupq_n_s32(0);
int32x4_t sse_hi_s32 = vdupq_n_s32(0);
// Each column has it's own accumulator entry in sum_s16.
assert(h <= 128);
do {
const uint8x8_t a_0_u8 = vld1_u8(src_ptr);
const uint8x8_t a_1_u8 = vld1_u8(src_ptr + src_stride);
const uint8x8_t b_0_u8 = vld1_u8(ref_ptr);
const uint8x8_t b_1_u8 = vld1_u8(ref_ptr + ref_stride);
const uint16x8_t diff_0_u16 = vsubl_u8(a_0_u8, b_0_u8);
const uint16x8_t diff_1_u16 = vsubl_u8(a_1_u8, b_1_u8);
const int16x8_t diff_0_s16 = vreinterpretq_s16_u16(diff_0_u16);
const int16x8_t diff_1_s16 = vreinterpretq_s16_u16(diff_1_u16);
sum_s16 = vaddq_s16(sum_s16, diff_0_s16);
sum_s16 = vaddq_s16(sum_s16, diff_1_s16);
sse_lo_s32 = vmlal_s16(sse_lo_s32, vget_low_s16(diff_0_s16),
vget_low_s16(diff_0_s16));
sse_lo_s32 = vmlal_s16(sse_lo_s32, vget_low_s16(diff_1_s16),
vget_low_s16(diff_1_s16));
sse_hi_s32 = vmlal_s16(sse_hi_s32, vget_high_s16(diff_0_s16),
vget_high_s16(diff_0_s16));
sse_hi_s32 = vmlal_s16(sse_hi_s32, vget_high_s16(diff_1_s16),
vget_high_s16(diff_1_s16));
src_ptr += src_stride + src_stride;
ref_ptr += ref_stride + ref_stride;
i += 2;
} while (i < h);
*sum = vget_lane_s32(horizontal_add_int16x8(sum_s16), 0);
*sse = vget_lane_u32(horizontal_add_uint32x4(vreinterpretq_u32_s32(
vaddq_s32(sse_lo_s32, sse_hi_s32))),
0);
}
void vpx_get8x8var_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
unsigned int *sse, int *sum) {
variance_neon_w8x2(src_ptr, src_stride, ref_ptr, ref_stride, 8, sse, sum);
}
void vpx_get16x16var_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
unsigned int *sse, int *sum) {
variance_neon_w16(src_ptr, src_stride, ref_ptr, ref_stride, 16, 16, sse, sum);
}
#define varianceNxM(n, m, shift) \
unsigned int vpx_variance##n##x##m##_neon( \
const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
int ref_stride, unsigned int *sse) { \
int sum; \
if (n == 4) \
variance_neon_w4x4(src_ptr, src_stride, ref_ptr, ref_stride, m, sse, \
&sum); \
else if (n == 8) \
variance_neon_w8x2(src_ptr, src_stride, ref_ptr, ref_stride, m, sse, \
&sum); \
else \
variance_neon_w16(src_ptr, src_stride, ref_ptr, ref_stride, n, m, sse, \
&sum); \
if (n * m < 16 * 16) \
return *sse - ((sum * sum) >> shift); \
else \
return *sse - (uint32_t)(((int64_t)sum * sum) >> shift); \
}
varianceNxM(4, 4, 4);
varianceNxM(4, 8, 5);
varianceNxM(8, 4, 5);
varianceNxM(8, 8, 6);
varianceNxM(8, 16, 7);
varianceNxM(16, 8, 7);
varianceNxM(16, 16, 8);
varianceNxM(16, 32, 9);
varianceNxM(32, 16, 9);
varianceNxM(32, 32, 10);
unsigned int vpx_variance32x64_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
unsigned int *sse) {
int sum1, sum2;
uint32_t sse1, sse2;
variance_neon_w16(src_ptr, src_stride, ref_ptr, ref_stride, 32, 32, &sse1,
&sum1);
variance_neon_w16(src_ptr + (32 * src_stride), src_stride,
ref_ptr + (32 * ref_stride), ref_stride, 32, 32, &sse2,
&sum2);
*sse = sse1 + sse2;
sum1 += sum2;
return *sse - (unsigned int)(((int64_t)sum1 * sum1) >> 11);
}
unsigned int vpx_variance64x32_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
unsigned int *sse) {
int sum1, sum2;
uint32_t sse1, sse2;
variance_neon_w16(src_ptr, src_stride, ref_ptr, ref_stride, 64, 16, &sse1,
&sum1);
variance_neon_w16(src_ptr + (16 * src_stride), src_stride,
ref_ptr + (16 * ref_stride), ref_stride, 64, 16, &sse2,
&sum2);
*sse = sse1 + sse2;
sum1 += sum2;
return *sse - (unsigned int)(((int64_t)sum1 * sum1) >> 11);
}
unsigned int vpx_variance64x64_neon(const uint8_t *src_ptr, int src_stride,
const uint8_t *ref_ptr, int ref_stride,
unsigned int *sse) {
int sum1, sum2;
uint32_t sse1, sse2;
variance_neon_w16(src_ptr, src_stride, ref_ptr, ref_stride, 64, 16, &sse1,
&sum1);
variance_neon_w16(src_ptr + (16 * src_stride), src_stride,
ref_ptr + (16 * ref_stride), ref_stride, 64, 16, &sse2,
&sum2);
sse1 += sse2;
sum1 += sum2;
variance_neon_w16(src_ptr + (16 * 2 * src_stride), src_stride,
ref_ptr + (16 * 2 * ref_stride), ref_stride, 64, 16, &sse2,
&sum2);
sse1 += sse2;
sum1 += sum2;
variance_neon_w16(src_ptr + (16 * 3 * src_stride), src_stride,
ref_ptr + (16 * 3 * ref_stride), ref_stride, 64, 16, &sse2,
&sum2);
*sse = sse1 + sse2;
sum1 += sum2;
return *sse - (unsigned int)(((int64_t)sum1 * sum1) >> 12);
}
unsigned int vpx_mse16x16_neon(const unsigned char *src_ptr, int src_stride,
const unsigned char *ref_ptr, int ref_stride,
unsigned int *sse) {
int i;
int16x4_t d22s16, d23s16, d24s16, d25s16, d26s16, d27s16, d28s16, d29s16;
int64x1_t d0s64;
uint8x16_t q0u8, q1u8, q2u8, q3u8;
int32x4_t q7s32, q8s32, q9s32, q10s32;
uint16x8_t q11u16, q12u16, q13u16, q14u16;
int64x2_t q1s64;
q7s32 = vdupq_n_s32(0);
q8s32 = vdupq_n_s32(0);
q9s32 = vdupq_n_s32(0);
q10s32 = vdupq_n_s32(0);
for (i = 0; i < 8; i++) { // mse16x16_neon_loop
q0u8 = vld1q_u8(src_ptr);
src_ptr += src_stride;
q1u8 = vld1q_u8(src_ptr);
src_ptr += src_stride;
q2u8 = vld1q_u8(ref_ptr);
ref_ptr += ref_stride;
q3u8 = vld1q_u8(ref_ptr);
ref_ptr += ref_stride;
q11u16 = vsubl_u8(vget_low_u8(q0u8), vget_low_u8(q2u8));
q12u16 = vsubl_u8(vget_high_u8(q0u8), vget_high_u8(q2u8));
q13u16 = vsubl_u8(vget_low_u8(q1u8), vget_low_u8(q3u8));
q14u16 = vsubl_u8(vget_high_u8(q1u8), vget_high_u8(q3u8));
d22s16 = vreinterpret_s16_u16(vget_low_u16(q11u16));
d23s16 = vreinterpret_s16_u16(vget_high_u16(q11u16));
q7s32 = vmlal_s16(q7s32, d22s16, d22s16);
q8s32 = vmlal_s16(q8s32, d23s16, d23s16);
d24s16 = vreinterpret_s16_u16(vget_low_u16(q12u16));
d25s16 = vreinterpret_s16_u16(vget_high_u16(q12u16));
q9s32 = vmlal_s16(q9s32, d24s16, d24s16);
q10s32 = vmlal_s16(q10s32, d25s16, d25s16);
d26s16 = vreinterpret_s16_u16(vget_low_u16(q13u16));
d27s16 = vreinterpret_s16_u16(vget_high_u16(q13u16));
q7s32 = vmlal_s16(q7s32, d26s16, d26s16);
q8s32 = vmlal_s16(q8s32, d27s16, d27s16);
d28s16 = vreinterpret_s16_u16(vget_low_u16(q14u16));
d29s16 = vreinterpret_s16_u16(vget_high_u16(q14u16));
q9s32 = vmlal_s16(q9s32, d28s16, d28s16);
q10s32 = vmlal_s16(q10s32, d29s16, d29s16);
}
q7s32 = vaddq_s32(q7s32, q8s32);
q9s32 = vaddq_s32(q9s32, q10s32);
q10s32 = vaddq_s32(q7s32, q9s32);
q1s64 = vpaddlq_s32(q10s32);
d0s64 = vadd_s64(vget_low_s64(q1s64), vget_high_s64(q1s64));
vst1_lane_u32((uint32_t *)sse, vreinterpret_u32_s64(d0s64), 0);
return vget_lane_u32(vreinterpret_u32_s64(d0s64), 0);
}
unsigned int vpx_get4x4sse_cs_neon(const unsigned char *src_ptr, int src_stride,
const unsigned char *ref_ptr,
int ref_stride) {
int16x4_t d22s16, d24s16, d26s16, d28s16;
int64x1_t d0s64;
uint8x8_t d0u8, d1u8, d2u8, d3u8, d4u8, d5u8, d6u8, d7u8;
int32x4_t q7s32, q8s32, q9s32, q10s32;
uint16x8_t q11u16, q12u16, q13u16, q14u16;
int64x2_t q1s64;
d0u8 = vld1_u8(src_ptr);
src_ptr += src_stride;
d4u8 = vld1_u8(ref_ptr);
ref_ptr += ref_stride;
d1u8 = vld1_u8(src_ptr);
src_ptr += src_stride;
d5u8 = vld1_u8(ref_ptr);
ref_ptr += ref_stride;
d2u8 = vld1_u8(src_ptr);
src_ptr += src_stride;
d6u8 = vld1_u8(ref_ptr);
ref_ptr += ref_stride;
d3u8 = vld1_u8(src_ptr);
src_ptr += src_stride;
d7u8 = vld1_u8(ref_ptr);
ref_ptr += ref_stride;
q11u16 = vsubl_u8(d0u8, d4u8);
q12u16 = vsubl_u8(d1u8, d5u8);
q13u16 = vsubl_u8(d2u8, d6u8);
q14u16 = vsubl_u8(d3u8, d7u8);
d22s16 = vget_low_s16(vreinterpretq_s16_u16(q11u16));
d24s16 = vget_low_s16(vreinterpretq_s16_u16(q12u16));
d26s16 = vget_low_s16(vreinterpretq_s16_u16(q13u16));
d28s16 = vget_low_s16(vreinterpretq_s16_u16(q14u16));
q7s32 = vmull_s16(d22s16, d22s16);
q8s32 = vmull_s16(d24s16, d24s16);
q9s32 = vmull_s16(d26s16, d26s16);
q10s32 = vmull_s16(d28s16, d28s16);
q7s32 = vaddq_s32(q7s32, q8s32);
q9s32 = vaddq_s32(q9s32, q10s32);
q9s32 = vaddq_s32(q7s32, q9s32);
q1s64 = vpaddlq_s32(q9s32);
d0s64 = vadd_s64(vget_low_s64(q1s64), vget_high_s64(q1s64));
return vget_lane_u32(vreinterpret_u32_s64(d0s64), 0);
}
@@ -0,0 +1,438 @@
;
; Copyright (c) 2018 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
;**************Variables Vs Registers*****************************************
; r0 => src
; r1 => dst
; r2 => src_stride
; r3 => dst_stride
; r4 => filter_x0
; r8 => ht
; r10 => wd
EXPORT |vpx_convolve8_avg_horiz_filter_type1_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
|vpx_convolve8_avg_horiz_filter_type1_neon| PROC
stmfd sp!, {r4 - r12, r14} ;stack stores the values of
; the arguments
vpush {d8 - d15} ; stack offset by 64
mov r4, r1
mov r1, r2
mov r2, r4
start_loop_count
ldr r4, [sp, #104] ;loads pi1_coeff
ldr r8, [sp, #108] ;loads x0_q4
add r4, r4, r8, lsl #4 ;r4 = filter[x0_q4]
ldr r8, [sp, #128] ;loads ht
ldr r10, [sp, #124] ;loads wd
vld2.8 {d0, d1}, [r4] ;coeff = vld1_s8(pi1_coeff)
mov r11, #1
subs r14, r8, #0 ;checks for ht == 0
vabs.s8 d2, d0 ;vabs_s8(coeff)
vdup.8 d24, d2[0] ;coeffabs_0 = vdup_lane_u8(coeffabs,
; 0)
sub r12, r0, #3 ;pu1_src - 3
vdup.8 d25, d2[1] ;coeffabs_1 = vdup_lane_u8(coeffabs,
; 1)
add r4, r12, r2 ;pu1_src_tmp2_8 = pu1_src + src_strd
vdup.8 d26, d2[2] ;coeffabs_2 = vdup_lane_u8(coeffabs,
; 2)
rsb r9, r10, r2, lsl #1 ;2*src_strd - wd
vdup.8 d27, d2[3] ;coeffabs_3 = vdup_lane_u8(coeffabs,
; 3)
rsb r8, r10, r3, lsl #1 ;2*dst_strd - wd
vdup.8 d28, d2[4] ;coeffabs_4 = vdup_lane_u8(coeffabs,
; 4)
vdup.8 d29, d2[5] ;coeffabs_5 = vdup_lane_u8(coeffabs,
; 5)
vdup.8 d30, d2[6] ;coeffabs_6 = vdup_lane_u8(coeffabs,
; 6)
vdup.8 d31, d2[7] ;coeffabs_7 = vdup_lane_u8(coeffabs,
; 7)
mov r7, r1
cmp r10, #4
ble outer_loop_4
cmp r10, #24
moveq r10, #16
addeq r8, #8
addeq r9, #8
cmp r10, #16
bge outer_loop_16
cmp r10, #12
addeq r8, #4
addeq r9, #4
b outer_loop_8
outer_loop8_residual
sub r12, r0, #3 ;pu1_src - 3
mov r1, r7
mov r14, #32
add r1, #16
add r12, #16
mov r10, #8
add r8, #8
add r9, #8
outer_loop_8
add r6, r1, r3 ;pu1_dst + dst_strd
add r4, r12, r2 ;pu1_src + src_strd
subs r5, r10, #0 ;checks wd
ble end_inner_loop_8
inner_loop_8
mov r7, #0xc000
vld1.u32 {d0}, [r12], r11 ;vector load pu1_src
vdup.16 q4, r7
vld1.u32 {d1}, [r12], r11
vdup.16 q5, r7
vld1.u32 {d2}, [r12], r11
vld1.u32 {d3}, [r12], r11
mov r7, #0x4000
vld1.u32 {d4}, [r12], r11
vmlsl.u8 q4, d1, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {d5}, [r12], r11
vmlal.u8 q4, d3, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {d6}, [r12], r11
vmlsl.u8 q4, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vld1.u32 {d7}, [r12], r11
vmlal.u8 q4, d2, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u32 {d12}, [r4], r11 ;vector load pu1_src + src_strd
vmlal.u8 q4, d4, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vld1.u32 {d13}, [r4], r11
vmlal.u8 q4, d5, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vld1.u32 {d14}, [r4], r11
vmlsl.u8 q4, d6, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vld1.u32 {d15}, [r4], r11
vmlsl.u8 q4, d7, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
vld1.u32 {d16}, [r4], r11 ;vector load pu1_src + src_strd
vdup.16 q11, r7
vmlal.u8 q5, d15, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {d17}, [r4], r11
vmlal.u8 q5, d14, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vhadd.s16 q4, q4, q11
vld1.u32 {d18}, [r4], r11
vmlal.u8 q5, d16, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vld1.u32 {d19}, [r4], r11 ;vector load pu1_src + src_strd
vmlal.u8 q5, d17, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vld1.u8 {d6}, [r1]
vqrshrun.s16 d20, q4, #6 ;right shift and saturating narrow
; result 1
vmlsl.u8 q5, d18, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q5, d19, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
vld1.u8 {d7}, [r6]
vrhadd.u8 d20, d20, d6
vmlsl.u8 q5, d12, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vmlsl.u8 q5, d13, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vst1.8 {d20}, [r1]! ;store the result pu1_dst
vhadd.s16 q5, q5, q11
subs r5, r5, #8 ;decrement the wd loop
vqrshrun.s16 d8, q5, #6 ;right shift and saturating narrow
; result 2
vrhadd.u8 d8, d8, d7
vst1.8 {d8}, [r6]! ;store the result pu1_dst
cmp r5, #4
bgt inner_loop_8
end_inner_loop_8
subs r14, r14, #2 ;decrement the ht loop
add r12, r12, r9 ;increment the src pointer by
; 2*src_strd-wd
add r1, r1, r8 ;increment the dst pointer by
; 2*dst_strd-wd
bgt outer_loop_8
ldr r10, [sp, #120] ;loads wd
cmp r10, #12
beq outer_loop4_residual
end_loops
b end_func
outer_loop_16
str r0, [sp, #-4]!
str r7, [sp, #-4]!
add r6, r1, r3 ;pu1_dst + dst_strd
add r4, r12, r2 ;pu1_src + src_strd
and r0, r12, #31
mov r7, #0xc000
sub r5, r10, #0 ;checks wd
pld [r4, r2, lsl #1]
pld [r12, r2, lsl #1]
vld1.u32 {q0}, [r12], r11 ;vector load pu1_src
vdup.16 q4, r7
vld1.u32 {q1}, [r12], r11
vld1.u32 {q2}, [r12], r11
vld1.u32 {q3}, [r12], r11
vmlsl.u8 q4, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vld1.u32 {q6}, [r12], r11
vmlsl.u8 q4, d2, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {q7}, [r12], r11
vmlal.u8 q4, d4, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u32 {q8}, [r12], r11
vmlal.u8 q4, d6, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {q9}, [r12], r11
vmlal.u8 q4, d12, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vmlal.u8 q4, d14, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vdup.16 q10, r7
vmlsl.u8 q4, d16, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q4, d18, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
inner_loop_16
vmlsl.u8 q10, d1, d24
vdup.16 q5, r7
vmlsl.u8 q10, d3, d25
mov r7, #0x4000
vdup.16 q11, r7
vmlal.u8 q10, d5, d26
vld1.u32 {q0}, [r4], r11 ;vector load pu1_src
vhadd.s16 q4, q4, q11
vld1.u32 {q1}, [r4], r11
vmlal.u8 q10, d7, d27
add r12, #8
subs r5, r5, #16
vmlal.u8 q10, d13, d28
vld1.u32 {q2}, [r4], r11
vmlal.u8 q10, d15, d29
vld1.u32 {q3}, [r4], r11
vqrshrun.s16 d8, q4, #6 ;right shift and saturating narrow
; result 1
vmlsl.u8 q10, d17, d30
vld1.u32 {q6}, [r4], r11
vmlsl.u8 q10, d19, d31
vld1.u32 {q7}, [r4], r11
add r7, r1, #8
vmlsl.u8 q5, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vmlsl.u8 q5, d2, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {q8}, [r4], r11
vhadd.s16 q10, q10, q11
vld1.u32 {q9}, [r4], r11
vld1.u8 {d0}, [r1]
vmlal.u8 q5, d4, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u8 {d2}, [r7]
vmlal.u8 q5, d6, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
add r4, #8
mov r7, #0xc000
vmlal.u8 q5, d12, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vmlal.u8 q5, d14, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vqrshrun.s16 d9, q10, #6
vdup.16 q11, r7
vmlsl.u8 q5, d16, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q5, d18, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
mov r7, #0x4000
vrhadd.u8 d8, d8, d0
vrhadd.u8 d9, d9, d2
vmlsl.u8 q11, d1, d24
vmlsl.u8 q11, d3, d25
vdup.16 q10, r7
vmlal.u8 q11, d5, d26
pld [r12, r2, lsl #2]
pld [r4, r2, lsl #2]
addeq r12, r12, r9 ;increment the src pointer by
; 2*src_strd-wd
addeq r4, r12, r2 ;pu1_src + src_strd
vmlal.u8 q11, d7, d27
vmlal.u8 q11, d13, d28
vst1.8 {q4}, [r1]! ;store the result pu1_dst
subeq r14, r14, #2
vhadd.s16 q5, q5, q10
vmlal.u8 q11, d15, d29
addeq r1, r1, r8
vmlsl.u8 q11, d17, d30
cmp r14, #0
vmlsl.u8 q11, d19, d31
vqrshrun.s16 d10, q5, #6 ;right shift and saturating narrow
; result 2
beq epilog_16
vld1.u32 {q0}, [r12], r11 ;vector load pu1_src
mov r7, #0xc000
cmp r5, #0
vld1.u32 {q1}, [r12], r11
vhadd.s16 q11, q11, q10
vld1.u32 {q2}, [r12], r11
vdup.16 q4, r7
vmlsl.u8 q4, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vdup.16 q10, r7
vld1.u32 {q3}, [r12], r11
add r7, r6, #8
moveq r5, r10
vld1.u8 {d0}, [r6]
vmlsl.u8 q4, d2, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u8 {d2}, [r7]
vqrshrun.s16 d11, q11, #6
vmlal.u8 q4, d4, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u32 {q6}, [r12], r11
vrhadd.u8 d10, d10, d0
vld1.u32 {q7}, [r12], r11
vrhadd.u8 d11, d11, d2
vld1.u32 {q8}, [r12], r11
vmlal.u8 q4, d6, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {q9}, [r12], r11
vmlal.u8 q4, d12, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vmlal.u8 q4, d14, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
mov r7, #0xc000
vmlsl.u8 q4, d16, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vst1.8 {q5}, [r6]! ;store the result pu1_dst
vmlsl.u8 q4, d18, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
addeq r6, r1, r3 ;pu1_dst + dst_strd
b inner_loop_16
epilog_16
mov r7, #0x4000
ldr r0, [sp], #4
ldr r10, [sp, #120]
vdup.16 q10, r7
vhadd.s16 q11, q11, q10
vqrshrun.s16 d11, q11, #6
add r7, r6, #8
vld1.u8 {d20}, [r6]
vld1.u8 {d21}, [r7]
vrhadd.u8 d10, d10, d20
vrhadd.u8 d11, d11, d21
vst1.8 {q5}, [r6]! ;store the result pu1_dst
ldr r7, [sp], #4
cmp r10, #24
beq outer_loop8_residual
end_loops1
b end_func
outer_loop4_residual
sub r12, r0, #3 ;pu1_src - 3
mov r1, r7
add r1, #8
mov r10, #4
add r12, #8
mov r14, #16
add r8, #4
add r9, #4
outer_loop_4
add r6, r1, r3 ;pu1_dst + dst_strd
add r4, r12, r2 ;pu1_src + src_strd
subs r5, r10, #0 ;checks wd
ble end_inner_loop_4
inner_loop_4
vld1.u32 {d0}, [r12], r11 ;vector load pu1_src
vld1.u32 {d1}, [r12], r11
vld1.u32 {d2}, [r12], r11
vld1.u32 {d3}, [r12], r11
vld1.u32 {d4}, [r12], r11
vld1.u32 {d5}, [r12], r11
vld1.u32 {d6}, [r12], r11
vld1.u32 {d7}, [r12], r11
sub r12, r12, #4
vld1.u32 {d12}, [r4], r11 ;vector load pu1_src + src_strd
vld1.u32 {d13}, [r4], r11
vzip.32 d0, d12 ;vector zip the i iteration and ii
; interation in single register
vld1.u32 {d14}, [r4], r11
vzip.32 d1, d13
vld1.u32 {d15}, [r4], r11
vzip.32 d2, d14
vld1.u32 {d16}, [r4], r11
vzip.32 d3, d15
vld1.u32 {d17}, [r4], r11
vzip.32 d4, d16
vld1.u32 {d18}, [r4], r11
vzip.32 d5, d17
vld1.u32 {d19}, [r4], r11
mov r7, #0xc000
vdup.16 q4, r7
sub r4, r4, #4
vzip.32 d6, d18
vzip.32 d7, d19
vmlsl.u8 q4, d1, d25 ;arithmetic operations for ii
; iteration in the same time
vmlsl.u8 q4, d0, d24
vmlal.u8 q4, d2, d26
vmlal.u8 q4, d3, d27
vmlal.u8 q4, d4, d28
vmlal.u8 q4, d5, d29
vmlsl.u8 q4, d6, d30
vmlsl.u8 q4, d7, d31
mov r7, #0x4000
vdup.16 q10, r7
vhadd.s16 q4, q4, q10
vqrshrun.s16 d8, q4, #6
vld1.u32 {d10[0]}, [r1]
vld1.u32 {d10[1]}, [r6]
vrhadd.u8 d8, d8, d10
vst1.32 {d8[0]},[r1]! ;store the i iteration result which
; is in upper part of the register
vst1.32 {d8[1]},[r6]! ;store the ii iteration result which
; is in lower part of the register
subs r5, r5, #4 ;decrement the wd by 4
bgt inner_loop_4
end_inner_loop_4
subs r14, r14, #2 ;decrement the ht by 4
add r12, r12, r9 ;increment the input pointer
; 2*src_strd-wd
add r1, r1, r8 ;increment the output pointer
; 2*dst_strd-wd
bgt outer_loop_4
end_func
vpop {d8 - d15}
ldmfd sp!, {r4 - r12, r15} ;reload the registers from sp
ENDP
END
@@ -0,0 +1,439 @@
;
; Copyright (c) 2018 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
;**************Variables Vs Registers***********************************
; r0 => src
; r1 => dst
; r2 => src_stride
; r3 => dst_stride
; r4 => filter_x0
; r8 => ht
; r10 => wd
EXPORT |vpx_convolve8_avg_horiz_filter_type2_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
|vpx_convolve8_avg_horiz_filter_type2_neon| PROC
stmfd sp!, {r4 - r12, r14} ;stack stores the values of
; the arguments
vpush {d8 - d15} ; stack offset by 64
mov r4, r1
mov r1, r2
mov r2, r4
start_loop_count
ldr r4, [sp, #104] ;loads pi1_coeff
ldr r8, [sp, #108] ;loads x0_q4
add r4, r4, r8, lsl #4 ;r4 = filter[x0_q4]
ldr r8, [sp, #128] ;loads ht
ldr r10, [sp, #124] ;loads wd
vld2.8 {d0, d1}, [r4] ;coeff = vld1_s8(pi1_coeff)
mov r11, #1
subs r14, r8, #0 ;checks for ht == 0
vabs.s8 d2, d0 ;vabs_s8(coeff)
vdup.8 d24, d2[0] ;coeffabs_0 = vdup_lane_u8(coeffabs,
; 0)
sub r12, r0, #3 ;pu1_src - 3
vdup.8 d25, d2[1] ;coeffabs_1 = vdup_lane_u8(coeffabs,
; 1)
add r4, r12, r2 ;pu1_src_tmp2_8 = pu1_src + src_strd
vdup.8 d26, d2[2] ;coeffabs_2 = vdup_lane_u8(coeffabs,
; 2)
rsb r9, r10, r2, lsl #1 ;2*src_strd - wd
vdup.8 d27, d2[3] ;coeffabs_3 = vdup_lane_u8(coeffabs,
; 3)
rsb r8, r10, r3, lsl #1 ;2*dst_strd - wd
vdup.8 d28, d2[4] ;coeffabs_4 = vdup_lane_u8(coeffabs,
; 4)
vdup.8 d29, d2[5] ;coeffabs_5 = vdup_lane_u8(coeffabs,
; 5)
vdup.8 d30, d2[6] ;coeffabs_6 = vdup_lane_u8(coeffabs,
; 6)
vdup.8 d31, d2[7] ;coeffabs_7 = vdup_lane_u8(coeffabs,
; 7)
mov r7, r1
cmp r10, #4
ble outer_loop_4
cmp r10, #24
moveq r10, #16
addeq r8, #8
addeq r9, #8
cmp r10, #16
bge outer_loop_16
cmp r10, #12
addeq r8, #4
addeq r9, #4
b outer_loop_8
outer_loop8_residual
sub r12, r0, #3 ;pu1_src - 3
mov r1, r7
mov r14, #32
add r1, #16
add r12, #16
mov r10, #8
add r8, #8
add r9, #8
outer_loop_8
add r6, r1, r3 ;pu1_dst + dst_strd
add r4, r12, r2 ;pu1_src + src_strd
subs r5, r10, #0 ;checks wd
ble end_inner_loop_8
inner_loop_8
mov r7, #0xc000
vld1.u32 {d0}, [r12], r11 ;vector load pu1_src
vdup.16 q4, r7
vld1.u32 {d1}, [r12], r11
vdup.16 q5, r7
vld1.u32 {d2}, [r12], r11
vld1.u32 {d3}, [r12], r11
mov r7, #0x4000
vld1.u32 {d4}, [r12], r11
vmlal.u8 q4, d1, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {d5}, [r12], r11
vmlal.u8 q4, d3, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {d6}, [r12], r11
vmlsl.u8 q4, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vld1.u32 {d7}, [r12], r11
vmlsl.u8 q4, d2, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u32 {d12}, [r4], r11 ;vector load pu1_src + src_strd
vmlal.u8 q4, d4, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vld1.u32 {d13}, [r4], r11
vmlsl.u8 q4, d5, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vld1.u32 {d14}, [r4], r11
vmlal.u8 q4, d6, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vld1.u32 {d15}, [r4], r11
vmlsl.u8 q4, d7, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
vld1.u32 {d16}, [r4], r11 ;vector load pu1_src + src_strd
vdup.16 q11, r7
vmlal.u8 q5, d15, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {d17}, [r4], r11
vmlsl.u8 q5, d14, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vhadd.s16 q4, q4, q11
vld1.u32 {d18}, [r4], r11
vmlal.u8 q5, d16, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vld1.u32 {d19}, [r4], r11 ;vector load pu1_src + src_strd
vmlsl.u8 q5, d17, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vld1.u8 {d6}, [r1]
vqrshrun.s16 d20, q4, #6 ;right shift and saturating narrow
; result 1
vmlal.u8 q5, d18, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q5, d19, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
vld1.u8 {d7}, [r6]
vrhadd.u8 d20, d20, d6
vmlsl.u8 q5, d12, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vmlal.u8 q5, d13, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vst1.8 {d20}, [r1]! ;store the result pu1_dst
vhadd.s16 q5, q5, q11
subs r5, r5, #8 ;decrement the wd loop
vqrshrun.s16 d8, q5, #6 ;right shift and saturating narrow
; result 2
vrhadd.u8 d8, d8, d7
vst1.8 {d8}, [r6]! ;store the result pu1_dst
cmp r5, #4
bgt inner_loop_8
end_inner_loop_8
subs r14, r14, #2 ;decrement the ht loop
add r12, r12, r9 ;increment the src pointer by
; 2*src_strd-wd
add r1, r1, r8 ;increment the dst pointer by
; 2*dst_strd-wd
bgt outer_loop_8
ldr r10, [sp, #120] ;loads wd
cmp r10, #12
beq outer_loop4_residual
end_loops
b end_func
outer_loop_16
str r0, [sp, #-4]!
str r7, [sp, #-4]!
add r6, r1, r3 ;pu1_dst + dst_strd
add r4, r12, r2 ;pu1_src + src_strd
and r0, r12, #31
mov r7, #0xc000
sub r5, r10, #0 ;checks wd
pld [r4, r2, lsl #1]
pld [r12, r2, lsl #1]
vld1.u32 {q0}, [r12], r11 ;vector load pu1_src
vdup.16 q4, r7
vld1.u32 {q1}, [r12], r11
vld1.u32 {q2}, [r12], r11
vld1.u32 {q3}, [r12], r11
vmlsl.u8 q4, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vld1.u32 {q6}, [r12], r11
vmlal.u8 q4, d2, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {q7}, [r12], r11
vmlsl.u8 q4, d4, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u32 {q8}, [r12], r11
vmlal.u8 q4, d6, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {q9}, [r12], r11
vmlal.u8 q4, d12, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vmlsl.u8 q4, d14, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vdup.16 q10, r7
vmlal.u8 q4, d16, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q4, d18, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
inner_loop_16
vmlsl.u8 q10, d1, d24
vdup.16 q5, r7
vmlal.u8 q10, d3, d25
mov r7, #0x4000
vdup.16 q11, r7
vmlsl.u8 q10, d5, d26
vld1.u32 {q0}, [r4], r11 ;vector load pu1_src
vhadd.s16 q4, q4, q11
vld1.u32 {q1}, [r4], r11
vmlal.u8 q10, d7, d27
add r12, #8
subs r5, r5, #16
vmlal.u8 q10, d13, d28
vld1.u32 {q2}, [r4], r11
vmlsl.u8 q10, d15, d29
vld1.u32 {q3}, [r4], r11
vqrshrun.s16 d8, q4, #6 ;right shift and saturating narrow
; result 1
vmlal.u8 q10, d17, d30
vld1.u32 {q6}, [r4], r11
vmlsl.u8 q10, d19, d31
vld1.u32 {q7}, [r4], r11
add r7, r1, #8
vmlsl.u8 q5, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vmlal.u8 q5, d2, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {q8}, [r4], r11
vhadd.s16 q10, q10, q11
vld1.u32 {q9}, [r4], r11
vld1.u8 {d0}, [r1]
vmlsl.u8 q5, d4, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u8 {d2}, [r7]
vmlal.u8 q5, d6, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
add r4, #8
mov r7, #0xc000
vmlal.u8 q5, d12, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vmlsl.u8 q5, d14, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vqrshrun.s16 d9, q10, #6
vdup.16 q11, r7
vmlal.u8 q5, d16, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q5, d18, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
mov r7, #0x4000
vrhadd.u8 d8, d8, d0
vrhadd.u8 d9, d9, d2
vmlsl.u8 q11, d1, d24
vmlal.u8 q11, d3, d25
vdup.16 q10, r7
vmlsl.u8 q11, d5, d26
pld [r12, r2, lsl #2]
pld [r4, r2, lsl #2]
addeq r12, r12, r9 ;increment the src pointer by
; 2*src_strd-wd
addeq r4, r12, r2 ;pu1_src + src_strd
vmlal.u8 q11, d7, d27
vmlal.u8 q11, d13, d28
vst1.8 {q4}, [r1]! ;store the result pu1_dst
subeq r14, r14, #2
vhadd.s16 q5, q5, q10
vmlsl.u8 q11, d15, d29
addeq r1, r1, r8
vmlal.u8 q11, d17, d30
cmp r14, #0
vmlsl.u8 q11, d19, d31
vqrshrun.s16 d10, q5, #6 ;right shift and saturating narrow
; result 2
beq epilog_16
vld1.u32 {q0}, [r12], r11 ;vector load pu1_src
mov r7, #0xc000
cmp r5, #0
vld1.u32 {q1}, [r12], r11
vhadd.s16 q11, q11, q10
vld1.u32 {q2}, [r12], r11
vdup.16 q4, r7
vmlsl.u8 q4, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vdup.16 q10, r7
vld1.u32 {q3}, [r12], r11
add r7, r6, #8
moveq r5, r10
vld1.u8 {d0}, [r6]
vmlal.u8 q4, d2, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u8 {d2}, [r7]
vqrshrun.s16 d11, q11, #6
vmlsl.u8 q4, d4, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u32 {q6}, [r12], r11
vrhadd.u8 d10, d10, d0
vld1.u32 {q7}, [r12], r11
vrhadd.u8 d11, d11, d2
vld1.u32 {q8}, [r12], r11
vmlal.u8 q4, d6, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {q9}, [r12], r11
vmlal.u8 q4, d12, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vmlsl.u8 q4, d14, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
mov r7, #0xc000
vmlal.u8 q4, d16, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vst1.8 {q5}, [r6]! ;store the result pu1_dst
vmlsl.u8 q4, d18, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
addeq r6, r1, r3 ;pu1_dst + dst_strd
b inner_loop_16
epilog_16
mov r7, #0x4000
ldr r0, [sp], #4
ldr r10, [sp, #120]
vdup.16 q10, r7
vhadd.s16 q11, q11, q10
vqrshrun.s16 d11, q11, #6
add r7, r6, #8
vld1.u8 {d20}, [r6]
vld1.u8 {d21}, [r7]
vrhadd.u8 d10, d10, d20
vrhadd.u8 d11, d11, d21
vst1.8 {q5}, [r6]! ;store the result pu1_dst
ldr r7, [sp], #4
cmp r10, #24
beq outer_loop8_residual
end_loops1
b end_func
outer_loop4_residual
sub r12, r0, #3 ;pu1_src - 3
mov r1, r7
add r1, #8
mov r10, #4
add r12, #8
mov r14, #16
add r8, #4
add r9, #4
outer_loop_4
add r6, r1, r3 ;pu1_dst + dst_strd
add r4, r12, r2 ;pu1_src + src_strd
subs r5, r10, #0 ;checks wd
ble end_inner_loop_4
inner_loop_4
vld1.u32 {d0}, [r12], r11 ;vector load pu1_src
vld1.u32 {d1}, [r12], r11
vld1.u32 {d2}, [r12], r11
vld1.u32 {d3}, [r12], r11
vld1.u32 {d4}, [r12], r11
vld1.u32 {d5}, [r12], r11
vld1.u32 {d6}, [r12], r11
vld1.u32 {d7}, [r12], r11
sub r12, r12, #4
vld1.u32 {d12}, [r4], r11 ;vector load pu1_src + src_strd
vld1.u32 {d13}, [r4], r11
vzip.32 d0, d12 ;vector zip the i iteration and ii
; interation in single register
vld1.u32 {d14}, [r4], r11
vzip.32 d1, d13
vld1.u32 {d15}, [r4], r11
vzip.32 d2, d14
vld1.u32 {d16}, [r4], r11
vzip.32 d3, d15
vld1.u32 {d17}, [r4], r11
vzip.32 d4, d16
vld1.u32 {d18}, [r4], r11
vzip.32 d5, d17
vld1.u32 {d19}, [r4], r11
mov r7, #0xc000
vdup.16 q4, r7
sub r4, r4, #4
vzip.32 d6, d18
vzip.32 d7, d19
vmlal.u8 q4, d1, d25 ;arithmetic operations for ii
; iteration in the same time
vmlsl.u8 q4, d0, d24
vmlsl.u8 q4, d2, d26
vmlal.u8 q4, d3, d27
vmlal.u8 q4, d4, d28
vmlsl.u8 q4, d5, d29
vmlal.u8 q4, d6, d30
vmlsl.u8 q4, d7, d31
mov r7, #0x4000
vdup.16 q10, r7
vhadd.s16 q4, q4, q10
vqrshrun.s16 d8, q4, #6
vld1.u32 {d10[0]}, [r1]
vld1.u32 {d10[1]}, [r6]
vrhadd.u8 d8, d8, d10
vst1.32 {d8[0]},[r1]! ;store the i iteration result which
; is in upper part of the register
vst1.32 {d8[1]},[r6]! ;store the ii iteration result which
; is in lower part of the register
subs r5, r5, #4 ;decrement the wd by 4
bgt inner_loop_4
end_inner_loop_4
subs r14, r14, #2 ;decrement the ht by 4
add r12, r12, r9 ;increment the input pointer
; 2*src_strd-wd
add r1, r1, r8 ;increment the output pointer
; 2*dst_strd-wd
bgt outer_loop_4
end_func
vpop {d8 - d15}
ldmfd sp!, {r4 - r12, r15} ;reload the registers from sp
ENDP
END
@@ -0,0 +1,486 @@
;
; Copyright (c) 2018 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
;**************Variables Vs Registers***********************************
; r0 => src
; r1 => dst
; r2 => src_stride
; r6 => dst_stride
; r12 => filter_y0
; r5 => ht
; r3 => wd
EXPORT |vpx_convolve8_avg_vert_filter_type1_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
|vpx_convolve8_avg_vert_filter_type1_neon| PROC
stmfd sp!, {r4 - r12, r14} ;stack stores the values of
; the arguments
vpush {d8 - d15} ; stack offset by 64
mov r4, r1
mov r1, r2
mov r2, r4
vmov.i16 q15, #0x4000
mov r11, #0xc000
ldr r12, [sp, #104] ;load filter
ldr r6, [sp, #116] ;load y0_q4
add r12, r12, r6, lsl #4 ;r12 = filter[y0_q4]
mov r6, r3
ldr r5, [sp, #124] ;load wd
vld2.8 {d0, d1}, [r12] ;coeff = vld1_s8(pi1_coeff)
sub r12, r2, r2, lsl #2 ;src_ctrd & pi1_coeff
vabs.s8 d0, d0 ;vabs_s8(coeff)
add r0, r0, r12 ;r0->pu1_src r12->pi1_coeff
ldr r3, [sp, #128] ;load ht
subs r7, r3, #0 ;r3->ht
vdup.u8 d22, d0[0] ;coeffabs_0 = vdup_lane_u8(coeffabs,
; 0);
cmp r5, #8
vdup.u8 d23, d0[1] ;coeffabs_1 = vdup_lane_u8(coeffabs,
; 1);
vdup.u8 d24, d0[2] ;coeffabs_2 = vdup_lane_u8(coeffabs,
; 2);
vdup.u8 d25, d0[3] ;coeffabs_3 = vdup_lane_u8(coeffabs,
; 3);
vdup.u8 d26, d0[4] ;coeffabs_4 = vdup_lane_u8(coeffabs,
; 4);
vdup.u8 d27, d0[5] ;coeffabs_5 = vdup_lane_u8(coeffabs,
; 5);
vdup.u8 d28, d0[6] ;coeffabs_6 = vdup_lane_u8(coeffabs,
; 6);
vdup.u8 d29, d0[7] ;coeffabs_7 = vdup_lane_u8(coeffabs,
; 7);
blt core_loop_wd_4 ;core loop wd 4 jump
str r0, [sp, #-4]!
str r1, [sp, #-4]!
bic r4, r5, #7 ;r5 ->wd
rsb r9, r4, r6, lsl #2 ;r6->dst_strd r5 ->wd
rsb r8, r4, r2, lsl #2 ;r2->src_strd
mov r3, r5, lsr #3 ;divide by 8
mul r7, r3 ;multiply height by width
sub r7, #4 ;subtract by one for epilog
prolog
and r10, r0, #31
add r3, r0, r2 ;pu1_src_tmp += src_strd;
vdup.16 q4, r11
vld1.u8 {d1}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vld1.u8 {d0}, [r0]! ;src_tmp1 = vld1_u8(pu1_src_tmp);
subs r4, r4, #8
vld1.u8 {d2}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d1, d23 ;mul_res1 = vmull_u8(src_tmp2,
; coeffabs_1);
vld1.u8 {d3}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d0, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp1, coeffabs_0);
vld1.u8 {d4}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d2, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp3, coeffabs_2);
vld1.u8 {d5}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d3, d25 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp4, coeffabs_3);
vld1.u8 {d6}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp1, coeffabs_4);
vld1.u8 {d7}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d5, d27 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp2, coeffabs_5);
vld1.u8 {d16}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp3, coeffabs_6);
vld1.u8 {d17}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d7, d29 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp4, coeffabs_7);
vdup.16 q5, r11
vld1.u8 {d18}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q5, d2, d23 ;mul_res2 = vmull_u8(src_tmp3,
; coeffabs_1);
addle r0, r0, r8
vmlsl.u8 q5, d1, d22 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp2, coeffabs_0);
bicle r4, r5, #7 ;r5 ->wd
vmlal.u8 q5, d3, d24 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp4, coeffabs_2);
pld [r3]
vmlal.u8 q5, d4, d25 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp1, coeffabs_3);
vhadd.s16 q4, q4, q15
vdup.16 q6, r11
pld [r3, r2]
pld [r3, r2, lsl #1]
vmlal.u8 q5, d5, d26 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp2, coeffabs_4);
add r3, r3, r2
vmlal.u8 q5, d6, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp3, coeffabs_5);
pld [r3, r2, lsl #1]
vmlsl.u8 q5, d7, d28 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp4, coeffabs_6);
add r3, r0, r2 ;pu1_src_tmp += src_strd;
vmlsl.u8 q5, d16, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp1, coeffabs_7);
vld1.u8 {d20}, [r1]
vqrshrun.s16 d8, q4, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u8 {d1}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q6, d3, d23
vld1.u8 {d0}, [r0]! ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q6, d2, d22
vrhadd.u8 d8, d8, d20
vld1.u8 {d2}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q6, d4, d24
vhadd.s16 q5, q5, q15
vdup.16 q7, r11
vmlal.u8 q6, d5, d25
vmlal.u8 q6, d6, d26
add r14, r1, r6
vmlal.u8 q6, d7, d27
vmlsl.u8 q6, d16, d28
vst1.8 {d8}, [r1]! ;vst1_u8(pu1_dst,sto_res);
vmlsl.u8 q6, d17, d29
vld1.u8 {d20}, [r14]
vqrshrun.s16 d10, q5, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
addle r1, r1, r9
vmlsl.u8 q7, d4, d23
subs r7, r7, #4
vmlsl.u8 q7, d3, d22
vmlal.u8 q7, d5, d24
vld1.u8 {d3}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vmlal.u8 q7, d6, d25
vrhadd.u8 d10, d10, d20
vhadd.s16 q6, q6, q15
vdup.16 q4, r11
vmlal.u8 q7, d7, d26
vld1.u8 {d4}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q7, d16, d27
vld1.u8 {d5}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d17, d28
vld1.u8 {d6}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d18, d29
vld1.u8 {d7}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vst1.8 {d10}, [r14], r6 ;vst1_u8(pu1_dst_tmp,sto_res);
vqrshrun.s16 d12, q6, #6
blt epilog_end ;jumps to epilog_end
beq epilog ;jumps to epilog
main_loop_8
subs r4, r4, #8
vmlsl.u8 q4, d1, d23 ;mul_res1 = vmull_u8(src_tmp2,
; coeffabs_1);
vld1.u8 {d20}, [r14]
vmlsl.u8 q4, d0, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp1, coeffabs_0);
addle r0, r0, r8
bicle r4, r5, #7 ;r5 ->wd
vmlal.u8 q4, d2, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp3, coeffabs_2);
vld1.u8 {d16}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d3, d25 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp4, coeffabs_3);
vrhadd.u8 d12, d12, d20
vhadd.s16 q7, q7, q15
vdup.16 q5, r11
vld1.u8 {d17}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp1, coeffabs_4);
vld1.u8 {d18}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d5, d27 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp2, coeffabs_5);
vmlsl.u8 q4, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp3, coeffabs_6);
vmlsl.u8 q4, d7, d29 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp4, coeffabs_7);
vst1.8 {d12}, [r14], r6
vld1.u8 {d20}, [r14]
vqrshrun.s16 d14, q7, #6
add r3, r0, r2 ;pu1_src_tmp += src_strd;
vmlsl.u8 q5, d2, d23 ;mul_res2 = vmull_u8(src_tmp3,
; coeffabs_1);
vld1.u8 {d0}, [r0]! ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q5, d1, d22 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp2, coeffabs_0);
vrhadd.u8 d14, d14, d20
vmlal.u8 q5, d3, d24 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp4, coeffabs_2);
vld1.u8 {d1}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q5, d4, d25 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp1, coeffabs_3);
vhadd.s16 q4, q4, q15
vdup.16 q6, r11
vst1.8 {d14}, [r14], r6
vmlal.u8 q5, d5, d26 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp2, coeffabs_4);
add r14, r1, #0
vmlal.u8 q5, d6, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp3, coeffabs_5);
add r1, r1, #8
vmlsl.u8 q5, d7, d28 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp4, coeffabs_6);
addle r1, r1, r9
vmlsl.u8 q5, d16, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp1, coeffabs_7);
vld1.u8 {d20}, [r14]
vqrshrun.s16 d8, q4, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vmlsl.u8 q6, d3, d23
add r10, r3, r2, lsl #3 ; 10*strd - 8+2
vmlsl.u8 q6, d2, d22
vrhadd.u8 d8, d8, d20
add r10, r10, r2 ; 11*strd
vmlal.u8 q6, d4, d24
vld1.u8 {d2}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q6, d5, d25
vhadd.s16 q5, q5, q15
vdup.16 q7, r11
vmlal.u8 q6, d6, d26
vst1.8 {d8}, [r14], r6 ;vst1_u8(pu1_dst,sto_res);
pld [r10] ;11+ 0
vmlal.u8 q6, d7, d27
pld [r10, r2] ;11+ 1*strd
pld [r10, r2, lsl #1] ;11+ 2*strd
vmlsl.u8 q6, d16, d28
add r10, r10, r2 ;12*strd
vmlsl.u8 q6, d17, d29
vld1.u8 {d20}, [r14]
vqrshrun.s16 d10, q5, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
pld [r10, r2, lsl #1] ;11+ 3*strd
vmlsl.u8 q7, d4, d23
vmlsl.u8 q7, d3, d22
vrhadd.u8 d10, d10, d20
subs r7, r7, #4
vmlal.u8 q7, d5, d24
vmlal.u8 q7, d6, d25
vld1.u8 {d3}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vhadd.s16 q6, q6, q15
vdup.16 q4, r11
vmlal.u8 q7, d7, d26
vld1.u8 {d4}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q7, d16, d27
vld1.u8 {d5}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d17, d28
vld1.u8 {d6}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d18, d29
vld1.u8 {d7}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vqrshrun.s16 d12, q6, #6
vst1.8 {d10}, [r14], r6 ;vst1_u8(pu1_dst_tmp,sto_res);
bgt main_loop_8 ;jumps to main_loop_8
epilog
vld1.u8 {d20}, [r14]
vmlsl.u8 q4, d1, d23 ;mul_res1 = vmull_u8(src_tmp2,
; coeffabs_1);
vmlsl.u8 q4, d0, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp1, coeffabs_0);
vmlal.u8 q4, d2, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp3, coeffabs_2);
vrhadd.u8 d12, d12, d20
vmlal.u8 q4, d3, d25 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp4, coeffabs_3);
vhadd.s16 q7, q7, q15
vdup.16 q5, r11
vmlal.u8 q4, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp1, coeffabs_4);
vmlal.u8 q4, d5, d27 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp2, coeffabs_5);
vmlsl.u8 q4, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp3, coeffabs_6);
vst1.8 {d12}, [r14], r6
vmlsl.u8 q4, d7, d29 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp4, coeffabs_7);
vld1.u8 {d20}, [r14]
vqrshrun.s16 d14, q7, #6
vld1.u8 {d16}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q5, d2, d23 ;mul_res2 = vmull_u8(src_tmp3,
; coeffabs_1);
vmlsl.u8 q5, d1, d22 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp2, coeffabs_0);
vrhadd.u8 d14, d14, d20
vmlal.u8 q5, d3, d24 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp4, coeffabs_2);
vmlal.u8 q5, d4, d25 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp1, coeffabs_3);
vhadd.s16 q4, q4, q15
vdup.16 q6, r11
vmlal.u8 q5, d5, d26 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp2, coeffabs_4);
vmlal.u8 q5, d6, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp3, coeffabs_5);
vmlsl.u8 q5, d7, d28 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp4, coeffabs_6);
vst1.8 {d14}, [r14], r6
vmlsl.u8 q5, d16, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp1, coeffabs_7);
vld1.u8 {d20}, [r1]
vqrshrun.s16 d8, q4, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u8 {d17}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q6, d3, d23
vmlsl.u8 q6, d2, d22
vrhadd.u8 d8, d8, d20
vmlal.u8 q6, d4, d24
vmlal.u8 q6, d5, d25
vhadd.s16 q5, q5, q15
vdup.16 q7, r11
vmlal.u8 q6, d6, d26
vmlal.u8 q6, d7, d27
add r14, r1, r6
vmlsl.u8 q6, d16, d28
vst1.8 {d8}, [r1]! ;vst1_u8(pu1_dst,sto_res);
vmlsl.u8 q6, d17, d29
vld1.u8 {d20}, [r14]
vqrshrun.s16 d10, q5, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u8 {d18}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d4, d23
vmlsl.u8 q7, d3, d22
vrhadd.u8 d10, d10, d20
vmlal.u8 q7, d5, d24
vmlal.u8 q7, d6, d25
vhadd.s16 q6, q6, q15
vmlal.u8 q7, d7, d26
vmlal.u8 q7, d16, d27
vmlsl.u8 q7, d17, d28
vmlsl.u8 q7, d18, d29
vst1.8 {d10}, [r14], r6 ;vst1_u8(pu1_dst_tmp,sto_res);
vqrshrun.s16 d12, q6, #6
epilog_end
vld1.u8 {d20}, [r14]
vrhadd.u8 d12, d12, d20
vst1.8 {d12}, [r14], r6
vhadd.s16 q7, q7, q15
vqrshrun.s16 d14, q7, #6
vld1.u8 {d20}, [r14]
vrhadd.u8 d14, d14, d20
vst1.8 {d14}, [r14], r6
end_loops
tst r5, #7
ldr r1, [sp], #4
ldr r0, [sp], #4
vpopeq {d8 - d15}
ldmfdeq sp!, {r4 - r12, r15} ;reload the registers from sp
mov r5, #4
add r0, r0, #8
add r1, r1, #8
mov r7, #16
core_loop_wd_4
rsb r9, r5, r6, lsl #2 ;r6->dst_strd r5 ->wd
rsb r8, r5, r2, lsl #2 ;r2->src_strd
vmov.i8 d4, #0
outer_loop_wd_4
subs r12, r5, #0
ble end_inner_loop_wd_4 ;outer loop jump
inner_loop_wd_4
add r3, r0, r2
vld1.u32 {d4[1]},[r3], r2 ;src_tmp1 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp1, 1);
subs r12, r12, #4
vdup.u32 d5, d4[1] ;src_tmp2 = vdup_lane_u32(src_tmp1,
; 1);
vld1.u32 {d5[1]},[r3], r2 ;src_tmp2 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp2, 1);
vld1.u32 {d4[0]},[r0] ;src_tmp1 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp1, 0);
vdup.16 q0, r11
vmlsl.u8 q0, d5, d23 ;mul_res1 =
; vmull_u8(vreinterpret_u8_u32(src_tmp2), coeffabs_1);
vdup.u32 d6, d5[1] ;src_tmp3 = vdup_lane_u32(src_tmp2,
; 1);
add r0, r0, #4
vld1.u32 {d6[1]},[r3], r2 ;src_tmp3 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp3, 1);
vmlsl.u8 q0, d4, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp1), coeffabs_0);
vdup.u32 d7, d6[1] ;src_tmp4 = vdup_lane_u32(src_tmp3,
; 1);
vld1.u32 {d7[1]},[r3], r2 ;src_tmp4 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp4, 1);
vmlal.u8 q0, d6, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp3), coeffabs_2);
vdup.16 q4, r11
vmlsl.u8 q4, d7, d23
vdup.u32 d4, d7[1] ;src_tmp1 = vdup_lane_u32(src_tmp4,
; 1);
vmull.u8 q1, d7, d25 ;mul_res2 =
; vmull_u8(vreinterpret_u8_u32(src_tmp4), coeffabs_3);
vld1.u32 {d4[1]},[r3], r2 ;src_tmp1 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp1, 1);
vmlsl.u8 q4, d6, d22
vmlal.u8 q0, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp1), coeffabs_4);
vdup.u32 d5, d4[1] ;src_tmp2 = vdup_lane_u32(src_tmp1,
; 1);
vmlal.u8 q4, d4, d24
vld1.u32 {d5[1]},[r3], r2 ;src_tmp2 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp2, 1);
vmlal.u8 q1, d5, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; vreinterpret_u8_u32(src_tmp2), coeffabs_5);
vdup.u32 d6, d5[1] ;src_tmp3 = vdup_lane_u32(src_tmp2,
; 1);
vmlal.u8 q4, d5, d25
vld1.u32 {d6[1]},[r3], r2 ;src_tmp3 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp3, 1);
vmlsl.u8 q0, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp3), coeffabs_6);
vdup.u32 d7, d6[1] ;src_tmp4 = vdup_lane_u32(src_tmp3,
; 1);
vmlal.u8 q4, d6, d26
vld1.u32 {d7[1]},[r3], r2 ;src_tmp4 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp4, 1);
vmlsl.u8 q1, d7, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; vreinterpret_u8_u32(src_tmp4), coeffabs_7);
vdup.u32 d4, d7[1]
vadd.i16 q0, q0, q1 ;mul_res1 = vaddq_u16(mul_res1,
; mul_res2);
vmlal.u8 q4, d7, d27
vld1.u32 {d4[1]},[r3], r2
vmlsl.u8 q4, d4, d28
vdup.u32 d5, d4[1]
vhadd.s16 q0, q0, q15
vqrshrun.s16 d0, q0, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u32 {d5[1]},[r3]
add r3, r1, r6
vld1.u32 {d20[0]}, [r1]
vld1.u32 {d20[1]}, [r3]
vrhadd.u8 d0, d0, d20
vst1.32 {d0[0]},[r1] ;vst1_lane_u32((uint32_t *)pu1_dst,
; vreinterpret_u32_u8(sto_res), 0);
vmlsl.u8 q4, d5, d29
vst1.32 {d0[1]},[r3], r6 ;vst1_lane_u32((uint32_t
; *)pu1_dst_tmp, vreinterpret_u32_u8(sto_res), 1);
vhadd.s16 q4, q4, q15
vqrshrun.s16 d8, q4, #6
mov r4, r3
vld1.u32 {d20[0]}, [r4], r6
vld1.u32 {d20[1]}, [r4]
vrhadd.u8 d8, d8, d20
vst1.32 {d8[0]},[r3], r6
add r1, r1, #4
vst1.32 {d8[1]},[r3]
bgt inner_loop_wd_4
end_inner_loop_wd_4
subs r7, r7, #4
add r1, r1, r9
add r0, r0, r8
bgt outer_loop_wd_4
vpop {d8 - d15}
ldmfd sp!, {r4 - r12, r15} ;reload the registers from sp
ENDP
END
@@ -0,0 +1,487 @@
;
; Copyright (c) 2018 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
;**************Variables Vs Registers***********************************
; r0 => src
; r1 => dst
; r2 => src_stride
; r6 => dst_stride
; r12 => filter_y0
; r5 => ht
; r3 => wd
EXPORT |vpx_convolve8_avg_vert_filter_type2_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
|vpx_convolve8_avg_vert_filter_type2_neon| PROC
stmfd sp!, {r4 - r12, r14} ;stack stores the values of
; the arguments
vpush {d8 - d15} ; stack offset by 64
mov r4, r1
mov r1, r2
mov r2, r4
vmov.i16 q15, #0x4000
mov r11, #0xc000
ldr r12, [sp, #104] ;load filter
ldr r6, [sp, #116] ;load y0_q4
add r12, r12, r6, lsl #4 ;r12 = filter[y0_q4]
mov r6, r3
ldr r5, [sp, #124] ;load wd
vld2.8 {d0, d1}, [r12] ;coeff = vld1_s8(pi1_coeff)
sub r12, r2, r2, lsl #2 ;src_ctrd & pi1_coeff
vabs.s8 d0, d0 ;vabs_s8(coeff)
add r0, r0, r12 ;r0->pu1_src r12->pi1_coeff
ldr r3, [sp, #128] ;load ht
subs r7, r3, #0 ;r3->ht
vdup.u8 d22, d0[0] ;coeffabs_0 = vdup_lane_u8(coeffabs,
; 0);
cmp r5, #8
vdup.u8 d23, d0[1] ;coeffabs_1 = vdup_lane_u8(coeffabs,
; 1);
vdup.u8 d24, d0[2] ;coeffabs_2 = vdup_lane_u8(coeffabs,
; 2);
vdup.u8 d25, d0[3] ;coeffabs_3 = vdup_lane_u8(coeffabs,
; 3);
vdup.u8 d26, d0[4] ;coeffabs_4 = vdup_lane_u8(coeffabs,
; 4);
vdup.u8 d27, d0[5] ;coeffabs_5 = vdup_lane_u8(coeffabs,
; 5);
vdup.u8 d28, d0[6] ;coeffabs_6 = vdup_lane_u8(coeffabs,
; 6);
vdup.u8 d29, d0[7] ;coeffabs_7 = vdup_lane_u8(coeffabs,
; 7);
blt core_loop_wd_4 ;core loop wd 4 jump
str r0, [sp, #-4]!
str r1, [sp, #-4]!
bic r4, r5, #7 ;r5 ->wd
rsb r9, r4, r6, lsl #2 ;r6->dst_strd r5 ->wd
rsb r8, r4, r2, lsl #2 ;r2->src_strd
mov r3, r5, lsr #3 ;divide by 8
mul r7, r3 ;multiply height by width
sub r7, #4 ;subtract by one for epilog
prolog
and r10, r0, #31
add r3, r0, r2 ;pu1_src_tmp += src_strd;
vdup.16 q4, r11
vld1.u8 {d1}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vld1.u8 {d0}, [r0]! ;src_tmp1 = vld1_u8(pu1_src_tmp);
subs r4, r4, #8
vld1.u8 {d2}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d1, d23 ;mul_res1 = vmull_u8(src_tmp2,
; coeffabs_1);
vld1.u8 {d3}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d0, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp1, coeffabs_0);
vld1.u8 {d4}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d2, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp3, coeffabs_2);
vld1.u8 {d5}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d3, d25 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp4, coeffabs_3);
vld1.u8 {d6}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp1, coeffabs_4);
vld1.u8 {d7}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d5, d27 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp2, coeffabs_5);
vld1.u8 {d16}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp3, coeffabs_6);
vld1.u8 {d17}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d7, d29 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp4, coeffabs_7);
vdup.16 q5, r11
vld1.u8 {d18}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q5, d2, d23 ;mul_res2 = vmull_u8(src_tmp3,
; coeffabs_1);
addle r0, r0, r8
vmlsl.u8 q5, d1, d22 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp2, coeffabs_0);
bicle r4, r5, #7 ;r5 ->wd
vmlsl.u8 q5, d3, d24 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp4, coeffabs_2);
pld [r3]
vmlal.u8 q5, d4, d25 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp1, coeffabs_3);
vhadd.s16 q4, q4, q15
vdup.16 q6, r11
pld [r3, r2]
pld [r3, r2, lsl #1]
vmlal.u8 q5, d5, d26 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp2, coeffabs_4);
add r3, r3, r2
vmlsl.u8 q5, d6, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp3, coeffabs_5);
pld [r3, r2, lsl #1]
vmlal.u8 q5, d7, d28 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp4, coeffabs_6);
add r3, r0, r2 ;pu1_src_tmp += src_strd;
vmlsl.u8 q5, d16, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp1, coeffabs_7);
vld1.u8 {d20}, [r1]
vqrshrun.s16 d8, q4, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u8 {d1}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q6, d3, d23
vld1.u8 {d0}, [r0]! ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q6, d2, d22
vrhadd.u8 d8, d8, d20
vld1.u8 {d2}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q6, d4, d24
vhadd.s16 q5, q5, q15
vdup.16 q7, r11
vmlal.u8 q6, d5, d25
vmlal.u8 q6, d6, d26
add r14, r1, r6
vmlsl.u8 q6, d7, d27
vmlal.u8 q6, d16, d28
vst1.8 {d8}, [r1]! ;vst1_u8(pu1_dst,sto_res);
vmlsl.u8 q6, d17, d29
vld1.u8 {d20}, [r14]
vqrshrun.s16 d10, q5, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
addle r1, r1, r9
vmlal.u8 q7, d4, d23
subs r7, r7, #4
vmlsl.u8 q7, d3, d22
vmlsl.u8 q7, d5, d24
vld1.u8 {d3}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vmlal.u8 q7, d6, d25
vrhadd.u8 d10, d10, d20
vhadd.s16 q6, q6, q15
vdup.16 q4, r11
vmlal.u8 q7, d7, d26
vld1.u8 {d4}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d16, d27
vld1.u8 {d5}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q7, d17, d28
vld1.u8 {d6}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d18, d29
vld1.u8 {d7}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vst1.8 {d10}, [r14], r6 ;vst1_u8(pu1_dst_tmp,sto_res);
vqrshrun.s16 d12, q6, #6
blt epilog_end ;jumps to epilog_end
beq epilog ;jumps to epilog
main_loop_8
subs r4, r4, #8
vmlal.u8 q4, d1, d23 ;mul_res1 = vmull_u8(src_tmp2,
; coeffabs_1);
vld1.u8 {d20}, [r14]
vmlsl.u8 q4, d0, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp1, coeffabs_0);
addle r0, r0, r8
bicle r4, r5, #7 ;r5 ->wd
vmlsl.u8 q4, d2, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp3, coeffabs_2);
vld1.u8 {d16}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d3, d25 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp4, coeffabs_3);
vrhadd.u8 d12, d12, d20
vhadd.s16 q7, q7, q15
vdup.16 q5, r11
vld1.u8 {d17}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp1, coeffabs_4);
vld1.u8 {d18}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d5, d27 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp2, coeffabs_5);
vmlal.u8 q4, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp3, coeffabs_6);
vmlsl.u8 q4, d7, d29 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp4, coeffabs_7);
vst1.8 {d12}, [r14], r6
vld1.u8 {d20}, [r14]
vqrshrun.s16 d14, q7, #6
add r3, r0, r2 ;pu1_src_tmp += src_strd;
vmlal.u8 q5, d2, d23 ;mul_res2 = vmull_u8(src_tmp3,
; coeffabs_1);
vld1.u8 {d0}, [r0]! ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q5, d1, d22 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp2, coeffabs_0);
vrhadd.u8 d14, d14, d20
vmlsl.u8 q5, d3, d24 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp4, coeffabs_2);
vld1.u8 {d1}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q5, d4, d25 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp1, coeffabs_3);
vhadd.s16 q4, q4, q15
vdup.16 q6, r11
vst1.8 {d14}, [r14], r6
vmlal.u8 q5, d5, d26 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp2, coeffabs_4);
add r14, r1, #0
vmlsl.u8 q5, d6, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp3, coeffabs_5);
add r1, r1, #8
vmlal.u8 q5, d7, d28 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp4, coeffabs_6);
addle r1, r1, r9
vmlsl.u8 q5, d16, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp1, coeffabs_7);
vld1.u8 {d20}, [r14]
vqrshrun.s16 d8, q4, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vmlal.u8 q6, d3, d23
add r10, r3, r2, lsl #3 ; 10*strd - 8+2
vmlsl.u8 q6, d2, d22
vrhadd.u8 d8, d8, d20
add r10, r10, r2 ; 11*strd
vmlsl.u8 q6, d4, d24
vld1.u8 {d2}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q6, d5, d25
vhadd.s16 q5, q5, q15
vdup.16 q7, r11
vmlal.u8 q6, d6, d26
vst1.8 {d8}, [r14], r6 ;vst1_u8(pu1_dst,sto_res);
pld [r10] ;11+ 0
vmlsl.u8 q6, d7, d27
pld [r10, r2] ;11+ 1*strd
pld [r10, r2, lsl #1] ;11+ 2*strd
vmlal.u8 q6, d16, d28
add r10, r10, r2 ;12*strd
vmlsl.u8 q6, d17, d29
vld1.u8 {d20}, [r14]
vqrshrun.s16 d10, q5, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
pld [r10, r2, lsl #1] ;11+ 3*strd
vmlal.u8 q7, d4, d23
vmlsl.u8 q7, d3, d22
vrhadd.u8 d10, d10, d20
subs r7, r7, #4
vmlsl.u8 q7, d5, d24
vmlal.u8 q7, d6, d25
vld1.u8 {d3}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vhadd.s16 q6, q6, q15
vdup.16 q4, r11
vmlal.u8 q7, d7, d26
vld1.u8 {d4}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d16, d27
vld1.u8 {d5}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q7, d17, d28
vld1.u8 {d6}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d18, d29
vld1.u8 {d7}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vqrshrun.s16 d12, q6, #6
vst1.8 {d10}, [r14], r6 ;vst1_u8(pu1_dst_tmp,sto_res);
bgt main_loop_8 ;jumps to main_loop_8
epilog
vld1.u8 {d20}, [r14]
vmlal.u8 q4, d1, d23 ;mul_res1 = vmull_u8(src_tmp2,
; coeffabs_1);
vmlsl.u8 q4, d0, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp1, coeffabs_0);
vmlsl.u8 q4, d2, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp3, coeffabs_2);
vrhadd.u8 d12, d12, d20
vmlal.u8 q4, d3, d25 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp4, coeffabs_3);
vhadd.s16 q7, q7, q15
vdup.16 q5, r11
vmlal.u8 q4, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp1, coeffabs_4);
vmlsl.u8 q4, d5, d27 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp2, coeffabs_5);
vmlal.u8 q4, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp3, coeffabs_6);
vst1.8 {d12}, [r14], r6
vmlsl.u8 q4, d7, d29 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp4, coeffabs_7);
vld1.u8 {d20}, [r14]
vqrshrun.s16 d14, q7, #6
vld1.u8 {d16}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q5, d2, d23 ;mul_res2 = vmull_u8(src_tmp3,
; coeffabs_1);
vmlsl.u8 q5, d1, d22 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp2, coeffabs_0);
vrhadd.u8 d14, d14, d20
vmlsl.u8 q5, d3, d24 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp4, coeffabs_2);
vmlal.u8 q5, d4, d25 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp1, coeffabs_3);
vhadd.s16 q4, q4, q15
vdup.16 q6, r11
vmlal.u8 q5, d5, d26 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp2, coeffabs_4);
vmlsl.u8 q5, d6, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp3, coeffabs_5);
vmlal.u8 q5, d7, d28 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp4, coeffabs_6);
vst1.8 {d14}, [r14], r6
vmlsl.u8 q5, d16, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp1, coeffabs_7);
vld1.u8 {d20}, [r1]
vqrshrun.s16 d8, q4, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u8 {d17}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q6, d3, d23
vmlsl.u8 q6, d2, d22
vrhadd.u8 d8, d8, d20
vmlsl.u8 q6, d4, d24
vmlal.u8 q6, d5, d25
vhadd.s16 q5, q5, q15
vdup.16 q7, r11
vmlal.u8 q6, d6, d26
vmlsl.u8 q6, d7, d27
add r14, r1, r6
vmlal.u8 q6, d16, d28
vst1.8 {d8}, [r1]! ;vst1_u8(pu1_dst,sto_res);
vmlsl.u8 q6, d17, d29
vld1.u8 {d20}, [r14]
vqrshrun.s16 d10, q5, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u8 {d18}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q7, d4, d23
vmlsl.u8 q7, d3, d22
vrhadd.u8 d10, d10, d20
vmlsl.u8 q7, d5, d24
vmlal.u8 q7, d6, d25
vhadd.s16 q6, q6, q15
vmlal.u8 q7, d7, d26
vmlsl.u8 q7, d16, d27
vmlal.u8 q7, d17, d28
vmlsl.u8 q7, d18, d29
vst1.8 {d10}, [r14], r6 ;vst1_u8(pu1_dst_tmp,sto_res);
vqrshrun.s16 d12, q6, #6
epilog_end
vld1.u8 {d20}, [r14]
vrhadd.u8 d12, d12, d20
vst1.8 {d12}, [r14], r6
vhadd.s16 q7, q7, q15
vqrshrun.s16 d14, q7, #6
vld1.u8 {d20}, [r14]
vrhadd.u8 d14, d14, d20
vst1.8 {d14}, [r14], r6
end_loops
tst r5, #7
ldr r1, [sp], #4
ldr r0, [sp], #4
vpopeq {d8 - d15}
ldmfdeq sp!, {r4 - r12, r15} ;reload the registers from sp
mov r5, #4
add r0, r0, #8
add r1, r1, #8
mov r7, #16
core_loop_wd_4
rsb r9, r5, r6, lsl #2 ;r6->dst_strd r5 ->wd
rsb r8, r5, r2, lsl #2 ;r2->src_strd
vmov.i8 d4, #0
outer_loop_wd_4
subs r12, r5, #0
ble end_inner_loop_wd_4 ;outer loop jump
inner_loop_wd_4
add r3, r0, r2
vld1.u32 {d4[1]},[r3], r2 ;src_tmp1 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp1, 1);
subs r12, r12, #4
vdup.u32 d5, d4[1] ;src_tmp2 = vdup_lane_u32(src_tmp1,
; 1);
vld1.u32 {d5[1]},[r3], r2 ;src_tmp2 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp2, 1);
vld1.u32 {d4[0]},[r0] ;src_tmp1 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp1, 0);
vdup.16 q0, r11
vmlal.u8 q0, d5, d23 ;mul_res1 =
; vmull_u8(vreinterpret_u8_u32(src_tmp2), coeffabs_1);
vdup.u32 d6, d5[1] ;src_tmp3 = vdup_lane_u32(src_tmp2,
; 1);
add r0, r0, #4
vld1.u32 {d6[1]},[r3], r2 ;src_tmp3 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp3, 1);
vmlsl.u8 q0, d4, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp1), coeffabs_0);
vdup.u32 d7, d6[1] ;src_tmp4 = vdup_lane_u32(src_tmp3,
; 1);
vld1.u32 {d7[1]},[r3], r2 ;src_tmp4 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp4, 1);
vmlsl.u8 q0, d6, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp3), coeffabs_2);
vdup.16 q4, r11
vmlal.u8 q4, d7, d23
vdup.u32 d4, d7[1] ;src_tmp1 = vdup_lane_u32(src_tmp4,
; 1);
vmull.u8 q1, d7, d25 ;mul_res2 =
; vmull_u8(vreinterpret_u8_u32(src_tmp4), coeffabs_3);
vld1.u32 {d4[1]},[r3], r2 ;src_tmp1 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp1, 1);
vmlsl.u8 q4, d6, d22
vmlal.u8 q0, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp1), coeffabs_4);
vdup.u32 d5, d4[1] ;src_tmp2 = vdup_lane_u32(src_tmp1,
; 1);
vmlsl.u8 q4, d4, d24
vld1.u32 {d5[1]},[r3], r2 ;src_tmp2 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp2, 1);
vmlsl.u8 q1, d5, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; vreinterpret_u8_u32(src_tmp2), coeffabs_5);
vdup.u32 d6, d5[1] ;src_tmp3 = vdup_lane_u32(src_tmp2,
; 1);
vmlal.u8 q4, d5, d25
vld1.u32 {d6[1]},[r3], r2 ;src_tmp3 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp3, 1);
vmlal.u8 q0, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp3), coeffabs_6);
vdup.u32 d7, d6[1] ;src_tmp4 = vdup_lane_u32(src_tmp3,
; 1);
vmlal.u8 q4, d6, d26
vld1.u32 {d7[1]},[r3], r2 ;src_tmp4 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp4, 1);
vmlsl.u8 q1, d7, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; vreinterpret_u8_u32(src_tmp4), coeffabs_7);
vdup.u32 d4, d7[1]
vadd.i16 q0, q0, q1 ;mul_res1 = vaddq_u16(mul_res1,
; mul_res2);
vmlsl.u8 q4, d7, d27
vld1.u32 {d4[1]},[r3], r2
vmlal.u8 q4, d4, d28
vdup.u32 d5, d4[1]
vhadd.s16 q0, q0, q15
vqrshrun.s16 d0, q0, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u32 {d5[1]},[r3]
add r3, r1, r6
vld1.u32 {d20[0]}, [r1]
vld1.u32 {d20[1]}, [r3]
vrhadd.u8 d0, d0, d20
vst1.32 {d0[0]},[r1] ;vst1_lane_u32((uint32_t *)pu1_dst,
; vreinterpret_u32_u8(sto_res), 0);
vmlsl.u8 q4, d5, d29
vst1.32 {d0[1]},[r3], r6 ;vst1_lane_u32((uint32_t
; *)pu1_dst_tmp, vreinterpret_u32_u8(sto_res), 1);
vhadd.s16 q4, q4, q15
vqrshrun.s16 d8, q4, #6
mov r4, r3
vld1.u32 {d20[0]}, [r4], r6
vld1.u32 {d20[1]}, [r4]
vrhadd.u8 d8, d8, d20
vst1.32 {d8[0]},[r3], r6
add r1, r1, #4
vst1.32 {d8[1]},[r3]
bgt inner_loop_wd_4
end_inner_loop_wd_4
subs r7, r7, #4
add r1, r1, r9
add r0, r0, r8
bgt outer_loop_wd_4
vpop {d8 - d15}
ldmfd sp!, {r4 - r12, r15} ;reload the registers from sp
ENDP
END
@@ -0,0 +1,415 @@
;
; Copyright (c) 2018 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
;**************Variables Vs Registers***********************************
; r0 => src
; r1 => dst
; r2 => src_stride
; r3 => dst_stride
; r4 => filter_x0
; r8 => ht
; r10 => wd
EXPORT |vpx_convolve8_horiz_filter_type1_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
|vpx_convolve8_horiz_filter_type1_neon| PROC
stmfd sp!, {r4 - r12, r14} ;stack stores the values of
; the arguments
vpush {d8 - d15} ; stack offset by 64
mov r4, r1
mov r1, r2
mov r2, r4
start_loop_count
ldr r4, [sp, #104] ;loads pi1_coeff
ldr r8, [sp, #108] ;loads x0_q4
add r4, r4, r8, lsl #4 ;r4 = filter[x0_q4]
ldr r8, [sp, #128] ;loads ht
ldr r10, [sp, #124] ;loads wd
vld2.8 {d0, d1}, [r4] ;coeff = vld1_s8(pi1_coeff)
mov r11, #1
subs r14, r8, #0 ;checks for ht == 0
vabs.s8 d2, d0 ;vabs_s8(coeff)
vdup.8 d24, d2[0] ;coeffabs_0 = vdup_lane_u8(coeffabs,
; 0)
sub r12, r0, #3 ;pu1_src - 3
vdup.8 d25, d2[1] ;coeffabs_1 = vdup_lane_u8(coeffabs,
; 1)
add r4, r12, r2 ;pu1_src_tmp2_8 = pu1_src + src_strd
vdup.8 d26, d2[2] ;coeffabs_2 = vdup_lane_u8(coeffabs,
; 2)
rsb r9, r10, r2, lsl #1 ;2*src_strd - wd
vdup.8 d27, d2[3] ;coeffabs_3 = vdup_lane_u8(coeffabs,
; 3)
rsb r8, r10, r3, lsl #1 ;2*dst_strd - wd
vdup.8 d28, d2[4] ;coeffabs_4 = vdup_lane_u8(coeffabs,
; 4)
vdup.8 d29, d2[5] ;coeffabs_5 = vdup_lane_u8(coeffabs,
; 5)
vdup.8 d30, d2[6] ;coeffabs_6 = vdup_lane_u8(coeffabs,
; 6)
vdup.8 d31, d2[7] ;coeffabs_7 = vdup_lane_u8(coeffabs,
; 7)
mov r7, r1
cmp r10, #4
ble outer_loop_4
cmp r10, #24
moveq r10, #16
addeq r8, #8
addeq r9, #8
cmp r10, #16
bge outer_loop_16
cmp r10, #12
addeq r8, #4
addeq r9, #4
b outer_loop_8
outer_loop8_residual
sub r12, r0, #3 ;pu1_src - 3
mov r1, r7
mov r14, #32
add r1, #16
add r12, #16
mov r10, #8
add r8, #8
add r9, #8
outer_loop_8
add r6, r1, r3 ;pu1_dst + dst_strd
add r4, r12, r2 ;pu1_src + src_strd
subs r5, r10, #0 ;checks wd
ble end_inner_loop_8
inner_loop_8
mov r7, #0xc000
vld1.u32 {d0}, [r12], r11 ;vector load pu1_src
vdup.16 q4, r7
vld1.u32 {d1}, [r12], r11
vdup.16 q5, r7
vld1.u32 {d2}, [r12], r11
vld1.u32 {d3}, [r12], r11
mov r7, #0x4000
vld1.u32 {d4}, [r12], r11
vmlsl.u8 q4, d1, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {d5}, [r12], r11
vmlal.u8 q4, d3, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {d6}, [r12], r11
vmlsl.u8 q4, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vld1.u32 {d7}, [r12], r11
vmlal.u8 q4, d2, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u32 {d12}, [r4], r11 ;vector load pu1_src + src_strd
vmlal.u8 q4, d4, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vld1.u32 {d13}, [r4], r11
vmlal.u8 q4, d5, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vld1.u32 {d14}, [r4], r11
vmlsl.u8 q4, d6, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vld1.u32 {d15}, [r4], r11
vmlsl.u8 q4, d7, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
vld1.u32 {d16}, [r4], r11 ;vector load pu1_src + src_strd
vdup.16 q11, r7
vmlal.u8 q5, d15, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {d17}, [r4], r11
vmlal.u8 q5, d14, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vhadd.s16 q4, q4, q11
vld1.u32 {d18}, [r4], r11
vmlal.u8 q5, d16, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vld1.u32 {d19}, [r4], r11 ;vector load pu1_src + src_strd
vmlal.u8 q5, d17, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vmlsl.u8 q5, d18, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q5, d19, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
vqrshrun.s16 d20, q4, #6 ;right shift and saturating narrow
; result 1
vmlsl.u8 q5, d12, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vmlsl.u8 q5, d13, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vst1.8 {d20}, [r1]! ;store the result pu1_dst
vhadd.s16 q5, q5, q11
subs r5, r5, #8 ;decrement the wd loop
vqrshrun.s16 d8, q5, #6 ;right shift and saturating narrow
; result 2
vst1.8 {d8}, [r6]! ;store the result pu1_dst
cmp r5, #4
bgt inner_loop_8
end_inner_loop_8
subs r14, r14, #2 ;decrement the ht loop
add r12, r12, r9 ;increment the src pointer by
; 2*src_strd-wd
add r1, r1, r8 ;increment the dst pointer by
; 2*dst_strd-wd
bgt outer_loop_8
ldr r10, [sp, #120] ;loads wd
cmp r10, #12
beq outer_loop4_residual
end_loops
b end_func
outer_loop_16
str r0, [sp, #-4]!
str r7, [sp, #-4]!
add r6, r1, r3 ;pu1_dst + dst_strd
add r4, r12, r2 ;pu1_src + src_strd
and r0, r12, #31
mov r7, #0xc000
sub r5, r10, #0 ;checks wd
pld [r4, r2, lsl #1]
pld [r12, r2, lsl #1]
vld1.u32 {q0}, [r12], r11 ;vector load pu1_src
vdup.16 q4, r7
vld1.u32 {q1}, [r12], r11
vld1.u32 {q2}, [r12], r11
vld1.u32 {q3}, [r12], r11
vmlsl.u8 q4, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vld1.u32 {q6}, [r12], r11
vmlsl.u8 q4, d2, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {q7}, [r12], r11
vmlal.u8 q4, d4, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u32 {q8}, [r12], r11
vmlal.u8 q4, d6, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {q9}, [r12], r11
vmlal.u8 q4, d12, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vmlal.u8 q4, d14, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vdup.16 q10, r7
vmlsl.u8 q4, d16, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q4, d18, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
inner_loop_16
vmlsl.u8 q10, d1, d24
vdup.16 q5, r7
vmlsl.u8 q10, d3, d25
mov r7, #0x4000
vdup.16 q11, r7
vmlal.u8 q10, d5, d26
vld1.u32 {q0}, [r4], r11 ;vector load pu1_src
vhadd.s16 q4, q4, q11
vld1.u32 {q1}, [r4], r11
vmlal.u8 q10, d7, d27
add r12, #8
subs r5, r5, #16
vmlal.u8 q10, d13, d28
vld1.u32 {q2}, [r4], r11
vmlal.u8 q10, d15, d29
vld1.u32 {q3}, [r4], r11
vqrshrun.s16 d8, q4, #6 ;right shift and saturating narrow
; result 1
vmlsl.u8 q10, d17, d30
vld1.u32 {q6}, [r4], r11
vmlsl.u8 q10, d19, d31
vld1.u32 {q7}, [r4], r11
vmlsl.u8 q5, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vmlsl.u8 q5, d2, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {q8}, [r4], r11
vhadd.s16 q10, q10, q11
vld1.u32 {q9}, [r4], r11
vmlal.u8 q5, d4, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vmlal.u8 q5, d6, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
add r4, #8
mov r7, #0xc000
vmlal.u8 q5, d12, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vmlal.u8 q5, d14, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vqrshrun.s16 d9, q10, #6
vdup.16 q11, r7
vmlsl.u8 q5, d16, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q5, d18, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
mov r7, #0x4000
vmlsl.u8 q11, d1, d24
vst1.8 {q4}, [r1]! ;store the result pu1_dst
vmlsl.u8 q11, d3, d25
vdup.16 q10, r7
vmlal.u8 q11, d5, d26
pld [r12, r2, lsl #2]
pld [r4, r2, lsl #2]
addeq r12, r12, r9 ;increment the src pointer by
; 2*src_strd-wd
addeq r4, r12, r2 ;pu1_src + src_strd
vmlal.u8 q11, d7, d27
addeq r1, r1, r8
subeq r14, r14, #2
vmlal.u8 q11, d13, d28
vhadd.s16 q5, q5, q10
vmlal.u8 q11, d15, d29
vmlsl.u8 q11, d17, d30
cmp r14, #0
vmlsl.u8 q11, d19, d31
vqrshrun.s16 d10, q5, #6 ;right shift and saturating narrow
; result 2
beq epilog_16
vld1.u32 {q0}, [r12], r11 ;vector load pu1_src
mov r7, #0xc000
cmp r5, #0
vld1.u32 {q1}, [r12], r11
vhadd.s16 q11, q11, q10
vld1.u32 {q2}, [r12], r11
vdup.16 q4, r7
vld1.u32 {q3}, [r12], r11
vmlsl.u8 q4, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vld1.u32 {q6}, [r12], r11
vld1.u32 {q7}, [r12], r11
vmlsl.u8 q4, d2, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {q8}, [r12], r11
vmlal.u8 q4, d4, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u32 {q9}, [r12], r11
vqrshrun.s16 d11, q11, #6
vmlal.u8 q4, d6, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
moveq r5, r10
vmlal.u8 q4, d12, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vdup.16 q10, r7
vmlal.u8 q4, d14, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vst1.8 {q5}, [r6]! ;store the result pu1_dst
vmlsl.u8 q4, d16, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q4, d18, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
addeq r6, r1, r3 ;pu1_dst + dst_strd
b inner_loop_16
epilog_16
mov r7, #0x4000
ldr r0, [sp], #4
ldr r10, [sp, #120]
vdup.16 q10, r7
vhadd.s16 q11, q11, q10
vqrshrun.s16 d11, q11, #6
vst1.8 {q5}, [r6]! ;store the result pu1_dst
ldr r7, [sp], #4
cmp r10, #24
beq outer_loop8_residual
end_loops1
b end_func
outer_loop4_residual
sub r12, r0, #3 ;pu1_src - 3
mov r1, r7
add r1, #8
mov r10, #4
add r12, #8
mov r14, #16
add r8, #4
add r9, #4
outer_loop_4
add r6, r1, r3 ;pu1_dst + dst_strd
add r4, r12, r2 ;pu1_src + src_strd
subs r5, r10, #0 ;checks wd
ble end_inner_loop_4
inner_loop_4
vld1.u32 {d0}, [r12], r11 ;vector load pu1_src
vld1.u32 {d1}, [r12], r11
vld1.u32 {d2}, [r12], r11
vld1.u32 {d3}, [r12], r11
vld1.u32 {d4}, [r12], r11
vld1.u32 {d5}, [r12], r11
vld1.u32 {d6}, [r12], r11
vld1.u32 {d7}, [r12], r11
sub r12, r12, #4
vld1.u32 {d12}, [r4], r11 ;vector load pu1_src + src_strd
vld1.u32 {d13}, [r4], r11
vzip.32 d0, d12 ;vector zip the i iteration and ii
; interation in single register
vld1.u32 {d14}, [r4], r11
vzip.32 d1, d13
vld1.u32 {d15}, [r4], r11
vzip.32 d2, d14
vld1.u32 {d16}, [r4], r11
vzip.32 d3, d15
vld1.u32 {d17}, [r4], r11
vzip.32 d4, d16
vld1.u32 {d18}, [r4], r11
vzip.32 d5, d17
vld1.u32 {d19}, [r4], r11
mov r7, #0xc000
vdup.16 q4, r7
sub r4, r4, #4
vzip.32 d6, d18
vzip.32 d7, d19
vmlsl.u8 q4, d1, d25 ;arithmetic operations for ii
; iteration in the same time
vmlsl.u8 q4, d0, d24
vmlal.u8 q4, d2, d26
vmlal.u8 q4, d3, d27
vmlal.u8 q4, d4, d28
vmlal.u8 q4, d5, d29
vmlsl.u8 q4, d6, d30
vmlsl.u8 q4, d7, d31
mov r7, #0x4000
vdup.16 q10, r7
vhadd.s16 q4, q4, q10
vqrshrun.s16 d8, q4, #6
vst1.32 {d8[0]},[r1]! ;store the i iteration result which
; is in upper part of the register
vst1.32 {d8[1]},[r6]! ;store the ii iteration result which
; is in lower part of the register
subs r5, r5, #4 ;decrement the wd by 4
bgt inner_loop_4
end_inner_loop_4
subs r14, r14, #2 ;decrement the ht by 4
add r12, r12, r9 ;increment the input pointer
; 2*src_strd-wd
add r1, r1, r8 ;increment the output pointer
; 2*dst_strd-wd
bgt outer_loop_4
end_func
vpop {d8 - d15}
ldmfd sp!, {r4 - r12, r15} ;reload the registers from sp
ENDP
END
@@ -0,0 +1,415 @@
;
; Copyright (c) 2018 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
;**************Variables Vs Registers***********************************
; r0 => src
; r1 => dst
; r2 => src_stride
; r3 => dst_stride
; r4 => filter_x0
; r8 => ht
; r10 => wd
EXPORT |vpx_convolve8_horiz_filter_type2_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
|vpx_convolve8_horiz_filter_type2_neon| PROC
stmfd sp!, {r4 - r12, r14} ;stack stores the values of
; the arguments
vpush {d8 - d15} ; stack offset by 64
mov r4, r1
mov r1, r2
mov r2, r4
start_loop_count
ldr r4, [sp, #104] ;loads pi1_coeff
ldr r8, [sp, #108] ;loads x0_q4
add r4, r4, r8, lsl #4 ;r4 = filter[x0_q4]
ldr r8, [sp, #128] ;loads ht
ldr r10, [sp, #124] ;loads wd
vld2.8 {d0, d1}, [r4] ;coeff = vld1_s8(pi1_coeff)
mov r11, #1
subs r14, r8, #0 ;checks for ht == 0
vabs.s8 d2, d0 ;vabs_s8(coeff)
vdup.8 d24, d2[0] ;coeffabs_0 = vdup_lane_u8(coeffabs,
; 0)
sub r12, r0, #3 ;pu1_src - 3
vdup.8 d25, d2[1] ;coeffabs_1 = vdup_lane_u8(coeffabs,
; 1)
add r4, r12, r2 ;pu1_src_tmp2_8 = pu1_src + src_strd
vdup.8 d26, d2[2] ;coeffabs_2 = vdup_lane_u8(coeffabs,
; 2)
rsb r9, r10, r2, lsl #1 ;2*src_strd - wd
vdup.8 d27, d2[3] ;coeffabs_3 = vdup_lane_u8(coeffabs,
; 3)
rsb r8, r10, r3, lsl #1 ;2*dst_strd - wd
vdup.8 d28, d2[4] ;coeffabs_4 = vdup_lane_u8(coeffabs,
; 4)
vdup.8 d29, d2[5] ;coeffabs_5 = vdup_lane_u8(coeffabs,
; 5)
vdup.8 d30, d2[6] ;coeffabs_6 = vdup_lane_u8(coeffabs,
; 6)
vdup.8 d31, d2[7] ;coeffabs_7 = vdup_lane_u8(coeffabs,
; 7)
mov r7, r1
cmp r10, #4
ble outer_loop_4
cmp r10, #24
moveq r10, #16
addeq r8, #8
addeq r9, #8
cmp r10, #16
bge outer_loop_16
cmp r10, #12
addeq r8, #4
addeq r9, #4
b outer_loop_8
outer_loop8_residual
sub r12, r0, #3 ;pu1_src - 3
mov r1, r7
mov r14, #32
add r1, #16
add r12, #16
mov r10, #8
add r8, #8
add r9, #8
outer_loop_8
add r6, r1, r3 ;pu1_dst + dst_strd
add r4, r12, r2 ;pu1_src + src_strd
subs r5, r10, #0 ;checks wd
ble end_inner_loop_8
inner_loop_8
mov r7, #0xc000
vld1.u32 {d0}, [r12], r11 ;vector load pu1_src
vdup.16 q4, r7
vld1.u32 {d1}, [r12], r11
vdup.16 q5, r7
vld1.u32 {d2}, [r12], r11
vld1.u32 {d3}, [r12], r11
mov r7, #0x4000
vld1.u32 {d4}, [r12], r11
vmlal.u8 q4, d1, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {d5}, [r12], r11
vmlal.u8 q4, d3, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {d6}, [r12], r11
vmlsl.u8 q4, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vld1.u32 {d7}, [r12], r11
vmlsl.u8 q4, d2, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u32 {d12}, [r4], r11 ;vector load pu1_src + src_strd
vmlal.u8 q4, d4, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vld1.u32 {d13}, [r4], r11
vmlsl.u8 q4, d5, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vld1.u32 {d14}, [r4], r11
vmlal.u8 q4, d6, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vld1.u32 {d15}, [r4], r11
vmlsl.u8 q4, d7, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
vld1.u32 {d16}, [r4], r11 ;vector load pu1_src + src_strd
vdup.16 q11, r7
vmlal.u8 q5, d15, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {d17}, [r4], r11
vmlsl.u8 q5, d14, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vhadd.s16 q4, q4, q11
vld1.u32 {d18}, [r4], r11
vmlal.u8 q5, d16, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vld1.u32 {d19}, [r4], r11 ;vector load pu1_src + src_strd
vmlsl.u8 q5, d17, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vmlal.u8 q5, d18, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q5, d19, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
vqrshrun.s16 d20, q4, #6 ;right shift and saturating narrow
; result 1
vmlsl.u8 q5, d12, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vmlal.u8 q5, d13, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vst1.8 {d20}, [r1]! ;store the result pu1_dst
vhadd.s16 q5, q5, q11
subs r5, r5, #8 ;decrement the wd loop
vqrshrun.s16 d8, q5, #6 ;right shift and saturating narrow
; result 2
vst1.8 {d8}, [r6]! ;store the result pu1_dst
cmp r5, #4
bgt inner_loop_8
end_inner_loop_8
subs r14, r14, #2 ;decrement the ht loop
add r12, r12, r9 ;increment the src pointer by
; 2*src_strd-wd
add r1, r1, r8 ;increment the dst pointer by
; 2*dst_strd-wd
bgt outer_loop_8
ldr r10, [sp, #120] ;loads wd
cmp r10, #12
beq outer_loop4_residual
end_loops
b end_func
outer_loop_16
str r0, [sp, #-4]!
str r7, [sp, #-4]!
add r6, r1, r3 ;pu1_dst + dst_strd
add r4, r12, r2 ;pu1_src + src_strd
and r0, r12, #31
mov r7, #0xc000
sub r5, r10, #0 ;checks wd
pld [r4, r2, lsl #1]
pld [r12, r2, lsl #1]
vld1.u32 {q0}, [r12], r11 ;vector load pu1_src
vdup.16 q4, r7
vld1.u32 {q1}, [r12], r11
vld1.u32 {q2}, [r12], r11
vld1.u32 {q3}, [r12], r11
vmlsl.u8 q4, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vld1.u32 {q6}, [r12], r11
vmlal.u8 q4, d2, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {q7}, [r12], r11
vmlsl.u8 q4, d4, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u32 {q8}, [r12], r11
vmlal.u8 q4, d6, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
vld1.u32 {q9}, [r12], r11
vmlal.u8 q4, d12, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vmlsl.u8 q4, d14, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vdup.16 q10, r7
vmlal.u8 q4, d16, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q4, d18, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
inner_loop_16
vmlsl.u8 q10, d1, d24
vdup.16 q5, r7
vmlal.u8 q10, d3, d25
mov r7, #0x4000
vdup.16 q11, r7
vmlsl.u8 q10, d5, d26
vld1.u32 {q0}, [r4], r11 ;vector load pu1_src
vhadd.s16 q4, q4, q11
vld1.u32 {q1}, [r4], r11
vmlal.u8 q10, d7, d27
add r12, #8
subs r5, r5, #16
vmlal.u8 q10, d13, d28
vld1.u32 {q2}, [r4], r11
vmlsl.u8 q10, d15, d29
vld1.u32 {q3}, [r4], r11
vqrshrun.s16 d8, q4, #6 ;right shift and saturating narrow
; result 1
vmlal.u8 q10, d17, d30
vld1.u32 {q6}, [r4], r11
vmlsl.u8 q10, d19, d31
vld1.u32 {q7}, [r4], r11
vmlsl.u8 q5, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vmlal.u8 q5, d2, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {q8}, [r4], r11
vhadd.s16 q10, q10, q11
vld1.u32 {q9}, [r4], r11
vmlsl.u8 q5, d4, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vmlal.u8 q5, d6, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
add r4, #8
mov r7, #0xc000
vmlal.u8 q5, d12, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vmlsl.u8 q5, d14, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vqrshrun.s16 d9, q10, #6
vdup.16 q11, r7
vmlal.u8 q5, d16, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q5, d18, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
mov r7, #0x4000
vmlsl.u8 q11, d1, d24
vst1.8 {q4}, [r1]! ;store the result pu1_dst
vmlal.u8 q11, d3, d25
vdup.16 q10, r7
vmlsl.u8 q11, d5, d26
pld [r12, r2, lsl #2]
pld [r4, r2, lsl #2]
addeq r12, r12, r9 ;increment the src pointer by
; 2*src_strd-wd
addeq r4, r12, r2 ;pu1_src + src_strd
vmlal.u8 q11, d7, d27
addeq r1, r1, r8
subeq r14, r14, #2
vmlal.u8 q11, d13, d28
vhadd.s16 q5, q5, q10
vmlsl.u8 q11, d15, d29
vmlal.u8 q11, d17, d30
cmp r14, #0
vmlsl.u8 q11, d19, d31
vqrshrun.s16 d10, q5, #6 ;right shift and saturating narrow
; result 2
beq epilog_16
vld1.u32 {q0}, [r12], r11 ;vector load pu1_src
mov r7, #0xc000
cmp r5, #0
vld1.u32 {q1}, [r12], r11
vhadd.s16 q11, q11, q10
vld1.u32 {q2}, [r12], r11
vdup.16 q4, r7
vld1.u32 {q3}, [r12], r11
vmlsl.u8 q4, d0, d24 ;mul_res = vmlsl_u8(src[0_0],
; coeffabs_0);
vld1.u32 {q6}, [r12], r11
vld1.u32 {q7}, [r12], r11
vmlal.u8 q4, d2, d25 ;mul_res = vmlal_u8(src[0_1],
; coeffabs_1);
vld1.u32 {q8}, [r12], r11
vmlsl.u8 q4, d4, d26 ;mul_res = vmlsl_u8(src[0_2],
; coeffabs_2);
vld1.u32 {q9}, [r12], r11
vqrshrun.s16 d11, q11, #6
vmlal.u8 q4, d6, d27 ;mul_res = vmull_u8(src[0_3],
; coeffabs_3);
moveq r5, r10
vmlal.u8 q4, d12, d28 ;mul_res = vmlal_u8(src[0_4],
; coeffabs_4);
vdup.16 q10, r7
vmlsl.u8 q4, d14, d29 ;mul_res = vmlsl_u8(src[0_5],
; coeffabs_5);
vst1.8 {q5}, [r6]! ;store the result pu1_dst
vmlal.u8 q4, d16, d30 ;mul_res = vmlal_u8(src[0_6],
; coeffabs_6);
vmlsl.u8 q4, d18, d31 ;mul_res = vmlsl_u8(src[0_7],
; coeffabs_7);
addeq r6, r1, r3 ;pu1_dst + dst_strd
b inner_loop_16
epilog_16
mov r7, #0x4000
ldr r0, [sp], #4
ldr r10, [sp, #120]
vdup.16 q10, r7
vhadd.s16 q11, q11, q10
vqrshrun.s16 d11, q11, #6
vst1.8 {q5}, [r6]! ;store the result pu1_dst
ldr r7, [sp], #4
cmp r10, #24
beq outer_loop8_residual
end_loops1
b end_func
outer_loop4_residual
sub r12, r0, #3 ;pu1_src - 3
mov r1, r7
add r1, #8
mov r10, #4
add r12, #8
mov r14, #16
add r8, #4
add r9, #4
outer_loop_4
add r6, r1, r3 ;pu1_dst + dst_strd
add r4, r12, r2 ;pu1_src + src_strd
subs r5, r10, #0 ;checks wd
ble end_inner_loop_4
inner_loop_4
vld1.u32 {d0}, [r12], r11 ;vector load pu1_src
vld1.u32 {d1}, [r12], r11
vld1.u32 {d2}, [r12], r11
vld1.u32 {d3}, [r12], r11
vld1.u32 {d4}, [r12], r11
vld1.u32 {d5}, [r12], r11
vld1.u32 {d6}, [r12], r11
vld1.u32 {d7}, [r12], r11
sub r12, r12, #4
vld1.u32 {d12}, [r4], r11 ;vector load pu1_src + src_strd
vld1.u32 {d13}, [r4], r11
vzip.32 d0, d12 ;vector zip the i iteration and ii
; interation in single register
vld1.u32 {d14}, [r4], r11
vzip.32 d1, d13
vld1.u32 {d15}, [r4], r11
vzip.32 d2, d14
vld1.u32 {d16}, [r4], r11
vzip.32 d3, d15
vld1.u32 {d17}, [r4], r11
vzip.32 d4, d16
vld1.u32 {d18}, [r4], r11
vzip.32 d5, d17
vld1.u32 {d19}, [r4], r11
mov r7, #0xc000
vdup.16 q4, r7
sub r4, r4, #4
vzip.32 d6, d18
vzip.32 d7, d19
vmlal.u8 q4, d1, d25 ;arithmetic operations for ii
; iteration in the same time
vmlsl.u8 q4, d0, d24
vmlsl.u8 q4, d2, d26
vmlal.u8 q4, d3, d27
vmlal.u8 q4, d4, d28
vmlsl.u8 q4, d5, d29
vmlal.u8 q4, d6, d30
vmlsl.u8 q4, d7, d31
mov r7, #0x4000
vdup.16 q10, r7
vhadd.s16 q4, q4, q10
vqrshrun.s16 d8, q4, #6
vst1.32 {d8[0]},[r1]! ;store the i iteration result which
; is in upper part of the register
vst1.32 {d8[1]},[r6]! ;store the ii iteration result which
; is in lower part of the register
subs r5, r5, #4 ;decrement the wd by 4
bgt inner_loop_4
end_inner_loop_4
subs r14, r14, #2 ;decrement the ht by 4
add r12, r12, r9 ;increment the input pointer
; 2*src_strd-wd
add r1, r1, r8 ;increment the output pointer
; 2*dst_strd-wd
bgt outer_loop_4
end_func
vpop {d8 - d15}
ldmfd sp!, {r4 - r12, r15} ;reload the registers from sp
ENDP
END
@@ -0,0 +1,959 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/arm/transpose_neon.h"
#include "vpx_dsp/arm/vpx_convolve8_neon.h"
#include "vpx_ports/mem.h"
// Note:
// 1. src is not always 32-bit aligned, so don't call vld1_lane_u32(src).
// 2. After refactoring the shared code in kernel loops with inline functions,
// the decoder speed dropped a lot when using gcc compiler. Therefore there is
// no refactoring for those parts by now.
// 3. For horizontal convolve, there is an alternative optimization that
// convolves a single row in each loop. For each row, 8 sample banks with 4 or 8
// samples in each are read from memory: src, (src+1), (src+2), (src+3),
// (src+4), (src+5), (src+6), (src+7), or prepared by vector extract
// instructions. This optimization is much faster in speed unit test, but slowed
// down the whole decoder by 5%.
static INLINE void store_u8_8x8(uint8_t *s, const ptrdiff_t p,
const uint8x8_t s0, const uint8x8_t s1,
const uint8x8_t s2, const uint8x8_t s3,
const uint8x8_t s4, const uint8x8_t s5,
const uint8x8_t s6, const uint8x8_t s7) {
vst1_u8(s, s0);
s += p;
vst1_u8(s, s1);
s += p;
vst1_u8(s, s2);
s += p;
vst1_u8(s, s3);
s += p;
vst1_u8(s, s4);
s += p;
vst1_u8(s, s5);
s += p;
vst1_u8(s, s6);
s += p;
vst1_u8(s, s7);
}
void vpx_convolve8_horiz_neon(const uint8_t *src, ptrdiff_t src_stride,
uint8_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4, int w,
int h) {
const int16x8_t filters = vld1q_s16(filter[x0_q4]);
uint8x8_t t0, t1, t2, t3;
assert(!((intptr_t)dst & 3));
assert(!(dst_stride & 3));
assert(x_step_q4 == 16);
(void)x_step_q4;
(void)y0_q4;
(void)y_step_q4;
src -= 3;
if (h == 4) {
uint8x8_t d01, d23;
int16x4_t filter3, filter4, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, d0,
d1, d2, d3;
int16x8_t tt0, tt1, tt2, tt3;
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
filter3 = vdup_lane_s16(vget_low_s16(filters), 3);
filter4 = vdup_lane_s16(vget_high_s16(filters), 0);
load_u8_8x4(src, src_stride, &t0, &t1, &t2, &t3);
transpose_u8_8x4(&t0, &t1, &t2, &t3);
tt0 = vreinterpretq_s16_u16(vmovl_u8(t0));
tt1 = vreinterpretq_s16_u16(vmovl_u8(t1));
tt2 = vreinterpretq_s16_u16(vmovl_u8(t2));
tt3 = vreinterpretq_s16_u16(vmovl_u8(t3));
s0 = vget_low_s16(tt0);
s1 = vget_low_s16(tt1);
s2 = vget_low_s16(tt2);
s3 = vget_low_s16(tt3);
s4 = vget_high_s16(tt0);
s5 = vget_high_s16(tt1);
s6 = vget_high_s16(tt2);
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
src += 7;
do {
load_u8_8x4(src, src_stride, &t0, &t1, &t2, &t3);
transpose_u8_8x4(&t0, &t1, &t2, &t3);
tt0 = vreinterpretq_s16_u16(vmovl_u8(t0));
tt1 = vreinterpretq_s16_u16(vmovl_u8(t1));
tt2 = vreinterpretq_s16_u16(vmovl_u8(t2));
tt3 = vreinterpretq_s16_u16(vmovl_u8(t3));
s7 = vget_low_s16(tt0);
s8 = vget_low_s16(tt1);
s9 = vget_low_s16(tt2);
s10 = vget_low_s16(tt3);
d0 = convolve8_4(s0, s1, s2, s3, s4, s5, s6, s7, filters, filter3,
filter4);
d1 = convolve8_4(s1, s2, s3, s4, s5, s6, s7, s8, filters, filter3,
filter4);
d2 = convolve8_4(s2, s3, s4, s5, s6, s7, s8, s9, filters, filter3,
filter4);
d3 = convolve8_4(s3, s4, s5, s6, s7, s8, s9, s10, filters, filter3,
filter4);
d01 = vqrshrun_n_s16(vcombine_s16(d0, d1), 7);
d23 = vqrshrun_n_s16(vcombine_s16(d2, d3), 7);
transpose_u8_4x4(&d01, &d23);
vst1_lane_u32((uint32_t *)(dst + 0 * dst_stride),
vreinterpret_u32_u8(d01), 0);
vst1_lane_u32((uint32_t *)(dst + 1 * dst_stride),
vreinterpret_u32_u8(d23), 0);
vst1_lane_u32((uint32_t *)(dst + 2 * dst_stride),
vreinterpret_u32_u8(d01), 1);
vst1_lane_u32((uint32_t *)(dst + 3 * dst_stride),
vreinterpret_u32_u8(d23), 1);
s0 = s4;
s1 = s5;
s2 = s6;
s3 = s7;
s4 = s8;
s5 = s9;
s6 = s10;
src += 4;
dst += 4;
w -= 4;
} while (w > 0);
} else {
const int16x8_t filter3 = vdupq_lane_s16(vget_low_s16(filters), 3);
const int16x8_t filter4 = vdupq_lane_s16(vget_high_s16(filters), 0);
int width;
const uint8_t *s;
uint8x8_t t4, t5, t6, t7;
int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
if (w == 4) {
do {
load_u8_8x8(src, src_stride, &t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
transpose_u8_8x8(&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
s0 = vreinterpretq_s16_u16(vmovl_u8(t0));
s1 = vreinterpretq_s16_u16(vmovl_u8(t1));
s2 = vreinterpretq_s16_u16(vmovl_u8(t2));
s3 = vreinterpretq_s16_u16(vmovl_u8(t3));
s4 = vreinterpretq_s16_u16(vmovl_u8(t4));
s5 = vreinterpretq_s16_u16(vmovl_u8(t5));
s6 = vreinterpretq_s16_u16(vmovl_u8(t6));
load_u8_8x8(src + 7, src_stride, &t0, &t1, &t2, &t3, &t4, &t5, &t6,
&t7);
src += 8 * src_stride;
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
__builtin_prefetch(dst + 4 * dst_stride);
__builtin_prefetch(dst + 5 * dst_stride);
__builtin_prefetch(dst + 6 * dst_stride);
__builtin_prefetch(dst + 7 * dst_stride);
transpose_u8_4x8(&t0, &t1, &t2, &t3, t4, t5, t6, t7);
s7 = vreinterpretq_s16_u16(vmovl_u8(t0));
s8 = vreinterpretq_s16_u16(vmovl_u8(t1));
s9 = vreinterpretq_s16_u16(vmovl_u8(t2));
s10 = vreinterpretq_s16_u16(vmovl_u8(t3));
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
__builtin_prefetch(src + 4 * src_stride);
__builtin_prefetch(src + 5 * src_stride);
__builtin_prefetch(src + 6 * src_stride);
__builtin_prefetch(src + 7 * src_stride);
t0 = convolve8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters, filter3,
filter4);
t1 = convolve8_8(s1, s2, s3, s4, s5, s6, s7, s8, filters, filter3,
filter4);
t2 = convolve8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters, filter3,
filter4);
t3 = convolve8_8(s3, s4, s5, s6, s7, s8, s9, s10, filters, filter3,
filter4);
transpose_u8_8x4(&t0, &t1, &t2, &t3);
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(t0), 0);
dst += dst_stride;
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(t1), 0);
dst += dst_stride;
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(t2), 0);
dst += dst_stride;
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(t3), 0);
dst += dst_stride;
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(t0), 1);
dst += dst_stride;
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(t1), 1);
dst += dst_stride;
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(t2), 1);
dst += dst_stride;
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(t3), 1);
dst += dst_stride;
h -= 8;
} while (h > 0);
} else {
uint8_t *d;
int16x8_t s11, s12, s13, s14;
do {
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
__builtin_prefetch(src + 4 * src_stride);
__builtin_prefetch(src + 5 * src_stride);
__builtin_prefetch(src + 6 * src_stride);
__builtin_prefetch(src + 7 * src_stride);
load_u8_8x8(src, src_stride, &t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
transpose_u8_8x8(&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
s0 = vreinterpretq_s16_u16(vmovl_u8(t0));
s1 = vreinterpretq_s16_u16(vmovl_u8(t1));
s2 = vreinterpretq_s16_u16(vmovl_u8(t2));
s3 = vreinterpretq_s16_u16(vmovl_u8(t3));
s4 = vreinterpretq_s16_u16(vmovl_u8(t4));
s5 = vreinterpretq_s16_u16(vmovl_u8(t5));
s6 = vreinterpretq_s16_u16(vmovl_u8(t6));
width = w;
s = src + 7;
d = dst;
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
__builtin_prefetch(dst + 4 * dst_stride);
__builtin_prefetch(dst + 5 * dst_stride);
__builtin_prefetch(dst + 6 * dst_stride);
__builtin_prefetch(dst + 7 * dst_stride);
do {
load_u8_8x8(s, src_stride, &t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
transpose_u8_8x8(&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
s7 = vreinterpretq_s16_u16(vmovl_u8(t0));
s8 = vreinterpretq_s16_u16(vmovl_u8(t1));
s9 = vreinterpretq_s16_u16(vmovl_u8(t2));
s10 = vreinterpretq_s16_u16(vmovl_u8(t3));
s11 = vreinterpretq_s16_u16(vmovl_u8(t4));
s12 = vreinterpretq_s16_u16(vmovl_u8(t5));
s13 = vreinterpretq_s16_u16(vmovl_u8(t6));
s14 = vreinterpretq_s16_u16(vmovl_u8(t7));
t0 = convolve8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters, filter3,
filter4);
t1 = convolve8_8(s1, s2, s3, s4, s5, s6, s7, s8, filters, filter3,
filter4);
t2 = convolve8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters, filter3,
filter4);
t3 = convolve8_8(s3, s4, s5, s6, s7, s8, s9, s10, filters, filter3,
filter4);
t4 = convolve8_8(s4, s5, s6, s7, s8, s9, s10, s11, filters, filter3,
filter4);
t5 = convolve8_8(s5, s6, s7, s8, s9, s10, s11, s12, filters, filter3,
filter4);
t6 = convolve8_8(s6, s7, s8, s9, s10, s11, s12, s13, filters, filter3,
filter4);
t7 = convolve8_8(s7, s8, s9, s10, s11, s12, s13, s14, filters,
filter3, filter4);
transpose_u8_8x8(&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
store_u8_8x8(d, dst_stride, t0, t1, t2, t3, t4, t5, t6, t7);
s0 = s8;
s1 = s9;
s2 = s10;
s3 = s11;
s4 = s12;
s5 = s13;
s6 = s14;
s += 8;
d += 8;
width -= 8;
} while (width > 0);
src += 8 * src_stride;
dst += 8 * dst_stride;
h -= 8;
} while (h > 0);
}
}
}
void vpx_convolve8_avg_horiz_neon(const uint8_t *src, ptrdiff_t src_stride,
uint8_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4,
int w, int h) {
const int16x8_t filters = vld1q_s16(filter[x0_q4]);
uint8x8_t t0, t1, t2, t3;
assert(!((intptr_t)dst & 3));
assert(!(dst_stride & 3));
assert(x_step_q4 == 16);
(void)x_step_q4;
(void)y0_q4;
(void)y_step_q4;
src -= 3;
if (h == 4) {
uint8x8_t d01, d23;
int16x4_t filter3, filter4, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, d0,
d1, d2, d3;
int16x8_t tt0, tt1, tt2, tt3;
uint32x4_t d0123 = vdupq_n_u32(0);
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
filter3 = vdup_lane_s16(vget_low_s16(filters), 3);
filter4 = vdup_lane_s16(vget_high_s16(filters), 0);
load_u8_8x4(src, src_stride, &t0, &t1, &t2, &t3);
transpose_u8_8x4(&t0, &t1, &t2, &t3);
tt0 = vreinterpretq_s16_u16(vmovl_u8(t0));
tt1 = vreinterpretq_s16_u16(vmovl_u8(t1));
tt2 = vreinterpretq_s16_u16(vmovl_u8(t2));
tt3 = vreinterpretq_s16_u16(vmovl_u8(t3));
s0 = vget_low_s16(tt0);
s1 = vget_low_s16(tt1);
s2 = vget_low_s16(tt2);
s3 = vget_low_s16(tt3);
s4 = vget_high_s16(tt0);
s5 = vget_high_s16(tt1);
s6 = vget_high_s16(tt2);
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
src += 7;
do {
load_u8_8x4(src, src_stride, &t0, &t1, &t2, &t3);
transpose_u8_8x4(&t0, &t1, &t2, &t3);
tt0 = vreinterpretq_s16_u16(vmovl_u8(t0));
tt1 = vreinterpretq_s16_u16(vmovl_u8(t1));
tt2 = vreinterpretq_s16_u16(vmovl_u8(t2));
tt3 = vreinterpretq_s16_u16(vmovl_u8(t3));
s7 = vget_low_s16(tt0);
s8 = vget_low_s16(tt1);
s9 = vget_low_s16(tt2);
s10 = vget_low_s16(tt3);
d0 = convolve8_4(s0, s1, s2, s3, s4, s5, s6, s7, filters, filter3,
filter4);
d1 = convolve8_4(s1, s2, s3, s4, s5, s6, s7, s8, filters, filter3,
filter4);
d2 = convolve8_4(s2, s3, s4, s5, s6, s7, s8, s9, filters, filter3,
filter4);
d3 = convolve8_4(s3, s4, s5, s6, s7, s8, s9, s10, filters, filter3,
filter4);
d01 = vqrshrun_n_s16(vcombine_s16(d0, d1), 7);
d23 = vqrshrun_n_s16(vcombine_s16(d2, d3), 7);
transpose_u8_4x4(&d01, &d23);
d0123 = vld1q_lane_u32((uint32_t *)(dst + 0 * dst_stride), d0123, 0);
d0123 = vld1q_lane_u32((uint32_t *)(dst + 1 * dst_stride), d0123, 2);
d0123 = vld1q_lane_u32((uint32_t *)(dst + 2 * dst_stride), d0123, 1);
d0123 = vld1q_lane_u32((uint32_t *)(dst + 3 * dst_stride), d0123, 3);
d0123 = vreinterpretq_u32_u8(
vrhaddq_u8(vreinterpretq_u8_u32(d0123), vcombine_u8(d01, d23)));
vst1q_lane_u32((uint32_t *)(dst + 0 * dst_stride), d0123, 0);
vst1q_lane_u32((uint32_t *)(dst + 1 * dst_stride), d0123, 2);
vst1q_lane_u32((uint32_t *)(dst + 2 * dst_stride), d0123, 1);
vst1q_lane_u32((uint32_t *)(dst + 3 * dst_stride), d0123, 3);
s0 = s4;
s1 = s5;
s2 = s6;
s3 = s7;
s4 = s8;
s5 = s9;
s6 = s10;
src += 4;
dst += 4;
w -= 4;
} while (w > 0);
} else {
const int16x8_t filter3 = vdupq_lane_s16(vget_low_s16(filters), 3);
const int16x8_t filter4 = vdupq_lane_s16(vget_high_s16(filters), 0);
int width;
const uint8_t *s;
uint8x8_t t4, t5, t6, t7;
int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
if (w == 4) {
uint32x4_t d0415 = vdupq_n_u32(0);
uint32x4_t d2637 = vdupq_n_u32(0);
do {
load_u8_8x8(src, src_stride, &t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
transpose_u8_8x8(&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
s0 = vreinterpretq_s16_u16(vmovl_u8(t0));
s1 = vreinterpretq_s16_u16(vmovl_u8(t1));
s2 = vreinterpretq_s16_u16(vmovl_u8(t2));
s3 = vreinterpretq_s16_u16(vmovl_u8(t3));
s4 = vreinterpretq_s16_u16(vmovl_u8(t4));
s5 = vreinterpretq_s16_u16(vmovl_u8(t5));
s6 = vreinterpretq_s16_u16(vmovl_u8(t6));
load_u8_8x8(src + 7, src_stride, &t0, &t1, &t2, &t3, &t4, &t5, &t6,
&t7);
src += 8 * src_stride;
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
__builtin_prefetch(dst + 4 * dst_stride);
__builtin_prefetch(dst + 5 * dst_stride);
__builtin_prefetch(dst + 6 * dst_stride);
__builtin_prefetch(dst + 7 * dst_stride);
transpose_u8_4x8(&t0, &t1, &t2, &t3, t4, t5, t6, t7);
s7 = vreinterpretq_s16_u16(vmovl_u8(t0));
s8 = vreinterpretq_s16_u16(vmovl_u8(t1));
s9 = vreinterpretq_s16_u16(vmovl_u8(t2));
s10 = vreinterpretq_s16_u16(vmovl_u8(t3));
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
__builtin_prefetch(src + 4 * src_stride);
__builtin_prefetch(src + 5 * src_stride);
__builtin_prefetch(src + 6 * src_stride);
__builtin_prefetch(src + 7 * src_stride);
t0 = convolve8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters, filter3,
filter4);
t1 = convolve8_8(s1, s2, s3, s4, s5, s6, s7, s8, filters, filter3,
filter4);
t2 = convolve8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters, filter3,
filter4);
t3 = convolve8_8(s3, s4, s5, s6, s7, s8, s9, s10, filters, filter3,
filter4);
transpose_u8_8x4(&t0, &t1, &t2, &t3);
d0415 = vld1q_lane_u32((uint32_t *)(dst + 0 * dst_stride), d0415, 0);
d0415 = vld1q_lane_u32((uint32_t *)(dst + 1 * dst_stride), d0415, 2);
d2637 = vld1q_lane_u32((uint32_t *)(dst + 2 * dst_stride), d2637, 0);
d2637 = vld1q_lane_u32((uint32_t *)(dst + 3 * dst_stride), d2637, 2);
d0415 = vld1q_lane_u32((uint32_t *)(dst + 4 * dst_stride), d0415, 1);
d0415 = vld1q_lane_u32((uint32_t *)(dst + 5 * dst_stride), d0415, 3);
d2637 = vld1q_lane_u32((uint32_t *)(dst + 6 * dst_stride), d2637, 1);
d2637 = vld1q_lane_u32((uint32_t *)(dst + 7 * dst_stride), d2637, 3);
d0415 = vreinterpretq_u32_u8(
vrhaddq_u8(vreinterpretq_u8_u32(d0415), vcombine_u8(t0, t1)));
d2637 = vreinterpretq_u32_u8(
vrhaddq_u8(vreinterpretq_u8_u32(d2637), vcombine_u8(t2, t3)));
vst1q_lane_u32((uint32_t *)dst, d0415, 0);
dst += dst_stride;
vst1q_lane_u32((uint32_t *)dst, d0415, 2);
dst += dst_stride;
vst1q_lane_u32((uint32_t *)dst, d2637, 0);
dst += dst_stride;
vst1q_lane_u32((uint32_t *)dst, d2637, 2);
dst += dst_stride;
vst1q_lane_u32((uint32_t *)dst, d0415, 1);
dst += dst_stride;
vst1q_lane_u32((uint32_t *)dst, d0415, 3);
dst += dst_stride;
vst1q_lane_u32((uint32_t *)dst, d2637, 1);
dst += dst_stride;
vst1q_lane_u32((uint32_t *)dst, d2637, 3);
dst += dst_stride;
h -= 8;
} while (h > 0);
} else {
uint8_t *d;
int16x8_t s11, s12, s13, s14;
uint8x16_t d01, d23, d45, d67;
do {
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
__builtin_prefetch(src + 4 * src_stride);
__builtin_prefetch(src + 5 * src_stride);
__builtin_prefetch(src + 6 * src_stride);
__builtin_prefetch(src + 7 * src_stride);
load_u8_8x8(src, src_stride, &t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
transpose_u8_8x8(&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
s0 = vreinterpretq_s16_u16(vmovl_u8(t0));
s1 = vreinterpretq_s16_u16(vmovl_u8(t1));
s2 = vreinterpretq_s16_u16(vmovl_u8(t2));
s3 = vreinterpretq_s16_u16(vmovl_u8(t3));
s4 = vreinterpretq_s16_u16(vmovl_u8(t4));
s5 = vreinterpretq_s16_u16(vmovl_u8(t5));
s6 = vreinterpretq_s16_u16(vmovl_u8(t6));
width = w;
s = src + 7;
d = dst;
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
__builtin_prefetch(dst + 4 * dst_stride);
__builtin_prefetch(dst + 5 * dst_stride);
__builtin_prefetch(dst + 6 * dst_stride);
__builtin_prefetch(dst + 7 * dst_stride);
do {
load_u8_8x8(s, src_stride, &t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
transpose_u8_8x8(&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
s7 = vreinterpretq_s16_u16(vmovl_u8(t0));
s8 = vreinterpretq_s16_u16(vmovl_u8(t1));
s9 = vreinterpretq_s16_u16(vmovl_u8(t2));
s10 = vreinterpretq_s16_u16(vmovl_u8(t3));
s11 = vreinterpretq_s16_u16(vmovl_u8(t4));
s12 = vreinterpretq_s16_u16(vmovl_u8(t5));
s13 = vreinterpretq_s16_u16(vmovl_u8(t6));
s14 = vreinterpretq_s16_u16(vmovl_u8(t7));
t0 = convolve8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters, filter3,
filter4);
t1 = convolve8_8(s1, s2, s3, s4, s5, s6, s7, s8, filters, filter3,
filter4);
t2 = convolve8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters, filter3,
filter4);
t3 = convolve8_8(s3, s4, s5, s6, s7, s8, s9, s10, filters, filter3,
filter4);
t4 = convolve8_8(s4, s5, s6, s7, s8, s9, s10, s11, filters, filter3,
filter4);
t5 = convolve8_8(s5, s6, s7, s8, s9, s10, s11, s12, filters, filter3,
filter4);
t6 = convolve8_8(s6, s7, s8, s9, s10, s11, s12, s13, filters, filter3,
filter4);
t7 = convolve8_8(s7, s8, s9, s10, s11, s12, s13, s14, filters,
filter3, filter4);
transpose_u8_8x8(&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7);
d01 = vcombine_u8(vld1_u8(d + 0 * dst_stride),
vld1_u8(d + 1 * dst_stride));
d23 = vcombine_u8(vld1_u8(d + 2 * dst_stride),
vld1_u8(d + 3 * dst_stride));
d45 = vcombine_u8(vld1_u8(d + 4 * dst_stride),
vld1_u8(d + 5 * dst_stride));
d67 = vcombine_u8(vld1_u8(d + 6 * dst_stride),
vld1_u8(d + 7 * dst_stride));
d01 = vrhaddq_u8(d01, vcombine_u8(t0, t1));
d23 = vrhaddq_u8(d23, vcombine_u8(t2, t3));
d45 = vrhaddq_u8(d45, vcombine_u8(t4, t5));
d67 = vrhaddq_u8(d67, vcombine_u8(t6, t7));
store_u8_8x8(d, dst_stride, vget_low_u8(d01), vget_high_u8(d01),
vget_low_u8(d23), vget_high_u8(d23), vget_low_u8(d45),
vget_high_u8(d45), vget_low_u8(d67), vget_high_u8(d67));
s0 = s8;
s1 = s9;
s2 = s10;
s3 = s11;
s4 = s12;
s5 = s13;
s6 = s14;
s += 8;
d += 8;
width -= 8;
} while (width > 0);
src += 8 * src_stride;
dst += 8 * dst_stride;
h -= 8;
} while (h > 0);
}
}
}
void vpx_convolve8_vert_neon(const uint8_t *src, ptrdiff_t src_stride,
uint8_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4, int w,
int h) {
const int16x8_t filters = vld1q_s16(filter[y0_q4]);
assert(!((intptr_t)dst & 3));
assert(!(dst_stride & 3));
assert(y_step_q4 == 16);
(void)x0_q4;
(void)x_step_q4;
(void)y_step_q4;
src -= 3 * src_stride;
if (w == 4) {
const int16x4_t filter3 = vdup_lane_s16(vget_low_s16(filters), 3);
const int16x4_t filter4 = vdup_lane_s16(vget_high_s16(filters), 0);
uint8x8_t d01, d23;
int16x4_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, d0, d1, d2, d3;
s0 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s1 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s2 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s3 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s4 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s5 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s6 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
do {
s7 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s8 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s9 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s10 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
d0 = convolve8_4(s0, s1, s2, s3, s4, s5, s6, s7, filters, filter3,
filter4);
d1 = convolve8_4(s1, s2, s3, s4, s5, s6, s7, s8, filters, filter3,
filter4);
d2 = convolve8_4(s2, s3, s4, s5, s6, s7, s8, s9, filters, filter3,
filter4);
d3 = convolve8_4(s3, s4, s5, s6, s7, s8, s9, s10, filters, filter3,
filter4);
d01 = vqrshrun_n_s16(vcombine_s16(d0, d1), 7);
d23 = vqrshrun_n_s16(vcombine_s16(d2, d3), 7);
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(d01), 0);
dst += dst_stride;
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(d01), 1);
dst += dst_stride;
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(d23), 0);
dst += dst_stride;
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(d23), 1);
dst += dst_stride;
s0 = s4;
s1 = s5;
s2 = s6;
s3 = s7;
s4 = s8;
s5 = s9;
s6 = s10;
h -= 4;
} while (h > 0);
} else {
const int16x8_t filter3 = vdupq_lane_s16(vget_low_s16(filters), 3);
const int16x8_t filter4 = vdupq_lane_s16(vget_high_s16(filters), 0);
int height;
const uint8_t *s;
uint8_t *d;
uint8x8_t t0, t1, t2, t3;
int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
do {
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
__builtin_prefetch(src + 4 * src_stride);
__builtin_prefetch(src + 5 * src_stride);
__builtin_prefetch(src + 6 * src_stride);
s = src;
s0 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s1 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s2 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s3 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s4 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s5 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s6 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
d = dst;
height = h;
do {
s7 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s8 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s9 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s10 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
__builtin_prefetch(d + 0 * dst_stride);
__builtin_prefetch(d + 1 * dst_stride);
__builtin_prefetch(d + 2 * dst_stride);
__builtin_prefetch(d + 3 * dst_stride);
__builtin_prefetch(s + 0 * src_stride);
__builtin_prefetch(s + 1 * src_stride);
__builtin_prefetch(s + 2 * src_stride);
__builtin_prefetch(s + 3 * src_stride);
t0 = convolve8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters, filter3,
filter4);
t1 = convolve8_8(s1, s2, s3, s4, s5, s6, s7, s8, filters, filter3,
filter4);
t2 = convolve8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters, filter3,
filter4);
t3 = convolve8_8(s3, s4, s5, s6, s7, s8, s9, s10, filters, filter3,
filter4);
vst1_u8(d, t0);
d += dst_stride;
vst1_u8(d, t1);
d += dst_stride;
vst1_u8(d, t2);
d += dst_stride;
vst1_u8(d, t3);
d += dst_stride;
s0 = s4;
s1 = s5;
s2 = s6;
s3 = s7;
s4 = s8;
s5 = s9;
s6 = s10;
height -= 4;
} while (height > 0);
src += 8;
dst += 8;
w -= 8;
} while (w > 0);
}
}
void vpx_convolve8_avg_vert_neon(const uint8_t *src, ptrdiff_t src_stride,
uint8_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4, int w,
int h) {
const int16x8_t filters = vld1q_s16(filter[y0_q4]);
assert(!((intptr_t)dst & 3));
assert(!(dst_stride & 3));
assert(y_step_q4 == 16);
(void)x0_q4;
(void)x_step_q4;
(void)y_step_q4;
src -= 3 * src_stride;
if (w == 4) {
const int16x4_t filter3 = vdup_lane_s16(vget_low_s16(filters), 3);
const int16x4_t filter4 = vdup_lane_s16(vget_high_s16(filters), 0);
uint8x8_t d01, d23;
int16x4_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, d0, d1, d2, d3;
uint32x4_t d0123 = vdupq_n_u32(0);
s0 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s1 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s2 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s3 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s4 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s5 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s6 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
do {
s7 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s8 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s9 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
s10 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(vld1_u8(src))));
src += src_stride;
__builtin_prefetch(dst + 0 * dst_stride);
__builtin_prefetch(dst + 1 * dst_stride);
__builtin_prefetch(dst + 2 * dst_stride);
__builtin_prefetch(dst + 3 * dst_stride);
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
d0 = convolve8_4(s0, s1, s2, s3, s4, s5, s6, s7, filters, filter3,
filter4);
d1 = convolve8_4(s1, s2, s3, s4, s5, s6, s7, s8, filters, filter3,
filter4);
d2 = convolve8_4(s2, s3, s4, s5, s6, s7, s8, s9, filters, filter3,
filter4);
d3 = convolve8_4(s3, s4, s5, s6, s7, s8, s9, s10, filters, filter3,
filter4);
d01 = vqrshrun_n_s16(vcombine_s16(d0, d1), 7);
d23 = vqrshrun_n_s16(vcombine_s16(d2, d3), 7);
d0123 = vld1q_lane_u32((uint32_t *)(dst + 0 * dst_stride), d0123, 0);
d0123 = vld1q_lane_u32((uint32_t *)(dst + 1 * dst_stride), d0123, 1);
d0123 = vld1q_lane_u32((uint32_t *)(dst + 2 * dst_stride), d0123, 2);
d0123 = vld1q_lane_u32((uint32_t *)(dst + 3 * dst_stride), d0123, 3);
d0123 = vreinterpretq_u32_u8(
vrhaddq_u8(vreinterpretq_u8_u32(d0123), vcombine_u8(d01, d23)));
vst1q_lane_u32((uint32_t *)dst, d0123, 0);
dst += dst_stride;
vst1q_lane_u32((uint32_t *)dst, d0123, 1);
dst += dst_stride;
vst1q_lane_u32((uint32_t *)dst, d0123, 2);
dst += dst_stride;
vst1q_lane_u32((uint32_t *)dst, d0123, 3);
dst += dst_stride;
s0 = s4;
s1 = s5;
s2 = s6;
s3 = s7;
s4 = s8;
s5 = s9;
s6 = s10;
h -= 4;
} while (h > 0);
} else {
const int16x8_t filter3 = vdupq_lane_s16(vget_low_s16(filters), 3);
const int16x8_t filter4 = vdupq_lane_s16(vget_high_s16(filters), 0);
int height;
const uint8_t *s;
uint8_t *d;
uint8x8_t t0, t1, t2, t3;
uint8x16_t d01, d23, dd01, dd23;
int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
do {
__builtin_prefetch(src + 0 * src_stride);
__builtin_prefetch(src + 1 * src_stride);
__builtin_prefetch(src + 2 * src_stride);
__builtin_prefetch(src + 3 * src_stride);
__builtin_prefetch(src + 4 * src_stride);
__builtin_prefetch(src + 5 * src_stride);
__builtin_prefetch(src + 6 * src_stride);
s = src;
s0 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s1 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s2 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s3 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s4 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s5 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s6 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
d = dst;
height = h;
do {
s7 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s8 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s9 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
s10 = vreinterpretq_s16_u16(vmovl_u8(vld1_u8(s)));
s += src_stride;
__builtin_prefetch(d + 0 * dst_stride);
__builtin_prefetch(d + 1 * dst_stride);
__builtin_prefetch(d + 2 * dst_stride);
__builtin_prefetch(d + 3 * dst_stride);
__builtin_prefetch(s + 0 * src_stride);
__builtin_prefetch(s + 1 * src_stride);
__builtin_prefetch(s + 2 * src_stride);
__builtin_prefetch(s + 3 * src_stride);
t0 = convolve8_8(s0, s1, s2, s3, s4, s5, s6, s7, filters, filter3,
filter4);
t1 = convolve8_8(s1, s2, s3, s4, s5, s6, s7, s8, filters, filter3,
filter4);
t2 = convolve8_8(s2, s3, s4, s5, s6, s7, s8, s9, filters, filter3,
filter4);
t3 = convolve8_8(s3, s4, s5, s6, s7, s8, s9, s10, filters, filter3,
filter4);
d01 = vcombine_u8(t0, t1);
d23 = vcombine_u8(t2, t3);
dd01 = vcombine_u8(vld1_u8(d + 0 * dst_stride),
vld1_u8(d + 1 * dst_stride));
dd23 = vcombine_u8(vld1_u8(d + 2 * dst_stride),
vld1_u8(d + 3 * dst_stride));
dd01 = vrhaddq_u8(dd01, d01);
dd23 = vrhaddq_u8(dd23, d23);
vst1_u8(d, vget_low_u8(dd01));
d += dst_stride;
vst1_u8(d, vget_high_u8(dd01));
d += dst_stride;
vst1_u8(d, vget_low_u8(dd23));
d += dst_stride;
vst1_u8(d, vget_high_u8(dd23));
d += dst_stride;
s0 = s4;
s1 = s5;
s2 = s6;
s3 = s7;
s4 = s8;
s5 = s9;
s6 = s10;
height -= 4;
} while (height > 0);
src += 8;
dst += 8;
w -= 8;
} while (w > 0);
}
}
@@ -0,0 +1,138 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VPX_VPX_DSP_ARM_VPX_CONVOLVE8_NEON_H_
#define VPX_VPX_DSP_ARM_VPX_CONVOLVE8_NEON_H_
#include <arm_neon.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
static INLINE void load_u8_8x4(const uint8_t *s, const ptrdiff_t p,
uint8x8_t *const s0, uint8x8_t *const s1,
uint8x8_t *const s2, uint8x8_t *const s3) {
*s0 = vld1_u8(s);
s += p;
*s1 = vld1_u8(s);
s += p;
*s2 = vld1_u8(s);
s += p;
*s3 = vld1_u8(s);
}
static INLINE void load_u8_8x8(const uint8_t *s, const ptrdiff_t p,
uint8x8_t *const s0, uint8x8_t *const s1,
uint8x8_t *const s2, uint8x8_t *const s3,
uint8x8_t *const s4, uint8x8_t *const s5,
uint8x8_t *const s6, uint8x8_t *const s7) {
*s0 = vld1_u8(s);
s += p;
*s1 = vld1_u8(s);
s += p;
*s2 = vld1_u8(s);
s += p;
*s3 = vld1_u8(s);
s += p;
*s4 = vld1_u8(s);
s += p;
*s5 = vld1_u8(s);
s += p;
*s6 = vld1_u8(s);
s += p;
*s7 = vld1_u8(s);
}
static INLINE void load_u8_16x8(const uint8_t *s, const ptrdiff_t p,
uint8x16_t *const s0, uint8x16_t *const s1,
uint8x16_t *const s2, uint8x16_t *const s3,
uint8x16_t *const s4, uint8x16_t *const s5,
uint8x16_t *const s6, uint8x16_t *const s7) {
*s0 = vld1q_u8(s);
s += p;
*s1 = vld1q_u8(s);
s += p;
*s2 = vld1q_u8(s);
s += p;
*s3 = vld1q_u8(s);
s += p;
*s4 = vld1q_u8(s);
s += p;
*s5 = vld1q_u8(s);
s += p;
*s6 = vld1q_u8(s);
s += p;
*s7 = vld1q_u8(s);
}
static INLINE int16x4_t convolve8_4(const int16x4_t s0, const int16x4_t s1,
const int16x4_t s2, const int16x4_t s3,
const int16x4_t s4, const int16x4_t s5,
const int16x4_t s6, const int16x4_t s7,
const int16x8_t filters,
const int16x4_t filter3,
const int16x4_t filter4) {
const int16x4_t filters_lo = vget_low_s16(filters);
const int16x4_t filters_hi = vget_high_s16(filters);
int16x4_t sum;
sum = vmul_lane_s16(s0, filters_lo, 0);
sum = vmla_lane_s16(sum, s1, filters_lo, 1);
sum = vmla_lane_s16(sum, s2, filters_lo, 2);
sum = vmla_lane_s16(sum, s5, filters_hi, 1);
sum = vmla_lane_s16(sum, s6, filters_hi, 2);
sum = vmla_lane_s16(sum, s7, filters_hi, 3);
sum = vqadd_s16(sum, vmul_s16(s3, filter3));
sum = vqadd_s16(sum, vmul_s16(s4, filter4));
return sum;
}
static INLINE uint8x8_t convolve8_8(const int16x8_t s0, const int16x8_t s1,
const int16x8_t s2, const int16x8_t s3,
const int16x8_t s4, const int16x8_t s5,
const int16x8_t s6, const int16x8_t s7,
const int16x8_t filters,
const int16x8_t filter3,
const int16x8_t filter4) {
const int16x4_t filters_lo = vget_low_s16(filters);
const int16x4_t filters_hi = vget_high_s16(filters);
int16x8_t sum;
sum = vmulq_lane_s16(s0, filters_lo, 0);
sum = vmlaq_lane_s16(sum, s1, filters_lo, 1);
sum = vmlaq_lane_s16(sum, s2, filters_lo, 2);
sum = vmlaq_lane_s16(sum, s5, filters_hi, 1);
sum = vmlaq_lane_s16(sum, s6, filters_hi, 2);
sum = vmlaq_lane_s16(sum, s7, filters_hi, 3);
sum = vqaddq_s16(sum, vmulq_s16(s3, filter3));
sum = vqaddq_s16(sum, vmulq_s16(s4, filter4));
return vqrshrun_n_s16(sum, 7);
}
static INLINE uint8x8_t scale_filter_8(const uint8x8_t *const s,
const int16x8_t filters) {
const int16x8_t filter3 = vdupq_lane_s16(vget_low_s16(filters), 3);
const int16x8_t filter4 = vdupq_lane_s16(vget_high_s16(filters), 0);
int16x8_t ss[8];
ss[0] = vreinterpretq_s16_u16(vmovl_u8(s[0]));
ss[1] = vreinterpretq_s16_u16(vmovl_u8(s[1]));
ss[2] = vreinterpretq_s16_u16(vmovl_u8(s[2]));
ss[3] = vreinterpretq_s16_u16(vmovl_u8(s[3]));
ss[4] = vreinterpretq_s16_u16(vmovl_u8(s[4]));
ss[5] = vreinterpretq_s16_u16(vmovl_u8(s[5]));
ss[6] = vreinterpretq_s16_u16(vmovl_u8(s[6]));
ss[7] = vreinterpretq_s16_u16(vmovl_u8(s[7]));
return convolve8_8(ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7],
filters, filter3, filter4);
}
#endif // VPX_VPX_DSP_ARM_VPX_CONVOLVE8_NEON_H_
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2018 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "./vpx_dsp_rtcd.h"
#include "vp9/common/vp9_filter.h"
#include "vpx_dsp/arm/vpx_convolve8_neon_asm.h"
/* Type1 and Type2 functions are called depending on the position of the
* negative and positive coefficients in the filter. In type1, the filter kernel
* used is sub_pel_filters_8lp, in which only the first two and the last two
* coefficients are negative. In type2, the negative coefficients are 0, 2, 5 &
* 7.
*/
#define DEFINE_FILTER(dir) \
void vpx_convolve8_##dir##_neon( \
const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, \
ptrdiff_t dst_stride, const InterpKernel *filter, int x0_q4, \
int x_step_q4, int y0_q4, int y_step_q4, int w, int h) { \
if (filter == vp9_filter_kernels[1]) { \
vpx_convolve8_##dir##_filter_type1_neon( \
src, src_stride, dst, dst_stride, filter, x0_q4, x_step_q4, y0_q4, \
y_step_q4, w, h); \
} else { \
vpx_convolve8_##dir##_filter_type2_neon( \
src, src_stride, dst, dst_stride, filter, x0_q4, x_step_q4, y0_q4, \
y_step_q4, w, h); \
} \
}
DEFINE_FILTER(horiz);
DEFINE_FILTER(avg_horiz);
DEFINE_FILTER(vert);
DEFINE_FILTER(avg_vert);
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2018 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VPX_VPX_DSP_ARM_VPX_CONVOLVE8_NEON_ASM_H_
#define VPX_VPX_DSP_ARM_VPX_CONVOLVE8_NEON_ASM_H_
#define DECLARE_FILTER(dir, type) \
void vpx_convolve8_##dir##_filter_##type##_neon( \
const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, \
ptrdiff_t dst_stride, const InterpKernel *filter, int x0_q4, \
int x_step_q4, int y0_q4, int y_step_q4, int w, int h);
DECLARE_FILTER(horiz, type1);
DECLARE_FILTER(avg_horiz, type1);
DECLARE_FILTER(horiz, type2);
DECLARE_FILTER(avg_horiz, type2);
DECLARE_FILTER(vert, type1);
DECLARE_FILTER(avg_vert, type1);
DECLARE_FILTER(vert, type2);
DECLARE_FILTER(avg_vert, type2);
#endif // VPX_VPX_DSP_ARM_VPX_CONVOLVE8_NEON_ASM_H_
@@ -0,0 +1,457 @@
;
; Copyright (c) 2018 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
;**************Variables Vs Registers***********************************
; r0 => src
; r1 => dst
; r2 => src_stride
; r6 => dst_stride
; r12 => filter_y0
; r5 => ht
; r3 => wd
EXPORT |vpx_convolve8_vert_filter_type1_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
|vpx_convolve8_vert_filter_type1_neon| PROC
stmfd sp!, {r4 - r12, r14} ;stack stores the values of
; the arguments
vpush {d8 - d15} ; stack offset by 64
mov r4, r1
mov r1, r2
mov r2, r4
vmov.i16 q15, #0x4000
mov r11, #0xc000
ldr r12, [sp, #104] ;load filter
ldr r6, [sp, #116] ;load y0_q4
add r12, r12, r6, lsl #4 ;r12 = filter[y0_q4]
mov r6, r3
ldr r5, [sp, #124] ;load wd
vld2.8 {d0, d1}, [r12] ;coeff = vld1_s8(pi1_coeff)
sub r12, r2, r2, lsl #2 ;src_ctrd & pi1_coeff
vabs.s8 d0, d0 ;vabs_s8(coeff)
add r0, r0, r12 ;r0->pu1_src r12->pi1_coeff
ldr r3, [sp, #128] ;load ht
subs r7, r3, #0 ;r3->ht
vdup.u8 d22, d0[0] ;coeffabs_0 = vdup_lane_u8(coeffabs,
; 0);
cmp r5, #8
vdup.u8 d23, d0[1] ;coeffabs_1 = vdup_lane_u8(coeffabs,
; 1);
vdup.u8 d24, d0[2] ;coeffabs_2 = vdup_lane_u8(coeffabs,
; 2);
vdup.u8 d25, d0[3] ;coeffabs_3 = vdup_lane_u8(coeffabs,
; 3);
vdup.u8 d26, d0[4] ;coeffabs_4 = vdup_lane_u8(coeffabs,
; 4);
vdup.u8 d27, d0[5] ;coeffabs_5 = vdup_lane_u8(coeffabs,
; 5);
vdup.u8 d28, d0[6] ;coeffabs_6 = vdup_lane_u8(coeffabs,
; 6);
vdup.u8 d29, d0[7] ;coeffabs_7 = vdup_lane_u8(coeffabs,
; 7);
blt core_loop_wd_4 ;core loop wd 4 jump
str r0, [sp, #-4]!
str r1, [sp, #-4]!
bic r4, r5, #7 ;r5 ->wd
rsb r9, r4, r6, lsl #2 ;r6->dst_strd r5 ->wd
rsb r8, r4, r2, lsl #2 ;r2->src_strd
mov r3, r5, lsr #3 ;divide by 8
mul r7, r3 ;multiply height by width
sub r7, #4 ;subtract by one for epilog
prolog
and r10, r0, #31
add r3, r0, r2 ;pu1_src_tmp += src_strd;
vdup.16 q4, r11
vld1.u8 {d1}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vld1.u8 {d0}, [r0]! ;src_tmp1 = vld1_u8(pu1_src_tmp);
subs r4, r4, #8
vld1.u8 {d2}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d1, d23 ;mul_res1 = vmull_u8(src_tmp2,
; coeffabs_1);
vld1.u8 {d3}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d0, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp1, coeffabs_0);
vld1.u8 {d4}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d2, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp3, coeffabs_2);
vld1.u8 {d5}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d3, d25 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp4, coeffabs_3);
vld1.u8 {d6}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp1, coeffabs_4);
vld1.u8 {d7}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d5, d27 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp2, coeffabs_5);
vld1.u8 {d16}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp3, coeffabs_6);
vld1.u8 {d17}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d7, d29 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp4, coeffabs_7);
vdup.16 q5, r11
vld1.u8 {d18}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q5, d2, d23 ;mul_res2 = vmull_u8(src_tmp3,
; coeffabs_1);
addle r0, r0, r8
vmlsl.u8 q5, d1, d22 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp2, coeffabs_0);
bicle r4, r5, #7 ;r5 ->wd
vmlal.u8 q5, d3, d24 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp4, coeffabs_2);
pld [r3]
vmlal.u8 q5, d4, d25 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp1, coeffabs_3);
vhadd.s16 q4, q4, q15
vdup.16 q6, r11
pld [r3, r2]
vmlal.u8 q5, d5, d26 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp2, coeffabs_4);
pld [r3, r2, lsl #1]
vmlal.u8 q5, d6, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp3, coeffabs_5);
add r3, r3, r2
vmlsl.u8 q5, d7, d28 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp4, coeffabs_6);
pld [r3, r2, lsl #1]
vmlsl.u8 q5, d16, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp1, coeffabs_7);
add r3, r0, r2 ;pu1_src_tmp += src_strd;
vqrshrun.s16 d8, q4, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u8 {d1}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q6, d3, d23
vld1.u8 {d0}, [r0]! ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q6, d2, d22
vld1.u8 {d2}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q6, d4, d24
vhadd.s16 q5, q5, q15
vdup.16 q7, r11
vmlal.u8 q6, d5, d25
vmlal.u8 q6, d6, d26
vmlal.u8 q6, d7, d27
vmlsl.u8 q6, d16, d28
vmlsl.u8 q6, d17, d29
add r14, r1, r6
vst1.8 {d8}, [r1]! ;vst1_u8(pu1_dst,sto_res);
vqrshrun.s16 d10, q5, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
addle r1, r1, r9
vmlsl.u8 q7, d4, d23
subs r7, r7, #4
vmlsl.u8 q7, d3, d22
vmlal.u8 q7, d5, d24
vmlal.u8 q7, d6, d25
vld1.u8 {d3}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vhadd.s16 q6, q6, q15
vdup.16 q4, r11
vmlal.u8 q7, d7, d26
vld1.u8 {d4}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q7, d16, d27
vld1.u8 {d5}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d17, d28
vld1.u8 {d6}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d18, d29
vld1.u8 {d7}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vst1.8 {d10}, [r14], r6 ;vst1_u8(pu1_dst_tmp,sto_res);
vqrshrun.s16 d12, q6, #6
blt epilog_end ;jumps to epilog_end
beq epilog ;jumps to epilog
main_loop_8
subs r4, r4, #8
vmlsl.u8 q4, d1, d23 ;mul_res1 = vmull_u8(src_tmp2,
; coeffabs_1);
addle r0, r0, r8
vmlsl.u8 q4, d0, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp1, coeffabs_0);
bicle r4, r5, #7 ;r5 ->wd
vmlal.u8 q4, d2, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp3, coeffabs_2);
vld1.u8 {d16}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d3, d25 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp4, coeffabs_3);
vhadd.s16 q7, q7, q15
vdup.16 q5, r11
vld1.u8 {d17}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp1, coeffabs_4);
vld1.u8 {d18}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d5, d27 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp2, coeffabs_5);
vmlsl.u8 q4, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp3, coeffabs_6);
vmlsl.u8 q4, d7, d29 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp4, coeffabs_7);
vst1.8 {d12}, [r14], r6
vqrshrun.s16 d14, q7, #6
add r3, r0, r2 ;pu1_src_tmp += src_strd;
vmlsl.u8 q5, d2, d23 ;mul_res2 = vmull_u8(src_tmp3,
; coeffabs_1);
vld1.u8 {d0}, [r0]! ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q5, d1, d22 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp2, coeffabs_0);
vmlal.u8 q5, d3, d24 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp4, coeffabs_2);
vld1.u8 {d1}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q5, d4, d25 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp1, coeffabs_3);
vhadd.s16 q4, q4, q15
vdup.16 q6, r11
vst1.8 {d14}, [r14], r6
vmlal.u8 q5, d5, d26 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp2, coeffabs_4);
add r14, r1, #0
vmlal.u8 q5, d6, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp3, coeffabs_5);
add r1, r1, #8
vmlsl.u8 q5, d7, d28 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp4, coeffabs_6);
vmlsl.u8 q5, d16, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp1, coeffabs_7);
addle r1, r1, r9
vqrshrun.s16 d8, q4, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vmlsl.u8 q6, d3, d23
add r10, r3, r2, lsl #3 ; 10*strd - 8+2
vmlsl.u8 q6, d2, d22
add r10, r10, r2 ; 11*strd
vmlal.u8 q6, d4, d24
vld1.u8 {d2}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q6, d5, d25
vhadd.s16 q5, q5, q15
vdup.16 q7, r11
vmlal.u8 q6, d6, d26
vst1.8 {d8}, [r14], r6 ;vst1_u8(pu1_dst,sto_res);
pld [r10] ;11+ 0
vmlal.u8 q6, d7, d27
pld [r10, r2] ;11+ 1*strd
vmlsl.u8 q6, d16, d28
pld [r10, r2, lsl #1] ;11+ 2*strd
vmlsl.u8 q6, d17, d29
add r10, r10, r2 ;12*strd
vqrshrun.s16 d10, q5, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
pld [r10, r2, lsl #1] ;11+ 3*strd
vmlsl.u8 q7, d4, d23
vmlsl.u8 q7, d3, d22
subs r7, r7, #4
vmlal.u8 q7, d5, d24
vmlal.u8 q7, d6, d25
vld1.u8 {d3}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vhadd.s16 q6, q6, q15
vdup.16 q4, r11
vmlal.u8 q7, d7, d26
vld1.u8 {d4}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q7, d16, d27
vld1.u8 {d5}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d17, d28
vld1.u8 {d6}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d18, d29
vld1.u8 {d7}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vqrshrun.s16 d12, q6, #6
vst1.8 {d10}, [r14], r6 ;vst1_u8(pu1_dst_tmp,sto_res);
bgt main_loop_8 ;jumps to main_loop_8
epilog
vmlsl.u8 q4, d1, d23 ;mul_res1 = vmull_u8(src_tmp2,
; coeffabs_1);
vmlsl.u8 q4, d0, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp1, coeffabs_0);
vmlal.u8 q4, d2, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp3, coeffabs_2);
vmlal.u8 q4, d3, d25 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp4, coeffabs_3);
vhadd.s16 q7, q7, q15
vdup.16 q5, r11
vmlal.u8 q4, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp1, coeffabs_4);
vmlal.u8 q4, d5, d27 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp2, coeffabs_5);
vmlsl.u8 q4, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp3, coeffabs_6);
vmlsl.u8 q4, d7, d29 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp4, coeffabs_7);
vst1.8 {d12}, [r14], r6
vqrshrun.s16 d14, q7, #6
vld1.u8 {d16}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q5, d2, d23 ;mul_res2 = vmull_u8(src_tmp3,
; coeffabs_1);
vmlsl.u8 q5, d1, d22 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp2, coeffabs_0);
vmlal.u8 q5, d3, d24 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp4, coeffabs_2);
vmlal.u8 q5, d4, d25 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp1, coeffabs_3);
vhadd.s16 q4, q4, q15
vdup.16 q6, r11
vmlal.u8 q5, d5, d26 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp2, coeffabs_4);
vmlal.u8 q5, d6, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp3, coeffabs_5);
vmlsl.u8 q5, d7, d28 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp4, coeffabs_6);
vmlsl.u8 q5, d16, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp1, coeffabs_7);
vst1.8 {d14}, [r14], r6
vqrshrun.s16 d8, q4, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u8 {d17}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q6, d3, d23
vmlsl.u8 q6, d2, d22
vmlal.u8 q6, d4, d24
vmlal.u8 q6, d5, d25
vhadd.s16 q5, q5, q15
vdup.16 q7, r11
vmlal.u8 q6, d6, d26
vmlal.u8 q6, d7, d27
vmlsl.u8 q6, d16, d28
vmlsl.u8 q6, d17, d29
add r14, r1, r6
vst1.8 {d8}, [r1]! ;vst1_u8(pu1_dst,sto_res);
vqrshrun.s16 d10, q5, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u8 {d18}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d4, d23
vmlsl.u8 q7, d3, d22
vmlal.u8 q7, d5, d24
vmlal.u8 q7, d6, d25
vhadd.s16 q6, q6, q15
vmlal.u8 q7, d7, d26
vmlal.u8 q7, d16, d27
vmlsl.u8 q7, d17, d28
vmlsl.u8 q7, d18, d29
vst1.8 {d10}, [r14], r6 ;vst1_u8(pu1_dst_tmp,sto_res);
vqrshrun.s16 d12, q6, #6
epilog_end
vst1.8 {d12}, [r14], r6
vhadd.s16 q7, q7, q15
vqrshrun.s16 d14, q7, #6
vst1.8 {d14}, [r14], r6
end_loops
tst r5, #7
ldr r1, [sp], #4
ldr r0, [sp], #4
vpopeq {d8 - d15}
ldmfdeq sp!, {r4 - r12, r15} ;reload the registers from
; sp
mov r5, #4
add r0, r0, #8
add r1, r1, #8
mov r7, #16
core_loop_wd_4
rsb r9, r5, r6, lsl #2 ;r6->dst_strd r5 ->wd
rsb r8, r5, r2, lsl #2 ;r2->src_strd
vmov.i8 d4, #0
outer_loop_wd_4
subs r12, r5, #0
ble end_inner_loop_wd_4 ;outer loop jump
inner_loop_wd_4
add r3, r0, r2
vld1.u32 {d4[1]},[r3], r2 ;src_tmp1 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp1, 1);
subs r12, r12, #4
vdup.u32 d5, d4[1] ;src_tmp2 = vdup_lane_u32(src_tmp1,
; 1);
vld1.u32 {d5[1]},[r3], r2 ;src_tmp2 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp2, 1);
vld1.u32 {d4[0]},[r0] ;src_tmp1 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp1, 0);
vdup.16 q0, r11
vmlsl.u8 q0, d5, d23 ;mul_res1 =
; vmull_u8(vreinterpret_u8_u32(src_tmp2), coeffabs_1);
vdup.u32 d6, d5[1] ;src_tmp3 = vdup_lane_u32(src_tmp2,
; 1);
add r0, r0, #4
vld1.u32 {d6[1]},[r3], r2 ;src_tmp3 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp3, 1);
vmlsl.u8 q0, d4, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp1), coeffabs_0);
vdup.u32 d7, d6[1] ;src_tmp4 = vdup_lane_u32(src_tmp3,
; 1);
vld1.u32 {d7[1]},[r3], r2 ;src_tmp4 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp4, 1);
vmlal.u8 q0, d6, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp3), coeffabs_2);
vdup.16 q4, r11
vmlsl.u8 q4, d7, d23
vdup.u32 d4, d7[1] ;src_tmp1 = vdup_lane_u32(src_tmp4,
; 1);
vmull.u8 q1, d7, d25 ;mul_res2 =
; vmull_u8(vreinterpret_u8_u32(src_tmp4), coeffabs_3);
vld1.u32 {d4[1]},[r3], r2 ;src_tmp1 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp1, 1);
vmlsl.u8 q4, d6, d22
vmlal.u8 q0, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp1), coeffabs_4);
vdup.u32 d5, d4[1] ;src_tmp2 = vdup_lane_u32(src_tmp1,
; 1);
vmlal.u8 q4, d4, d24
vld1.u32 {d5[1]},[r3], r2 ;src_tmp2 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp2, 1);
vmlal.u8 q1, d5, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; vreinterpret_u8_u32(src_tmp2), coeffabs_5);
vdup.u32 d6, d5[1] ;src_tmp3 = vdup_lane_u32(src_tmp2,
; 1);
vmlal.u8 q4, d5, d25
vld1.u32 {d6[1]},[r3], r2 ;src_tmp3 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp3, 1);
vmlsl.u8 q0, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp3), coeffabs_6);
vdup.u32 d7, d6[1] ;src_tmp4 = vdup_lane_u32(src_tmp3,
; 1);
vmlal.u8 q4, d6, d26
vld1.u32 {d7[1]},[r3], r2 ;src_tmp4 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp4, 1);
vmlsl.u8 q1, d7, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; vreinterpret_u8_u32(src_tmp4), coeffabs_7);
vdup.u32 d4, d7[1]
vadd.i16 q0, q0, q1 ;mul_res1 = vaddq_u16(mul_res1,
; mul_res2);
vmlal.u8 q4, d7, d27
vld1.u32 {d4[1]},[r3], r2
vmlsl.u8 q4, d4, d28
vdup.u32 d5, d4[1]
vhadd.s16 q0, q0, q15
vqrshrun.s16 d0, q0, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u32 {d5[1]},[r3]
add r3, r1, r6
vst1.32 {d0[0]},[r1] ;vst1_lane_u32((uint32_t *)pu1_dst,
; vreinterpret_u32_u8(sto_res), 0);
vmlsl.u8 q4, d5, d29
vst1.32 {d0[1]},[r3], r6 ;vst1_lane_u32((uint32_t
; *)pu1_dst_tmp, vreinterpret_u32_u8(sto_res), 1);
vhadd.s16 q4, q4, q15
vqrshrun.s16 d8, q4, #6
vst1.32 {d8[0]},[r3], r6
add r1, r1, #4
vst1.32 {d8[1]},[r3]
bgt inner_loop_wd_4
end_inner_loop_wd_4
subs r7, r7, #4
add r1, r1, r9
add r0, r0, r8
bgt outer_loop_wd_4
vpop {d8 - d15}
ldmfd sp!, {r4 - r12, r15} ;reload the registers from sp
ENDP
END
@@ -0,0 +1,455 @@
;
; Copyright (c) 2018 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
;**************Variables Vs Registers***********************************
; r0 => src
; r1 => dst
; r2 => src_stride
; r6 => dst_stride
; r12 => filter_y0
; r5 => ht
; r3 => wd
EXPORT |vpx_convolve8_vert_filter_type2_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
|vpx_convolve8_vert_filter_type2_neon| PROC
stmfd sp!, {r4 - r12, r14} ;stack stores the values of
; the arguments
vpush {d8 - d15} ; stack offset by 64
mov r4, r1
mov r1, r2
mov r2, r4
vmov.i16 q15, #0x4000
mov r11, #0xc000
ldr r12, [sp, #104] ;load filter
ldr r6, [sp, #116] ;load y0_q4
add r12, r12, r6, lsl #4 ;r12 = filter[y0_q4]
mov r6, r3
ldr r5, [sp, #124] ;load wd
vld2.8 {d0, d1}, [r12] ;coeff = vld1_s8(pi1_coeff)
sub r12, r2, r2, lsl #2 ;src_ctrd & pi1_coeff
vabs.s8 d0, d0 ;vabs_s8(coeff)
add r0, r0, r12 ;r0->pu1_src r12->pi1_coeff
ldr r3, [sp, #128] ;load ht
subs r7, r3, #0 ;r3->ht
vdup.u8 d22, d0[0] ;coeffabs_0 = vdup_lane_u8(coeffabs,
; 0);
cmp r5, #8
vdup.u8 d23, d0[1] ;coeffabs_1 = vdup_lane_u8(coeffabs,
; 1);
vdup.u8 d24, d0[2] ;coeffabs_2 = vdup_lane_u8(coeffabs,
; 2);
vdup.u8 d25, d0[3] ;coeffabs_3 = vdup_lane_u8(coeffabs,
; 3);
vdup.u8 d26, d0[4] ;coeffabs_4 = vdup_lane_u8(coeffabs,
; 4);
vdup.u8 d27, d0[5] ;coeffabs_5 = vdup_lane_u8(coeffabs,
; 5);
vdup.u8 d28, d0[6] ;coeffabs_6 = vdup_lane_u8(coeffabs,
; 6);
vdup.u8 d29, d0[7] ;coeffabs_7 = vdup_lane_u8(coeffabs,
; 7);
blt core_loop_wd_4 ;core loop wd 4 jump
str r0, [sp, #-4]!
str r1, [sp, #-4]!
bic r4, r5, #7 ;r5 ->wd
rsb r9, r4, r6, lsl #2 ;r6->dst_strd r5 ->wd
rsb r8, r4, r2, lsl #2 ;r2->src_strd
mov r3, r5, lsr #3 ;divide by 8
mul r7, r3 ;multiply height by width
sub r7, #4 ;subtract by one for epilog
prolog
and r10, r0, #31
add r3, r0, r2 ;pu1_src_tmp += src_strd;
vdup.16 q4, r11
vld1.u8 {d1}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vld1.u8 {d0}, [r0]! ;src_tmp1 = vld1_u8(pu1_src_tmp);
subs r4, r4, #8
vld1.u8 {d2}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d1, d23 ;mul_res1 = vmull_u8(src_tmp2,
; coeffabs_1);
vld1.u8 {d3}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d0, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp1, coeffabs_0);
vld1.u8 {d4}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d2, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp3, coeffabs_2);
vld1.u8 {d5}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d3, d25 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp4, coeffabs_3);
vld1.u8 {d6}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp1, coeffabs_4);
vld1.u8 {d7}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d5, d27 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp2, coeffabs_5);
vld1.u8 {d16}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp3, coeffabs_6);
vld1.u8 {d17}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d7, d29 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp4, coeffabs_7);
vdup.16 q5, r11
vld1.u8 {d18}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q5, d2, d23 ;mul_res2 = vmull_u8(src_tmp3,
; coeffabs_1);
addle r0, r0, r8
vmlsl.u8 q5, d1, d22 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp2, coeffabs_0);
bicle r4, r5, #7 ;r5 ->wd
vmlsl.u8 q5, d3, d24 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp4, coeffabs_2);
pld [r3]
vmlal.u8 q5, d4, d25 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp1, coeffabs_3);
vhadd.s16 q4, q4, q15
vdup.16 q6, r11
pld [r3, r2]
vmlal.u8 q5, d5, d26 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp2, coeffabs_4);
pld [r3, r2, lsl #1]
vmlsl.u8 q5, d6, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp3, coeffabs_5);
add r3, r3, r2
vmlal.u8 q5, d7, d28 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp4, coeffabs_6);
pld [r3, r2, lsl #1]
vmlsl.u8 q5, d16, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp1, coeffabs_7);
add r3, r0, r2 ;pu1_src_tmp += src_strd;
vqrshrun.s16 d8, q4, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u8 {d1}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q6, d3, d23
vld1.u8 {d0}, [r0]! ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q6, d2, d22
vld1.u8 {d2}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q6, d4, d24
vhadd.s16 q5, q5, q15
vdup.16 q7, r11
vmlal.u8 q6, d5, d25
vmlal.u8 q6, d6, d26
vmlsl.u8 q6, d7, d27
vmlal.u8 q6, d16, d28
vmlsl.u8 q6, d17, d29
add r14, r1, r6
vst1.8 {d8}, [r1]! ;vst1_u8(pu1_dst,sto_res);
vqrshrun.s16 d10, q5, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
addle r1, r1, r9
vmlal.u8 q7, d4, d23
subs r7, r7, #4
vmlsl.u8 q7, d3, d22
vmlsl.u8 q7, d5, d24
vmlal.u8 q7, d6, d25
vld1.u8 {d3}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vhadd.s16 q6, q6, q15
vdup.16 q4, r11
vmlal.u8 q7, d7, d26
vld1.u8 {d4}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d16, d27
vld1.u8 {d5}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q7, d17, d28
vld1.u8 {d6}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d18, d29
vld1.u8 {d7}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vst1.8 {d10}, [r14], r6 ;vst1_u8(pu1_dst_tmp,sto_res);
vqrshrun.s16 d12, q6, #6
blt epilog_end ;jumps to epilog_end
beq epilog ;jumps to epilog
main_loop_8
subs r4, r4, #8
vmlal.u8 q4, d1, d23 ;mul_res1 = vmull_u8(src_tmp2,
; coeffabs_1);
addle r0, r0, r8
vmlsl.u8 q4, d0, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp1, coeffabs_0);
bicle r4, r5, #7 ;r5 ->wd
vmlsl.u8 q4, d2, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp3, coeffabs_2);
vld1.u8 {d16}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d3, d25 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp4, coeffabs_3);
vhadd.s16 q7, q7, q15
vdup.16 q5, r11
vld1.u8 {d17}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q4, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp1, coeffabs_4);
vld1.u8 {d18}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q4, d5, d27 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp2, coeffabs_5);
vmlal.u8 q4, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp3, coeffabs_6);
vmlsl.u8 q4, d7, d29 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp4, coeffabs_7);
vst1.8 {d12}, [r14], r6
vqrshrun.s16 d14, q7, #6
add r3, r0, r2 ;pu1_src_tmp += src_strd;
vmlal.u8 q5, d2, d23 ;mul_res2 = vmull_u8(src_tmp3,
; coeffabs_1);
vld1.u8 {d0}, [r0]! ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q5, d1, d22 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp2, coeffabs_0);
vmlsl.u8 q5, d3, d24 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp4, coeffabs_2);
vld1.u8 {d1}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q5, d4, d25 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp1, coeffabs_3);
vhadd.s16 q4, q4, q15
vdup.16 q6, r11
vst1.8 {d14}, [r14], r6
vmlal.u8 q5, d5, d26 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp2, coeffabs_4);
add r14, r1, #0
vmlsl.u8 q5, d6, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp3, coeffabs_5);
add r1, r1, #8
vmlal.u8 q5, d7, d28 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp4, coeffabs_6);
vmlsl.u8 q5, d16, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp1, coeffabs_7);
addle r1, r1, r9
vqrshrun.s16 d8, q4, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vmlal.u8 q6, d3, d23
add r10, r3, r2, lsl #3 ; 10*strd - 8+2
vmlsl.u8 q6, d2, d22
add r10, r10, r2 ; 11*strd
vmlsl.u8 q6, d4, d24
vld1.u8 {d2}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q6, d5, d25
vhadd.s16 q5, q5, q15
vdup.16 q7, r11
vmlal.u8 q6, d6, d26
vst1.8 {d8}, [r14], r6 ;vst1_u8(pu1_dst,sto_res);
pld [r10] ;11+ 0
vmlsl.u8 q6, d7, d27
pld [r10, r2] ;11+ 1*strd
vmlal.u8 q6, d16, d28
pld [r10, r2, lsl #1] ;11+ 2*strd
vmlsl.u8 q6, d17, d29
add r10, r10, r2 ;12*strd
vqrshrun.s16 d10, q5, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
pld [r10, r2, lsl #1] ;11+ 3*strd
vmlal.u8 q7, d4, d23
vmlsl.u8 q7, d3, d22
subs r7, r7, #4
vmlsl.u8 q7, d5, d24
vmlal.u8 q7, d6, d25
vld1.u8 {d3}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vhadd.s16 q6, q6, q15
vdup.16 q4, r11
vmlal.u8 q7, d7, d26
vld1.u8 {d4}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d16, d27
vld1.u8 {d5}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q7, d17, d28
vld1.u8 {d6}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlsl.u8 q7, d18, d29
vld1.u8 {d7}, [r3], r2 ;src_tmp4 = vld1_u8(pu1_src_tmp);
vqrshrun.s16 d12, q6, #6
vst1.8 {d10}, [r14], r6 ;vst1_u8(pu1_dst_tmp,sto_res);
bgt main_loop_8 ;jumps to main_loop_8
epilog
vmlal.u8 q4, d1, d23 ;mul_res1 = vmull_u8(src_tmp2,
vmlsl.u8 q4, d0, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp1, coeffabs_0);
vmlsl.u8 q4, d2, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp3, coeffabs_2);
vmlal.u8 q4, d3, d25 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp4, coeffabs_3);
vhadd.s16 q7, q7, q15
vdup.16 q5, r11
vmlal.u8 q4, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp1, coeffabs_4);
vmlsl.u8 q4, d5, d27 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp2, coeffabs_5);
vmlal.u8 q4, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; src_tmp3, coeffabs_6);
vmlsl.u8 q4, d7, d29 ;mul_res1 = vmlsl_u8(mul_res1,
; src_tmp4, coeffabs_7);
vst1.8 {d12}, [r14], r6
vqrshrun.s16 d14, q7, #6
vld1.u8 {d16}, [r3], r2 ;src_tmp1 = vld1_u8(pu1_src_tmp);
vmlal.u8 q5, d2, d23 ;mul_res2 = vmull_u8(src_tmp3,
; coeffabs_1);
vmlsl.u8 q5, d1, d22 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp2, coeffabs_0);
vmlsl.u8 q5, d3, d24 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp4, coeffabs_2);
vmlal.u8 q5, d4, d25 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp1, coeffabs_3);
vhadd.s16 q4, q4, q15
vdup.16 q6, r11
vmlal.u8 q5, d5, d26 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp2, coeffabs_4);
vmlsl.u8 q5, d6, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp3, coeffabs_5);
vmlal.u8 q5, d7, d28 ;mul_res2 = vmlal_u8(mul_res2,
; src_tmp4, coeffabs_6);
vmlsl.u8 q5, d16, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; src_tmp1, coeffabs_7);
vst1.8 {d14}, [r14], r6
vqrshrun.s16 d8, q4, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u8 {d17}, [r3], r2 ;src_tmp2 = vld1_u8(pu1_src_tmp);
vmlal.u8 q6, d3, d23
vmlsl.u8 q6, d2, d22
vmlsl.u8 q6, d4, d24
vmlal.u8 q6, d5, d25
vhadd.s16 q5, q5, q15
vdup.16 q7, r11
vmlal.u8 q6, d6, d26
vmlsl.u8 q6, d7, d27
vmlal.u8 q6, d16, d28
vmlsl.u8 q6, d17, d29
add r14, r1, r6
vst1.8 {d8}, [r1]! ;vst1_u8(pu1_dst,sto_res);
vqrshrun.s16 d10, q5, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u8 {d18}, [r3], r2 ;src_tmp3 = vld1_u8(pu1_src_tmp);
vmlal.u8 q7, d4, d23
vmlsl.u8 q7, d3, d22
vmlsl.u8 q7, d5, d24
vmlal.u8 q7, d6, d25
vhadd.s16 q6, q6, q15
vmlal.u8 q7, d7, d26
vmlsl.u8 q7, d16, d27
vmlal.u8 q7, d17, d28
vmlsl.u8 q7, d18, d29
vst1.8 {d10}, [r14], r6 ;vst1_u8(pu1_dst_tmp,sto_res);
vqrshrun.s16 d12, q6, #6
epilog_end
vst1.8 {d12}, [r14], r6
vhadd.s16 q7, q7, q15
vqrshrun.s16 d14, q7, #6
vst1.8 {d14}, [r14], r6
end_loops
tst r5, #7
ldr r1, [sp], #4
ldr r0, [sp], #4
vpopeq {d8 - d15}
ldmfdeq sp!, {r4 - r12, r15} ;reload the registers from sp
mov r5, #4
add r0, r0, #8
add r1, r1, #8
mov r7, #16
core_loop_wd_4
rsb r9, r5, r6, lsl #2 ;r6->dst_strd r5 ->wd
rsb r8, r5, r2, lsl #2 ;r2->src_strd
vmov.i8 d4, #0
outer_loop_wd_4
subs r12, r5, #0
ble end_inner_loop_wd_4 ;outer loop jump
inner_loop_wd_4
add r3, r0, r2
vld1.u32 {d4[1]},[r3], r2 ;src_tmp1 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp1, 1);
subs r12, r12, #4
vdup.u32 d5, d4[1] ;src_tmp2 = vdup_lane_u32(src_tmp1,
; 1);
vld1.u32 {d5[1]},[r3], r2 ;src_tmp2 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp2, 1);
vld1.u32 {d4[0]},[r0] ;src_tmp1 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp1, 0);
vdup.16 q0, r11
vmlal.u8 q0, d5, d23 ;mul_res1 =
; vmull_u8(vreinterpret_u8_u32(src_tmp2), coeffabs_1);
vdup.u32 d6, d5[1] ;src_tmp3 = vdup_lane_u32(src_tmp2,
; 1);
add r0, r0, #4
vld1.u32 {d6[1]},[r3], r2 ;src_tmp3 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp3, 1);
vmlsl.u8 q0, d4, d22 ;mul_res1 = vmlsl_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp1), coeffabs_0);
vdup.u32 d7, d6[1] ;src_tmp4 = vdup_lane_u32(src_tmp3,
; 1);
vld1.u32 {d7[1]},[r3], r2 ;src_tmp4 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp4, 1);
vmlsl.u8 q0, d6, d24 ;mul_res1 = vmlsl_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp3), coeffabs_2);
vdup.16 q4, r11
vmlal.u8 q4, d7, d23
vdup.u32 d4, d7[1] ;src_tmp1 = vdup_lane_u32(src_tmp4,
; 1);
vmull.u8 q1, d7, d25 ;mul_res2 =
; vmull_u8(vreinterpret_u8_u32(src_tmp4), coeffabs_3);
vld1.u32 {d4[1]},[r3], r2 ;src_tmp1 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp1, 1);
vmlsl.u8 q4, d6, d22
vmlal.u8 q0, d4, d26 ;mul_res1 = vmlal_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp1), coeffabs_4);
vdup.u32 d5, d4[1] ;src_tmp2 = vdup_lane_u32(src_tmp1,
; 1);
vmlsl.u8 q4, d4, d24
vld1.u32 {d5[1]},[r3], r2 ;src_tmp2 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp2, 1);
vmlsl.u8 q1, d5, d27 ;mul_res2 = vmlsl_u8(mul_res2,
; vreinterpret_u8_u32(src_tmp2), coeffabs_5);
vdup.u32 d6, d5[1] ;src_tmp3 = vdup_lane_u32(src_tmp2,
; 1);
vmlal.u8 q4, d5, d25
vld1.u32 {d6[1]},[r3], r2 ;src_tmp3 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp3, 1);
vmlal.u8 q0, d6, d28 ;mul_res1 = vmlal_u8(mul_res1,
; vreinterpret_u8_u32(src_tmp3), coeffabs_6);
vdup.u32 d7, d6[1] ;src_tmp4 = vdup_lane_u32(src_tmp3,
; 1);
vmlal.u8 q4, d6, d26
vld1.u32 {d7[1]},[r3], r2 ;src_tmp4 = vld1_lane_u32((uint32_t
; *)pu1_src_tmp, src_tmp4, 1);
vmlsl.u8 q1, d7, d29 ;mul_res2 = vmlsl_u8(mul_res2,
; vreinterpret_u8_u32(src_tmp4), coeffabs_7);
vdup.u32 d4, d7[1]
vadd.i16 q0, q0, q1 ;mul_res1 = vaddq_u16(mul_res1,
; mul_res2);
vmlsl.u8 q4, d7, d27
vld1.u32 {d4[1]},[r3], r2
vmlal.u8 q4, d4, d28
vdup.u32 d5, d4[1]
vhadd.s16 q0, q0, q15
vqrshrun.s16 d0, q0, #6 ;sto_res = vqmovun_s16(sto_res_tmp);
vld1.u32 {d5[1]},[r3]
add r3, r1, r6
vst1.32 {d0[0]},[r1] ;vst1_lane_u32((uint32_t *)pu1_dst,
; vreinterpret_u32_u8(sto_res), 0);
vmlsl.u8 q4, d5, d29
vst1.32 {d0[1]},[r3], r6 ;vst1_lane_u32((uint32_t
; *)pu1_dst_tmp, vreinterpret_u32_u8(sto_res), 1);
vhadd.s16 q4, q4, q15
vqrshrun.s16 d8, q4, #6
vst1.32 {d8[0]},[r3], r6
add r1, r1, #4
vst1.32 {d8[1]},[r3]
bgt inner_loop_wd_4
end_inner_loop_wd_4
subs r7, r7, #4
add r1, r1, r9
add r0, r0, r8
bgt outer_loop_wd_4
vpop {d8 - d15}
ldmfd sp!, {r4 - r12, r15} ;reload the registers from sp
ENDP
END
@@ -0,0 +1,139 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
void vpx_convolve_avg_neon(const uint8_t *src, ptrdiff_t src_stride,
uint8_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4, int x_step_q4,
int y0_q4, int y_step_q4, int w, int h) {
(void)filter;
(void)x0_q4;
(void)x_step_q4;
(void)y0_q4;
(void)y_step_q4;
if (w < 8) { // avg4
uint8x8_t s0, s1;
uint8x8_t dd0 = vdup_n_u8(0);
uint32x2x2_t s01;
do {
s0 = vld1_u8(src);
src += src_stride;
s1 = vld1_u8(src);
src += src_stride;
s01 = vzip_u32(vreinterpret_u32_u8(s0), vreinterpret_u32_u8(s1));
dd0 = vreinterpret_u8_u32(
vld1_lane_u32((const uint32_t *)dst, vreinterpret_u32_u8(dd0), 0));
dd0 = vreinterpret_u8_u32(vld1_lane_u32(
(const uint32_t *)(dst + dst_stride), vreinterpret_u32_u8(dd0), 1));
dd0 = vrhadd_u8(vreinterpret_u8_u32(s01.val[0]), dd0);
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(dd0), 0);
dst += dst_stride;
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(dd0), 1);
dst += dst_stride;
h -= 2;
} while (h > 0);
} else if (w == 8) { // avg8
uint8x8_t s0, s1, d0, d1;
uint8x16_t s01, d01;
do {
s0 = vld1_u8(src);
src += src_stride;
s1 = vld1_u8(src);
src += src_stride;
d0 = vld1_u8(dst);
d1 = vld1_u8(dst + dst_stride);
s01 = vcombine_u8(s0, s1);
d01 = vcombine_u8(d0, d1);
d01 = vrhaddq_u8(s01, d01);
vst1_u8(dst, vget_low_u8(d01));
dst += dst_stride;
vst1_u8(dst, vget_high_u8(d01));
dst += dst_stride;
h -= 2;
} while (h > 0);
} else if (w < 32) { // avg16
uint8x16_t s0, s1, d0, d1;
do {
s0 = vld1q_u8(src);
src += src_stride;
s1 = vld1q_u8(src);
src += src_stride;
d0 = vld1q_u8(dst);
d1 = vld1q_u8(dst + dst_stride);
d0 = vrhaddq_u8(s0, d0);
d1 = vrhaddq_u8(s1, d1);
vst1q_u8(dst, d0);
dst += dst_stride;
vst1q_u8(dst, d1);
dst += dst_stride;
h -= 2;
} while (h > 0);
} else if (w == 32) { // avg32
uint8x16_t s0, s1, s2, s3, d0, d1, d2, d3;
do {
s0 = vld1q_u8(src);
s1 = vld1q_u8(src + 16);
src += src_stride;
s2 = vld1q_u8(src);
s3 = vld1q_u8(src + 16);
src += src_stride;
d0 = vld1q_u8(dst);
d1 = vld1q_u8(dst + 16);
d2 = vld1q_u8(dst + dst_stride);
d3 = vld1q_u8(dst + dst_stride + 16);
d0 = vrhaddq_u8(s0, d0);
d1 = vrhaddq_u8(s1, d1);
d2 = vrhaddq_u8(s2, d2);
d3 = vrhaddq_u8(s3, d3);
vst1q_u8(dst, d0);
vst1q_u8(dst + 16, d1);
dst += dst_stride;
vst1q_u8(dst, d2);
vst1q_u8(dst + 16, d3);
dst += dst_stride;
h -= 2;
} while (h > 0);
} else { // avg64
uint8x16_t s0, s1, s2, s3, d0, d1, d2, d3;
do {
s0 = vld1q_u8(src);
s1 = vld1q_u8(src + 16);
s2 = vld1q_u8(src + 32);
s3 = vld1q_u8(src + 48);
src += src_stride;
d0 = vld1q_u8(dst);
d1 = vld1q_u8(dst + 16);
d2 = vld1q_u8(dst + 32);
d3 = vld1q_u8(dst + 48);
d0 = vrhaddq_u8(s0, d0);
d1 = vrhaddq_u8(s1, d1);
d2 = vrhaddq_u8(s2, d2);
d3 = vrhaddq_u8(s3, d3);
vst1q_u8(dst, d0);
vst1q_u8(dst + 16, d1);
vst1q_u8(dst + 32, d2);
vst1q_u8(dst + 48, d3);
dst += dst_stride;
} while (--h);
}
}
@@ -0,0 +1,116 @@
;
; Copyright (c) 2013 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
EXPORT |vpx_convolve_avg_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
|vpx_convolve_avg_neon| PROC
push {r4-r6, lr}
ldrd r4, r5, [sp, #36]
mov r6, r2
cmp r4, #32
bgt avg64
beq avg32
cmp r4, #8
bgt avg16
beq avg8
b avg4
avg64
sub lr, r1, #32
sub r4, r3, #32
avg64_h
pld [r0, r1, lsl #1]
vld1.8 {q0-q1}, [r0]!
vld1.8 {q2-q3}, [r0], lr
pld [r2, r3]
vld1.8 {q8-q9}, [r6@128]!
vld1.8 {q10-q11}, [r6@128], r4
vrhadd.u8 q0, q0, q8
vrhadd.u8 q1, q1, q9
vrhadd.u8 q2, q2, q10
vrhadd.u8 q3, q3, q11
vst1.8 {q0-q1}, [r2@128]!
vst1.8 {q2-q3}, [r2@128], r4
subs r5, r5, #1
bgt avg64_h
pop {r4-r6, pc}
avg32
vld1.8 {q0-q1}, [r0], r1
vld1.8 {q2-q3}, [r0], r1
vld1.8 {q8-q9}, [r6@128], r3
vld1.8 {q10-q11}, [r6@128], r3
pld [r0]
vrhadd.u8 q0, q0, q8
pld [r0, r1]
vrhadd.u8 q1, q1, q9
pld [r6]
vrhadd.u8 q2, q2, q10
pld [r6, r3]
vrhadd.u8 q3, q3, q11
vst1.8 {q0-q1}, [r2@128], r3
vst1.8 {q2-q3}, [r2@128], r3
subs r5, r5, #2
bgt avg32
pop {r4-r6, pc}
avg16
vld1.8 {q0}, [r0], r1
vld1.8 {q1}, [r0], r1
vld1.8 {q2}, [r6@128], r3
vld1.8 {q3}, [r6@128], r3
pld [r0]
pld [r0, r1]
vrhadd.u8 q0, q0, q2
pld [r6]
pld [r6, r3]
vrhadd.u8 q1, q1, q3
vst1.8 {q0}, [r2@128], r3
vst1.8 {q1}, [r2@128], r3
subs r5, r5, #2
bgt avg16
pop {r4-r6, pc}
avg8
vld1.8 {d0}, [r0], r1
vld1.8 {d1}, [r0], r1
vld1.8 {d2}, [r6@64], r3
vld1.8 {d3}, [r6@64], r3
pld [r0]
pld [r0, r1]
vrhadd.u8 q0, q0, q1
pld [r6]
pld [r6, r3]
vst1.8 {d0}, [r2@64], r3
vst1.8 {d1}, [r2@64], r3
subs r5, r5, #2
bgt avg8
pop {r4-r6, pc}
avg4
vld1.32 {d0[0]}, [r0], r1
vld1.32 {d0[1]}, [r0], r1
vld1.32 {d2[0]}, [r6@32], r3
vld1.32 {d2[1]}, [r6@32], r3
vrhadd.u8 d0, d0, d2
vst1.32 {d0[0]}, [r2@32], r3
vst1.32 {d0[1]}, [r2@32], r3
subs r5, r5, #2
bgt avg4
pop {r4-r6, pc}
ENDP
END
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
void vpx_convolve_copy_neon(const uint8_t *src, ptrdiff_t src_stride,
uint8_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4, int w,
int h) {
(void)filter;
(void)x0_q4;
(void)x_step_q4;
(void)y0_q4;
(void)y_step_q4;
if (w < 8) { // copy4
do {
*(uint32_t *)dst = *(const uint32_t *)src;
src += src_stride;
dst += dst_stride;
*(uint32_t *)dst = *(const uint32_t *)src;
src += src_stride;
dst += dst_stride;
h -= 2;
} while (h > 0);
} else if (w == 8) { // copy8
uint8x8_t s0, s1;
do {
s0 = vld1_u8(src);
src += src_stride;
s1 = vld1_u8(src);
src += src_stride;
vst1_u8(dst, s0);
dst += dst_stride;
vst1_u8(dst, s1);
dst += dst_stride;
h -= 2;
} while (h > 0);
} else if (w < 32) { // copy16
uint8x16_t s0, s1;
do {
s0 = vld1q_u8(src);
src += src_stride;
s1 = vld1q_u8(src);
src += src_stride;
vst1q_u8(dst, s0);
dst += dst_stride;
vst1q_u8(dst, s1);
dst += dst_stride;
h -= 2;
} while (h > 0);
} else if (w == 32) { // copy32
uint8x16_t s0, s1, s2, s3;
do {
s0 = vld1q_u8(src);
s1 = vld1q_u8(src + 16);
src += src_stride;
s2 = vld1q_u8(src);
s3 = vld1q_u8(src + 16);
src += src_stride;
vst1q_u8(dst, s0);
vst1q_u8(dst + 16, s1);
dst += dst_stride;
vst1q_u8(dst, s2);
vst1q_u8(dst + 16, s3);
dst += dst_stride;
h -= 2;
} while (h > 0);
} else { // copy64
uint8x16_t s0, s1, s2, s3;
do {
s0 = vld1q_u8(src);
s1 = vld1q_u8(src + 16);
s2 = vld1q_u8(src + 32);
s3 = vld1q_u8(src + 48);
src += src_stride;
vst1q_u8(dst, s0);
vst1q_u8(dst + 16, s1);
vst1q_u8(dst + 32, s2);
vst1q_u8(dst + 48, s3);
dst += dst_stride;
} while (--h);
}
}
@@ -0,0 +1,84 @@
;
; Copyright (c) 2013 The WebM project authors. All Rights Reserved.
;
; Use of this source code is governed by a BSD-style license
; that can be found in the LICENSE file in the root of the source
; tree. An additional intellectual property rights grant can be found
; in the file PATENTS. All contributing project authors may
; be found in the AUTHORS file in the root of the source tree.
;
EXPORT |vpx_convolve_copy_neon|
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
|vpx_convolve_copy_neon| PROC
push {r4-r5, lr}
ldrd r4, r5, [sp, #32]
cmp r4, #32
bgt copy64
beq copy32
cmp r4, #8
bgt copy16
beq copy8
b copy4
copy64
sub lr, r1, #32
sub r3, r3, #32
copy64_h
pld [r0, r1, lsl #1]
vld1.8 {q0-q1}, [r0]!
vld1.8 {q2-q3}, [r0], lr
vst1.8 {q0-q1}, [r2@128]!
vst1.8 {q2-q3}, [r2@128], r3
subs r5, r5, #1
bgt copy64_h
pop {r4-r5, pc}
copy32
pld [r0, r1, lsl #1]
vld1.8 {q0-q1}, [r0], r1
pld [r0, r1, lsl #1]
vld1.8 {q2-q3}, [r0], r1
vst1.8 {q0-q1}, [r2@128], r3
vst1.8 {q2-q3}, [r2@128], r3
subs r5, r5, #2
bgt copy32
pop {r4-r5, pc}
copy16
pld [r0, r1, lsl #1]
vld1.8 {q0}, [r0], r1
pld [r0, r1, lsl #1]
vld1.8 {q1}, [r0], r1
vst1.8 {q0}, [r2@128], r3
vst1.8 {q1}, [r2@128], r3
subs r5, r5, #2
bgt copy16
pop {r4-r5, pc}
copy8
pld [r0, r1, lsl #1]
vld1.8 {d0}, [r0], r1
pld [r0, r1, lsl #1]
vld1.8 {d2}, [r0], r1
vst1.8 {d0}, [r2@64], r3
vst1.8 {d2}, [r2@64], r3
subs r5, r5, #2
bgt copy8
pop {r4-r5, pc}
copy4
ldr r12, [r0], r1
str r12, [r2], r3
subs r5, r5, #1
bgt copy4
pop {r4-r5, pc}
ENDP
END
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2013 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <assert.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/vpx_dsp_common.h"
#include "vpx_ports/mem.h"
void vpx_convolve8_neon(const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,
ptrdiff_t dst_stride, const InterpKernel *filter,
int x0_q4, int x_step_q4, int y0_q4, int y_step_q4,
int w, int h) {
/* Given our constraints: w <= 64, h <= 64, taps == 8 we can reduce the
* maximum buffer size to 64 * 64 + 7 (+ 1 to make it divisible by 4).
*/
uint8_t temp[64 * 72];
// Account for the vertical phase needing 3 lines prior and 4 lines post
// (+ 1 to make it divisible by 4).
const int intermediate_height = h + 8;
assert(y_step_q4 == 16);
assert(x_step_q4 == 16);
/* Filter starting 3 lines back. The neon implementation will ignore the given
* height and filter a multiple of 4 lines. Since this goes in to the temp
* buffer which has lots of extra room and is subsequently discarded this is
* safe if somewhat less than ideal. */
vpx_convolve8_horiz_neon(src - src_stride * 3, src_stride, temp, w, filter,
x0_q4, x_step_q4, y0_q4, y_step_q4, w,
intermediate_height);
/* Step into the temp buffer 3 lines to get the actual frame data */
vpx_convolve8_vert_neon(temp + w * 3, w, dst, dst_stride, filter, x0_q4,
x_step_q4, y0_q4, y_step_q4, w, h);
}
void vpx_convolve8_avg_neon(const uint8_t *src, ptrdiff_t src_stride,
uint8_t *dst, ptrdiff_t dst_stride,
const InterpKernel *filter, int x0_q4,
int x_step_q4, int y0_q4, int y_step_q4, int w,
int h) {
uint8_t temp[64 * 72];
const int intermediate_height = h + 8;
assert(y_step_q4 == 16);
assert(x_step_q4 == 16);
/* This implementation has the same issues as above. In addition, we only want
* to average the values after both passes.
*/
vpx_convolve8_horiz_neon(src - src_stride * 3, src_stride, temp, w, filter,
x0_q4, x_step_q4, y0_q4, y_step_q4, w,
intermediate_height);
vpx_convolve8_avg_vert_neon(temp + w * 3, w, dst, dst_stride, filter, x0_q4,
x_step_q4, y0_q4, y_step_q4, w, h);
}
@@ -0,0 +1,324 @@
/*
* Copyright (c) 2017 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <arm_neon.h>
#include <assert.h>
#include <string.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/arm/transpose_neon.h"
#include "vpx_dsp/arm/vpx_convolve8_neon.h"
#include "vpx_ports/mem.h"
static INLINE void scaledconvolve_horiz_w4(
const uint8_t *src, const ptrdiff_t src_stride, uint8_t *dst,
const ptrdiff_t dst_stride, const InterpKernel *const x_filters,
const int x0_q4, const int x_step_q4, const int w, const int h) {
DECLARE_ALIGNED(16, uint8_t, temp[4 * 4]);
int x, y, z;
src -= SUBPEL_TAPS / 2 - 1;
y = h;
do {
int x_q4 = x0_q4;
x = 0;
do {
// process 4 src_x steps
for (z = 0; z < 4; ++z) {
const uint8_t *const src_x = &src[x_q4 >> SUBPEL_BITS];
if (x_q4 & SUBPEL_MASK) {
const int16x8_t filters = vld1q_s16(x_filters[x_q4 & SUBPEL_MASK]);
const int16x4_t filter3 = vdup_lane_s16(vget_low_s16(filters), 3);
const int16x4_t filter4 = vdup_lane_s16(vget_high_s16(filters), 0);
uint8x8_t s[8], d;
int16x8_t ss[4];
int16x4_t t[8], tt;
load_u8_8x4(src_x, src_stride, &s[0], &s[1], &s[2], &s[3]);
transpose_u8_8x4(&s[0], &s[1], &s[2], &s[3]);
ss[0] = vreinterpretq_s16_u16(vmovl_u8(s[0]));
ss[1] = vreinterpretq_s16_u16(vmovl_u8(s[1]));
ss[2] = vreinterpretq_s16_u16(vmovl_u8(s[2]));
ss[3] = vreinterpretq_s16_u16(vmovl_u8(s[3]));
t[0] = vget_low_s16(ss[0]);
t[1] = vget_low_s16(ss[1]);
t[2] = vget_low_s16(ss[2]);
t[3] = vget_low_s16(ss[3]);
t[4] = vget_high_s16(ss[0]);
t[5] = vget_high_s16(ss[1]);
t[6] = vget_high_s16(ss[2]);
t[7] = vget_high_s16(ss[3]);
tt = convolve8_4(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7],
filters, filter3, filter4);
d = vqrshrun_n_s16(vcombine_s16(tt, tt), 7);
vst1_lane_u32((uint32_t *)&temp[4 * z], vreinterpret_u32_u8(d), 0);
} else {
int i;
for (i = 0; i < 4; ++i) {
temp[z * 4 + i] = src_x[i * src_stride + 3];
}
}
x_q4 += x_step_q4;
}
// transpose the 4x4 filters values back to dst
{
const uint8x8x4_t d4 = vld4_u8(temp);
vst1_lane_u32((uint32_t *)&dst[x + 0 * dst_stride],
vreinterpret_u32_u8(d4.val[0]), 0);
vst1_lane_u32((uint32_t *)&dst[x + 1 * dst_stride],
vreinterpret_u32_u8(d4.val[1]), 0);
vst1_lane_u32((uint32_t *)&dst[x + 2 * dst_stride],
vreinterpret_u32_u8(d4.val[2]), 0);
vst1_lane_u32((uint32_t *)&dst[x + 3 * dst_stride],
vreinterpret_u32_u8(d4.val[3]), 0);
}
x += 4;
} while (x < w);
src += src_stride * 4;
dst += dst_stride * 4;
y -= 4;
} while (y > 0);
}
static INLINE void scaledconvolve_horiz_w8(
const uint8_t *src, const ptrdiff_t src_stride, uint8_t *dst,
const ptrdiff_t dst_stride, const InterpKernel *const x_filters,
const int x0_q4, const int x_step_q4, const int w, const int h) {
DECLARE_ALIGNED(16, uint8_t, temp[8 * 8]);
int x, y, z;
src -= SUBPEL_TAPS / 2 - 1;
// This function processes 8x8 areas. The intermediate height is not always
// a multiple of 8, so force it to be a multiple of 8 here.
y = (h + 7) & ~7;
do {
int x_q4 = x0_q4;
x = 0;
do {
uint8x8_t d[8];
// process 8 src_x steps
for (z = 0; z < 8; ++z) {
const uint8_t *const src_x = &src[x_q4 >> SUBPEL_BITS];
if (x_q4 & SUBPEL_MASK) {
const int16x8_t filters = vld1q_s16(x_filters[x_q4 & SUBPEL_MASK]);
uint8x8_t s[8];
load_u8_8x8(src_x, src_stride, &s[0], &s[1], &s[2], &s[3], &s[4],
&s[5], &s[6], &s[7]);
transpose_u8_8x8(&s[0], &s[1], &s[2], &s[3], &s[4], &s[5], &s[6],
&s[7]);
d[0] = scale_filter_8(s, filters);
vst1_u8(&temp[8 * z], d[0]);
} else {
int i;
for (i = 0; i < 8; ++i) {
temp[z * 8 + i] = src_x[i * src_stride + 3];
}
}
x_q4 += x_step_q4;
}
// transpose the 8x8 filters values back to dst
load_u8_8x8(temp, 8, &d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6],
&d[7]);
transpose_u8_8x8(&d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6], &d[7]);
vst1_u8(&dst[x + 0 * dst_stride], d[0]);
vst1_u8(&dst[x + 1 * dst_stride], d[1]);
vst1_u8(&dst[x + 2 * dst_stride], d[2]);
vst1_u8(&dst[x + 3 * dst_stride], d[3]);
vst1_u8(&dst[x + 4 * dst_stride], d[4]);
vst1_u8(&dst[x + 5 * dst_stride], d[5]);
vst1_u8(&dst[x + 6 * dst_stride], d[6]);
vst1_u8(&dst[x + 7 * dst_stride], d[7]);
x += 8;
} while (x < w);
src += src_stride * 8;
dst += dst_stride * 8;
} while (y -= 8);
}
static INLINE void scaledconvolve_vert_w4(
const uint8_t *src, const ptrdiff_t src_stride, uint8_t *dst,
const ptrdiff_t dst_stride, const InterpKernel *const y_filters,
const int y0_q4, const int y_step_q4, const int w, const int h) {
int y;
int y_q4 = y0_q4;
src -= src_stride * (SUBPEL_TAPS / 2 - 1);
y = h;
do {
const unsigned char *src_y = &src[(y_q4 >> SUBPEL_BITS) * src_stride];
if (y_q4 & SUBPEL_MASK) {
const int16x8_t filters = vld1q_s16(y_filters[y_q4 & SUBPEL_MASK]);
const int16x4_t filter3 = vdup_lane_s16(vget_low_s16(filters), 3);
const int16x4_t filter4 = vdup_lane_s16(vget_high_s16(filters), 0);
uint8x8_t s[8], d;
int16x4_t t[8], tt;
load_u8_8x8(src_y, src_stride, &s[0], &s[1], &s[2], &s[3], &s[4], &s[5],
&s[6], &s[7]);
t[0] = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(s[0])));
t[1] = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(s[1])));
t[2] = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(s[2])));
t[3] = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(s[3])));
t[4] = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(s[4])));
t[5] = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(s[5])));
t[6] = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(s[6])));
t[7] = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(s[7])));
tt = convolve8_4(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], filters,
filter3, filter4);
d = vqrshrun_n_s16(vcombine_s16(tt, tt), 7);
vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(d), 0);
} else {
memcpy(dst, &src_y[3 * src_stride], w);
}
dst += dst_stride;
y_q4 += y_step_q4;
} while (--y);
}
static INLINE void scaledconvolve_vert_w8(
const uint8_t *src, const ptrdiff_t src_stride, uint8_t *dst,
const ptrdiff_t dst_stride, const InterpKernel *const y_filters,
const int y0_q4, const int y_step_q4, const int w, const int h) {
int y;
int y_q4 = y0_q4;
src -= src_stride * (SUBPEL_TAPS / 2 - 1);
y = h;
do {
const unsigned char *src_y = &src[(y_q4 >> SUBPEL_BITS) * src_stride];
if (y_q4 & SUBPEL_MASK) {
const int16x8_t filters = vld1q_s16(y_filters[y_q4 & SUBPEL_MASK]);
uint8x8_t s[8], d;
load_u8_8x8(src_y, src_stride, &s[0], &s[1], &s[2], &s[3], &s[4], &s[5],
&s[6], &s[7]);
d = scale_filter_8(s, filters);
vst1_u8(dst, d);
} else {
memcpy(dst, &src_y[3 * src_stride], w);
}
dst += dst_stride;
y_q4 += y_step_q4;
} while (--y);
}
static INLINE void scaledconvolve_vert_w16(
const uint8_t *src, const ptrdiff_t src_stride, uint8_t *dst,
const ptrdiff_t dst_stride, const InterpKernel *const y_filters,
const int y0_q4, const int y_step_q4, const int w, const int h) {
int x, y;
int y_q4 = y0_q4;
src -= src_stride * (SUBPEL_TAPS / 2 - 1);
y = h;
do {
const unsigned char *src_y = &src[(y_q4 >> SUBPEL_BITS) * src_stride];
if (y_q4 & SUBPEL_MASK) {
x = 0;
do {
const int16x8_t filters = vld1q_s16(y_filters[y_q4 & SUBPEL_MASK]);
uint8x16_t ss[8];
uint8x8_t s[8], d[2];
load_u8_16x8(src_y, src_stride, &ss[0], &ss[1], &ss[2], &ss[3], &ss[4],
&ss[5], &ss[6], &ss[7]);
s[0] = vget_low_u8(ss[0]);
s[1] = vget_low_u8(ss[1]);
s[2] = vget_low_u8(ss[2]);
s[3] = vget_low_u8(ss[3]);
s[4] = vget_low_u8(ss[4]);
s[5] = vget_low_u8(ss[5]);
s[6] = vget_low_u8(ss[6]);
s[7] = vget_low_u8(ss[7]);
d[0] = scale_filter_8(s, filters);
s[0] = vget_high_u8(ss[0]);
s[1] = vget_high_u8(ss[1]);
s[2] = vget_high_u8(ss[2]);
s[3] = vget_high_u8(ss[3]);
s[4] = vget_high_u8(ss[4]);
s[5] = vget_high_u8(ss[5]);
s[6] = vget_high_u8(ss[6]);
s[7] = vget_high_u8(ss[7]);
d[1] = scale_filter_8(s, filters);
vst1q_u8(&dst[x], vcombine_u8(d[0], d[1]));
src_y += 16;
x += 16;
} while (x < w);
} else {
memcpy(dst, &src_y[3 * src_stride], w);
}
dst += dst_stride;
y_q4 += y_step_q4;
} while (--y);
}
void vpx_scaled_2d_neon(const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,
ptrdiff_t dst_stride, const InterpKernel *filter,
int x0_q4, int x_step_q4, int y0_q4, int y_step_q4,
int w, int h) {
// Note: Fixed size intermediate buffer, temp, places limits on parameters.
// 2d filtering proceeds in 2 steps:
// (1) Interpolate horizontally into an intermediate buffer, temp.
// (2) Interpolate temp vertically to derive the sub-pixel result.
// Deriving the maximum number of rows in the temp buffer (135):
// --Smallest scaling factor is x1/2 ==> y_step_q4 = 32 (Normative).
// --Largest block size is 64x64 pixels.
// --64 rows in the downscaled frame span a distance of (64 - 1) * 32 in the
// original frame (in 1/16th pixel units).
// --Must round-up because block may be located at sub-pixel position.
// --Require an additional SUBPEL_TAPS rows for the 8-tap filter tails.
// --((64 - 1) * 32 + 15) >> 4 + 8 = 135.
// --Require an additional 8 rows for the horiz_w8 transpose tail.
// When calling in frame scaling function, the smallest scaling factor is x1/4
// ==> y_step_q4 = 64. Since w and h are at most 16, the temp buffer is still
// big enough.
DECLARE_ALIGNED(16, uint8_t, temp[(135 + 8) * 64]);
const int intermediate_height =
(((h - 1) * y_step_q4 + y0_q4) >> SUBPEL_BITS) + SUBPEL_TAPS;
assert(w <= 64);
assert(h <= 64);
assert(y_step_q4 <= 32 || (y_step_q4 <= 64 && h <= 32));
assert(x_step_q4 <= 64);
if (w >= 8) {
scaledconvolve_horiz_w8(src - src_stride * (SUBPEL_TAPS / 2 - 1),
src_stride, temp, 64, filter, x0_q4, x_step_q4, w,
intermediate_height);
} else {
scaledconvolve_horiz_w4(src - src_stride * (SUBPEL_TAPS / 2 - 1),
src_stride, temp, 64, filter, x0_q4, x_step_q4, w,
intermediate_height);
}
if (w >= 16) {
scaledconvolve_vert_w16(temp + 64 * (SUBPEL_TAPS / 2 - 1), 64, dst,
dst_stride, filter, y0_q4, y_step_q4, w, h);
} else if (w == 8) {
scaledconvolve_vert_w8(temp + 64 * (SUBPEL_TAPS / 2 - 1), 64, dst,
dst_stride, filter, y0_q4, y_step_q4, w, h);
} else {
scaledconvolve_vert_w4(temp + 64 * (SUBPEL_TAPS / 2 - 1), 64, dst,
dst_stride, filter, y0_q4, y_step_q4, w, h);
}
}