libyuv/source/row_hvx.cc
Frank Barchard 700f153cb8 [libyuv] Add Qualcomm Hexagon HVX SIMD support
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>
2026-10-19 14:16:18 -07:00

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__)