Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::gpu_audio::WebGpuConvolver Class Reference

Submit/collect FFT convolver for a single-threaded event loop. More...

#include <web_gpu_convolver.hpp>

Public Types

using Sink = std::function<void(uint32_t seq, const float* out_planar, bool ok)>
 Called once per finished block, in submission order.

Public Member Functions

 WebGpuConvolver (uint32_t depth=kDefaultDepth)
 ~WebGpuConvolver ()
 WebGpuConvolver (const WebGpuConvolver &)=delete
WebGpuConvolver & operator= (const WebGpuConvolver &)=delete
bool prepare (render::GpuCompute *gpu, int sample_rate, int block, int channels, const float *ir, int ir_len)
 Allocate scratch, transform the IR on the CPU, and upload the resident IR spectrum.
bool submit (uint32_t seq, const float *in_planar, int frames, std::chrono::microseconds deadline)
 Issue one block.
uint32_t collect (const Sink &sink)
 Harvest.
bool prepared () const
bool device_lost () const
 Device loss is normal browser behavior, not an init failure: the owner is expected to re-acquire a device and prepare() again.
uint32_t fft_size () const
uint32_t depth () const
uint32_t in_flight () const
uint64_t submits () const
uint64_t resolves () const
 maps that landed with a usable payload
uint64_t expired () const
 deadline passed before the map resolved
uint64_t failed () const
 map error, device loss, or non-finite payload

Static Public Attributes

static constexpr uint32_t kDefaultDepth = 3
 Blocks that may be in flight at once.

Detailed Description

Submit/collect FFT convolver for a single-threaded event loop.

Same math as GpuConvolver (zero-padded complex block → fused GPU forward-FFT / complex-multiply by the resident IR spectrum / inverse-FFT → overlap-add carry), with two structural differences that a browser forces:

  1. NO GPU READBACK IN prepare(). GpuConvolver builds the IR spectrum with the BLOCKING GpuCompute::fft_forward(). That call pumps the device event queue until the map resolves — on a browser's event loop the pump IS the loop, so it can never resolve its own map and would simply burn the deadline. The IR transform is a one-time offline cost, so it is done on the CPU (signal::FftT) and handed to prepare_convolution_batch(), which is upload-only. One readback deleted from the critical path.
  2. NO BLOCKING PER BLOCK. submit() issues convolve_batch_async() and returns; collect() pumps GpuCompute::poll_readbacks() exactly ONCE (never spins) and drains whatever landed. Up to depth blocks may be in flight, each with its own scratch slot.

THE OVERLAP-ADD CARRY IS SEQUENTIAL STATE and is therefore applied in collect(), in completion (== submission) order — never at submit time, where blocks may be issued out of the order their results land in. A block that Expires, Fails, or reads back non-finite does NOT land: it is reported to the sink with ok == false and the carry is NOT mutated (mirroring GpuConvolver::process_block, which on a failed readback emits silence and deliberately leaves the carry alone — a stale result added to the carry would poison every later block of that channel).

This class carries NO CPU fallback. In the browser the safety net lives in the plugin, on the audio side of the ring, because the GPU work runs in a DedicatedWorker with its own wasm heap — a fallback here would be in the wrong linear memory and, worse, on the wrong thread.

Not real-time-safe: submit/collect from the GPU worker, never from the audio callback.

Member Typedef Documentation

◆ Sink

using pulp::gpu_audio::WebGpuConvolver::Sink = std::function<void(uint32_t seq, const float* out_planar, bool ok)>

Called once per finished block, in submission order.

out_planar holds channels * block floats (channel-major); it is silence when ok is false. The pointer is owned by the convolver and valid only for the duration of the call.

Constructor & Destructor Documentation

◆ WebGpuConvolver() [1/2]

pulp::gpu_audio::WebGpuConvolver::WebGpuConvolver ( uint32_t depth = kDefaultDepth)
explicit

◆ ~WebGpuConvolver()

pulp::gpu_audio::WebGpuConvolver::~WebGpuConvolver ( )

◆ WebGpuConvolver() [2/2]

pulp::gpu_audio::WebGpuConvolver::WebGpuConvolver ( const WebGpuConvolver & )
delete

Member Function Documentation

◆ collect()

uint32_t pulp::gpu_audio::WebGpuConvolver::collect ( const Sink & sink)

Harvest.

Pumps poll_readbacks() ONCE and delivers every block that has resolved, in submission order, applying the overlap-add carry to the ones that landed. Returns the number of blocks handed to the sink.

◆ depth()

uint32_t pulp::gpu_audio::WebGpuConvolver::depth ( ) const
inline

◆ device_lost()

bool pulp::gpu_audio::WebGpuConvolver::device_lost ( ) const
inline

Device loss is normal browser behavior, not an init failure: the owner is expected to re-acquire a device and prepare() again.

◆ expired()

uint64_t pulp::gpu_audio::WebGpuConvolver::expired ( ) const

deadline passed before the map resolved

◆ failed()

uint64_t pulp::gpu_audio::WebGpuConvolver::failed ( ) const

map error, device loss, or non-finite payload

◆ fft_size()

uint32_t pulp::gpu_audio::WebGpuConvolver::fft_size ( ) const
inline

◆ in_flight()

uint32_t pulp::gpu_audio::WebGpuConvolver::in_flight ( ) const

◆ operator=()

WebGpuConvolver & pulp::gpu_audio::WebGpuConvolver::operator= ( const WebGpuConvolver & )
delete

◆ prepare()

bool pulp::gpu_audio::WebGpuConvolver::prepare ( render::GpuCompute * gpu,
int sample_rate,
int block,
int channels,
const float * ir,
int ir_len )

Allocate scratch, transform the IR on the CPU, and upload the resident IR spectrum.

gpu must already be initialized and must outlive this object. No GPU readback happens here (see the class comment).

◆ prepared()

bool pulp::gpu_audio::WebGpuConvolver::prepared ( ) const
inline

◆ resolves()

uint64_t pulp::gpu_audio::WebGpuConvolver::resolves ( ) const

maps that landed with a usable payload

◆ submit()

bool pulp::gpu_audio::WebGpuConvolver::submit ( uint32_t seq,
const float * in_planar,
int frames,
std::chrono::microseconds deadline )

Issue one block.

in_planar holds channels * block floats (channel-major) and is consumed (copied into this block's slot) before returning. Returns false — allocating nothing — when the pipeline is at its depth cap, the device is gone, frames is not the prepared block size, or the GPU rejects the dispatch.

◆ submits()

uint64_t pulp::gpu_audio::WebGpuConvolver::submits ( ) const

Member Data Documentation

◆ kDefaultDepth

uint32_t pulp::gpu_audio::WebGpuConvolver::kDefaultDepth = 3
staticconstexpr

Blocks that may be in flight at once.

3 keeps the GPU fed across one round-trip of map latency without letting a stalled tab queue unbounded work — every in-flight block is one more block of scratch, and one more block that must expire before its deadline is honoured.


The documentation for this class was generated from the following file: