Files
daedalus-fourier/CMakeLists.txt
T
marfrit be7ff5587c Cycle 2 (deblocking) Phase 1-3: M3'' = 48.285 Medge/s baseline
Second kernel candidate per phase7_M4.md verdict "next-kernel cycle
authorised". VP9 4-tap inner loop filter, horizontal direction,
8-pixel edge (libavcodec ff_vp9_loop_filter_h_4_8_neon as baseline).
Different workload shape from IDCT - boundary streaming, lighter
compute per unit, per-row conditionals - tests whether QPU win
generalises.

docs/k2_deblock_phase1.md - goal-setting. Same R-band decision rules
as cycle 1 (phase1.md), with the cycle-1 calibration adjustment:
ORANGE band is no longer auto-close because M4 showed mixed > pure
CPU even at modest R when CPU bandwidth-saturates.

docs/k2_deblock_phase2.md - situation analysis. C reference already
in vendored snapshot (vp9dsp_template.c:1780-1898). Fetched
vp9lpf_neon.S fresh (1334 lines, LGPL-2.1+, FFmpeg n7.1.3 pin,
SHA-256 384e49e7...). PROVENANCE.md updated.

docs/k2_deblock_phase3.md - NEON baseline:

  M1''_c bit-exact     100.0000 % (10000 random edges)
  M3'' throughput      48.285 Medge/s  (20.7 ns/edge, single A76)
  per-frame 1080p-eq   748 FPS (worst case 64 530 edges/frame)
  cycles/edge          ~58 (=20.7ns x 2.8GHz), ~7 cycles/row

LPF is 5.9x faster per-unit than IDCT M3 (20.7 vs 122 ns), so the
QPU break-even point moves down. Predicted R''_v1 band ~0.5-0.9
- frame-level batching amortises the same 33us dispatch overhead;
workload becomes bandwidth-bound rather than compute-bound
(~5.7 MB/frame traffic at 64 530 edges x ~88 B per edge).

New artifacts:
- tests/vp9_lpf_ref.c    - standalone bit-exact C ref (8-bit, wd=4
                           inner only; clean transcription)
- tests/bench_neon_lpf.c - M1''_c gate + M3'' time-based bench
                           (5s window, edge-content-biased RNG for
                           realistic fm/hev hit rates)
- external/ffmpeg-snapshot/libavcodec/aarch64/vp9lpf_neon.S
- CMakeLists.txt updated with bench_neon_lpf target

Phase 4 next: plan the QPU LPF compute shader. Cycle 1's phase4.md
+ phase5.md + phase7.md learnings apply directly - bake in the v4
winning patterns from the start (WG=256, edges-per-subgroup
pattern adapted from blocks, uint8_t dst SSBO, oob flag, unrolled
writes).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 12:28:57 +00:00

156 lines
5.5 KiB
CMake

