18 if (preferred_frame && !current_frame)
21 if (preferred_sample && current_frame)
24 if ((preferred_sample && current_sample) || (preferred_frame && current_frame))
33 if (preferred_sample && current_gpu)
35 if (preferred_gpu && current_cpu)
38 if (preferred_cpu && current_gpu && !current_frame)
43 bool preferred_par = preferred &
PARALLEL;
45 bool current_par = current &
PARALLEL;
47 if ((preferred_seq && current_par) || (preferred_par && current_seq)) {
49 if ((preferred_sample && current_sample) || (preferred_frame && current_frame)) {
64 error<std::invalid_argument>(
67 std::source_location::current(),
68 "SAMPLE_RATE and FRAME_RATE are mutually exclusive.");
74 std::source_location::current(),
75 "CPU_PROCESS and GPU_PROCESS are mutually exclusive.");
81 std::source_location::current(),
82 "SEQUENTIAL and PARALLEL are mutually exclusive.");
88 if (buffer_type ==
"audio") {
92 if (buffer_type ==
"video" || buffer_type ==
"texture") {
99 const std::shared_ptr<Nodes::Node>& node,
100 uint64_t active_context_id,
105 while (node->is_in_snapshot_context(active_context_id) && spin_count < max_spins) {
106 if (spin_count < 10) {
107 for (
int i = 0; i < (1 << spin_count); ++i) {
108 MF_PAUSE_INSTRUCTION();
111 std::this_thread::yield();
116 if (spin_count >= max_spins) {
118 "Timeout waiting for node snapshot to complete. "
119 "Possible deadlock or very long processing time.");
130 "extract_single_sample: null node");
134 static std::atomic<uint64_t> s_context_counter { 1 };
135 uint64_t my_context_id = s_context_counter.fetch_add(1, std::memory_order_relaxed);
137 const auto state = node->m_state.load(std::memory_order_acquire);
140 double value = node->process_sample(0.F);
141 node->mark_buffer_processed();
145 bool claimed = node->try_claim_snapshot_context(my_context_id);
150 double value = node->process_sample(0.F);
151 node->restore_state();
153 if (node->is_buffer_processed()) {
154 node->request_buffer_reset();
157 node->release_snapshot_context(my_context_id);
160 }
catch (
const std::exception& e) {
161 node->release_snapshot_context(my_context_id);
163 "Error processing node: {}", e.what());
167 uint64_t active_context = node->get_active_snapshot_context();
174 double value = node->process_sample(0.F);
175 node->restore_state();
177 if (node->is_buffer_processed()) {
178 node->request_buffer_reset();
186 const std::shared_ptr<Nodes::Node>& node,
189 std::vector<double> output(num_samples);
193 "extract_multiple_samples: null node");
197 static std::atomic<uint64_t> s_context_counter { 1 };
198 uint64_t my_context_id = s_context_counter.fetch_add(1, std::memory_order_relaxed);
200 const auto state = node->m_state.load(std::memory_order_acquire);
204 for (
size_t i = 0; i < num_samples; i++) {
205 output[i] = node->process_sample(0.F);
207 node->mark_buffer_processed();
211 bool claimed = node->try_claim_snapshot_context(my_context_id);
217 for (
size_t i = 0; i < num_samples; i++) {
218 output[i] = node->process_sample(0.F);
221 node->restore_state();
223 if (node->is_buffer_processed()) {
224 node->request_buffer_reset();
227 node->release_snapshot_context(my_context_id);
229 }
catch (
const std::exception& e) {
230 node->release_snapshot_context(my_context_id);
232 "Error processing node: {}", e.what());
236 uint64_t active_context = node->get_active_snapshot_context();
244 for (
size_t i = 0; i < num_samples; i++) {
245 output[i] = node->process_sample(0.F);
247 node->restore_state();
249 if (node->is_buffer_processed()) {
250 node->request_buffer_reset();
258 const std::shared_ptr<Nodes::Node>& node,
259 std::span<double> buffer,
264 "apply_to_buffer: null node");
268 static std::atomic<uint64_t> s_context_counter { 1 };
269 uint64_t my_context_id = s_context_counter.fetch_add(1, std::memory_order_relaxed);
271 const auto state = node->m_state.load(std::memory_order_acquire);
274 for (
double& sample : buffer) {
275 sample += node->process_sample(0.F) *
mix;
277 node->mark_buffer_processed();
281 bool claimed = node->try_claim_snapshot_context(my_context_id);
287 for (
double& sample : buffer) {
288 sample += node->process_sample(0.F) *
mix;
291 node->restore_state();
293 if (node->is_buffer_processed()) {
294 node->request_buffer_reset();
297 node->release_snapshot_context(my_context_id);
299 }
catch (
const std::exception& e) {
300 node->release_snapshot_context(my_context_id);
302 "Error processing node: {}", e.what());
305 uint64_t active_context = node->get_active_snapshot_context();
312 for (
double& sample : buffer) {
313 sample += node->process_sample(0.F) *
mix;
315 node->restore_state();
317 if (node->is_buffer_processed()) {
318 node->request_buffer_reset();
324 const std::shared_ptr<Nodes::Network::NodeNetwork>& network,
325 std::string_view name)
327 auto* op = network->get_operator();
330 "Network '{}' has no operator", name);
337 "Network '{}' operator '{}' is not a GraphicsOperator",
338 name, op->get_type_name());
342 auto vertex_data = graphics_op->get_vertex_data();
343 size_t vertex_count = graphics_op->get_vertex_count();
345 if (vertex_data.empty() || vertex_count == 0) {
347 "Network '{}' has no vertex data this frame", name);
352 .vertex_data = vertex_data,
353 .vertex_count = vertex_count,
354 .layout = graphics_op->get_vertex_layout()
359 const std::shared_ptr<Nodes::Network::NodeNetwork>& network,
360 std::string_view name)
362 auto buf = network->get_audio_buffer();
363 if (!buf || buf->empty()) {
365 "Network '{}' has no audio buffer this cycle", name);
368 return { buf->data(), buf->size() };
#define MF_RT_WARN(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_RT_TRACE(comp, ctx,...)
Operator that produces GPU-renderable geometry.
std::vector< double > extract_multiple_samples(const std::shared_ptr< Nodes::Node > &node, size_t num_samples)
Extract multiple samples from a node into a vector.
bool are_tokens_compatible(ProcessingToken preferred, ProcessingToken current)
Determines if two processing tokens are compatible for joint execution.
ProcessingToken
Bitfield enum defining processing characteristics and backend requirements for buffer operations.
@ GPU_PROCESS
Executes processing operations on GPU hardware.
@ SAMPLE_RATE
Processes data at audio sample rate with buffer-sized chunks.
@ CPU_PROCESS
Executes processing operations on CPU threads.
@ AUDIO_BACKEND
Standard audio processing backend configuration.
@ PARALLEL
Processes operations in parallel when possible.
@ SEQUENTIAL
Processes operations sequentially, one after another.
@ GRAPHICS_BACKEND
Standard graphics processing backend configuration.
@ FRAME_RATE
Processes data at video frame rate.
@ AUDIO_PARALLEL
High-performance audio processing with GPU acceleration.
void validate_token(ProcessingToken token)
Validates that a processing token has a valid, non-conflicting configuration.
double extract_single_sample(const std::shared_ptr< Nodes::Node > &node)
Extract a single sample from a node with proper snapshot management.
ProcessingToken get_optimal_token(const std::string &buffer_type, uint32_t system_capabilities)
Gets the optimal processing token for a given buffer type and system configuration.
void update_buffer_with_node_data(const std::shared_ptr< Nodes::Node > &node, std::span< double > buffer, double mix)
Apply node output to an existing buffer with mixing.
NetworkGpuData extract_network_gpu_data(const std::shared_ptr< Nodes::Network::NodeNetwork > &network, std::string_view name)
Extract GPU geometry data from a NodeNetwork via its GraphicsOperator.
std::span< const double > extract_network_audio_data(const std::shared_ptr< Nodes::Network::NodeNetwork > &network, std::string_view name)
Extract audio buffer data from a NodeNetwork.
bool wait_for_snapshot_completion(const std::shared_ptr< Nodes::Node > &node, uint64_t active_context_id, int max_spins)
Wait for an active snapshot context to complete using exponential backoff.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Buffers
Buffers, Managers, processors and processing chains.
@ INACTIVE
Engine is not processing this node.
std::vector< double > mix(const std::vector< std::vector< double > > &streams)
Mix multiple data streams with equal weighting.
Result of extracting GPU-ready data from a NodeNetwork operator.