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

Architecture-neutral realtime neural node with a built-in CPU shadow. More...

#include <gpu_neural_realtime_node.hpp>

Classes

struct  ShadowStatus
 Allocation-free shadow diagnostics. More...
struct  Config

Public Types

enum class  ShadowPolicy : std::uint8_t { Auto = 0 , Inline = 1 , Worker = 2 , None = 3 }
 Where the built-in CPU shadow runs. More...
enum class  PrepareError : std::uint8_t {
  None , InvalidConfig , FamilyMismatch , ChannelMismatch ,
  BackendInflightExceeded , ModelBound , ShadowPrepareFailed , ShadowUnpublished ,
  BridgeFailed , ReleaseFailed , ShadowRequired , ShadowModelMismatch
}
 Why the last prepare() returned false. More...

Public Member Functions

 GpuNeuralRealtimeNode (Config config)
 Host thread only.
 ~GpuNeuralRealtimeNode () override
 Stop/join the callback and worker first; destruction releases.
 GpuNeuralRealtimeNode (const GpuNeuralRealtimeNode &)=delete
GpuNeuralRealtimeNode & operator= (const GpuNeuralRealtimeNode &)=delete
GpuAudioNodeDescriptor descriptor () const override
bool prepare () override
 Stop/join callback and worker first: prepare() begins with release().
bool release () noexcept
 Stop/join callback and worker first.
bool cpu_fallback_prepared () const noexcept override
 True once every channel's shadow processor is published.
void prime_fallback (const audio::BufferView< const float > &input, std::uint32_t n) noexcept override
 RT-safe.
void process_cpu_fallback (const audio::BufferView< const float > &input, audio::BufferView< float > &output, std::uint32_t n) noexcept override
 RT-safe. Emits the latency-aligned block staged by prime_fallback().
void process_block (const audio::BufferView< const float > &, audio::BufferView< float > &, std::uint32_t) final
 Not a legacy FIFO node. GpuAudioTransport rejects an unprepared instance.
PrepareError last_prepare_error () const noexcept
 Reason for the most recent failed prepare(); None after a success.
std::uint64_t sanitized_input_samples () const noexcept
 Non-finite input samples (NaN, +/-Inf) replaced with zero since prepare().
std::uint64_t callback_contract_violations () const noexcept
 Invalid or out-of-sequence callbacks observed on the CPU-only path.
NeuralFamily family () const noexcept
bool gpu_kernel_available () const noexcept
 True only while a GPU backend for this family is prepared and has not been quiesced by an offline fence.
std::uint64_t epoch () const noexcept
 Current GPU delivery epoch, or zero when no GPU epoch is open.
bool fenced () const noexcept
 True before preparation, or once GPU delivery was fenced.
GpuAudioRecoveryReason recovery_reason () const noexcept
 First latched recovery cause.
std::uint64_t recovery_sequence () const noexcept
 Sequence associated with the first latched recovery cause, or UINT64_MAX.
GpuAudioStatus status_snapshot () const noexcept override
 Allocation-free lifecycle projection.
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 stamped realtime path describes that path here.
GpuAudioCapabilityReport capability_report () const noexcept
 Allocation-free capability projection.
ShadowStatus shadow_status () const noexcept
 Allocation-free shadow diagnostics beyond the public shadow_* fields of status_snapshot(), which carry the mode and the authoritative delivered, late and double-miss counts.
virtual void process_block (const audio::BufferView< const float > &input, audio::BufferView< float > &output, uint32_t n)=0
 Non-RT worker context. Process exactly one block (n == block_size).
virtual void prime_fallback (const audio::BufferView< const float > &, uint32_t) noexcept
 RT-safe.
virtual void process_cpu_fallback (const audio::BufferView< const float > &input, audio::BufferView< float > &output, uint32_t n) noexcept
 RT-safe fallback.
virtual bool release_bounded (std::uint64_t) noexcept
 Host thread, audio stopped.

Static Public Attributes

