# Macrostep 05 — GPU resources and 2-D FFT proof ## Objective Build a narrow, safe GPU layer under the raylib context and prove both selectable FFT algorithms against CPU oracles: the standard default and retained `LegacyPackedUnitary`. Do not implement the complete simulator until resource safety, stage fidelity, and numerical parity are demonstrated. ## Dependencies Macrosteps 00–04 complete. ## Phase 5.1 — Capability and backend policy ### Substep 5.1.1 — Capability report Probe and record: - OpenGL and GLSL versions; - maximum 2-D texture size, texture units, and draw buffers; - `R32F` and `RG32F` texture/render-target support; - framebuffer completeness; - timer-query availability; - estimated resource budget. `Backend::Auto` with `FftAlgorithm::Standard` falls back to CPU with a visible explanation. `LegacyPackedUnitary` is an explicit GPU-only request; unsupported capabilities or shapes fail clearly and never silently substitute the standard algorithm. ### Substep 5.1.2 — Portability target Primary path: desktop OpenGL 3.3 core-compatible GLSL. Do not copy legacy compatibility constructs (`gl_TexCoord`, `ftransform`, `gl_FragColor`, implicit shader versions). GLES/Web is a later secondary target. ## Phase 5.2 — Isolated resource layer ### Substep 5.2.1 — Unsafe boundary Place all raw OpenGL/`rlgl` operations in `src/gpu/resource/`. Public wrappers are RAII-managed, non-cloneable owners of: - texture IDs and format/extent metadata; - framebuffers and attachment ownership; - shader programs and uniform locations; - fullscreen pass geometry; - optional timer queries. Every creation checks errors/completeness. Every custom pass flushes/restores raylib state according to a documented protocol. ### Substep 5.2.2 — Ping-pong discipline Make sampling a current render target impossible through the safe pass API. A pass declares read textures and a distinct write target; debug mode asserts no alias. This prevents legacy feedback-loop defects across all later variants. ### Substep 5.2.3 — Shader assets Embed release shaders and fail shader compilation/link with source name plus complete log. Support explicit development overrides only. Add shader preprocessing for shared curve/palette code if it produces deterministic, debuggable output. ## Phase 5.3 — GPU data layouts Use 2-D textures as the portable baseline: - scalar fields: `R32F`; - standard full-complex fields: `RG32F` at logical extent; - legacy packed fields: `RG32F` at the historical half-x packed extent; - 1-D later: one row; - 2-D: direct layout; - 3-D later: tiled z-slice atlas. Define exact texel-center and logical-to-physical mappings. Compute shaders and native 3-D render targets may be optional optimizations, never the only correctness path. ## Phase 5.4 — Standard 2-D FFT implementation ### Substep 5.4.1 — Standard algorithm spike Select Stockham autosort or a conventional staged radix-2 butterfly after comparing pass count, addressing clarity, and driver portability. Use integer `texelFetch`; never rely on filtering or normalized-coordinate rounding. ### Substep 5.4.2 — Transform passes Implement: - real-to-complex copy; - x and y forward stages; - x and y inverse stages; - exactly one `1/(Nx·Ny)` inverse scale; - round-trip readback harness. Cache twiddles/plans by shape. Require power-of-two GPU extents initially and report this distinction from the more flexible CPU backend. ### Substep 5.4.3 — Spectral convolution Upload or generate kernel spectra, multiply state spectrum by disk/ring spectra, inverse transform, and normalize by sampled sums consistent with CPU convention. Reuse the state forward FFT for both kernels. ## Phase 5.5 — Legacy packed-unitary 2-D FFT ### Substep 5.5.1 — CPU stage oracle Implement a small, clear CPU oracle for adjacent-real packing, packed-spectrum conversion, historical plan entries, unitary butterflies, and inverse unpacking. It exists for fixtures and diagnosis, not as a production CPU backend. ### Substep 5.5.2 — Modern GPU port of the historical algorithm Retain the algorithmic behavior while rewriting its infrastructure: - adjacent x samples packed into real/imaginary components; - historical half-x complex layout and conjugate/Nyquist handling; - bit-reversal and twiddle plan stages for x/y; - forward/inverse unitary scaling at each stage; - ping-pong FFT scratch textures; - convolution multiplier `sqrt(Nx·Ny)/kernel_sum`. Use GLSL 330, integer texel addressing, embedded shaders, checked resources, and the common safe pass API. Do not copy compatibility-profile GLSL or resource hazards. ### Substep 5.5.3 — Algorithm-specific constraints Require power-of-two extents and enough texture/FBO resources. Keep standard and legacy plans, spectra, and scratch caches separate. Changing `FftAlgorithm` is a cold transactional rebuild and invalidates integration history. ## Phase 5.6 — Numerical proof harness For each algorithm and test field, read back explicit stages: - input complex copy; - forward spectrum; - inverse round trip; - disk/ring spectral products; - `M` and `N`. Compare to CPU with max absolute, mean absolute, and L2 error. Include zero, constant, impulse, checkerboard, random seeded, and asymmetric patterns at multiple small powers of two. Initial targets: - standard round-trip max error `≤1e-4`; - standard convolution max error `≤2e-4` on agreed fixtures; - legacy packed stage outputs match the CPU stage fixtures within documented `f32` tolerances; - legacy final convolution agrees with direct/standard CPU convolution within `2e-4` on agreed fixtures; - constant-field density error is small enough to preserve the documented tolerance. Tolerances must be measured and recorded per GPU/driver class before broadening; never hide systematic normalization errors behind a loose bound. ## Phase 5.7 — Lifecycle and failure testing - Recreate FFT resources repeatedly across sizes. - Simulate allocation/shader failures and preserve the CPU backend. - Check for GL errors and incomplete FBOs in debug validation mode. - Verify no resource growth after repeated switches. - Confirm no synchronous readback in the normal frame path. - Preflight memory estimates before allocation and retain the prior valid backend on failure. ## Deliverables - GPU capability report and automatic fallback policy. - Auditable unsafe/RAII resource layer. - Validated standard and legacy packed-unitary 2-D GPU FFT/convolution proofs. - Legacy packing/plan/unitary CPU stage oracle. - Per-algorithm stage-comparison harness and initial GPU benchmark metadata. ## Exit gate - Standard CPU/GPU round trip and convolution tolerances pass on the reference environment. - Legacy packing, plans, scaling, round trip, spectra, and convolution pass their stage/final tolerances. - Resource alias checks prevent read/write feedback. - Shader and allocation failures are actionable and non-destructive. - Repeated recreation shows no incomplete framebuffer or resource leak. - GPU simulation work does not begin until the 2-D proof is stable.