Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
gpu_convolver.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5#include <cstdint>
6#include <memory>
7#include <string>
8#include <vector>
9
14
16
17namespace pulp::gpu_audio {
18
25 bool enabled = false;
26 bool capture_admissions = false;
28 std::uint32_t success_stride = 1;
29};
30
39 std::uint32_t trip_after_misses = 8;
40 std::uint32_t probe_interval_blocks = 32;
41 std::uint32_t recover_after_hits = 4;
42};
43
44class GpuConvolver;
45
46namespace detail {
47struct RealtimeGpuHealth;
48struct SharedIoCompletionNotifier;
49struct GpuConvolverTestAccess;
50struct SharedIoProviderIdentity;
51struct GpuConvolverTrialConfig;
52struct SharedIoTraceRecord;
53struct SharedIoTraceAdmission;
54class StagedAsyncTrialState;
55bool configure_gpu_convolver_trial(GpuConvolver&, const GpuConvolverTrialConfig&) noexcept;
56bool drain_gpu_convolver_trial_records(GpuConvolver&, std::vector<SharedIoTraceRecord>&) noexcept;
58 std::vector<SharedIoTraceAdmission>&) noexcept;
59std::uint64_t gpu_convolver_trial_engine_id(const GpuConvolver&) noexcept;
60} // namespace detail
61
118 public:
135
139 static constexpr uint32_t kLatencyBlocks = 2;
140 static constexpr uint32_t kMaxLatencyBlocks = 64;
141 // Physical shared-I/O provider capacity, independent of logical lead.
142 // Diagnostic receipts use this value instead of a stale literal.
143 static constexpr uint32_t kSharedIoSlots = 16;
144
145 GpuConvolver(uint32_t channels, uint32_t block_size, uint32_t sample_rate,
146 std::vector<float> impulse_response);
147 GpuConvolver(uint32_t channels, uint32_t block_size, uint32_t sample_rate,
148 std::vector<float> impulse_response, uint32_t latency_blocks);
149 ~GpuConvolver() override;
150
155 bool set_provider_policy(ProviderPolicy policy) noexcept;
157 return provider_policy_;
158 }
159
163 bool configure_trace(const GpuConvolverTraceConfig& config) noexcept;
164
169
171 bool prepare() override;
172
173 bool cpu_fallback_prepared() const noexcept override {
174 return prepared_;
175 }
177 audio::BufferView<float>& output, uint32_t n) override;
178
184 void prime_fallback(const audio::BufferView<const float>& input, uint32_t n) noexcept override;
185
189 audio::BufferView<float>& output, uint32_t n) noexcept override {
190 const uint32_t out_ch = static_cast<uint32_t>(output.num_channels());
191 for (uint32_t ch = 0; ch < out_ch; ++ch)
192 std::fill_n(output.channel_ptr(ch), n, 0.0f);
193 if (!prepared_ || n != block_)
194 return;
195 const uint32_t ch_count = std::min<uint32_t>(channels_, out_ch);
196 for (uint32_t ch = 0; ch < ch_count; ++ch) {
197 const float* due = fb_out_.data() + static_cast<std::size_t>(ch) * block_;
198 std::copy_n(due, n, output.channel_ptr(ch));
199 }
200 }
201
203 bool gpu_available() const;
207 std::string backend() const;
208 uint32_t fft_size() const {
209 return fft_size_;
210 }
211
221 GpuAudioStatus status_snapshot() const noexcept override;
222 bool bind_realtime_path(detail::RealtimeGpuNodeBinding& binding) noexcept override;
227 bool fenced() const noexcept;
233 std::uint64_t sanitized_input_samples() const noexcept;
234
235 protected:
240 fallback_.clear();
241 worker_fallback_.clear();
242 fallback_.resize(channels_);
244 for (uint32_t ch = 0; ch < channels_; ++ch) {
245 fallback_[ch].load_ir(ir_.data(), ir_.size(), block_);
246 worker_fallback_[ch].load_ir(ir_.data(), ir_.size(), block_);
247 }
249 fb_delay_idx_ = 0;
250 fb_delay_.assign(static_cast<std::size_t>(fallback_delay_blocks_) * block_ * channels_,
251 0.0f);
252 fb_out_.assign(static_cast<std::size_t>(block_) * channels_, 0.0f);
253 }
254
269 audio::BufferView<float>& output, uint32_t n) noexcept {
270 const uint32_t out_ch = static_cast<uint32_t>(output.num_channels());
271 for (uint32_t ch = 0; ch < out_ch; ++ch)
272 std::fill_n(output.channel_ptr(ch), n, 0.0f);
273 if (!prepared_)
274 return;
275 const uint32_t ch_count = std::min<uint32_t>(channels_, out_ch);
276 for (uint32_t ch = 0; ch < ch_count && ch < worker_fallback_.size(); ++ch) {
277 if (ch >= input.num_channels())
278 continue;
279 const float* x = input.channel_ptr(ch);
280 bool finite = true;
281 for (uint32_t i = 0; i < n; ++i) {
282 if (!std::isfinite(x[i])) {
283 finite = false;
284 break;
285 }
286 }
287 if (!finite) {
288 worker_fallback_[ch].reset(); // output stays the pre-cleared silence
289 continue;
290 }
291 worker_fallback_[ch].process(x, output.channel_ptr(ch), static_cast<std::size_t>(n));
292 }
293 }
294
295 static std::uint8_t process_realtime_shared_io(void* self,
298 std::uint32_t n, std::uint64_t sequence,
299 bool input_valid,
300 std::uint64_t callback_start_ns) noexcept;
301 static std::uint32_t service_realtime_shared_io(void* self, std::uint64_t now_ns) noexcept;
302 static bool fence_realtime_shared_io(void* self) noexcept;
303 static void complete_realtime_shared_io(void*, std::uint64_t, std::uint8_t,
304 std::uint64_t callback_end_ns,
305 std::uint64_t result_visible_ns) noexcept;
306 static std::uint64_t next_realtime_shared_io_sequence(void*) noexcept;
307 // Serialized non-RT (transport worker or quiescent host). Also republishes
308 // the sample for status_snapshot() readers on other threads.
309 static bool realtime_shared_io_health(const void* self, detail::RealtimeGpuHealth&) noexcept;
310 // Host only, while no service step runs: route the shared session's
311 // provider completion events to the transport worker.
312 static bool set_realtime_shared_io_notifier(void* self,
313 detail::SharedIoCompletionNotifier) noexcept;
314 // Host-thread safe: the staged GpuCompute loss query is atomic.
316 bool has_realtime_shared_io() const noexcept;
317 detail::SharedIoProviderIdentity provider_identity_for_diagnostics() const noexcept;
318
319 struct StagedReadbackState;
320 // One-block-lead fallback: submit the packed block and wait, bounded, for
321 // its completion into `dest`. True only for a Success readback.
322 bool wait_staged_readback(StagedReadbackState& staged, float* dest);
323 // Pipelined path: submit the packed block into slot `slot_index` without
324 // waiting; it is judged when due, pipeline_blocks calls later.
325 void submit_staged_readback(StagedReadbackState& staged, std::size_t slot_index);
326 // Choose the staged pipeline depth from the prepared device and policy and
327 // size its slots. Called at the end of prepare(); a test that swaps in a
328 // scripted device calls it again before the node is attached.
330 // Pipeline depth the current hosting, device and policy call for.
331 std::uint32_t staged_pipeline_depth() const noexcept;
333 void update_staged_breaker(StagedReadbackState& staged, bool on_time) noexcept;
334 // Blocks for which the staged worker ran its CPU convolution since
335 // prepare() (a missed block or the tail after one). Diagnostic.
336 std::uint64_t staged_cpu_blocks() const noexcept;
337 // Blocks whose GPU result was used, and breaker trips, since prepare().
338 // Diagnostic; worker-thread values, read when the worker is quiescent.
339 std::uint64_t staged_gpu_blocks() const noexcept;
340 std::uint64_t staged_breaker_trips() const noexcept;
341 // First cause latched by the staged worker since prepare(): ProviderLost
342 // (device loss; replaces any other cause), SustainedDeadlineMisses (the
343 // breaker tripped on a run of late results), ProviderFailure (failed map or
344 // non-finite readback), else None. A single late block latches nothing.
345 // Any thread; the public status accessor reads it.
347 // The transport's worker-pipelining opt-in, bound through
348 // bind_realtime_path(); `self` is the GpuConvolver.
349 static bool set_staged_pipeline_hosting(void* self, bool hosted) noexcept;
350 friend bool
352 const detail::GpuConvolverTrialConfig&) noexcept;
353 friend bool
355 std::vector<detail::SharedIoTraceRecord>&) noexcept;
357 GpuConvolver&, std::vector<detail::SharedIoTraceAdmission>&) noexcept;
358 friend std::uint64_t detail::gpu_convolver_trial_engine_id(const GpuConvolver&) noexcept;
360
361 struct SharedIoState;
362
363 uint32_t channels_;
364 uint32_t block_;
365 uint32_t sample_rate_;
366 // Fixed before prepare(); this value is shared by descriptor PDC, the
367 // shared-I/O bridge lead, and the CPU fallback delay.
370 std::vector<float> ir_;
371 uint32_t fft_size_ = 0;
372 std::uint8_t trial_requested_path_ = 0; // detail::SharedIoRequest::Auto
373 std::uint64_t trial_generation_ = 1;
374 bool trial_configured_ = false;
380 std::uint8_t trial_completion_policy_ = 0; // Dawn completion policy enum
381 // Low 32 bits carry the private completion wait; high 32 bits carry the
382 // private trace-retention bound. Keeping both in this existing field
383 // preserves the exported class layout for SDK consumers.
385
386 std::unique_ptr<render::GpuCompute> gpu_;
387 std::unique_ptr<SharedIoState> shared_io_;
388 std::unique_ptr<detail::StagedAsyncTrialState> staged_trial_;
389 // Quiescent-only records for the explicit P4 staged_sync reference.
390 std::vector<detail::SharedIoTraceRecord> staged_sync_records_;
391 std::uint64_t staged_sequence_ = 0;
392 std::vector<float> ir_spec_; // 2*fft_size interleaved IR spectrum
393 std::vector<std::vector<float>> carry_; // per-channel OLA accumulator (fft_size)
394
395 // Per-block host scratch (allocated in prepare()). The FFT/mul/inverse
396 // intermediates stay GPU-resident inside GpuCompute::convolve().
397 std::vector<float> in_pad_; // 2*fft_size interleaved complex input
398 std::vector<float> time_; // 2*fft_size inverse result (one readback)
399
400 // Continuously-fed zero-latency CPU fallbacks.
401 std::vector<signal::FixedIrConvolver> fallback_; // RT miss fallback
402 std::vector<signal::FixedIrConvolver> worker_fallback_; // no-GPU worker path
403
404 // Latency-alignment delay for the RT miss fallback. `fb_delay_` is a
405 // `fallback_delay_blocks_`-deep circular buffer of block-sized, per-channel
406 // slots; `fb_out_` holds this block's due (input(t-L)-convolved) substitute.
408 uint32_t fb_delay_idx_ = 0;
409 std::vector<float> fb_delay_; // [delay_blocks][channels][block]
410 std::vector<float> fb_out_; // [channels][block]
411
412 bool prepared_ = false;
413
414 // Staged worker state: breaker settings, the pipelined readback slots, the
415 // CPU convolution's owed tail and the latched recovery cause. Allocated by
416 // the constructor so settings made before prepare() have a home.
417 std::unique_ptr<StagedReadbackState> staged_readback_;
418};
419
420} // namespace pulp::gpu_audio
Non-owning view over multi-channel audio sample data.
Definition buffer.hpp:30
A unit of audio work the transport schedules onto a non-real-time worker.
Definition gpu_audio_node.hpp:92
First real GPU audio node: FFT-based (overlap-add) convolution of the input with a fixed impulse resp...
Definition gpu_convolver.hpp:117
ProviderPolicy
Host-thread selection for the provider used during the next prepare().
Definition gpu_convolver.hpp:129
@ Auto
Definition gpu_convolver.hpp:130
@ StagedBlocking
Definition gpu_convolver.hpp:133
@ StagedOnly
Definition gpu_convolver.hpp:131
@ SharedRequired
Definition gpu_convolver.hpp:132
std::uint64_t sanitized_input_samples() const noexcept
Non-finite input samples (NaN, +/-Inf) replaced with zero before they reached the GPU,...
friend struct detail::GpuConvolverTestAccess
Definition gpu_convolver.hpp:359
bool trial_configured_
Definition gpu_convolver.hpp:374
bool trial_capture_admissions_
Definition gpu_convolver.hpp:376
std::vector< detail::SharedIoTraceRecord > staged_sync_records_
Definition gpu_convolver.hpp:390
static bool set_realtime_shared_io_notifier(void *self, detail::SharedIoCompletionNotifier) noexcept
void render_worker_fallback(const audio::BufferView< const float > &input, audio::BufferView< float > &output, uint32_t n) noexcept
No-GPU worker path: run the (continuously-fed) worker fallback for every prepared channel into output...
Definition gpu_convolver.hpp:268
std::uint64_t staged_sequence_
Definition gpu_convolver.hpp:391
std::uint64_t staged_breaker_trips() const noexcept
std::unique_ptr< render::GpuCompute > gpu_
Definition gpu_convolver.hpp:386
uint32_t fb_delay_idx_
Definition gpu_convolver.hpp:408
bool trial_capture_callback_timing_
Definition gpu_convolver.hpp:377
std::uint32_t trial_success_stride_
Definition gpu_convolver.hpp:379
uint32_t latency_blocks_
Definition gpu_convolver.hpp:368
uint32_t fallback_delay_blocks_
Definition gpu_convolver.hpp:407
std::vector< std::vector< float > > carry_
Definition gpu_convolver.hpp:393
std::uint8_t trial_completion_policy_
Definition gpu_convolver.hpp:380
std::vector< signal::FixedIrConvolver > fallback_
Definition gpu_convolver.hpp:401
friend std::uint64_t detail::gpu_convolver_trial_engine_id(const GpuConvolver &) noexcept
bool prepared_
Definition gpu_convolver.hpp:412
uint32_t sample_rate_
Definition gpu_convolver.hpp:365
bool has_realtime_shared_io() const noexcept
std::vector< float > ir_spec_
Definition gpu_convolver.hpp:392
static void complete_realtime_shared_io(void *, std::uint64_t, std::uint8_t, std::uint64_t callback_end_ns, std::uint64_t result_visible_ns) noexcept
void update_staged_breaker(StagedReadbackState &staged, bool on_time) noexcept
friend bool detail::drain_gpu_convolver_trial_admissions(GpuConvolver &, std::vector< detail::SharedIoTraceAdmission > &) noexcept
uint32_t channels_
Definition gpu_convolver.hpp:363
void process_cpu_fallback(const audio::BufferView< const float > &, audio::BufferView< float > &output, uint32_t n) noexcept override
RT-safe miss substitute: emit the latency-aligned block that prime_fallback() already computed for th...
Definition gpu_convolver.hpp:188
friend bool detail::configure_gpu_convolver_trial(GpuConvolver &, const detail::GpuConvolverTrialConfig &) noexcept
bool trial_staged_sync_reference_
Definition gpu_convolver.hpp:378
void process_block(const audio::BufferView< const float > &input, audio::BufferView< float > &output, uint32_t n) override
Non-RT worker context. Process exactly one block (n == block_size).
static std::uint32_t service_realtime_shared_io(void *self, std::uint64_t now_ns) noexcept
GpuConvolver(uint32_t channels, uint32_t block_size, uint32_t sample_rate, std::vector< float > impulse_response, uint32_t latency_blocks)
bool bind_realtime_path(detail::RealtimeGpuNodeBinding &binding) noexcept override
Private transport hook, not for node authors: a node that the GPU audio transport drives through a st...
static bool set_staged_pipeline_hosting(void *self, bool hosted) noexcept
GpuConvolverStagedBreaker staged_breaker() const noexcept
friend bool detail::drain_gpu_convolver_trial_records(GpuConvolver &, std::vector< detail::SharedIoTraceRecord > &) noexcept
std::vector< signal::FixedIrConvolver > worker_fallback_
Definition gpu_convolver.hpp:402
static constexpr uint32_t kSharedIoSlots
Definition gpu_convolver.hpp:143
void prime_fallback(const audio::BufferView< const float > &input, uint32_t n) noexcept override
RT-safe.
GpuAudioRecoveryReason staged_recovery_reason() const noexcept
GpuAudioRecoveryReason recovery_reason() const noexcept
First latched recovery cause, or None. Same snapshot as status_snapshot().
bool wait_staged_readback(StagedReadbackState &staged, float *dest)
static std::uint8_t process_realtime_shared_io(void *self, const audio::BufferView< const float > &input, audio::BufferView< float > &output, std::uint32_t n, std::uint64_t sequence, bool input_valid, std::uint64_t callback_start_ns) noexcept
std::string backend() const
The live native compute backend ("Metal"/"D3D12"/"Vulkan"), or "" if CPU-only.
std::uint64_t staged_gpu_blocks() const noexcept
std::vector< float > ir_
Definition gpu_convolver.hpp:370
uint32_t block_
Definition gpu_convolver.hpp:364
bool configure_trace(const GpuConvolverTraceConfig &config) noexcept
Enable bounded shared-I/O tracing for the next prepare().
static constexpr uint32_t kMaxLatencyBlocks
Definition gpu_convolver.hpp:140
std::uint8_t trial_requested_path_
Definition gpu_convolver.hpp:372
ProviderPolicy provider_policy() const noexcept
Definition gpu_convolver.hpp:156
void latch_staged_recovery(GpuAudioRecoveryReason reason) noexcept
std::vector< float > in_pad_
Definition gpu_convolver.hpp:397
bool cpu_fallback_prepared() const noexcept override
Host-thread witness that the realtime CPU fallback is already built before prepare() returns.
Definition gpu_convolver.hpp:173
bool configure_staged_breaker(const GpuConvolverStagedBreaker &config) noexcept
Set the staged-path circuit breaker for the next prepare().
static constexpr uint32_t kLatencyBlocks
Default worker/round-trip latency, in host blocks.
Definition gpu_convolver.hpp:139
static std::uint64_t next_realtime_shared_io_sequence(void *) noexcept
static bool realtime_shared_io_health(const void *self, detail::RealtimeGpuHealth &) noexcept
uint32_t fft_size() const
Definition gpu_convolver.hpp:208
GpuAudioNodeDescriptor descriptor() const override
std::uint64_t trial_completion_wait_ns_
Definition gpu_convolver.hpp:384
std::uint64_t trial_generation_
Definition gpu_convolver.hpp:373
std::uint64_t staged_cpu_blocks() const noexcept
std::unique_ptr< SharedIoState > shared_io_
Definition gpu_convolver.hpp:387
bool fenced() const noexcept
True before preparation, or once GPU delivery was fenced or its provider lost.
std::vector< float > fb_delay_
Definition gpu_convolver.hpp:409
ProviderPolicy provider_policy_
Definition gpu_convolver.hpp:369
std::uint32_t staged_pipeline_depth() const noexcept
bool trial_enable_trace_
Definition gpu_convolver.hpp:375
bool prepare() override
Non-RT. Allocate/compile/upload static data here.
GpuConvolver(uint32_t channels, uint32_t block_size, uint32_t sample_rate, std::vector< float > impulse_response)
std::unique_ptr< detail::StagedAsyncTrialState > staged_trial_
Definition gpu_convolver.hpp:388
bool set_provider_policy(ProviderPolicy policy) noexcept
Select the provider policy for the next prepare().
std::vector< float > fb_out_
Definition gpu_convolver.hpp:410
GpuAudioStatus status_snapshot() const noexcept override
Allocation-free provider-neutral lifecycle projection, safe to call from a host or UI thread while a ...
void init_fallback()
Allocate + load the CPU fallback machinery (both the RT miss fallback and the no-GPU worker fallback)...
Definition gpu_convolver.hpp:239
std::unique_ptr< StagedReadbackState > staged_readback_
Definition gpu_convolver.hpp:417
detail::SharedIoProviderIdentity provider_identity_for_diagnostics() const noexcept
GpuAudioRecoveryReason staged_latched_reason() const noexcept
bool gpu_available() const
True if the GPU compute device initialized (process_block uses the GPU).
uint32_t fft_size_
Definition gpu_convolver.hpp:371
void submit_staged_readback(StagedReadbackState &staged, std::size_t slot_index)
static bool fence_realtime_shared_io(void *self) noexcept
std::vector< float > time_
Definition gpu_convolver.hpp:398
Fixed-IR convolution that picks the cheaper engine at prepare time.
Definition gpu_audio_node.hpp:78
bool configure_gpu_convolver_trial(GpuConvolver &, const GpuConvolverTrialConfig &) noexcept
std::uint64_t gpu_convolver_trial_engine_id(const GpuConvolver &) noexcept
bool drain_gpu_convolver_trial_admissions(GpuConvolver &, std::vector< SharedIoTraceAdmission > &) noexcept
bool drain_gpu_convolver_trial_records(GpuConvolver &, std::vector< SharedIoTraceRecord > &) noexcept
Definition flow_pans.hpp:19
GpuAudioRecoveryReason
First latched reason that a node entered recovery.
Definition gpu_audio_status.hpp:40
Definition gpu_fwd.hpp:31
Definition host_transport_projector.hpp:8
Definition additive_bank.hpp:218
STL namespace.
Declared, fixed scheduling properties of a GPU audio node.
Definition gpu_audio_node.hpp:44
Versioned, allocation-free status shared by native hosts and UI adapters.
Definition gpu_audio_status.hpp:80
Circuit breaker for the staged GPU readback.
Definition gpu_convolver.hpp:38
std::uint32_t trip_after_misses
Definition gpu_convolver.hpp:39
std::uint32_t probe_interval_blocks
Definition gpu_convolver.hpp:40
std::uint32_t recover_after_hits
Definition gpu_convolver.hpp:41
Opt-in diagnostics for the shared-I/O path.
Definition gpu_convolver.hpp:24
std::uint32_t success_stride
Definition gpu_convolver.hpp:28
bool capture_callback_timing
Definition gpu_convolver.hpp:27
bool capture_admissions
Definition gpu_convolver.hpp:26
bool enabled
Definition gpu_convolver.hpp:25