| /* |
| * Copyright (c) 2012 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 <stdlib.h> |
| #include "vp8_rtcd.h" |
| #include "vp8/common/onyxc_int.h" |
| |
| #if HAVE_DSPR2 |
| typedef unsigned char uc; |
| |
| /* prefetch data for load */ |
| inline void prefetch_load_lf(unsigned char *src) { |
| __asm__ __volatile__("pref 0, 0(%[src]) \n\t" : : [src] "r"(src)); |
| } |
| |
| /* prefetch data for store */ |
| inline void prefetch_store_lf(unsigned char *dst) { |
| __asm__ __volatile__("pref 1, 0(%[dst]) \n\t" : : [dst] "r"(dst)); |
| } |
| |
| /* processing 4 pixels at the same time |
| * compute hev and mask in the same function |
| */ |
| static __inline void vp8_filter_mask_vec_mips( |
| uint32_t limit, uint32_t flimit, uint32_t p1, uint32_t p0, uint32_t p3, |
| uint32_t p2, uint32_t q0, uint32_t q1, uint32_t q2, uint32_t q3, |
| uint32_t thresh, uint32_t *hev, uint32_t *mask) { |
| uint32_t c, r, r3, r_k; |
| uint32_t s1, s2, s3; |
| uint32_t ones = 0xFFFFFFFF; |
| uint32_t hev1; |
| |
| __asm__ __volatile__( |
| /* mask |= (abs(p3 - p2) > limit) */ |
| "subu_s.qb %[c], %[p3], %[p2] \n\t" |
| "subu_s.qb %[r_k], %[p2], %[p3] \n\t" |
| "or %[r_k], %[r_k], %[c] \n\t" |
| "cmpgu.lt.qb %[c], %[limit], %[r_k] \n\t" |
| "or %[r], $0, %[c] \n\t" |
| |
| /* mask |= (abs(p2 - p1) > limit) */ |
| "subu_s.qb %[c], %[p2], %[p1] \n\t" |
| "subu_s.qb %[r_k], %[p1], %[p2] \n\t" |
| "or %[r_k], %[r_k], %[c] \n\t" |
| "cmpgu.lt.qb %[c], %[limit], %[r_k] \n\t" |
| "or %[r], %[r], %[c] \n\t" |
| |
| /* mask |= (abs(p1 - p0) > limit) |
| * hev |= (abs(p1 - p0) > thresh) |
| */ |
| "subu_s.qb %[c], %[p1], %[p0] \n\t" |
| "subu_s.qb %[r_k], %[p0], %[p1] \n\t" |
| "or %[r_k], %[r_k], %[c] \n\t" |
| "cmpgu.lt.qb %[c], %[thresh], %[r_k] \n\t" |
| "or %[r3], $0, %[c] \n\t" |
| "cmpgu.lt.qb %[c], %[limit], %[r_k] \n\t" |
| "or %[r], %[r], %[c] \n\t" |
| |
| /* mask |= (abs(q1 - q0) > limit) |
| * hev |= (abs(q1 - q0) > thresh) |
| */ |
| "subu_s.qb %[c], %[q1], %[q0] \n\t" |
| "subu_s.qb %[r_k], %[q0], %[q1] \n\t" |
| "or %[r_k], %[r_k], %[c] \n\t" |
| "cmpgu.lt.qb %[c], %[thresh], %[r_k] \n\t" |
| "or %[r3], %[r3], %[c] \n\t" |
| "cmpgu.lt.qb %[c], %[limit], %[r_k] \n\t" |
| "or %[r], %[r], %[c] \n\t" |
| |
| /* mask |= (abs(q2 - q1) > limit) */ |
| "subu_s.qb %[c], %[q2], %[q1] \n\t" |
| "subu_s.qb %[r_k], %[q1], %[q2] \n\t" |
| "or %[r_k], %[r_k], %[c] \n\t" |
| "cmpgu.lt.qb %[c], %[limit], %[r_k] \n\t" |
| "or %[r], %[r], %[c] \n\t" |
| "sll %[r3], %[r3], 24 \n\t" |
| |
| /* mask |= (abs(q3 - q2) > limit) */ |
| "subu_s.qb %[c], %[q3], %[q2] \n\t" |
| "subu_s.qb %[r_k], %[q2], %[q3] \n\t" |
| "or %[r_k], %[r_k], %[c] \n\t" |
| "cmpgu.lt.qb %[c], %[limit], %[r_k] \n\t" |
| "or %[r], %[r], %[c] \n\t" |
| |
| : [c] "=&r"(c), [r_k] "=&r"(r_k), [r] "=&r"(r), [r3] "=&r"(r3) |
| : [limit] "r"(limit), [p3] "r"(p3), [p2] "r"(p2), [p1] "r"(p1), |
| [p0] "r"(p0), [q1] "r"(q1), [q0] "r"(q0), [q2] "r"(q2), [q3] "r"(q3), |
| [thresh] "r"(thresh)); |
| |
| __asm__ __volatile__( |
| /* abs(p0 - q0) */ |
| "subu_s.qb %[c], %[p0], %[q0] \n\t" |
| "subu_s.qb %[r_k], %[q0], %[p0] \n\t" |
| "wrdsp %[r3] \n\t" |
| "or %[s1], %[r_k], %[c] \n\t" |
| |
| /* abs(p1 - q1) */ |
| "subu_s.qb %[c], %[p1], %[q1] \n\t" |
| "addu_s.qb %[s3], %[s1], %[s1] \n\t" |
| "pick.qb %[hev1], %[ones], $0 \n\t" |
| "subu_s.qb %[r_k], %[q1], %[p1] \n\t" |
| "or %[s2], %[r_k], %[c] \n\t" |
| |
| /* abs(p0 - q0) * 2 + abs(p1 - q1) / 2 > flimit * 2 + limit */ |
| "shrl.qb %[s2], %[s2], 1 \n\t" |
| "addu_s.qb %[s1], %[s2], %[s3] \n\t" |
| "cmpgu.lt.qb %[c], %[flimit], %[s1] \n\t" |
| "or %[r], %[r], %[c] \n\t" |
| "sll %[r], %[r], 24 \n\t" |
| |
| "wrdsp %[r] \n\t" |
| "pick.qb %[s2], $0, %[ones] \n\t" |
| |
| : [c] "=&r"(c), [r_k] "=&r"(r_k), [s1] "=&r"(s1), [hev1] "=&r"(hev1), |
| [s2] "=&r"(s2), [r] "+r"(r), [s3] "=&r"(s3) |
| : [p0] "r"(p0), [q0] "r"(q0), [p1] "r"(p1), [r3] "r"(r3), [q1] "r"(q1), |
| [ones] "r"(ones), [flimit] "r"(flimit)); |
| |
| *hev = hev1; |
| *mask = s2; |
| } |
| |
| /* inputs & outputs are quad-byte vectors */ |
| static __inline void vp8_filter_mips(uint32_t mask, uint32_t hev, uint32_t *ps1, |
| uint32_t *ps0, uint32_t *qs0, |
| uint32_t *qs1) { |
| int32_t vp8_filter_l, vp8_filter_r; |
| int32_t Filter1_l, Filter1_r, Filter2_l, Filter2_r; |
| int32_t subr_r, subr_l; |
| uint32_t t1, t2, HWM, t3; |
| uint32_t hev_l, hev_r, mask_l, mask_r, invhev_l, invhev_r; |
| |
| int32_t vps1, vps0, vqs0, vqs1; |
| int32_t vps1_l, vps1_r, vps0_l, vps0_r, vqs0_l, vqs0_r, vqs1_l, vqs1_r; |
| uint32_t N128; |
| |
| N128 = 0x80808080; |
| t1 = 0x03000300; |
| t2 = 0x04000400; |
| t3 = 0x01000100; |
| HWM = 0xFF00FF00; |
| |
| vps0 = (*ps0) ^ N128; |
| vps1 = (*ps1) ^ N128; |
| vqs0 = (*qs0) ^ N128; |
| vqs1 = (*qs1) ^ N128; |
| |
| /* use halfword pairs instead quad-bytes because of accuracy */ |
| vps0_l = vps0 & HWM; |
| vps0_r = vps0 << 8; |
| vps0_r = vps0_r & HWM; |
| |
| vps1_l = vps1 & HWM; |
| vps1_r = vps1 << 8; |
| vps1_r = vps1_r & HWM; |
| |
| vqs0_l = vqs0 & HWM; |
| vqs0_r = vqs0 << 8; |
| vqs0_r = vqs0_r & HWM; |
| |
| vqs1_l = vqs1 & HWM; |
| vqs1_r = vqs1 << 8; |
| vqs1_r = vqs1_r & HWM; |
| |
| mask_l = mask & HWM; |
| mask_r = mask << 8; |
| mask_r = mask_r & HWM; |
| |
| hev_l = hev & HWM; |
| hev_r = hev << 8; |
| hev_r = hev_r & HWM; |
| |
| __asm__ __volatile__( |
| /* vp8_filter = vp8_signed_char_clamp(ps1 - qs1); */ |
| "subq_s.ph %[vp8_filter_l], %[vps1_l], %[vqs1_l] \n\t" |
| "subq_s.ph %[vp8_filter_r], %[vps1_r], %[vqs1_r] \n\t" |
| |
| /* qs0 - ps0 */ |
| "subq_s.ph %[subr_l], %[vqs0_l], %[vps0_l] \n\t" |
| "subq_s.ph %[subr_r], %[vqs0_r], %[vps0_r] \n\t" |
| |
| /* vp8_filter &= hev; */ |
| "and %[vp8_filter_l], %[vp8_filter_l], %[hev_l] \n\t" |
| "and %[vp8_filter_r], %[vp8_filter_r], %[hev_r] \n\t" |
| |
| /* vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (qs0 - ps0)); */ |
| "addq_s.ph %[vp8_filter_l], %[vp8_filter_l], %[subr_l] \n\t" |
| "addq_s.ph %[vp8_filter_r], %[vp8_filter_r], %[subr_r] \n\t" |
| "xor %[invhev_l], %[hev_l], %[HWM] \n\t" |
| "addq_s.ph %[vp8_filter_l], %[vp8_filter_l], %[subr_l] \n\t" |
| "addq_s.ph %[vp8_filter_r], %[vp8_filter_r], %[subr_r] \n\t" |
| "xor %[invhev_r], %[hev_r], %[HWM] \n\t" |
| "addq_s.ph %[vp8_filter_l], %[vp8_filter_l], %[subr_l] \n\t" |
| "addq_s.ph %[vp8_filter_r], %[vp8_filter_r], %[subr_r] \n\t" |
| |
| /* vp8_filter &= mask; */ |
| "and %[vp8_filter_l], %[vp8_filter_l], %[mask_l] \n\t" |
| "and %[vp8_filter_r], %[vp8_filter_r], %[mask_r] \n\t" |
| |
| : [vp8_filter_l] "=&r"(vp8_filter_l), [vp8_filter_r] "=&r"(vp8_filter_r), |
| [subr_l] "=&r"(subr_l), [subr_r] "=&r"(subr_r), |
| [invhev_l] "=&r"(invhev_l), [invhev_r] "=&r"(invhev_r) |
| |
| : [vps0_l] "r"(vps0_l), [vps0_r] "r"(vps0_r), [vps1_l] "r"(vps1_l), |
| [vps1_r] "r"(vps1_r), [vqs0_l] "r"(vqs0_l), [vqs0_r] "r"(vqs0_r), |
| [vqs1_l] "r"(vqs1_l), [vqs1_r] "r"(vqs1_r), [mask_l] "r"(mask_l), |
| [mask_r] "r"(mask_r), [hev_l] "r"(hev_l), [hev_r] "r"(hev_r), |
| [HWM] "r"(HWM)); |
| |
| /* save bottom 3 bits so that we round one side +4 and the other +3 */ |
| __asm__ __volatile__( |
| /* Filter2 = vp8_signed_char_clamp(vp8_filter + 3) >>= 3; */ |
| "addq_s.ph %[Filter1_l], %[vp8_filter_l], %[t2] \n\t" |
| "addq_s.ph %[Filter1_r], %[vp8_filter_r], %[t2] \n\t" |
| |
| /* Filter1 = vp8_signed_char_clamp(vp8_filter + 4) >>= 3; */ |
| "addq_s.ph %[Filter2_l], %[vp8_filter_l], %[t1] \n\t" |
| "addq_s.ph %[Filter2_r], %[vp8_filter_r], %[t1] \n\t" |
| "shra.ph %[Filter1_r], %[Filter1_r], 3 \n\t" |
| "shra.ph %[Filter1_l], %[Filter1_l], 3 \n\t" |
| |
| "shra.ph %[Filter2_l], %[Filter2_l], 3 \n\t" |
| "shra.ph %[Filter2_r], %[Filter2_r], 3 \n\t" |
| |
| "and %[Filter1_l], %[Filter1_l], %[HWM] \n\t" |
| "and %[Filter1_r], %[Filter1_r], %[HWM] \n\t" |
| |
| /* vps0 = vp8_signed_char_clamp(ps0 + Filter2); */ |
| "addq_s.ph %[vps0_l], %[vps0_l], %[Filter2_l] \n\t" |
| "addq_s.ph %[vps0_r], %[vps0_r], %[Filter2_r] \n\t" |
| |
| /* vqs0 = vp8_signed_char_clamp(qs0 - Filter1); */ |
| "subq_s.ph %[vqs0_l], %[vqs0_l], %[Filter1_l] \n\t" |
| "subq_s.ph %[vqs0_r], %[vqs0_r], %[Filter1_r] \n\t" |
| |
| : [Filter1_l] "=&r"(Filter1_l), [Filter1_r] "=&r"(Filter1_r), |
| [Filter2_l] "=&r"(Filter2_l), [Filter2_r] "=&r"(Filter2_r), |
| [vps0_l] "+r"(vps0_l), [vps0_r] "+r"(vps0_r), [vqs0_l] "+r"(vqs0_l), |
| [vqs0_r] "+r"(vqs0_r) |
| |
| : [t1] "r"(t1), [t2] "r"(t2), [vp8_filter_l] "r"(vp8_filter_l), |
| [vp8_filter_r] "r"(vp8_filter_r), [HWM] "r"(HWM)); |
| |
| __asm__ __volatile__( |
| /* (vp8_filter += 1) >>= 1 */ |
| "addqh.ph %[Filter1_l], %[Filter1_l], %[t3] \n\t" |
| "addqh.ph %[Filter1_r], %[Filter1_r], %[t3] \n\t" |
| |
| /* vp8_filter &= ~hev; */ |
| "and %[Filter1_l], %[Filter1_l], %[invhev_l] \n\t" |
| "and %[Filter1_r], %[Filter1_r], %[invhev_r] \n\t" |
| |
| /* vps1 = vp8_signed_char_clamp(ps1 + vp8_filter); */ |
| "addq_s.ph %[vps1_l], %[vps1_l], %[Filter1_l] \n\t" |
| "addq_s.ph %[vps1_r], %[vps1_r], %[Filter1_r] \n\t" |
| |
| /* vqs1 = vp8_signed_char_clamp(qs1 - vp8_filter); */ |
| "subq_s.ph %[vqs1_l], %[vqs1_l], %[Filter1_l] \n\t" |
| "subq_s.ph %[vqs1_r], %[vqs1_r], %[Filter1_r] \n\t" |
| |
| : [Filter1_l] "+r"(Filter1_l), [Filter1_r] "+r"(Filter1_r), |
| [vps1_l] "+r"(vps1_l), [vps1_r] "+r"(vps1_r), [vqs1_l] "+r"(vqs1_l), |
| [vqs1_r] "+r"(vqs1_r) |
| |
| : [t3] "r"(t3), [invhev_l] "r"(invhev_l), [invhev_r] "r"(invhev_r)); |
| |
| /* Create quad-bytes from halfword pairs */ |
| vqs0_l = vqs0_l & HWM; |
| vqs1_l = vqs1_l & HWM; |
| vps0_l = vps0_l & HWM; |
| vps1_l = vps1_l & HWM; |
| |
| __asm__ __volatile__( |
| "shrl.ph %[vqs0_r], %[vqs0_r], 8 \n\t" |
| "shrl.ph %[vps0_r], %[vps0_r], 8 \n\t" |
| "shrl.ph %[vqs1_r], %[vqs1_r], 8 \n\t" |
| "shrl.ph %[vps1_r], %[vps1_r], 8 \n\t" |
| |
| : [vps1_r] "+r"(vps1_r), [vqs1_r] "+r"(vqs1_r), [vps0_r] "+r"(vps0_r), |
| [vqs0_r] "+r"(vqs0_r) |
| :); |
| |
| vqs0 = vqs0_l | vqs0_r; |
| vqs1 = vqs1_l | vqs1_r; |
| vps0 = vps0_l | vps0_r; |
| vps1 = vps1_l | vps1_r; |
| |
| *ps0 = vps0 ^ N128; |
| *ps1 = vps1 ^ N128; |
| *qs0 = vqs0 ^ N128; |
| *qs1 = vqs1 ^ N128; |
| } |
| |
| void vp8_loop_filter_horizontal_edge_mips(unsigned char *s, int p, |
| unsigned int flimit, |
| unsigned int limit, |
| unsigned int thresh, int count) { |
| uint32_t mask; |
| uint32_t hev; |
| uint32_t pm1, p0, p1, p2, p3, p4, p5, p6; |
| unsigned char *sm1, *s0, *s1, *s2, *s3, *s4, *s5, *s6; |
| (void)count; |
| |
| mask = 0; |
| hev = 0; |
| p1 = 0; |
| p2 = 0; |
| p3 = 0; |
| p4 = 0; |
| |
| /* prefetch data for store */ |
| prefetch_store_lf(s); |
| |
| /* loop filter designed to work using chars so that we can make maximum use |
| * of 8 bit simd instructions. |
| */ |
| |
| sm1 = s - (p << 2); |
| s0 = s - p - p - p; |
| s1 = s - p - p; |
| s2 = s - p; |
| s3 = s; |
| s4 = s + p; |
| s5 = s + p + p; |
| s6 = s + p + p + p; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p1 = *((uint32_t *)(s1)); |
| p2 = *((uint32_t *)(s2)); |
| p3 = *((uint32_t *)(s3)); |
| p4 = *((uint32_t *)(s4)); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| pm1 = *((uint32_t *)(sm1)); |
| p0 = *((uint32_t *)(s0)); |
| p5 = *((uint32_t *)(s5)); |
| p6 = *((uint32_t *)(s6)); |
| |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_filter_mips(mask, hev, &p1, &p2, &p3, &p4); |
| |
| /* unpack processed 4x4 neighborhood */ |
| *((uint32_t *)s1) = p1; |
| *((uint32_t *)s2) = p2; |
| *((uint32_t *)s3) = p3; |
| *((uint32_t *)s4) = p4; |
| } |
| } |
| |
| sm1 += 4; |
| s0 += 4; |
| s1 += 4; |
| s2 += 4; |
| s3 += 4; |
| s4 += 4; |
| s5 += 4; |
| s6 += 4; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p1 = *((uint32_t *)(s1)); |
| p2 = *((uint32_t *)(s2)); |
| p3 = *((uint32_t *)(s3)); |
| p4 = *((uint32_t *)(s4)); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| pm1 = *((uint32_t *)(sm1)); |
| p0 = *((uint32_t *)(s0)); |
| p5 = *((uint32_t *)(s5)); |
| p6 = *((uint32_t *)(s6)); |
| |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_filter_mips(mask, hev, &p1, &p2, &p3, &p4); |
| |
| /* unpack processed 4x4 neighborhood */ |
| *((uint32_t *)s1) = p1; |
| *((uint32_t *)s2) = p2; |
| *((uint32_t *)s3) = p3; |
| *((uint32_t *)s4) = p4; |
| } |
| } |
| |
| sm1 += 4; |
| s0 += 4; |
| s1 += 4; |
| s2 += 4; |
| s3 += 4; |
| s4 += 4; |
| s5 += 4; |
| s6 += 4; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p1 = *((uint32_t *)(s1)); |
| p2 = *((uint32_t *)(s2)); |
| p3 = *((uint32_t *)(s3)); |
| p4 = *((uint32_t *)(s4)); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| pm1 = *((uint32_t *)(sm1)); |
| p0 = *((uint32_t *)(s0)); |
| p5 = *((uint32_t *)(s5)); |
| p6 = *((uint32_t *)(s6)); |
| |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_filter_mips(mask, hev, &p1, &p2, &p3, &p4); |
| |
| /* unpack processed 4x4 neighborhood */ |
| *((uint32_t *)s1) = p1; |
| *((uint32_t *)s2) = p2; |
| *((uint32_t *)s3) = p3; |
| *((uint32_t *)s4) = p4; |
| } |
| } |
| |
| sm1 += 4; |
| s0 += 4; |
| s1 += 4; |
| s2 += 4; |
| s3 += 4; |
| s4 += 4; |
| s5 += 4; |
| s6 += 4; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p1 = *((uint32_t *)(s1)); |
| p2 = *((uint32_t *)(s2)); |
| p3 = *((uint32_t *)(s3)); |
| p4 = *((uint32_t *)(s4)); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| pm1 = *((uint32_t *)(sm1)); |
| p0 = *((uint32_t *)(s0)); |
| p5 = *((uint32_t *)(s5)); |
| p6 = *((uint32_t *)(s6)); |
| |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_filter_mips(mask, hev, &p1, &p2, &p3, &p4); |
| |
| /* unpack processed 4x4 neighborhood */ |
| *((uint32_t *)s1) = p1; |
| *((uint32_t *)s2) = p2; |
| *((uint32_t *)s3) = p3; |
| *((uint32_t *)s4) = p4; |
| } |
| } |
| } |
| |
| void vp8_loop_filter_uvhorizontal_edge_mips(unsigned char *s, int p, |
| unsigned int flimit, |
| unsigned int limit, |
| unsigned int thresh, int count) { |
| uint32_t mask; |
| uint32_t hev; |
| uint32_t pm1, p0, p1, p2, p3, p4, p5, p6; |
| unsigned char *sm1, *s0, *s1, *s2, *s3, *s4, *s5, *s6; |
| (void)count; |
| |
| mask = 0; |
| hev = 0; |
| p1 = 0; |
| p2 = 0; |
| p3 = 0; |
| p4 = 0; |
| |
| /* loop filter designed to work using chars so that we can make maximum use |
| * of 8 bit simd instructions. |
| */ |
| |
| sm1 = s - (p << 2); |
| s0 = s - p - p - p; |
| s1 = s - p - p; |
| s2 = s - p; |
| s3 = s; |
| s4 = s + p; |
| s5 = s + p + p; |
| s6 = s + p + p + p; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p1 = *((uint32_t *)(s1)); |
| p2 = *((uint32_t *)(s2)); |
| p3 = *((uint32_t *)(s3)); |
| p4 = *((uint32_t *)(s4)); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| pm1 = *((uint32_t *)(sm1)); |
| p0 = *((uint32_t *)(s0)); |
| p5 = *((uint32_t *)(s5)); |
| p6 = *((uint32_t *)(s6)); |
| |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_filter_mips(mask, hev, &p1, &p2, &p3, &p4); |
| |
| /* unpack processed 4x4 neighborhood */ |
| *((uint32_t *)s1) = p1; |
| *((uint32_t *)s2) = p2; |
| *((uint32_t *)s3) = p3; |
| *((uint32_t *)s4) = p4; |
| } |
| } |
| |
| sm1 += 4; |
| s0 += 4; |
| s1 += 4; |
| s2 += 4; |
| s3 += 4; |
| s4 += 4; |
| s5 += 4; |
| s6 += 4; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p1 = *((uint32_t *)(s1)); |
| p2 = *((uint32_t *)(s2)); |
| p3 = *((uint32_t *)(s3)); |
| p4 = *((uint32_t *)(s4)); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| pm1 = *((uint32_t *)(sm1)); |
| p0 = *((uint32_t *)(s0)); |
| p5 = *((uint32_t *)(s5)); |
| p6 = *((uint32_t *)(s6)); |
| |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_filter_mips(mask, hev, &p1, &p2, &p3, &p4); |
| |
| /* unpack processed 4x4 neighborhood */ |
| *((uint32_t *)s1) = p1; |
| *((uint32_t *)s2) = p2; |
| *((uint32_t *)s3) = p3; |
| *((uint32_t *)s4) = p4; |
| } |
| } |
| } |
| |
| void vp8_loop_filter_vertical_edge_mips(unsigned char *s, int p, |
| const unsigned int flimit, |
| const unsigned int limit, |
| const unsigned int thresh, int count) { |
| int i; |
| uint32_t mask, hev; |
| uint32_t pm1, p0, p1, p2, p3, p4, p5, p6; |
| unsigned char *s1, *s2, *s3, *s4; |
| uint32_t prim1, prim2, sec3, sec4, prim3, prim4; |
| |
| hev = 0; |
| mask = 0; |
| i = 0; |
| pm1 = 0; |
| p0 = 0; |
| p1 = 0; |
| p2 = 0; |
| p3 = 0; |
| p4 = 0; |
| p5 = 0; |
| p6 = 0; |
| |
| /* loop filter designed to work using chars so that we can make maximum use |
| * of 8 bit simd instructions. |
| */ |
| |
| /* apply filter on 4 pixesl at the same time */ |
| do { |
| /* prefetch data for store */ |
| prefetch_store_lf(s + p); |
| |
| s1 = s; |
| s2 = s + p; |
| s3 = s2 + p; |
| s4 = s3 + p; |
| s = s4 + p; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p2 = *((uint32_t *)(s1 - 4)); |
| p6 = *((uint32_t *)(s1)); |
| p1 = *((uint32_t *)(s2 - 4)); |
| p5 = *((uint32_t *)(s2)); |
| p0 = *((uint32_t *)(s3 - 4)); |
| p4 = *((uint32_t *)(s3)); |
| pm1 = *((uint32_t *)(s4 - 4)); |
| p3 = *((uint32_t *)(s4)); |
| |
| /* transpose pm1, p0, p1, p2 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p2], %[p1] \n\t" |
| "precr.qb.ph %[prim2], %[p2], %[p1] \n\t" |
| "precrq.qb.ph %[prim3], %[p0], %[pm1] \n\t" |
| "precr.qb.ph %[prim4], %[p0], %[pm1] \n\t" |
| |
| "precrq.qb.ph %[p1], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[pm1], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p2], %[p1], %[sec3] \n\t" |
| "precrq.ph.w %[p0], %[pm1], %[sec4] \n\t" |
| "append %[p1], %[sec3], 16 \n\t" |
| "append %[pm1], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p2] "+r"(p2), [p1] "+r"(p1), [p0] "+r"(p0), |
| [pm1] "+r"(pm1), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* transpose p3, p4, p5, p6 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p6], %[p5] \n\t" |
| "precr.qb.ph %[prim2], %[p6], %[p5] \n\t" |
| "precrq.qb.ph %[prim3], %[p4], %[p3] \n\t" |
| "precr.qb.ph %[prim4], %[p4], %[p3] \n\t" |
| |
| "precrq.qb.ph %[p5], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[p3], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p6], %[p5], %[sec3] \n\t" |
| "precrq.ph.w %[p4], %[p3], %[sec4] \n\t" |
| "append %[p5], %[sec3], 16 \n\t" |
| "append %[p3], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p6] "+r"(p6), [p5] "+r"(p5), [p4] "+r"(p4), |
| [p3] "+r"(p3), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_filter_mips(mask, hev, &p1, &p2, &p3, &p4); |
| |
| /* unpack processed 4x4 neighborhood |
| * don't use transpose on output data |
| * because memory isn't aligned |
| */ |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s4]) \n\t" |
| "sb %[p3], 0(%[s4]) \n\t" |
| "sb %[p2], -1(%[s4]) \n\t" |
| "sb %[p1], -2(%[s4]) \n\t" |
| : |
| : [p4] "r"(p4), [p3] "r"(p3), [s4] "r"(s4), [p2] "r"(p2), |
| [p1] "r"(p1)); |
| |
| __asm__ __volatile__( |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| : [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), [p1] "+r"(p1) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s3]) \n\t" |
| "sb %[p3], 0(%[s3]) \n\t" |
| "sb %[p2], -1(%[s3]) \n\t" |
| "sb %[p1], -2(%[s3]) \n\t" |
| : [p1] "+r"(p1) |
| : [p4] "r"(p4), [p3] "r"(p3), [s3] "r"(s3), [p2] "r"(p2)); |
| |
| __asm__ __volatile__( |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| : [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), [p1] "+r"(p1) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s2]) \n\t" |
| "sb %[p3], 0(%[s2]) \n\t" |
| "sb %[p2], -1(%[s2]) \n\t" |
| "sb %[p1], -2(%[s2]) \n\t" |
| : |
| : [p4] "r"(p4), [p3] "r"(p3), [s2] "r"(s2), [p2] "r"(p2), |
| [p1] "r"(p1)); |
| |
| __asm__ __volatile__( |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| : [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), [p1] "+r"(p1) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s1]) \n\t" |
| "sb %[p3], 0(%[s1]) \n\t" |
| "sb %[p2], -1(%[s1]) \n\t" |
| "sb %[p1], -2(%[s1]) \n\t" |
| : |
| : [p4] "r"(p4), [p3] "r"(p3), [s1] "r"(s1), [p2] "r"(p2), |
| [p1] "r"(p1)); |
| } |
| } |
| |
| s1 = s; |
| s2 = s + p; |
| s3 = s2 + p; |
| s4 = s3 + p; |
| s = s4 + p; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p2 = *((uint32_t *)(s1 - 4)); |
| p6 = *((uint32_t *)(s1)); |
| p1 = *((uint32_t *)(s2 - 4)); |
| p5 = *((uint32_t *)(s2)); |
| p0 = *((uint32_t *)(s3 - 4)); |
| p4 = *((uint32_t *)(s3)); |
| pm1 = *((uint32_t *)(s4 - 4)); |
| p3 = *((uint32_t *)(s4)); |
| |
| /* transpose pm1, p0, p1, p2 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p2], %[p1] \n\t" |
| "precr.qb.ph %[prim2], %[p2], %[p1] \n\t" |
| "precrq.qb.ph %[prim3], %[p0], %[pm1] \n\t" |
| "precr.qb.ph %[prim4], %[p0], %[pm1] \n\t" |
| |
| "precrq.qb.ph %[p1], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[pm1], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p2], %[p1], %[sec3] \n\t" |
| "precrq.ph.w %[p0], %[pm1], %[sec4] \n\t" |
| "append %[p1], %[sec3], 16 \n\t" |
| "append %[pm1], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p2] "+r"(p2), [p1] "+r"(p1), [p0] "+r"(p0), |
| [pm1] "+r"(pm1), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* transpose p3, p4, p5, p6 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p6], %[p5] \n\t" |
| "precr.qb.ph %[prim2], %[p6], %[p5] \n\t" |
| "precrq.qb.ph %[prim3], %[p4], %[p3] \n\t" |
| "precr.qb.ph %[prim4], %[p4], %[p3] \n\t" |
| |
| "precrq.qb.ph %[p5], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[p3], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p6], %[p5], %[sec3] \n\t" |
| "precrq.ph.w %[p4], %[p3], %[sec4] \n\t" |
| "append %[p5], %[sec3], 16 \n\t" |
| "append %[p3], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p6] "+r"(p6), [p5] "+r"(p5), [p4] "+r"(p4), |
| [p3] "+r"(p3), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_filter_mips(mask, hev, &p1, &p2, &p3, &p4); |
| |
| /* unpack processed 4x4 neighborhood |
| * don't use transpose on output data |
| * because memory isn't aligned |
| */ |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s4]) \n\t" |
| "sb %[p3], 0(%[s4]) \n\t" |
| "sb %[p2], -1(%[s4]) \n\t" |
| "sb %[p1], -2(%[s4]) \n\t" |
| : |
| : [p4] "r"(p4), [p3] "r"(p3), [s4] "r"(s4), [p2] "r"(p2), |
| [p1] "r"(p1)); |
| |
| __asm__ __volatile__( |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| : [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), [p1] "+r"(p1) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s3]) \n\t" |
| "sb %[p3], 0(%[s3]) \n\t" |
| "sb %[p2], -1(%[s3]) \n\t" |
| "sb %[p1], -2(%[s3]) \n\t" |
| : [p1] "+r"(p1) |
| : [p4] "r"(p4), [p3] "r"(p3), [s3] "r"(s3), [p2] "r"(p2)); |
| |
| __asm__ __volatile__( |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| : [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), [p1] "+r"(p1) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s2]) \n\t" |
| "sb %[p3], 0(%[s2]) \n\t" |
| "sb %[p2], -1(%[s2]) \n\t" |
| "sb %[p1], -2(%[s2]) \n\t" |
| : |
| : [p4] "r"(p4), [p3] "r"(p3), [s2] "r"(s2), [p2] "r"(p2), |
| [p1] "r"(p1)); |
| |
| __asm__ __volatile__( |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| : [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), [p1] "+r"(p1) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s1]) \n\t" |
| "sb %[p3], 0(%[s1]) \n\t" |
| "sb %[p2], -1(%[s1]) \n\t" |
| "sb %[p1], -2(%[s1]) \n\t" |
| : |
| : [p4] "r"(p4), [p3] "r"(p3), [s1] "r"(s1), [p2] "r"(p2), |
| [p1] "r"(p1)); |
| } |
| } |
| |
| i += 8; |
| } |
| |
| while (i < count); |
| } |
| |
| void vp8_loop_filter_uvvertical_edge_mips(unsigned char *s, int p, |
| unsigned int flimit, |
| unsigned int limit, |
| unsigned int thresh, int count) { |
| uint32_t mask, hev; |
| uint32_t pm1, p0, p1, p2, p3, p4, p5, p6; |
| unsigned char *s1, *s2, *s3, *s4; |
| uint32_t prim1, prim2, sec3, sec4, prim3, prim4; |
| (void)count; |
| |
| /* loop filter designed to work using chars so that we can make maximum use |
| * of 8 bit simd instructions. |
| */ |
| |
| /* apply filter on 4 pixesl at the same time */ |
| |
| s1 = s; |
| s2 = s + p; |
| s3 = s2 + p; |
| s4 = s3 + p; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p2 = *((uint32_t *)(s1 - 4)); |
| p6 = *((uint32_t *)(s1)); |
| p1 = *((uint32_t *)(s2 - 4)); |
| p5 = *((uint32_t *)(s2)); |
| p0 = *((uint32_t *)(s3 - 4)); |
| p4 = *((uint32_t *)(s3)); |
| pm1 = *((uint32_t *)(s4 - 4)); |
| p3 = *((uint32_t *)(s4)); |
| |
| /* transpose pm1, p0, p1, p2 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p2], %[p1] \n\t" |
| "precr.qb.ph %[prim2], %[p2], %[p1] \n\t" |
| "precrq.qb.ph %[prim3], %[p0], %[pm1] \n\t" |
| "precr.qb.ph %[prim4], %[p0], %[pm1] \n\t" |
| |
| "precrq.qb.ph %[p1], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[pm1], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p2], %[p1], %[sec3] \n\t" |
| "precrq.ph.w %[p0], %[pm1], %[sec4] \n\t" |
| "append %[p1], %[sec3], 16 \n\t" |
| "append %[pm1], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p2] "+r"(p2), [p1] "+r"(p1), [p0] "+r"(p0), |
| [pm1] "+r"(pm1), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* transpose p3, p4, p5, p6 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p6], %[p5] \n\t" |
| "precr.qb.ph %[prim2], %[p6], %[p5] \n\t" |
| "precrq.qb.ph %[prim3], %[p4], %[p3] \n\t" |
| "precr.qb.ph %[prim4], %[p4], %[p3] \n\t" |
| |
| "precrq.qb.ph %[p5], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[p3], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p6], %[p5], %[sec3] \n\t" |
| "precrq.ph.w %[p4], %[p3], %[sec4] \n\t" |
| "append %[p5], %[sec3], 16 \n\t" |
| "append %[p3], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p6] "+r"(p6), [p5] "+r"(p5), [p4] "+r"(p4), |
| [p3] "+r"(p3), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_filter_mips(mask, hev, &p1, &p2, &p3, &p4); |
| |
| /* unpack processed 4x4 neighborhood |
| * don't use transpose on output data |
| * because memory isn't aligned |
| */ |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s4]) \n\t" |
| "sb %[p3], 0(%[s4]) \n\t" |
| "sb %[p2], -1(%[s4]) \n\t" |
| "sb %[p1], -2(%[s4]) \n\t" |
| : |
| : |
| [p4] "r"(p4), [p3] "r"(p3), [s4] "r"(s4), [p2] "r"(p2), [p1] "r"(p1)); |
| |
| __asm__ __volatile__( |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| : [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), [p1] "+r"(p1) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s3]) \n\t" |
| "sb %[p3], 0(%[s3]) \n\t" |
| "sb %[p2], -1(%[s3]) \n\t" |
| "sb %[p1], -2(%[s3]) \n\t" |
| : [p1] "+r"(p1) |
| : [p4] "r"(p4), [p3] "r"(p3), [s3] "r"(s3), [p2] "r"(p2)); |
| |
| __asm__ __volatile__( |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| : [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), [p1] "+r"(p1) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s2]) \n\t" |
| "sb %[p3], 0(%[s2]) \n\t" |
| "sb %[p2], -1(%[s2]) \n\t" |
| "sb %[p1], -2(%[s2]) \n\t" |
| : |
| : |
| [p4] "r"(p4), [p3] "r"(p3), [s2] "r"(s2), [p2] "r"(p2), [p1] "r"(p1)); |
| |
| __asm__ __volatile__( |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| : [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), [p1] "+r"(p1) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s1]) \n\t" |
| "sb %[p3], 0(%[s1]) \n\t" |
| "sb %[p2], -1(%[s1]) \n\t" |
| "sb %[p1], -2(%[s1]) \n\t" |
| : |
| : |
| [p4] "r"(p4), [p3] "r"(p3), [s1] "r"(s1), [p2] "r"(p2), [p1] "r"(p1)); |
| } |
| } |
| |
| s1 = s4 + p; |
| s2 = s1 + p; |
| s3 = s2 + p; |
| s4 = s3 + p; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p2 = *((uint32_t *)(s1 - 4)); |
| p6 = *((uint32_t *)(s1)); |
| p1 = *((uint32_t *)(s2 - 4)); |
| p5 = *((uint32_t *)(s2)); |
| p0 = *((uint32_t *)(s3 - 4)); |
| p4 = *((uint32_t *)(s3)); |
| pm1 = *((uint32_t *)(s4 - 4)); |
| p3 = *((uint32_t *)(s4)); |
| |
| /* transpose pm1, p0, p1, p2 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p2], %[p1] \n\t" |
| "precr.qb.ph %[prim2], %[p2], %[p1] \n\t" |
| "precrq.qb.ph %[prim3], %[p0], %[pm1] \n\t" |
| "precr.qb.ph %[prim4], %[p0], %[pm1] \n\t" |
| |
| "precrq.qb.ph %[p1], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[pm1], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p2], %[p1], %[sec3] \n\t" |
| "precrq.ph.w %[p0], %[pm1], %[sec4] \n\t" |
| "append %[p1], %[sec3], 16 \n\t" |
| "append %[pm1], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p2] "+r"(p2), [p1] "+r"(p1), [p0] "+r"(p0), |
| [pm1] "+r"(pm1), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* transpose p3, p4, p5, p6 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p6], %[p5] \n\t" |
| "precr.qb.ph %[prim2], %[p6], %[p5] \n\t" |
| "precrq.qb.ph %[prim3], %[p4], %[p3] \n\t" |
| "precr.qb.ph %[prim4], %[p4], %[p3] \n\t" |
| |
| "precrq.qb.ph %[p5], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[p3], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p6], %[p5], %[sec3] \n\t" |
| "precrq.ph.w %[p4], %[p3], %[sec4] \n\t" |
| "append %[p5], %[sec3], 16 \n\t" |
| "append %[p3], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p6] "+r"(p6), [p5] "+r"(p5), [p4] "+r"(p4), |
| [p3] "+r"(p3), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_filter_mips(mask, hev, &p1, &p2, &p3, &p4); |
| |
| /* unpack processed 4x4 neighborhood |
| * don't use transpose on output data |
| * because memory isn't aligned |
| */ |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s4]) \n\t" |
| "sb %[p3], 0(%[s4]) \n\t" |
| "sb %[p2], -1(%[s4]) \n\t" |
| "sb %[p1], -2(%[s4]) \n\t" |
| : |
| : |
| [p4] "r"(p4), [p3] "r"(p3), [s4] "r"(s4), [p2] "r"(p2), [p1] "r"(p1)); |
| |
| __asm__ __volatile__( |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| : [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), [p1] "+r"(p1) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s3]) \n\t" |
| "sb %[p3], 0(%[s3]) \n\t" |
| "sb %[p2], -1(%[s3]) \n\t" |
| "sb %[p1], -2(%[s3]) \n\t" |
| : [p1] "+r"(p1) |
| : [p4] "r"(p4), [p3] "r"(p3), [s3] "r"(s3), [p2] "r"(p2)); |
| |
| __asm__ __volatile__( |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| : [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), [p1] "+r"(p1) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s2]) \n\t" |
| "sb %[p3], 0(%[s2]) \n\t" |
| "sb %[p2], -1(%[s2]) \n\t" |
| "sb %[p1], -2(%[s2]) \n\t" |
| : |
| : |
| [p4] "r"(p4), [p3] "r"(p3), [s2] "r"(s2), [p2] "r"(p2), [p1] "r"(p1)); |
| |
| __asm__ __volatile__( |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| : [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), [p1] "+r"(p1) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p4], 1(%[s1]) \n\t" |
| "sb %[p3], 0(%[s1]) \n\t" |
| "sb %[p2], -1(%[s1]) \n\t" |
| "sb %[p1], -2(%[s1]) \n\t" |
| : |
| : |
| [p4] "r"(p4), [p3] "r"(p3), [s1] "r"(s1), [p2] "r"(p2), [p1] "r"(p1)); |
| } |
| } |
| } |
| |
| /* inputs & outputs are quad-byte vectors */ |
| static __inline void vp8_mbfilter_mips(uint32_t mask, uint32_t hev, |
| uint32_t *ps2, uint32_t *ps1, |
| uint32_t *ps0, uint32_t *qs0, |
| uint32_t *qs1, uint32_t *qs2) { |
| int32_t vps2, vps1, vps0, vqs0, vqs1, vqs2; |
| int32_t vps2_l, vps1_l, vps0_l, vqs0_l, vqs1_l, vqs2_l; |
| int32_t vps2_r, vps1_r, vps0_r, vqs0_r, vqs1_r, vqs2_r; |
| uint32_t HWM, vp8_filter_l, vp8_filter_r, mask_l, mask_r, hev_l, hev_r, |
| subr_r, subr_l; |
| uint32_t Filter2_l, Filter2_r, t1, t2, Filter1_l, Filter1_r, invhev_l, |
| invhev_r; |
| uint32_t N128, R63; |
| uint32_t u1_l, u1_r, u2_l, u2_r, u3_l, u3_r; |
| |
| R63 = 0x003F003F; |
| HWM = 0xFF00FF00; |
| N128 = 0x80808080; |
| t1 = 0x03000300; |
| t2 = 0x04000400; |
| |
| vps0 = (*ps0) ^ N128; |
| vps1 = (*ps1) ^ N128; |
| vps2 = (*ps2) ^ N128; |
| vqs0 = (*qs0) ^ N128; |
| vqs1 = (*qs1) ^ N128; |
| vqs2 = (*qs2) ^ N128; |
| |
| /* use halfword pairs instead quad-bytes because of accuracy */ |
| vps0_l = vps0 & HWM; |
| vps0_r = vps0 << 8; |
| vps0_r = vps0_r & HWM; |
| |
| vqs0_l = vqs0 & HWM; |
| vqs0_r = vqs0 << 8; |
| vqs0_r = vqs0_r & HWM; |
| |
| vps1_l = vps1 & HWM; |
| vps1_r = vps1 << 8; |
| vps1_r = vps1_r & HWM; |
| |
| vqs1_l = vqs1 & HWM; |
| vqs1_r = vqs1 << 8; |
| vqs1_r = vqs1_r & HWM; |
| |
| vqs2_l = vqs2 & HWM; |
| vqs2_r = vqs2 << 8; |
| vqs2_r = vqs2_r & HWM; |
| |
| __asm__ __volatile__( |
| /* qs0 - ps0 */ |
| "subq_s.ph %[subr_l], %[vqs0_l], %[vps0_l] \n\t" |
| "subq_s.ph %[subr_r], %[vqs0_r], %[vps0_r] \n\t" |
| |
| /* vp8_filter = vp8_signed_char_clamp(ps1 - qs1); */ |
| "subq_s.ph %[vp8_filter_l], %[vps1_l], %[vqs1_l] \n\t" |
| "subq_s.ph %[vp8_filter_r], %[vps1_r], %[vqs1_r] \n\t" |
| |
| : [vp8_filter_l] "=&r"(vp8_filter_l), [vp8_filter_r] "=r"(vp8_filter_r), |
| [subr_l] "=&r"(subr_l), [subr_r] "=&r"(subr_r) |
| : [vps0_l] "r"(vps0_l), [vps0_r] "r"(vps0_r), [vps1_l] "r"(vps1_l), |
| [vps1_r] "r"(vps1_r), [vqs0_l] "r"(vqs0_l), [vqs0_r] "r"(vqs0_r), |
| [vqs1_l] "r"(vqs1_l), [vqs1_r] "r"(vqs1_r)); |
| |
| vps2_l = vps2 & HWM; |
| vps2_r = vps2 << 8; |
| vps2_r = vps2_r & HWM; |
| |
| /* add outer taps if we have high edge variance */ |
| __asm__ __volatile__( |
| /* vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (qs0 - ps0)); */ |
| "addq_s.ph %[vp8_filter_l], %[vp8_filter_l], %[subr_l] \n\t" |
| "addq_s.ph %[vp8_filter_r], %[vp8_filter_r], %[subr_r] \n\t" |
| "and %[mask_l], %[HWM], %[mask] \n\t" |
| "sll %[mask_r], %[mask], 8 \n\t" |
| "and %[mask_r], %[HWM], %[mask_r] \n\t" |
| "addq_s.ph %[vp8_filter_l], %[vp8_filter_l], %[subr_l] \n\t" |
| "addq_s.ph %[vp8_filter_r], %[vp8_filter_r], %[subr_r] \n\t" |
| "and %[hev_l], %[HWM], %[hev] \n\t" |
| "sll %[hev_r], %[hev], 8 \n\t" |
| "and %[hev_r], %[HWM], %[hev_r] \n\t" |
| "addq_s.ph %[vp8_filter_l], %[vp8_filter_l], %[subr_l] \n\t" |
| "addq_s.ph %[vp8_filter_r], %[vp8_filter_r], %[subr_r] \n\t" |
| |
| /* vp8_filter &= mask; */ |
| "and %[vp8_filter_l], %[vp8_filter_l], %[mask_l] \n\t" |
| "and %[vp8_filter_r], %[vp8_filter_r], %[mask_r] \n\t" |
| |
| /* Filter2 = vp8_filter & hev; */ |
| "and %[Filter2_l], %[vp8_filter_l], %[hev_l] \n\t" |
| "and %[Filter2_r], %[vp8_filter_r], %[hev_r] \n\t" |
| |
| : [vp8_filter_l] "+r"(vp8_filter_l), [vp8_filter_r] "+r"(vp8_filter_r), |
| [hev_l] "=&r"(hev_l), [hev_r] "=&r"(hev_r), [mask_l] "=&r"(mask_l), |
| [mask_r] "=&r"(mask_r), [Filter2_l] "=&r"(Filter2_l), |
| [Filter2_r] "=&r"(Filter2_r) |
| : [subr_l] "r"(subr_l), [subr_r] "r"(subr_r), [HWM] "r"(HWM), |
| [hev] "r"(hev), [mask] "r"(mask)); |
| |
| /* save bottom 3 bits so that we round one side +4 and the other +3 */ |
| __asm__ __volatile__( |
| /* Filter1 = vp8_signed_char_clamp(Filter2 + 4) >>= 3; */ |
| "addq_s.ph %[Filter1_l], %[Filter2_l], %[t2] \n\t" |
| "xor %[invhev_l], %[hev_l], %[HWM] \n\t" |
| "addq_s.ph %[Filter1_r], %[Filter2_r], %[t2] \n\t" |
| |
| /* Filter2 = vp8_signed_char_clamp(Filter2 + 3) >>= 3; */ |
| "addq_s.ph %[Filter2_l], %[Filter2_l], %[t1] \n\t" |
| "addq_s.ph %[Filter2_r], %[Filter2_r], %[t1] \n\t" |
| |
| "shra.ph %[Filter1_l], %[Filter1_l], 3 \n\t" |
| "shra.ph %[Filter1_r], %[Filter1_r], 3 \n\t" |
| |
| "shra.ph %[Filter2_l], %[Filter2_l], 3 \n\t" |
| "shra.ph %[Filter2_r], %[Filter2_r], 3 \n\t" |
| "and %[Filter1_l], %[Filter1_l], %[HWM] \n\t" |
| "and %[Filter1_r], %[Filter1_r], %[HWM] \n\t" |
| "xor %[invhev_r], %[hev_r], %[HWM] \n\t" |
| |
| /* qs0 = vp8_signed_char_clamp(qs0 - Filter1); */ |
| "subq_s.ph %[vqs0_l], %[vqs0_l], %[Filter1_l] \n\t" |
| "subq_s.ph %[vqs0_r], %[vqs0_r], %[Filter1_r] \n\t" |
| |
| /* ps0 = vp8_signed_char_clamp(ps0 + Filter2); */ |
| "addq_s.ph %[vps0_l], %[vps0_l], %[Filter2_l] \n\t" |
| "addq_s.ph %[vps0_r], %[vps0_r], %[Filter2_r] \n\t" |
| |
| : [invhev_l] "=&r"(invhev_l), [invhev_r] "=&r"(invhev_r), |
| [Filter1_l] "=&r"(Filter1_l), [Filter1_r] "=&r"(Filter1_r), |
| [Filter2_l] "+r"(Filter2_l), [Filter2_r] "+r"(Filter2_r), |
| [vps0_l] "+r"(vps0_l), [vps0_r] "+r"(vps0_r), [vqs0_l] "+r"(vqs0_l), |
| [vqs0_r] "+r"(vqs0_r) |
| : [t1] "r"(t1), [t2] "r"(t2), [HWM] "r"(HWM), [hev_l] "r"(hev_l), |
| [hev_r] "r"(hev_r)); |
| |
| /* only apply wider filter if not high edge variance */ |
| __asm__ __volatile__( |
| /* vp8_filter &= ~hev; */ |
| "and %[Filter2_l], %[vp8_filter_l], %[invhev_l] \n\t" |
| "and %[Filter2_r], %[vp8_filter_r], %[invhev_r] \n\t" |
| |
| "shra.ph %[Filter2_l], %[Filter2_l], 8 \n\t" |
| "shra.ph %[Filter2_r], %[Filter2_r], 8 \n\t" |
| |
| : [Filter2_l] "=&r"(Filter2_l), [Filter2_r] "=&r"(Filter2_r) |
| : [vp8_filter_l] "r"(vp8_filter_l), [vp8_filter_r] "r"(vp8_filter_r), |
| [invhev_l] "r"(invhev_l), [invhev_r] "r"(invhev_r)); |
| |
| /* roughly 3/7th difference across boundary */ |
| __asm__ __volatile__( |
| "shll.ph %[u3_l], %[Filter2_l], 3 \n\t" |
| "shll.ph %[u3_r], %[Filter2_r], 3 \n\t" |
| |
| "addq.ph %[u3_l], %[u3_l], %[Filter2_l] \n\t" |
| "addq.ph %[u3_r], %[u3_r], %[Filter2_r] \n\t" |
| |
| "shll.ph %[u2_l], %[u3_l], 1 \n\t" |
| "shll.ph %[u2_r], %[u3_r], 1 \n\t" |
| |
| "addq.ph %[u1_l], %[u3_l], %[u2_l] \n\t" |
| "addq.ph %[u1_r], %[u3_r], %[u2_r] \n\t" |
| |
| "addq.ph %[u2_l], %[u2_l], %[R63] \n\t" |
| "addq.ph %[u2_r], %[u2_r], %[R63] \n\t" |
| |
| "addq.ph %[u3_l], %[u3_l], %[R63] \n\t" |
| "addq.ph %[u3_r], %[u3_r], %[R63] \n\t" |
| |
| /* vp8_signed_char_clamp((63 + Filter2 * 27) >> 7) |
| * vp8_signed_char_clamp((63 + Filter2 * 18) >> 7) |
| */ |
| "addq.ph %[u1_l], %[u1_l], %[R63] \n\t" |
| "addq.ph %[u1_r], %[u1_r], %[R63] \n\t" |
| "shra.ph %[u1_l], %[u1_l], 7 \n\t" |
| "shra.ph %[u1_r], %[u1_r], 7 \n\t" |
| "shra.ph %[u2_l], %[u2_l], 7 \n\t" |
| "shra.ph %[u2_r], %[u2_r], 7 \n\t" |
| "shll.ph %[u1_l], %[u1_l], 8 \n\t" |
| "shll.ph %[u1_r], %[u1_r], 8 \n\t" |
| "shll.ph %[u2_l], %[u2_l], 8 \n\t" |
| "shll.ph %[u2_r], %[u2_r], 8 \n\t" |
| |
| /* vqs0 = vp8_signed_char_clamp(qs0 - u); */ |
| "subq_s.ph %[vqs0_l], %[vqs0_l], %[u1_l] \n\t" |
| "subq_s.ph %[vqs0_r], %[vqs0_r], %[u1_r] \n\t" |
| |
| /* vps0 = vp8_signed_char_clamp(ps0 + u); */ |
| "addq_s.ph %[vps0_l], %[vps0_l], %[u1_l] \n\t" |
| "addq_s.ph %[vps0_r], %[vps0_r], %[u1_r] \n\t" |
| |
| : [u1_l] "=&r"(u1_l), [u1_r] "=&r"(u1_r), [u2_l] "=&r"(u2_l), |
| [u2_r] "=&r"(u2_r), [u3_l] "=&r"(u3_l), [u3_r] "=&r"(u3_r), |
| [vps0_l] "+r"(vps0_l), [vps0_r] "+r"(vps0_r), [vqs0_l] "+r"(vqs0_l), |
| [vqs0_r] "+r"(vqs0_r) |
| : [R63] "r"(R63), [Filter2_l] "r"(Filter2_l), [Filter2_r] "r"(Filter2_r)); |
| |
| __asm__ __volatile__( |
| /* vqs1 = vp8_signed_char_clamp(qs1 - u); */ |
| "subq_s.ph %[vqs1_l], %[vqs1_l], %[u2_l] \n\t" |
| "addq_s.ph %[vps1_l], %[vps1_l], %[u2_l] \n\t" |
| |
| /* vps1 = vp8_signed_char_clamp(ps1 + u); */ |
| "addq_s.ph %[vps1_r], %[vps1_r], %[u2_r] \n\t" |
| "subq_s.ph %[vqs1_r], %[vqs1_r], %[u2_r] \n\t" |
| |
| : [vps1_l] "+r"(vps1_l), [vps1_r] "+r"(vps1_r), [vqs1_l] "+r"(vqs1_l), |
| [vqs1_r] "+r"(vqs1_r) |
| : [u2_l] "r"(u2_l), [u2_r] "r"(u2_r)); |
| |
| /* roughly 1/7th difference across boundary */ |
| __asm__ __volatile__( |
| /* u = vp8_signed_char_clamp((63 + Filter2 * 9) >> 7); */ |
| "shra.ph %[u3_l], %[u3_l], 7 \n\t" |
| "shra.ph %[u3_r], %[u3_r], 7 \n\t" |
| "shll.ph %[u3_l], %[u3_l], 8 \n\t" |
| "shll.ph %[u3_r], %[u3_r], 8 \n\t" |
| |
| /* vqs2 = vp8_signed_char_clamp(qs2 - u); */ |
| "subq_s.ph %[vqs2_l], %[vqs2_l], %[u3_l] \n\t" |
| "subq_s.ph %[vqs2_r], %[vqs2_r], %[u3_r] \n\t" |
| |
| /* vps2 = vp8_signed_char_clamp(ps2 + u); */ |
| "addq_s.ph %[vps2_l], %[vps2_l], %[u3_l] \n\t" |
| "addq_s.ph %[vps2_r], %[vps2_r], %[u3_r] \n\t" |
| |
| : [u3_l] "+r"(u3_l), [u3_r] "+r"(u3_r), [vps2_l] "+r"(vps2_l), |
| [vps2_r] "+r"(vps2_r), [vqs2_l] "+r"(vqs2_l), [vqs2_r] "+r"(vqs2_r) |
| :); |
| |
| /* Create quad-bytes from halfword pairs */ |
| __asm__ __volatile__( |
| "and %[vqs0_l], %[vqs0_l], %[HWM] \n\t" |
| "shrl.ph %[vqs0_r], %[vqs0_r], 8 \n\t" |
| |
| "and %[vps0_l], %[vps0_l], %[HWM] \n\t" |
| "shrl.ph %[vps0_r], %[vps0_r], 8 \n\t" |
| |
| "and %[vqs1_l], %[vqs1_l], %[HWM] \n\t" |
| "shrl.ph %[vqs1_r], %[vqs1_r], 8 \n\t" |
| |
| "and %[vps1_l], %[vps1_l], %[HWM] \n\t" |
| "shrl.ph %[vps1_r], %[vps1_r], 8 \n\t" |
| |
| "and %[vqs2_l], %[vqs2_l], %[HWM] \n\t" |
| "shrl.ph %[vqs2_r], %[vqs2_r], 8 \n\t" |
| |
| "and %[vps2_l], %[vps2_l], %[HWM] \n\t" |
| "shrl.ph %[vps2_r], %[vps2_r], 8 \n\t" |
| |
| "or %[vqs0_r], %[vqs0_l], %[vqs0_r] \n\t" |
| "or %[vps0_r], %[vps0_l], %[vps0_r] \n\t" |
| "or %[vqs1_r], %[vqs1_l], %[vqs1_r] \n\t" |
| "or %[vps1_r], %[vps1_l], %[vps1_r] \n\t" |
| "or %[vqs2_r], %[vqs2_l], %[vqs2_r] \n\t" |
| "or %[vps2_r], %[vps2_l], %[vps2_r] \n\t" |
| |
| : [vps1_l] "+r"(vps1_l), [vps1_r] "+r"(vps1_r), [vqs1_l] "+r"(vqs1_l), |
| [vqs1_r] "+r"(vqs1_r), [vps0_l] "+r"(vps0_l), [vps0_r] "+r"(vps0_r), |
| [vqs0_l] "+r"(vqs0_l), [vqs0_r] "+r"(vqs0_r), [vqs2_l] "+r"(vqs2_l), |
| [vqs2_r] "+r"(vqs2_r), [vps2_r] "+r"(vps2_r), [vps2_l] "+r"(vps2_l) |
| : [HWM] "r"(HWM)); |
| |
| *ps0 = vps0_r ^ N128; |
| *ps1 = vps1_r ^ N128; |
| *ps2 = vps2_r ^ N128; |
| *qs0 = vqs0_r ^ N128; |
| *qs1 = vqs1_r ^ N128; |
| *qs2 = vqs2_r ^ N128; |
| } |
| |
| void vp8_mbloop_filter_horizontal_edge_mips(unsigned char *s, int p, |
| unsigned int flimit, |
| unsigned int limit, |
| unsigned int thresh, int count) { |
| int i; |
| uint32_t mask, hev; |
| uint32_t pm1, p0, p1, p2, p3, p4, p5, p6; |
| unsigned char *sm1, *s0, *s1, *s2, *s3, *s4, *s5, *s6; |
| |
| mask = 0; |
| hev = 0; |
| i = 0; |
| p1 = 0; |
| p2 = 0; |
| p3 = 0; |
| p4 = 0; |
| |
| /* loop filter designed to work using chars so that we can make maximum use |
| * of 8 bit simd instructions. |
| */ |
| |
| sm1 = s - (p << 2); |
| s0 = s - p - p - p; |
| s1 = s - p - p; |
| s2 = s - p; |
| s3 = s; |
| s4 = s + p; |
| s5 = s + p + p; |
| s6 = s + p + p + p; |
| |
| /* prefetch data for load */ |
| prefetch_load_lf(s + p); |
| |
| /* apply filter on 4 pixesl at the same time */ |
| do { |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p1 = *((uint32_t *)(s1)); |
| p2 = *((uint32_t *)(s2)); |
| p3 = *((uint32_t *)(s3)); |
| p4 = *((uint32_t *)(s4)); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| pm1 = *((uint32_t *)(sm1)); |
| p0 = *((uint32_t *)(s0)); |
| p5 = *((uint32_t *)(s5)); |
| p6 = *((uint32_t *)(s6)); |
| |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_mbfilter_mips(mask, hev, &p0, &p1, &p2, &p3, &p4, &p5); |
| |
| /* unpack processed 4x4 neighborhood |
| * memory is 4 byte aligned |
| */ |
| *((uint32_t *)s0) = p0; |
| *((uint32_t *)s1) = p1; |
| *((uint32_t *)s2) = p2; |
| *((uint32_t *)s3) = p3; |
| *((uint32_t *)s4) = p4; |
| *((uint32_t *)s5) = p5; |
| } |
| } |
| |
| sm1 += 4; |
| s0 += 4; |
| s1 += 4; |
| s2 += 4; |
| s3 += 4; |
| s4 += 4; |
| s5 += 4; |
| s6 += 4; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p1 = *((uint32_t *)(s1)); |
| p2 = *((uint32_t *)(s2)); |
| p3 = *((uint32_t *)(s3)); |
| p4 = *((uint32_t *)(s4)); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| pm1 = *((uint32_t *)(sm1)); |
| p0 = *((uint32_t *)(s0)); |
| p5 = *((uint32_t *)(s5)); |
| p6 = *((uint32_t *)(s6)); |
| |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_mbfilter_mips(mask, hev, &p0, &p1, &p2, &p3, &p4, &p5); |
| |
| /* unpack processed 4x4 neighborhood |
| * memory is 4 byte aligned |
| */ |
| *((uint32_t *)s0) = p0; |
| *((uint32_t *)s1) = p1; |
| *((uint32_t *)s2) = p2; |
| *((uint32_t *)s3) = p3; |
| *((uint32_t *)s4) = p4; |
| *((uint32_t *)s5) = p5; |
| } |
| } |
| |
| sm1 += 4; |
| s0 += 4; |
| s1 += 4; |
| s2 += 4; |
| s3 += 4; |
| s4 += 4; |
| s5 += 4; |
| s6 += 4; |
| |
| i += 8; |
| } |
| |
| while (i < count); |
| } |
| |
| void vp8_mbloop_filter_uvhorizontal_edge_mips(unsigned char *s, int p, |
| unsigned int flimit, |
| unsigned int limit, |
| unsigned int thresh, int count) { |
| uint32_t mask, hev; |
| uint32_t pm1, p0, p1, p2, p3, p4, p5, p6; |
| unsigned char *sm1, *s0, *s1, *s2, *s3, *s4, *s5, *s6; |
| (void)count; |
| |
| mask = 0; |
| hev = 0; |
| p1 = 0; |
| p2 = 0; |
| p3 = 0; |
| p4 = 0; |
| |
| /* loop filter designed to work using chars so that we can make maximum use |
| * of 8 bit simd instructions. |
| */ |
| |
| sm1 = s - (p << 2); |
| s0 = s - p - p - p; |
| s1 = s - p - p; |
| s2 = s - p; |
| s3 = s; |
| s4 = s + p; |
| s5 = s + p + p; |
| s6 = s + p + p + p; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p1 = *((uint32_t *)(s1)); |
| p2 = *((uint32_t *)(s2)); |
| p3 = *((uint32_t *)(s3)); |
| p4 = *((uint32_t *)(s4)); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| pm1 = *((uint32_t *)(sm1)); |
| p0 = *((uint32_t *)(s0)); |
| p5 = *((uint32_t *)(s5)); |
| p6 = *((uint32_t *)(s6)); |
| |
| /* if mask == 0 do filtering is not needed */ |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| if (mask) { |
| /* filtering */ |
| vp8_mbfilter_mips(mask, hev, &p0, &p1, &p2, &p3, &p4, &p5); |
| |
| /* unpack processed 4x4 neighborhood |
| * memory is 4 byte aligned |
| */ |
| *((uint32_t *)s0) = p0; |
| *((uint32_t *)s1) = p1; |
| *((uint32_t *)s2) = p2; |
| *((uint32_t *)s3) = p3; |
| *((uint32_t *)s4) = p4; |
| *((uint32_t *)s5) = p5; |
| } |
| } |
| |
| sm1 += 4; |
| s0 += 4; |
| s1 += 4; |
| s2 += 4; |
| s3 += 4; |
| s4 += 4; |
| s5 += 4; |
| s6 += 4; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p1 = *((uint32_t *)(s1)); |
| p2 = *((uint32_t *)(s2)); |
| p3 = *((uint32_t *)(s3)); |
| p4 = *((uint32_t *)(s4)); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| pm1 = *((uint32_t *)(sm1)); |
| p0 = *((uint32_t *)(s0)); |
| p5 = *((uint32_t *)(s5)); |
| p6 = *((uint32_t *)(s6)); |
| |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_mbfilter_mips(mask, hev, &p0, &p1, &p2, &p3, &p4, &p5); |
| |
| /* unpack processed 4x4 neighborhood |
| * memory is 4 byte aligned |
| */ |
| *((uint32_t *)s0) = p0; |
| *((uint32_t *)s1) = p1; |
| *((uint32_t *)s2) = p2; |
| *((uint32_t *)s3) = p3; |
| *((uint32_t *)s4) = p4; |
| *((uint32_t *)s5) = p5; |
| } |
| } |
| } |
| |
| void vp8_mbloop_filter_vertical_edge_mips(unsigned char *s, int p, |
| unsigned int flimit, |
| unsigned int limit, |
| unsigned int thresh, int count) { |
| int i; |
| uint32_t mask, hev; |
| uint32_t pm1, p0, p1, p2, p3, p4, p5, p6; |
| unsigned char *s1, *s2, *s3, *s4; |
| uint32_t prim1, prim2, sec3, sec4, prim3, prim4; |
| |
| mask = 0; |
| hev = 0; |
| i = 0; |
| pm1 = 0; |
| p0 = 0; |
| p1 = 0; |
| p2 = 0; |
| p3 = 0; |
| p4 = 0; |
| p5 = 0; |
| p6 = 0; |
| |
| /* loop filter designed to work using chars so that we can make maximum use |
| * of 8 bit simd instructions. |
| */ |
| |
| /* apply filter on 4 pixesl at the same time */ |
| do { |
| s1 = s; |
| s2 = s + p; |
| s3 = s2 + p; |
| s4 = s3 + p; |
| s = s4 + p; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p2 = *((uint32_t *)(s1 - 4)); |
| p6 = *((uint32_t *)(s1)); |
| p1 = *((uint32_t *)(s2 - 4)); |
| p5 = *((uint32_t *)(s2)); |
| p0 = *((uint32_t *)(s3 - 4)); |
| p4 = *((uint32_t *)(s3)); |
| pm1 = *((uint32_t *)(s4 - 4)); |
| p3 = *((uint32_t *)(s4)); |
| |
| /* transpose pm1, p0, p1, p2 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p2], %[p1] \n\t" |
| "precr.qb.ph %[prim2], %[p2], %[p1] \n\t" |
| "precrq.qb.ph %[prim3], %[p0], %[pm1] \n\t" |
| "precr.qb.ph %[prim4], %[p0], %[pm1] \n\t" |
| |
| "precrq.qb.ph %[p1], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[pm1], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p2], %[p1], %[sec3] \n\t" |
| "precrq.ph.w %[p0], %[pm1], %[sec4] \n\t" |
| "append %[p1], %[sec3], 16 \n\t" |
| "append %[pm1], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p2] "+r"(p2), [p1] "+r"(p1), [p0] "+r"(p0), |
| [pm1] "+r"(pm1), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* transpose p3, p4, p5, p6 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p6], %[p5] \n\t" |
| "precr.qb.ph %[prim2], %[p6], %[p5] \n\t" |
| "precrq.qb.ph %[prim3], %[p4], %[p3] \n\t" |
| "precr.qb.ph %[prim4], %[p4], %[p3] \n\t" |
| |
| "precrq.qb.ph %[p5], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[p3], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p6], %[p5], %[sec3] \n\t" |
| "precrq.ph.w %[p4], %[p3], %[sec4] \n\t" |
| "append %[p5], %[sec3], 16 \n\t" |
| "append %[p3], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p6] "+r"(p6), [p5] "+r"(p5), [p4] "+r"(p4), |
| [p3] "+r"(p3), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_mbfilter_mips(mask, hev, &p0, &p1, &p2, &p3, &p4, &p5); |
| |
| /* don't use transpose on output data |
| * because memory isn't aligned |
| */ |
| __asm__ __volatile__( |
| "sb %[p5], 2(%[s4]) \n\t" |
| "sb %[p4], 1(%[s4]) \n\t" |
| "sb %[p3], 0(%[s4]) \n\t" |
| "sb %[p2], -1(%[s4]) \n\t" |
| "sb %[p1], -2(%[s4]) \n\t" |
| "sb %[p0], -3(%[s4]) \n\t" |
| : |
| : [p5] "r"(p5), [p4] "r"(p4), [p3] "r"(p3), [s4] "r"(s4), |
| [p2] "r"(p2), [p1] "r"(p1), [p0] "r"(p0)); |
| |
| __asm__ __volatile__( |
| "srl %[p5], %[p5], 8 \n\t" |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| "srl %[p0], %[p0], 8 \n\t" |
| : [p5] "+r"(p5), [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), |
| [p1] "+r"(p1), [p0] "+r"(p0) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p5], 2(%[s3]) \n\t" |
| "sb %[p4], 1(%[s3]) \n\t" |
| "sb %[p3], 0(%[s3]) \n\t" |
| "sb %[p2], -1(%[s3]) \n\t" |
| "sb %[p1], -2(%[s3]) \n\t" |
| "sb %[p0], -3(%[s3]) \n\t" |
| : |
| : [p5] "r"(p5), [p4] "r"(p4), [p3] "r"(p3), [s3] "r"(s3), |
| [p2] "r"(p2), [p1] "r"(p1), [p0] "r"(p0)); |
| |
| __asm__ __volatile__( |
| "srl %[p5], %[p5], 8 \n\t" |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| "srl %[p0], %[p0], 8 \n\t" |
| : [p5] "+r"(p5), [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), |
| [p1] "+r"(p1), [p0] "+r"(p0) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p5], 2(%[s2]) \n\t" |
| "sb %[p4], 1(%[s2]) \n\t" |
| "sb %[p3], 0(%[s2]) \n\t" |
| "sb %[p2], -1(%[s2]) \n\t" |
| "sb %[p1], -2(%[s2]) \n\t" |
| "sb %[p0], -3(%[s2]) \n\t" |
| : |
| : [p5] "r"(p5), [p4] "r"(p4), [p3] "r"(p3), [s2] "r"(s2), |
| [p2] "r"(p2), [p1] "r"(p1), [p0] "r"(p0)); |
| |
| __asm__ __volatile__( |
| "srl %[p5], %[p5], 8 \n\t" |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| "srl %[p0], %[p0], 8 \n\t" |
| : [p5] "+r"(p5), [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), |
| [p1] "+r"(p1), [p0] "+r"(p0) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p5], 2(%[s1]) \n\t" |
| "sb %[p4], 1(%[s1]) \n\t" |
| "sb %[p3], 0(%[s1]) \n\t" |
| "sb %[p2], -1(%[s1]) \n\t" |
| "sb %[p1], -2(%[s1]) \n\t" |
| "sb %[p0], -3(%[s1]) \n\t" |
| : |
| : [p5] "r"(p5), [p4] "r"(p4), [p3] "r"(p3), [s1] "r"(s1), |
| [p2] "r"(p2), [p1] "r"(p1), [p0] "r"(p0)); |
| } |
| } |
| |
| i += 4; |
| } |
| |
| while (i < count); |
| } |
| |
| void vp8_mbloop_filter_uvvertical_edge_mips(unsigned char *s, int p, |
| unsigned int flimit, |
| unsigned int limit, |
| unsigned int thresh, int count) { |
| uint32_t mask, hev; |
| uint32_t pm1, p0, p1, p2, p3, p4, p5, p6; |
| unsigned char *s1, *s2, *s3, *s4; |
| uint32_t prim1, prim2, sec3, sec4, prim3, prim4; |
| (void)count; |
| |
| mask = 0; |
| hev = 0; |
| pm1 = 0; |
| p0 = 0; |
| p1 = 0; |
| p2 = 0; |
| p3 = 0; |
| p4 = 0; |
| p5 = 0; |
| p6 = 0; |
| |
| /* loop filter designed to work using chars so that we can make maximum use |
| * of 8 bit simd instructions. |
| */ |
| |
| /* apply filter on 4 pixesl at the same time */ |
| |
| s1 = s; |
| s2 = s + p; |
| s3 = s2 + p; |
| s4 = s3 + p; |
| |
| /* prefetch data for load */ |
| prefetch_load_lf(s + 2 * p); |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p2 = *((uint32_t *)(s1 - 4)); |
| p6 = *((uint32_t *)(s1)); |
| p1 = *((uint32_t *)(s2 - 4)); |
| p5 = *((uint32_t *)(s2)); |
| p0 = *((uint32_t *)(s3 - 4)); |
| p4 = *((uint32_t *)(s3)); |
| pm1 = *((uint32_t *)(s4 - 4)); |
| p3 = *((uint32_t *)(s4)); |
| |
| /* transpose pm1, p0, p1, p2 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p2], %[p1] \n\t" |
| "precr.qb.ph %[prim2], %[p2], %[p1] \n\t" |
| "precrq.qb.ph %[prim3], %[p0], %[pm1] \n\t" |
| "precr.qb.ph %[prim4], %[p0], %[pm1] \n\t" |
| |
| "precrq.qb.ph %[p1], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[pm1], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p2], %[p1], %[sec3] \n\t" |
| "precrq.ph.w %[p0], %[pm1], %[sec4] \n\t" |
| "append %[p1], %[sec3], 16 \n\t" |
| "append %[pm1], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p2] "+r"(p2), [p1] "+r"(p1), [p0] "+r"(p0), |
| [pm1] "+r"(pm1), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* transpose p3, p4, p5, p6 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p6], %[p5] \n\t" |
| "precr.qb.ph %[prim2], %[p6], %[p5] \n\t" |
| "precrq.qb.ph %[prim3], %[p4], %[p3] \n\t" |
| "precr.qb.ph %[prim4], %[p4], %[p3] \n\t" |
| |
| "precrq.qb.ph %[p5], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[p3], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p6], %[p5], %[sec3] \n\t" |
| "precrq.ph.w %[p4], %[p3], %[sec4] \n\t" |
| "append %[p5], %[sec3], 16 \n\t" |
| "append %[p3], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p6] "+r"(p6), [p5] "+r"(p5), [p4] "+r"(p4), |
| [p3] "+r"(p3), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_mbfilter_mips(mask, hev, &p0, &p1, &p2, &p3, &p4, &p5); |
| |
| /* don't use transpose on output data |
| * because memory isn't aligned |
| */ |
| __asm__ __volatile__( |
| "sb %[p5], 2(%[s4]) \n\t" |
| "sb %[p4], 1(%[s4]) \n\t" |
| "sb %[p3], 0(%[s4]) \n\t" |
| "sb %[p2], -1(%[s4]) \n\t" |
| "sb %[p1], -2(%[s4]) \n\t" |
| "sb %[p0], -3(%[s4]) \n\t" |
| : |
| : [p5] "r"(p5), [p4] "r"(p4), [p3] "r"(p3), [s4] "r"(s4), |
| [p2] "r"(p2), [p1] "r"(p1), [p0] "r"(p0)); |
| |
| __asm__ __volatile__( |
| "srl %[p5], %[p5], 8 \n\t" |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| "srl %[p0], %[p0], 8 \n\t" |
| : [p5] "+r"(p5), [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), |
| [p1] "+r"(p1), [p0] "+r"(p0) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p5], 2(%[s3]) \n\t" |
| "sb %[p4], 1(%[s3]) \n\t" |
| "sb %[p3], 0(%[s3]) \n\t" |
| "sb %[p2], -1(%[s3]) \n\t" |
| "sb %[p1], -2(%[s3]) \n\t" |
| "sb %[p0], -3(%[s3]) \n\t" |
| : |
| : [p5] "r"(p5), [p4] "r"(p4), [p3] "r"(p3), [s3] "r"(s3), |
| [p2] "r"(p2), [p1] "r"(p1), [p0] "r"(p0)); |
| |
| __asm__ __volatile__( |
| "srl %[p5], %[p5], 8 \n\t" |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| "srl %[p0], %[p0], 8 \n\t" |
| : [p5] "+r"(p5), [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), |
| [p1] "+r"(p1), [p0] "+r"(p0) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p5], 2(%[s2]) \n\t" |
| "sb %[p4], 1(%[s2]) \n\t" |
| "sb %[p3], 0(%[s2]) \n\t" |
| "sb %[p2], -1(%[s2]) \n\t" |
| "sb %[p1], -2(%[s2]) \n\t" |
| "sb %[p0], -3(%[s2]) \n\t" |
| : |
| : [p5] "r"(p5), [p4] "r"(p4), [p3] "r"(p3), [s2] "r"(s2), |
| [p2] "r"(p2), [p1] "r"(p1), [p0] "r"(p0)); |
| |
| __asm__ __volatile__( |
| "srl %[p5], %[p5], 8 \n\t" |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| "srl %[p0], %[p0], 8 \n\t" |
| : [p5] "+r"(p5), [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), |
| [p1] "+r"(p1), [p0] "+r"(p0) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p5], 2(%[s1]) \n\t" |
| "sb %[p4], 1(%[s1]) \n\t" |
| "sb %[p3], 0(%[s1]) \n\t" |
| "sb %[p2], -1(%[s1]) \n\t" |
| "sb %[p1], -2(%[s1]) \n\t" |
| "sb %[p0], -3(%[s1]) \n\t" |
| : |
| : [p5] "r"(p5), [p4] "r"(p4), [p3] "r"(p3), [s1] "r"(s1), |
| [p2] "r"(p2), [p1] "r"(p1), [p0] "r"(p0)); |
| } |
| } |
| |
| s1 = s4 + p; |
| s2 = s1 + p; |
| s3 = s2 + p; |
| s4 = s3 + p; |
| |
| /* load quad-byte vectors |
| * memory is 4 byte aligned |
| */ |
| p2 = *((uint32_t *)(s1 - 4)); |
| p6 = *((uint32_t *)(s1)); |
| p1 = *((uint32_t *)(s2 - 4)); |
| p5 = *((uint32_t *)(s2)); |
| p0 = *((uint32_t *)(s3 - 4)); |
| p4 = *((uint32_t *)(s3)); |
| pm1 = *((uint32_t *)(s4 - 4)); |
| p3 = *((uint32_t *)(s4)); |
| |
| /* transpose pm1, p0, p1, p2 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p2], %[p1] \n\t" |
| "precr.qb.ph %[prim2], %[p2], %[p1] \n\t" |
| "precrq.qb.ph %[prim3], %[p0], %[pm1] \n\t" |
| "precr.qb.ph %[prim4], %[p0], %[pm1] \n\t" |
| |
| "precrq.qb.ph %[p1], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[pm1], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p2], %[p1], %[sec3] \n\t" |
| "precrq.ph.w %[p0], %[pm1], %[sec4] \n\t" |
| "append %[p1], %[sec3], 16 \n\t" |
| "append %[pm1], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p2] "+r"(p2), [p1] "+r"(p1), [p0] "+r"(p0), |
| [pm1] "+r"(pm1), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* transpose p3, p4, p5, p6 */ |
| __asm__ __volatile__( |
| "precrq.qb.ph %[prim1], %[p6], %[p5] \n\t" |
| "precr.qb.ph %[prim2], %[p6], %[p5] \n\t" |
| "precrq.qb.ph %[prim3], %[p4], %[p3] \n\t" |
| "precr.qb.ph %[prim4], %[p4], %[p3] \n\t" |
| |
| "precrq.qb.ph %[p5], %[prim1], %[prim2] \n\t" |
| "precr.qb.ph %[p3], %[prim1], %[prim2] \n\t" |
| "precrq.qb.ph %[sec3], %[prim3], %[prim4] \n\t" |
| "precr.qb.ph %[sec4], %[prim3], %[prim4] \n\t" |
| |
| "precrq.ph.w %[p6], %[p5], %[sec3] \n\t" |
| "precrq.ph.w %[p4], %[p3], %[sec4] \n\t" |
| "append %[p5], %[sec3], 16 \n\t" |
| "append %[p3], %[sec4], 16 \n\t" |
| |
| : [prim1] "=&r"(prim1), [prim2] "=&r"(prim2), [prim3] "=&r"(prim3), |
| [prim4] "=&r"(prim4), [p6] "+r"(p6), [p5] "+r"(p5), [p4] "+r"(p4), |
| [p3] "+r"(p3), [sec3] "=&r"(sec3), [sec4] "=&r"(sec4) |
| :); |
| |
| /* if (p1 - p4 == 0) and (p2 - p3 == 0) |
| * mask will be zero and filtering is not needed |
| */ |
| if (!(((p1 - p4) == 0) && ((p2 - p3) == 0))) { |
| vp8_filter_mask_vec_mips(limit, flimit, p1, p2, pm1, p0, p3, p4, p5, p6, |
| thresh, &hev, &mask); |
| |
| /* if mask == 0 do filtering is not needed */ |
| if (mask) { |
| /* filtering */ |
| vp8_mbfilter_mips(mask, hev, &p0, &p1, &p2, &p3, &p4, &p5); |
| |
| /* don't use transpose on output data |
| * because memory isn't aligned |
| */ |
| __asm__ __volatile__( |
| "sb %[p5], 2(%[s4]) \n\t" |
| "sb %[p4], 1(%[s4]) \n\t" |
| "sb %[p3], 0(%[s4]) \n\t" |
| "sb %[p2], -1(%[s4]) \n\t" |
| "sb %[p1], -2(%[s4]) \n\t" |
| "sb %[p0], -3(%[s4]) \n\t" |
| : |
| : [p5] "r"(p5), [p4] "r"(p4), [p3] "r"(p3), [s4] "r"(s4), |
| [p2] "r"(p2), [p1] "r"(p1), [p0] "r"(p0)); |
| |
| __asm__ __volatile__( |
| "srl %[p5], %[p5], 8 \n\t" |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| "srl %[p0], %[p0], 8 \n\t" |
| : [p5] "+r"(p5), [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), |
| [p1] "+r"(p1), [p0] "+r"(p0) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p5], 2(%[s3]) \n\t" |
| "sb %[p4], 1(%[s3]) \n\t" |
| "sb %[p3], 0(%[s3]) \n\t" |
| "sb %[p2], -1(%[s3]) \n\t" |
| "sb %[p1], -2(%[s3]) \n\t" |
| "sb %[p0], -3(%[s3]) \n\t" |
| : |
| : [p5] "r"(p5), [p4] "r"(p4), [p3] "r"(p3), [s3] "r"(s3), |
| [p2] "r"(p2), [p1] "r"(p1), [p0] "r"(p0)); |
| |
| __asm__ __volatile__( |
| "srl %[p5], %[p5], 8 \n\t" |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| "srl %[p0], %[p0], 8 \n\t" |
| : [p5] "+r"(p5), [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), |
| [p1] "+r"(p1), [p0] "+r"(p0) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p5], 2(%[s2]) \n\t" |
| "sb %[p4], 1(%[s2]) \n\t" |
| "sb %[p3], 0(%[s2]) \n\t" |
| "sb %[p2], -1(%[s2]) \n\t" |
| "sb %[p1], -2(%[s2]) \n\t" |
| "sb %[p0], -3(%[s2]) \n\t" |
| : |
| : [p5] "r"(p5), [p4] "r"(p4), [p3] "r"(p3), [s2] "r"(s2), |
| [p2] "r"(p2), [p1] "r"(p1), [p0] "r"(p0)); |
| |
| __asm__ __volatile__( |
| "srl %[p5], %[p5], 8 \n\t" |
| "srl %[p4], %[p4], 8 \n\t" |
| "srl %[p3], %[p3], 8 \n\t" |
| "srl %[p2], %[p2], 8 \n\t" |
| "srl %[p1], %[p1], 8 \n\t" |
| "srl %[p0], %[p0], 8 \n\t" |
| : [p5] "+r"(p5), [p4] "+r"(p4), [p3] "+r"(p3), [p2] "+r"(p2), |
| [p1] "+r"(p1), [p0] "+r"(p0) |
| :); |
| |
| __asm__ __volatile__( |
| "sb %[p5], 2(%[s1]) \n\t" |
| "sb %[p4], 1(%[s1]) \n\t" |
| "sb %[p3], 0(%[s1]) \n\t" |
| "sb %[p2], -1(%[s1]) \n\t" |
| "sb %[p1], -2(%[s1]) \n\t" |
| "sb %[p0], -3(%[s1]) \n\t" |
| : |
| : [p5] "r"(p5), [p4] "r"(p4), [p3] "r"(p3), [s1] "r"(s1), |
| [p2] "r"(p2), [p1] "r"(p1), [p0] "r"(p0)); |
| } |
| } |
| } |
| |
| /* Horizontal MB filtering */ |
| void vp8_loop_filter_mbh_dspr2(unsigned char *y_ptr, unsigned char *u_ptr, |
| unsigned char *v_ptr, int y_stride, |
| int uv_stride, loop_filter_info *lfi) { |
| unsigned int thresh_vec, flimit_vec, limit_vec; |
| unsigned char thresh, flimit, limit, flimit_temp; |
| |
| /* use direct value instead pointers */ |
| limit = *(lfi->lim); |
| flimit_temp = *(lfi->mblim); |
| thresh = *(lfi->hev_thr); |
| flimit = flimit_temp; |
| |
| /* create quad-byte */ |
| __asm__ __volatile__( |
| "replv.qb %[thresh_vec], %[thresh] \n\t" |
| "replv.qb %[flimit_vec], %[flimit] \n\t" |
| "replv.qb %[limit_vec], %[limit] \n\t" |
| : [thresh_vec] "=&r"(thresh_vec), [flimit_vec] "=&r"(flimit_vec), |
| [limit_vec] "=r"(limit_vec) |
| : [thresh] "r"(thresh), [flimit] "r"(flimit), [limit] "r"(limit)); |
| |
| vp8_mbloop_filter_horizontal_edge_mips(y_ptr, y_stride, flimit_vec, limit_vec, |
| thresh_vec, 16); |
| |
| if (u_ptr) { |
| vp8_mbloop_filter_uvhorizontal_edge_mips(u_ptr, uv_stride, flimit_vec, |
| limit_vec, thresh_vec, 0); |
| } |
| |
| if (v_ptr) { |
| vp8_mbloop_filter_uvhorizontal_edge_mips(v_ptr, uv_stride, flimit_vec, |
| limit_vec, thresh_vec, 0); |
| } |
| } |
| |
| /* Vertical MB Filtering */ |
| void vp8_loop_filter_mbv_dspr2(unsigned char *y_ptr, unsigned char *u_ptr, |
| unsigned char *v_ptr, int y_stride, |
| int uv_stride, loop_filter_info *lfi) { |
| unsigned int thresh_vec, flimit_vec, limit_vec; |
| unsigned char thresh, flimit, limit, flimit_temp; |
| |
| /* use direct value instead pointers */ |
| limit = *(lfi->lim); |
| flimit_temp = *(lfi->mblim); |
| thresh = *(lfi->hev_thr); |
| flimit = flimit_temp; |
| |
| /* create quad-byte */ |
| __asm__ __volatile__( |
| "replv.qb %[thresh_vec], %[thresh] \n\t" |
| "replv.qb %[flimit_vec], %[flimit] \n\t" |
| "replv.qb %[limit_vec], %[limit] \n\t" |
| : [thresh_vec] "=&r"(thresh_vec), [flimit_vec] "=&r"(flimit_vec), |
| [limit_vec] "=r"(limit_vec) |
| : [thresh] "r"(thresh), [flimit] "r"(flimit), [limit] "r"(limit)); |
| |
| vp8_mbloop_filter_vertical_edge_mips(y_ptr, y_stride, flimit_vec, limit_vec, |
| thresh_vec, 16); |
| |
| if (u_ptr) |
| vp8_mbloop_filter_uvvertical_edge_mips(u_ptr, uv_stride, flimit_vec, |
| limit_vec, thresh_vec, 0); |
| |
| if (v_ptr) |
| vp8_mbloop_filter_uvvertical_edge_mips(v_ptr, uv_stride, flimit_vec, |
| limit_vec, thresh_vec, 0); |
| } |
| |
| /* Horizontal B Filtering */ |
| void vp8_loop_filter_bh_dspr2(unsigned char *y_ptr, unsigned char *u_ptr, |
| unsigned char *v_ptr, int y_stride, int uv_stride, |
| loop_filter_info *lfi) { |
| unsigned int thresh_vec, flimit_vec, limit_vec; |
| unsigned char thresh, flimit, limit, flimit_temp; |
| |
| /* use direct value instead pointers */ |
| limit = *(lfi->lim); |
| flimit_temp = *(lfi->blim); |
| thresh = *(lfi->hev_thr); |
| flimit = flimit_temp; |
| |
| /* create quad-byte */ |
| __asm__ __volatile__( |
| "replv.qb %[thresh_vec], %[thresh] \n\t" |
| "replv.qb %[flimit_vec], %[flimit] \n\t" |
| "replv.qb %[limit_vec], %[limit] \n\t" |
| : [thresh_vec] "=&r"(thresh_vec), [flimit_vec] "=&r"(flimit_vec), |
| [limit_vec] "=r"(limit_vec) |
| : [thresh] "r"(thresh), [flimit] "r"(flimit), [limit] "r"(limit)); |
| |
| vp8_loop_filter_horizontal_edge_mips(y_ptr + 4 * y_stride, y_stride, |
| flimit_vec, limit_vec, thresh_vec, 16); |
| vp8_loop_filter_horizontal_edge_mips(y_ptr + 8 * y_stride, y_stride, |
| flimit_vec, limit_vec, thresh_vec, 16); |
| vp8_loop_filter_horizontal_edge_mips(y_ptr + 12 * y_stride, y_stride, |
| flimit_vec, limit_vec, thresh_vec, 16); |
| |
| if (u_ptr) |
| vp8_loop_filter_uvhorizontal_edge_mips( |
| u_ptr + 4 * uv_stride, uv_stride, flimit_vec, limit_vec, thresh_vec, 0); |
| |
| if (v_ptr) |
| vp8_loop_filter_uvhorizontal_edge_mips( |
| v_ptr + 4 * uv_stride, uv_stride, flimit_vec, limit_vec, thresh_vec, 0); |
| } |
| |
| /* Vertical B Filtering */ |
| void vp8_loop_filter_bv_dspr2(unsigned char *y_ptr, unsigned char *u_ptr, |
| unsigned char *v_ptr, int y_stride, int uv_stride, |
| loop_filter_info *lfi) { |
| unsigned int thresh_vec, flimit_vec, limit_vec; |
| unsigned char thresh, flimit, limit, flimit_temp; |
| |
| /* use direct value instead pointers */ |
| limit = *(lfi->lim); |
| flimit_temp = *(lfi->blim); |
| thresh = *(lfi->hev_thr); |
| flimit = flimit_temp; |
| |
| /* create quad-byte */ |
| __asm__ __volatile__( |
| "replv.qb %[thresh_vec], %[thresh] \n\t" |
| "replv.qb %[flimit_vec], %[flimit] \n\t" |
| "replv.qb %[limit_vec], %[limit] \n\t" |
| : [thresh_vec] "=&r"(thresh_vec), [flimit_vec] "=&r"(flimit_vec), |
| [limit_vec] "=r"(limit_vec) |
| : [thresh] "r"(thresh), [flimit] "r"(flimit), [limit] "r"(limit)); |
| |
| vp8_loop_filter_vertical_edge_mips(y_ptr + 4, y_stride, flimit_vec, limit_vec, |
| thresh_vec, 16); |
| vp8_loop_filter_vertical_edge_mips(y_ptr + 8, y_stride, flimit_vec, limit_vec, |
| thresh_vec, 16); |
| vp8_loop_filter_vertical_edge_mips(y_ptr + 12, y_stride, flimit_vec, |
| limit_vec, thresh_vec, 16); |
| |
| if (u_ptr) |
| vp8_loop_filter_uvvertical_edge_mips(u_ptr + 4, uv_stride, flimit_vec, |
| limit_vec, thresh_vec, 0); |
| |
| if (v_ptr) |
| vp8_loop_filter_uvvertical_edge_mips(v_ptr + 4, uv_stride, flimit_vec, |
| limit_vec, thresh_vec, 0); |
| } |
| |
| #endif |