static constexpr float kAutoInlineMaxCostPct = 15.0f
 Auto selects Inline when the total inline cost (one channel's cost times the channel count) is at most this share of the block period.

Friends

struct detail::NeuralRealtimeTestAccess

Detailed Description

Architecture-neutral realtime neural node with a built-in CPU shadow.

Every family (WaveNet/NAM, TCN/NAM-TCN, SSM, LSTM, GRU, custom) owns a continuously primed CPU instance of its model. The transport feeds it on every callback and it emits its result lead_blocks callbacks later, so a missed, failed, or fenced GPU block is replaced by a latency-aligned, history-continuous CPU block without waiting. cpu_fallback_prepared() is therefore true for every prepared node, and the miss policy is always MissPolicy::CpuFallback.

Families without a GPU kernel run CPU-only: they report GpuAudioExecutionPath::Cpu, GpuAudioProvider::Cpu, gpu_kernel_available() == false, and never open a GPU delivery epoch (epoch() == 0). A family with a GPU kernel whose provider cannot be prepared runs the same CPU-only contract and reports a degraded GPU request instead of failing preparation.

Where the shadow runs is the ShadowPolicy. Inline runs it on the audio thread every block, including blocks the GPU delivers. Worker runs it on a dedicated non-realtime thread: the callback only copies its input in and, when the GPU misses, copies the shadow's stamped result out. A shadow result that is late for its slot is dropped, and a block both paths miss is silent. None makes a realtime GPU miss silent. Auto times one block of the CPU model for one channel at prepare() and picks Inline when that cost times the channel count is at most kAutoInlineMaxCostPct of the block period, otherwise Worker. Families without a GPU backend, and a GPU family whose provider could not be prepared, always run Inline, because the CPU model is their output.

The policy governs realtime misses only. An offline render always runs the CPU model inline on the same timeline: under Worker and None the model is kept primed off the audio thread, the start of an offline render finishes its queue and continues it inline, and the first realtime callback after the render hands it back to the shadow thread. The node's shadow_* status fields are the authoritative shadow counts; the transport's CpuFallbackDelivered label means only that the fallback path ran, which can be a silent double miss.

On the GPU path the node detects device loss (the provider's loss query, which outranks the failed completions it causes) and a hung provider (a completion watchdog in callback blocks); both report Unavailable.

Recovery is manual: any latched cause, including a single invalid callback, fences GPU delivery until the host prepares the node again. The shadow carries the stream meanwhile. Automatic re-acquire is future work.

Threading: prepare() and release() are host-thread operations with the callback and worker stopped. The queries below read lifecycle state that only those two calls change, plus counters and recovery state that are atomics, so they are safe from a host or UI thread at any time except concurrently with prepare() or release(). A transport-hosted node is sampled by the transport worker into a sequence-guarded mirror, so the UI-safe read is GpuAudioTransport::status_snapshot().

Member Enumeration Documentation

◆ PrepareError

enum class pulp::gpu_audio::GpuNeuralRealtimeNode::PrepareError : std::uint8_t
strong

Why the last prepare() returned false.

Enumerator
None 
InvalidConfig 
FamilyMismatch 
ChannelMismatch 
BackendInflightExceeded 

max_inflight exceeds the backend's own in-flight capacity.

ModelBound 

The model is bound to another node.

ShadowPrepareFailed 
ShadowUnpublished 

The shadow processors were prepared but not published.

BridgeFailed 
ReleaseFailed 
ShadowRequired 

ShadowPolicy::None for a family without a GPU kernel.

ShadowModelMismatch 

The shadow model's channels, block size or sample rate differ.

◆ ShadowPolicy

enum class pulp::gpu_audio::GpuNeuralRealtimeNode::ShadowPolicy : std::uint8_t
strong

Where the built-in CPU shadow runs.

Enumerator
Auto 
Inline 
Worker 
None 

A realtime GPU miss is silent.

The model is still kept primed off the audio thread so an offline render can continue it. Requires a family with a GPU kernel.

Constructor & Destructor Documentation

◆ GpuNeuralRealtimeNode() [1/2]

pulp::gpu_audio::GpuNeuralRealtimeNode::GpuNeuralRealtimeNode ( Config config)
explicit

Host thread only.

◆ ~GpuNeuralRealtimeNode()

pulp::gpu_audio::GpuNeuralRealtimeNode::~GpuNeuralRealtimeNode ( )
override

Stop/join the callback and worker first; destruction releases.

◆ GpuNeuralRealtimeNode() [2/2]

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

Member Function Documentation

◆ bind_realtime_path()

bool pulp::gpu_audio::GpuNeuralRealtimeNode::bind_realtime_path ( detail::RealtimeGpuNodeBinding & )
overridevirtualnoexcept

Private transport hook, not for node authors: a node that the GPU audio transport drives through a stamped realtime path describes that path here.

Returns false for a node the transport drives through its staged worker path, which is the default.

Reimplemented from pulp::gpu_audio::GpuAudioNode.

◆ callback_contract_violations()

std::uint64_t pulp::gpu_audio::GpuNeuralRealtimeNode::callback_contract_violations ( ) const
noexcept

Invalid or out-of-sequence callbacks observed on the CPU-only path.

They are counted, not latched: nothing is fenced there and the CPU model keeps delivering. On the GPU path the same violation fences GPU delivery and is reported as the recovery reason.

◆ capability_report()

GpuAudioCapabilityReport pulp::gpu_audio::GpuNeuralRealtimeNode::capability_report ( ) const
noexcept

Allocation-free capability projection.

◆ cpu_fallback_prepared()

bool pulp::gpu_audio::GpuNeuralRealtimeNode::cpu_fallback_prepared ( ) const
overridevirtualnoexcept

True once every channel's shadow processor is published.

Reimplemented from pulp::gpu_audio::GpuAudioNode.

◆ descriptor()

GpuAudioNodeDescriptor pulp::gpu_audio::GpuNeuralRealtimeNode::descriptor ( ) const
overridevirtual

◆ epoch()

std::uint64_t pulp::gpu_audio::GpuNeuralRealtimeNode::epoch ( ) const
noexcept

Current GPU delivery epoch, or zero when no GPU epoch is open.

A CPU-only node stays at zero for its whole lifetime.

◆ family()

NeuralFamily pulp::gpu_audio::GpuNeuralRealtimeNode::family ( ) const
noexcept

◆ fenced()

bool pulp::gpu_audio::GpuNeuralRealtimeNode::fenced ( ) const
noexcept

True before preparation, or once GPU delivery was fenced.

A CPU-only node has no GPU delivery to fence and reports false.

◆ gpu_kernel_available()

bool pulp::gpu_audio::GpuNeuralRealtimeNode::gpu_kernel_available ( ) const
noexcept

True only while a GPU backend for this family is prepared and has not been quiesced by an offline fence.

◆ last_prepare_error()

PrepareError pulp::gpu_audio::GpuNeuralRealtimeNode::last_prepare_error ( ) const
noexcept

Reason for the most recent failed prepare(); None after a success.

◆ operator=()

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

◆ prepare()

bool pulp::gpu_audio::GpuNeuralRealtimeNode::prepare ( )
overridevirtual

Stop/join callback and worker first: prepare() begins with release().

Fails unless every channel's CPU shadow is prepared and published.

Implements pulp::gpu_audio::GpuAudioNode.

◆ prime_fallback() [1/2]

virtual void pulp::gpu_audio::GpuAudioNode::prime_fallback ( const audio::BufferView< const float > & ,
uint32_t  )
inlinevirtualnoexceptinherited

RT-safe.

Called by the transport on EVERY block (not just misses) for a CpuFallback node, BEFORE the output-ring read, so the node's CPU fallback can be kept continuously fed and its convolution history is always current the moment a miss makes it take over. A node whose fallback needs no live priming (the default) does nothing. MUST NOT allocate, lock, or block.

Reimplemented in pulp::gpu_audio::GpuConvolver.

◆ prime_fallback() [2/2]

void pulp::gpu_audio::GpuNeuralRealtimeNode::prime_fallback ( const audio::BufferView< const float > & input,
std::uint32_t n )
overridenoexcept

RT-safe.

Runs the CPU shadow on this block and stages the result due lead_blocks callbacks ago. Called by the transport on every block.

◆ process_block() [1/2]

virtual void pulp::gpu_audio::GpuAudioNode::process_block ( const audio::BufferView< const float > & input,
audio::BufferView< float > & output,
uint32_t n )
pure virtualinherited

Non-RT worker context. Process exactly one block (n == block_size).

Implemented in pulp::gpu_audio::GpuConvolver, and pulp::gpu_audio::GpuMultiConvolver.

◆ process_block() [2/2]

void pulp::gpu_audio::GpuNeuralRealtimeNode::process_block ( const audio::BufferView< const float > & ,
audio::BufferView< float > & ,
std::uint32_t  )
final

Not a legacy FIFO node. GpuAudioTransport rejects an unprepared instance.

◆ process_cpu_fallback() [1/2]

virtual void pulp::gpu_audio::GpuAudioNode::process_cpu_fallback ( const audio::BufferView< const float > & input,
audio::BufferView< float > & output,
uint32_t n )
inlinevirtualnoexceptinherited

RT-safe fallback.

MUST NOT allocate, lock, or block — it runs on the audio thread for the CpuFallback miss policy (hence noexcept). The default copies the current dry input to the output. The transport's output is delayed by latency_blocks, so that dry block breaks the timeline; it is not a safe fallback. A CpuFallback node should override this with a primed, latency-aligned fallback, or declare Silence. When paired with prime_fallback(), this emits the latency-aligned block the continuously-fed fallback has already computed.

Reimplemented in pulp::gpu_audio::GpuConvolver, and pulp::gpu_audio::GpuMultiConvolver.

◆ process_cpu_fallback() [2/2]

void pulp::gpu_audio::GpuNeuralRealtimeNode::process_cpu_fallback ( const audio::BufferView< const float > & input,
audio::BufferView< float > & output,
std::uint32_t n )
overridenoexcept

RT-safe. Emits the latency-aligned block staged by prime_fallback().

◆ recovery_reason()

GpuAudioRecoveryReason pulp::gpu_audio::GpuNeuralRealtimeNode::recovery_reason ( ) const
noexcept

First latched recovery cause.

◆ recovery_sequence()

std::uint64_t pulp::gpu_audio::GpuNeuralRealtimeNode::recovery_sequence ( ) const
noexcept

Sequence associated with the first latched recovery cause, or UINT64_MAX.

◆ release()

bool pulp::gpu_audio::GpuNeuralRealtimeNode::release ( )
noexcept

Stop/join callback and worker first.

False retains provider owners for retry.

◆ release_bounded()

virtual bool pulp::gpu_audio::GpuAudioNode::release_bounded ( std::uint64_t )
inlinevirtualnoexceptinherited

Host thread, audio stopped.

Release provider resources within budget_ns, returning false if teardown had to be abandoned to stay in budget. The default holds nothing to release.

Reimplemented in pulp::gpu_audio::GpuWaveNetRealtimeNode.

◆ sanitized_input_samples()

std::uint64_t pulp::gpu_audio::GpuNeuralRealtimeNode::sanitized_input_samples ( ) const
noexcept

Non-finite input samples (NaN, +/-Inf) replaced with zero since prepare().

The GPU submission and the CPU shadow both see the replacement, so they stay comparable.

◆ shadow_status()

ShadowStatus pulp::gpu_audio::GpuNeuralRealtimeNode::shadow_status ( ) const
noexcept

Allocation-free shadow diagnostics beyond the public shadow_* fields of status_snapshot(), which carry the mode and the authoritative delivered, late and double-miss counts.

◆ status_snapshot()

GpuAudioStatus pulp::gpu_audio::GpuNeuralRealtimeNode::status_snapshot ( ) const
overridevirtualnoexcept

Allocation-free lifecycle projection.

Reimplemented from pulp::gpu_audio::GpuAudioNode.

◆ detail::NeuralRealtimeTestAccess

friend struct detail::NeuralRealtimeTestAccess
friend

Member Data Documentation

◆ kAutoInlineMaxCostPct

float pulp::gpu_audio::GpuNeuralRealtimeNode::kAutoInlineMaxCostPct = 15.0f
staticconstexpr

Auto selects Inline when the total inline cost (one channel's cost times the channel count) is at most this share of the block period.


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