mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2026-10-28 18:07:12 +08:00
Implement Qualcomm Hexagon Vector Extensions (HVX) 128-byte SIMD optimizations and runtime CPU detection for Hexagon DSP targets: - CPU detection: Add kCpuHasHexagon and kCpuHasHVX flags, LIBYUV_DISABLE_HVX environment variable support, and Hexagon unit_test mmap/munmap shims. - Rotate/Transpose (rotate_hvx.cc): Implement TransposeWxH_HVX, TransposeUVWxH_HVX, TransposeWxH_16_HVX, and TransposeWxH_32_HVX using power-of-2 vdeal/vshuff butterfly networks. - Compare (compare_hvx.cc): Implement HammingDistance_HVX, SumSquareError_HVX, HashDjb2_HVX, and Ssim4x4Row_HVX. - Scale (scale_hvx.cc): Implement 16 scale row kernels including ScaleAddRow_HVX, ScaleRowDown2*_HVX (8-bit and 16-bit), ScaleRowDown4*_HVX, ScaleARGBRowDown2*_HVX, and ScaleUVRowDown2*_HVX. - Row functions (row_hvx.cc): Implement 58 row kernels covering copy/set/mirror, split/merge, 8/16-bit conversions, YUV-to-ARGB, ARGB-to-YUV, ARGB channel swizzles, blend, attenuate, and interpolate using hardware-predicated partial loads/stores. R=rrwinterton@gmail.com Bug: None Test: libyuv_unittest on Hexagon v81 simulator and Snapdragon 8 Elite Change-Id: Ib6713de51f6246d95e58c95e629ff03f18e3b91e Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/8604586 Reviewed-by: richard winterton <rrwinterton@gmail.com>
531 lines
19 KiB
C++
531 lines
19 KiB
C++
/*
|
|
* Copyright 2026 The LibYuv 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 "libyuv/scale_row.h"
|
|
|
|
#if !defined(LIBYUV_DISABLE_HVX) && defined(__HVX__)
|
|
#include <hexagon_protos.h>
|
|
#include <hexagon_types.h>
|
|
#include <hvx_hexagon_protos.h>
|
|
#include <string.h>
|
|
|
|
#ifdef __cplusplus
|
|
namespace libyuv {
|
|
extern "C" {
|
|
#endif
|
|
|
|
static __inline HVX_Vector vloada(const void* ptr) {
|
|
HVX_Vector v;
|
|
memcpy(&v, (const HVX_Vector*)ptr, sizeof(v));
|
|
return v;
|
|
}
|
|
|
|
static __inline HVX_UVector vloadu(const void* ptr) {
|
|
HVX_UVector v;
|
|
memcpy(&v, ptr, sizeof(v));
|
|
return v;
|
|
}
|
|
|
|
static __inline void vstoreu(void* ptr, HVX_UVector v) {
|
|
memcpy(ptr, &v, sizeof(v));
|
|
}
|
|
|
|
static __inline void vstoreu_partial(void* dst, HVX_Vector v, int n) {
|
|
if (n >= 128) {
|
|
vstoreu(dst, v);
|
|
} else if (n > 0) {
|
|
const uintptr_t addr = (uintptr_t)dst;
|
|
const uintptr_t offset = addr & 127;
|
|
HVX_Vector value = Q6_V_vlalign_VVR(v, v, addr);
|
|
HVX_VectorPred ql_not = Q6_Q_vsetq_R(addr);
|
|
HVX_VectorPred qr = Q6_Q_vsetq2_R(offset + (uintptr_t)n);
|
|
if (offset + (uintptr_t)n > 128) {
|
|
Q6_vmem_QRIV(qr, (uint8_t*)dst + 128, value);
|
|
qr = Q6_Q_vcmp_eq_VbVb(value, value);
|
|
}
|
|
ql_not = Q6_Q_or_QQn(ql_not, qr);
|
|
Q6_vmem_QnRIV(ql_not, dst, value);
|
|
}
|
|
}
|
|
|
|
static __inline HVX_Vector vloadu_partial_zero(const void* src, int n) {
|
|
if (n >= 128) {
|
|
return vloadu(src);
|
|
}
|
|
if (n <= 0) {
|
|
return Q6_V_vzero();
|
|
}
|
|
const uintptr_t addr = (uintptr_t)src;
|
|
const uintptr_t offset = addr & 127;
|
|
HVX_Vector v0 = vloada(src);
|
|
HVX_Vector v1 =
|
|
(offset + (uintptr_t)n > 128) ? vloada((const uint8_t*)src + 128) : v0;
|
|
HVX_Vector v = Q6_V_valign_VVR(v1, v0, addr);
|
|
return Q6_V_vmux_QVV(Q6_Q_vsetq_R(n), v, Q6_V_vzero());
|
|
}
|
|
|
|
void ScaleAddRow_HVX(const uint8_t* src_ptr, uint16_t* dst_ptr, int src_width) {
|
|
while (src_width > 0) {
|
|
int w = src_width >= 128 ? 128 : src_width;
|
|
HVX_Vector s = vloadu_partial_zero(src_ptr, w);
|
|
HVX_VectorPair s16 = Q6_Wuh_vunpack_Vub(s);
|
|
int b0 = w > 64 ? 128 : w * 2;
|
|
HVX_Vector d0 = vloadu_partial_zero(dst_ptr, b0);
|
|
d0 = Q6_Vh_vadd_VhVh(d0, Q6_V_lo_W(s16));
|
|
vstoreu_partial(dst_ptr, d0, b0);
|
|
if (w > 64) {
|
|
int b1 = (w - 64) * 2;
|
|
HVX_Vector d1 = vloadu_partial_zero(dst_ptr + 64, b1);
|
|
d1 = Q6_Vh_vadd_VhVh(d1, Q6_V_hi_W(s16));
|
|
vstoreu_partial(dst_ptr + 64, d1, b1);
|
|
}
|
|
src_ptr += 128;
|
|
dst_ptr += 128;
|
|
src_width -= 128;
|
|
}
|
|
}
|
|
|
|
void ScaleRowDown2_HVX(const uint8_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
uint8_t* dst,
|
|
int dst_width) {
|
|
(void)src_stride;
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 128 ? 128 : dst_width;
|
|
int src_bytes = w * 2;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_ptr, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_ptr + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair d = Q6_W_vdeal_VVR(s1, s0, -1);
|
|
vstoreu_partial(dst, Q6_V_hi_W(d), w);
|
|
src_ptr += 256;
|
|
dst += 128;
|
|
dst_width -= 128;
|
|
}
|
|
}
|
|
|
|
void ScaleRowDown2Linear_HVX(const uint8_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
uint8_t* dst,
|
|
int dst_width) {
|
|
(void)src_stride;
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 128 ? 128 : dst_width;
|
|
int src_bytes = w * 2;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_ptr, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_ptr + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair d = Q6_W_vdeal_VVR(s1, s0, -1);
|
|
HVX_Vector avg = Q6_Vub_vavg_VubVub_rnd(Q6_V_lo_W(d), Q6_V_hi_W(d));
|
|
vstoreu_partial(dst, avg, w);
|
|
src_ptr += 256;
|
|
dst += 128;
|
|
dst_width -= 128;
|
|
}
|
|
}
|
|
|
|
void ScaleRowDown2Box_HVX(const uint8_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
uint8_t* dst,
|
|
int dst_width) {
|
|
const uint8_t* s = src_ptr;
|
|
const uint8_t* t = src_ptr + src_stride;
|
|
const int32_t kOnes = 0x01010101;
|
|
HVX_Vector vtwo = Q6_Vh_vsplat_R(2);
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 128 ? 128 : dst_width;
|
|
int src_bytes = w * 2;
|
|
HVX_Vector s0 = vloadu_partial_zero(s, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector t0 = vloadu_partial_zero(t, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector sum0 = Q6_Vh_vdmpy_VubRb(s0, kOnes);
|
|
sum0 = Q6_Vh_vdmpyacc_VhVubRb(sum0, t0, kOnes);
|
|
sum0 = Q6_Vh_vasr_VhR(Q6_Vh_vadd_VhVh(sum0, vtwo), 2);
|
|
|
|
HVX_Vector sum1 = Q6_V_vzero();
|
|
if (src_bytes > 128) {
|
|
HVX_Vector s1 = vloadu_partial_zero(s + 128, src_bytes - 128);
|
|
HVX_Vector t1 = vloadu_partial_zero(t + 128, src_bytes - 128);
|
|
sum1 = Q6_Vh_vdmpy_VubRb(s1, kOnes);
|
|
sum1 = Q6_Vh_vdmpyacc_VhVubRb(sum1, t1, kOnes);
|
|
sum1 = Q6_Vh_vasr_VhR(Q6_Vh_vadd_VhVh(sum1, vtwo), 2);
|
|
}
|
|
HVX_Vector out = Q6_Vub_vpack_VhVh_sat(sum1, sum0);
|
|
vstoreu_partial(dst, out, w);
|
|
s += 256;
|
|
t += 256;
|
|
dst += 128;
|
|
dst_width -= 128;
|
|
}
|
|
}
|
|
|
|
void ScaleRowDown2Box_Odd_HVX(const uint8_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
uint8_t* dst,
|
|
int dst_width) {
|
|
dst_width -= 1;
|
|
if (dst_width > 0) {
|
|
ScaleRowDown2Box_HVX(src_ptr, src_stride, dst, dst_width);
|
|
}
|
|
const uint8_t* s = src_ptr + dst_width * 2;
|
|
const uint8_t* t = s + src_stride;
|
|
dst[dst_width] = (s[0] + t[0] + 1) >> 1;
|
|
}
|
|
|
|
void ScaleRowDown2_16_HVX(const uint16_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
uint16_t* dst,
|
|
int dst_width) {
|
|
(void)src_stride;
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 64 ? 64 : dst_width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_ptr, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_ptr + 64, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair d = Q6_W_vdeal_VVR(s1, s0, -2);
|
|
vstoreu_partial(dst, Q6_V_hi_W(d), w * 2);
|
|
src_ptr += 128;
|
|
dst += 64;
|
|
dst_width -= 64;
|
|
}
|
|
}
|
|
|
|
void ScaleRowDown2Linear_16_HVX(const uint16_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
uint16_t* dst,
|
|
int dst_width) {
|
|
(void)src_stride;
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 64 ? 64 : dst_width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_ptr, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_ptr + 64, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair d = Q6_W_vdeal_VVR(s1, s0, -2);
|
|
HVX_Vector avg = Q6_Vuh_vavg_VuhVuh_rnd(Q6_V_lo_W(d), Q6_V_hi_W(d));
|
|
vstoreu_partial(dst, avg, w * 2);
|
|
src_ptr += 128;
|
|
dst += 64;
|
|
dst_width -= 64;
|
|
}
|
|
}
|
|
|
|
void ScaleRowDown2Box_16_HVX(const uint16_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
uint16_t* dst,
|
|
int dst_width) {
|
|
const uint16_t* s = src_ptr;
|
|
const uint16_t* t = src_ptr + src_stride;
|
|
HVX_Vector vtwo = Q6_V_vsplat_R(2);
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 64 ? 64 : dst_width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector s0 = vloadu_partial_zero(s, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector t0 = vloadu_partial_zero(t, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(s + 64, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector t1 = src_bytes > 128
|
|
? vloadu_partial_zero(t + 64, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair ds = Q6_W_vdeal_VVR(s1, s0, -2);
|
|
HVX_VectorPair dt = Q6_W_vdeal_VVR(t1, t0, -2);
|
|
HVX_VectorPair s_even = Q6_Wuw_vunpack_Vuh(Q6_V_lo_W(ds));
|
|
HVX_VectorPair s_odd = Q6_Wuw_vunpack_Vuh(Q6_V_hi_W(ds));
|
|
HVX_VectorPair t_even = Q6_Wuw_vunpack_Vuh(Q6_V_lo_W(dt));
|
|
HVX_VectorPair t_odd = Q6_Wuw_vunpack_Vuh(Q6_V_hi_W(dt));
|
|
|
|
HVX_Vector sum_lo = Q6_Vw_vadd_VwVw(Q6_V_lo_W(s_even), Q6_V_lo_W(s_odd));
|
|
sum_lo = Q6_Vw_vadd_VwVw(sum_lo, Q6_V_lo_W(t_even));
|
|
sum_lo = Q6_Vw_vadd_VwVw(sum_lo, Q6_V_lo_W(t_odd));
|
|
sum_lo = Q6_Vw_vasr_VwR(Q6_Vw_vadd_VwVw(sum_lo, vtwo), 2);
|
|
|
|
HVX_Vector sum_hi = Q6_Vw_vadd_VwVw(Q6_V_hi_W(s_even), Q6_V_hi_W(s_odd));
|
|
sum_hi = Q6_Vw_vadd_VwVw(sum_hi, Q6_V_hi_W(t_even));
|
|
sum_hi = Q6_Vw_vadd_VwVw(sum_hi, Q6_V_hi_W(t_odd));
|
|
sum_hi = Q6_Vw_vasr_VwR(Q6_Vw_vadd_VwVw(sum_hi, vtwo), 2);
|
|
|
|
HVX_Vector out = Q6_Vuh_vpack_VwVw_sat(sum_hi, sum_lo);
|
|
vstoreu_partial(dst, out, w * 2);
|
|
s += 128;
|
|
t += 128;
|
|
dst += 64;
|
|
dst_width -= 64;
|
|
}
|
|
}
|
|
|
|
void ScaleRowDown4_HVX(const uint8_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
uint8_t* dst_ptr,
|
|
int dst_width) {
|
|
(void)src_stride;
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 128 ? 128 : dst_width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_ptr, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 =
|
|
src_bytes > 128
|
|
? vloadu_partial_zero(src_ptr + 128,
|
|
src_bytes > 256 ? 128 : src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector s2 =
|
|
src_bytes > 256
|
|
? vloadu_partial_zero(src_ptr + 256,
|
|
src_bytes > 384 ? 128 : src_bytes - 256)
|
|
: Q6_V_vzero();
|
|
HVX_Vector s3 = src_bytes > 384
|
|
? vloadu_partial_zero(src_ptr + 384, src_bytes - 384)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair d01 = Q6_W_vdeal_VVR(s1, s0, -1);
|
|
HVX_VectorPair d23 = Q6_W_vdeal_VVR(s3, s2, -1);
|
|
HVX_VectorPair d_even = Q6_W_vdeal_VVR(Q6_V_lo_W(d23), Q6_V_lo_W(d01), -1);
|
|
vstoreu_partial(dst_ptr, Q6_V_hi_W(d_even), w);
|
|
src_ptr += 512;
|
|
dst_ptr += 128;
|
|
dst_width -= 128;
|
|
}
|
|
}
|
|
|
|
void ScaleRowDown4Box_HVX(const uint8_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
uint8_t* dst_ptr,
|
|
int dst_width) {
|
|
const uint8_t* r0 = src_ptr;
|
|
const uint8_t* r1 = r0 + src_stride;
|
|
const uint8_t* r2 = r1 + src_stride;
|
|
const uint8_t* r3 = r2 + src_stride;
|
|
const int32_t kOnes = 0x01010101;
|
|
HVX_Vector veight = Q6_Vh_vsplat_R(8);
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 128 ? 128 : dst_width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector sum[4];
|
|
for (int c = 0; c < 4; ++c) {
|
|
int rem = src_bytes - c * 128;
|
|
if (rem > 0) {
|
|
int b = rem > 128 ? 128 : rem;
|
|
HVX_Vector v0 = vloadu_partial_zero(r0 + c * 128, b);
|
|
HVX_Vector v1 = vloadu_partial_zero(r1 + c * 128, b);
|
|
HVX_Vector v2 = vloadu_partial_zero(r2 + c * 128, b);
|
|
HVX_Vector v3 = vloadu_partial_zero(r3 + c * 128, b);
|
|
HVX_Vector s = Q6_Vw_vrmpy_VubRb(v0, kOnes);
|
|
s = Q6_Vw_vrmpyacc_VwVubRb(s, v1, kOnes);
|
|
s = Q6_Vw_vrmpyacc_VwVubRb(s, v2, kOnes);
|
|
s = Q6_Vw_vrmpyacc_VwVubRb(s, v3, kOnes);
|
|
sum[c] = s;
|
|
} else {
|
|
sum[c] = Q6_V_vzero();
|
|
}
|
|
}
|
|
HVX_Vector s01 = Q6_Vh_vpack_VwVw_sat(sum[1], sum[0]);
|
|
HVX_Vector s23 = Q6_Vh_vpack_VwVw_sat(sum[3], sum[2]);
|
|
s01 = Q6_Vh_vasr_VhR(Q6_Vh_vadd_VhVh(s01, veight), 4);
|
|
s23 = Q6_Vh_vasr_VhR(Q6_Vh_vadd_VhVh(s23, veight), 4);
|
|
HVX_Vector out = Q6_Vub_vpack_VhVh_sat(s23, s01);
|
|
vstoreu_partial(dst_ptr, out, w);
|
|
r0 += 512;
|
|
r1 += 512;
|
|
r2 += 512;
|
|
r3 += 512;
|
|
dst_ptr += 128;
|
|
dst_width -= 128;
|
|
}
|
|
}
|
|
|
|
void ScaleARGBRowDown2_HVX(const uint8_t* src_argb,
|
|
ptrdiff_t src_stride,
|
|
uint8_t* dst_argb,
|
|
int dst_width) {
|
|
(void)src_stride;
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 32 ? 32 : dst_width;
|
|
int src_bytes = w * 8;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_argb, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_argb + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair d = Q6_W_vdeal_VVR(s1, s0, -4);
|
|
vstoreu_partial(dst_argb, Q6_V_hi_W(d), w * 4);
|
|
src_argb += 256;
|
|
dst_argb += 128;
|
|
dst_width -= 32;
|
|
}
|
|
}
|
|
|
|
void ScaleARGBRowDown2Linear_HVX(const uint8_t* src_argb,
|
|
ptrdiff_t src_stride,
|
|
uint8_t* dst_argb,
|
|
int dst_width) {
|
|
(void)src_stride;
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 32 ? 32 : dst_width;
|
|
int src_bytes = w * 8;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_argb, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_argb + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair d = Q6_W_vdeal_VVR(s1, s0, -4);
|
|
HVX_Vector avg = Q6_Vub_vavg_VubVub_rnd(Q6_V_lo_W(d), Q6_V_hi_W(d));
|
|
vstoreu_partial(dst_argb, avg, w * 4);
|
|
src_argb += 256;
|
|
dst_argb += 128;
|
|
dst_width -= 32;
|
|
}
|
|
}
|
|
|
|
void ScaleARGBRowDown2Box_HVX(const uint8_t* src_argb,
|
|
ptrdiff_t src_stride,
|
|
uint8_t* dst_argb,
|
|
int dst_width) {
|
|
const uint8_t* s = src_argb;
|
|
const uint8_t* t = src_argb + src_stride;
|
|
HVX_Vector vtwo = Q6_Vh_vsplat_R(2);
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 32 ? 32 : dst_width;
|
|
int src_bytes = w * 8;
|
|
HVX_Vector s0 = vloadu_partial_zero(s, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector t0 = vloadu_partial_zero(t, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(s + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector t1 = src_bytes > 128
|
|
? vloadu_partial_zero(t + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair ds = Q6_W_vdeal_VVR(s1, s0, -4);
|
|
HVX_VectorPair dt = Q6_W_vdeal_VVR(t1, t0, -4);
|
|
HVX_VectorPair s_even = Q6_Wuh_vunpack_Vub(Q6_V_lo_W(ds));
|
|
HVX_VectorPair s_odd = Q6_Wuh_vunpack_Vub(Q6_V_hi_W(ds));
|
|
HVX_VectorPair t_even = Q6_Wuh_vunpack_Vub(Q6_V_lo_W(dt));
|
|
HVX_VectorPair t_odd = Q6_Wuh_vunpack_Vub(Q6_V_hi_W(dt));
|
|
|
|
HVX_Vector sum_lo = Q6_Vh_vadd_VhVh(Q6_V_lo_W(s_even), Q6_V_lo_W(s_odd));
|
|
sum_lo = Q6_Vh_vadd_VhVh(sum_lo, Q6_V_lo_W(t_even));
|
|
sum_lo = Q6_Vh_vadd_VhVh(sum_lo, Q6_V_lo_W(t_odd));
|
|
sum_lo = Q6_Vh_vasr_VhR(Q6_Vh_vadd_VhVh(sum_lo, vtwo), 2);
|
|
|
|
HVX_Vector sum_hi = Q6_Vh_vadd_VhVh(Q6_V_hi_W(s_even), Q6_V_hi_W(s_odd));
|
|
sum_hi = Q6_Vh_vadd_VhVh(sum_hi, Q6_V_hi_W(t_even));
|
|
sum_hi = Q6_Vh_vadd_VhVh(sum_hi, Q6_V_hi_W(t_odd));
|
|
sum_hi = Q6_Vh_vasr_VhR(Q6_Vh_vadd_VhVh(sum_hi, vtwo), 2);
|
|
|
|
HVX_Vector out = Q6_Vub_vpack_VhVh_sat(sum_hi, sum_lo);
|
|
vstoreu_partial(dst_argb, out, w * 4);
|
|
s += 256;
|
|
t += 256;
|
|
dst_argb += 128;
|
|
dst_width -= 32;
|
|
}
|
|
}
|
|
|
|
void ScaleUVRowDown2_HVX(const uint8_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
uint8_t* dst_uv,
|
|
int dst_width) {
|
|
(void)src_stride;
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 64 ? 64 : dst_width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_ptr, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_ptr + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair d = Q6_W_vdeal_VVR(s1, s0, -2);
|
|
vstoreu_partial(dst_uv, Q6_V_hi_W(d), w * 2);
|
|
src_ptr += 256;
|
|
dst_uv += 128;
|
|
dst_width -= 64;
|
|
}
|
|
}
|
|
|
|
void ScaleUVRowDown2Linear_HVX(const uint8_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
uint8_t* dst_uv,
|
|
int dst_width) {
|
|
(void)src_stride;
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 64 ? 64 : dst_width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_ptr, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_ptr + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair d = Q6_W_vdeal_VVR(s1, s0, -2);
|
|
HVX_Vector avg = Q6_Vub_vavg_VubVub_rnd(Q6_V_lo_W(d), Q6_V_hi_W(d));
|
|
vstoreu_partial(dst_uv, avg, w * 2);
|
|
src_ptr += 256;
|
|
dst_uv += 128;
|
|
dst_width -= 64;
|
|
}
|
|
}
|
|
|
|
void ScaleUVRowDown2Box_HVX(const uint8_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
uint8_t* dst_uv,
|
|
int dst_width) {
|
|
const uint8_t* s = src_ptr;
|
|
const uint8_t* t = src_ptr + src_stride;
|
|
HVX_Vector vtwo = Q6_Vh_vsplat_R(2);
|
|
while (dst_width > 0) {
|
|
int w = dst_width >= 64 ? 64 : dst_width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector s0 = vloadu_partial_zero(s, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector t0 = vloadu_partial_zero(t, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(s + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector t1 = src_bytes > 128
|
|
? vloadu_partial_zero(t + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair ds = Q6_W_vdeal_VVR(s1, s0, -2);
|
|
HVX_VectorPair dt = Q6_W_vdeal_VVR(t1, t0, -2);
|
|
HVX_VectorPair s_even = Q6_Wuh_vunpack_Vub(Q6_V_lo_W(ds));
|
|
HVX_VectorPair s_odd = Q6_Wuh_vunpack_Vub(Q6_V_hi_W(ds));
|
|
HVX_VectorPair t_even = Q6_Wuh_vunpack_Vub(Q6_V_lo_W(dt));
|
|
HVX_VectorPair t_odd = Q6_Wuh_vunpack_Vub(Q6_V_hi_W(dt));
|
|
|
|
HVX_Vector sum_lo = Q6_Vh_vadd_VhVh(Q6_V_lo_W(s_even), Q6_V_lo_W(s_odd));
|
|
sum_lo = Q6_Vh_vadd_VhVh(sum_lo, Q6_V_lo_W(t_even));
|
|
sum_lo = Q6_Vh_vadd_VhVh(sum_lo, Q6_V_lo_W(t_odd));
|
|
sum_lo = Q6_Vh_vasr_VhR(Q6_Vh_vadd_VhVh(sum_lo, vtwo), 2);
|
|
|
|
HVX_Vector sum_hi = Q6_Vh_vadd_VhVh(Q6_V_hi_W(s_even), Q6_V_hi_W(s_odd));
|
|
sum_hi = Q6_Vh_vadd_VhVh(sum_hi, Q6_V_hi_W(t_even));
|
|
sum_hi = Q6_Vh_vadd_VhVh(sum_hi, Q6_V_hi_W(t_odd));
|
|
sum_hi = Q6_Vh_vasr_VhR(Q6_Vh_vadd_VhVh(sum_hi, vtwo), 2);
|
|
|
|
HVX_Vector out = Q6_Vub_vpack_VhVh_sat(sum_hi, sum_lo);
|
|
vstoreu_partial(dst_uv, out, w * 2);
|
|
s += 256;
|
|
t += 256;
|
|
dst_uv += 128;
|
|
dst_width -= 64;
|
|
}
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
} // extern "C"
|
|
} // namespace libyuv
|
|
#endif
|
|
|
|
#endif // !defined(LIBYUV_DISABLE_HVX) && defined(__HVX__)
|