mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2026-10-29 02:17:13 +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>
1772 lines
61 KiB
C++
1772 lines
61 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/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 CopyRow_HVX(const uint8_t* src, uint8_t* dst, int count) {
|
|
while (count >= 128) {
|
|
vstoreu(dst, vloadu(src));
|
|
src += 128;
|
|
dst += 128;
|
|
count -= 128;
|
|
}
|
|
if (count > 0) {
|
|
vstoreu_partial(dst, vloadu_partial_zero(src, count), count);
|
|
}
|
|
}
|
|
|
|
void CopyRow_16_HVX(const uint16_t* src, uint16_t* dst, int count) {
|
|
CopyRow_HVX((const uint8_t*)src, (uint8_t*)dst, count * 2);
|
|
}
|
|
|
|
void SetRow_HVX(uint8_t* dst, uint8_t v8, int width) {
|
|
HVX_Vector v = Q6_Vb_vsplat_R(v8);
|
|
while (width >= 128) {
|
|
vstoreu(dst, v);
|
|
dst += 128;
|
|
width -= 128;
|
|
}
|
|
if (width > 0) {
|
|
vstoreu_partial(dst, v, width);
|
|
}
|
|
}
|
|
|
|
void ARGBSetRow_HVX(uint8_t* dst_argb, uint32_t v32, int width) {
|
|
HVX_Vector v = Q6_V_vsplat_R(v32);
|
|
int bytes = width * 4;
|
|
while (bytes >= 128) {
|
|
vstoreu(dst_argb, v);
|
|
dst_argb += 128;
|
|
bytes -= 128;
|
|
}
|
|
if (bytes > 0) {
|
|
vstoreu_partial(dst_argb, v, bytes);
|
|
}
|
|
}
|
|
|
|
void MirrorRow_HVX(const uint8_t* src, uint8_t* dst, int width) {
|
|
HVX_Vector ctrl = Q6_Vb_vsplat_R(0x7F);
|
|
src += width;
|
|
while (width >= 128) {
|
|
src -= 128;
|
|
HVX_Vector v = vloadu(src);
|
|
v = Q6_V_vdelta_VV(v, ctrl);
|
|
vstoreu(dst, v);
|
|
dst += 128;
|
|
width -= 128;
|
|
}
|
|
if (width > 0) {
|
|
src -= width;
|
|
HVX_Vector v = vloadu_partial_zero(src, width);
|
|
v = Q6_V_vdelta_VV(v, ctrl);
|
|
v = Q6_V_valign_VVR(v, v, 128 - width);
|
|
vstoreu_partial(dst, v, width);
|
|
}
|
|
}
|
|
|
|
void MirrorRow_16_HVX(const uint16_t* src, uint16_t* dst, int width) {
|
|
HVX_Vector ctrl = Q6_Vb_vsplat_R(0x7E);
|
|
const uint8_t* s = (const uint8_t*)(src + width);
|
|
uint8_t* d = (uint8_t*)dst;
|
|
int bytes = width * 2;
|
|
while (bytes >= 128) {
|
|
s -= 128;
|
|
HVX_Vector v = vloadu(s);
|
|
v = Q6_V_vdelta_VV(v, ctrl);
|
|
vstoreu(d, v);
|
|
d += 128;
|
|
bytes -= 128;
|
|
}
|
|
if (bytes > 0) {
|
|
s -= bytes;
|
|
HVX_Vector v = vloadu_partial_zero(s, bytes);
|
|
v = Q6_V_vdelta_VV(v, ctrl);
|
|
v = Q6_V_valign_VVR(v, v, 128 - bytes);
|
|
vstoreu_partial(d, v, bytes);
|
|
}
|
|
}
|
|
|
|
void MirrorUVRow_HVX(const uint8_t* src_uv, uint8_t* dst_uv, int width) {
|
|
MirrorRow_16_HVX((const uint16_t*)src_uv, (uint16_t*)dst_uv, width);
|
|
}
|
|
|
|
void MirrorSplitUVRow_HVX(const uint8_t* src_uv,
|
|
uint8_t* dst_u,
|
|
uint8_t* dst_v,
|
|
int width) {
|
|
HVX_Vector ctrl = Q6_Vb_vsplat_R(0x7F);
|
|
src_uv += width * 2;
|
|
while (width >= 128) {
|
|
src_uv -= 256;
|
|
HVX_Vector s0 = vloadu(src_uv);
|
|
HVX_Vector s1 = vloadu(src_uv + 128);
|
|
HVX_VectorPair uv = Q6_W_vdeal_VVR(s1, s0, -1);
|
|
HVX_Vector u = Q6_V_vdelta_VV(Q6_V_lo_W(uv), ctrl);
|
|
HVX_Vector v = Q6_V_vdelta_VV(Q6_V_hi_W(uv), ctrl);
|
|
vstoreu(dst_u, u);
|
|
vstoreu(dst_v, v);
|
|
dst_u += 128;
|
|
dst_v += 128;
|
|
width -= 128;
|
|
}
|
|
if (width > 0) {
|
|
int src_bytes = width * 2;
|
|
src_uv -= src_bytes;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_uv, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_uv + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair uv = Q6_W_vdeal_VVR(s1, s0, -1);
|
|
HVX_Vector u = Q6_V_vdelta_VV(Q6_V_lo_W(uv), ctrl);
|
|
HVX_Vector v = Q6_V_vdelta_VV(Q6_V_hi_W(uv), ctrl);
|
|
u = Q6_V_valign_VVR(u, u, 128 - width);
|
|
v = Q6_V_valign_VVR(v, v, 128 - width);
|
|
vstoreu_partial(dst_u, u, width);
|
|
vstoreu_partial(dst_v, v, width);
|
|
}
|
|
}
|
|
|
|
void ARGBMirrorRow_HVX(const uint8_t* src, uint8_t* dst, int width) {
|
|
HVX_Vector ctrl = Q6_Vb_vsplat_R(0x7C);
|
|
int bytes = width * 4;
|
|
src += bytes;
|
|
while (bytes >= 128) {
|
|
src -= 128;
|
|
HVX_Vector v = vloadu(src);
|
|
v = Q6_V_vdelta_VV(v, ctrl);
|
|
vstoreu(dst, v);
|
|
dst += 128;
|
|
bytes -= 128;
|
|
}
|
|
if (bytes > 0) {
|
|
src -= bytes;
|
|
HVX_Vector v = vloadu_partial_zero(src, bytes);
|
|
v = Q6_V_vdelta_VV(v, ctrl);
|
|
v = Q6_V_valign_VVR(v, v, 128 - bytes);
|
|
vstoreu_partial(dst, v, bytes);
|
|
}
|
|
}
|
|
|
|
void SplitUVRow_HVX(const uint8_t* src_uv,
|
|
uint8_t* dst_u,
|
|
uint8_t* dst_v,
|
|
int width) {
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int src_bytes = w * 2;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_uv, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_uv + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair uv = Q6_W_vdeal_VVR(s1, s0, -1);
|
|
vstoreu_partial(dst_u, Q6_V_lo_W(uv), w);
|
|
vstoreu_partial(dst_v, Q6_V_hi_W(uv), w);
|
|
src_uv += 256;
|
|
dst_u += 128;
|
|
dst_v += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void MergeUVRow_HVX(const uint8_t* src_u,
|
|
const uint8_t* src_v,
|
|
uint8_t* dst_uv,
|
|
int width) {
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
HVX_Vector u = vloadu_partial_zero(src_u, w);
|
|
HVX_Vector v = vloadu_partial_zero(src_v, w);
|
|
HVX_VectorPair uv = Q6_W_vshuff_VVR(v, u, -1);
|
|
int dst_bytes = w * 2;
|
|
vstoreu_partial(dst_uv, Q6_V_lo_W(uv), dst_bytes > 128 ? 128 : dst_bytes);
|
|
if (dst_bytes > 128) {
|
|
vstoreu_partial(dst_uv + 128, Q6_V_hi_W(uv), dst_bytes - 128);
|
|
}
|
|
src_u += 128;
|
|
src_v += 128;
|
|
dst_uv += 256;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void SplitUVRow_16_HVX(const uint16_t* src_uv,
|
|
uint16_t* dst_u,
|
|
uint16_t* dst_v,
|
|
int depth,
|
|
int width) {
|
|
int shift = 16 - depth;
|
|
while (width > 0) {
|
|
int w = width >= 64 ? 64 : width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_uv, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 =
|
|
src_bytes > 128
|
|
? vloadu_partial_zero((const uint8_t*)src_uv + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair uv = Q6_W_vdeal_VVR(s1, s0, -2);
|
|
HVX_Vector u = Q6_Vuh_vlsr_VuhR(Q6_V_lo_W(uv), shift);
|
|
HVX_Vector v = Q6_Vuh_vlsr_VuhR(Q6_V_hi_W(uv), shift);
|
|
vstoreu_partial(dst_u, u, w * 2);
|
|
vstoreu_partial(dst_v, v, w * 2);
|
|
src_uv += 128;
|
|
dst_u += 64;
|
|
dst_v += 64;
|
|
width -= 64;
|
|
}
|
|
}
|
|
|
|
void MergeUVRow_16_HVX(const uint16_t* src_u,
|
|
const uint16_t* src_v,
|
|
uint16_t* dst_uv,
|
|
int depth,
|
|
int width) {
|
|
int shift = 16 - depth;
|
|
while (width > 0) {
|
|
int w = width >= 64 ? 64 : width;
|
|
HVX_Vector u = vloadu_partial_zero(src_u, w * 2);
|
|
HVX_Vector v = vloadu_partial_zero(src_v, w * 2);
|
|
u = Q6_Vh_vasl_VhR(u, shift);
|
|
v = Q6_Vh_vasl_VhR(v, shift);
|
|
HVX_VectorPair uv = Q6_W_vshuff_VVR(v, u, -2);
|
|
int dst_bytes = w * 4;
|
|
vstoreu_partial(dst_uv, Q6_V_lo_W(uv), dst_bytes > 128 ? 128 : dst_bytes);
|
|
if (dst_bytes > 128) {
|
|
vstoreu_partial((uint8_t*)dst_uv + 128, Q6_V_hi_W(uv), dst_bytes - 128);
|
|
}
|
|
src_u += 64;
|
|
src_v += 64;
|
|
dst_uv += 128;
|
|
width -= 64;
|
|
}
|
|
}
|
|
|
|
void SplitARGBRow_HVX(const uint8_t* src_argb,
|
|
uint8_t* dst_r,
|
|
uint8_t* dst_g,
|
|
uint8_t* dst_b,
|
|
uint8_t* dst_a,
|
|
int width) {
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int src_bytes = w * 4;
|
|
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 > 256 ? 128 : src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector s2 =
|
|
src_bytes > 256
|
|
? vloadu_partial_zero(src_argb + 256,
|
|
src_bytes > 384 ? 128 : src_bytes - 256)
|
|
: Q6_V_vzero();
|
|
HVX_Vector s3 = src_bytes > 384
|
|
? vloadu_partial_zero(src_argb + 384, src_bytes - 384)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair p01 = Q6_W_vdeal_VVR(s1, s0, -1);
|
|
HVX_VectorPair p23 = Q6_W_vdeal_VVR(s3, s2, -1);
|
|
HVX_VectorPair br = Q6_W_vdeal_VVR(Q6_V_lo_W(p23), Q6_V_lo_W(p01), -1);
|
|
HVX_VectorPair ga = Q6_W_vdeal_VVR(Q6_V_hi_W(p23), Q6_V_hi_W(p01), -1);
|
|
vstoreu_partial(dst_b, Q6_V_lo_W(br), w);
|
|
vstoreu_partial(dst_g, Q6_V_lo_W(ga), w);
|
|
vstoreu_partial(dst_r, Q6_V_hi_W(br), w);
|
|
vstoreu_partial(dst_a, Q6_V_hi_W(ga), w);
|
|
src_argb += 512;
|
|
dst_b += 128;
|
|
dst_g += 128;
|
|
dst_r += 128;
|
|
dst_a += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void MergeARGBRow_HVX(const uint8_t* src_r,
|
|
const uint8_t* src_g,
|
|
const uint8_t* src_b,
|
|
const uint8_t* src_a,
|
|
uint8_t* dst_argb,
|
|
int width) {
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
HVX_Vector b = vloadu_partial_zero(src_b, w);
|
|
HVX_Vector g = vloadu_partial_zero(src_g, w);
|
|
HVX_Vector r = vloadu_partial_zero(src_r, w);
|
|
HVX_Vector a = vloadu_partial_zero(src_a, w);
|
|
HVX_VectorPair br = Q6_W_vshuff_VVR(r, b, -1);
|
|
HVX_VectorPair ga = Q6_W_vshuff_VVR(a, g, -1);
|
|
HVX_VectorPair p01 = Q6_W_vshuff_VVR(Q6_V_lo_W(ga), Q6_V_lo_W(br), -1);
|
|
HVX_VectorPair p23 = Q6_W_vshuff_VVR(Q6_V_hi_W(ga), Q6_V_hi_W(br), -1);
|
|
int dst_bytes = w * 4;
|
|
vstoreu_partial(dst_argb, Q6_V_lo_W(p01),
|
|
dst_bytes > 128 ? 128 : dst_bytes);
|
|
if (dst_bytes > 128) {
|
|
vstoreu_partial(dst_argb + 128, Q6_V_hi_W(p01),
|
|
dst_bytes > 256 ? 128 : dst_bytes - 128);
|
|
}
|
|
if (dst_bytes > 256) {
|
|
vstoreu_partial(dst_argb + 256, Q6_V_lo_W(p23),
|
|
dst_bytes > 384 ? 128 : dst_bytes - 256);
|
|
}
|
|
if (dst_bytes > 384) {
|
|
vstoreu_partial(dst_argb + 384, Q6_V_hi_W(p23), dst_bytes - 384);
|
|
}
|
|
src_b += 128;
|
|
src_g += 128;
|
|
src_r += 128;
|
|
src_a += 128;
|
|
dst_argb += 512;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void SplitXRGBRow_HVX(const uint8_t* src_argb,
|
|
uint8_t* dst_r,
|
|
uint8_t* dst_g,
|
|
uint8_t* dst_b,
|
|
int width) {
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int src_bytes = w * 4;
|
|
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 > 256 ? 128 : src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector s2 =
|
|
src_bytes > 256
|
|
? vloadu_partial_zero(src_argb + 256,
|
|
src_bytes > 384 ? 128 : src_bytes - 256)
|
|
: Q6_V_vzero();
|
|
HVX_Vector s3 = src_bytes > 384
|
|
? vloadu_partial_zero(src_argb + 384, src_bytes - 384)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair p01 = Q6_W_vdeal_VVR(s1, s0, -1);
|
|
HVX_VectorPair p23 = Q6_W_vdeal_VVR(s3, s2, -1);
|
|
HVX_VectorPair br = Q6_W_vdeal_VVR(Q6_V_lo_W(p23), Q6_V_lo_W(p01), -1);
|
|
HVX_VectorPair ga = Q6_W_vdeal_VVR(Q6_V_hi_W(p23), Q6_V_hi_W(p01), -1);
|
|
vstoreu_partial(dst_b, Q6_V_lo_W(br), w);
|
|
vstoreu_partial(dst_g, Q6_V_lo_W(ga), w);
|
|
vstoreu_partial(dst_r, Q6_V_hi_W(br), w);
|
|
src_argb += 512;
|
|
dst_b += 128;
|
|
dst_g += 128;
|
|
dst_r += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void MergeXRGBRow_HVX(const uint8_t* src_r,
|
|
const uint8_t* src_g,
|
|
const uint8_t* src_b,
|
|
uint8_t* dst_argb,
|
|
int width) {
|
|
HVX_Vector a = Q6_Vb_vsplat_R(0xff);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
HVX_Vector b = vloadu_partial_zero(src_b, w);
|
|
HVX_Vector g = vloadu_partial_zero(src_g, w);
|
|
HVX_Vector r = vloadu_partial_zero(src_r, w);
|
|
HVX_VectorPair br = Q6_W_vshuff_VVR(r, b, -1);
|
|
HVX_VectorPair ga = Q6_W_vshuff_VVR(a, g, -1);
|
|
HVX_VectorPair p01 = Q6_W_vshuff_VVR(Q6_V_lo_W(ga), Q6_V_lo_W(br), -1);
|
|
HVX_VectorPair p23 = Q6_W_vshuff_VVR(Q6_V_hi_W(ga), Q6_V_hi_W(br), -1);
|
|
int dst_bytes = w * 4;
|
|
vstoreu_partial(dst_argb, Q6_V_lo_W(p01),
|
|
dst_bytes > 128 ? 128 : dst_bytes);
|
|
if (dst_bytes > 128) {
|
|
vstoreu_partial(dst_argb + 128, Q6_V_hi_W(p01),
|
|
dst_bytes > 256 ? 128 : dst_bytes - 128);
|
|
}
|
|
if (dst_bytes > 256) {
|
|
vstoreu_partial(dst_argb + 256, Q6_V_lo_W(p23),
|
|
dst_bytes > 384 ? 128 : dst_bytes - 256);
|
|
}
|
|
if (dst_bytes > 384) {
|
|
vstoreu_partial(dst_argb + 384, Q6_V_hi_W(p23), dst_bytes - 384);
|
|
}
|
|
src_b += 128;
|
|
src_g += 128;
|
|
src_r += 128;
|
|
dst_argb += 512;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void SwapUVRow_HVX(const uint8_t* src_uv, uint8_t* dst_vu, int width) {
|
|
HVX_Vector ctrl = Q6_Vb_vsplat_R(0x01);
|
|
int bytes = width * 2;
|
|
while (bytes >= 128) {
|
|
HVX_Vector v = vloadu(src_uv);
|
|
vstoreu(dst_vu, Q6_V_vdelta_VV(v, ctrl));
|
|
src_uv += 128;
|
|
dst_vu += 128;
|
|
bytes -= 128;
|
|
}
|
|
if (bytes > 0) {
|
|
HVX_Vector v = vloadu_partial_zero(src_uv, bytes);
|
|
vstoreu_partial(dst_vu, Q6_V_vdelta_VV(v, ctrl), bytes);
|
|
}
|
|
}
|
|
|
|
void InterpolateRow_HVX(uint8_t* dst_ptr,
|
|
const uint8_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
int width,
|
|
int source_y_fraction) {
|
|
int y1_fraction = source_y_fraction;
|
|
int y0_fraction = 256 - y1_fraction;
|
|
const uint8_t* src_ptr1 = src_ptr + src_stride;
|
|
if (y1_fraction == 0) {
|
|
CopyRow_HVX(src_ptr, dst_ptr, width);
|
|
return;
|
|
}
|
|
if (y1_fraction == 128) {
|
|
while (width >= 128) {
|
|
HVX_Vector s0 = vloadu(src_ptr);
|
|
HVX_Vector s1 = vloadu(src_ptr1);
|
|
vstoreu(dst_ptr, Q6_Vub_vavg_VubVub_rnd(s0, s1));
|
|
src_ptr += 128;
|
|
src_ptr1 += 128;
|
|
dst_ptr += 128;
|
|
width -= 128;
|
|
}
|
|
if (width > 0) {
|
|
HVX_Vector s0 = vloadu_partial_zero(src_ptr, width);
|
|
HVX_Vector s1 = vloadu_partial_zero(src_ptr1, width);
|
|
vstoreu_partial(dst_ptr, Q6_Vub_vavg_VubVub_rnd(s0, s1), width);
|
|
}
|
|
return;
|
|
}
|
|
uint32_t y0_32 = (uint32_t)y0_fraction * 0x01010101u;
|
|
uint32_t y1_32 = (uint32_t)y1_fraction * 0x01010101u;
|
|
HVX_Vector v128 = Q6_Vh_vsplat_R(128);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
HVX_Vector s0 = vloadu_partial_zero(src_ptr, w);
|
|
HVX_Vector s1 = vloadu_partial_zero(src_ptr1, w);
|
|
HVX_VectorPair p = Q6_Wuh_vmpy_VubRub(s0, y0_32);
|
|
p = Q6_Wuh_vmpyacc_WuhVubRub(p, s1, y1_32);
|
|
HVX_Vector lo = Q6_Vuh_vadd_VuhVuh_sat(Q6_V_lo_W(p), v128);
|
|
HVX_Vector hi = Q6_Vuh_vadd_VuhVuh_sat(Q6_V_hi_W(p), v128);
|
|
HVX_Vector out = Q6_Vb_vshuffo_VbVb(hi, lo);
|
|
vstoreu_partial(dst_ptr, out, w);
|
|
src_ptr += 128;
|
|
src_ptr1 += 128;
|
|
dst_ptr += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void InterpolateRow_16_HVX(uint16_t* dst_ptr,
|
|
const uint16_t* src_ptr,
|
|
ptrdiff_t src_stride,
|
|
int width,
|
|
int source_y_fraction) {
|
|
int y1_fraction = source_y_fraction;
|
|
int y0_fraction = 256 - y1_fraction;
|
|
const uint16_t* src_ptr1 = src_ptr + src_stride;
|
|
if (y1_fraction == 0) {
|
|
CopyRow_16_HVX(src_ptr, dst_ptr, width);
|
|
return;
|
|
}
|
|
if (y1_fraction == 128) {
|
|
int bytes = width * 2;
|
|
const uint8_t* s0_p = (const uint8_t*)src_ptr;
|
|
const uint8_t* s1_p = (const uint8_t*)src_ptr1;
|
|
uint8_t* d_p = (uint8_t*)dst_ptr;
|
|
while (bytes >= 128) {
|
|
HVX_Vector s0 = vloadu(s0_p);
|
|
HVX_Vector s1 = vloadu(s1_p);
|
|
vstoreu(d_p, Q6_Vuh_vavg_VuhVuh_rnd(s0, s1));
|
|
s0_p += 128;
|
|
s1_p += 128;
|
|
d_p += 128;
|
|
bytes -= 128;
|
|
}
|
|
if (bytes > 0) {
|
|
HVX_Vector s0 = vloadu_partial_zero(s0_p, bytes);
|
|
HVX_Vector s1 = vloadu_partial_zero(s1_p, bytes);
|
|
vstoreu_partial(d_p, Q6_Vuh_vavg_VuhVuh_rnd(s0, s1), bytes);
|
|
}
|
|
return;
|
|
}
|
|
uint32_t y0_32 = ((uint32_t)y0_fraction << 16) | (uint32_t)y0_fraction;
|
|
uint32_t y1_32 = ((uint32_t)y1_fraction << 16) | (uint32_t)y1_fraction;
|
|
HVX_Vector v128 = Q6_V_vsplat_R(128);
|
|
while (width > 0) {
|
|
int w = width >= 64 ? 64 : width;
|
|
int bytes = w * 2;
|
|
HVX_Vector s0 = vloadu_partial_zero(src_ptr, bytes);
|
|
HVX_Vector s1 = vloadu_partial_zero(src_ptr1, bytes);
|
|
HVX_VectorPair p = Q6_Wuw_vmpy_VuhRuh(s0, y0_32);
|
|
p = Q6_Wuw_vmpyacc_WuwVuhRuh(p, s1, y1_32);
|
|
HVX_Vector lo = Q6_Vuw_vlsr_VuwR(Q6_Vw_vadd_VwVw(Q6_V_lo_W(p), v128), 8);
|
|
HVX_Vector hi = Q6_Vuw_vlsr_VuwR(Q6_Vw_vadd_VwVw(Q6_V_hi_W(p), v128), 8);
|
|
HVX_Vector out = Q6_Vh_vshuffe_VhVh(hi, lo);
|
|
vstoreu_partial(dst_ptr, out, bytes);
|
|
src_ptr += 64;
|
|
src_ptr1 += 64;
|
|
dst_ptr += 64;
|
|
width -= 64;
|
|
}
|
|
}
|
|
|
|
void BlendPlaneRow_HVX(const uint8_t* src0,
|
|
const uint8_t* src1,
|
|
const uint8_t* alpha,
|
|
uint8_t* dst,
|
|
int width) {
|
|
HVX_Vector v255 = Q6_Vh_vsplat_R(255);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
HVX_Vector f = vloadu_partial_zero(src0, w);
|
|
HVX_Vector b = vloadu_partial_zero(src1, w);
|
|
HVX_Vector a = vloadu_partial_zero(alpha, w);
|
|
HVX_Vector not_a = Q6_V_vnot_V(a);
|
|
HVX_VectorPair p = Q6_Wuh_vmpy_VubVub(f, a);
|
|
p = Q6_Wuh_vmpyacc_WuhVubVub(p, b, not_a);
|
|
HVX_Vector lo = Q6_Vuh_vadd_VuhVuh_sat(Q6_V_lo_W(p), v255);
|
|
HVX_Vector hi = Q6_Vuh_vadd_VuhVuh_sat(Q6_V_hi_W(p), v255);
|
|
HVX_Vector out = Q6_Vb_vshuffo_VbVb(hi, lo);
|
|
vstoreu_partial(dst, out, w);
|
|
src0 += 128;
|
|
src1 += 128;
|
|
alpha += 128;
|
|
dst += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBBlendRow_HVX(const uint8_t* src_argb,
|
|
const uint8_t* src_argb1,
|
|
uint8_t* dst_argb,
|
|
int width) {
|
|
HVX_Vector v255 = Q6_Vh_vsplat_R(255);
|
|
HVX_Vector v_alpha_mask = Q6_V_vsplat_R(0xFF000000u);
|
|
int bytes = width * 4;
|
|
while (bytes > 0) {
|
|
int b_cnt = bytes >= 128 ? 128 : bytes;
|
|
HVX_Vector fg = vloadu_partial_zero(src_argb, b_cnt);
|
|
HVX_Vector bg = vloadu_partial_zero(src_argb1, b_cnt);
|
|
HVX_Vector t = Q6_Vb_vshuffo_VbVb(fg, fg);
|
|
HVX_Vector a_vec = Q6_Vh_vshuffo_VhVh(t, t);
|
|
HVX_VectorPair p = Q6_Wuh_vmpy_VubVub(bg, a_vec);
|
|
HVX_Vector lo = Q6_Vuh_vadd_VuhVuh_sat(Q6_V_lo_W(p), v255);
|
|
HVX_Vector hi = Q6_Vuh_vadd_VuhVuh_sat(Q6_V_hi_W(p), v255);
|
|
HVX_Vector atten_bg = Q6_Vb_vshuffo_VbVb(hi, lo);
|
|
HVX_Vector scaled_bg = Q6_Vub_vsub_VubVub_sat(bg, atten_bg);
|
|
HVX_Vector out = Q6_Vub_vadd_VubVub_sat(scaled_bg, fg);
|
|
out = Q6_V_vor_VV(out, v_alpha_mask);
|
|
vstoreu_partial(dst_argb, out, b_cnt);
|
|
src_argb += 128;
|
|
src_argb1 += 128;
|
|
dst_argb += 128;
|
|
bytes -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBAttenuateRow_HVX(const uint8_t* src_argb,
|
|
uint8_t* dst_argb,
|
|
int width) {
|
|
HVX_Vector v255 = Q6_Vh_vsplat_R(255);
|
|
HVX_Vector v_rgb_mask = Q6_V_vsplat_R(0x00FFFFFFu);
|
|
HVX_Vector v_a_mask = Q6_V_vsplat_R(0xFF000000u);
|
|
int bytes = width * 4;
|
|
while (bytes > 0) {
|
|
int b_cnt = bytes >= 128 ? 128 : bytes;
|
|
HVX_Vector src = vloadu_partial_zero(src_argb, b_cnt);
|
|
HVX_Vector t = Q6_Vb_vshuffo_VbVb(src, src);
|
|
HVX_Vector a_vec = Q6_Vh_vshuffo_VhVh(t, t);
|
|
HVX_VectorPair p = Q6_Wuh_vmpy_VubVub(src, a_vec);
|
|
HVX_Vector lo = Q6_Vuh_vadd_VuhVuh_sat(Q6_V_lo_W(p), v255);
|
|
HVX_Vector hi = Q6_Vuh_vadd_VuhVuh_sat(Q6_V_hi_W(p), v255);
|
|
HVX_Vector out = Q6_Vb_vshuffo_VbVb(hi, lo);
|
|
out =
|
|
Q6_V_vor_VV(Q6_V_vand_VV(out, v_rgb_mask), Q6_V_vand_VV(src, v_a_mask));
|
|
vstoreu_partial(dst_argb, out, b_cnt);
|
|
src_argb += 128;
|
|
dst_argb += 128;
|
|
bytes -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBMultiplyRow_HVX(const uint8_t* src_argb,
|
|
const uint8_t* src_argb1,
|
|
uint8_t* dst_argb,
|
|
int width) {
|
|
HVX_Vector v128 = Q6_Vh_vsplat_R(128);
|
|
int bytes = width * 4;
|
|
while (bytes > 0) {
|
|
int b_cnt = bytes >= 128 ? 128 : bytes;
|
|
HVX_Vector s0 = vloadu_partial_zero(src_argb, b_cnt);
|
|
HVX_Vector s1 = vloadu_partial_zero(src_argb1, b_cnt);
|
|
HVX_VectorPair p = Q6_Wuh_vmpy_VubVub(s0, s1);
|
|
HVX_Vector lo = Q6_Vuh_vadd_VuhVuh_sat(Q6_V_lo_W(p), v128);
|
|
HVX_Vector hi = Q6_Vuh_vadd_VuhVuh_sat(Q6_V_hi_W(p), v128);
|
|
HVX_Vector out = Q6_Vb_vshuffo_VbVb(hi, lo);
|
|
vstoreu_partial(dst_argb, out, b_cnt);
|
|
src_argb += 128;
|
|
src_argb1 += 128;
|
|
dst_argb += 128;
|
|
bytes -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBAddRow_HVX(const uint8_t* src_argb,
|
|
const uint8_t* src_argb1,
|
|
uint8_t* dst_argb,
|
|
int width) {
|
|
int bytes = width * 4;
|
|
while (bytes > 0) {
|
|
int b_cnt = bytes >= 128 ? 128 : bytes;
|
|
HVX_Vector s0 = vloadu_partial_zero(src_argb, b_cnt);
|
|
HVX_Vector s1 = vloadu_partial_zero(src_argb1, b_cnt);
|
|
vstoreu_partial(dst_argb, Q6_Vub_vadd_VubVub_sat(s0, s1), b_cnt);
|
|
src_argb += 128;
|
|
src_argb1 += 128;
|
|
dst_argb += 128;
|
|
bytes -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBSubtractRow_HVX(const uint8_t* src_argb,
|
|
const uint8_t* src_argb1,
|
|
uint8_t* dst_argb,
|
|
int width) {
|
|
int bytes = width * 4;
|
|
while (bytes > 0) {
|
|
int b_cnt = bytes >= 128 ? 128 : bytes;
|
|
HVX_Vector s0 = vloadu_partial_zero(src_argb, b_cnt);
|
|
HVX_Vector s1 = vloadu_partial_zero(src_argb1, b_cnt);
|
|
vstoreu_partial(dst_argb, Q6_Vub_vsub_VubVub_sat(s0, s1), b_cnt);
|
|
src_argb += 128;
|
|
src_argb1 += 128;
|
|
dst_argb += 128;
|
|
bytes -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBExtractAlphaRow_HVX(const uint8_t* src_argb,
|
|
uint8_t* dst_a,
|
|
int width) {
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int src_bytes = w * 4;
|
|
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 > 256 ? 128 : src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector s2 =
|
|
src_bytes > 256
|
|
? vloadu_partial_zero(src_argb + 256,
|
|
src_bytes > 384 ? 128 : src_bytes - 256)
|
|
: Q6_V_vzero();
|
|
HVX_Vector s3 = src_bytes > 384
|
|
? vloadu_partial_zero(src_argb + 384, src_bytes - 384)
|
|
: Q6_V_vzero();
|
|
HVX_Vector ga01 = Q6_V_hi_W(Q6_W_vdeal_VVR(s1, s0, -1));
|
|
HVX_Vector ga23 = Q6_V_hi_W(Q6_W_vdeal_VVR(s3, s2, -1));
|
|
HVX_Vector a = Q6_V_hi_W(Q6_W_vdeal_VVR(ga23, ga01, -1));
|
|
vstoreu_partial(dst_a, a, w);
|
|
src_argb += 512;
|
|
dst_a += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBCopyAlphaRow_HVX(const uint8_t* src, uint8_t* dst, int width) {
|
|
HVX_Vector v_rgb_mask = Q6_V_vsplat_R(0x00FFFFFFu);
|
|
HVX_Vector v_a_mask = Q6_V_vsplat_R(0xFF000000u);
|
|
int bytes = width * 4;
|
|
while (bytes > 0) {
|
|
int b_cnt = bytes >= 128 ? 128 : bytes;
|
|
HVX_Vector s = vloadu_partial_zero(src, b_cnt);
|
|
HVX_Vector d = vloadu_partial_zero(dst, b_cnt);
|
|
HVX_Vector out =
|
|
Q6_V_vor_VV(Q6_V_vand_VV(d, v_rgb_mask), Q6_V_vand_VV(s, v_a_mask));
|
|
vstoreu_partial(dst, out, b_cnt);
|
|
src += 128;
|
|
dst += 128;
|
|
bytes -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBCopyYToAlphaRow_HVX(const uint8_t* src, uint8_t* dst, int width) {
|
|
HVX_Vector v_rgb_mask = Q6_V_vsplat_R(0x00FFFFFFu);
|
|
HVX_Vector z = Q6_V_vzero();
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
HVX_Vector y = vloadu_partial_zero(src, w);
|
|
HVX_VectorPair ga = Q6_W_vshuff_VVR(y, z, -1);
|
|
HVX_VectorPair p01 = Q6_W_vshuff_VVR(Q6_V_lo_W(ga), z, -1);
|
|
HVX_VectorPair p23 = Q6_W_vshuff_VVR(Q6_V_hi_W(ga), z, -1);
|
|
int dst_bytes = w * 4;
|
|
int b0 = dst_bytes > 128 ? 128 : dst_bytes;
|
|
HVX_Vector d0 = vloadu_partial_zero(dst, b0);
|
|
vstoreu_partial(
|
|
dst, Q6_V_vor_VV(Q6_V_vand_VV(d0, v_rgb_mask), Q6_V_lo_W(p01)), b0);
|
|
if (dst_bytes > 128) {
|
|
int b1 = dst_bytes > 256 ? 128 : dst_bytes - 128;
|
|
HVX_Vector d1 = vloadu_partial_zero(dst + 128, b1);
|
|
vstoreu_partial(dst + 128,
|
|
Q6_V_vor_VV(Q6_V_vand_VV(d1, v_rgb_mask), Q6_V_hi_W(p01)),
|
|
b1);
|
|
}
|
|
if (dst_bytes > 256) {
|
|
int b2 = dst_bytes > 384 ? 128 : dst_bytes - 256;
|
|
HVX_Vector d2 = vloadu_partial_zero(dst + 256, b2);
|
|
vstoreu_partial(dst + 256,
|
|
Q6_V_vor_VV(Q6_V_vand_VV(d2, v_rgb_mask), Q6_V_lo_W(p23)),
|
|
b2);
|
|
}
|
|
if (dst_bytes > 384) {
|
|
int b3 = dst_bytes - 384;
|
|
HVX_Vector d3 = vloadu_partial_zero(dst + 384, b3);
|
|
vstoreu_partial(dst + 384,
|
|
Q6_V_vor_VV(Q6_V_vand_VV(d3, v_rgb_mask), Q6_V_hi_W(p23)),
|
|
b3);
|
|
}
|
|
src += 128;
|
|
dst += 512;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void Convert16To8Row_HVX(const uint16_t* src_y,
|
|
uint8_t* dst_y,
|
|
int scale,
|
|
int width) {
|
|
uint32_t scale32 = ((uint32_t)(uint16_t)scale << 16) | (uint16_t)scale;
|
|
HVX_Vector v255 = Q6_Vh_vsplat_R(255);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int src_bytes = w * 2;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_y, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 =
|
|
src_bytes > 128
|
|
? vloadu_partial_zero((const uint8_t*)src_y + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair p0 = Q6_Wuw_vmpy_VuhRuh(s0, scale32);
|
|
HVX_VectorPair p1 = Q6_Wuw_vmpy_VuhRuh(s1, scale32);
|
|
HVX_Vector h0 = Q6_Vuh_vmin_VuhVuh(
|
|
Q6_Vh_vshuffo_VhVh(Q6_V_hi_W(p0), Q6_V_lo_W(p0)), v255);
|
|
HVX_Vector h1 = Q6_Vuh_vmin_VuhVuh(
|
|
Q6_Vh_vshuffo_VhVh(Q6_V_hi_W(p1), Q6_V_lo_W(p1)), v255);
|
|
HVX_Vector out = Q6_Vb_vpacke_VhVh(h1, h0);
|
|
vstoreu_partial(dst_y, out, w);
|
|
src_y += 128;
|
|
dst_y += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void Convert8To16Row_HVX(const uint8_t* src_y,
|
|
uint16_t* dst_y,
|
|
int bits,
|
|
int width) {
|
|
int shift = 16 - bits;
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
HVX_Vector s = vloadu_partial_zero(src_y, w);
|
|
HVX_VectorPair d16 = Q6_W_vshuff_VVR(s, s, -1);
|
|
HVX_Vector d0 = Q6_Vuh_vlsr_VuhR(Q6_V_lo_W(d16), shift);
|
|
HVX_Vector d1 = Q6_Vuh_vlsr_VuhR(Q6_V_hi_W(d16), shift);
|
|
int dst_bytes = w * 2;
|
|
vstoreu_partial(dst_y, d0, dst_bytes > 128 ? 128 : dst_bytes);
|
|
if (dst_bytes > 128) {
|
|
vstoreu_partial((uint8_t*)dst_y + 128, d1, dst_bytes - 128);
|
|
}
|
|
src_y += 128;
|
|
dst_y += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void Convert8To8Row_HVX(const uint8_t* src_y,
|
|
uint8_t* dst_y,
|
|
int scale,
|
|
int bias,
|
|
int width) {
|
|
uint32_t scale32 = (uint32_t)(uint8_t)scale * 0x01010101u;
|
|
HVX_Vector vbias = Q6_Vb_vsplat_R(bias);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
HVX_Vector s = vloadu_partial_zero(src_y, w);
|
|
HVX_VectorPair p = Q6_Wuh_vmpy_VubRub(s, scale32);
|
|
HVX_Vector out =
|
|
Q6_Vb_vadd_VbVb(Q6_Vb_vshuffo_VbVb(Q6_V_hi_W(p), Q6_V_lo_W(p)), vbias);
|
|
vstoreu_partial(dst_y, out, w);
|
|
src_y += 128;
|
|
dst_y += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void MultiplyRow_16_HVX(const uint16_t* src_y,
|
|
uint16_t* dst_y,
|
|
int scale,
|
|
int width) {
|
|
uint32_t scale32 = ((uint32_t)(uint16_t)scale << 16) | (uint16_t)scale;
|
|
while (width > 0) {
|
|
int w = width >= 64 ? 64 : width;
|
|
int bytes = w * 2;
|
|
HVX_Vector s = vloadu_partial_zero(src_y, bytes);
|
|
HVX_VectorPair p = Q6_Wuw_vmpy_VuhRuh(s, scale32);
|
|
HVX_Vector out = Q6_Vh_vshuffe_VhVh(Q6_V_hi_W(p), Q6_V_lo_W(p));
|
|
vstoreu_partial(dst_y, out, bytes);
|
|
src_y += 64;
|
|
dst_y += 64;
|
|
width -= 64;
|
|
}
|
|
}
|
|
|
|
void DivideRow_16_HVX(const uint16_t* src_y,
|
|
uint16_t* dst_y,
|
|
int scale,
|
|
int width) {
|
|
uint32_t scale32 = ((uint32_t)(uint16_t)scale << 16) | (uint16_t)scale;
|
|
while (width > 0) {
|
|
int w = width >= 64 ? 64 : width;
|
|
int bytes = w * 2;
|
|
HVX_Vector s = vloadu_partial_zero(src_y, bytes);
|
|
HVX_VectorPair p = Q6_Wuw_vmpy_VuhRuh(s, scale32);
|
|
HVX_Vector out = Q6_Vh_vshuffo_VhVh(Q6_V_hi_W(p), Q6_V_lo_W(p));
|
|
vstoreu_partial(dst_y, out, bytes);
|
|
src_y += 64;
|
|
dst_y += 64;
|
|
width -= 64;
|
|
}
|
|
}
|
|
|
|
void HalfRow_16To8_HVX(const uint16_t* src_uv,
|
|
ptrdiff_t src_uv_stride,
|
|
uint8_t* dst_uv,
|
|
int scale,
|
|
int width) {
|
|
uint32_t scale32 = ((uint32_t)(uint16_t)scale << 16) | (uint16_t)scale;
|
|
HVX_Vector v255 = Q6_Vh_vsplat_R(255);
|
|
const uint16_t* src_uv1 = src_uv + src_uv_stride;
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int src_bytes = w * 2;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_uv, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 =
|
|
src_bytes > 128
|
|
? vloadu_partial_zero((const uint8_t*)src_uv + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector t0 =
|
|
vloadu_partial_zero(src_uv1, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector t1 = src_bytes > 128
|
|
? vloadu_partial_zero((const uint8_t*)src_uv1 + 128,
|
|
src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector a0 = Q6_Vuh_vavg_VuhVuh_rnd(s0, t0);
|
|
HVX_Vector a1 = Q6_Vuh_vavg_VuhVuh_rnd(s1, t1);
|
|
HVX_VectorPair p0 = Q6_Wuw_vmpy_VuhRuh(a0, scale32);
|
|
HVX_VectorPair p1 = Q6_Wuw_vmpy_VuhRuh(a1, scale32);
|
|
HVX_Vector h0 = Q6_Vuh_vmin_VuhVuh(
|
|
Q6_Vh_vshuffo_VhVh(Q6_V_hi_W(p0), Q6_V_lo_W(p0)), v255);
|
|
HVX_Vector h1 = Q6_Vuh_vmin_VuhVuh(
|
|
Q6_Vh_vshuffo_VhVh(Q6_V_hi_W(p1), Q6_V_lo_W(p1)), v255);
|
|
HVX_Vector out = Q6_Vb_vpacke_VhVh(h1, h0);
|
|
vstoreu_partial(dst_uv, out, w);
|
|
src_uv += 128;
|
|
src_uv1 += 128;
|
|
dst_uv += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void YUY2ToYRow_HVX(const uint8_t* src_yuy2, uint8_t* dst_y, int width) {
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int src_bytes = w * 2;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_yuy2, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_yuy2 + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair d = Q6_W_vdeal_VVR(s1, s0, -1);
|
|
vstoreu_partial(dst_y, Q6_V_lo_W(d), w);
|
|
src_yuy2 += 256;
|
|
dst_y += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void YUY2ToUV422Row_HVX(const uint8_t* src_yuy2,
|
|
uint8_t* dst_u,
|
|
uint8_t* dst_v,
|
|
int width) {
|
|
int uv_width = (width + 1) >> 1;
|
|
while (uv_width > 0) {
|
|
int w = uv_width >= 64 ? 64 : uv_width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_yuy2, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_yuy2 + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector uv = Q6_V_hi_W(Q6_W_vdeal_VVR(s1, s0, -1));
|
|
HVX_VectorPair u_v = Q6_W_vdeal_VVR(uv, uv, -1);
|
|
vstoreu_partial(dst_u, Q6_V_lo_W(u_v), w);
|
|
vstoreu_partial(dst_v, Q6_V_hi_W(u_v), w);
|
|
src_yuy2 += 256;
|
|
dst_u += 64;
|
|
dst_v += 64;
|
|
uv_width -= 64;
|
|
}
|
|
}
|
|
|
|
void YUY2ToUVRow_HVX(const uint8_t* src_yuy2,
|
|
int src_stride_yuy2,
|
|
uint8_t* dst_u,
|
|
uint8_t* dst_v,
|
|
int width) {
|
|
const uint8_t* src_yuy2_1 = src_yuy2 + src_stride_yuy2;
|
|
int uv_width = (width + 1) >> 1;
|
|
while (uv_width > 0) {
|
|
int w = uv_width >= 64 ? 64 : uv_width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_yuy2, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_yuy2 + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector t0 =
|
|
vloadu_partial_zero(src_yuy2_1, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector t1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_yuy2_1 + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector a0 = Q6_Vub_vavg_VubVub_rnd(s0, t0);
|
|
HVX_Vector a1 = Q6_Vub_vavg_VubVub_rnd(s1, t1);
|
|
HVX_Vector uv = Q6_V_hi_W(Q6_W_vdeal_VVR(a1, a0, -1));
|
|
HVX_VectorPair u_v = Q6_W_vdeal_VVR(uv, uv, -1);
|
|
vstoreu_partial(dst_u, Q6_V_lo_W(u_v), w);
|
|
vstoreu_partial(dst_v, Q6_V_hi_W(u_v), w);
|
|
src_yuy2 += 256;
|
|
src_yuy2_1 += 256;
|
|
dst_u += 64;
|
|
dst_v += 64;
|
|
uv_width -= 64;
|
|
}
|
|
}
|
|
|
|
void UYVYToYRow_HVX(const uint8_t* src_uyvy, uint8_t* dst_y, int width) {
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int src_bytes = w * 2;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_uyvy, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_uyvy + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_VectorPair d = Q6_W_vdeal_VVR(s1, s0, -1);
|
|
vstoreu_partial(dst_y, Q6_V_hi_W(d), w);
|
|
src_uyvy += 256;
|
|
dst_y += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void UYVYToUV422Row_HVX(const uint8_t* src_uyvy,
|
|
uint8_t* dst_u,
|
|
uint8_t* dst_v,
|
|
int width) {
|
|
int uv_width = (width + 1) >> 1;
|
|
while (uv_width > 0) {
|
|
int w = uv_width >= 64 ? 64 : uv_width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_uyvy, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_uyvy + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector uv = Q6_V_lo_W(Q6_W_vdeal_VVR(s1, s0, -1));
|
|
HVX_VectorPair u_v = Q6_W_vdeal_VVR(uv, uv, -1);
|
|
vstoreu_partial(dst_u, Q6_V_lo_W(u_v), w);
|
|
vstoreu_partial(dst_v, Q6_V_hi_W(u_v), w);
|
|
src_uyvy += 256;
|
|
dst_u += 64;
|
|
dst_v += 64;
|
|
uv_width -= 64;
|
|
}
|
|
}
|
|
|
|
void UYVYToUVRow_HVX(const uint8_t* src_uyvy,
|
|
int src_stride_uyvy,
|
|
uint8_t* dst_u,
|
|
uint8_t* dst_v,
|
|
int width) {
|
|
const uint8_t* src_uyvy_1 = src_uyvy + src_stride_uyvy;
|
|
int uv_width = (width + 1) >> 1;
|
|
while (uv_width > 0) {
|
|
int w = uv_width >= 64 ? 64 : uv_width;
|
|
int src_bytes = w * 4;
|
|
HVX_Vector s0 =
|
|
vloadu_partial_zero(src_uyvy, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_uyvy + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector t0 =
|
|
vloadu_partial_zero(src_uyvy_1, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector t1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_uyvy_1 + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector a0 = Q6_Vub_vavg_VubVub_rnd(s0, t0);
|
|
HVX_Vector a1 = Q6_Vub_vavg_VubVub_rnd(s1, t1);
|
|
HVX_Vector uv = Q6_V_lo_W(Q6_W_vdeal_VVR(a1, a0, -1));
|
|
HVX_VectorPair u_v = Q6_W_vdeal_VVR(uv, uv, -1);
|
|
vstoreu_partial(dst_u, Q6_V_lo_W(u_v), w);
|
|
vstoreu_partial(dst_v, Q6_V_hi_W(u_v), w);
|
|
src_uyvy += 256;
|
|
src_uyvy_1 += 256;
|
|
dst_u += 64;
|
|
dst_v += 64;
|
|
uv_width -= 64;
|
|
}
|
|
}
|
|
|
|
void J400ToARGBRow_HVX(const uint8_t* src_y, uint8_t* dst_argb, int width) {
|
|
HVX_Vector a = Q6_Vb_vsplat_R(0xff);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
HVX_Vector y = vloadu_partial_zero(src_y, w);
|
|
HVX_VectorPair yy = Q6_W_vshuff_VVR(y, y, -1);
|
|
HVX_VectorPair ya = Q6_W_vshuff_VVR(a, y, -1);
|
|
HVX_VectorPair p01 = Q6_W_vshuff_VVR(Q6_V_lo_W(ya), Q6_V_lo_W(yy), -1);
|
|
HVX_VectorPair p23 = Q6_W_vshuff_VVR(Q6_V_hi_W(ya), Q6_V_hi_W(yy), -1);
|
|
int dst_bytes = w * 4;
|
|
vstoreu_partial(dst_argb, Q6_V_lo_W(p01),
|
|
dst_bytes > 128 ? 128 : dst_bytes);
|
|
if (dst_bytes > 128) {
|
|
vstoreu_partial(dst_argb + 128, Q6_V_hi_W(p01),
|
|
dst_bytes > 256 ? 128 : dst_bytes - 128);
|
|
}
|
|
if (dst_bytes > 256) {
|
|
vstoreu_partial(dst_argb + 256, Q6_V_lo_W(p23),
|
|
dst_bytes > 384 ? 128 : dst_bytes - 256);
|
|
}
|
|
if (dst_bytes > 384) {
|
|
vstoreu_partial(dst_argb + 384, Q6_V_hi_W(p23), dst_bytes - 384);
|
|
}
|
|
src_y += 128;
|
|
dst_argb += 512;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void I400ToARGBRow_HVX(const uint8_t* src_y,
|
|
uint8_t* dst_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width) {
|
|
uint16_t yg = (uint16_t)yuvconstants->kYToRgb[0];
|
|
int16_t yb = yuvconstants->kYBiasToRgb[0];
|
|
uint32_t yg32 = ((uint32_t)yg << 16) | yg;
|
|
HVX_Vector v_yb = Q6_Vh_vsplat_R(yb);
|
|
HVX_Vector a = Q6_Vb_vsplat_R(0xff);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
HVX_Vector y = vloadu_partial_zero(src_y, w);
|
|
HVX_Vector y_even_0101 = Q6_Vb_vshuffe_VbVb(y, y);
|
|
HVX_Vector y_odd_0101 = Q6_Vb_vshuffo_VbVb(y, y);
|
|
HVX_VectorPair p_even = Q6_Wuw_vmpy_VuhRuh(y_even_0101, yg32);
|
|
HVX_VectorPair p_odd = Q6_Wuw_vmpy_VuhRuh(y_odd_0101, yg32);
|
|
HVX_Vector y_lo = Q6_Vh_vasr_VhR(
|
|
Q6_Vh_vadd_VhVh(
|
|
Q6_Vh_vshuffo_VhVh(Q6_V_hi_W(p_even), Q6_V_lo_W(p_even)), v_yb),
|
|
6);
|
|
HVX_Vector y_hi = Q6_Vh_vasr_VhR(
|
|
Q6_Vh_vadd_VhVh(Q6_Vh_vshuffo_VhVh(Q6_V_hi_W(p_odd), Q6_V_lo_W(p_odd)),
|
|
v_yb),
|
|
6);
|
|
HVX_Vector y_out = Q6_Vub_vsat_VhVh(y_hi, y_lo);
|
|
HVX_VectorPair yy = Q6_W_vshuff_VVR(y_out, y_out, -1);
|
|
HVX_VectorPair ya = Q6_W_vshuff_VVR(a, y_out, -1);
|
|
HVX_VectorPair p01 = Q6_W_vshuff_VVR(Q6_V_lo_W(ya), Q6_V_lo_W(yy), -1);
|
|
HVX_VectorPair p23 = Q6_W_vshuff_VVR(Q6_V_hi_W(ya), Q6_V_hi_W(yy), -1);
|
|
int dst_bytes = w * 4;
|
|
vstoreu_partial(dst_argb, Q6_V_lo_W(p01),
|
|
dst_bytes > 128 ? 128 : dst_bytes);
|
|
if (dst_bytes > 128) {
|
|
vstoreu_partial(dst_argb + 128, Q6_V_hi_W(p01),
|
|
dst_bytes > 256 ? 128 : dst_bytes - 128);
|
|
}
|
|
if (dst_bytes > 256) {
|
|
vstoreu_partial(dst_argb + 256, Q6_V_lo_W(p23),
|
|
dst_bytes > 384 ? 128 : dst_bytes - 256);
|
|
}
|
|
if (dst_bytes > 384) {
|
|
vstoreu_partial(dst_argb + 384, Q6_V_hi_W(p23), dst_bytes - 384);
|
|
}
|
|
src_y += 128;
|
|
dst_argb += 512;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBToABGRRow_HVX(const uint8_t* src_argb, uint8_t* dst_abgr, int width) {
|
|
HVX_Vector ctrl = Q6_V_vsplat_R(0x00020002);
|
|
int bytes = width * 4;
|
|
while (bytes >= 128) {
|
|
vstoreu(dst_abgr, Q6_V_vdelta_VV(vloadu(src_argb), ctrl));
|
|
src_argb += 128;
|
|
dst_abgr += 128;
|
|
bytes -= 128;
|
|
}
|
|
if (bytes > 0) {
|
|
vstoreu_partial(dst_abgr,
|
|
Q6_V_vdelta_VV(vloadu_partial_zero(src_argb, bytes), ctrl),
|
|
bytes);
|
|
}
|
|
}
|
|
|
|
void ARGBToBGRARow_HVX(const uint8_t* src_argb, uint8_t* dst_bgra, int width) {
|
|
HVX_Vector ctrl = Q6_Vb_vsplat_R(0x03);
|
|
int bytes = width * 4;
|
|
while (bytes >= 128) {
|
|
vstoreu(dst_bgra, Q6_V_vdelta_VV(vloadu(src_argb), ctrl));
|
|
src_argb += 128;
|
|
dst_bgra += 128;
|
|
bytes -= 128;
|
|
}
|
|
if (bytes > 0) {
|
|
vstoreu_partial(dst_bgra,
|
|
Q6_V_vdelta_VV(vloadu_partial_zero(src_argb, bytes), ctrl),
|
|
bytes);
|
|
}
|
|
}
|
|
|
|
void ARGBToRGBARow_HVX(const uint8_t* src_argb, uint8_t* dst_rgba, int width) {
|
|
int bytes = width * 4;
|
|
while (bytes > 0) {
|
|
int b_cnt = bytes >= 128 ? 128 : bytes;
|
|
HVX_Vector v = vloadu_partial_zero(src_argb, b_cnt);
|
|
HVX_Vector out = Q6_V_vor_VV(Q6_Vw_vasl_VwR(v, 8), Q6_Vuw_vlsr_VuwR(v, 24));
|
|
vstoreu_partial(dst_rgba, out, b_cnt);
|
|
src_argb += 128;
|
|
dst_rgba += 128;
|
|
bytes -= 128;
|
|
}
|
|
}
|
|
|
|
void RGBAToARGBRow_HVX(const uint8_t* src_rgba, uint8_t* dst_argb, int width) {
|
|
int bytes = width * 4;
|
|
while (bytes > 0) {
|
|
int b_cnt = bytes >= 128 ? 128 : bytes;
|
|
HVX_Vector v = vloadu_partial_zero(src_rgba, b_cnt);
|
|
HVX_Vector out = Q6_V_vor_VV(Q6_Vuw_vlsr_VuwR(v, 8), Q6_Vw_vasl_VwR(v, 24));
|
|
vstoreu_partial(dst_argb, out, b_cnt);
|
|
src_rgba += 128;
|
|
dst_argb += 128;
|
|
bytes -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBToAR64Row_HVX(const uint8_t* src_argb, uint16_t* dst_ar64, int width) {
|
|
Convert8To16Row_HVX(src_argb, dst_ar64, 16, width * 4);
|
|
}
|
|
|
|
void ARGBToAB64Row_HVX(const uint8_t* src_argb, uint16_t* dst_ab64, int width) {
|
|
HVX_Vector ctrl = Q6_V_vsplat_R(0x00020002);
|
|
int bytes = width * 4;
|
|
uint8_t* dst = (uint8_t*)dst_ab64;
|
|
while (bytes > 0) {
|
|
int b_cnt = bytes >= 128 ? 128 : bytes;
|
|
HVX_Vector v = Q6_V_vdelta_VV(vloadu_partial_zero(src_argb, b_cnt), ctrl);
|
|
HVX_VectorPair d16 = Q6_W_vshuff_VVR(v, v, -1);
|
|
int dst_bytes = b_cnt * 2;
|
|
vstoreu_partial(dst, Q6_V_lo_W(d16), dst_bytes > 128 ? 128 : dst_bytes);
|
|
if (dst_bytes > 128) {
|
|
vstoreu_partial(dst + 128, Q6_V_hi_W(d16), dst_bytes - 128);
|
|
}
|
|
src_argb += 128;
|
|
dst += 256;
|
|
bytes -= 128;
|
|
}
|
|
}
|
|
|
|
void AR64ToARGBRow_HVX(const uint16_t* src_ar64, uint8_t* dst_argb, int width) {
|
|
int bytes = width * 4;
|
|
const uint8_t* src = (const uint8_t*)src_ar64;
|
|
while (bytes > 0) {
|
|
int b_cnt = bytes >= 128 ? 128 : bytes;
|
|
int src_bytes = b_cnt * 2;
|
|
HVX_Vector s0 = vloadu_partial_zero(src, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
vstoreu_partial(dst_argb, Q6_Vb_vpacko_VhVh(s1, s0), b_cnt);
|
|
src += 256;
|
|
dst_argb += 128;
|
|
bytes -= 128;
|
|
}
|
|
}
|
|
|
|
void AB64ToARGBRow_HVX(const uint16_t* src_ab64, uint8_t* dst_argb, int width) {
|
|
HVX_Vector ctrl = Q6_V_vsplat_R(0x00020002);
|
|
int bytes = width * 4;
|
|
const uint8_t* src = (const uint8_t*)src_ab64;
|
|
while (bytes > 0) {
|
|
int b_cnt = bytes >= 128 ? 128 : bytes;
|
|
int src_bytes = b_cnt * 2;
|
|
HVX_Vector s0 = vloadu_partial_zero(src, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector s1 = src_bytes > 128
|
|
? vloadu_partial_zero(src + 128, src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector out = Q6_V_vdelta_VV(Q6_Vb_vpacko_VhVh(s1, s0), ctrl);
|
|
vstoreu_partial(dst_argb, out, b_cnt);
|
|
src += 256;
|
|
dst_argb += 128;
|
|
bytes -= 128;
|
|
}
|
|
}
|
|
|
|
void AR64ToAB64Row_HVX(const uint16_t* src_ar64,
|
|
uint16_t* dst_ab64,
|
|
int width) {
|
|
HVX_Vector ctrl = Q6_V_vsplat_R(0x00000404);
|
|
int bytes = width * 8;
|
|
const uint8_t* src = (const uint8_t*)src_ar64;
|
|
uint8_t* dst = (uint8_t*)dst_ab64;
|
|
while (bytes >= 128) {
|
|
vstoreu(dst, Q6_V_vdelta_VV(vloadu(src), ctrl));
|
|
src += 128;
|
|
dst += 128;
|
|
bytes -= 128;
|
|
}
|
|
if (bytes > 0) {
|
|
vstoreu_partial(dst, Q6_V_vdelta_VV(vloadu_partial_zero(src, bytes), ctrl),
|
|
bytes);
|
|
}
|
|
}
|
|
|
|
static __inline void YuvToRgb_HVX(HVX_Vector y,
|
|
HVX_Vector u,
|
|
HVX_Vector v,
|
|
HVX_Vector* b_out,
|
|
HVX_Vector* g_out,
|
|
HVX_Vector* r_out,
|
|
const struct YuvConstants* yuvconstants) {
|
|
uint8_t ub = yuvconstants->kUVToB[0];
|
|
uint8_t ug = yuvconstants->kUVToG[0];
|
|
uint8_t vg = yuvconstants->kUVToG[1];
|
|
uint8_t vr = yuvconstants->kUVToR[1];
|
|
uint16_t yg = (uint16_t)yuvconstants->kYToRgb[0];
|
|
int16_t yb = yuvconstants->kYBiasToRgb[0];
|
|
|
|
uint32_t yg32 = ((uint32_t)yg << 16) | yg;
|
|
HVX_Vector v_yb = Q6_Vh_vsplat_R(yb);
|
|
HVX_Vector v_ub = Q6_Vb_vsplat_R(ub);
|
|
HVX_Vector v_ug = Q6_Vb_vsplat_R(ug);
|
|
HVX_Vector v_vg = Q6_Vb_vsplat_R(vg);
|
|
HVX_Vector v_vr = Q6_Vb_vsplat_R(vr);
|
|
HVX_Vector v80 = Q6_Vb_vsplat_R(0x80);
|
|
|
|
HVX_Vector ui = Q6_Vb_vsub_VbVb(u, v80);
|
|
HVX_Vector vi = Q6_Vb_vsub_VbVb(v, v80);
|
|
|
|
HVX_Vector y_even_0101 = Q6_Vb_vshuffe_VbVb(y, y);
|
|
HVX_Vector y_odd_0101 = Q6_Vb_vshuffo_VbVb(y, y);
|
|
HVX_VectorPair p_even = Q6_Wuw_vmpy_VuhRuh(y_even_0101, yg32);
|
|
HVX_VectorPair p_odd = Q6_Wuw_vmpy_VuhRuh(y_odd_0101, yg32);
|
|
HVX_Vector y1_lo = Q6_Vh_vadd_VhVh(
|
|
Q6_Vh_vshuffo_VhVh(Q6_V_hi_W(p_even), Q6_V_lo_W(p_even)), v_yb);
|
|
HVX_Vector y1_hi = Q6_Vh_vadd_VhVh(
|
|
Q6_Vh_vshuffo_VhVh(Q6_V_hi_W(p_odd), Q6_V_lo_W(p_odd)), v_yb);
|
|
|
|
HVX_VectorPair b_uv = Q6_Wh_vmpy_VubVb(v_ub, ui);
|
|
HVX_Vector b_lo =
|
|
Q6_Vh_vasr_VhR(Q6_Vh_vadd_VhVh_sat(y1_lo, Q6_V_lo_W(b_uv)), 6);
|
|
HVX_Vector b_hi =
|
|
Q6_Vh_vasr_VhR(Q6_Vh_vadd_VhVh_sat(y1_hi, Q6_V_hi_W(b_uv)), 6);
|
|
*b_out = Q6_Vub_vsat_VhVh(b_hi, b_lo);
|
|
|
|
HVX_VectorPair g_uv =
|
|
Q6_Wh_vmpyacc_WhVubVb(Q6_Wh_vmpy_VubVb(v_ug, ui), v_vg, vi);
|
|
HVX_Vector g_lo =
|
|
Q6_Vh_vasr_VhR(Q6_Vh_vsub_VhVh_sat(y1_lo, Q6_V_lo_W(g_uv)), 6);
|
|
HVX_Vector g_hi =
|
|
Q6_Vh_vasr_VhR(Q6_Vh_vsub_VhVh_sat(y1_hi, Q6_V_hi_W(g_uv)), 6);
|
|
*g_out = Q6_Vub_vsat_VhVh(g_hi, g_lo);
|
|
|
|
HVX_VectorPair r_uv = Q6_Wh_vmpy_VubVb(v_vr, vi);
|
|
HVX_Vector r_lo =
|
|
Q6_Vh_vasr_VhR(Q6_Vh_vadd_VhVh_sat(y1_lo, Q6_V_lo_W(r_uv)), 6);
|
|
HVX_Vector r_hi =
|
|
Q6_Vh_vasr_VhR(Q6_Vh_vadd_VhVh_sat(y1_hi, Q6_V_hi_W(r_uv)), 6);
|
|
*r_out = Q6_Vub_vsat_VhVh(r_hi, r_lo);
|
|
}
|
|
|
|
static __inline void StoreARGB_HVX(uint8_t* dst_argb,
|
|
HVX_Vector b,
|
|
HVX_Vector g,
|
|
HVX_Vector r,
|
|
HVX_Vector a,
|
|
int w) {
|
|
HVX_VectorPair br = Q6_W_vshuff_VVR(r, b, -1);
|
|
HVX_VectorPair ga = Q6_W_vshuff_VVR(a, g, -1);
|
|
HVX_VectorPair p01 = Q6_W_vshuff_VVR(Q6_V_lo_W(ga), Q6_V_lo_W(br), -1);
|
|
HVX_VectorPair p23 = Q6_W_vshuff_VVR(Q6_V_hi_W(ga), Q6_V_hi_W(br), -1);
|
|
int dst_bytes = w * 4;
|
|
vstoreu_partial(dst_argb, Q6_V_lo_W(p01), dst_bytes > 128 ? 128 : dst_bytes);
|
|
if (dst_bytes > 128) {
|
|
vstoreu_partial(dst_argb + 128, Q6_V_hi_W(p01),
|
|
dst_bytes > 256 ? 128 : dst_bytes - 128);
|
|
}
|
|
if (dst_bytes > 256) {
|
|
vstoreu_partial(dst_argb + 256, Q6_V_lo_W(p23),
|
|
dst_bytes > 384 ? 128 : dst_bytes - 256);
|
|
}
|
|
if (dst_bytes > 384) {
|
|
vstoreu_partial(dst_argb + 384, Q6_V_hi_W(p23), dst_bytes - 384);
|
|
}
|
|
}
|
|
|
|
void I444ToARGBRow_HVX(const uint8_t* src_y,
|
|
const uint8_t* src_u,
|
|
const uint8_t* src_v,
|
|
uint8_t* dst_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width) {
|
|
HVX_Vector a = Q6_Vb_vsplat_R(0xff);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
HVX_Vector y = vloadu_partial_zero(src_y, w);
|
|
HVX_Vector u = vloadu_partial_zero(src_u, w);
|
|
HVX_Vector v = vloadu_partial_zero(src_v, w);
|
|
HVX_Vector b, g, r;
|
|
YuvToRgb_HVX(y, u, v, &b, &g, &r, yuvconstants);
|
|
StoreARGB_HVX(dst_argb, b, g, r, a, w);
|
|
src_y += 128;
|
|
src_u += 128;
|
|
src_v += 128;
|
|
dst_argb += 512;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void I444AlphaToARGBRow_HVX(const uint8_t* src_y,
|
|
const uint8_t* src_u,
|
|
const uint8_t* src_v,
|
|
const uint8_t* src_a,
|
|
uint8_t* dst_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width) {
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
HVX_Vector y = vloadu_partial_zero(src_y, w);
|
|
HVX_Vector u = vloadu_partial_zero(src_u, w);
|
|
HVX_Vector v = vloadu_partial_zero(src_v, w);
|
|
HVX_Vector a = vloadu_partial_zero(src_a, w);
|
|
HVX_Vector b, g, r;
|
|
YuvToRgb_HVX(y, u, v, &b, &g, &r, yuvconstants);
|
|
StoreARGB_HVX(dst_argb, b, g, r, a, w);
|
|
src_y += 128;
|
|
src_u += 128;
|
|
src_v += 128;
|
|
src_a += 128;
|
|
dst_argb += 512;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void I422ToARGBRow_HVX(const uint8_t* src_y,
|
|
const uint8_t* src_u,
|
|
const uint8_t* src_v,
|
|
uint8_t* dst_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width) {
|
|
HVX_Vector a = Q6_Vb_vsplat_R(0xff);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int uv_w = (w + 1) >> 1;
|
|
HVX_Vector y = vloadu_partial_zero(src_y, w);
|
|
HVX_Vector u_sub = vloadu_partial_zero(src_u, uv_w);
|
|
HVX_Vector v_sub = vloadu_partial_zero(src_v, uv_w);
|
|
HVX_Vector u = Q6_V_lo_W(Q6_W_vshuff_VVR(u_sub, u_sub, -1));
|
|
HVX_Vector v = Q6_V_lo_W(Q6_W_vshuff_VVR(v_sub, v_sub, -1));
|
|
HVX_Vector b, g, r;
|
|
YuvToRgb_HVX(y, u, v, &b, &g, &r, yuvconstants);
|
|
StoreARGB_HVX(dst_argb, b, g, r, a, w);
|
|
src_y += 128;
|
|
src_u += 64;
|
|
src_v += 64;
|
|
dst_argb += 512;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void I422AlphaToARGBRow_HVX(const uint8_t* src_y,
|
|
const uint8_t* src_u,
|
|
const uint8_t* src_v,
|
|
const uint8_t* src_a,
|
|
uint8_t* dst_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width) {
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int uv_w = (w + 1) >> 1;
|
|
HVX_Vector y = vloadu_partial_zero(src_y, w);
|
|
HVX_Vector u_sub = vloadu_partial_zero(src_u, uv_w);
|
|
HVX_Vector v_sub = vloadu_partial_zero(src_v, uv_w);
|
|
HVX_Vector a = vloadu_partial_zero(src_a, w);
|
|
HVX_Vector u = Q6_V_lo_W(Q6_W_vshuff_VVR(u_sub, u_sub, -1));
|
|
HVX_Vector v = Q6_V_lo_W(Q6_W_vshuff_VVR(v_sub, v_sub, -1));
|
|
HVX_Vector b, g, r;
|
|
YuvToRgb_HVX(y, u, v, &b, &g, &r, yuvconstants);
|
|
StoreARGB_HVX(dst_argb, b, g, r, a, w);
|
|
src_y += 128;
|
|
src_u += 64;
|
|
src_v += 64;
|
|
src_a += 128;
|
|
dst_argb += 512;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void I422ToRGBARow_HVX(const uint8_t* src_y,
|
|
const uint8_t* src_u,
|
|
const uint8_t* src_v,
|
|
uint8_t* dst_rgba,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width) {
|
|
HVX_Vector a = Q6_Vb_vsplat_R(0xff);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int uv_w = (w + 1) >> 1;
|
|
HVX_Vector y = vloadu_partial_zero(src_y, w);
|
|
HVX_Vector u_sub = vloadu_partial_zero(src_u, uv_w);
|
|
HVX_Vector v_sub = vloadu_partial_zero(src_v, uv_w);
|
|
HVX_Vector u = Q6_V_lo_W(Q6_W_vshuff_VVR(u_sub, u_sub, -1));
|
|
HVX_Vector v = Q6_V_lo_W(Q6_W_vshuff_VVR(v_sub, v_sub, -1));
|
|
HVX_Vector b, g, r;
|
|
YuvToRgb_HVX(y, u, v, &b, &g, &r, yuvconstants);
|
|
StoreARGB_HVX(dst_rgba, a, b, g, r, w);
|
|
src_y += 128;
|
|
src_u += 64;
|
|
src_v += 64;
|
|
dst_rgba += 512;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void NV12ToARGBRow_HVX(const uint8_t* src_y,
|
|
const uint8_t* src_uv,
|
|
uint8_t* dst_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width) {
|
|
HVX_Vector a = Q6_Vb_vsplat_R(0xff);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int uv_bytes = ((w + 1) >> 1) * 2;
|
|
HVX_Vector y = vloadu_partial_zero(src_y, w);
|
|
HVX_Vector uv = vloadu_partial_zero(src_uv, uv_bytes);
|
|
HVX_VectorPair u_v = Q6_W_vdeal_VVR(uv, uv, -1);
|
|
HVX_Vector u_sub = Q6_V_lo_W(u_v);
|
|
HVX_Vector v_sub = Q6_V_hi_W(u_v);
|
|
HVX_Vector u = Q6_V_lo_W(Q6_W_vshuff_VVR(u_sub, u_sub, -1));
|
|
HVX_Vector v = Q6_V_lo_W(Q6_W_vshuff_VVR(v_sub, v_sub, -1));
|
|
HVX_Vector b, g, r;
|
|
YuvToRgb_HVX(y, u, v, &b, &g, &r, yuvconstants);
|
|
StoreARGB_HVX(dst_argb, b, g, r, a, w);
|
|
src_y += 128;
|
|
src_uv += 128;
|
|
dst_argb += 512;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void NV21ToARGBRow_HVX(const uint8_t* src_y,
|
|
const uint8_t* src_vu,
|
|
uint8_t* dst_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width) {
|
|
HVX_Vector a = Q6_Vb_vsplat_R(0xff);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int uv_bytes = ((w + 1) >> 1) * 2;
|
|
HVX_Vector y = vloadu_partial_zero(src_y, w);
|
|
HVX_Vector vu = vloadu_partial_zero(src_vu, uv_bytes);
|
|
HVX_VectorPair v_u = Q6_W_vdeal_VVR(vu, vu, -1);
|
|
HVX_Vector v_sub = Q6_V_lo_W(v_u);
|
|
HVX_Vector u_sub = Q6_V_hi_W(v_u);
|
|
HVX_Vector u = Q6_V_lo_W(Q6_W_vshuff_VVR(u_sub, u_sub, -1));
|
|
HVX_Vector v = Q6_V_lo_W(Q6_W_vshuff_VVR(v_sub, v_sub, -1));
|
|
HVX_Vector b, g, r;
|
|
YuvToRgb_HVX(y, u, v, &b, &g, &r, yuvconstants);
|
|
StoreARGB_HVX(dst_argb, b, g, r, a, w);
|
|
src_y += 128;
|
|
src_vu += 128;
|
|
dst_argb += 512;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBToYMatrixRow_HVX(const uint8_t* src_argb,
|
|
uint8_t* dst_y,
|
|
int width,
|
|
const struct ArgbConstants* c) {
|
|
uint32_t coeff_y;
|
|
memcpy(&coeff_y, c->kRGBToY, sizeof(coeff_y));
|
|
HVX_Vector v_add_y = Q6_V_vsplat_R((uint32_t)c->kAddY[0]);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int src_bytes = w * 4;
|
|
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 > 256 ? 128 : src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector s2 =
|
|
src_bytes > 256
|
|
? vloadu_partial_zero(src_argb + 256,
|
|
src_bytes > 384 ? 128 : src_bytes - 256)
|
|
: Q6_V_vzero();
|
|
HVX_Vector s3 = src_bytes > 384
|
|
? vloadu_partial_zero(src_argb + 384, src_bytes - 384)
|
|
: Q6_V_vzero();
|
|
HVX_Vector y0 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vadd_VwVw(Q6_Vuw_vrmpy_VubRub(s0, coeff_y), v_add_y), 8);
|
|
HVX_Vector y1 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vadd_VwVw(Q6_Vuw_vrmpy_VubRub(s1, coeff_y), v_add_y), 8);
|
|
HVX_Vector y2 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vadd_VwVw(Q6_Vuw_vrmpy_VubRub(s2, coeff_y), v_add_y), 8);
|
|
HVX_Vector y3 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vadd_VwVw(Q6_Vuw_vrmpy_VubRub(s3, coeff_y), v_add_y), 8);
|
|
HVX_Vector y01 = Q6_Vh_vpacke_VwVw(y1, y0);
|
|
HVX_Vector y23 = Q6_Vh_vpacke_VwVw(y3, y2);
|
|
HVX_Vector out = Q6_Vb_vpacke_VhVh(y23, y01);
|
|
vstoreu_partial(dst_y, out, w);
|
|
src_argb += 512;
|
|
dst_y += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBToUV444MatrixRow_HVX(const uint8_t* src_argb,
|
|
uint8_t* dst_u,
|
|
uint8_t* dst_v,
|
|
int width,
|
|
const struct ArgbConstants* c) {
|
|
int32_t coeff_u;
|
|
int32_t coeff_v;
|
|
memcpy(&coeff_u, c->kRGBToU, sizeof(coeff_u));
|
|
memcpy(&coeff_v, c->kRGBToV, sizeof(coeff_v));
|
|
HVX_Vector v_add_uv = Q6_V_vsplat_R((uint32_t)c->kAddUV[0]);
|
|
while (width > 0) {
|
|
int w = width >= 128 ? 128 : width;
|
|
int src_bytes = w * 4;
|
|
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 > 256 ? 128 : src_bytes - 128)
|
|
: Q6_V_vzero();
|
|
HVX_Vector s2 =
|
|
src_bytes > 256
|
|
? vloadu_partial_zero(src_argb + 256,
|
|
src_bytes > 384 ? 128 : src_bytes - 256)
|
|
: Q6_V_vzero();
|
|
HVX_Vector s3 = src_bytes > 384
|
|
? vloadu_partial_zero(src_argb + 384, src_bytes - 384)
|
|
: Q6_V_vzero();
|
|
|
|
HVX_Vector u0 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vsub_VwVw(v_add_uv, Q6_Vw_vrmpy_VubRb(s0, coeff_u)), 8);
|
|
HVX_Vector u1 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vsub_VwVw(v_add_uv, Q6_Vw_vrmpy_VubRb(s1, coeff_u)), 8);
|
|
HVX_Vector u2 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vsub_VwVw(v_add_uv, Q6_Vw_vrmpy_VubRb(s2, coeff_u)), 8);
|
|
HVX_Vector u3 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vsub_VwVw(v_add_uv, Q6_Vw_vrmpy_VubRb(s3, coeff_u)), 8);
|
|
HVX_Vector u_out =
|
|
Q6_Vb_vpacke_VhVh(Q6_Vh_vpacke_VwVw(u3, u2), Q6_Vh_vpacke_VwVw(u1, u0));
|
|
vstoreu_partial(dst_u, u_out, w);
|
|
|
|
HVX_Vector v0 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vsub_VwVw(v_add_uv, Q6_Vw_vrmpy_VubRb(s0, coeff_v)), 8);
|
|
HVX_Vector v1 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vsub_VwVw(v_add_uv, Q6_Vw_vrmpy_VubRb(s1, coeff_v)), 8);
|
|
HVX_Vector v2 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vsub_VwVw(v_add_uv, Q6_Vw_vrmpy_VubRb(s2, coeff_v)), 8);
|
|
HVX_Vector v3 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vsub_VwVw(v_add_uv, Q6_Vw_vrmpy_VubRb(s3, coeff_v)), 8);
|
|
HVX_Vector v_out =
|
|
Q6_Vb_vpacke_VhVh(Q6_Vh_vpacke_VwVw(v3, v2), Q6_Vh_vpacke_VwVw(v1, v0));
|
|
vstoreu_partial(dst_v, v_out, w);
|
|
|
|
src_argb += 512;
|
|
dst_u += 128;
|
|
dst_v += 128;
|
|
width -= 128;
|
|
}
|
|
}
|
|
|
|
void ARGBToUVMatrixRow_HVX(const uint8_t* src_argb,
|
|
int src_stride_argb,
|
|
uint8_t* dst_u,
|
|
uint8_t* dst_v,
|
|
int width,
|
|
const struct ArgbConstants* c) {
|
|
int32_t coeff_u;
|
|
int32_t coeff_v;
|
|
memcpy(&coeff_u, c->kRGBToU, sizeof(coeff_u));
|
|
memcpy(&coeff_v, c->kRGBToV, sizeof(coeff_v));
|
|
HVX_Vector v_add_uv = Q6_V_vsplat_R((uint32_t)c->kAddUV[0]);
|
|
HVX_Vector vtwo = Q6_Vh_vsplat_R(2);
|
|
const uint8_t* src_argb1 = src_argb + src_stride_argb;
|
|
|
|
int even_width = width & ~1;
|
|
while (even_width > 0) {
|
|
int w = even_width >= 64 ? 64 : even_width;
|
|
int uv_w = w >> 1;
|
|
int src_bytes = w * 4;
|
|
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_Vector t0 =
|
|
vloadu_partial_zero(src_argb1, src_bytes > 128 ? 128 : src_bytes);
|
|
HVX_Vector t1 = src_bytes > 128
|
|
? vloadu_partial_zero(src_argb1 + 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 avg = Q6_Vub_vpack_VhVh_sat(sum_hi, sum_lo);
|
|
HVX_Vector u0 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vsub_VwVw(v_add_uv, Q6_Vw_vrmpy_VubRb(avg, coeff_u)), 8);
|
|
HVX_Vector v0 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vsub_VwVw(v_add_uv, Q6_Vw_vrmpy_VubRb(avg, coeff_v)), 8);
|
|
HVX_Vector u_out =
|
|
Q6_Vb_vpacke_VhVh(Q6_V_vzero(), Q6_Vh_vpacke_VwVw(Q6_V_vzero(), u0));
|
|
HVX_Vector v_out =
|
|
Q6_Vb_vpacke_VhVh(Q6_V_vzero(), Q6_Vh_vpacke_VwVw(Q6_V_vzero(), v0));
|
|
vstoreu_partial(dst_u, u_out, uv_w);
|
|
vstoreu_partial(dst_v, v_out, uv_w);
|
|
|
|
src_argb += w * 4;
|
|
src_argb1 += w * 4;
|
|
dst_u += uv_w;
|
|
dst_v += uv_w;
|
|
even_width -= w;
|
|
}
|
|
if (width & 1) {
|
|
HVX_Vector s0 = vloadu_partial_zero(src_argb, 4);
|
|
HVX_Vector t0 = vloadu_partial_zero(src_argb1, 4);
|
|
HVX_Vector avg = Q6_Vub_vavg_VubVub_rnd(s0, t0);
|
|
HVX_Vector u0 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vsub_VwVw(v_add_uv, Q6_Vw_vrmpy_VubRb(avg, coeff_u)), 8);
|
|
HVX_Vector v0 = Q6_Vuw_vlsr_VuwR(
|
|
Q6_Vw_vsub_VwVw(v_add_uv, Q6_Vw_vrmpy_VubRb(avg, coeff_v)), 8);
|
|
vstoreu_partial(dst_u, u0, 1);
|
|
vstoreu_partial(dst_v, v0, 1);
|
|
}
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
} // extern "C"
|
|
} // namespace libyuv
|
|
#endif
|
|
|
|
#endif // !defined(LIBYUV_DISABLE_HVX) && defined(__HVX__)
|