MayaFlux 0.5.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
108 //==========================================================================
109 // Dispatch Configuration
110 //==========================================================================
111
112 /**
113 * @brief Set workgroup size (should match shader local_size)
114 * @param x Workgroup size X
115 * @param y Workgroup size Y (default 1)
116 * @param z Workgroup size Z (default 1)
117 */
118 void set_workgroup_size(uint32_t x, uint32_t y = 1, uint32_t z = 1);
119
120 /**
121 * @brief Set dispatch mode
122 * @param mode Dispatch calculation mode
123 */
124 void set_dispatch_mode(ShaderDispatchConfig::DispatchMode mode);
125
126 /**
127 * @brief Set manual dispatch group counts
128 * @param x Group count X
129 * @param y Group count Y (default 1)
130 * @param z Group count Z (default 1)
131 */
132 void set_manual_dispatch(uint32_t x, uint32_t y = 1, uint32_t z = 1);
133
134 /**
135 * @brief Set custom dispatch calculator
136 * @param calculator Function that calculates dispatch from buffer
137 */
138 void set_custom_dispatch(std::function<std::array<uint32_t, 3>(const std::shared_ptr<VKBuffer>&)> calculator);
139
140 /**
141 * @brief Set how many dispatches are recorded per execute cycle.
142 * @param count Dispatch count. Values below 1 are clamped to 1.
143 *
144 * All iterations record into one command buffer and submit once.
145 * on_iteration runs before each; on_iteration_barrier runs between
146 * consecutive iterations. At the default of 1 the recorded command
147 * stream is identical to a single-dispatch cycle.
148 */
149 void set_iteration_count(uint32_t count);
150
151 /** @brief Dispatches recorded per execute cycle. */
152 [[nodiscard]] uint32_t get_iteration_count() const { return m_dispatch_config.iteration_count; }
153
154 /**
155 * @brief Get current dispatch configuration
156 */
157 [[nodiscard]] const ShaderDispatchConfig& get_dispatch_config() const { return m_dispatch_config; }
158
159 /**
160 * @brief Check if pipeline is created
161 */
162 bool is_pipeline_ready() const { return m_pipeline_id != Portal::Graphics::INVALID_COMPUTE_PIPELINE; }
163
164protected:
165 /**
166 * @brief Calculate dispatch size from buffer
167 * @param buffer Buffer to process
168 * @return {group_count_x, group_count_y, group_count_z}
169 *
170 * Override for custom dispatch calculation logic.
171 * Default implementation uses m_config.dispatch settings.
172 */
173 virtual std::array<uint32_t, 3> calculate_dispatch_size(const std::shared_ptr<VKBuffer>& buffer);
174
175 /**
176 * @brief Called before each iteration's push constants and dispatch.
177 * @param cmd_id Command buffer being recorded into.
178 * @param buffer Buffer under processing.
179 * @param index Zero-based iteration index.
180 * @return False to skip this iteration's dispatch.
181 *
182 * The place to rewrite descriptor bindings for ping-pong resources and
183 * to update m_push_constant_data, since push constants are re-pushed
184 * after every successful return.
185 */
186 virtual bool on_iteration(
188 const std::shared_ptr<VKBuffer>& buffer,
189 uint32_t index);
190
191 /**
192 * @brief Called after each iteration except the last.
193 * @param cmd_id Command buffer being recorded into.
194 * @param buffer Buffer under processing.
195 * @param index Zero-based index of the iteration just recorded.
196 *
197 * Default issues a compute-to-compute buffer_barrier on the attached
198 * buffer's own handle. Override when the hazard is on resources the
199 * attached buffer does not own, such as raw double-buffered state.
200 */
201 virtual void on_iteration_barrier(
203 const std::shared_ptr<VKBuffer>& buffer,
204 uint32_t index);
205
206 void initialize_pipeline(const std::shared_ptr<VKBuffer>& buffer) override;
207
208 void initialize_descriptors(const std::shared_ptr<VKBuffer>& buffer) override;
209
210 void cleanup() override;
211
212private:
214
215 std::vector<uint8_t> m_push_constant_scratch; ///< Coalesced push constant bindings, reused across iterations.
216
217 void execute_shader(const std::shared_ptr<VKBuffer>& buffer) override;
218
219 Portal::Graphics::ComputePipelineID m_pipeline_id = Portal::Graphics::INVALID_COMPUTE_PIPELINE;
220};
221
222} // namespace MayaFlux::Buffers
uint32_t index
Definition VKDevice.cpp:142
size_t count
std::vector< uint8_t > m_push_constant_scratch
Coalesced push constant bindings, reused across iterations.
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.