MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ComputeProcessor.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "ShaderProcessor.hpp"
4
5namespace MayaFlux::Buffers {
6
7/**
8 * @struct ShaderDispatchConfig
9 * @brief Configuration for compute shader dispatch
10 */
12 uint32_t workgroup_x = 256; ///< Workgroup size X (should match shader)
13 uint32_t workgroup_y = 1;
14 uint32_t workgroup_z = 1;
15
16 enum class DispatchMode : uint8_t {
17 ELEMENT_COUNT, ///< Calculate from buffer element count
18 MANUAL, ///< Use explicit group counts
19 BUFFER_SIZE, ///< Calculate from buffer byte size
20 CUSTOM ///< User-provided calculation function
22
23 // Manual dispatch (MANUAL mode)
24 uint32_t group_count_x = 1;
25 uint32_t group_count_y = 1;
26 uint32_t group_count_z = 1;
27 uint32_t iteration_count = 1; ///< Dispatches recorded per execute cycle.
28
29 std::function<std::array<uint32_t, 3>(const std::shared_ptr<VKBuffer>&)> custom_calculator;
30
32};
33
34/**
35 * @class ComputeProcessor
36 * @brief Specialized ShaderProcessor for Compute Pipelines
37 *
38 * ComputeProcessor extends ShaderProcessor to handle the specifics of compute shader execution:
39 * - **Pipeline Creation:** Creates and manages `VKComputePipeline`.
40 * - **Dispatch Logic:** Calculates workgroup counts based on buffer size or manual configuration.
41 * - **Execution:** Records `vkCmdDispatch` commands.
42 *
43 * It inherits all shader resource management (descriptors, push constants, bindings) from
44 * ShaderProcessor, adding only what is necessary for compute dispatch.
45 *
46 * Dispatch Modes:
47 * - **ELEMENT_COUNT:** (Default) Calculates groups based on buffer element count / workgroup size.
48 * - **BUFFER_SIZE:** Calculates groups based on total buffer bytes / workgroup size.
49 * - **MANUAL:** Uses fixed group counts (x, y, z).
50 * - **CUSTOM:** Uses a user-provided lambda to calculate dispatch dimensions.
51 *
52 * Usage:
53 * // Simple usage - single buffer processor
54 * auto processor = std::make_shared<ComputeProcessor>("shaders/kernel.comp");
55 * processor->bind_buffer("input_buffer", my_buffer);
56 * my_buffer->set_default_processor(processor);
57 *
58 * // Advanced - multi-buffer with explicit bindings
59 * ComputeProcessorConfig config("shaders/complex.comp");
60 * config.bindings["input"] = ShaderBinding(0, 0);
61 * config.bindings["output"] = ShaderBinding(0, 1);
62 * config.dispatch.workgroup_x = 512;
63 *
64 * auto processor = std::make_shared<ComputeProcessor>(config);
65 * processor->bind_buffer("input", input_buffer);
66 * processor->bind_buffer("output", output_buffer);
67 *
68 * chain->add_processor(processor, input_buffer);
69 * chain->add_processor(processor, output_buffer);
70 *
71 * // With push constants
72 * struct Params { float scale; uint32_t iterations; };
73 * processor->set_push_constant_size<Params>();
74 * processor->set_push_constant_data(Params{2.0f, 100});
75 *
76 * Specialized Processors:
77 * class FFTProcessor : public ComputeProcessor {
78 * FFTProcessor() : ComputeProcessor("shaders/fft.comp") {
79 * configure_fft_bindings();
80 * }
81 *
82 * void on_attach(std::shared_ptr<Buffer> buffer) override {
83 * ComputeProcessor::on_attach(buffer);
84 * // FFT-specific setup
85 * }
86 * };
87 */
88class MAYAFLUX_API ComputeProcessor : public ShaderProcessor {
89public:
90 /**
91 * @brief Construct processor with shader path
92 * @param shader_path Path to compute shader (.comp or .spv)
93 * @param workgroup_x Workgroup size X (default 256)
94 */
95 explicit ComputeProcessor(const std::string& shader_path, uint32_t workgroup_x = 256);
96
97 /**
98 * @brief Construct processor from a generated ShaderSpec.
99 * @param spec ShaderSpec produced by ShaderSpec::Assemble::build().
100 *
101 * Delegates to ShaderProcessor(ShaderConfig(spec)) for compilation,
102 * then applies spec.workgroup_size to this processor's own
103 * ShaderDispatchConfig — workgroup sizing is a ComputeProcessor
104 * concern the shared ShaderProcessor base has no knowledge of.
105 */
107
109 {
110 cleanup();
111 }
112
113 //==========================================================================
114 // Dispatch Configuration
115 //==========================================================================
116
117 /**
118 * @brief Set workgroup size (should match shader local_size)
119 * @param x Workgroup size X
120 * @param y Workgroup size Y (default 1)
121 * @param z Workgroup size Z (default 1)
122 */
123 void set_workgroup_size(uint32_t x, uint32_t y = 1, uint32_t z = 1);
124
125 /**
126 * @brief Set dispatch mode
127 * @param mode Dispatch calculation mode
128 */
129 void set_dispatch_mode(ShaderDispatchConfig::DispatchMode mode);
130
131 /**
132 * @brief Set manual dispatch group counts
133 * @param x Group count X
134 * @param y Group count Y (default 1)
135 * @param z Group count Z (default 1)
136 */
137 void set_manual_dispatch(uint32_t x, uint32_t y = 1, uint32_t z = 1);
138
139 /**
140 * @brief Set custom dispatch calculator
141 * @param calculator Function that calculates dispatch from buffer
142 */
143 void set_custom_dispatch(std::function<std::array<uint32_t, 3>(const std::shared_ptr<VKBuffer>&)> calculator);
144
145 /**
146 * @brief Set how many dispatches are recorded per execute cycle.
147 * @param count Dispatch count. Values below 1 are clamped to 1.
148 *
149 * All iterations record into one command buffer and submit once.
150 * on_iteration runs before each; on_iteration_barrier runs between
151 * consecutive iterations. At the default of 1 the recorded command
152 * stream is identical to a single-dispatch cycle.
153 */
154 void set_iteration_count(uint32_t count);
155
156 /** @brief Dispatches recorded per execute cycle. */
157 [[nodiscard]] uint32_t get_iteration_count() const { return m_dispatch_config.iteration_count; }
158
159 /**
160 * @brief Get current dispatch configuration
161 */
162 [[nodiscard]] const ShaderDispatchConfig& get_dispatch_config() const { return m_dispatch_config; }
163
164 /**
165 * @brief Check if pipeline is created
166 */
167 bool is_pipeline_ready() const { return m_pipeline_id != Portal::Graphics::INVALID_COMPUTE_PIPELINE; }
168
169protected:
170 /**
171 * @brief Calculate dispatch size from buffer
172 * @param buffer Buffer to process
173 * @return {group_count_x, group_count_y, group_count_z}
174 *
175 * Override for custom dispatch calculation logic.
176 * Default implementation uses m_config.dispatch settings.
177 */
178 virtual std::array<uint32_t, 3> calculate_dispatch_size(const std::shared_ptr<VKBuffer>& buffer);
179
180 /**
181 * @brief Called before each iteration's push constants and dispatch.
182 * @param cmd_id Command buffer being recorded into.
183 * @param buffer Buffer under processing.
184 * @param index Zero-based iteration index.
185 * @return False to skip this iteration's dispatch.
186 *
187 * The place to rewrite descriptor bindings for ping-pong resources and
188 * to update m_push_constant_data, since push constants are re-pushed
189 * after every successful return.
190 */
191 virtual bool on_iteration(
193 const std::shared_ptr<VKBuffer>& buffer,
194 uint32_t index);
195
196 /**
197 * @brief Called after each iteration except the last.
198 * @param cmd_id Command buffer being recorded into.
199 * @param buffer Buffer under processing.
200 * @param index Zero-based index of the iteration just recorded.
201 *
202 * Default issues a compute-to-compute buffer_barrier on the attached
203 * buffer's own handle. Override when the hazard is on resources the
204 * attached buffer does not own, such as raw double-buffered state.
205 */
206 virtual void on_iteration_barrier(
208 const std::shared_ptr<VKBuffer>& buffer,
209 uint32_t index);
210
211 void initialize_pipeline(const std::shared_ptr<VKBuffer>& buffer) override;
212
213 void initialize_descriptors(const std::shared_ptr<VKBuffer>& buffer) override;
214
215 [[nodiscard]] bool tracks_pipeline_layout() const override { return true; }
216
217 void cleanup() override;
218
219private:
221
222 std::vector<uint8_t> m_push_constant_scratch; ///< Merged push constant block, reused across iterations.
223
224 void execute_shader(const std::shared_ptr<VKBuffer>& buffer) override;
225
226 Portal::Graphics::ComputePipelineID m_pipeline_id = Portal::Graphics::INVALID_COMPUTE_PIPELINE;
227};
228
229} // namespace MayaFlux::Buffers
std::shared_ptr< NetworkGeometryBuffer > buffer
uint32_t mode
uint32_t index
Definition VKDevice.cpp:122
size_t count
std::vector< uint8_t > m_push_constant_scratch
Merged push constant block, reused across iterations.
bool tracks_pipeline_layout() const override
Whether the owner builds its pipeline layout from this processor's bindings, staged descriptors and p...
const ShaderDispatchConfig & get_dispatch_config() const
Get current dispatch configuration.
bool is_pipeline_ready() const
Check if pipeline is created.
uint32_t get_iteration_count() const
Dispatches recorded per execute cycle.
Specialized ShaderProcessor for Compute Pipelines.
Abstract base class for shader-based buffer processing.
enum MayaFlux::Buffers::ShaderDispatchConfig::DispatchMode mode
std::function< std::array< uint32_t, 3 >(const std::shared_ptr< VKBuffer > &)> custom_calculator
@ CUSTOM
User-provided calculation function.
@ BUFFER_SIZE
Calculate from buffer byte size.
@ ELEMENT_COUNT
Calculate from buffer element count.
uint32_t workgroup_x
Workgroup size X (should match shader)
uint32_t iteration_count
Dispatches recorded per execute cycle.
Configuration for compute shader dispatch.
Complete declarative description of a generated compute shader.