From 6e71acf07b1aced39eb01a5ed858bcde4b77b454 Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <barracuda@macos-powerpc.org>
Date: Fri, 24 Jul 2026 07:05:35 +0000
Subject: [PATCH 20/38] avutil/ppc: add directly-selectable top-level av_tx FFT
 codelets (F1)

The AltiVec FFT codelets were registered only as FF_TX_PRESHUFFLE
"_ns" building blocks, so a bare av_tx_init() always resolved to the
generic C wrapper with the AltiVec kernel one level down as a
sub-transform. That works, but is invisible to checkasm (which
compares top-level function pointers) and pays a wrapper indirection.

Mirror x86's TX_DEF dual-registration pattern: alongside each fftN_ns
entry, register a plain fftN top-level codelet (out-of-place, aligned,
no PRESHUFFLE) that gathers the input through the split-radix revtab
into dst and runs the in-register kernel in place. In-place requests
and MDCT wrappers keep selecting the _ns codelets as sub-transforms,
as before.

Verified under qemu -cpu 7400: av_tx_init() for a plain out-of-place
FLOAT_FFT now selects fftN_altivec at the top level (transform-tree
debug output), in-place/MDCT trees are unchanged; the AltiVec-vs-C
end-to-end comparison passes for FFT lens 4..131072 fwd+inv and iMDCT
32..8192; checkasm av_tx now shows a real ALTIVEC: block and passes
across 3 seeds; full checkasm suite 537/537 (was 530, +7
newly-dispatching float_fft lengths).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011BUPvhbJmFUU7zpuZf36JZ
---
 libavutil/ppc/tx_float_altivec.c | 68 ++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/libavutil/ppc/tx_float_altivec.c b/libavutil/ppc/tx_float_altivec.c
index a892012..bbc3c86 100644
--- a/libavutil/ppc/tx_float_altivec.c
+++ b/libavutil/ppc/tx_float_altivec.c
@@ -359,6 +359,58 @@ DECL_SR_CODELET(32768)
 DECL_SR_CODELET(65536)
 DECL_SR_CODELET(131072)
 
+/* Directly-selectable top-level codelets (same dual registration as x86's
+ * TX_DEF pattern: plain fftN alongside the fftN_ns building blocks above).
+ * They gather the input through the split-radix revtab (generated by
+ * sr_codelet_init) into dst and run the in-register kernel in place.
+ * Out-of-place only; in-place requests keep going through the generic C
+ * wrapper, which then picks the _ns codelets as its sub-transform. With
+ * these, a bare av_tx_init() resolves to a distinct AltiVec top-level
+ * function pointer -- which is also what checkasm's av_tx test compares,
+ * so the AltiVec path becomes directly testable. */
+#define DECL_SR_CODELET_TOP(n)                                          \
+static void ff_tx_fft##n##_altivec(AVTXContext *s, void *_dst,          \
+                                   void *_src, ptrdiff_t stride)        \
+{                                                                       \
+    TXComplex *src = _src;                                              \
+    TXComplex *dst = _dst;                                              \
+    const int *map = s->map;                                            \
+    for (int i = 0; i < n; i++)                                         \
+        dst[i] = src[map[i]];                                           \
+    fft##n##_av(dst, dst);                                              \
+}                                                                       \
+                                                                        \
+static const FFTXCodelet ff_tx_fft##n##_def_altivec = {                 \
+    .name       = NULL_IF_CONFIG_SMALL("fft" #n "_altivec"),            \
+    .function   = ff_tx_fft##n##_altivec,                               \
+    .type       = AV_TX_FLOAT_FFT,                                      \
+    .flags      = FF_TX_OUT_OF_PLACE | FF_TX_ALIGNED,                   \
+    .factors[0] = 2,                                                    \
+    .nb_factors = 1,                                                    \
+    .min_len    = n,                                                    \
+    .max_len    = n,                                                    \
+    .init       = sr_codelet_init,                                      \
+    .cpu_flags  = AV_CPU_FLAG_ALTIVEC,                                  \
+    .prio       = FF_TX_PRIO_BASE + 128,                                \
+};
+
+DECL_SR_CODELET_TOP(4)
+DECL_SR_CODELET_TOP(8)
+DECL_SR_CODELET_TOP(16)
+DECL_SR_CODELET_TOP(32)
+DECL_SR_CODELET_TOP(64)
+DECL_SR_CODELET_TOP(128)
+DECL_SR_CODELET_TOP(256)
+DECL_SR_CODELET_TOP(512)
+DECL_SR_CODELET_TOP(1024)
+DECL_SR_CODELET_TOP(2048)
+DECL_SR_CODELET_TOP(4096)
+DECL_SR_CODELET_TOP(8192)
+DECL_SR_CODELET_TOP(16384)
+DECL_SR_CODELET_TOP(32768)
+DECL_SR_CODELET_TOP(65536)
+DECL_SR_CODELET_TOP(131072)
+
 const FFTXCodelet * const ff_tx_codelet_list_float_ppc[] = {
     &ff_tx_fft4_ns_def_altivec,
     &ff_tx_fft8_ns_def_altivec,
@@ -376,6 +428,22 @@ const FFTXCodelet * const ff_tx_codelet_list_float_ppc[] = {
     &ff_tx_fft32768_ns_def_altivec,
     &ff_tx_fft65536_ns_def_altivec,
     &ff_tx_fft131072_ns_def_altivec,
+    &ff_tx_fft4_def_altivec,
+    &ff_tx_fft8_def_altivec,
+    &ff_tx_fft16_def_altivec,
+    &ff_tx_fft32_def_altivec,
+    &ff_tx_fft64_def_altivec,
+    &ff_tx_fft128_def_altivec,
+    &ff_tx_fft256_def_altivec,
+    &ff_tx_fft512_def_altivec,
+    &ff_tx_fft1024_def_altivec,
+    &ff_tx_fft2048_def_altivec,
+    &ff_tx_fft4096_def_altivec,
+    &ff_tx_fft8192_def_altivec,
+    &ff_tx_fft16384_def_altivec,
+    &ff_tx_fft32768_def_altivec,
+    &ff_tx_fft65536_def_altivec,
+    &ff_tx_fft131072_def_altivec,
     NULL,
 };
 
-- 
2.43.0

