From e538efd129685e7f62b465109a916cbee3c5dbc9 Mon Sep 17 00:00:00 2001
From: Developer <dev@localhost>
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) <noreply@anthropic.com>
---
 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

