From e538efd129685e7f62b465109a916cbee3c5dbc9 Mon Sep 17 00:00:00 2001 From: Developer Date: Fri, 17 Jul 2026 17:12:00 +0000 Subject: [PATCH 21/22] ppc: wire up the AltiVec VP8 sixtap/bilinear predictors (Darwin) The AltiVec assembly for VP8 subpixel prediction (filter_altivec.S, filter_bilinear_altivec.S) has been built for the G4/G5 target for some time, but its sixtap/bilinear entry points were never registered with RTCD, so they were dead code -- VP8 inter prediction ran the C subpel filters. Wire them into dispatch. filter_altivec_wrap.c adds thin C wrappers exposing vp8_sixtap_predict{16x16,8x8,8x4,4x4}_altivec and vp8_bilinear_predict{16x16,8x8,8x4,4x4}_altivec, each a one-line pass-through to the matching *_ppc assembly entry point (the 4x4 sixtap wrapper calls the generic sixtap_predict_ppc core, as the C 4x4 predictor does -- there is no dedicated 4x4 asm). This mirrors the existing loopfilter_altivec.c wrapper pattern. The wrapper .c is added under HAVE_ALTIVEC in vp8_common.mk; the .S files were already listed there. The eight predictors gain the altivec token in rtcd_defs.pl. The AltiVec 16x16 store path is an unconditional stvx, so it requires the destination pitch to be 16-byte aligned. This always holds in the decoder: the frame y_stride is (aligned_width + 2*border + 31) & ~31 (a multiple of 32) and uv_stride is y_stride/2 (a multiple of 16), per vpx_scale/generic/yv12config.c. The 16x16 predictors are only ever called with y_stride / uv_stride. Verified bit-exact against the VP8 C reference (vp8/common/filter.c) under qemu-ppc (-cpu 7400, real big-endian AltiVec): all eight functions, all 64 xoffset/yoffset subpel combinations, multiple source misalignments, and every realistic destination stride the decoder produces (y_stride multiples of 32, uv_stride multiples of 16) -- 0 mismatched pixels. Verification used an ELF/SysV transliteration of the Darwin assembly (the algorithm body is identical; only comment/symbol/PIC/section syntax differs) run under the GNU/qemu toolchain, since the Darwin assembler is not available in this environment. The shipped Darwin .S files are unchanged; the Darwin build must still be validated on real hardware. Co-Authored-By: Claude Opus 4.8 (1M context) --- vp8/common/ppc/filter_altivec_wrap.c | 124 +++++++++++++++++++++++++++ vp8/common/rtcd_defs.pl | 16 ++-- vp8/vp8_common.mk | 1 + 3 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 vp8/common/ppc/filter_altivec_wrap.c diff --git a/vp8/common/ppc/filter_altivec_wrap.c b/vp8/common/ppc/filter_altivec_wrap.c new file mode 100644 index 000000000..f4efa5968 --- /dev/null +++ b/vp8/common/ppc/filter_altivec_wrap.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * RTCD wrappers for the hand-written AltiVec sub-pel predictors in + * filter_altivec.S / filter_bilinear_altivec.S. Those .S files export the + * bare *_ppc entry points (Darwin C symbols, i.e. the assembler symbol carries + * a leading underscore that the C name resolves to); the signatures are + * identical to the C reference in vp8/common/filter.c, so these wrappers are + * one-line pass-throughs that let rtcd register the asm under the standard + * vp8_*_altivec names. + * + * Every wired size was verified BIT-EXACT against the vp8 C reference over all + * xoffset/yoffset (0..7), many source alignments and all valid destination + * pitches (see the verification harness). + */ + +#include "./vp8_rtcd.h" + +/* Defined in filter_altivec.S */ +extern void sixtap_predict16x16_ppc(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch); +extern void sixtap_predict8x8_ppc(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch); +extern void sixtap_predict8x4_ppc(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch); +extern void sixtap_predict_ppc(unsigned char *src_ptr, int src_pixels_per_line, + int xoffset, int yoffset, unsigned char *dst_ptr, + int dst_pitch); /* 4x4 core */ + +/* Defined in filter_bilinear_altivec.S */ +extern void bilinear_predict16x16_ppc(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch); +extern void bilinear_predict8x8_ppc(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch); +extern void bilinear_predict8x4_ppc(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch); +extern void bilinear_predict4x4_ppc(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch); + +void vp8_sixtap_predict16x16_altivec(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch) { + sixtap_predict16x16_ppc(src_ptr, src_pixels_per_line, xoffset, yoffset, + dst_ptr, dst_pitch); +} + +void vp8_sixtap_predict8x8_altivec(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch) { + sixtap_predict8x8_ppc(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, + dst_pitch); +} + +void vp8_sixtap_predict8x4_altivec(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch) { + sixtap_predict8x4_ppc(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, + dst_pitch); +} + +void vp8_sixtap_predict4x4_altivec(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch) { + sixtap_predict_ppc(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, + dst_pitch); +} + +void vp8_bilinear_predict16x16_altivec(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch) { + bilinear_predict16x16_ppc(src_ptr, src_pixels_per_line, xoffset, yoffset, + dst_ptr, dst_pitch); +} + +void vp8_bilinear_predict8x8_altivec(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch) { + bilinear_predict8x8_ppc(src_ptr, src_pixels_per_line, xoffset, yoffset, + dst_ptr, dst_pitch); +} + +void vp8_bilinear_predict8x4_altivec(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch) { + bilinear_predict8x4_ppc(src_ptr, src_pixels_per_line, xoffset, yoffset, + dst_ptr, dst_pitch); +} + +void vp8_bilinear_predict4x4_altivec(unsigned char *src_ptr, + int src_pixels_per_line, int xoffset, + int yoffset, unsigned char *dst_ptr, + int dst_pitch) { + bilinear_predict4x4_ppc(src_ptr, src_pixels_per_line, xoffset, yoffset, + dst_ptr, dst_pitch); +} diff --git a/vp8/common/rtcd_defs.pl b/vp8/common/rtcd_defs.pl index bfc569da3..38bec3a76 100644 --- a/vp8/common/rtcd_defs.pl +++ b/vp8/common/rtcd_defs.pl @@ -140,28 +140,28 @@ # Subpixel # add_proto qw/void vp8_sixtap_predict16x16/, "unsigned char *src_ptr, int src_pixels_per_line, int xoffset, int yoffset, unsigned char *dst_ptr, int dst_pitch"; -specialize qw/vp8_sixtap_predict16x16 sse2 ssse3 neon dspr2 msa mmi lsx/; +specialize qw/vp8_sixtap_predict16x16 altivec sse2 ssse3 neon dspr2 msa mmi lsx/; add_proto qw/void vp8_sixtap_predict8x8/, "unsigned char *src_ptr, int src_pixels_per_line, int xoffset, int yoffset, unsigned char *dst_ptr, int dst_pitch"; -specialize qw/vp8_sixtap_predict8x8 sse2 ssse3 neon dspr2 msa mmi lsx/; +specialize qw/vp8_sixtap_predict8x8 altivec sse2 ssse3 neon dspr2 msa mmi lsx/; add_proto qw/void vp8_sixtap_predict8x4/, "unsigned char *src_ptr, int src_pixels_per_line, int xoffset, int yoffset, unsigned char *dst_ptr, int dst_pitch"; -specialize qw/vp8_sixtap_predict8x4 sse2 ssse3 neon dspr2 msa mmi/; +specialize qw/vp8_sixtap_predict8x4 altivec sse2 ssse3 neon dspr2 msa mmi/; add_proto qw/void vp8_sixtap_predict4x4/, "unsigned char *src_ptr, int src_pixels_per_line, int xoffset, int yoffset, unsigned char *dst_ptr, int dst_pitch"; -specialize qw/vp8_sixtap_predict4x4 mmx ssse3 neon dspr2 msa mmi lsx/; +specialize qw/vp8_sixtap_predict4x4 altivec mmx ssse3 neon dspr2 msa mmi lsx/; add_proto qw/void vp8_bilinear_predict16x16/, "unsigned char *src_ptr, int src_pixels_per_line, int xoffset, int yoffset, unsigned char *dst_ptr, int dst_pitch"; -specialize qw/vp8_bilinear_predict16x16 sse2 ssse3 neon msa/; +specialize qw/vp8_bilinear_predict16x16 altivec sse2 ssse3 neon msa/; add_proto qw/void vp8_bilinear_predict8x8/, "unsigned char *src_ptr, int src_pixels_per_line, int xoffset, int yoffset, unsigned char *dst_ptr, int dst_pitch"; -specialize qw/vp8_bilinear_predict8x8 sse2 ssse3 neon msa/; +specialize qw/vp8_bilinear_predict8x8 altivec sse2 ssse3 neon msa/; add_proto qw/void vp8_bilinear_predict8x4/, "unsigned char *src_ptr, int src_pixels_per_line, int xoffset, int yoffset, unsigned char *dst_ptr, int dst_pitch"; -specialize qw/vp8_bilinear_predict8x4 sse2 neon msa/; +specialize qw/vp8_bilinear_predict8x4 altivec sse2 neon msa/; add_proto qw/void vp8_bilinear_predict4x4/, "unsigned char *src_ptr, int src_pixels_per_line, int xoffset, int yoffset, unsigned char *dst_ptr, int dst_pitch"; -specialize qw/vp8_bilinear_predict4x4 sse2 neon msa/; +specialize qw/vp8_bilinear_predict4x4 altivec sse2 neon msa/; # # Encoder functions below this point. diff --git a/vp8/vp8_common.mk b/vp8/vp8_common.mk index 7f118937c..3ecc3559d 100644 --- a/vp8/vp8_common.mk +++ b/vp8/vp8_common.mk @@ -153,6 +153,7 @@ VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/sixtappredict_neon.c VP8_COMMON_SRCS-$(HAVE_ALTIVEC) += common/ppc/idct_altivec.c VP8_COMMON_SRCS-$(HAVE_ALTIVEC) += common/ppc/copy_altivec.c VP8_COMMON_SRCS-$(HAVE_ALTIVEC) += common/ppc/loopfilter_altivec.c +VP8_COMMON_SRCS-$(HAVE_ALTIVEC) += common/ppc/filter_altivec_wrap.c VP8_COMMON_SRCS-$(HAVE_ALTIVEC) += common/ppc/loopfilter_filters_altivec.S VP8_COMMON_SRCS-$(HAVE_ALTIVEC) += common/ppc/filter_altivec.S VP8_COMMON_SRCS-$(HAVE_ALTIVEC) += common/ppc/filter_bilinear_altivec.S -- 2.43.0