15 "ComputePress already initialized (static flag)");
20 if (!foundry->is_initialized()) {
22 "Cannot initialize ComputePress: ShaderFoundry not initialized");
33 "ComputePress initialized");
44 "ComputePress stopped");
54 "Shutting down ComputePress...");
58 "Cannot shutdown ComputePress: ShaderFoundry not initialized");
66 "Cannot shutdown ComputePress: Vulkan device is null");
83 "ComputePress shutdown complete");
92 const std::vector<std::vector<DescriptorBindingInfo>>& descriptor_sets,
93 size_t push_constant_size)
97 "ComputePress not initialized");
102 if (!shader_module) {
104 "Invalid shader ID: {}", shader_id);
111 "Shader is not a compute shader (stage: {})",
static_cast<int>(stage));
126 for (
const auto& set_bindings : descriptor_sets) {
129 for (
const auto& binding : set_bindings) {
133 vk::ShaderStageFlagBits::eCompute,
141 pipeline_config.
shader = shader_module;
144 if (push_constant_size > 0) {
146 vk::ShaderStageFlagBits::eCompute,
147 static_cast<uint32_t
>(push_constant_size));
150 state.
pipeline = std::make_shared<Core::VKComputePipeline>();
153 "Failed to create compute pipeline");
162 "Created compute pipeline (ID: {}, {} descriptor sets, {} bytes push constants)",
163 id, state.
layouts.size(), push_constant_size);
170 size_t push_constant_size)
174 "ComputePress not initialized");
180 std::map<uint32_t, std::vector<DescriptorBindingInfo>> bindings_by_set;
181 for (
const auto& binding : reflection.descriptor_bindings) {
183 config.
set = binding.set;
184 config.
binding = binding.binding;
185 config.
type = binding.type;
186 bindings_by_set[binding.set].push_back(config);
189 std::vector<std::vector<DescriptorBindingInfo>> descriptor_sets;
190 descriptor_sets.reserve(bindings_by_set.size());
191 for (
const auto& [set_index, bindings] : bindings_by_set) {
192 descriptor_sets.push_back(bindings);
195 size_t pc_size = push_constant_size;
196 if (pc_size == 0 && !reflection.push_constant_ranges.empty()) {
197 pc_size = reflection.push_constant_ranges[0].size;
201 "Auto-creating pipeline: {} descriptor sets, {} bindings total",
202 descriptor_sets.size(), reflection.descriptor_bindings.size());
216 if (it->second.pipeline) {
217 it->second.pipeline->cleanup(
device);
223 "Destroyed compute pipeline (ID: {})", pipeline_id);
231 if (state.pipeline) {
232 state.pipeline->cleanup(
device);
237 "Cleaned up all compute pipelines");
249 "Invalid pipeline ID: {}", pipeline_id);
256 "Invalid command buffer ID: {}", cmd_id);
260 pipeline_it->second.pipeline->bind(
cmd);
266 const std::vector<DescriptorSetID>& descriptor_set_ids)
271 "Invalid pipeline ID: {}", pipeline_id);
278 "Invalid command buffer ID: {}", cmd_id);
282 std::vector<vk::DescriptorSet> vk_sets;
283 for (
auto ds_id : descriptor_set_ids) {
287 pipeline_it->second.pipeline->bind_descriptor_sets(
cmd, vk_sets);
299 "Invalid pipeline ID: {}", pipeline_id);
306 "Invalid command buffer ID: {}", cmd_id);
310 pipeline_it->second.pipeline->push_constants(
312 vk::ShaderStageFlagBits::eCompute,
314 static_cast<uint32_t
>(
size),
328 "Invalid pipeline ID: {}", pipeline_id);
332 if (
static_cast<size_t>(
offset) +
size > pipeline_it->second.push_constant_size) {
334 "Push constant range [{}, {}) exceeds the {} bytes declared for pipeline {}",
336 pipeline_it->second.push_constant_size, pipeline_id);
343 "Invalid command buffer ID: {}", cmd_id);
347 pipeline_it->second.pipeline->push_constants(
349 vk::ShaderStageFlagBits::eCompute,
351 static_cast<uint32_t
>(
size),
368 "Invalid command buffer ID: {}", cmd_id);
372 cmd.dispatch(x, y, z);
375 "Dispatched compute: {}x{}x{} workgroups", x, y, z);
380 vk::Buffer indirect_buffer,
390 "Invalid command buffer ID: {}", cmd_id);
394 cmd.dispatchIndirect(indirect_buffer,
offset);
397 "Dispatched compute indirect from buffer");
409 "Invalid pipeline ID: {}", pipeline_id);
413 std::vector<DescriptorSetID> descriptor_set_ids;
414 for (
const auto& layout : pipeline_it->second.layouts) {
418 "Failed to allocate descriptor set for pipeline {}", pipeline_id);
421 descriptor_set_ids.push_back(ds_id);
425 "Allocated {} descriptor sets for pipeline {}",
426 descriptor_set_ids.size(), pipeline_id);
428 return descriptor_set_ids;
434 const std::vector<DescriptorSetID>& descriptor_set_ids,
435 const void* push_constants_data,
436 size_t push_constant_size)
441 if (push_constants_data && push_constant_size > 0) {
442 this->
push_constants(cmd_id, pipeline_id, push_constants_data, push_constant_size);
448 const std::vector<ComputeStage>& stages)
456 for (
size_t i = 0; i < stages.size(); ++i) {
457 const auto& stage = stages[i];
462 stage.descriptor_set_ids,
463 stage.push_constant_data.empty() ?
nullptr : stage.push_constant_data.data(),
464 stage.push_constant_data.size());
466 if (stage.indirect.buffer) {
469 stage.indirect.buffer,
470 vk::AccessFlagBits::eShaderWrite,
471 vk::AccessFlagBits::eIndirectCommandRead,
472 vk::PipelineStageFlagBits::eComputeShader,
473 vk::PipelineStageFlagBits::eDrawIndirect);
476 dispatch(cmd_id, stage.groups[0], stage.groups[1], stage.groups[2]);
479 for (
const auto& hazard : stage.hazard_resources) {
487 foundry.image_barrier(
490 vk::ImageLayout::eGeneral,
491 vk::ImageLayout::eGeneral,
492 vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
493 vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
494 vk::PipelineStageFlagBits::eComputeShader,
495 vk::PipelineStageFlagBits::eComputeShader);
497 foundry.buffer_barrier(
500 vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
501 vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
502 vk::PipelineStageFlagBits::eComputeShader,
503 vk::PipelineStageFlagBits::eComputeShader);
508 "record_sequence: stage {} of {} recorded ({} hazard barriers)",
509 i + 1, stages.size(), stage.hazard_resources.size());
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
vk::PhysicalDevice device
ShaderFoundry * m_shader_foundry
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.
std::atomic< uint64_t > m_next_pipeline_id
void record_sequence(CommandBufferID cmd_id, const std::vector< ComputeStage > &stages)
Record multiple pipeline dispatches into one already-open command buffer, inserting a barrier between...
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
bool is_initialized() const
Check if ComputePress is initialized.
void dispatch_indirect(CommandBufferID cmd_id, vk::Buffer indirect_buffer, vk::DeviceSize offset=0)
Dispatch compute workgroups indirectly.
static bool s_initialized
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.
vk::Device get_device() const
Get logical device handle.
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.
void buffer_barrier(CommandBufferID cmd_id, vk::Buffer buffer, vk::AccessFlags src_access, vk::AccessFlags dst_access, vk::PipelineStageFlags src_stage, vk::PipelineStageFlags dst_stage)
Insert buffer memory barrier.
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.
uint64_t ComputePipelineID
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.
constexpr ComputePipelineID INVALID_COMPUTE_PIPELINE
constexpr DescriptorSetID INVALID_DESCRIPTOR_SET
bool is_image(const fs::path &filepath)
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.
size_t push_constant_size
vk::PipelineLayout layout
std::vector< vk::DescriptorSetLayout > layouts
std::shared_ptr< Core::VKComputePipeline > pipeline