shithub: libvpx

Download patch

ref: 3a3169be597e1338bd09724ba4482534accf4de0
parent: e66cd132f09e6303c1746a7c071fb742c3cca637
parent: 49165155111ce2188c27e471f7ad46a27044ade7
author: Linfeng Zhang <[email protected]>
date: Mon Aug 29 17:37:07 EDT 2016

Merge "Update vpx_lpf_horizontal_edge_16_neon() intrinsics"

--- a/vpx_dsp/arm/loopfilter_mb_neon.c
+++ b/vpx_dsp/arm/loopfilter_mb_neon.c
@@ -13,8 +13,12 @@
 #include "./vpx_dsp_rtcd.h"
 #include "vpx_dsp/arm/transpose_neon.h"
 
+// For all the static inline functions, the functions ending with '_8' process
+// 8 samples in a bunch, and the functions ending with '_16' process 16 samples
+// in a bunch.
+
 // Should we apply any filter at all: 11111111 yes, 00000000 no
-static INLINE uint8x8_t filter_mask(
+static INLINE uint8x8_t filter_mask_8(
     const uint8x8_t limit, const uint8x8_t blimit, const uint8x8_t thresh,
     const uint8x8_t p3, const uint8x8_t p2, const uint8x8_t p1,
     const uint8x8_t p0, const uint8x8_t q0, const uint8x8_t q1,
@@ -47,11 +51,46 @@
   return max;
 }
 
-static INLINE uint8x8_t flat_mask5(const uint8x8_t p4, const uint8x8_t p3,
-                                   const uint8x8_t p2, const uint8x8_t p1,
-                                   const uint8x8_t p0, const uint8x8_t q0,
-                                   const uint8x8_t q1, const uint8x8_t q2,
-                                   const uint8x8_t q3, const uint8x8_t q4) {
+// Should we apply any filter at all: 11111111 yes, 00000000 no
+static INLINE uint8x16_t
+filter_mask_16(const uint8x16_t limit, const uint8x16_t blimit,
+               const uint8x16_t thresh, const uint8x16_t p3,
+               const uint8x16_t p2, const uint8x16_t p1, const uint8x16_t p0,
+               const uint8x16_t q0, const uint8x16_t q1, const uint8x16_t q2,
+               const uint8x16_t q3, uint8x16_t *flat, uint8x16_t *hev) {
+  uint8x16_t t0, t1;
+  uint8x16_t max = vabdq_u8(p1, p0);
+  max = vmaxq_u8(max, vabdq_u8(q1, q0));
+
+  // Is there high edge variance internal edge: 11111111 yes, 00000000 no
+  *hev = vcgtq_u8(max, thresh);
+  *flat = vmaxq_u8(max, vabdq_u8(p2, p0));
+  max = vmaxq_u8(max, vabdq_u8(p3, p2));
+  max = vmaxq_u8(max, vabdq_u8(p2, p1));
+  max = vmaxq_u8(max, vabdq_u8(q2, q1));
+  max = vmaxq_u8(max, vabdq_u8(q3, q2));
+  t0 = vabdq_u8(p0, q0);
+  t1 = vabdq_u8(p1, q1);
+  t0 = vqshlq_n_u8(t0, 1);
+  t1 = vshrq_n_u8(t1, 1);
+  t0 = vqaddq_u8(t0, t1);
+  max = vcleq_u8(max, limit);
+  t0 = vcleq_u8(t0, blimit);
+  max = vandq_u8(max, t0);
+
+  *flat = vmaxq_u8(*flat, vabdq_u8(q2, q0));
+  *flat = vmaxq_u8(*flat, vabdq_u8(p3, p0));
+  *flat = vmaxq_u8(*flat, vabdq_u8(q3, q0));
+  *flat = vcleq_u8(*flat, vdupq_n_u8(1));  // flat_mask4()
+
+  return max;
+}
+
+static INLINE uint8x8_t flat_mask5_8(const uint8x8_t p4, const uint8x8_t p3,
+                                     const uint8x8_t p2, const uint8x8_t p1,
+                                     const uint8x8_t p0, const uint8x8_t q0,
+                                     const uint8x8_t q1, const uint8x8_t q2,
+                                     const uint8x8_t q3, const uint8x8_t q4) {
   uint8x8_t max = vabd_u8(p4, p0);
   max = vmax_u8(max, vabd_u8(p3, p0));
   max = vmax_u8(max, vabd_u8(p2, p0));
@@ -65,47 +104,118 @@
   return max;
 }
 
-static INLINE int8x8_t flip_sign(const uint8x8_t v) {
+static INLINE uint8x16_t flat_mask5_16(const uint8x16_t p4, const uint8x16_t p3,
+                                       const uint8x16_t p2, const uint8x16_t p1,
+                                       const uint8x16_t p0, const uint8x16_t q0,
+                                       const uint8x16_t q1, const uint8x16_t q2,
+                                       const uint8x16_t q3,
+                                       const uint8x16_t q4) {
+  uint8x16_t max = vabdq_u8(p4, p0);
+  max = vmaxq_u8(max, vabdq_u8(p3, p0));
+  max = vmaxq_u8(max, vabdq_u8(p2, p0));
+  max = vmaxq_u8(max, vabdq_u8(p1, p0));
+  max = vmaxq_u8(max, vabdq_u8(q1, q0));
+  max = vmaxq_u8(max, vabdq_u8(q2, q0));
+  max = vmaxq_u8(max, vabdq_u8(q3, q0));
+  max = vmaxq_u8(max, vabdq_u8(q4, q0));
+  max = vcleq_u8(max, vdupq_n_u8(1));
+
+  return max;
+}
+
+static INLINE int8x8_t flip_sign_8(const uint8x8_t v) {
   const uint8x8_t sign_bit = vdup_n_u8(0x80);
   return vreinterpret_s8_u8(veor_u8(v, sign_bit));
 }
 
-static INLINE uint8x8_t flip_sign_back(const int8x8_t v) {
+static INLINE int8x16_t flip_sign_16(const uint8x16_t v) {
+  const uint8x16_t sign_bit = vdupq_n_u8(0x80);
+  return vreinterpretq_s8_u8(veorq_u8(v, sign_bit));
+}
+
+static INLINE uint8x8_t flip_sign_back_8(const int8x8_t v) {
   const int8x8_t sign_bit = vdup_n_s8(0x80);
   return vreinterpret_u8_s8(veor_s8(v, sign_bit));
 }
 
-static INLINE uint8x8_t filter_tap7(const uint8x8_t flat, const uint8x8_t sub0,
-                                    const uint8x8_t sub1, const uint8x8_t add0,
-                                    const uint8x8_t add1, const uint8x8_t in,
-                                    uint16x8_t *sum) {
+static INLINE uint8x16_t flip_sign_back_16(const int8x16_t v) {
+  const int8x16_t sign_bit = vdupq_n_s8(0x80);
+  return vreinterpretq_u8_s8(veorq_s8(v, sign_bit));
+}
+
+static INLINE void filter_update_8(const uint8x8_t sub0, const uint8x8_t sub1,
+                                   const uint8x8_t add0, const uint8x8_t add1,
+                                   uint16x8_t *sum) {
   *sum = vsubw_u8(*sum, sub0);
   *sum = vsubw_u8(*sum, sub1);
   *sum = vaddw_u8(*sum, add0);
   *sum = vaddw_u8(*sum, add1);
+}
+
+static INLINE void filter_update_16(const uint8x16_t sub0,
+                                    const uint8x16_t sub1,
+                                    const uint8x16_t add0,
+                                    const uint8x16_t add1, uint16x8_t *sum0,
+                                    uint16x8_t *sum1) {
+  *sum0 = vsubw_u8(*sum0, vget_low_u8(sub0));
+  *sum1 = vsubw_u8(*sum1, vget_high_u8(sub0));
+  *sum0 = vsubw_u8(*sum0, vget_low_u8(sub1));
+  *sum1 = vsubw_u8(*sum1, vget_high_u8(sub1));
+  *sum0 = vaddw_u8(*sum0, vget_low_u8(add0));
+  *sum1 = vaddw_u8(*sum1, vget_high_u8(add0));
+  *sum0 = vaddw_u8(*sum0, vget_low_u8(add1));
+  *sum1 = vaddw_u8(*sum1, vget_high_u8(add1));
+}
+
+static INLINE uint8x8_t filter_tap7_8(const uint8x8_t flat,
+                                      const uint8x8_t sub0,
+                                      const uint8x8_t sub1,
+                                      const uint8x8_t add0,
+                                      const uint8x8_t add1, const uint8x8_t in,
+                                      uint16x8_t *sum) {
+  filter_update_8(sub0, sub1, add0, add1, sum);
   return vbsl_u8(flat, vrshrn_n_u16(*sum, 3), in);
 }
 
-static INLINE uint8x8_t filter_tap15(const uint8x8_t flat, const uint8x8_t sub0,
-                                     const uint8x8_t sub1, const uint8x8_t add0,
-                                     const uint8x8_t add1, const uint8x8_t in,
-                                     uint16x8_t *sum) {
-  *sum = vsubw_u8(*sum, sub0);
-  *sum = vsubw_u8(*sum, sub1);
-  *sum = vaddw_u8(*sum, add0);
-  *sum = vaddw_u8(*sum, add1);
+static INLINE uint8x16_t filter_tap7_16(
+    const uint8x16_t flat, const uint8x16_t sub0, const uint8x16_t sub1,
+    const uint8x16_t add0, const uint8x16_t add1, const uint8x16_t in,
+    uint16x8_t *sum0, uint16x8_t *sum1) {
+  uint8x16_t t;
+  filter_update_16(sub0, sub1, add0, add1, sum0, sum1);
+  t = vcombine_u8(vrshrn_n_u16(*sum0, 3), vrshrn_n_u16(*sum1, 3));
+  return vbslq_u8(flat, t, in);
+}
+
+static INLINE uint8x8_t filter_tap15_8(const uint8x8_t flat,
+                                       const uint8x8_t sub0,
+                                       const uint8x8_t sub1,
+                                       const uint8x8_t add0,
+                                       const uint8x8_t add1, const uint8x8_t in,
+                                       uint16x8_t *sum) {
+  filter_update_8(sub0, sub1, add0, add1, sum);
   return vbsl_u8(flat, vrshrn_n_u16(*sum, 4), in);
 }
 
+static INLINE uint8x16_t filter_tap15_16(
+    const uint8x16_t flat, const uint8x16_t sub0, const uint8x16_t sub1,
+    const uint8x16_t add0, const uint8x16_t add1, const uint8x16_t in,
+    uint16x8_t *sum0, uint16x8_t *sum1) {
+  uint8x16_t t;
+  filter_update_16(sub0, sub1, add0, add1, sum0, sum1);
+  t = vcombine_u8(vrshrn_n_u16(*sum0, 4), vrshrn_n_u16(*sum1, 4));
+  return vbslq_u8(flat, t, in);
+}
+
 // 7-tap filter [1, 1, 1, 2, 1, 1, 1]
-static INLINE void apply_7_tap_filter(const uint8x8_t flat, const uint8x8_t p3,
-                                      const uint8x8_t p2, const uint8x8_t p1,
-                                      const uint8x8_t p0, const uint8x8_t q0,
-                                      const uint8x8_t q1, const uint8x8_t q2,
-                                      const uint8x8_t q3, uint8x8_t *op2,
-                                      uint8x8_t *op1, uint8x8_t *op0,
-                                      uint8x8_t *oq0, uint8x8_t *oq1,
-                                      uint8x8_t *oq2) {
+static INLINE void apply_7_tap_filter_8(const uint8x8_t flat,
+                                        const uint8x8_t p3, const uint8x8_t p2,
+                                        const uint8x8_t p1, const uint8x8_t p0,
+                                        const uint8x8_t q0, const uint8x8_t q1,
+                                        const uint8x8_t q2, const uint8x8_t q3,
+                                        uint8x8_t *op2, uint8x8_t *op1,
+                                        uint8x8_t *op0, uint8x8_t *oq0,
+                                        uint8x8_t *oq1, uint8x8_t *oq2) {
   uint16x8_t sum;
   sum = vaddl_u8(p3, p3);   // 2*p3
   sum = vaddw_u8(sum, p3);  // 3*p3
@@ -115,15 +225,47 @@
   sum = vaddw_u8(sum, p0);  // 3*p3+2*p2+p1+p0
   sum = vaddw_u8(sum, q0);  // 3*p3+2*p2+p1+p0+q0
   *op2 = vbsl_u8(flat, vrshrn_n_u16(sum, 3), p2);
-  *op1 = filter_tap7(flat, p3, p2, p1, q1, *op1, &sum);
-  *op0 = filter_tap7(flat, p3, p1, p0, q2, *op0, &sum);
-  *oq0 = filter_tap7(flat, p3, p0, q0, q3, *oq0, &sum);
-  *oq1 = filter_tap7(flat, p2, q0, q1, q3, *oq1, &sum);
-  *oq2 = filter_tap7(flat, p1, q1, q2, q3, q2, &sum);
+  *op1 = filter_tap7_8(flat, p3, p2, p1, q1, *op1, &sum);
+  *op0 = filter_tap7_8(flat, p3, p1, p0, q2, *op0, &sum);
+  *oq0 = filter_tap7_8(flat, p3, p0, q0, q3, *oq0, &sum);
+  *oq1 = filter_tap7_8(flat, p2, q0, q1, q3, *oq1, &sum);
+  *oq2 = filter_tap7_8(flat, p1, q1, q2, q3, q2, &sum);
 }
 
+// 7-tap filter [1, 1, 1, 2, 1, 1, 1]
+static INLINE void apply_7_tap_filter_16(
+    const uint8x16_t flat, const uint8x16_t p3, const uint8x16_t p2,
+    const uint8x16_t p1, const uint8x16_t p0, const uint8x16_t q0,
+    const uint8x16_t q1, const uint8x16_t q2, const uint8x16_t q3,
+    uint8x16_t *op2, uint8x16_t *op1, uint8x16_t *op0, uint8x16_t *oq0,
+    uint8x16_t *oq1, uint8x16_t *oq2) {
+  uint16x8_t sum0, sum1;
+  uint8x16_t t;
+  sum0 = vaddl_u8(vget_low_u8(p3), vget_low_u8(p3));    // 2*p3
+  sum1 = vaddl_u8(vget_high_u8(p3), vget_high_u8(p3));  // 2*p3
+  sum0 = vaddw_u8(sum0, vget_low_u8(p3));               // 3*p3
+  sum1 = vaddw_u8(sum1, vget_high_u8(p3));              // 3*p3
+  sum0 = vaddw_u8(sum0, vget_low_u8(p2));               // 3*p3+p2
+  sum1 = vaddw_u8(sum1, vget_high_u8(p2));              // 3*p3+p2
+  sum0 = vaddw_u8(sum0, vget_low_u8(p2));               // 3*p3+2*p2
+  sum1 = vaddw_u8(sum1, vget_high_u8(p2));              // 3*p3+2*p2
+  sum0 = vaddw_u8(sum0, vget_low_u8(p1));               // 3*p3+2*p2+p1
+  sum1 = vaddw_u8(sum1, vget_high_u8(p1));              // 3*p3+2*p2+p1
+  sum0 = vaddw_u8(sum0, vget_low_u8(p0));               // 3*p3+2*p2+p1+p0
+  sum1 = vaddw_u8(sum1, vget_high_u8(p0));              // 3*p3+2*p2+p1+p0
+  sum0 = vaddw_u8(sum0, vget_low_u8(q0));               // 3*p3+2*p2+p1+p0+q0
+  sum1 = vaddw_u8(sum1, vget_high_u8(q0));              // 3*p3+2*p2+p1+p0+q0
+  t = vcombine_u8(vrshrn_n_u16(sum0, 3), vrshrn_n_u16(sum1, 3));
+  *op2 = vbslq_u8(flat, t, p2);
+  *op1 = filter_tap7_16(flat, p3, p2, p1, q1, *op1, &sum0, &sum1);
+  *op0 = filter_tap7_16(flat, p3, p1, p0, q2, *op0, &sum0, &sum1);
+  *oq0 = filter_tap7_16(flat, p3, p0, q0, q3, *oq0, &sum0, &sum1);
+  *oq1 = filter_tap7_16(flat, p2, q0, q1, q3, *oq1, &sum0, &sum1);
+  *oq2 = filter_tap7_16(flat, p1, q1, q2, q3, q2, &sum0, &sum1);
+}
+
 // 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(
+static INLINE void apply_15_tap_filter_8(
     const uint8x8_t flat2, const uint8x8_t p7, const uint8x8_t p6,
     const uint8x8_t p5, const uint8x8_t p4, const uint8x8_t p3,
     const uint8x8_t p2, const uint8x8_t p1, const uint8x8_t p0,
@@ -146,22 +288,74 @@
   sum = vaddw_u8(sum, p0);  // 7*p7+2*p6+p5+p4+p3+p2+p1+p0
   sum = vaddw_u8(sum, q0);  // 7*p7+2*p6+p5+p4+p3+p2+p1+p0+q0
   *op6 = vbsl_u8(flat2, vrshrn_n_u16(sum, 4), p6);
-  *op5 = filter_tap15(flat2, p7, p6, p5, q1, p5, &sum);
-  *op4 = filter_tap15(flat2, p7, p5, p4, q2, p4, &sum);
-  *op3 = filter_tap15(flat2, p7, p4, p3, q3, p3, &sum);
-  *op2 = filter_tap15(flat2, p7, p3, p2, q4, *op2, &sum);
-  *op1 = filter_tap15(flat2, p7, p2, p1, q5, *op1, &sum);
-  *op0 = filter_tap15(flat2, p7, p1, p0, q6, *op0, &sum);
-  *oq0 = filter_tap15(flat2, p7, p0, q0, q7, *oq0, &sum);
-  *oq1 = filter_tap15(flat2, p6, q0, q1, q7, *oq1, &sum);
-  *oq2 = filter_tap15(flat2, p5, q1, q2, q7, *oq2, &sum);
-  *oq3 = filter_tap15(flat2, p4, q2, q3, q7, q3, &sum);
-  *oq4 = filter_tap15(flat2, p3, q3, q4, q7, q4, &sum);
-  *oq5 = filter_tap15(flat2, p2, q4, q5, q7, q5, &sum);
-  *oq6 = filter_tap15(flat2, p1, q5, q6, q7, q6, &sum);
+  *op5 = filter_tap15_8(flat2, p7, p6, p5, q1, p5, &sum);
+  *op4 = filter_tap15_8(flat2, p7, p5, p4, q2, p4, &sum);
+  *op3 = filter_tap15_8(flat2, p7, p4, p3, q3, p3, &sum);
+  *op2 = filter_tap15_8(flat2, p7, p3, p2, q4, *op2, &sum);
+  *op1 = filter_tap15_8(flat2, p7, p2, p1, q5, *op1, &sum);
+  *op0 = filter_tap15_8(flat2, p7, p1, p0, q6, *op0, &sum);
+  *oq0 = filter_tap15_8(flat2, p7, p0, q0, q7, *oq0, &sum);
+  *oq1 = filter_tap15_8(flat2, p6, q0, q1, q7, *oq1, &sum);
+  *oq2 = filter_tap15_8(flat2, p5, q1, q2, q7, *oq2, &sum);
+  *oq3 = filter_tap15_8(flat2, p4, q2, q3, q7, q3, &sum);
+  *oq4 = filter_tap15_8(flat2, p3, q3, q4, q7, q4, &sum);
+  *oq5 = filter_tap15_8(flat2, p2, q4, q5, q7, q5, &sum);
+  *oq6 = filter_tap15_8(flat2, p1, q5, q6, q7, q6, &sum);
 }
 
-static INLINE void filter16(
+// 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_16(
+    const uint8x16_t flat2, const uint8x16_t p7, const uint8x16_t p6,
+    const uint8x16_t p5, const uint8x16_t p4, const uint8x16_t p3,
+    const uint8x16_t p2, const uint8x16_t p1, const uint8x16_t p0,
+    const uint8x16_t q0, const uint8x16_t q1, const uint8x16_t q2,
+    const uint8x16_t q3, const uint8x16_t q4, const uint8x16_t q5,
+    const uint8x16_t q6, const uint8x16_t q7, uint8x16_t *op6, uint8x16_t *op5,
+    uint8x16_t *op4, uint8x16_t *op3, uint8x16_t *op2, uint8x16_t *op1,
+    uint8x16_t *op0, uint8x16_t *oq0, uint8x16_t *oq1, uint8x16_t *oq2,
+    uint8x16_t *oq3, uint8x16_t *oq4, uint8x16_t *oq5, uint8x16_t *oq6) {
+  uint16x8_t sum0, sum1;
+  uint8x16_t t;
+  sum0 = vshll_n_u8(vget_low_u8(p7), 3);    // 8*p7
+  sum1 = vshll_n_u8(vget_high_u8(p7), 3);   // 8*p7
+  sum0 = vsubw_u8(sum0, vget_low_u8(p7));   // 7*p7
+  sum1 = vsubw_u8(sum1, vget_high_u8(p7));  // 7*p7
+  sum0 = vaddw_u8(sum0, vget_low_u8(p6));   // 7*p7+p6
+  sum1 = vaddw_u8(sum1, vget_high_u8(p6));  // 7*p7+p6
+  sum0 = vaddw_u8(sum0, vget_low_u8(p6));   // 7*p7+2*p6
+  sum1 = vaddw_u8(sum1, vget_high_u8(p6));  // 7*p7+2*p6
+  sum0 = vaddw_u8(sum0, vget_low_u8(p5));   // 7*p7+2*p6+p5
+  sum1 = vaddw_u8(sum1, vget_high_u8(p5));  // 7*p7+2*p6+p5
+  sum0 = vaddw_u8(sum0, vget_low_u8(p4));   // 7*p7+2*p6+p5+p4
+  sum1 = vaddw_u8(sum1, vget_high_u8(p4));  // 7*p7+2*p6+p5+p4
+  sum0 = vaddw_u8(sum0, vget_low_u8(p3));   // 7*p7+2*p6+p5+p4+p3
+  sum1 = vaddw_u8(sum1, vget_high_u8(p3));  // 7*p7+2*p6+p5+p4+p3
+  sum0 = vaddw_u8(sum0, vget_low_u8(p2));   // 7*p7+2*p6+p5+p4+p3+p2
+  sum1 = vaddw_u8(sum1, vget_high_u8(p2));  // 7*p7+2*p6+p5+p4+p3+p2
+  sum0 = vaddw_u8(sum0, vget_low_u8(p1));   // 7*p7+2*p6+p5+p4+p3+p2+p1
+  sum1 = vaddw_u8(sum1, vget_high_u8(p1));  // 7*p7+2*p6+p5+p4+p3+p2+p1
+  sum0 = vaddw_u8(sum0, vget_low_u8(p0));   // 7*p7+2*p6+p5+p4+p3+p2+p1+p0
+  sum1 = vaddw_u8(sum1, vget_high_u8(p0));  // 7*p7+2*p6+p5+p4+p3+p2+p1+p0
+  sum0 = vaddw_u8(sum0, vget_low_u8(q0));   // 7*p7+2*p6+p5+p4+p3+p2+p1+p0+q0
+  sum1 = vaddw_u8(sum1, vget_high_u8(q0));  // 7*p7+2*p6+p5+p4+p3+p2+p1+p0+q0
+  t = vcombine_u8(vrshrn_n_u16(sum0, 4), vrshrn_n_u16(sum1, 4));
+  *op6 = vbslq_u8(flat2, t, p6);
+  *op5 = filter_tap15_16(flat2, p7, p6, p5, q1, p5, &sum0, &sum1);
+  *op4 = filter_tap15_16(flat2, p7, p5, p4, q2, p4, &sum0, &sum1);
+  *op3 = filter_tap15_16(flat2, p7, p4, p3, q3, p3, &sum0, &sum1);
+  *op2 = filter_tap15_16(flat2, p7, p3, p2, q4, *op2, &sum0, &sum1);
+  *op1 = filter_tap15_16(flat2, p7, p2, p1, q5, *op1, &sum0, &sum1);
+  *op0 = filter_tap15_16(flat2, p7, p1, p0, q6, *op0, &sum0, &sum1);
+  *oq0 = filter_tap15_16(flat2, p7, p0, q0, q7, *oq0, &sum0, &sum1);
+  *oq1 = filter_tap15_16(flat2, p6, q0, q1, q7, *oq1, &sum0, &sum1);
+  *oq2 = filter_tap15_16(flat2, p5, q1, q2, q7, *oq2, &sum0, &sum1);
+  *oq3 = filter_tap15_16(flat2, p4, q2, q3, q7, q3, &sum0, &sum1);
+  *oq4 = filter_tap15_16(flat2, p3, q3, q4, q7, q4, &sum0, &sum1);
+  *oq5 = filter_tap15_16(flat2, p2, q4, q5, q7, q5, &sum0, &sum1);
+  *oq6 = filter_tap15_16(flat2, p1, q5, q6, q7, q6, &sum0, &sum1);
+}
+
+static INLINE void filter16_8(
     const uint8x8_t mask, const uint8x8_t flat, const uint64_t flat_u64,
     const uint8x8_t flat2, const uint64_t flat2_u64, const uint8x8_t hev,
     const uint8x8_t p7, const uint8x8_t p6, const uint8x8_t p5,
@@ -176,10 +370,10 @@
   // add outer taps if we have high edge variance
   if (flat_u64 != (uint64_t)-1) {
     int8x8_t filter, filter1, filter2, t;
-    int8x8_t ps1 = flip_sign(p1);
-    int8x8_t ps0 = flip_sign(p0);
-    int8x8_t qs0 = flip_sign(q0);
-    int8x8_t qs1 = flip_sign(q1);
+    int8x8_t ps1 = flip_sign_8(p1);
+    int8x8_t ps0 = flip_sign_8(p0);
+    int8x8_t qs0 = flip_sign_8(q0);
+    int8x8_t qs1 = flip_sign_8(q1);
 
     filter = vqsub_s8(ps1, qs1);
     filter = vand_s8(filter, vreinterpret_s8_u8(hev));
@@ -199,8 +393,8 @@
 
     qs0 = vqsub_s8(qs0, filter1);
     ps0 = vqadd_s8(ps0, filter2);
-    *oq0 = flip_sign_back(qs0);
-    *op0 = flip_sign_back(ps0);
+    *oq0 = flip_sign_back_8(qs0);
+    *op0 = flip_sign_back_8(ps0);
 
     // outer tap adjustments
     filter = vrshr_n_s8(filter1, 1);
@@ -208,8 +402,8 @@
 
     qs1 = vqsub_s8(qs1, filter);
     ps1 = vqadd_s8(ps1, filter);
-    *oq1 = flip_sign_back(qs1);
-    *op1 = flip_sign_back(ps1);
+    *oq1 = flip_sign_back_8(qs1);
+    *op1 = flip_sign_back_8(ps1);
   }
 
   if (flat_u64) {
@@ -216,89 +410,227 @@
     *op2 = p2;
     *oq2 = q2;
     if (flat2_u64 != (uint64_t)-1) {
-      apply_7_tap_filter(flat, p3, p2, p1, p0, q0, q1, q2, q3, op2, op1, op0,
-                         oq0, oq1, oq2);
+      apply_7_tap_filter_8(flat, p3, p2, p1, p0, q0, q1, q2, q3, op2, op1, op0,
+                           oq0, oq1, oq2);
     }
     if (flat2_u64) {
-      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);
+      apply_15_tap_filter_8(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 void mb_lpf_horizontal_edge_w(uint8_t *s, int p, const uint8_t *blimit,
-                                     const uint8_t *limit,
-                                     const uint8_t *thresh, int count) {
-  const uint8x8_t blimit_u8x8 = vld1_dup_u8(blimit);
-  const uint8x8_t limit_u8x8 = vld1_dup_u8(limit);
-  const uint8x8_t thresh_u8x8 = vld1_dup_u8(thresh);
+static INLINE void filter16_16(
+    const uint8x16_t mask, const uint8x16_t flat, const uint64_t flat_u64,
+    const uint8x16_t flat2, const uint64_t flat2_u64, const uint8x16_t hev,
+    const uint8x16_t p7, const uint8x16_t p6, const uint8x16_t p5,
+    const uint8x16_t p4, const uint8x16_t p3, const uint8x16_t p2,
+    const uint8x16_t p1, const uint8x16_t p0, const uint8x16_t q0,
+    const uint8x16_t q1, const uint8x16_t q2, const uint8x16_t q3,
+    const uint8x16_t q4, const uint8x16_t q5, const uint8x16_t q6,
+    const uint8x16_t q7, uint8x16_t *op6, uint8x16_t *op5, uint8x16_t *op4,
+    uint8x16_t *op3, uint8x16_t *op2, uint8x16_t *op1, uint8x16_t *op0,
+    uint8x16_t *oq0, uint8x16_t *oq1, uint8x16_t *oq2, uint8x16_t *oq3,
+    uint8x16_t *oq4, uint8x16_t *oq5, uint8x16_t *oq6) {
+  // add outer taps if we have high edge variance
+  if (flat_u64 != (uint64_t)-2) {
+    int8x16_t filter, filter1, filter2, t;
+    int8x16_t ps1 = flip_sign_16(p1);
+    int8x16_t ps0 = flip_sign_16(p0);
+    int8x16_t qs0 = flip_sign_16(q0);
+    int8x16_t qs1 = flip_sign_16(q1);
 
-  do {
-    const uint8x8_t p7 = vld1_u8(s - 8 * p);
-    const uint8x8_t p6 = vld1_u8(s - 7 * p);
-    const uint8x8_t p5 = vld1_u8(s - 6 * p);
-    const uint8x8_t p4 = vld1_u8(s - 5 * p);
-    const uint8x8_t p3 = vld1_u8(s - 4 * p);
-    const uint8x8_t p2 = vld1_u8(s - 3 * p);
-    const uint8x8_t p1 = vld1_u8(s - 2 * p);
-    const uint8x8_t p0 = vld1_u8(s - 1 * p);
-    const uint8x8_t q0 = vld1_u8(s + 0 * p);
-    const uint8x8_t q1 = vld1_u8(s + 1 * p);
-    const uint8x8_t q2 = vld1_u8(s + 2 * p);
-    const uint8x8_t q3 = vld1_u8(s + 3 * p);
-    const uint8x8_t q4 = vld1_u8(s + 4 * p);
-    const uint8x8_t q5 = vld1_u8(s + 5 * p);
-    const uint8x8_t q6 = vld1_u8(s + 6 * p);
-    const uint8x8_t q7 = vld1_u8(s + 7 * p);
-    uint8x8_t op6, op5, op4, op3, op2, op1, op0, oq0, oq1, oq2, oq3, oq4, oq5,
-        oq6, flat, hev;
-    const uint8x8_t mask = filter_mask(limit_u8x8, blimit_u8x8, thresh_u8x8, p3,
-                                       p2, p1, p0, q0, q1, q2, q3, &flat, &hev);
-    uint8x8_t flat2 = flat_mask5(p7, p6, p5, p4, p0, q0, q4, q5, q6, q7);
-    uint64_t flat_u64, flat2_u64;
+    filter = vqsubq_s8(ps1, qs1);
+    filter = vandq_s8(filter, vreinterpretq_s8_u8(hev));
+    t = vqsubq_s8(qs0, ps0);
 
-    flat = vand_u8(flat, mask);
-    flat2 = vand_u8(flat2, flat);
-    flat_u64 = vget_lane_u64(vreinterpret_u64_u8(flat), 0);
-    flat2_u64 = vget_lane_u64(vreinterpret_u64_u8(flat2), 0);
+    // inner taps
+    filter = vqaddq_s8(filter, t);
+    filter = vqaddq_s8(filter, t);
+    filter = vqaddq_s8(filter, t);
+    filter = vandq_s8(filter, vreinterpretq_s8_u8(mask));
 
-    filter16(mask, flat, flat_u64, flat2, flat2_u64, 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);
+    // save bottom 3 bits so that we round one side +4 and the other +3
+    // if it equals 4 we'll set to adjust by -1 to account for the fact
+    // we'd round 3 the other way
+    filter1 = vshrq_n_s8(vqaddq_s8(filter, vdupq_n_s8(4)), 3);
+    filter2 = vshrq_n_s8(vqaddq_s8(filter, vdupq_n_s8(3)), 3);
 
-    if (flat_u64) {
-      if (flat2_u64) {
-        vst1_u8(s - 7 * p, op6);
-        vst1_u8(s - 6 * p, op5);
-        vst1_u8(s - 5 * p, op4);
-        vst1_u8(s - 4 * p, op3);
-        vst1_u8(s + 3 * p, oq3);
-        vst1_u8(s + 4 * p, oq4);
-        vst1_u8(s + 5 * p, oq5);
-        vst1_u8(s + 6 * p, oq6);
-      }
-      vst1_u8(s - 3 * p, op2);
-      vst1_u8(s + 2 * p, oq2);
+    qs0 = vqsubq_s8(qs0, filter1);
+    ps0 = vqaddq_s8(ps0, filter2);
+    *oq0 = flip_sign_back_16(qs0);
+    *op0 = flip_sign_back_16(ps0);
+
+    // outer tap adjustments
+    filter = vrshrq_n_s8(filter1, 1);
+    filter = vbicq_s8(filter, vreinterpretq_s8_u8(hev));
+
+    qs1 = vqsubq_s8(qs1, filter);
+    ps1 = vqaddq_s8(ps1, filter);
+    *oq1 = flip_sign_back_16(qs1);
+    *op1 = flip_sign_back_16(ps1);
+  }
+
+  if (flat_u64) {
+    *op2 = p2;
+    *oq2 = q2;
+    if (flat2_u64 != (uint64_t)-2) {
+      apply_7_tap_filter_16(flat, p3, p2, p1, p0, q0, q1, q2, q3, op2, op1, op0,
+                            oq0, oq1, oq2);
     }
-    vst1_u8(s - 2 * p, op1);
-    vst1_u8(s - 1 * p, op0);
-    vst1_u8(s + 0 * p, oq0);
-    vst1_u8(s + 1 * p, oq1);
-    s += 8;
-  } while (--count);
+    if (flat2_u64) {
+      apply_15_tap_filter_16(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 store_result_8(uint8_t *s, int p, const uint8x8_t p6,
+                                  const uint8x8_t p5, const uint8x8_t p4,
+                                  const uint8x8_t p3, const uint8x8_t p2,
+                                  const uint8x8_t p1, const uint8x8_t p0,
+                                  const uint8x8_t q0, const uint8x8_t q1,
+                                  const uint8x8_t q2, const uint8x8_t q3,
+                                  const uint8x8_t q4, const uint8x8_t q5,
+                                  const uint8x8_t q6, const uint64_t flat_u64,
+                                  const uint64_t flat2_u64) {
+  if (flat_u64) {
+    if (flat2_u64) {
+      vst1_u8(s - 7 * p, p6);
+      vst1_u8(s - 6 * p, p5);
+      vst1_u8(s - 5 * p, p4);
+      vst1_u8(s - 4 * p, p3);
+      vst1_u8(s + 3 * p, q3);
+      vst1_u8(s + 4 * p, q4);
+      vst1_u8(s + 5 * p, q5);
+      vst1_u8(s + 6 * p, q6);
+    }
+    vst1_u8(s - 3 * p, p2);
+    vst1_u8(s + 2 * p, q2);
+  }
+  vst1_u8(s - 2 * p, p1);
+  vst1_u8(s - 1 * p, p0);
+  vst1_u8(s + 0 * p, q0);
+  vst1_u8(s + 1 * p, q1);
+}
+
+static INLINE void store_result_16(uint8_t *s, int p, const uint8x16_t p6,
+                                   const uint8x16_t p5, const uint8x16_t p4,
+                                   const uint8x16_t p3, const uint8x16_t p2,
+                                   const uint8x16_t p1, const uint8x16_t p0,
+                                   const uint8x16_t q0, const uint8x16_t q1,
+                                   const uint8x16_t q2, const uint8x16_t q3,
+                                   const uint8x16_t q4, const uint8x16_t q5,
+                                   const uint8x16_t q6, const uint64_t flat_u64,
+                                   const uint64_t flat2_u64) {
+  if (flat_u64) {
+    if (flat2_u64) {
+      vst1q_u8(s - 7 * p, p6);
+      vst1q_u8(s - 6 * p, p5);
+      vst1q_u8(s - 5 * p, p4);
+      vst1q_u8(s - 4 * p, p3);
+      vst1q_u8(s + 3 * p, q3);
+      vst1q_u8(s + 4 * p, q4);
+      vst1q_u8(s + 5 * p, q5);
+      vst1q_u8(s + 6 * p, q6);
+    }
+    vst1q_u8(s - 3 * p, p2);
+    vst1q_u8(s + 2 * p, q2);
+  }
+  vst1q_u8(s - 2 * p, p1);
+  vst1q_u8(s - 1 * p, p0);
+  vst1q_u8(s + 0 * p, q0);
+  vst1q_u8(s + 1 * p, q1);
+}
+
 void vpx_lpf_horizontal_edge_8_neon(uint8_t *s, int p, const uint8_t *blimit,
                                     const uint8_t *limit,
                                     const uint8_t *thresh) {
-  mb_lpf_horizontal_edge_w(s, p, blimit, limit, thresh, 1);
+  const uint8x8_t blimit_u8x8 = vld1_dup_u8(blimit);
+  const uint8x8_t limit_u8x8 = vld1_dup_u8(limit);
+  const uint8x8_t thresh_u8x8 = vld1_dup_u8(thresh);
+  const uint8x8_t p7 = vld1_u8(s - 8 * p);
+  const uint8x8_t p6 = vld1_u8(s - 7 * p);
+  const uint8x8_t p5 = vld1_u8(s - 6 * p);
+  const uint8x8_t p4 = vld1_u8(s - 5 * p);
+  const uint8x8_t p3 = vld1_u8(s - 4 * p);
+  const uint8x8_t p2 = vld1_u8(s - 3 * p);
+  const uint8x8_t p1 = vld1_u8(s - 2 * p);
+  const uint8x8_t p0 = vld1_u8(s - 1 * p);
+  const uint8x8_t q0 = vld1_u8(s + 0 * p);
+  const uint8x8_t q1 = vld1_u8(s + 1 * p);
+  const uint8x8_t q2 = vld1_u8(s + 2 * p);
+  const uint8x8_t q3 = vld1_u8(s + 3 * p);
+  const uint8x8_t q4 = vld1_u8(s + 4 * p);
+  const uint8x8_t q5 = vld1_u8(s + 5 * p);
+  const uint8x8_t q6 = vld1_u8(s + 6 * p);
+  const uint8x8_t q7 = vld1_u8(s + 7 * p);
+  uint8x8_t op6, op5, op4, op3, op2, op1, op0, oq0, oq1, oq2, oq3, oq4, oq5,
+      oq6, flat, hev;
+  const uint8x8_t mask = filter_mask_8(limit_u8x8, blimit_u8x8, thresh_u8x8, p3,
+                                       p2, p1, p0, q0, q1, q2, q3, &flat, &hev);
+  uint8x8_t flat2 = flat_mask5_8(p7, p6, p5, p4, p0, q0, q4, q5, q6, q7);
+  uint64_t flat_u64, flat2_u64;
+
+  flat = vand_u8(flat, mask);
+  flat2 = vand_u8(flat2, flat);
+  flat_u64 = vget_lane_u64(vreinterpret_u64_u8(flat), 0);
+  flat2_u64 = vget_lane_u64(vreinterpret_u64_u8(flat2), 0);
+
+  filter16_8(mask, flat, flat_u64, flat2, flat2_u64, 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);
+  store_result_8(s, p, op6, op5, op4, op3, op2, op1, op0, oq0, oq1, oq2, oq3,
+                 oq4, oq5, oq6, flat_u64, flat2_u64);
 }
 
 void vpx_lpf_horizontal_edge_16_neon(uint8_t *s, int p, const uint8_t *blimit,
                                      const uint8_t *limit,
                                      const uint8_t *thresh) {
-  mb_lpf_horizontal_edge_w(s, p, blimit, limit, thresh, 2);
+  const uint8x16_t blimit_u8x16 = vld1q_dup_u8(blimit);
+  const uint8x16_t limit_u8x16 = vld1q_dup_u8(limit);
+  const uint8x16_t thresh_u8x16 = vld1q_dup_u8(thresh);
+  const uint8x16_t p3 = vld1q_u8(s - 4 * p);
+  const uint8x16_t p2 = vld1q_u8(s - 3 * p);
+  const uint8x16_t p1 = vld1q_u8(s - 2 * p);
+  const uint8x16_t p0 = vld1q_u8(s - 1 * p);
+  const uint8x16_t q0 = vld1q_u8(s + 0 * p);
+  const uint8x16_t q1 = vld1q_u8(s + 1 * p);
+  const uint8x16_t q2 = vld1q_u8(s + 2 * p);
+  const uint8x16_t q3 = vld1q_u8(s + 3 * p);
+  uint8x16_t op6, op5, op4, op3, op2, op1, op0, oq0, oq1, oq2, oq3, oq4, oq5,
+      oq6, flat, hev;
+  const uint8x16_t mask =
+      filter_mask_16(limit_u8x16, blimit_u8x16, thresh_u8x16, p3, p2, p1, p0,
+                     q0, q1, q2, q3, &flat, &hev);
+  const uint8x16_t p7 = vld1q_u8(s - 8 * p);
+  const uint8x16_t p6 = vld1q_u8(s - 7 * p);
+  const uint8x16_t p5 = vld1q_u8(s - 6 * p);
+  const uint8x16_t p4 = vld1q_u8(s - 5 * p);
+  const uint8x16_t q4 = vld1q_u8(s + 4 * p);
+  const uint8x16_t q5 = vld1q_u8(s + 5 * p);
+  const uint8x16_t q6 = vld1q_u8(s + 6 * p);
+  const uint8x16_t q7 = vld1q_u8(s + 7 * p);
+  uint8x16_t flat2 = flat_mask5_16(p7, p6, p5, p4, p0, q0, q4, q5, q6, q7);
+  uint64x1_t flat_u64x1, flat2_u64x1;
+  uint64_t flat_u64, flat2_u64;
+
+  flat = vandq_u8(flat, mask);
+  flat2 = vandq_u8(flat2, flat);
+  flat_u64x1 = vadd_u64(vreinterpret_u64_u8(vget_low_u8(flat)),
+                        vreinterpret_u64_u8(vget_high_u8(flat)));
+  flat2_u64x1 = vadd_u64(vreinterpret_u64_u8(vget_low_u8(flat2)),
+                         vreinterpret_u64_u8(vget_high_u8(flat2)));
+  flat_u64 = vget_lane_u64(flat_u64x1, 0);
+  flat2_u64 = vget_lane_u64(flat2_u64x1, 0);
+
+  filter16_16(mask, flat, flat_u64, flat2, flat2_u64, 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);
+  store_result_16(s, p, op6, op5, op4, op3, op2, op1, op0, oq0, oq1, oq2, oq3,
+                  oq4, oq5, oq6, flat_u64, flat2_u64);
 }
 
 static void mb_lpf_vertical_edge_w(uint8_t *s, int p, const uint8_t *blimit,
@@ -338,17 +670,18 @@
     transpose_u8_16x8(t0, t1, t2, t3, t4, t5, t6, t7, &p7, &p6, &p5, &p4, &p3,
                       &p2, &p1, &p0, &q0, &q1, &q2, &q3, &q4, &q5, &q6, &q7);
 
-    mask = filter_mask(limit_u8x8, blimit_u8x8, thresh_u8x8, p3, p2, p1, p0, q0,
-                       q1, q2, q3, &flat, &hev);
-    flat2 = flat_mask5(p7, p6, p5, p4, p0, q0, q4, q5, q6, q7);
+    mask = filter_mask_8(limit_u8x8, blimit_u8x8, thresh_u8x8, p3, p2, p1, p0,
+                         q0, q1, q2, q3, &flat, &hev);
+    flat2 = flat_mask5_8(p7, p6, p5, p4, p0, q0, q4, q5, q6, q7);
     flat = vand_u8(flat, mask);
     flat2 = vand_u8(flat2, flat);
     flat_u64 = vget_lane_u64(vreinterpret_u64_u8(flat), 0);
     flat2_u64 = vget_lane_u64(vreinterpret_u64_u8(flat2), 0);
 
-    filter16(mask, flat, flat_u64, flat2, flat2_u64, 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);
+    filter16_8(mask, flat, flat_u64, flat2, flat2_u64, 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);
 
     if (flat_u64) {
       if (flat2_u64) {