/* * 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 #include #include #include #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 ARGBOrRow_HVX(const uint8_t* src_argb, uint8_t* dst_argb, uint32_t value, int width) { HVX_Vector v = Q6_V_vsplat_R(value); int bytes = width * 4; while (bytes >= 128) { HVX_Vector s = vloadu(src_argb); vstoreu(dst_argb, Q6_V_vor_VV(s, v)); src_argb += 128; dst_argb += 128; bytes -= 128; } if (bytes > 0) { HVX_Vector s = vloadu_partial_zero(src_argb, bytes); vstoreu_partial(dst_argb, Q6_V_vor_VV(s, 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 ARGBAlphaBlendRow_HVX(const uint8_t* src_argb0, const uint8_t* src_argb1, uint8_t* dst_argb, int width) { HVX_Vector vzero = Q6_V_vzero(); HVX_Vector v0001 = Q6_Vh_vsplat_R(1); HVX_Vector v00ff = Q6_Vh_vsplat_R(255); HVX_Vector vffff = Q6_Vh_vsplat_R(-1); HVX_Vector v_rgb_mask = Q6_V_vsplat_R(0x00FFFFFFu); int bytes = width * 4; while (bytes > 0) { int b_cnt = bytes >= 128 ? 128 : bytes; HVX_Vector fg = vloadu_partial_zero(src_argb0, b_cnt); HVX_Vector bg = vloadu_partial_zero(src_argb1, b_cnt); // Broadcast sa and da to all 4 byte lanes of each 32-bit pixel. HVX_Vector t_fg = Q6_Vb_vshuffo_VbVb(fg, fg); HVX_Vector sa_vec = Q6_Vh_vshuffo_VhVh(t_fg, t_fg); HVX_Vector t_bg = Q6_Vb_vshuffo_VbVb(bg, bg); HVX_Vector da_vec = Q6_Vh_vshuffo_VhVh(t_bg, t_bg); // Both uint16_t halfwords of each pixel hold sa and da (0..255). HVX_Vector sa16 = Q6_V_vand_VV(sa_vec, v00ff); HVX_Vector da16 = Q6_V_vand_VV(da_vec, v00ff); // x = da * sa in both uint16_t halfwords of each pixel. HVX_Vector x = Q6_V_lo_W(Q6_Wuh_vmpy_VubVub(da_vec, sa_vec)); // prod_div255 = (x + 1 + (x >> 8)) >> 8. HVX_Vector prod_div255 = Q6_Vuh_vlsr_VuhR( Q6_Vh_vadd_VhVh(Q6_Vh_vadd_VhVh(x, v0001), Q6_Vuh_vlsr_VuhR(x, 8)), 8); // out_a = da + sa - (da * sa) / 255. HVX_Vector out_a16 = Q6_Vh_vadd_VhVh(da16, Q6_Vh_vsub_VhVh(sa16, prod_div255)); // 8-step restoring division: ratio = (da == 0) ? 255 : (sa * 255) / out_a. HVX_Vector rem = Q6_Vh_vsub_VhVh(Q6_Vh_vasl_VhR(sa16, 8), sa16); HVX_VectorPred q_da_zero = Q6_Q_vcmp_eq_VhVh(da16, vzero); rem = Q6_V_vmux_QVV(q_da_zero, vffff, rem); HVX_Vector ratio = vzero; for (int bit = 7; bit >= 0; --bit) { HVX_Vector d_sh = Q6_Vh_vasl_VhR(out_a16, bit); HVX_VectorPred q_gt = Q6_Q_vcmp_gt_VuhVuh(d_sh, rem); rem = Q6_V_vmux_QVV(q_gt, rem, Q6_Vh_vsub_VhVh(rem, d_sh)); ratio = Q6_V_vmux_QVV(q_gt, ratio, Q6_V_vor_VV(ratio, Q6_Vb_vsplat_R(1 << bit))); } // Exact RGB lerp: (bg * (255 - ratio) + fg * ratio) / 255. HVX_Vector inv_ratio = Q6_V_vnot_V(ratio); HVX_VectorPair p_rgb = Q6_Wuh_vmpy_VubVub(fg, ratio); p_rgb = Q6_Wuh_vmpyacc_WuhVubVub(p_rgb, bg, inv_ratio); HVX_Vector lo = Q6_V_lo_W(p_rgb); HVX_Vector hi = Q6_V_hi_W(p_rgb); lo = Q6_Vh_vadd_VhVh(Q6_Vh_vadd_VhVh(lo, v0001), Q6_Vuh_vlsr_VuhR(lo, 8)); hi = Q6_Vh_vadd_VhVh(Q6_Vh_vadd_VhVh(hi, v0001), Q6_Vuh_vlsr_VuhR(hi, 8)); HVX_Vector out = Q6_Vb_vshuffo_VbVb(hi, lo); out = Q6_V_vor_VV(Q6_V_vand_VV(out, v_rgb_mask), Q6_Vw_vasl_VwR(out_a16, 24)); vstoreu_partial(dst_argb, out, b_cnt); src_argb0 += 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__)