MayaFlux 0.5.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 dispatch_core_dependency(dependency_params.stages);
66 return output_type {};
67 }
68
69 if (!ensure_gpu_ready()) {
70 error<std::runtime_error>(
73 std::source_location::current(),
74 "GpuExecutionContext: GPU initialisation failed");
75 }
76
77 auto [ch_copies, structure_info] = extract_inputs(input);
78
80 switch (ctx.mode) {
82 raw = dispatch_core_chained(ch_copies, structure_info, ctx);
83 break;
85 raw = dispatch_core_chained_indirect(ch_copies, structure_info, ctx);
86 break;
87 default:
88 raw = dispatch_core(ch_copies, structure_info);
89 break;
90 }
91
92 return collect_gpu_outputs(raw, ch_copies, structure_info);
93 }
94
95protected:
96 /**
97 * @brief Extract channel data and structure metadata from the input Datum.
98 *
99 * Calls extract_structured_native first to obtain native-typed spans without
100 * any conversion, then resolves the native element type from the first span's
101 * active DataSpanVariant alternative (which is already determined by visiting
102 * the source variants -- no separate original_type inspection needed).
103 *
104 * - float / uint8_t / uint16_t / uint32_t: stages raw bytes natively via
105 * flatten_native_variants_to_staging. Returns ({}, structure_info).
106 * - double / complex / anything else: converts spans to vector<vector<double>>
107 * for the standard double staging path. Unchanged from previous behaviour.
108 *
109 * Override to return ({}, {}) when channel extraction is not needed
110 * (e.g. image-only shaders that stage via on_before_gpu_dispatch).
111 */
112 virtual std::pair<std::vector<std::vector<double>>, DataStructureInfo>
114 {
115 auto info = OperationHelper::get_structure_info(const_cast<input_type&>(input));
116
117 const std::type_index native_type = [&]() -> std::type_index {
118 if constexpr (std::is_same_v<
119 std::decay_t<decltype(input.data)>,
120 std::shared_ptr<Kakshya::SignalSourceContainer>>) {
121 if (input.data)
122 return input.data->value_element_type();
123 } else if constexpr (std::is_same_v<
124 std::decay_t<decltype(input.data)>,
125 std::vector<Kakshya::DataVariant>>) {
126 if (!input.data.empty())
127 return Kakshya::FrameView(OperationHelper::extract_native_data(input.data[0])).element_type();
128 }
129 return typeid(double);
130 }();
131
132 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);
133
134 if (is_native_non_double) {
135 if constexpr (std::is_same_v<
136 std::decay_t<decltype(input.data)>,
137 std::vector<Kakshya::DataVariant>>) {
139 } else if constexpr (std::is_same_v<
140 std::decay_t<decltype(input.data)>,
141 std::shared_ptr<Kakshya::SignalSourceContainer>>) {
142 flatten_native_variants_to_staging(input.data->get_data(), info);
143 }
144 return { {}, std::move(info) };
145 }
146
147 auto [spans, double_info] = OperationHelper::extract_structured_double(
148 const_cast<input_type&>(input));
149
150 std::vector<std::vector<double>> channels(spans.size());
151 for (size_t c = 0; c < spans.size(); ++c)
152 channels[c].assign(spans[c].begin(), spans[c].end());
153 return { std::move(channels), std::move(double_info) };
154 }
155
156 /**
157 * @brief Reconstruct Datum<OutputType> from a GpuChannelResult.
158 *
159 * Branches on structure_info.original_type:
160 *
161 * - Non-double native types (float, uint8_t, uint16_t, uint32_t):
162 * reads raw bytes directly from the first OUTPUT binding via download_binding
163 * rather than the float readback path, then packs them into a DataVariant
164 * in the correct native type. No float reinterpretation of pixel bytes.
165 *
166 * - Double / complex / other: reads raw.primary as float, widens to double
167 * per channel, delegates to reconstruct_from_double. Unchanged from
168 * previous behaviour.
169 *
170 * Override to perform custom readback interpretation (e.g. image containers).
171 */
173 const GpuChannelResult& raw,
174 const std::vector<std::vector<double>>& channels,
175 const DataStructureInfo& structure_info)
176 {
177 output_type result;
178
179 const auto& ot = structure_info.original_type;
180 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>));
181
182 if (is_native_non_double) {
183 const size_t out_idx = find_first_output_index();
184 const size_t allocated = m_resources.buffer_allocated_bytes(dispatch_key(), out_idx);
185 if (allocated > 0) {
186 std::vector<uint8_t> raw_bytes(allocated);
187 download_binding(out_idx, raw_bytes.data(), allocated);
188
189 auto native_variant = OperationHelper::reconstruct_from_double<Kakshya::DataVariant>(
190 { std::vector<double>(allocated / sizeof(double), 0.0) },
191 structure_info);
192 std::visit([&](auto& vec) {
193 using V = typename std::decay_t<decltype(vec)>::value_type;
194 vec.resize(allocated / sizeof(V));
195 std::memcpy(vec.data(), raw_bytes.data(), allocated);
196 },
197 native_variant);
198
199 if constexpr (std::is_same_v<OutputType, std::vector<Kakshya::DataVariant>>) {
200 result.data = { std::move(native_variant) };
201 } else if constexpr (std::is_same_v<OutputType, Kakshya::DataVariant>) {
202 result.data = std::move(native_variant);
203 }
204 }
205 for (const auto& [idx, bytes] : raw.aux)
206 result.metadata["gpu_output_" + std::to_string(idx)] = bytes;
207 return result;
208 }
209
210 const size_t total = std::accumulate(channels.begin(), channels.end(), size_t { 0 },
211 [](size_t s, const auto& ch) { return s + ch.size(); });
212 if (!raw.primary.empty() && !channels.empty() && raw.primary.size() >= total) {
213 size_t offset = 0;
214 std::vector<std::vector<double>> result_ch(channels.size());
215 for (size_t c = 0; c < channels.size(); ++c) {
216 result_ch[c].resize(channels[c].size());
217 for (size_t i = 0; i < channels[c].size(); ++i)
218 result_ch[c][i] = static_cast<double>(raw.primary[offset++]);
219 }
220 result = Datum<OutputType>(
221 OperationHelper::reconstruct_from_double<OutputType>(result_ch, structure_info));
222 }
223 for (const auto& [idx, bytes] : raw.aux)
224 result.metadata["gpu_output_" + std::to_string(idx)] = bytes;
225 return result;
226 }
227};
228
229} // namespace MayaFlux::Yantra
Core::GlobalInputConfig input
Definition Config.cpp:38
float offset
Zero-copy typed view over one frame of container storage.
Definition NDData.hpp:621
void download_binding(size_t index, void *dest, size_t byte_size)
Read back a specific binding into a caller-provided destination.
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 DataStructureInfo get_structure_info(T &compute_data)
Populate DataStructureInfo from a Datum without extracting spans.
static Kakshya::DataSpanVariant extract_native_data(const Kakshya::DataVariant &variant)
Extract a single DataVariant as a type-erased span without conversion.
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.
Metadata about data structure for reconstruction.
T data
The actual computation data.
Definition DataIO.hpp:25
std::unordered_map< std::string, std::any > metadata
Associated metadata.
Definition DataIO.hpp:28
Input/Output container for computation pipeline data flow with structure preservation.
Definition DataIO.hpp:24
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...