# daedalus-fourier — Phase 3 baseline + (later) Phase 6 implementation.
#
# Builds:
# bench_neon_idct — NEON throughput baseline (Phase 3 M3) +
# bit-exact correctness gate (Phase 1 M1).
# bench_vulkan_dispatch — Vulkan compute dispatch-overhead baseline (M5).
#
# Linkage note: bench_neon_idct statically links the vendored
# FFmpeg n7.1.3 NEON snapshot (LGPL-2.1+); see
# external/ffmpeg-snapshot/PROVENANCE.md.
cmake_minimum_required(VERSION 3.20)
project(daedalus-fourier C ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
if (NOT CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
message(FATAL_ERROR
"daedalus-fourier targets aarch64 (Pi 5 / BCM2712). "
"Cross-compile not yet wired.")
endif()
add_compile_options(-Wall -Wextra -Wno-unused-parameter)
# ---- Vendored FFmpeg snapshot (LGPL-2.1+) -----------------------------------
set(FFSNAP ${CMAKE_SOURCE_DIR}/external/ffmpeg-snapshot)
# Assembly preamble (config.h shim + FFmpeg's asm helpers) used by the
# vendored .S file. -I flags expose:
# - FFSNAP/ so `#include "config.h"` finds our shim
# - FFSNAP/libavcodec/aarch64/ so `#include "neon.S"` finds the helper
# - FFSNAP/ so `#include "libavutil/aarch64/asm.S"`
# resolves against the vendored copy
set(FFASM_FLAGS
-I${FFSNAP}
-I${FFSNAP}/libavcodec/aarch64
-I${FFSNAP}
)
set(FFASM_SOURCES
${FFSNAP}/libavcodec/aarch64/vp9itxfm_neon.S
)
# Cycle 2 — VP9 loop filter NEON source (vendored 2026-05-18).
set(FFASM_LPF_SOURCES
${FFSNAP}/libavcodec/aarch64/vp9lpf_neon.S
)
set_source_files_properties(${FFASM_LPF_SOURCES} PROPERTIES
COMPILE_OPTIONS "${FFASM_FLAGS}"
LANGUAGE ASM)
# Tell CMake/gas to preprocess .S sources.
set_source_files_properties(${FFASM_SOURCES} PROPERTIES
COMPILE_OPTIONS "${FFASM_FLAGS}"
LANGUAGE ASM)
# ---- NEON baseline microbenches --------------------------------------------
add_executable(bench_neon_idct
tests/bench_neon_idct.c
tests/vp9_idct8_ref.c
${FFASM_SOURCES}
)
target_compile_options(bench_neon_idct PRIVATE -O3 -march=armv8-a+simd)
# Cycle 2 — VP9 loop filter NEON baseline.
add_executable(bench_neon_lpf
tests/bench_neon_lpf.c
tests/vp9_lpf_ref.c
${FFASM_LPF_SOURCES}
)
target_compile_options(bench_neon_lpf PRIVATE -O3 -march=armv8-a+simd)
# bench_neon_idct doesn't need vulkan/drm — pure CPU baseline.
# ---- Vulkan dispatch-overhead microbench (next chunk) ----------------------
# Stub: written in a follow-up step. Toggle ON with -DDAEDALUS_BUILD_VULKAN=ON
# once tests/bench_vulkan_dispatch.c exists.
option(DAEDALUS_BUILD_VULKAN "Build Vulkan compute-dispatch microbench" ON)
if (DAEDALUS_BUILD_VULKAN)
find_package(Vulkan REQUIRED)
# Compile GLSL compute shaders to SPIR-V via glslangValidator.
# The binary loads them at runtime from the build dir (cwd-relative).
find_program(GLSLANG_VALIDATOR
NAMES glslangValidator glslang
REQUIRED)
set(NOOP_SPV ${CMAKE_BINARY_DIR}/noop.spv)
add_custom_command(
OUTPUT ${NOOP_SPV}
COMMAND ${GLSLANG_VALIDATOR} -V -o ${NOOP_SPV}
${CMAKE_SOURCE_DIR}/tests/shaders/noop.comp
DEPENDS ${CMAKE_SOURCE_DIR}/tests/shaders/noop.comp
COMMENT "glslang: noop.comp -> noop.spv"
VERBATIM
)
set(IDCT8_SPV ${CMAKE_BINARY_DIR}/v3d_idct8.spv)
add_custom_command(
OUTPUT ${IDCT8_SPV}
COMMAND ${GLSLANG_VALIDATOR} -V --target-env vulkan1.3
-o ${IDCT8_SPV}
${CMAKE_SOURCE_DIR}/src/v3d_idct8.comp
DEPENDS ${CMAKE_SOURCE_DIR}/src/v3d_idct8.comp
COMMENT "glslang: v3d_idct8.comp -> v3d_idct8.spv"
VERBATIM
)
add_custom_target(daedalus_shaders ALL DEPENDS ${NOOP_SPV} ${IDCT8_SPV})
# v3d_runner — reusable Vulkan plumbing.
add_library(v3d_runner STATIC src/v3d_runner.c)
target_include_directories(v3d_runner PUBLIC src)
target_link_libraries(v3d_runner PUBLIC Vulkan::Vulkan)
target_compile_options(v3d_runner PRIVATE -O2)
add_executable(bench_vulkan_dispatch tests/bench_vulkan_dispatch.c)
add_dependencies(bench_vulkan_dispatch daedalus_shaders)
target_link_libraries(bench_vulkan_dispatch PRIVATE Vulkan::Vulkan)
target_compile_options(bench_vulkan_dispatch PRIVATE -O2)
add_executable(bench_v3d_idct
tests/bench_v3d_idct.c
tests/vp9_idct8_ref.c
)
add_dependencies(bench_v3d_idct daedalus_shaders)
target_link_libraries(bench_v3d_idct PRIVATE v3d_runner Vulkan::Vulkan)
target_compile_options(bench_v3d_idct PRIVATE -O2)
# M4 — concurrent CPU(NEON) + QPU bench. Links the FFmpeg NEON
# snapshot so we can run real NEON kernels on pinned CPU cores
# while the QPU runs its dispatch loop concurrently.
add_executable(bench_concurrent
tests/bench_concurrent.c
${FFASM_SOURCES}
)
add_dependencies(bench_concurrent daedalus_shaders)
target_link_libraries(bench_concurrent PRIVATE v3d_runner Vulkan::Vulkan pthread)
target_compile_options(bench_concurrent PRIVATE -O3 -march=armv8-a+simd)
endif()
# ---- Summary ----------------------------------------------------------------
message(STATUS "daedalus-fourier build configured for ${CMAKE_SYSTEM_PROCESSOR}")
message(STATUS " FFmpeg snapshot: ${FFSNAP}")
message(STATUS " Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS " Targets: bench_neon_idct"
"$<$<BOOL:${DAEDALUS_BUILD_VULKAN}>:; bench_vulkan_dispatch>")