MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ComputeProcessor.cpp
Go to the documentation of this file.
2
4
5namespace MayaFlux::Buffers {
6
7//==============================================================================
8// Construction
9//==============================================================================
10
11ComputeProcessor::ComputeProcessor(const std::string& shader_path, uint32_t workgroup_x)
12 : ShaderProcessor(shader_path)
13
14{
15 m_dispatch_config.workgroup_x = workgroup_x;
16}
17
18void ComputeProcessor::initialize_pipeline(const std::shared_ptr<VKBuffer>& buffer)
19{
22 "Cannot create pipeline without shader");
23 return;
24 }
25
26 auto& compute_press = Portal::Graphics::get_compute_press();
27
28 std::map<std::pair<uint32_t, uint32_t>, Portal::Graphics::DescriptorBindingInfo> unified_bindings;
29
30 const auto& descriptor_bindings = buffer->get_pipeline_context().descriptor_buffer_bindings;
31 for (const auto& binding : descriptor_bindings) {
32 unified_bindings[{ binding.set, binding.binding }] = binding;
33 }
34
35 for (const auto& [name, binding] : m_config.bindings) {
36 auto key = std::make_pair(binding.set, binding.binding);
37 if (unified_bindings.find(key) == unified_bindings.end()) {
38 unified_bindings[key] = Portal::Graphics::DescriptorBindingInfo {
39 .set = binding.set,
40 .binding = binding.binding,
41 .type = binding.type,
42 .buffer_info = {},
43 .name = name
44 };
45 }
46 }
47
48 std::map<uint32_t, std::vector<Portal::Graphics::DescriptorBindingInfo>> bindings_by_set;
49 for (const auto& [key, binding] : unified_bindings) {
50 bindings_by_set[binding.set].push_back(binding);
51 }
52
53 std::vector<std::vector<Portal::Graphics::DescriptorBindingInfo>> descriptor_sets;
54
55 descriptor_sets.reserve(bindings_by_set.size());
56 for (const auto& [set_index, set_bindings] : bindings_by_set) {
57 descriptor_sets.push_back(set_bindings);
58 }
59
60 const auto& staging = buffer->get_pipeline_context().push_constant_staging;
61 size_t push_constant_size = 0;
62
63 if (!staging.empty()) {
64 push_constant_size = staging.size();
65 } else {
66 push_constant_size = std::max(m_config.push_constant_size, m_push_constant_data.size());
67 }
68
69 m_pipeline_id = compute_press.create_pipeline(
71 descriptor_sets,
72 push_constant_size);
73
76 "Failed to create compute pipeline");
77 return;
78 }
79
81
83 "Compute pipeline created (ID: {}, {} descriptor sets, {} bytes push constants)",
84 m_pipeline_id, descriptor_sets.size(), m_config.push_constant_size);
85}
86
87void ComputeProcessor::initialize_descriptors(const std::shared_ptr<VKBuffer>& buffer)
88{
91 "Cannot allocate descriptor sets without pipeline");
92 return;
93 }
94
96
97 auto& compute_press = Portal::Graphics::get_compute_press();
98
99 m_descriptor_set_ids = compute_press.allocate_pipeline_descriptors(m_pipeline_id);
100
101 if (m_descriptor_set_ids.empty()) {
103 "Failed to allocate descriptor sets");
104 return;
105 }
106
107 update_descriptors(buffer);
109
111 "Descriptor sets initialized: {} sets", m_descriptor_set_ids.size());
112}
113
114//==============================================================================
115// Dispatch Configuration
116//==============================================================================
117
118void ComputeProcessor::set_workgroup_size(uint32_t x, uint32_t y, uint32_t z)
119{
123}
124
129
137
139 std::function<std::array<uint32_t, 3>(const std::shared_ptr<VKBuffer>&)> calculator)
140{
142 m_dispatch_config.custom_calculator = std::move(calculator);
143}
144
145std::array<uint32_t, 3> ComputeProcessor::calculate_dispatch_size(const std::shared_ptr<VKBuffer>& buffer)
146{
147 using DispatchMode = ShaderDispatchConfig::DispatchMode;
148
149 switch (m_dispatch_config.mode) {
150 case DispatchMode::MANUAL:
152
153 case DispatchMode::ELEMENT_COUNT: {
154 uint64_t element_count = 0;
155 const auto& dimensions = buffer->get_dimensions();
156
157 if (!dimensions.empty()) {
158 element_count = dimensions[0].size;
159 } else {
160 element_count = buffer->get_size_bytes() / sizeof(float);
161 }
162
163 auto groups_x = static_cast<uint32_t>(
165 return { groups_x, 1, 1 };
166 }
167
168 case DispatchMode::BUFFER_SIZE: {
169 uint64_t size_bytes = buffer->get_size_bytes();
170 auto groups_x = static_cast<uint32_t>(
172 return { groups_x, 1, 1 };
173 }
174
175 case DispatchMode::CUSTOM:
178 }
179 return { 1, 1, 1 };
180
181 default:
182 return { 1, 1, 1 };
183 }
184}
185
186void ComputeProcessor::execute_shader(const std::shared_ptr<VKBuffer>& buffer)
187{
190 "Cannot dispatch without pipeline and descriptors");
191 return;
192 }
193
194 if (m_descriptor_set_ids.empty()) {
196 "Descriptor sets not initialized");
197 return;
198 }
199
200 auto& foundry = Portal::Graphics::get_shader_foundry();
201 auto& compute_press = Portal::Graphics::get_compute_press();
202
203 auto cmd_id = foundry.begin_commands(Portal::Graphics::ShaderFoundry::CommandBufferType::COMPUTE);
204
205 m_last_command_buffer = cmd_id;
207
208 compute_press.bind_pipeline(cmd_id, m_pipeline_id);
209
210 auto& descriptor_bindings = buffer->get_pipeline_context().descriptor_buffer_bindings;
211 if (!descriptor_bindings.empty()) {
212 for (const auto& binding : descriptor_bindings) {
213 if (binding.set >= m_descriptor_set_ids.size()) {
215 "Descriptor set index {} out of range", binding.set);
216 continue;
217 }
218
219 foundry.update_descriptor_buffer(
220 m_descriptor_set_ids[binding.set],
221 binding.binding,
222 binding.type,
223 binding.buffer_info.buffer,
224 binding.buffer_info.offset,
225 binding.buffer_info.range);
226 }
227 }
228
229 if (!m_descriptor_set_ids.empty()) {
230 compute_press.bind_descriptor_sets(cmd_id, m_pipeline_id, m_descriptor_set_ids);
231 }
232
233 const auto& staging = buffer->get_pipeline_context();
234 if (!staging.push_constant_staging.empty()) {
235 compute_press.push_constants(
236 cmd_id,
238 staging.push_constant_staging.data(),
239 staging.push_constant_staging.size());
240 } else if (!m_push_constant_data.empty()) {
241 compute_press.push_constants(
242 cmd_id,
245 m_push_constant_data.size());
246 }
247
248 on_before_execute(cmd_id, buffer);
249
250 auto dispatch_size = calculate_dispatch_size(buffer);
251 compute_press.dispatch(cmd_id, dispatch_size[0], dispatch_size[1], dispatch_size[2]);
252
253 on_after_execute(cmd_id, buffer);
254
255 foundry.buffer_barrier(
256 cmd_id,
257 buffer->get_buffer(),
258 vk::AccessFlagBits::eShaderWrite,
259 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead,
260 vk::PipelineStageFlagBits::eComputeShader,
261 vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer);
262
263 foundry.submit_and_wait(cmd_id);
264}
265
267{
268 auto& foundry = Portal::Graphics::get_shader_foundry();
269 auto& compute_press = Portal::Graphics::get_compute_press();
270
272 compute_press.destroy_pipeline(m_pipeline_id);
274 }
275
277 foundry.destroy_shader(m_shader_id);
279 }
280
281 m_descriptor_set_ids.clear();
282 m_bound_buffers.clear();
283 m_initialized = false;
284}
285
286} // namespace MayaFlux::Buffers
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
void set_workgroup_size(uint32_t x, uint32_t y=1, uint32_t z=1)
Set workgroup size (should match shader local_size)
void initialize_descriptors(const std::shared_ptr< VKBuffer > &buffer) override
void execute_shader(const std::shared_ptr< VKBuffer > &buffer) override
ComputeProcessor(const std::string &shader_path, uint32_t workgroup_x=256)
Construct processor with shader path.
void initialize_pipeline(const std::shared_ptr< VKBuffer > &buffer) override
Portal::Graphics::ComputePipelineID m_pipeline_id
void set_dispatch_mode(ShaderDispatchConfig::DispatchMode mode)
Set dispatch mode.
void set_manual_dispatch(uint32_t x, uint32_t y=1, uint32_t z=1)
Set manual dispatch group counts.
virtual std::array< uint32_t, 3 > calculate_dispatch_size(const std::shared_ptr< VKBuffer > &buffer)
Calculate dispatch size from buffer.
void set_custom_dispatch(std::function< std::array< uint32_t, 3 >(const std::shared_ptr< VKBuffer > &)> calculator)
Set custom dispatch calculator.
Portal::Graphics::CommandBufferID m_last_command_buffer
std::unordered_map< std::string, std::shared_ptr< VKBuffer > > m_bound_buffers
Portal::Graphics::ShaderID m_shader_id
std::vector< uint8_t > m_push_constant_data
virtual void on_after_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr< VKBuffer > &buffer)
Called after each process callback.
virtual void on_descriptors_created()
Called after descriptor sets are created.
virtual void update_descriptors(const std::shared_ptr< VKBuffer > &buffer)
virtual bool on_before_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr< VKBuffer > &buffer)
Called before each process callback.
virtual void on_pipeline_created(Portal::Graphics::ComputePipelineID pipeline_id)
Called after pipeline is created.
std::shared_ptr< VKBuffer > m_last_processed_buffer
virtual void on_before_descriptors_create()
Called before descriptor sets are created.
std::vector< Portal::Graphics::DescriptorSetID > m_descriptor_set_ids
Abstract base class for shader-based buffer processing.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Buffers
Buffers, Managers, processors and processing chains.
constexpr ShaderID INVALID_SHADER
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.
constexpr ComputePipelineID INVALID_COMPUTE_PIPELINE
MAYAFLUX_API ComputePress & get_compute_press()
std::unordered_map< std::string, ShaderBinding > bindings
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.
uint32_t workgroup_x
Workgroup size X (should match shader)