Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
gpu_compute.hpp
Go to the documentation of this file.
1#pragma once
2
3#if defined(PULP_GPU_RUNTIME)
4// This build's device layer is gpu-runtime's (tools/cmake/PulpGpuRuntime.cmake):
5// these are its types and functions under their Pulp names, so a Pulp object
6// and a gpu-runtime object are one and the same.
7#include <gpu_runtime/gpu_compute.hpp>
8// The Pulp names of the types it uses, as the header always provided.
10#ifdef PULP_BENCHMARK
12#endif
13
14namespace pulp::render {
15using gpu_runtime::GpuCompute;
16} // namespace pulp::render
17#else // !PULP_GPU_RUNTIME
18
20
21#include <atomic>
22#include <chrono>
23#include <cstddef>
24#include <cstdint>
25#include <functional>
26#include <memory>
27#include <string>
28#include <vector>
29
30#ifdef PULP_BENCHMARK
32#endif
33
34namespace pulp::render {
35
49public:
50 virtual ~GpuCompute() = default;
51
54 virtual bool initialize_from_surface(GpuSurface& surface) = 0;
55
64 virtual bool initialize_standalone() = 0;
65
80 virtual bool initialize_from_device(void* wgpu_device) = 0;
81
82 bool is_initialized() const {
83 return initialized_.load(std::memory_order_acquire);
84 }
85
91 virtual bool device_lost() const = 0;
92
96 virtual std::uint64_t device_generation() const {
97 return 0;
98 }
99
109 virtual void notify_device_lost() = 0;
110
111 virtual void notify_device_lost(std::uint64_t generation) {
112 if (generation == device_generation())
114 }
115
123 virtual void post_device_lost(std::uint64_t generation) {
124 notify_device_lost(generation);
125 }
126
127 // ── Compute operations ──────────────────────────────────────────────
128
133 virtual bool compute_magnitude(const float* complex_pairs, float* magnitudes,
134 uint32_t num_bins) = 0;
135
139 virtual bool complex_multiply(const float* a, const float* b, float* result,
140 uint32_t count) = 0;
141
145 virtual bool batch_magnitude(const float* complex_frames, float* magnitude_frames,
146 uint32_t bins_per_frame, uint32_t num_frames) = 0;
147
148 // ── FFT ──────────────────────────────────────────────────────────────
149 //
150 // GPU radix-2 FFT (Stockham auto-sort, no bit-reversal pass). Operates on
151 // interleaved complex data [re0, im0, re1, im1, ...] of length `n` complex
152 // values (2*n floats in and out). `n` must be a power of two and small
153 // enough that 2*n*sizeof(float) fits the device storage-buffer limit.
154 // Not for the audio callback — these build/cache a per-`n` plan and block
155 // on readback. Validated against a direct DFT and the CPU FFT
156 // (magnitude parity + round-trip identity); see test/test_gpu_compute.cpp.
157 //
158 // Thread-safety: like the rest of GpuCompute, a single instance is NOT
159 // safe for concurrent use — call all methods from one thread (e.g. the
160 // GPU worker). The plan/pipeline caches are unsynchronized by design.
161
165 virtual bool fft_forward(const float* complex_in, float* complex_out, uint32_t n) = 0;
166
170 virtual bool fft_inverse(const float* complex_in, float* complex_out, uint32_t n) = 0;
171
179 virtual bool fft_forward_timed(const float* complex_in, float* complex_out,
180 uint32_t n, double* gpu_compute_us) = 0;
181
182 // ── GPU-resident convolution ───────────────────────────────────────────
183 //
184 // Fused FFT convolution that keeps intermediates GPU-resident: forward FFT
185 // → complex-multiply by a resident IR spectrum → inverse FFT (1/N
186 // normalized), all encoded into ONE command buffer with ONE readback
187 // (vs three readbacks for fft_forward + complex_multiply + fft_inverse).
188 // Not real-time-safe (still blocks on the single readback) but the
189 // amortizable building block toward a real-time GPU convolver.
190
195 virtual bool prepare_convolution(uint32_t n, const float* ir_spec) = 0;
196
200 virtual bool convolve(const float* in_complex, float* out_complex, uint32_t n) = 0;
201
207 virtual bool prepare_convolution_batch(uint32_t n, const float* ir_spec,
208 uint32_t batch) = 0;
209 virtual bool convolve_batch(const float* in_complex, float* out_complex,
210 uint32_t n, uint32_t batch) = 0;
211
212 // ── Multi-IR convolution (one input → many distinct IRs → stereo) ───────
213 //
214 // The mass-parallel regime: convolve ONE input block against `num_ir`
215 // DISTINCT IR spectra ("rooms"/"taps") in ONE submit, then reduce the
216 // num_ir results to a stereo pair on the GPU with per-room pan weights —
217 // so only one stereo block (2*n floats) is read back regardless of num_ir.
218 // The forward FFT runs once and is shared across all rooms; each room gets
219 // its own complex-multiply and inverse FFT, all batched. On the CPU this is
220 // num_ir independent convolutions; on the GPU it is one batched job — the
221 // structural win that scales past real time on the CPU while the GPU holds.
222 // Not real-time-safe (blocks on the single readback); the amortizable
223 // building block for a GPU multi-room convolution reverb.
224
229 virtual bool prepare_multi_convolution(uint32_t n, const float* ir_specs,
230 uint32_t num_ir) = 0;
231
238 virtual bool multi_convolve(const float* in_complex, const float* pan_l,
239 const float* pan_r, float* out_lr, uint32_t n,
240 uint32_t num_ir) = 0;
241
251 virtual bool multi_convolve_timed(const float* in_complex, const float* pan_l,
252 const float* pan_r, float* out_lr, uint32_t n,
253 uint32_t num_ir, double* gpu_compute_us) = 0;
254 // ── Partitioned-FDL multi-convolution (roofline #1) ──────────────────────
255 //
256 // The same one-input → many-IRs → stereo result, but with the IR split into
257 // `num_part` block-size partitions so the FFT stays at the small fixed block
258 // size (n = 2*block) instead of growing to next_pow2(block + IR_len). The
259 // convolution becomes a sum of spectral products over a delay line of recent
260 // input spectra — the algorithm signal::PartitionedConvolver uses on the CPU.
261 // This trades one giant FFT for P small-FFT-equivalent MAC rows, which is the
262 // removable waste multi_convolve_timed measured. Not real-time-safe (blocks
263 // on the readback); the amortizable building block for a real-time GPU
264 // multi-room convolver.
265
272 virtual bool prepare_multi_fdl(uint32_t n, const float* ir_part_specs,
273 uint32_t num_ir, uint32_t num_part) = 0;
274
282 virtual bool multi_fdl_convolve(const float* in_block, const float* pan_l,
283 const float* pan_r, float* out_block,
284 uint32_t n, uint32_t num_ir) = 0;
285
286 // ── Multi-layer spectral stack (N resident layer-spectra → one frame) ───
287 //
288 // The spectral analogue of the multi-IR regime: keep `num_layers` frozen
289 // spectral frames (each a magnitude array + a persistent phase array)
290 // RESIDENT on the GPU, and per hop process EVERY layer's bins in ONE batched
291 // submit — advance each layer's phase by its nominal per-hop frequency, blur
292 // (smear) each layer's magnitude across frequency, then weighted-sum all
293 // layers into one combined spectrum and inverse-FFT it to a single real
294 // frame. Only that one frame (2n floats) is read back per hop, regardless of
295 // how many layers there are. On the CPU this is num_layers × (per-bin smear
296 // + transcendentals), serial; on the GPU it is one batch parallel across all
297 // n bins — the structural win that scales past real time on the CPU at high
298 // num_layers while the GPU holds. Not real-time-safe (blocks on the single
299 // readback); driven from the GPU audio worker / offline.
300
309 virtual bool prepare_spectral_stack(uint32_t n, uint32_t hop,
310 uint32_t num_layers) = 0;
311
317 virtual bool spectral_stack_set_layer(uint32_t layer, const float* mag,
318 const float* phase, uint32_t n,
319 uint32_t num_layers) = 0;
320
328 virtual bool spectral_stack_render(const float* layer_weights,
329 uint32_t num_layers, float smear,
330 float jitter, uint32_t rng_seed,
331 float* frame_out, uint32_t n) = 0;
332
333 // ── Linear algebra ─────────────────────────────────────────────────────
334
339 virtual bool matmul(const float* a, const float* b, float* c,
340 uint32_t m, uint32_t k, uint32_t n) = 0;
341
342 // ── Synthesis ──────────────────────────────────────────────────────────
343
350 virtual bool additive_synth(const float* partials, float* out,
351 uint32_t num_partials, uint32_t num_samples,
352 float sample_rate, float t0_samples) = 0;
353
359 virtual bool modal_strike(const float* modes, float* out, uint32_t num_modes,
360 uint32_t num_samples, float sample_rate, float t0_samples) = 0;
361
367 virtual bool granular_cloud(const float* grains, const float* source, float* out,
368 uint32_t num_grains, uint32_t source_len,
369 uint32_t num_samples) = 0;
370
371 // ── Neural inference ────────────────────────────────────────────────────
372
379 virtual bool dense_tanh(const float* input, const float* weights, const float* bias,
380 float* output, uint32_t in_dim, uint32_t out_dim) = 0;
381
382 // ── Fused conv-stack inference (WaveNet-style neural amp) ───────────────
383 //
384 // A stack of gated, dilated, causal 1-D conv layers — the architecture
385 // behind neural-amp captures. The whole block's samples are computed in
386 // PARALLEL (the network is feedforward: output[t] depends on past inputs,
387 // not past outputs) and the entire forward pass runs as successive compute
388 // passes in ONE submit with device-resident activations — so the CPU<->GPU
389 // round-trip is paid ONCE per block, not per layer or per sample. That is
390 // the regime where GPU neural inference beats the CPU, and the win grows
391 // with model size (big captures the CPU can't run in real time stay smooth
392 // on the GPU). Per-sample/per-layer dispatch loses badly and is never used.
393 //
394 // Per-layer weight layout (row-major f32, concatenated for all layers, then
395 // the two global blocks): conv W [2C*C*K] + bias [2C], residual W [C*C] +
396 // bias [C], skip W [C*C] + bias [C]; then once: input W [C] + bias [C], head
397 // W [C] + bias [1]. `channels` = C, `kernel` = K, `dilations` has one entry
398 // per layer. Not real-time-safe (blocks on readback); run on the worker.
399
405 virtual bool prepare_conv_stack(uint32_t channels, uint32_t kernel,
406 const uint32_t* dilations, uint32_t num_layers,
407 const float* weights, uint32_t weights_len,
408 uint32_t block_size, float head_scale) = 0;
409
416 virtual bool conv_stack_forward(const float* in_block, float* out_block,
417 uint32_t block_size) = 0;
418
419 // ── Fused conditioned WaveNet inference (gated dilated conv sequence) ────
420 //
421 // A conditioned WaveNet forward — a sequence of layer-arrays of gated,
422 // dilated, causal 1-D conv layers (van den Oord et al.) — reproduced
423 // GPU-resident and block-parallel. Unlike conv_stack (a single gated layer
424 // stack), this models the full shape: a sequence of layer-arrays, each with
425 // an input rechannel (1x1), dilated causal conv layers that mix in a
426 // separate condition signal (here the raw mono input), Tanh (or gated
427 // tanh·sigmoid) activation, a 1x1 residual, a per-array head accumulator,
428 // and a head rechannel — with the layer output and the head accumulator
429 // chained array→array. The whole block's samples compute in PARALLEL (the
430 // net is feedforward), every pass encodes into ONE submit over
431 // device-resident activations, and only the final mono block is read back —
432 // the round-trip is paid once per block. Dilation history carries across
433 // calls so streaming blocks are continuous. Not real-time-safe (blocks on
434 // the readback); run on the GPU worker / offline. It is the GPU counterpart
435 // to a streaming CPU WaveNet and drives neural waveshaping / amp inference.
436 //
437 // Weight layout (flat f32 blob). Per layer-array, walking the blob:
438 // rechannel W [channels*input_size] (no bias); then per layer: conv W
439 // [Z*channels*kernel] + bias [Z], input_mixin W [Z*condition_size] (no bias),
440 // layer1x1 W [channels*channels] + bias [channels]; then head_rechannel W
441 // [head_size*channels] (+ bias [head_size] if head_bias). After all arrays:
442 // one trailing head_scale scalar. Z = gated ? 2*channels : channels.
443 // Activation is Tanh; the gate is sigmoid.
444
449 uint32_t input_size = 1;
450 uint32_t condition_size = 1;
451 uint32_t channels = 1;
452 uint32_t kernel = 1;
453 uint32_t head_size = 1;
454 uint32_t gated = 0;
455 uint32_t head_bias = 0;
456 const uint32_t* dilations = nullptr;
457 uint32_t num_layers = 0;
458 };
459
477 virtual bool prepare_wavenet(const WavenetLayerArraySpec* arrays, uint32_t num_arrays,
478 const float* weights, uint32_t weights_len,
479 uint32_t block_size, float head_scale,
480 uint32_t instance = 0) = 0;
481
489 virtual bool wavenet_forward(const float* in_block, float* out_block,
490 uint32_t block_size, uint32_t instance = 0) = 0;
491
504 virtual bool prepare_wavenet_group(const WavenetLayerArraySpec* /*arrays*/,
505 uint32_t /*num_arrays*/, const float* const* /*weights*/,
506 uint32_t /*weights_len*/, const float* /*head_scales*/,
507 uint32_t /*count*/, uint32_t /*block_size*/,
508 uint32_t /*group*/) {
509 return false;
510 }
511
519 virtual bool wavenet_forward_group(const float* const* /*in_blocks*/,
520 float* const* /*out_blocks*/, uint32_t /*count*/,
521 uint32_t /*block_size*/, uint32_t /*group*/,
522 double* gpu_busy_us = nullptr) {
523 if (gpu_busy_us)
524 *gpu_busy_us = -1.0;
525 return false;
526 }
527
543 virtual bool wavenet_forward_batch(const float* const* in_blocks, float* const* out_blocks,
544 const uint32_t* instances, uint32_t count,
545 uint32_t block_size, double* gpu_busy_us = nullptr) {
546 if (gpu_busy_us)
547 *gpu_busy_us = -1.0;
548 if (!in_blocks || !out_blocks || !instances || count == 0)
549 return false;
550 for (uint32_t i = 0; i < count; ++i)
551 for (uint32_t j = i + 1; j < count; ++j)
552 if (instances[i] == instances[j])
553 return false;
554 for (uint32_t i = 0; i < count; ++i)
555 if (!wavenet_forward(in_blocks[i], out_blocks[i], block_size, instances[i]))
556 return false;
557 return true;
558 }
559
560 // ── Asynchronous readback (compute_magnitude + convolve_batch) ──────────
561 //
562 // SCOPE FIRST, so nobody reads the contract below as a general promise:
563 // exactly TWO operations have an async variant — compute_magnitude_async()
564 // and convolve_batch_async(). fft_forward, convolve, multi_convolve,
565 // multi_fdl_convolve, spectral_stack_render, matmul, conv_stack_forward and
566 // wavenet_forward ALL still block. This is not a non-blocking mode for
567 // GpuCompute; it is two non-blocking operations plus the completion
568 // machinery the rest of the ops reuse when they are converted.
569 //
570 // Every blocking operation pumps the device event queue until the GPU map
571 // resolves. That is only viable where the caller owns a thread it may stall
572 // (the GPU worker, an offline render). On a single-threaded event loop it is
573 // fatal — spinning starves the very loop that would resolve the map. The
574 // async path submits the dispatch, returns immediately, and hands results
575 // back from poll_readbacks(), so the caller decides when completions run.
576 //
577 // In the browser (Emscripten/emdawnwebgpu) the blocking ops are compiled out
578 // or hard-fail: the async path is the ONLY way to get bytes back from the
579 // GPU there.
580 //
581 // Contract (of the async path):
582 // - An accepted request (non-zero id) completes EXACTLY ONCE, from
583 // poll_readbacks() or from ~GpuCompute(). It never hangs: a request whose
584 // map has not resolved by its deadline completes as `Expired`, which the
585 // caller routes to its miss policy (gpu_audio::MissPolicy) exactly as it
586 // would route a late block.
587 // - Completions fire in submission order.
588 // - `dest` must stay valid until the completion fires. It is written only
589 // on `Success`; a map that lands after an `Expired` completion is
590 // discarded without touching `dest`.
591 // - Not real-time-safe: submit and poll from the GPU worker, never from the
592 // audio callback. The audio thread's contract (never wait on, allocate
593 // for, or synchronize with the GPU) is upheld by the transport, not here.
594
600
602 uint64_t id = 0;
604 uint32_t bytes = 0;
605 };
606
607 using ReadbackCallback = std::function<void(const ReadbackResult&)>;
608
614 virtual uint64_t compute_magnitude_async(const float* complex_pairs,
615 float* magnitudes, uint32_t num_bins,
616 std::chrono::microseconds deadline,
617 ReadbackCallback on_complete) = 0;
618
634 virtual uint64_t convolve_batch_async(const float* in_complex, float* out_complex,
635 uint32_t n, uint32_t batch,
636 std::chrono::microseconds deadline,
637 ReadbackCallback on_complete) = 0;
638
643 virtual std::size_t poll_readbacks() = 0;
644
650 virtual std::size_t readbacks_in_flight() const = 0;
651
658 virtual void set_max_readbacks_in_flight(std::size_t max_in_flight) = 0;
659
666 struct AsyncStats {
667 uint64_t submits = 0;
668 uint64_t map_resolves = 0;
669 uint64_t expired = 0;
670 uint64_t failed = 0;
671 uint64_t write_buffer_calls = 0;
672 uint64_t write_buffer_bytes = 0;
673 uint64_t output_copy_calls = 0;
674 uint64_t output_copy_bytes = 0;
675 uint64_t map_async_calls = 0;
678 };
679
680 virtual AsyncStats async_stats() const = 0;
681
690 virtual void set_async_timing_enabled(bool /*enabled*/) {}
691
696 virtual double last_gpu_busy_ns() const { return 0.0; }
697
698 // ── Kernel-source seam (diagnostic) ──────────────────────────────────
699 //
700 // A named compute pipeline's WGSL is readable, and replaceable before the
701 // pipeline is built. This exists for ONE purpose: to demonstrate that the
702 // WGSL text is causally upstream of the audio samples — mutate the kernel,
703 // hear/measure the mutation in the output. It is what makes the browser
704 // GPU-audio claim checkable rather than asserted. It is a diagnostic seam,
705 // not a plugin/effect API: there is no validation of the replacement beyond
706 // WGSL compilation, and a bad override simply fails pipeline creation.
707
711 virtual const char* kernel_source(const char* label) const = 0;
712
718 virtual bool override_kernel_source(const char* label, const char* wgsl) = 0;
719
720 // ── Capabilities ─────────────────────────────────────────────────────
721
728 bool available = false;
732 std::string backend;
734 std::string adapter_type;
736 std::string name;
738 std::string vendor;
740 std::string architecture;
742 std::string description;
744 uint32_t vendor_id = 0;
746 uint32_t device_id = 0;
747 bool timestamp_query = false; // compute-pass GPU timing available
748 bool shader_f16 = false; // half-precision in WGSL
750 uint64_t max_buffer_size = 0;
754 // Largest power-of-two complex FFT this device's storage-buffer limit
755 // admits, capped at the implementation maximum (0 if unavailable).
756 uint32_t max_fft_size = 0;
757 };
758
760 virtual CapabilityReport capabilities() const = 0;
761
762 // ── Device sharing verification ──────────────────────────────────────
763
765 bool device_obtained = false;
768 bool memory_pressure_ok = false;
769 std::string backend_name; // "Metal", "D3D12", "Vulkan"
770 std::string notes;
771 };
772
777
778 // ── Benchmarking ────────────────────────────────────────────────────
779
781 uint32_t num_elements = 0;
782 double upload_us = 0; // microseconds: CPU → GPU buffer
783 double dispatch_us = 0; // microseconds: compute shader execution
784 double readback_us = 0; // microseconds: GPU buffer → CPU
785 double total_us = 0; // upload + dispatch + readback
786 double cpu_baseline_us = 0; // equivalent CPU operation for comparison
787 bool gpu_faster = false;
788 };
789
792 virtual std::vector<BenchmarkResult> benchmark_magnitude(
793 const std::vector<uint32_t>& sizes, int iterations = 10) = 0;
794
796 virtual std::vector<BenchmarkResult> benchmark_complex_multiply(
797 const std::vector<uint32_t>& sizes, int iterations = 10) = 0;
798
799 static std::unique_ptr<GpuCompute> create();
800
801#ifdef PULP_BENCHMARK
806 virtual void set_bench_counters(bench::PerfCounters* counters) = 0;
807#endif
808
809 protected:
810 std::atomic<bool> initialized_{false};
811};
812
813} // namespace pulp::render
814
815#endif // PULP_GPU_RUNTIME
GPU compute pipeline for non-rendering workloads (e.g.
Definition gpu_compute.hpp:48
virtual std::size_t readbacks_in_flight() const =0
Requests submitted whose completion has not fired yet.
virtual bool multi_convolve(const float *in_complex, const float *pan_l, const float *pan_r, float *out_lr, uint32_t n, uint32_t num_ir)=0
Run the multi-IR convolution for a prepared (n, num_ir).
virtual bool prepare_wavenet(const WavenetLayerArraySpec *arrays, uint32_t num_arrays, const float *weights, uint32_t weights_len, uint32_t block_size, float head_scale, uint32_t instance=0)=0
Build the WaveNet plan: upload weights (flat, length weights_len, head_scale is the trailing scalar p...
virtual bool multi_fdl_convolve(const float *in_block, const float *pan_l, const float *pan_r, float *out_block, uint32_t n, uint32_t num_ir)=0
Run one block of partitioned-FDL convolution for a prepared (n, num_ir).
virtual bool wavenet_forward(const float *in_block, float *out_block, uint32_t block_size, uint32_t instance=0)=0
Run the fused WaveNet forward for one mono block (block_size in/out): the per-array rechannel,...
virtual double last_gpu_busy_ns() const
The most recent GPU-busy time of the async convolution shader, in nanoseconds (EMA-smoothed),...
Definition gpu_compute.hpp:696
virtual bool batch_magnitude(const float *complex_frames, float *magnitude_frames, uint32_t bins_per_frame, uint32_t num_frames)=0
Batch spectral magnitude: processes multiple FFT frames in one dispatch.
virtual void notify_device_lost(std::uint64_t generation)
Definition gpu_compute.hpp:111
virtual bool fft_inverse(const float *complex_in, float *complex_out, uint32_t n)=0
Inverse DFT, normalized by 1/N (so ifft(fft(x)) == x within tolerance).
virtual bool prepare_spectral_stack(uint32_t n, uint32_t hop, uint32_t num_layers)=0
Build the spectral-stack plan for FFT size n (power of two), STFT hop hop, and num_layers resident la...
virtual bool initialize_from_device(void *wgpu_device)=0
Initialize by adopting an already-created WebGPU device.
virtual bool prepare_multi_fdl(uint32_t n, const float *ir_part_specs, uint32_t num_ir, uint32_t num_part)=0
Build the partitioned-FDL plan for n = 2*block.
virtual bool fft_forward_timed(const float *complex_in, float *complex_out, uint32_t n, double *gpu_compute_us)=0
Forward FFT that also reports the TRUE GPU compute time (microseconds) of the transform passes,...
virtual std::vector< BenchmarkResult > benchmark_complex_multiply(const std::vector< uint32_t > &sizes, int iterations=10)=0
Benchmark complex multiply at various sizes.
ReadbackStatus
Definition gpu_compute.hpp:595
@ Expired
Deadline passed before the map resolved; dest untouched.
Definition gpu_compute.hpp:597
@ Success
dest holds the full payload.
Definition gpu_compute.hpp:596
@ Failed
Map error, or the device went away before the map landed.
Definition gpu_compute.hpp:598
virtual uint64_t convolve_batch_async(const float *in_complex, float *out_complex, uint32_t n, uint32_t batch, std::chrono::microseconds deadline, ReadbackCallback on_complete)=0
Non-blocking counterpart of convolve_batch().
virtual bool prepare_convolution(uint32_t n, const float *ir_spec)=0
Build the resident convolution plan for size n (power of two) and upload ir_spec — the interleaved-co...
static std::unique_ptr< GpuCompute > create()
virtual bool initialize_from_surface(GpuSurface &surface)=0
Initialize from an existing GpuSurface's device (device sharing).
virtual std::vector< BenchmarkResult > benchmark_magnitude(const std::vector< uint32_t > &sizes, int iterations=10)=0
Benchmark magnitude computation at various sizes.
virtual AsyncStats async_stats() const =0
virtual bool modal_strike(const float *modes, float *out, uint32_t num_modes, uint32_t num_samples, float sample_rate, float t0_samples)=0
GPU struck modal synthesis: out[s] = Σ_m amp_m·exp(-decay_m·t)· sin(2π·freq_m·t + phase_m),...
virtual bool dense_tanh(const float *input, const float *weights, const float *bias, float *output, uint32_t in_dim, uint32_t out_dim)=0
GPU dense (fully-connected) layer with tanh activation: out[j] = tanh(Σ_i W[j][i]·x[i] + b[j]),...
virtual DeviceSharingReport verify_device_sharing(GpuSurface &surface)=0
Test device sharing between Skia Graphite and compute pipelines.
virtual bool spectral_stack_render(const float *layer_weights, uint32_t num_layers, float smear, float jitter, uint32_t rng_seed, float *frame_out, uint32_t n)=0
Advance + smear + weighted-sum all resident layers and inverse-FFT to one real frame.
virtual bool override_kernel_source(const char *label, const char *wgsl)=0
Replace the WGSL of a named pipeline.
virtual bool convolve(const float *in_complex, float *out_complex, uint32_t n)=0
Run the fused convolution for a prepared n.
virtual bool fft_forward(const float *complex_in, float *complex_out, uint32_t n)=0
Forward DFT: X[k] = sum_n x[n] exp(-2*pi*i*k*n/N).
virtual bool additive_synth(const float *partials, float *out, uint32_t num_partials, uint32_t num_samples, float sample_rate, float t0_samples)=0
GPU additive synthesis: out[s] = Σ_p amp_p · sin(2π·freq_p·(t0+s)/sr + phase_p), one thread per outpu...
virtual bool initialize_standalone()=0
Initialize standalone (creates its own device, no rendering surface).
bool is_initialized() const
Definition gpu_compute.hpp:82
virtual bool convolve_batch(const float *in_complex, float *out_complex, uint32_t n, uint32_t batch)=0
virtual const char * kernel_source(const char *label) const =0
Built-in WGSL for a named pipeline (e.g.
virtual bool compute_magnitude(const float *complex_pairs, float *magnitudes, uint32_t num_bins)=0
Compute magnitude spectrum from interleaved complex float pairs.
virtual bool prepare_convolution_batch(uint32_t n, const float *ir_spec, uint32_t batch)=0
Batched fused convolution: batch independent length-n blocks convolved with the same resident IR,...
std::function< void(const ReadbackResult &)> ReadbackCallback
Definition gpu_compute.hpp:607
virtual uint64_t compute_magnitude_async(const float *complex_pairs, float *magnitudes, uint32_t num_bins, std::chrono::microseconds deadline, ReadbackCallback on_complete)=0
Non-blocking counterpart of compute_magnitude().
virtual bool granular_cloud(const float *grains, const float *source, float *out, uint32_t num_grains, uint32_t source_len, uint32_t num_samples)=0
GPU granular synthesis ("grain cloud"): sum many Hann-windowed, pitch-shifted snippets of source into...
virtual void set_max_readbacks_in_flight(std::size_t max_in_flight)=0
Cap on concurrently in-flight async readbacks (default 4).
virtual bool multi_convolve_timed(const float *in_complex, const float *pan_l, const float *pan_r, float *out_lr, uint32_t n, uint32_t num_ir, double *gpu_compute_us)=0
Same as multi_convolve, but also reports the true GPU-busy time of the fused pass sequence (forward F...
virtual ~GpuCompute()=default
virtual bool prepare_multi_convolution(uint32_t n, const float *ir_specs, uint32_t num_ir)=0
Build the multi-IR plan for size n (power of two) and upload ir_specs — num_ir back-to-back interleav...
virtual CapabilityReport capabilities() const =0
Query the compute device's backend, optional features, and limits.
virtual bool wavenet_forward_batch(const float *const *in_blocks, float *const *out_blocks, const uint32_t *instances, uint32_t count, uint32_t block_size, double *gpu_busy_us=nullptr)
Run one block for count independent WaveNet instances at once.
Definition gpu_compute.hpp:543
virtual void notify_device_lost()=0
Report that an ADOPTED device (initialize_from_device / initialize_from_surface) has been lost.
virtual bool matmul(const float *a, const float *b, float *c, uint32_t m, uint32_t k, uint32_t n)=0
Dense matrix multiply C[M×N] = A[M×K] · B[K×N], all row-major f32.
virtual bool prepare_conv_stack(uint32_t channels, uint32_t kernel, const uint32_t *dilations, uint32_t num_layers, const float *weights, uint32_t weights_len, uint32_t block_size, float head_scale)=0
Build the conv-stack plan: upload weights, allocate the per-layer device-resident activation buffers ...
std::atomic< bool > initialized_
Definition gpu_compute.hpp:810
virtual bool complex_multiply(const float *a, const float *b, float *result, uint32_t count)=0
Element-wise complex multiply (frequency-domain convolution step).
virtual bool conv_stack_forward(const float *in_block, float *out_block, uint32_t block_size)=0
Run the fused forward for one mono block (block_size samples in/out): input projection,...
virtual void post_device_lost(std::uint64_t generation)
Publish a loss from a backend callback without touching readback queues or invoking user completions.
Definition gpu_compute.hpp:123
virtual bool wavenet_forward_group(const float *const *, float *const *, uint32_t, uint32_t, uint32_t, double *gpu_busy_us=nullptr)
Run one block for every instance of a prepared group: in_blocks[i] / out_blocks[i] are instance i's b...
Definition gpu_compute.hpp:519
virtual bool spectral_stack_set_layer(uint32_t layer, const float *mag, const float *phase, uint32_t n, uint32_t num_layers)=0
Upload one captured layer's magnitude (mag, n reals) and initial phase (phase, n reals) into the resi...
virtual std::size_t poll_readbacks()=0
Pump the device event queue once and fire the completions that are ready or past their deadline.
virtual bool prepare_wavenet_group(const WavenetLayerArraySpec *, uint32_t, const float *const *, uint32_t, const float *, uint32_t, uint32_t, uint32_t)
Prepare a group of count independent WaveNet instances that share one shape (arrays) and run as one u...
Definition gpu_compute.hpp:504
virtual bool device_lost() const =0
True once the WebGPU device has been lost.
virtual void set_async_timing_enabled(bool)
Opt the ASYNC convolution path into GPU-busy timing (default OFF).
Definition gpu_compute.hpp:690
virtual std::uint64_t device_generation() const
Monotonic device generation.
Definition gpu_compute.hpp:96
Abstract GPU surface — a presentable rendering target backed by a native window/view.
Definition gpu_surface.hpp:112
Definition gpu_fwd.hpp:31
Benchmark perf counters for copy/upload/readback costs.
Counters for the async path, incremented where the work actually happens: submits at the queue submit...
Definition gpu_compute.hpp:666
uint64_t write_buffer_bytes
Definition gpu_compute.hpp:672
uint64_t write_buffer_calls
Definition gpu_compute.hpp:671
uint64_t mapped_readback_memcpy_bytes
Definition gpu_compute.hpp:677
uint64_t map_async_calls
Definition gpu_compute.hpp:675
uint64_t mapped_readback_memcpy_calls
Definition gpu_compute.hpp:676
uint64_t failed
Definition gpu_compute.hpp:670
uint64_t expired
Definition gpu_compute.hpp:669
uint64_t output_copy_calls
Definition gpu_compute.hpp:673
uint64_t submits
Definition gpu_compute.hpp:667
uint64_t map_resolves
Definition gpu_compute.hpp:668
uint64_t output_copy_bytes
Definition gpu_compute.hpp:674
Definition gpu_compute.hpp:780
double readback_us
Definition gpu_compute.hpp:784
double dispatch_us
Definition gpu_compute.hpp:783
bool gpu_faster
Definition gpu_compute.hpp:787
double upload_us
Definition gpu_compute.hpp:782
double cpu_baseline_us
Definition gpu_compute.hpp:786
double total_us
Definition gpu_compute.hpp:785
uint32_t num_elements
Definition gpu_compute.hpp:781
Runtime GPU capability/limit report for the compute device.
Definition gpu_compute.hpp:726
uint32_t max_compute_workgroup_storage_size
Definition gpu_compute.hpp:753
bool available
True when a usable compute device and queue are ready.
Definition gpu_compute.hpp:728
std::string name
Dawn-provided device name; empty when authentic identity is unavailable.
Definition gpu_compute.hpp:736
std::string adapter_type
Stable class: "discrete-gpu", "integrated-gpu", "cpu", or "unknown".
Definition gpu_compute.hpp:734
uint32_t max_compute_workgroup_size_x
Definition gpu_compute.hpp:752
bool timestamp_query
Definition gpu_compute.hpp:747
bool shader_f16
Definition gpu_compute.hpp:748
std::string description
Dawn-provided adapter description; empty when unavailable.
Definition gpu_compute.hpp:742
uint32_t max_fft_size
Definition gpu_compute.hpp:756
uint32_t vendor_id
PCI-style vendor identifier, or zero when unavailable.
Definition gpu_compute.hpp:744
uint32_t device_id
PCI-style device identifier, or zero when unavailable.
Definition gpu_compute.hpp:746
bool adapter_info_authentic
True only when Dawn returned this adapter's own AdapterInfo.
Definition gpu_compute.hpp:730
uint64_t max_storage_buffer_binding_size
Definition gpu_compute.hpp:749
uint32_t max_compute_invocations_per_workgroup
Definition gpu_compute.hpp:751
std::string backend
Backend family, for example "Metal", "D3D12", "Vulkan", or "shared".
Definition gpu_compute.hpp:732
std::string vendor
Dawn-provided vendor name; empty when unavailable.
Definition gpu_compute.hpp:738
uint64_t max_buffer_size
Definition gpu_compute.hpp:750
std::string architecture
Dawn-provided architecture; empty when unavailable.
Definition gpu_compute.hpp:740
Definition gpu_compute.hpp:764
std::string notes
Definition gpu_compute.hpp:770
bool concurrent_submission_ok
Definition gpu_compute.hpp:767
bool second_consumer_works
Definition gpu_compute.hpp:766
bool memory_pressure_ok
Definition gpu_compute.hpp:768
bool device_obtained
Definition gpu_compute.hpp:765
std::string backend_name
Definition gpu_compute.hpp:769
Definition gpu_compute.hpp:601
ReadbackStatus status
Definition gpu_compute.hpp:603
uint32_t bytes
written to dest (0 unless Success)
Definition gpu_compute.hpp:604
One WaveNet layer-array's static shape.
Definition gpu_compute.hpp:448
uint32_t kernel
Definition gpu_compute.hpp:452
uint32_t condition_size
Definition gpu_compute.hpp:450
uint32_t head_size
Definition gpu_compute.hpp:453
uint32_t channels
Definition gpu_compute.hpp:451
uint32_t head_bias
Definition gpu_compute.hpp:455
uint32_t gated
Definition gpu_compute.hpp:454
uint32_t input_size
Definition gpu_compute.hpp:449
const uint32_t * dilations
Definition gpu_compute.hpp:456
uint32_t num_layers
Definition gpu_compute.hpp:457