MayaFlux 0.1.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
44 "Cannot shutdown ComputePress: ShaderFoundry not initialized");
45 return;
46 }
47
48 auto device = m_shader_foundry->get_device();
49
50 if (!device) {
52 "Cannot shutdown ComputePress: Vulkan device is null");
53 return;
54 }
55
56 for (auto& [id, state] : m_pipelines) {
57 if (state.pipeline) {
58 state.pipeline->cleanup(device);
59 }
60
61 if (state.layout && device) {
62 device.destroyPipelineLayout(state.layout);
63 }
64 }
65
66 if (m_descriptor_manager && device) {
67 m_descriptor_manager->cleanup(device);
68 m_descriptor_manager = nullptr;
69 }
70
71 m_pipelines.clear();
72
73 s_initialized = false;
74
76 "ComputePress shutdown complete");
77}
78
79//==============================================================================
80// Pipeline Creation
81//==============================================================================
82
84 ShaderID shader_id,
85 const std::vector<std::vector<DescriptorBindingConfig>>& descriptor_sets,
86 size_t push_constant_size)
87{
88 auto shader_module = m_shader_foundry->get_vk_shader_module(shader_id);
89 if (!shader_module) {
91 "Invalid shader ID: {}", shader_id);
93 }
94
95 auto stage = m_shader_foundry->get_shader_stage(shader_id);
96 if (stage != ShaderStage::COMPUTE) {
98 "Shader is not a compute shader (stage: {})", static_cast<int>(stage));
100 }
101
103 PipelineState& state = m_pipelines[id];
104 state.shader_id = shader_id;
105
106 auto device = m_shader_foundry->get_device();
107
109 m_descriptor_manager = std::make_shared<Core::VKDescriptorManager>();
110 m_descriptor_manager->initialize(device, 1024);
111 }
112
113 for (const auto& set_bindings : descriptor_sets) {
115
116 for (const auto& binding : set_bindings) {
117 layout_config.add_binding(
118 binding.binding,
119 binding.type,
120 vk::ShaderStageFlagBits::eCompute,
121 1);
122 }
123
124 state.layouts.push_back(m_descriptor_manager->create_layout(device, layout_config));
125 }
126
127 Core::ComputePipelineConfig pipeline_config;
128 pipeline_config.shader = shader_module;
129 pipeline_config.set_layouts = state.layouts;
130
131 if (push_constant_size > 0) {
132 pipeline_config.add_push_constant(
133 vk::ShaderStageFlagBits::eCompute,
134 static_cast<uint32_t>(push_constant_size));
135 }
136
137 state.pipeline = std::make_shared<Core::VKComputePipeline>();
138 if (!state.pipeline->create(device, pipeline_config)) {
140 "Failed to create compute pipeline");
141 m_pipelines.erase(id);
143 }
144
145 state.layout = state.pipeline->get_layout();
146
148 "Created compute pipeline (ID: {}, {} descriptor sets, {} bytes push constants)",
149 id, state.layouts.size(), push_constant_size);
150
151 return id;
152}
153
155 ShaderID shader_id,
156 size_t push_constant_size)
157{
158 auto reflection = m_shader_foundry->get_shader_reflection(shader_id);
159
160 std::map<uint32_t, std::vector<DescriptorBindingConfig>> bindings_by_set;
161 for (const auto& binding : reflection.descriptor_bindings) {
163 config.set = binding.set;
164 config.binding = binding.binding;
165 config.type = binding.type;
166 bindings_by_set[binding.set].push_back(config);
167 }
168
169 std::vector<std::vector<DescriptorBindingConfig>> descriptor_sets;
170 descriptor_sets.reserve(bindings_by_set.size());
171 for (const auto& [set_index, bindings] : bindings_by_set) {
172 descriptor_sets.push_back(bindings);
173 }
174
175 size_t pc_size = push_constant_size;
176 if (pc_size == 0 && !reflection.push_constant_ranges.empty()) {
177 pc_size = reflection.push_constant_ranges[0].size;
178 }
179
181 "Auto-creating pipeline: {} descriptor sets, {} bindings total",
182 descriptor_sets.size(), reflection.descriptor_bindings.size());
183
184 return create_pipeline(shader_id, descriptor_sets, pc_size);
185}
186
188{
189 auto it = m_pipelines.find(pipeline_id);
190 if (it == m_pipelines.end()) {
191 return;
192 }
193
194 auto device = m_shader_foundry->get_device();
195
196 if (it->second.pipeline) {
197 it->second.pipeline->cleanup(device);
198 }
199
200 if (it->second.layout) {
201 device.destroyPipelineLayout(it->second.layout);
202 }
203
204 m_pipelines.erase(it);
205
207 "Destroyed compute pipeline (ID: {})", pipeline_id);
208}
209
210//==============================================================================
211// Pipeline Binding
212//==============================================================================
213
215{
216 auto pipeline_it = m_pipelines.find(pipeline_id);
217 if (pipeline_it == m_pipelines.end()) {
219 "Invalid pipeline ID: {}", pipeline_id);
220 return;
221 }
222
223 auto cmd = m_shader_foundry->get_command_buffer(cmd_id);
224 if (!cmd) {
226 "Invalid command buffer ID: {}", cmd_id);
227 return;
228 }
229
230 pipeline_it->second.pipeline->bind(cmd);
231}
232
234 CommandBufferID cmd_id,
235 ComputePipelineID pipeline_id,
236 const std::vector<DescriptorSetID>& descriptor_set_ids)
237{
238 auto pipeline_it = m_pipelines.find(pipeline_id);
239 if (pipeline_it == m_pipelines.end()) {
241 "Invalid pipeline ID: {}", pipeline_id);
242 return;
243 }
244
245 auto cmd = m_shader_foundry->get_command_buffer(cmd_id);
246 if (!cmd) {
248 "Invalid command buffer ID: {}", cmd_id);
249 return;
250 }
251
252 std::vector<vk::DescriptorSet> vk_sets;
253 for (auto ds_id : descriptor_set_ids) {
254 vk_sets.push_back(m_shader_foundry->get_descriptor_set(ds_id));
255 }
256
257 pipeline_it->second.pipeline->bind_descriptor_sets(cmd, vk_sets);
258}
259
261 CommandBufferID cmd_id,
262 ComputePipelineID pipeline_id,
263 const void* data,
264 size_t size)
265{
266 auto pipeline_it = m_pipelines.find(pipeline_id);
267 if (pipeline_it == m_pipelines.end()) {
269 "Invalid pipeline ID: {}", pipeline_id);
270 return;
271 }
272
273 auto cmd = m_shader_foundry->get_command_buffer(cmd_id);
274 if (!cmd) {
276 "Invalid command buffer ID: {}", cmd_id);
277 return;
278 }
279
280 pipeline_it->second.pipeline->push_constants(
281 cmd,
282 vk::ShaderStageFlagBits::eCompute,
283 0,
284 static_cast<uint32_t>(size),
285 data);
286}
287
288//==============================================================================
289// Dispatch
290//==============================================================================
291
292void ComputePress::dispatch(CommandBufferID cmd_id, uint32_t x, uint32_t y, uint32_t z)
293{
294 auto cmd = m_shader_foundry->get_command_buffer(cmd_id);
295 if (!cmd) {
297 "Invalid command buffer ID: {}", cmd_id);
298 return;
299 }
300
301 cmd.dispatch(x, y, z);
302
304 "Dispatched compute: {}x{}x{} workgroups", x, y, z);
305}
306
308 CommandBufferID cmd_id,
309 vk::Buffer indirect_buffer,
310 vk::DeviceSize offset)
311{
312 auto cmd = m_shader_foundry->get_command_buffer(cmd_id);
313 if (!cmd) {
315 "Invalid command buffer ID: {}", cmd_id);
316 return;
317 }
318
319 cmd.dispatchIndirect(indirect_buffer, offset);
320
322 "Dispatched compute indirect from buffer");
323}
324
325//==============================================================================
326// Convenience Wrappers
327//==============================================================================
328
329std::vector<DescriptorSetID> ComputePress::allocate_pipeline_descriptors(ComputePipelineID pipeline_id)
330{
331 auto pipeline_it = m_pipelines.find(pipeline_id);
332 if (pipeline_it == m_pipelines.end()) {
334 "Invalid pipeline ID: {}", pipeline_id);
335 return {};
336 }
337
338 std::vector<DescriptorSetID> descriptor_set_ids;
339 for (const auto& layout : pipeline_it->second.layouts) {
340 auto ds_id = m_shader_foundry->allocate_descriptor_set(layout);
341 if (ds_id == INVALID_DESCRIPTOR_SET) {
343 "Failed to allocate descriptor set for pipeline {}", pipeline_id);
344 return {};
345 }
346 descriptor_set_ids.push_back(ds_id);
347 }
348
350 "Allocated {} descriptor sets for pipeline {}",
351 descriptor_set_ids.size(), pipeline_id);
352
353 return descriptor_set_ids;
354}
355
357 CommandBufferID cmd_id,
358 ComputePipelineID pipeline_id,
359 const std::vector<DescriptorSetID>& descriptor_set_ids,
360 const void* push_constants_data,
361 size_t push_constant_size)
362{
363 bind_pipeline(cmd_id, pipeline_id);
364 bind_descriptor_sets(cmd_id, pipeline_id, descriptor_set_ids);
365
366 if (push_constants_data && push_constant_size > 0) {
367 this->push_constants(cmd_id, pipeline_id, push_constants_data, push_constant_size);
368 }
369}
370
371} // 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.
std::unordered_map< ComputePipelineID, PipelineState > m_pipelines
ComputePipelineID create_pipeline(ShaderID shader_id, const std::vector< std::vector< DescriptorBindingConfig > > &descriptor_sets={}, size_t push_constant_size=0)
Create compute pipeline.
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
Portal-level descriptor binding configuration.