15 "VKDescriptorManager destroyed without cleanup() - potential leak");
20 : m_device(other.m_device)
21 , m_pools(std::move(other.m_pools))
22 , m_current_pool_index(other.m_current_pool_index)
23 , m_pool_size(other.m_pool_size)
24 , m_allocated_count(other.m_allocated_count)
25 , m_pool_capacity(other.m_pool_capacity)
26 , m_layouts(std::move(other.m_layouts))
27 , m_layout_cache(std::move(other.m_layout_cache))
29 other.m_device =
nullptr;
30 other.m_pools.clear();
31 other.m_layouts.clear();
37 if (!m_pools.empty() || !m_layouts.empty()) {
39 "VKDescriptorManager move-assigned without cleanup() - potential leak");
42 m_device = other.m_device;
43 m_pools = std::move(other.m_pools);
44 m_current_pool_index = other.m_current_pool_index;
45 m_pool_size = other.m_pool_size;
46 m_allocated_count = other.m_allocated_count;
47 m_pool_capacity = other.m_pool_capacity;
48 m_layouts = std::move(other.m_layouts);
49 m_layout_cache = std::move(other.m_layout_cache);
51 other.m_device =
nullptr;
52 other.m_pools.clear();
53 other.m_layouts.clear();
62 "Cannot initialize descriptor manager with null device");
72 "Failed to create initial descriptor pool");
82 "Descriptor manager initialized (pool size: {} sets)",
m_pool_size);
91 "cleanup() called with null device");
97 device.destroyDescriptorSetLayout(layout);
105 device.destroyDescriptorPool(pool);
116 "Descriptor manager cleaned up");
129 "Creating descriptor set layout with no bindings");
136 "Reusing cached descriptor set layout (hash: 0x{:X})", config_hash);
140 std::vector<vk::DescriptorSetLayoutBinding> vk_bindings;
141 vk_bindings.reserve(config.
bindings.size());
143 for (
const auto& binding : config.
bindings) {
144 vk::DescriptorSetLayoutBinding vk_binding;
145 vk_binding.binding = binding.binding;
146 vk_binding.descriptorType = binding.type;
147 vk_binding.descriptorCount = binding.count;
148 vk_binding.stageFlags = binding.stage_flags;
149 vk_binding.pImmutableSamplers =
nullptr;
151 vk_bindings.push_back(vk_binding);
154 vk::DescriptorSetLayoutCreateInfo layout_info;
155 layout_info.bindingCount =
static_cast<uint32_t
>(vk_bindings.size());
156 layout_info.pBindings = vk_bindings.data();
158 vk::DescriptorSetLayout layout;
160 layout = device.createDescriptorSetLayout(layout_info);
161 }
catch (
const vk::SystemError& e) {
163 "Failed to create descriptor set layout: {}", e.what());
172 "Created descriptor set layout ({} bindings, hash: 0x{:X})",
173 config.
bindings.size(), config_hash);
182 auto hash_combine = [](
size_t& seed,
size_t value) {
183 seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
186 for (
const auto& binding : config.
bindings) {
187 hash_combine(hash, binding.binding);
188 hash_combine(hash,
static_cast<size_t>(binding.type));
189 hash_combine(hash, binding.count);
190 hash_combine(hash,
static_cast<uint32_t
>(binding.stage_flags));
202 std::vector<vk::DescriptorPoolSize> pool_sizes = {
203 { vk::DescriptorType::eStorageBuffer, max_sets * 4 },
205 { vk::DescriptorType::eUniformBuffer, max_sets * 2 },
207 { vk::DescriptorType::eStorageImage, max_sets * 2 },
209 { vk::DescriptorType::eCombinedImageSampler, max_sets * 2 },
212 vk::DescriptorPoolCreateInfo pool_info;
213 pool_info.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet;
214 pool_info.maxSets = max_sets;
215 pool_info.poolSizeCount =
static_cast<uint32_t
>(pool_sizes.size());
216 pool_info.pPoolSizes = pool_sizes.data();
218 vk::DescriptorPool pool;
220 pool = device.createDescriptorPool(pool_info);
221 }
catch (
const vk::SystemError& e) {
223 "Failed to create descriptor pool: {}", e.what());
228 "Created descriptor pool (max sets: {})", max_sets);
238 "Failed to grow descriptor pool");
258 vk::DescriptorSetLayout layout)
262 "Cannot allocate descriptor set with null layout");
268 "No descriptor pools available - call initialize() first");
272 vk::DescriptorSetAllocateInfo alloc_info;
274 alloc_info.descriptorSetCount = 1;
275 alloc_info.pSetLayouts = &layout;
277 vk::DescriptorSet set;
279 auto sets = device.allocateDescriptorSets(alloc_info);
282 }
catch (
const vk::OutOfPoolMemoryError&) {
292 auto sets = device.allocateDescriptorSets(alloc_info);
295 }
catch (
const vk::SystemError& e) {
297 "Failed to allocate descriptor set after pool growth: {}", e.what());
300 }
catch (
const vk::SystemError& e) {
302 "Failed to allocate descriptor set: {}", e.what());
318 vk::DescriptorSet set,
321 vk::DeviceSize offset,
322 vk::DeviceSize range)
326 "Cannot update null descriptor set");
332 "Cannot bind null buffer to descriptor set");
336 vk::DescriptorBufferInfo buffer_info;
337 buffer_info.buffer = buffer;
338 buffer_info.offset = offset;
339 buffer_info.range = range;
341 vk::WriteDescriptorSet write;
343 write.dstBinding = binding;
344 write.dstArrayElement = 0;
345 write.descriptorCount = 1;
348 write.descriptorType = vk::DescriptorType::eStorageBuffer;
349 write.pBufferInfo = &buffer_info;
351 device.updateDescriptorSets(1, &write, 0,
nullptr);
354 "Updated descriptor set binding {} with buffer (offset: {}, range: {})",
355 binding, offset, range);
360 vk::DescriptorSet set,
362 vk::ImageView image_view,
364 vk::ImageLayout layout)
368 "Cannot update null descriptor set");
374 "Cannot bind null image view to descriptor set");
378 vk::DescriptorImageInfo image_info;
379 image_info.imageView = image_view;
380 image_info.sampler = sampler;
381 image_info.imageLayout = layout;
383 vk::WriteDescriptorSet write;
385 write.dstBinding = binding;
386 write.dstArrayElement = 0;
387 write.descriptorCount = 1;
388 write.descriptorType = sampler ? vk::DescriptorType::eCombinedImageSampler : vk::DescriptorType::eStorageImage;
389 write.pImageInfo = &image_info;
391 device.updateDescriptorSets(1, &write, 0,
nullptr);
394 "Updated descriptor set binding {} with image (layout: {})",
395 binding, vk::to_string(layout));
400 vk::DescriptorSet set,
406 "Cannot update null descriptor set");
412 "Cannot bind null sampler to descriptor set");
416 vk::DescriptorImageInfo image_info;
417 image_info.sampler = sampler;
418 image_info.imageView =
nullptr;
419 image_info.imageLayout = vk::ImageLayout::eUndefined;
421 vk::WriteDescriptorSet write;
423 write.dstBinding = binding;
424 write.dstArrayElement = 0;
425 write.descriptorCount = 1;
426 write.descriptorType = vk::DescriptorType::eSampler;
427 write.pImageInfo = &image_info;
429 device.updateDescriptorSets(1, &write, 0,
nullptr);
432 "Updated descriptor set binding {} with sampler", binding);
437 vk::DescriptorSet set,
439 vk::ImageView image_view,
441 vk::ImageLayout layout)
445 "Cannot update null descriptor set");
449 if (!image_view || !sampler) {
451 "Cannot bind null image view or sampler");
455 vk::DescriptorImageInfo image_info;
456 image_info.imageView = image_view;
457 image_info.sampler = sampler;
458 image_info.imageLayout = layout;
460 vk::WriteDescriptorSet write;
462 write.dstBinding = binding;
463 write.dstArrayElement = 0;
464 write.descriptorCount = 1;
465 write.descriptorType = vk::DescriptorType::eCombinedImageSampler;
466 write.pImageInfo = &image_info;
468 device.updateDescriptorSets(1, &write, 0,
nullptr);
471 "Updated descriptor set binding {} with combined image sampler", binding);
476 vk::DescriptorSet set,
478 vk::ImageView image_view,
479 vk::ImageLayout layout)
483 "Cannot update null descriptor set");
489 "Cannot bind null image view to input attachment");
493 vk::DescriptorImageInfo image_info;
494 image_info.imageView = image_view;
495 image_info.sampler =
nullptr;
496 image_info.imageLayout = layout;
498 vk::WriteDescriptorSet write;
500 write.dstBinding = binding;
501 write.dstArrayElement = 0;
502 write.descriptorCount = 1;
503 write.descriptorType = vk::DescriptorType::eInputAttachment;
504 write.pImageInfo = &image_info;
506 device.updateDescriptorSets(1, &write, 0,
nullptr);
509 "Updated descriptor set binding {} with input attachment", binding);
514 vk::DescriptorSet src,
515 vk::DescriptorSet dst,
520 "Cannot copy null descriptor sets");
524 vk::CopyDescriptorSet copy;
527 copy.srcArrayElement = 0;
530 copy.dstArrayElement = 0;
531 copy.descriptorCount = copy_count;
533 device.updateDescriptorSets(0,
nullptr, 1, ©);
536 "Copied descriptor set ({} descriptors)", copy_count);
541 const std::vector<vk::DescriptorSetLayout>& layouts)
543 if (layouts.empty()) {
545 "Allocating zero descriptor sets");
551 "No descriptor pools available - call initialize() first");
555 vk::DescriptorSetAllocateInfo alloc_info;
557 alloc_info.descriptorSetCount =
static_cast<uint32_t
>(layouts.size());
558 alloc_info.pSetLayouts = layouts.data();
560 std::vector<vk::DescriptorSet> sets;
562 sets = device.allocateDescriptorSets(alloc_info);
564 }
catch (
const vk::OutOfPoolMemoryError&) {
574 sets = device.allocateDescriptorSets(alloc_info);
576 }
catch (
const vk::SystemError& e) {
578 "Failed to allocate descriptor sets after pool growth: {}", e.what());
581 }
catch (
const vk::SystemError& e) {
583 "Failed to allocate descriptor sets: {}", e.what());
588 "Allocated {} descriptor sets (total: {}/{})",
596 const std::vector<vk::WriteDescriptorSet>& writes)
598 if (writes.empty()) {
600 "Batch update called with no writes");
604 device.updateDescriptorSets(
605 static_cast<uint32_t
>(writes.size()),
610 "Batch updated {} descriptor bindings", writes.size());
622 device.resetDescriptorPool(pool);
623 }
catch (
const vk::SystemError& e) {
625 "Failed to reset descriptor pool: {}", e.what());
634 "Reset all descriptor pools");
650 vk::DeviceSize offset,
651 vk::DeviceSize range)
653 vk::DescriptorBufferInfo buffer_info;
655 buffer_info.offset = offset;
656 buffer_info.range = range;
659 vk::WriteDescriptorSet write;
660 write.dstSet =
m_set;
661 write.dstBinding = binding;
662 write.dstArrayElement = 0;
663 write.descriptorCount = 1;
664 write.descriptorType = vk::DescriptorType::eStorageBuffer;
673 vk::ImageView image_view,
674 vk::ImageLayout layout)
676 vk::DescriptorImageInfo image_info;
677 image_info.imageView = image_view;
679 image_info.imageLayout = layout;
682 vk::WriteDescriptorSet write;
683 write.dstSet =
m_set;
684 write.dstBinding = binding;
685 write.dstArrayElement = 0;
686 write.descriptorCount = 1;
687 write.descriptorType = vk::DescriptorType::eStorageImage;
696 vk::ImageView image_view,
698 vk::ImageLayout layout)
700 vk::DescriptorImageInfo image_info;
701 image_info.imageView = image_view;
703 image_info.imageLayout = layout;
706 vk::WriteDescriptorSet write;
707 write.dstSet =
m_set;
708 write.dstBinding = binding;
709 write.dstArrayElement = 0;
710 write.descriptorCount = 1;
711 write.descriptorType = vk::DescriptorType::eCombinedImageSampler;
722 vk::DescriptorImageInfo image_info;
724 image_info.imageView =
nullptr;
725 image_info.imageLayout = vk::ImageLayout::eUndefined;
728 vk::WriteDescriptorSet write;
729 write.dstSet =
m_set;
730 write.dstBinding = binding;
731 write.dstArrayElement = 0;
732 write.descriptorCount = 1;
733 write.descriptorType = vk::DescriptorType::eSampler;
747 static_cast<uint32_t
>(
m_writes.size()),
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
DescriptorUpdateBatch & sampler(uint32_t binding, vk::Sampler sampler)
std::vector< vk::DescriptorBufferInfo > m_buffer_infos
std::vector< vk::WriteDescriptorSet > m_writes
DescriptorUpdateBatch & combined_image_sampler(uint32_t binding, vk::ImageView image_view, vk::Sampler sampler, vk::ImageLayout layout=vk::ImageLayout::eShaderReadOnlyOptimal)
DescriptorUpdateBatch(vk::Device device, vk::DescriptorSet set)
DescriptorUpdateBatch & buffer(uint32_t binding, vk::Buffer buffer, vk::DeviceSize offset=0, vk::DeviceSize range=VK_WHOLE_SIZE)
DescriptorUpdateBatch & storage_image(uint32_t binding, vk::ImageView image_view, vk::ImageLayout layout=vk::ImageLayout::eGeneral)
std::vector< vk::DescriptorImageInfo > m_image_infos
Fluent interface for batching descriptor updates.
void reset_pools(vk::Device device)
Reset all descriptor pools.
uint32_t m_allocated_count
Total allocated sets.
vk::DescriptorSet allocate_set(vk::Device device, vk::DescriptorSetLayout layout)
Allocate a descriptor set from the pool.
void batch_update(vk::Device device, const std::vector< vk::WriteDescriptorSet > &writes)
Batch update multiple bindings at once.
std::unordered_map< size_t, size_t > m_layout_cache
vk::DescriptorSetLayout create_layout(vk::Device device, const DescriptorSetLayoutConfig &config)
Create descriptor set layout from configuration.
uint32_t m_pool_capacity
Total capacity across all pools.
void update_image(vk::Device device, vk::DescriptorSet set, uint32_t binding, vk::ImageView image_view, vk::Sampler sampler=nullptr, vk::ImageLayout layout=vk::ImageLayout::eGeneral)
Update descriptor set with image binding.
void update_combined_image_sampler(vk::Device device, vk::DescriptorSet set, uint32_t binding, vk::ImageView image_view, vk::Sampler sampler, vk::ImageLayout layout=vk::ImageLayout::eShaderReadOnlyOptimal)
Update descriptor set with combined image+sampler.
bool grow_pools(vk::Device device)
Grow pool capacity by allocating new pool.
void cleanup(vk::Device device)
Cleanup all descriptor resources.
std::vector< vk::DescriptorSet > allocate_sets(vk::Device device, const std::vector< vk::DescriptorSetLayout > &layouts)
Allocate multiple descriptor sets at once.
void update_buffer(vk::Device device, vk::DescriptorSet set, uint32_t binding, vk::Buffer buffer, vk::DeviceSize offset=0, vk::DeviceSize range=VK_WHOLE_SIZE)
Update descriptor set with buffer binding.
size_t m_current_pool_index
uint32_t m_pool_size
Sets per pool.
vk::DescriptorPool create_pool(vk::Device device, uint32_t max_sets)
Create a new descriptor pool.
void update_input_attachment(vk::Device device, vk::DescriptorSet set, uint32_t binding, vk::ImageView image_view, vk::ImageLayout layout=vk::ImageLayout::eShaderReadOnlyOptimal)
Update descriptor set with input attachment.
VKDescriptorManager()=default
VKDescriptorManager & operator=(const VKDescriptorManager &)=delete
void copy_descriptor_set(vk::Device device, vk::DescriptorSet src, vk::DescriptorSet dst, uint32_t copy_count=0)
Copy descriptor set contents.
void update_sampler(vk::Device device, vk::DescriptorSet set, uint32_t binding, vk::Sampler sampler)
Update descriptor set with sampler binding.
std::vector< vk::DescriptorPool > m_pools
size_t hash_layout_config(const DescriptorSetLayoutConfig &config) const
Compute hash of descriptor set layout config.
std::vector< vk::DescriptorSetLayout > m_layouts
bool initialize(vk::Device device, uint32_t initial_pool_size=1024)
Initialize descriptor manager.
Manages descriptor pools, layouts, and set allocation.
@ GraphicsBackend
Graphics/visual rendering backend (Vulkan, OpenGL)
@ Core
Core engine, backend, subsystems.
std::vector< DescriptorBinding > bindings
Configuration for creating a descriptor set layout.