Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
gpu_audio_capability.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4
6
7namespace pulp::gpu_audio {
8
10enum class GpuAudioExecutionPath : std::uint8_t {
12 Staged = 1,
16 Cpu = 3,
17};
18
21enum class GpuAudioProvider : std::uint8_t {
23 Dawn = 1,
24 Metal = 2,
27 Cpu = 3,
28};
29
32enum class GpuAudioEligibility : std::uint8_t {
35};
36
39enum class GpuAudioRecoveryPolicy : std::uint8_t {
40 Manual = 0,
42};
43
51 // Algorithmic lead is reported only when an authenticated concrete
52 // provider establishes it. Generic staged nodes leave this at zero.
53 std::uint32_t prepared_lead_blocks = 0;
54 bool prepared = false;
55 bool fallback_available = false;
57 // The fixed output/PDC delay established by the transport. This is
58 // appended to preserve the existing positional field order for SDK
59 // consumers and must not be read as algorithmic pipeline lead.
60 std::uint32_t prepared_latency_blocks = 0;
61 // Appended: whether this node family has a GPU kernel at all. False for
62 // CPU-only families, which report the Cpu path rather than a GPU miss.
68};
69
86
94
120constexpr GpuAudioCapabilityValidation
122 using Error = GpuAudioCapabilityError;
123 using Path = GpuAudioExecutionPath;
124 if (static_cast<std::uint8_t>(capability.path) > static_cast<std::uint8_t>(Path::Cpu) ||
125 static_cast<std::uint8_t>(capability.provider) >
126 static_cast<std::uint8_t>(GpuAudioProvider::Cpu) ||
127 static_cast<std::uint8_t>(capability.eligibility) >
128 static_cast<std::uint8_t>(GpuAudioEligibility::Eligible) ||
129 static_cast<int>(capability.fallback_policy) < 0 ||
130 static_cast<int>(capability.fallback_policy) > static_cast<int>(MissPolicy::CpuFallback) ||
131 static_cast<std::uint8_t>(capability.recovery_policy) >
132 static_cast<std::uint8_t>(GpuAudioRecoveryPolicy::AutoReacquire))
133 return {Error::InvalidEnumValue};
134
135 if (!capability.prepared) {
136 if (capability.path != Path::Unavailable ||
137 capability.provider != GpuAudioProvider::Unknown ||
138 capability.eligibility != GpuAudioEligibility::Unavailable ||
139 capability.fallback_policy != MissPolicy::Silence ||
140 capability.prepared_lead_blocks != 0 || capability.fallback_available ||
141 capability.diagnostics_available || capability.prepared_latency_blocks != 0 ||
142 capability.gpu_kernel_available ||
143 capability.recovery_policy != GpuAudioRecoveryPolicy::Manual)
144 return {Error::UnpreparedStateHasPreparation};
145 return {};
146 }
147
148 if (capability.path == Path::Unavailable)
149 return {Error::PreparedPathUnavailable};
150 if (capability.eligibility != GpuAudioEligibility::Eligible)
151 return {Error::PreparedPathIneligible};
152 if (capability.path == Path::Cpu) {
153 if (capability.provider != GpuAudioProvider::Cpu)
154 return {Error::CpuPathWithoutCpuProvider};
155 if (capability.gpu_kernel_available)
156 return {Error::CpuPathWithGpuKernel};
157 } else if (capability.provider == GpuAudioProvider::Cpu) {
158 return {Error::CpuProviderOnGpuPath};
159 }
160 if (capability.path == Path::SharedMemory && capability.prepared_lead_blocks == 0)
161 return {Error::SharedLeadMissing};
162 if (capability.fallback_policy == MissPolicy::CpuFallback && !capability.fallback_available)
163 return {Error::FallbackUnavailable};
164 return {};
165}
166
167// The status validator lives here rather than in gpu_audio_status.hpp: it needs
168// MissPolicy and GpuAudioProvider complete, which the status header only
169// forward-declares. Every include order reaches this point with both complete,
170// and gpu_audio_status.hpp includes this header, so its users see it.
171
176enum class GpuAudioStatusError : std::uint8_t {
177 None = 0,
193 // Schema v4: automatic re-acquire accounting.
198 // Appended: a status naming the GPU engine must also report a prepared
199 // GPU kernel. Checked after every other rule, the re-acquire rules
200 // included, so a status breaking both reports the other error.
202 // Appended: a cause that fences delivery (SequenceGap, InputSaturated,
203 // ProviderFailure, InvalidCallback, OfflineFence) never reads Ready.
205 // Appended: a stamped node (nonzero epoch) whose delivery epoch is
206 // inactive is fenced, so never Ready.
208};
209
212
213 constexpr bool accepted() const noexcept {
215 }
216};
217
221constexpr GpuAudioStatusValidation
223 using Error = GpuAudioStatusError;
224 using Reason = GpuAudioRecoveryReason;
225 using State = GpuAudioProviderState;
226 if (status.schema_version != GpuAudioStatus::kSchemaVersion)
227 return {Error::SchemaVersionMismatch};
228
229 const auto engine_ok = [](GpuAudioEngine value) constexpr {
230 return static_cast<std::uint8_t>(value) <= static_cast<std::uint8_t>(GpuAudioEngine::Gpu);
231 };
232 if (!engine_ok(status.requested_engine) || !engine_ok(status.selected_engine) ||
233 static_cast<std::uint8_t>(status.provider_state) >
234 static_cast<std::uint8_t>(State::Unavailable) ||
235 static_cast<std::uint8_t>(status.provider) >
236 static_cast<std::uint8_t>(GpuAudioProvider::Cpu) ||
237 static_cast<int>(status.fallback_policy) < 0 ||
238 static_cast<int>(status.fallback_policy) > static_cast<int>(MissPolicy::CpuFallback) ||
239 static_cast<std::uint8_t>(status.recovery_reason) >
240 static_cast<std::uint8_t>(Reason::SustainedDeadlineMisses) ||
241 static_cast<std::uint8_t>(status.completion_mode) >
242 static_cast<std::uint8_t>(GpuAudioCompletionMode::TimedWaitAny) ||
243 static_cast<std::uint8_t>(status.shadow_mode) >
244 static_cast<std::uint8_t>(GpuAudioShadowMode::Worker))
245 return {Error::InvalidEnumValue};
246
247 // A latched recovery always carries the sequence it latched at.
248 if ((status.recovery_reason == Reason::None) != (status.recovery_sequence == UINT64_MAX))
249 return {Error::RecoverySequenceMismatch};
250
251 if (status.shadow_mode == GpuAudioShadowMode::None &&
252 (status.shadow_delivered_blocks != 0 || status.shadow_late_blocks != 0 ||
253 status.shadow_double_miss_blocks != 0 || status.shadow_inline_cost_pct != 0.0f))
254 return {Error::ShadowCountsWithoutShadow};
255
256 // Terminal counts are per admitted block, so the GPU and CPU-fallback
257 // dispositions cannot exceed the delivery counters that count the same
258 // blocks, and the total must be representable.
259 std::uint64_t terminal_total = 0;
260 for (const auto count : status.terminal_counts) {
261 if (count > UINT64_MAX - terminal_total)
262 return {Error::TerminalCountsInconsistent};
263 terminal_total += count;
264 }
265 // GpuAudioTerminalDisposition::GpuDelivered and ::CpuFallback; the enum is
266 // declared later, in gpu_audio_program.hpp, which asserts these indices.
267 const auto gpu_delivered = status.terminal_counts[1];
268 const auto cpu_fallback = status.terminal_counts[2];
269 if (gpu_delivered > status.produced_blocks || cpu_fallback > status.fallback_blocks)
270 return {Error::TerminalCountsInconsistent};
271
272 // A CPU provider has no GPU kernel and never opens a GPU delivery epoch.
273 if (status.provider == GpuAudioProvider::Cpu &&
274 (status.gpu_kernel_available || status.epoch != 0))
275 return {Error::CpuProviderWithGpuState};
276
277 if (status.provider_state == State::Uninitialized) {
278 if (status.recovery_reason != Reason::None)
279 return {Error::UninitializedStateHasRecovery};
280 if (status.selected_engine != GpuAudioEngine::Unknown ||
281 status.provider != GpuAudioProvider::Unknown || status.sample_rate != 0 ||
282 status.block_size != 0 || status.latency_samples != 0 ||
283 status.prepared_lead_blocks != 0 || status.fallback_available ||
284 status.diagnostics_available)
285 return {Error::UninitializedStateHasPreparation};
286 return {};
287 }
288
289 if (status.sample_rate == 0 || status.block_size == 0)
290 return {Error::PreparedShapeMissing};
291 if (status.provider_state == State::Ready && status.selected_engine == GpuAudioEngine::Unknown)
292 return {Error::ReadyWithoutEngine};
293 if (status.selected_engine == GpuAudioEngine::Gpu &&
294 (status.provider == GpuAudioProvider::Unknown || status.provider == GpuAudioProvider::Cpu))
295 return {Error::GpuEngineWithoutProvider};
296 // A GPU provider may stay identified while the node runs on the CPU (for
297 // example after sustained deadline misses, with periodic GPU probes), so a
298 // CPU engine does not by itself rule out a GPU provider.
299 if ((status.provider_state == State::Degraded || status.provider_state == State::Unavailable) &&
300 status.selected_engine == GpuAudioEngine::Gpu)
301 return {Error::DegradedOrUnavailableOnGpu};
302 if ((status.recovery_reason == Reason::ProviderLost ||
303 status.recovery_reason == Reason::ProviderUnresponsive) &&
304 status.provider_state != State::Unavailable)
305 return {Error::LostProviderNotUnavailable};
306 if (status.recovery_reason == Reason::SustainedDeadlineMisses &&
307 status.provider_state != State::Degraded)
308 return {Error::SustainedMissesNotDegraded};
309 // Every other latched cause fences GPU delivery until a reprime or a new
310 // preparation, leaving the CPU fallback carrying the stream: Degraded, or
311 // Unavailable when the device was lost after the cause latched. A
312 // re-acquire is informational and keeps the new provider's own state.
313 if ((status.recovery_reason == Reason::SequenceGap ||
314 status.recovery_reason == Reason::InputSaturated ||
315 status.recovery_reason == Reason::ProviderFailure ||
316 status.recovery_reason == Reason::InvalidCallback ||
317 status.recovery_reason == Reason::OfflineFence) &&
318 status.provider_state == State::Ready)
319 return {Error::FencingCauseReportedReady};
320 // A stamped node (one that names a delivery epoch) delivers only while
321 // that epoch is active; otherwise it is fenced. Unstamped paths report
322 // epoch zero and are not constrained here.
323 if (status.epoch != 0 && !status.delivery_epoch_active && status.provider_state == State::Ready)
324 return {Error::ReadyWithoutDeliveryEpoch};
325 if (status.fallback_policy == MissPolicy::CpuFallback && !status.fallback_available)
326 return {Error::FallbackUnavailable};
327 // A re-acquire is a counted success that left a provider able to deliver.
328 if (status.reacquire_successes > status.reacquire_attempts)
329 return {Error::ReacquireSuccessesExceedAttempts};
330 if (status.last_reacquire_to_gpu_ns != 0 && status.reacquire_successes == 0)
331 return {Error::ReacquireTimingWithoutSuccess};
332 if (status.recovery_reason == Reason::ProviderReacquired) {
333 if (status.reacquire_successes == 0)
334 return {Error::ReacquiredWithoutSuccess};
335 if (status.provider_state == State::Unavailable)
336 return {Error::ReacquiredNotDelivering};
337 }
338 // The GPU engine delivers only through a prepared kernel; every producer
339 // that selects it reads the kernel from the same health sample. Checked
340 // last, so every earlier error, the re-acquire rules included, wins.
341 if (status.selected_engine == GpuAudioEngine::Gpu && !status.gpu_kernel_available)
342 return {Error::GpuEngineWithoutKernel};
343 return {};
344}
345
346} // namespace pulp::gpu_audio
Definition flow_pans.hpp:19
GpuAudioRecoveryPolicy
Whether a node may re-acquire a lost provider on its own.
Definition gpu_audio_capability.hpp:39
@ AutoReacquire
Definition gpu_audio_capability.hpp:41
@ Manual
Definition gpu_audio_capability.hpp:40
constexpr GpuAudioCapabilityValidation validate_gpu_audio_capability(const GpuAudioCapabilityReport &capability) noexcept
Validate a capability snapshot.
Definition gpu_audio_capability.hpp:121
GpuAudioExecutionPath
The transport path selected for a prepared audio node.
Definition gpu_audio_capability.hpp:10
@ Staged
Definition gpu_audio_capability.hpp:12
@ Unavailable
Definition gpu_audio_capability.hpp:11
@ Cpu
A prepared CPU implementation with no GPU provider resources.
Definition gpu_audio_capability.hpp:16
@ SharedMemory
Definition gpu_audio_capability.hpp:13
constexpr GpuAudioStatusValidation validate_gpu_audio_status(const GpuAudioStatus &status) noexcept
Validate a status snapshot taken at a quiescent point.
Definition gpu_audio_capability.hpp:222
GpuAudioStatusError
Why a host-visible status snapshot is inconsistent.
Definition gpu_audio_capability.hpp:176
@ ReacquiredNotDelivering
Definition gpu_audio_capability.hpp:196
@ PreparedShapeMissing
Definition gpu_audio_capability.hpp:183
@ ShadowCountsWithoutShadow
Definition gpu_audio_capability.hpp:190
@ LostProviderNotUnavailable
Definition gpu_audio_capability.hpp:187
@ UninitializedStateHasRecovery
Definition gpu_audio_capability.hpp:182
@ GpuEngineWithoutProvider
Definition gpu_audio_capability.hpp:185
@ CpuProviderWithGpuState
Definition gpu_audio_capability.hpp:189
@ GpuEngineWithoutKernel
Definition gpu_audio_capability.hpp:201
@ TerminalCountsInconsistent
Definition gpu_audio_capability.hpp:191
@ SchemaVersionMismatch
Definition gpu_audio_capability.hpp:178
@ DegradedOrUnavailableOnGpu
Definition gpu_audio_capability.hpp:186
@ None
Definition gpu_audio_capability.hpp:177
@ ReadyWithoutEngine
Definition gpu_audio_capability.hpp:184
@ UninitializedStateHasPreparation
Definition gpu_audio_capability.hpp:181
@ SustainedMissesNotDegraded
Definition gpu_audio_capability.hpp:188
@ ReacquireSuccessesExceedAttempts
Definition gpu_audio_capability.hpp:194
@ RecoverySequenceMismatch
Definition gpu_audio_capability.hpp:180
@ ReacquireTimingWithoutSuccess
Definition gpu_audio_capability.hpp:197
@ ReadyWithoutDeliveryEpoch
Definition gpu_audio_capability.hpp:207
@ FencingCauseReportedReady
Definition gpu_audio_capability.hpp:204
@ ReacquiredWithoutSuccess
Definition gpu_audio_capability.hpp:195
GpuAudioRecoveryReason
First latched reason that a node entered recovery.
Definition gpu_audio_status.hpp:40
GpuAudioEligibility
Eligibility of the configured transport path.
Definition gpu_audio_capability.hpp:32
@ Eligible
Definition gpu_audio_capability.hpp:34
@ Unavailable
Definition gpu_audio_capability.hpp:33
MissPolicy
What the transport does for a block when the GPU result is not ready in time (the worker fell behind,...
Definition gpu_audio_node.hpp:12
@ CpuFallback
Run the node's CPU fallback for the missed block.
Definition gpu_audio_node.hpp:38
@ Silence
Output silence for the missed block (+ telemetry).
Definition gpu_audio_node.hpp:15
GpuAudioCapabilityError
Why a capability snapshot is not self-consistent.
Definition gpu_audio_capability.hpp:74
@ InvalidEnumValue
Definition gpu_audio_capability.hpp:76
@ PreparedPathUnavailable
Definition gpu_audio_capability.hpp:78
@ UnpreparedStateHasPreparation
Definition gpu_audio_capability.hpp:77
@ FallbackUnavailable
Definition gpu_audio_capability.hpp:84
@ None
Definition gpu_audio_capability.hpp:75
@ PreparedPathIneligible
Definition gpu_audio_capability.hpp:79
@ SharedLeadMissing
Definition gpu_audio_capability.hpp:83
@ CpuPathWithGpuKernel
Definition gpu_audio_capability.hpp:82
@ CpuProviderOnGpuPath
Definition gpu_audio_capability.hpp:81
@ CpuPathWithoutCpuProvider
Definition gpu_audio_capability.hpp:80
GpuAudioProvider
Provider identity when the selected path can establish it without exposing backend handles.
Definition gpu_audio_capability.hpp:21
@ Cpu
A CPU implementation with no GPU provider.
Definition gpu_audio_capability.hpp:27
@ Dawn
Definition gpu_audio_capability.hpp:23
@ Unknown
Definition gpu_audio_capability.hpp:22
@ Metal
Definition gpu_audio_capability.hpp:24
GpuAudioEngine
The engine a host asked the audio provider to use.
Definition gpu_audio_status.hpp:16
@ Gpu
Definition gpu_audio_status.hpp:19
@ Unknown
Definition gpu_audio_status.hpp:17
@ Worker
Definition gpu_audio_status.hpp:73
@ None
Definition gpu_audio_status.hpp:71
GpuAudioProviderState
Lifecycle state suitable for UI, trace, and host diagnostics.
Definition gpu_audio_status.hpp:28
@ TimedWaitAny
Definition gpu_audio_status.hpp:64
Backend-neutral, allocation-free capability snapshot for installed SDK consumers.
Definition gpu_audio_capability.hpp:46
GpuAudioRecoveryPolicy recovery_policy
The recovery policy in effect, not the one configured: a transport configured for AutoReacquire repor...
Definition gpu_audio_capability.hpp:67
std::uint32_t prepared_latency_blocks
Definition gpu_audio_capability.hpp:60
GpuAudioEligibility eligibility
Definition gpu_audio_capability.hpp:49
bool gpu_kernel_available
Definition gpu_audio_capability.hpp:63
std::uint32_t prepared_lead_blocks
Definition gpu_audio_capability.hpp:53
GpuAudioProvider provider
Definition gpu_audio_capability.hpp:48
GpuAudioExecutionPath path
Definition gpu_audio_capability.hpp:47
bool prepared
Definition gpu_audio_capability.hpp:54
MissPolicy fallback_policy
Definition gpu_audio_capability.hpp:50
bool diagnostics_available
Definition gpu_audio_capability.hpp:56
bool fallback_available
Definition gpu_audio_capability.hpp:55
Definition gpu_audio_capability.hpp:87
constexpr bool accepted() const noexcept
Definition gpu_audio_capability.hpp:90
GpuAudioCapabilityError error
Definition gpu_audio_capability.hpp:88
Definition gpu_audio_capability.hpp:210
constexpr bool accepted() const noexcept
Definition gpu_audio_capability.hpp:213
GpuAudioStatusError error
Definition gpu_audio_capability.hpp:211
Versioned, allocation-free status shared by native hosts and UI adapters.
Definition gpu_audio_status.hpp:80
static constexpr std::uint32_t kSchemaVersion
Definition gpu_audio_status.hpp:81