MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ComputePress.cpp
Go to the documentation of this file.
1#include "ComputePress.hpp"
2
6
8
10
12{
13 if (s_initialized) {
15 "ComputePress already initialized (static flag)");
16 return true;
17 }
18
22 "Cannot initialize ComputePress: ShaderFoundry not initialized");
23 return false;
24 }
25
26 m_descriptor_manager = std::make_shared<Core::VKDescriptorManager>();
28
29 s_initialized = true;
30
32 "ComputePress initialized");
33 return true;
34}
35
37{
38 if (!s_initialized) {
39 return;
40 }
41
43 "ComputePress stopped");
44}
45
47{
48 if (!s_initialized) {
49 return;
50 }
51
53 "Shutting down ComputePress...");
54
57 "Cannot shutdown ComputePress: ShaderFoundry not initialized");
58 return;
59 }
60
61 auto device = m_shader_foundry->get_device();
62
63 if (!device) {
65 "Cannot shutdown ComputePress: Vulkan device is null");
66 return;
67 }
68
70
71 if (m_descriptor_manager && device) {
72 m_descriptor_manager->cleanup(device);
74 }
75
76 m_pipelines.clear();
77 m_shader_foundry = nullptr;
78
79 s_initialized = false;
80
82 "ComputePress shutdown complete");
83}
84
85//==============================================================================
86// Pipeline Creation
87//==============================================================================
88
90 ShaderID shader_id,
91 const std::vector<std::vector<DescriptorBindingInfo>>& descriptor_sets,
92 size_t push_constant_size)
93{
94 auto shader_module = m_shader_foundry->get_vk_shader_module(shader_id);
95 if (!shader_module) {
97 "Invalid shader ID: {}", shader_id);
99 }
100
101 auto stage = m_shader_foundry->get_shader_stage(shader_id);
102 if (stage != ShaderStage::COMPUTE) {
104 "Shader is not a compute shader (stage: {})", static_cast<int>(stage));
106 }
107
109 PipelineState& state = m_pipelines[id];
110 state.shader_id = shader_id;
111
112 auto device = m_shader_foundry->get_device();
113
115 m_descriptor_manager = std::make_shared<Core::VKDescriptorManager>();
116 m_descriptor_manager->initialize(device, 1024);
117 }
118
119 for (const auto& set_bindings : descriptor_sets) {
121
122 for (const auto& binding : set_bindings) {
123 layout_config.add_binding(
124 binding.binding,
125 binding.type,
126 vk::ShaderStageFlagBits::eCompute,
127 1);
128 }
129
130 state.layouts.push_back(m_descriptor_manager->create_layout(device, layout_config));
131 }
132
133 Core::ComputePipelineConfig pipeline_config;
134 pipeline_config.shader = shader_module;
135 pipeline_config.set_layouts = state.layouts;
136
137 if (push_constant_size > 0) {
138 pipeline_config.add_push_constant(
139 vk::ShaderStageFlagBits::eCompute,
140 static_cast<uint32_t>(push_constant_size));
141 }
142
143 state.pipeline = std::make_shared<Core::VKComputePipeline>();
144 if (!state.pipeline->create(device, pipeline_config)) {
146 "Failed to create compute pipeline");
147 m_pipelines.erase(id);
149 }
150
151 state.layout = state.pipeline->get_layout();
152
154 "Created compute pipeline (ID: {}, {} descriptor sets, {} bytes push constants)",
155 id, state.layouts.size(), push_constant_size);
156
157 return id;
158}
159
161 ShaderID shader_id,
162 size_t push_constant_size)
163{
164 auto reflection = m_shader_foundry->get_shader_reflection(shader_id);
165
166 std::map<uint32_t, std::vector<DescriptorBindingInfo>> bindings_by_set;
167 for (const auto& binding : reflection.descriptor_bindings) {
169 config.set = binding.set;
170 config.binding = binding.binding;
171 config.type = binding.type;
172 bindings_by_set[binding.set].push_back(config);
173 }
174
175 std::vector<std::vector<DescriptorBindingInfo>> descriptor_sets;
176 descriptor_sets.reserve(bindings_by_set.size());
177 for (const auto& [set_index, bindings] : bindings_by_set) {
178 descriptor_sets.push_back(bindings);
179 }
180
181 size_t pc_size = push_constant_size;
182 if (pc_size == 0 && !reflection.push_constant_ranges.empty()) {
183 pc_size = reflection.push_constant_ranges[0].size;
184 }
185
187 "Auto-creating pipeline: {} descriptor sets, {} bindings total",
188 descriptor_sets.size(), reflection.descriptor_bindings.size());
189
190 return create_pipeline(shader_id, descriptor_sets, pc_size);
191}
192
194{
195 auto it = m_pipelines.find(pipeline_id);
196 if (it == m_pipelines.end()) {
197 return;
198 }
199
200 auto device = m_shader_foundry->get_device();
201
202 if (it->second.pipeline) {
203 it->second.pipeline->cleanup(device);
204 }
205
206 if (it->second.layout) {
207 device.destroyPipelineLayout(it->second.layout);
208 }
209
210 m_pipelines.erase(it);
211
213 "Destroyed compute pipeline (ID: {})", pipeline_id);
214}
215
217{
218 auto device = m_shader_foundry->get_device();
219
220 for (auto& [id, state] : m_pipelines) {
221 if (state.pipeline) {
222 state.pipeline->cleanup(device);
223 }
224
225 if (state.layout) {
226 device.destroyPipelineLayout(state.layout);
227 }
228 }
229
231 "Cleaned up all compute pipelines");
232}
233
234//==============================================================================
235// Pipeline Binding
236//==============================================================================
237
239{
240 auto pipeline_it = m_pipelines.find(pipeline_id);
241 if (pipeline_it == m_pipelines.end()) {
243 "Invalid pipeline ID: {}", pipeline_id);
244 return;
245 }
246
247 auto cmd = m_shader_foundry->get_command_buffer(cmd_id);
248 if (!cmd) {
250 "Invalid command buffer ID: {}", cmd_id);
251 return;
252 }
253
254 pipeline_it->second.pipeline->bind(cmd);
255}
256
258 CommandBufferID cmd_id,
259 ComputePipelineID pipeline_id,
260 const std::vector<DescriptorSetID>& descriptor_set_ids)
261{
262 auto pipeline_it = m_pipelines.find(pipeline_id);
263 if (pipeline_it == m_pipelines.end()) {
265 "Invalid pipeline ID: {}", pipeline_id);
266 return;
267 }
268
269 auto cmd = m_shader_foundry->get_command_buffer(cmd_id);
270 if (!cmd) {
272 "Invalid command buffer ID: {}", cmd_id);
273 return;
274 }
275
276 std::vector<vk::DescriptorSet> vk_sets;
277 for (auto ds_id : descriptor_set_ids) {
278 vk_sets.push_back(m_shader_foundry->get_descriptor_set(ds_id));
279 }
280
281 pipeline_it->second.pipeline->bind_descriptor_sets(cmd, vk_sets);
282}
283
285 CommandBufferID cmd_id,
286 ComputePipelineID pipeline_id,
287 const void* data,
288 size_t size)
289{
290 auto pipeline_it = m_pipelines.find(pipeline_id);
291 if (pipeline_it == m_pipelines.end()) {
293 "Invalid pipeline ID: {}", pipeline_id);
294 return;
295 }
296
297 auto cmd = m_shader_foundry->get_command_buffer(cmd_id);
298 if (!cmd) {
300 "Invalid command buffer ID: {}", cmd_id);
301 return;
302 }
303
304 pipeline_it->second.pipeline->push_constants(
305 cmd,
306 vk::ShaderStageFlagBits::eCompute,
307 0,
308 static_cast<uint32_t>(size),
309 data);
310}
311
312//==============================================================================
313// Dispatch
314//==============================================================================
315
316void ComputePress::dispatch(CommandBufferID cmd_id, uint32_t x, uint32_t y, uint32_t z)
317{
318 auto cmd = m_shader_foundry->get_command_buffer(cmd_id);
319 if (!cmd) {
321 "Invalid command buffer ID: {}", cmd_id);
322 return;
323 }
324
325 cmd.dispatch(x, y, z);
326
328 "Dispatched compute: {}x{}x{} workgroups", x, y, z);
329}
330
332 CommandBufferID cmd_id,
333 vk::Buffer indirect_buffer,
334 vk::DeviceSize offset)
335{
336 auto cmd = m_shader_foundry->get_command_buffer(cmd_id);
337 if (!cmd) {
339 "Invalid command buffer ID: {}", cmd_id);
340 return;
341 }
342
343 cmd.dispatchIndirect(indirect_buffer, offset);
344
346 "Dispatched compute indirect from buffer");
347}
348
349//==============================================================================
350// Convenience Wrappers
351//==============================================================================
352
353std::vector<DescriptorSetID> ComputePress::allocate_pipeline_descriptors(ComputePipelineID pipeline_id)
354{
355 auto pipeline_it = m_pipelines.find(pipeline_id);
356 if (pipeline_it == m_pipelines.end()) {
358 "Invalid pipeline ID: {}", pipeline_id);
359 return {};
360 }
361
362 std::vector<DescriptorSetID> descriptor_set_ids;
363 for (const auto& layout : pipeline_it->second.layouts) {
364 auto ds_id = m_shader_foundry->allocate_descriptor_set(layout);
365 if (ds_id == INVALID_DESCRIPTOR_SET) {
367 "Failed to allocate descriptor set for pipeline {}", pipeline_id);
368 return {};
369 }
370 descriptor_set_ids.push_back(ds_id);
371 }
372
374 "Allocated {} descriptor sets for pipeline {}",
375 descriptor_set_ids.size(), pipeline_id);
376
377 return descriptor_set_ids;
378}
379
381 CommandBufferID cmd_id,
382 ComputePipelineID pipeline_id,
383 const std::vector<DescriptorSetID>& descriptor_set_ids,
384 const void* push_constants_data,
385 size_t push_constant_size)
386{
387 bind_pipeline(cmd_id, pipeline_id);
388 bind_descriptor_sets(cmd_id, pipeline_id, descriptor_set_ids);
389
390 if (push_constants_data && push_constant_size > 0) {
391 this->push_constants(cmd_id, pipeline_id, push_constants_data, push_constant_size);
392 }
393}
394
395} // namespace MayaFlux::Portal::Graphics
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
void destroy_pipeline(ComputePipelineID pipeline_id)
void push_constants(CommandBufferID cmd_id, ComputePipelineID pipeline_id, const void *data, size_t size)
Push constants to active command buffer.
void bind_pipeline(CommandBufferID cmd_id, ComputePipelineID pipeline_id)
Bind pipeline to active command buffer.
std::vector< DescriptorSetID > allocate_pipeline_descriptors(ComputePipelineID pipeline_id)
All-in-one: allocate descriptors for pipeline.
void bind_all(CommandBufferID cmd_id, ComputePipelineID pipeline_id, const std::vector< DescriptorSetID > &descriptor_set_ids, const void *push_constants_data=nullptr, size_t push_constant_size=0)
All-in-one: bind pipeline + descriptors + push constants.
void dispatch(CommandBufferID cmd_id, uint32_t x, uint32_t y, uint32_t z)
Dispatch compute workgroups.
void bind_descriptor_sets(CommandBufferID cmd_id, ComputePipelineID pipeline_id, const std::vector< DescriptorSetID > &descriptor_set_ids)
Bind descriptor sets to active command buffer.
ComputePipelineID create_pipeline(ShaderID shader_id, const std::vector< std::vector< DescriptorBindingInfo > > &descriptor_sets={}, size_t push_constant_size=0)
Create compute pipeline.
std::unordered_map< ComputePipelineID, PipelineState > m_pipelines
void dispatch_indirect(CommandBufferID cmd_id, vk::Buffer indirect_buffer, vk::DeviceSize offset=0)
Dispatch compute workgroups indirectly.
ComputePipelineID create_pipeline_auto(ShaderID shader_id, size_t push_constant_size=0)
Create pipeline with auto-reflection.
std::shared_ptr< Core::VKDescriptorManager > m_descriptor_manager
vk::DescriptorSet get_descriptor_set(DescriptorSetID descriptor_set_id)
Get Vulkan descriptor set handle from DescriptorSetID.
std::shared_ptr< Core::VKShaderModule > get_vk_shader_module(ShaderID shader_id)
bool is_initialized() const
Check if compiler is initialized.
vk::CommandBuffer get_command_buffer(CommandBufferID cmd_id)
Get Vulkan command buffer handle from CommandBufferID.
ShaderReflectionInfo get_shader_reflection(ShaderID shader_id)
Get reflection info for compiled shader.
ShaderStage get_shader_stage(ShaderID shader_id)
Get shader stage for compiled shader.
DescriptorSetID allocate_descriptor_set(vk::DescriptorSetLayout layout)
Allocate descriptor set for a pipeline.
@ GPUCompute
GPU compute operations (shaders, GPGPU tasks)
@ Portal
High-level user-facing API layer.
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.
constexpr ComputePipelineID INVALID_COMPUTE_PIPELINE
constexpr DescriptorSetID INVALID_DESCRIPTOR_SET
std::vector< vk::DescriptorSetLayout > set_layouts
Descriptor layouts.
std::shared_ptr< VKShaderModule > shader
Compute shader.
void add_push_constant(vk::ShaderStageFlags stages, uint32_t size, uint32_t offset=0)
Configuration for creating a compute pipeline.
void add_binding(uint32_t binding, vk::DescriptorType type, vk::ShaderStageFlags stages, uint32_t count=1)
Configuration for creating a descriptor set layout.
std::vector< vk::DescriptorSetLayout > layouts
std::shared_ptr< Core::VKComputePipeline > pipeline