15 "VKComputePipeline destroyed without cleanup() - potential leak");
20 : m_pipeline(other.m_pipeline)
21 , m_layout(other.m_layout)
22 , m_shader(std::move(other.m_shader))
23 , m_workgroup_size(other.m_workgroup_size)
25 other.m_pipeline =
nullptr;
26 other.m_layout =
nullptr;
32 if (m_pipeline || m_layout) {
34 "VKComputePipeline move-assigned without cleanup() - potential leak");
37 m_pipeline = other.m_pipeline;
38 m_layout = other.m_layout;
39 m_workgroup_size = other.m_workgroup_size;
40 m_shader = std::move(other.m_shader);
42 other.m_pipeline =
nullptr;
43 other.m_layout =
nullptr;
54 "Compute pipeline destroyed");
61 "Pipeline layout destroyed");
76 "Cannot create compute pipeline without shader");
80 if (!config.
shader->is_valid()) {
82 "Cannot create compute pipeline with invalid shader module");
86 if (config.
shader->get_stage() != vk::ShaderStageFlagBits::eCompute) {
88 "Shader is not a compute shader (stage: {})",
89 vk::to_string(config.
shader->get_stage()));
96 "Failed to create pipeline layout");
100 auto shader_stage = config.
shader->get_stage_create_info();
102 vk::ComputePipelineCreateInfo pipeline_info;
103 pipeline_info.stage = shader_stage;
105 pipeline_info.basePipelineHandle =
nullptr;
106 pipeline_info.basePipelineIndex = -1;
109 auto result =
device.createComputePipeline(config.
cache, pipeline_info);
110 if (result.result != vk::Result::eSuccess) {
112 "Failed to create compute pipeline: {}",
113 vk::to_string(result.result));
119 }
catch (
const vk::SystemError& e) {
121 "Failed to create compute pipeline: {}", e.what());
128 const auto& reflection = config.
shader->get_reflection();
133 "Compute pipeline created (workgroup: {}x{}x{}, {} descriptor sets, {} push constants)",
138 "Compute pipeline created ({} descriptor sets, {} push constants)",
149 std::vector<vk::PushConstantRange> vk_push_constants;
153 vk::PushConstantRange range;
154 range.stageFlags = pc.stage_flags;
155 range.offset = pc.offset;
156 range.size = pc.size;
157 vk_push_constants.push_back(range);
160 vk::PipelineLayoutCreateInfo layout_info;
161 layout_info.setLayoutCount =
static_cast<uint32_t
>(config.
set_layouts.size());
163 layout_info.pushConstantRangeCount =
static_cast<uint32_t
>(vk_push_constants.size());
164 layout_info.pPushConstantRanges = vk_push_constants.empty() ? nullptr : vk_push_constants.data();
166 vk::PipelineLayout layout;
168 layout =
device.createPipelineLayout(layout_info);
169 }
catch (
const vk::SystemError& e) {
171 "Failed to create pipeline layout: {}", e.what());
176 "Pipeline layout created ({} sets, {} push constant ranges)",
190 "Cannot bind invalid compute pipeline");
194 cmd.bindPipeline(vk::PipelineBindPoint::eCompute,
m_pipeline);
198 vk::CommandBuffer
cmd,
199 const std::vector<vk::DescriptorSet>& descriptor_sets,
201 const std::vector<uint32_t>& dynamic_offsets)
const
205 "Cannot bind descriptor sets without pipeline layout");
209 if (descriptor_sets.empty()) {
211 "Binding empty descriptor sets");
215 for (
size_t i = 0; i < descriptor_sets.size(); ++i) {
216 if (!descriptor_sets[i]) {
218 "Descriptor set at index {} is null", first_set + i);
223 cmd.bindDescriptorSets(
224 vk::PipelineBindPoint::eCompute,
227 static_cast<uint32_t
>(descriptor_sets.size()),
228 descriptor_sets.data(),
229 static_cast<uint32_t
>(dynamic_offsets.size()),
230 dynamic_offsets.empty() ?
nullptr : dynamic_offsets.data());
234 vk::CommandBuffer
cmd,
235 vk::ShaderStageFlags stage_flags,
238 const void* data)
const
242 "Cannot push constants without pipeline layout");
248 "Cannot push null data");
254 "Pushing zero-sized constant data");
266 vk::CommandBuffer
cmd,
267 uint32_t group_count_x,
268 uint32_t group_count_y,
269 uint32_t group_count_z)
const
273 "Cannot dispatch invalid compute pipeline");
277 if (group_count_x == 0 || group_count_y == 0 || group_count_z == 0) {
279 "Dispatching with zero workgroups ({}x{}x{})",
280 group_count_x, group_count_y, group_count_z);
284 cmd.dispatch(group_count_x, group_count_y, group_count_z);
288 vk::CommandBuffer
cmd,
289 uint32_t element_count,
290 uint32_t local_size_x)
const
292 if (local_size_x == 0) {
294 "Invalid workgroup size: {}", local_size_x);
303 vk::CommandBuffer
cmd,
304 uint32_t width_elements,
305 uint32_t height_elements,
306 uint32_t local_size_x,
307 uint32_t local_size_y)
const
309 if (local_size_x == 0 || local_size_y == 0) {
311 "Invalid workgroup size: {}x{}", local_size_x, local_size_y);
321 vk::CommandBuffer
cmd,
322 uint32_t width_elements,
323 uint32_t height_elements,
324 uint32_t depth_elements,
325 uint32_t local_size_x,
326 uint32_t local_size_y,
327 uint32_t local_size_z)
const
329 if (local_size_x == 0 || local_size_y == 0 || local_size_z == 0) {
331 "Invalid workgroup size: {}x{}x{}", local_size_x, local_size_y, local_size_z);
338 dispatch(
cmd, workgroups_x, workgroups_y, workgroups_z);
352 if (workgroup_size == 0) {
356 return (element_count + workgroup_size - 1) / workgroup_size;
362 const std::unordered_map<uint32_t, uint32_t>& specialization_data)
366 "Cannot create compute pipeline without shader");
370 config.
shader->set_specialization_constants(specialization_data);
375 uint32_t element_count,
376 uint32_t workgroup_size)
383 uint32_t workgroup_x, uint32_t workgroup_y)
394 uint32_t workgroup_x, uint32_t workgroup_y, uint32_t workgroup_z)
404 vk::CommandBuffer
cmd,
410 "Cannot dispatch invalid compute pipeline");
416 "Cannot dispatch with null indirect buffer");
427 "Cannot get shader reflection - no shader attached");
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
std::shared_ptr< NetworkGeometryBuffer > buffer
vk::PhysicalDevice device
bool create_specialized(vk::Device device, const ComputePipelineConfig &config, const std::unordered_map< uint32_t, uint32_t > &specialization_data)
Create pipeline with specialization constants.
void dispatch_1d(vk::CommandBuffer cmd, uint32_t element_count, uint32_t local_size_x) const
Dispatch compute workgroups with automatic calculation.
void bind(vk::CommandBuffer cmd) const
Bind pipeline to command buffer.
VKComputePipeline()=default
std::optional< std::array< uint32_t, 3 > > m_workgroup_size
void cleanup(vk::Device device)
Cleanup pipeline resources.
const ShaderReflection & get_shader_reflection() const
Get shader module reflection data.
void dispatch_indirect(vk::CommandBuffer cmd, vk::Buffer buffer, vk::DeviceSize offset=0)
Dispatch compute shader indirectly from GPU buffer.
static std::array< uint32_t, 3 > calculate_dispatch_2d(uint32_t width, uint32_t height, uint32_t workgroup_x, uint32_t workgroup_y)
Calculate 2D dispatch size.
static uint32_t calculate_workgroups(uint32_t element_count, uint32_t workgroup_size)
Calculate number of workgroups needed.
void dispatch(vk::CommandBuffer cmd, uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z) const
Dispatch compute workgroups.
std::shared_ptr< VKShaderModule > m_shader
void dispatch_2d(vk::CommandBuffer cmd, uint32_t width_elements, uint32_t height_elements, uint32_t local_size_x, uint32_t local_size_y) const
Dispatch compute workgroups in 2D with automatic calculation.
static std::array< uint32_t, 3 > calculate_dispatch_1d(uint32_t element_count, uint32_t workgroup_size)
Calculate dispatch size from element count.
std::optional< std::array< uint32_t, 3 > > get_workgroup_size() const
Get shader workgroup size from reflection.
void bind_descriptor_sets(vk::CommandBuffer cmd, const std::vector< vk::DescriptorSet > &descriptor_sets, uint32_t first_set=0, const std::vector< uint32_t > &dynamic_offsets={}) const
Bind descriptor sets to pipeline.
bool create(vk::Device device, const ComputePipelineConfig &config)
Create compute pipeline from configuration.
VKComputePipeline & operator=(const VKComputePipeline &)=delete
void push_constants(vk::CommandBuffer cmd, vk::ShaderStageFlags stage_flags, uint32_t offset, uint32_t size, const void *data) const
Update push constants.
void dispatch_3d(vk::CommandBuffer cmd, uint32_t width_elements, uint32_t height_elements, uint32_t depth_elements, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z) const
Dispatch compute workgroups in 3D with automatic calculation.
static std::array< uint32_t, 3 > calculate_dispatch_3d(uint32_t width, uint32_t height, uint32_t depth, uint32_t workgroup_x, uint32_t workgroup_y, uint32_t workgroup_z)
Calculate 3D dispatch size.
vk::PipelineLayout m_layout
vk::PipelineLayout create_pipeline_layout(vk::Device device, const ComputePipelineConfig &config)
Create pipeline layout from configuration.
Wrapper for Vulkan compute pipeline with simplified interface.
@ GraphicsBackend
Graphics/visual rendering backend (Vulkan, OpenGL)
@ Core
Core engine, backend, subsystems.
std::vector< vk::DescriptorSetLayout > set_layouts
Descriptor layouts.
std::shared_ptr< VKShaderModule > shader
Compute shader.
std::vector< PushConstantRange > push_constants
Push constant ranges.
Configuration for creating a compute pipeline.
Metadata extracted from shader module.