MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
GpuExecutionContext.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "GpuDispatchCore.hpp"
4
5namespace MayaFlux::Yantra {
6
7/**
8 * @class GpuExecutionContext
9 * @brief Type-parameterised shell over GpuDispatchCore.
10 *
11 * Handles the two type-aware boundary steps:
12 * 1. Extracting input data for dispatch_core — overridable via extract_inputs().
13 * 2. Reconstructing a Datum<OutputType> — overridable via collect_gpu_outputs().
14 *
15 * All resource management, buffer staging, dispatch orchestration, and
16 * virtual override points live in GpuDispatchCore and are compiled once
17 * in GpuDispatchCore.cpp.
18 *
19 * Subclasses override GpuDispatchCore virtuals (declare_buffer_bindings,
20 * on_before_gpu_dispatch, prepare_gpu_inputs, calculate_dispatch_size)
21 * directly;
22 * Subclasses that do not operate on numeric channels (e.g. image-only shaders)
23 * override extract_inputs() to return empty channels and override
24 * collect_gpu_outputs() to pull from get_output_image() instead of the float
25 * readback.
26 *
27 * @tparam InputType ComputeData type accepted.
28 * @tparam OutputType ComputeData type produced.
29 */
30template <ComputeData InputType = std::vector<Kakshya::DataVariant>,
31 ComputeData OutputType = InputType>
33public:
36
38 : GpuDispatchCore(std::move(config))
39 {
40 }
41
42 ~GpuExecutionContext() override = default;
43
48
49 /**
50 * @brief Dispatch to GPU and reconstruct a typed output Datum.
51 *
52 * Routes to dispatch_core_chained for CHAINED mode; all other modes
53 * use dispatch_core. Both paths are defined in GpuDispatchCore.cpp.
54 *
55 * @param input Input Datum to process.
56 * @param ctx ExecutionContext; CHAINED mode requires ChainedParams, CHAINED_INDIRECT requires
57 * ChainedIndirectParams, DEPENDENCY requires DependencyParams in parameters.
58 * @throws std::runtime_error If GPU initialisation fails.
59 */
61 {
63 const auto& dependency_params = safe_variant_get_or_throw<DependencyParams>(ctx.parameters,
64 "GpuExecutionContext: DEPENDENCY mode requires DependencyParams");
65
66 if (dependency_params.async) {
67 output_type result;
68 result.set_metadata("gpu_fence", dispatch_core_dependency_async(dependency_params.stages));
69 return result;
70 }
71
72 dispatch_core_dependency(dependency_params.stages);
73 return output_type {};
74 }
75
76 if (!ensure_gpu_ready()) {
77 error<std::runtime_error>(
80 std::source_location::current(),
81 "GpuExecutionContext: GPU initialisation failed");
82 }
83
84 auto [ch_copies, structure_info] = extract_inputs(input);
85
87 switch (ctx.mode) {
89 raw = dispatch_core_chained(ch_copies, structure_info, ctx);
90 break;
92 raw = dispatch_core_chained_indirect(ch_copies, structure_info, ctx);
93 break;
94 default:
95 raw = dispatch_core(ch_copies, structure_info);
96 break;
97 }
98
99 return collect_gpu_outputs(raw, ch_copies, structure_info);
100 }
101
102protected:
103 /**
104 * @brief Extract channel data and structure metadata from the input Datum.
105 *
106 * Calls extract_structured_native first to obtain native-typed spans without
107 * any conversion, then resolves the native element type from the first span's
108 * active DataSpanVariant alternative (which is already determined by visiting
109 * the source variants -- no separate original_type inspection needed).
110 *
111 * - float / uint8_t / uint16_t / uint32_t: stages raw bytes natively via
112 * flatten_native_variants_to_staging. Returns ({}, structure_info).
113 * - double / complex / anything else: converts spans to vector<vector<double>>
114 * for the standard double staging path. Unchanged from previous behaviour.
115 *
116 * Override to return ({}, {}) when channel extraction is not needed
117 * (e.g. image-only shaders that stage via on_before_gpu_dispatch).
118 */
119 virtual std::pair<std::vector<std::vector<double>>, DataStructureInfo>
121 {
122 auto info = OperationHelper::get_structure_info(const_cast<input_type&>(input));
123
124 const std::type_index native_type = [&]() -> std::type_index {
125 if constexpr (std::is_same_v<
126 std::decay_t<decltype(input.data)>,
127 std::shared_ptr<Kakshya::SignalSourceContainer>>) {
128 if (input.data)
129 return input.data->value_element_type();
130 } else if constexpr (std::is_same_v<
131 std::decay_t<decltype(input.data)>,
132 std::vector<Kakshya::DataVariant>>) {
133 if (!input.data.empty())
134 return Kakshya::FrameView(OperationHelper::extract_native_data(input.data[0])).element_type();
135 }
136 return typeid(double);
137 }();
138
139 const bool is_native_non_double = native_type == typeid(float) || native_type == typeid(uint8_t) || native_type == typeid(uint16_t) || native_type == typeid(uint32_t);
140
141 if (is_native_non_double) {
142 if constexpr (std::is_same_v<
143 std::decay_t<decltype(input.data)>,
144 std::vector<Kakshya::DataVariant>>) {
146 } else if constexpr (std::is_same_v<
147 std::decay_t<decltype(input.data)>,
148 std::shared_ptr<Kakshya::SignalSourceContainer>>) {
149 flatten_native_variants_to_staging(input.data->get_data(), info);
150 }
151 return { {}, std::move(info) };
152 }
153
154 auto [spans, double_info] = OperationHelper::extract_structured_double(
155 const_cast<input_type&>(input));
156
157 std::vector<std::vector<double>> channels(spans.size());
158 for (size_t c = 0; c < spans.size(); ++c)
159 channels[c].assign(spans[c].begin(), spans[c].end());
160 return { std::move(channels), std::move(double_info) };
161 }
162
163 /**
164 * @brief Reconstruct Datum<OutputType> from a GpuChannelResult.
165 *
166 * Branches on structure_info.original_type:
167 *
168 * - Non-double native types (float, uint8_t, uint16_t, uint32_t):
169 * reads raw bytes directly from the first OUTPUT binding via download_binding
170 * rather than the float readback path, then packs them into a DataVariant
171 * in the correct native type. No float reinterpretation of pixel bytes.
172 *
173 * - Double / complex / other: reads raw.primary as float, widens to double
174 * per channel, delegates to reconstruct_from_double. Unchanged from
175 * previous behaviour.
176 *
177 * Override to perform custom readback interpretation (e.g. image containers).
178 */
180 const GpuChannelResult& raw,
181 const std::vector<std::vector<double>>& channels,
182 const DataStructureInfo& structure_info)
183 {
184 output_type result;
185
186 const auto& ot = structure_info.original_type;
187 const bool is_native_non_double = ot == std::type_index(typeid(std::vector<float>)) || ot == std::type_index(typeid(std::vector<uint8_t>)) || ot == std::type_index(typeid(std::vector<uint16_t>)) || ot == std::type_index(typeid(std::vector<uint32_t>));
188
189 if (is_native_non_double) {
190 const size_t out_idx = find_first_output_index();
191 const size_t allocated = m_resources.buffer_allocated_bytes(dispatch_key(), out_idx);
192 if (allocated > 0) {
193 std::vector<uint8_t> raw_bytes(allocated);
194 download_binding(out_idx, raw_bytes.data(), allocated);
195
196 auto native_variant = OperationHelper::reconstruct_from_double<Kakshya::DataVariant>(
197 { std::vector<double>(allocated / sizeof(double), 0.0) },
198 structure_info);
199 std::visit([&](auto& vec) {
200 using V = typename std::decay_t<decltype(vec)>::value_type;
201 vec.resize(allocated / sizeof(V));
202 std::memcpy(vec.data(), raw_bytes.data(), allocated);
203 },
204 native_variant);
205
206 if constexpr (std::is_same_v<OutputType, std::vector<Kakshya::DataVariant>>) {
207 result.data = { std::move(native_variant) };
208 } else if constexpr (std::is_same_v<OutputType, Kakshya::DataVariant>) {
209 result.data = std::move(native_variant);
210 }
211 }
212 for (const auto& [idx, bytes] : raw.aux)
213 result.metadata["gpu_output_" + std::to_string(idx)] = bytes;
214 return result;
215 }
216
217 const size_t total = std::accumulate(channels.begin(), channels.end(), size_t { 0 },
218 [](size_t s, const auto& ch) { return s + ch.size(); });
219 if (!raw.primary.empty() && !channels.empty() && raw.primary.size() >= total) {
220 size_t offset = 0;
221 std::vector<std::vector<double>> result_ch(channels.size());
222 for (size_t c = 0; c < channels.size(); ++c) {
223 result_ch[c].resize(channels[c].size());
224 for (size_t i = 0; i < channels[c].size(); ++i)
225 result_ch[c][i] = static_cast<double>(raw.primary[offset++]);
226 }
227 result = Datum<OutputType>(
228 OperationHelper::reconstruct_from_double<OutputType>(result_ch, structure_info));
229 }
230 for (const auto& [idx, bytes] : raw.aux)
231 result.metadata["gpu_output_" + std::to_string(idx)] = bytes;
232 return result;
233 }
234};
235
236} // namespace MayaFlux::Yantra
uint64_t offset
Definition Composite.cpp:10
Core::GlobalInputConfig input
Definition Config.cpp:42
bool size
uint32_t total
uint32_t channels
Zero-copy typed view over one frame of container storage.
Definition NDData.hpp:654
void download_binding(size_t index, void *dest, size_t byte_size)
Read back a specific binding into a caller-provided destination.
Portal::Graphics::FenceID dispatch_core_dependency_async(const std::vector< DependencyStage > &stages)
Non-blocking variant of dispatch_core_dependency.
const std::string & dispatch_key() const
The key used for this context's GpuResourceManager unit.
void flatten_native_variants_to_staging(const std::vector< Kakshya::DataVariant > &variants, const DataStructureInfo &structure_info)
Flatten native-typed DataVariant channels into m_native_staging_bytes without any conversion.
GpuChannelResult dispatch_core(const std::vector< std::vector< double > > &channels, const DataStructureInfo &structure_info)
Full single-pass dispatch.
bool ensure_gpu_ready()
Ensure GPU resources are initialised.
void dispatch_core_dependency(const std::vector< DependencyStage > &stages)
Multi-pipeline dependency dispatch.
GpuChannelResult dispatch_core_chained(const std::vector< std::vector< double > > &channels, const DataStructureInfo &structure_info, const ExecutionContext &ctx)
Multi-pass (chained) dispatch.
GpuChannelResult dispatch_core_chained_indirect(const std::vector< std::vector< double > > &channels, const DataStructureInfo &structure_info, const ExecutionContext &ctx)
Multi-pass dispatch where a GPU-resident indirect buffer gates each pass's workgroup count instead of...
Non-template base that owns all type-independent GPU dispatch logic.
GpuExecutionContext & operator=(const GpuExecutionContext &)=delete
virtual output_type execute(const input_type &input, const ExecutionContext &ctx)
Dispatch to GPU and reconstruct a typed output Datum.
GpuExecutionContext(const GpuExecutionContext &)=delete
virtual output_type collect_gpu_outputs(const GpuChannelResult &raw, const std::vector< std::vector< double > > &channels, const DataStructureInfo &structure_info)
Reconstruct Datum<OutputType> from a GpuChannelResult.
GpuExecutionContext(GpuExecutionContext &&)=delete
GpuExecutionContext & operator=(GpuExecutionContext &&)=delete
virtual std::pair< std::vector< std::vector< double > >, DataStructureInfo > extract_inputs(const input_type &input)
Extract channel data and structure metadata from the input Datum.
Type-parameterised shell over GpuDispatchCore.
size_t buffer_allocated_bytes(const std::string &key, size_t index) const
static Kakshya::DataSpanVariant extract_native_data(const Kakshya::DataVariant &variant)
Extract a single DataVariant as a type-erased span without conversion.
static DataStructureInfo get_structure_info(const T &compute_data)
Populate DataStructureInfo from a Datum without extracting spans.
static std::tuple< std::vector< std::span< double > >, DataStructureInfo > extract_structured_double(T &compute_data)
Extract structured double data from Datum container or direct ComputeData with automatic container ha...
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Yantra
DSP algorithms, computational units, matrix operations, Grammar.
@ CHAINED
Part of a sequential chain.
@ DEPENDENCY
Part of dependency graph.
@ CHAINED_INDIRECT
Chained dispatch where a GPU-written indirect buffer gates each pass's workgroup count.
Plain-data description of the compute shader to dispatch.
Dimensions, modality, source type, and optional Composite field schema.
T data
The actual computation data.
Definition DataIO.hpp:27
void set_metadata(const std::string &key, ValueType &&value)
Add or update metadata entry.
Definition DataIO.hpp:259
std::unordered_map< std::string, std::any > metadata
Associated metadata.
Definition DataIO.hpp:30
Input/Output container for computation pipeline data flow with structure preservation.
Definition DataIO.hpp:26
ExecutionMode mode
Execution mode controlling scheduling behavior.
ExecutionParams parameters
Optional parameters specific to the execution mode.
Context information controlling how a compute operation executes.
std::unordered_map< size_t, std::vector< uint8_t > > aux
Erased output of a GPU dispatch: reconstructed float data plus any raw auxiliary outputs keyed by bin...