36 std::optional<uint32_t> try_memory_type(vk::PhysicalDevice phys,
38 vk::MemoryPropertyFlags props)
40 auto mem_props = phys.getMemoryProperties();
41 for (uint32_t i = 0; i < mem_props.memoryTypeCount; ++i) {
42 if ((type_filter & (1U << i))
43 && (mem_props.memoryTypes[i].propertyFlags & props) == props) {
50 uint32_t find_memory_type(vk::PhysicalDevice phys,
52 vk::MemoryPropertyFlags props,
53 vk::MemoryPropertyFlags fallback_props = {})
55 if (
const auto type = try_memory_type(phys, type_filter, props))
58 if (
const auto type = try_memory_type(phys, type_filter, fallback_props))
61 error<std::runtime_error>(
64 std::source_location::current(),
65 "GpuResourceManager: no suitable memory type found");
68 void free_slot(vk::Device
device, VulkanBufferSlot& slot)
70 if (slot.mapped_ptr) {
71 device.unmapMemory(slot.memory);
72 slot.mapped_ptr =
nullptr;
75 device.destroyBuffer(slot.buffer);
76 slot.buffer = vk::Buffer {};
79 device.freeMemory(slot.memory);
80 slot.memory = vk::DeviceMemory {};
82 slot.allocated_bytes = 0;
97 void allocate_slot(vk::Device
device, vk::PhysicalDevice phys,
98 VulkanBufferSlot& slot,
size_t byte_size,
99 vk::BufferUsageFlags extra_usage = vk::BufferUsageFlagBits::eStorageBuffer,
100 bool prefer_device_local =
false)
104 vk::BufferCreateInfo bi;
106 bi.usage = extra_usage;
107 bi.sharingMode = vk::SharingMode::eExclusive;
108 slot.buffer =
device.createBuffer(bi);
110 auto req =
device.getBufferMemoryRequirements(slot.buffer);
112 vk::MemoryAllocateInfo ai;
113 ai.allocationSize = req.size;
115 if (prefer_device_local) {
116 const auto resident = try_memory_type(phys, req.memoryTypeBits,
117 vk::MemoryPropertyFlagBits::eDeviceLocal
118 | vk::MemoryPropertyFlagBits::eHostVisible
119 | vk::MemoryPropertyFlagBits::eHostCoherent);
121 ai.memoryTypeIndex = *resident;
123 slot.memory =
device.allocateMemory(ai);
124 }
catch (
const vk::SystemError&) {
125 slot.memory = vk::DeviceMemory {};
131 ai.memoryTypeIndex = find_memory_type(phys, req.memoryTypeBits,
132 vk::MemoryPropertyFlagBits::eHostVisible
133 | vk::MemoryPropertyFlagBits::eHostCoherent
134 | vk::MemoryPropertyFlagBits::eHostCached,
135 vk::MemoryPropertyFlagBits::eHostVisible
136 | vk::MemoryPropertyFlagBits::eHostCoherent);
137 slot.memory =
device.allocateMemory(ai);
140 device.bindBufferMemory(slot.buffer, slot.memory, 0);
141 slot.mapped_ptr =
device.mapMemory(slot.memory, 0, VK_WHOLE_SIZE);
142 slot.allocated_bytes = byte_size;
149 return vk::DescriptorType::eStorageImage;
151 return vk::DescriptorType::eCombinedImageSampler;
153 return vk::DescriptorType::eStorageBuffer;
181 error<std::runtime_error>(
184 std::source_location::current(),
185 "GpuResourceManager: no unit for key '{}' — call initialise() first", key);
193 return it ==
m_units.end() ? nullptr : it->second.get();
199 return unit && unit->ready;
204 const std::vector<GpuBufferBinding>& bindings)
212 auto unit = std::make_unique<PipelineUnit>();
217 unit->shader_id = foundry.load_shader(config.
shader_path);
222 "GpuResourceManager: failed to load shader '{}' for key '{}'",
227 std::map<uint32_t, std::vector<Portal::Graphics::DescriptorBindingInfo>> by_set;
228 for (
const auto&
b : bindings) {
229 const auto et =
b.element_type;
233 by_set[
b.set].push_back({
235 .binding =
b.binding,
236 .type = element_type_to_vk(et),
241 for (
const auto&
b : bindings) {
242 const auto et =
b.element_type;
246 by_set[
b.set].push_back({
248 .binding =
b.binding,
249 .type = vk::DescriptorType::eStorageBuffer,
254 std::vector<std::vector<Portal::Graphics::DescriptorBindingInfo>> descriptor_sets;
255 descriptor_sets.reserve(by_set.size());
256 for (
auto& [set_idx, set_bindings] : by_set)
257 descriptor_sets.push_back(std::move(set_bindings));
259 unit->pipeline_id = compute_press.create_pipeline(
264 "GpuResourceManager: failed to create pipeline for key '{}'", key);
265 foundry.destroy_shader(unit->shader_id);
269 unit->descriptor_set_ids = compute_press.allocate_pipeline_descriptors(unit->pipeline_id);
270 if (unit->descriptor_set_ids.empty()) {
272 "GpuResourceManager: failed to allocate descriptor sets for key '{}'", key);
273 compute_press.destroy_pipeline(unit->pipeline_id);
274 foundry.destroy_shader(unit->shader_id);
278 unit->impl = std::make_unique<GpuResourceManagerImpl>();
279 size_t max_binding = 0;
280 for (
const auto&
b : bindings)
281 max_binding = std::max(max_binding,
static_cast<size_t>(
b.binding));
282 const size_t capacity = bindings.empty() ? 0 : max_binding + 1;
283 unit->impl->buffers.resize(capacity);
284 unit->buffer_slots.resize(capacity);
285 unit->image_slots.resize(capacity);
288 m_units[key] = std::move(unit);
298 auto& unit = *it->second;
306 auto device = foundry.get_device();
309 for (
auto& slot : unit.impl->buffers)
313 unit.buffer_slots.clear();
314 unit.image_slots.clear();
317 compute_press.destroy_pipeline(unit.pipeline_id);
320 foundry.destroy_shader(unit.shader_id);
327 std::vector<std::string> keys;
329 for (
const auto& [k, v] :
m_units)
331 for (
const auto& k : keys)
343 auto& vk_slot = unit.impl->buffers[
index];
344 if (vk_slot.allocated_bytes >= required_bytes) {
349 allocate_slot(foundry.get_device(), foundry.get_physical_device(),
352 unit.buffer_slots[
index].allocated_bytes = required_bytes;
358 std::memcpy(vk_slot.mapped_ptr, data, byte_size);
364 std::memcpy(vk_slot.mapped_ptr, data, byte_size);
370 std::memcpy(dest, vk_slot.mapped_ptr, byte_size);
377 auto& vk_slot = unit.impl->buffers[
index];
379 foundry.update_descriptor_buffer(
380 unit.descriptor_set_ids[spec.
set],
382 vk::DescriptorType::eStorageBuffer,
383 vk_slot.buffer, 0, vk_slot.allocated_bytes);
391 std::vector<Portal::Graphics::DescriptorBufferWrite> writes;
392 writes.reserve(bindings.size());
394 for (
const auto&
b : bindings) {
395 const auto et =
b.element_type;
401 const auto shared_it =
m_shared->slots.find({
b.set,
static_cast<size_t>(
b.binding) });
403 size_t allocated_bytes = 0;
404 if (shared_it !=
m_shared->slots.end()) {
405 buffer = shared_it->second.buffer;
406 allocated_bytes = shared_it->second.allocated_bytes;
408 if (
static_cast<size_t>(
b.binding) >= unit.impl->buffers.size()) {
411 const auto& vk_slot = unit.impl->buffers[
b.binding];
413 allocated_bytes = vk_slot.allocated_bytes;
420 .descriptor_set_id = unit.descriptor_set_ids[
b.set],
421 .binding =
b.binding,
422 .type = vk::DescriptorType::eStorageBuffer,
425 .size = allocated_bytes,
429 foundry.update_descriptor_buffers(writes);
443 error<std::runtime_error>(
446 std::source_location::current(),
447 "GpuResourceManager: ensure_shared_buffer requires a sized element_type");
450 auto& slot =
m_shared->slots[{ set, binding_index }];
451 const size_t required_bytes = element_count *
width;
452 if (slot.allocated_bytes >= required_bytes)
458 allocate_slot(foundry.get_device(), foundry.get_physical_device(),
464 const auto it =
m_shared->slots.find({ set, binding_index });
467 return { .
buffer = it->second.buffer, .mapped_ptr = it->second.mapped_ptr, .size_bytes = it->second.allocated_bytes };
474 auto& slot =
m_shared->slots.at({ set, binding_index });
476 foundry.update_descriptor_buffer(
477 unit.descriptor_set_ids[spec.
set],
479 vk::DescriptorType::eStorageBuffer,
480 slot.buffer, 0, slot.allocated_bytes);
485 auto& slot =
m_shared->slots.at({ set, binding_index });
486 std::memcpy(dest, slot.mapped_ptr, byte_size);
491 auto& slot =
m_shared->slots.at({ set, binding_index });
492 std::memcpy(slot.mapped_ptr, data, byte_size);
498 const auto it =
m_shared->slots.find({ spec.
set,
static_cast<size_t>(spec.
binding) });
499 vk::Buffer handle = it !=
m_shared->slots.end() ? it->second.
buffer : vk::Buffer {};
508 const std::string& key,
size_t index,
509 const std::shared_ptr<Core::VKImage>&
image,
515 if (
index >= unit.image_slots.size())
516 unit.image_slots.resize(
index + 1);
519 foundry.update_descriptor_storage_image(
520 unit.descriptor_set_ids[spec.
set],
522 image->get_image_view(),
523 vk::ImageLayout::eGeneral);
527 const std::string& key,
size_t index,
528 const std::shared_ptr<Core::VKImage>&
image,
535 if (
index >= unit.image_slots.size())
536 unit.image_slots.resize(
index + 1);
539 foundry.update_descriptor_image(
540 unit.descriptor_set_ids[spec.
set],
542 image->get_image_view(),
544 vk::ImageLayout::eShaderReadOnlyOptimal);
552 std::vector<Portal::Graphics::DescriptorImageWrite> writes;
553 writes.reserve(images.size());
555 for (
const auto& entry : images) {
556 if (entry.index >= unit.image_slots.size())
557 unit.image_slots.resize(entry.index + 1);
558 unit.image_slots[entry.index] = entry.image;
562 .descriptor_set_id = unit.descriptor_set_ids[entry.spec.set],
563 .binding = entry.spec.binding,
564 .type = is_storage ? vk::DescriptorType::eStorageImage : vk::DescriptorType::eCombinedImageSampler,
565 .image_view = entry.image->get_image_view(),
566 .sampler = entry.sampler,
567 .layout = is_storage ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal,
571 foundry.update_descriptor_images(writes);
575 const std::shared_ptr<Core::VKImage>&
image,
576 vk::ImageLayout old_layout,
577 vk::ImageLayout new_layout)
582 backend.transition_layout(
586 1, 1, vk::ImageAspectFlagBits::eColor);
594 const std::array<uint32_t, 3>& groups,
595 const std::vector<GpuBufferBinding>& bindings,
596 const uint8_t* push_constant_data,
597 size_t push_constant_size)
603 auto cmd_id = foundry.begin_commands(
606 compute_press.bind_all(
607 cmd_id, unit.pipeline_id, unit.descriptor_set_ids,
608 push_constant_data, push_constant_size);
610 compute_press.dispatch(cmd_id, groups[0], groups[1], groups[2]);
612 for (
const auto&
b : bindings) {
613 const auto et =
b.element_type;
619 const bool is_shared =
m_shared->slots.contains({
b.set,
static_cast<size_t>(
b.binding) });
620 if (is_output && !
is_image && !is_shared
621 &&
static_cast<size_t>(
b.binding) < unit.impl->buffers.size()
622 && unit.impl->buffers[
b.binding].buffer) {
623 foundry.buffer_barrier(
625 unit.impl->buffers[
b.binding].buffer,
626 vk::AccessFlagBits::eShaderWrite,
627 vk::AccessFlagBits::eHostRead,
628 vk::PipelineStageFlagBits::eComputeShader,
629 vk::PipelineStageFlagBits::eHost);
633 foundry.submit_and_wait(cmd_id);
637 const std::array<uint32_t, 3>& groups,
638 const std::vector<GpuBufferBinding>& bindings,
639 size_t push_constant_size,
642 const auto& params = safe_variant_get_or_throw<ChainedParams>(ctx.
parameters,
643 "GpuResourceManager: dispatch_batched requires ChainedParams");
649 const uint32_t workgroups_per_pass = groups[0] * groups[1] * groups[2];
651 const uint32_t default_passes = std::max(1U, 65536U / std::max(1U, workgroups_per_pass));
653 const uint32_t effective_passes_per_batch = params.passes_per_batch.value_or(default_passes);
654 for (uint32_t base = 0; base < params.pass_count; base += effective_passes_per_batch) {
655 const uint32_t batch_end = std::min(base + effective_passes_per_batch, params.pass_count);
656 auto cmd_id = foundry.begin_commands(
659 for (uint32_t pass = base; pass < batch_end; ++pass) {
660 std::vector<uint8_t> pc_data(push_constant_size);
661 params.pc_updater(pass, pc_data.data());
662 compute_press.bind_all(
663 cmd_id, unit.pipeline_id, unit.descriptor_set_ids,
664 pc_data.data(), push_constant_size);
665 compute_press.dispatch(cmd_id, groups[0], groups[1], groups[2]);
667 for (
const auto&
b : bindings) {
673 const bool is_shared =
m_shared->slots.contains({
b.set,
static_cast<size_t>(
b.binding) });
676 if (
static_cast<size_t>(
b.binding) < unit.image_slots.size() && unit.image_slots[
b.binding]) {
677 foundry.image_barrier(
679 unit.image_slots[
b.binding]->get_image(),
680 vk::ImageLayout::eGeneral,
681 vk::ImageLayout::eGeneral,
682 vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
683 vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
684 vk::PipelineStageFlagBits::eComputeShader,
685 vk::PipelineStageFlagBits::eComputeShader);
687 }
else if (!is_shared &&
static_cast<size_t>(
b.binding) < unit.impl->buffers.size()
688 && unit.impl->buffers[
b.binding].buffer) {
689 foundry.buffer_barrier(
691 unit.impl->buffers[
b.binding].buffer,
692 vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
693 vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
694 vk::PipelineStageFlagBits::eComputeShader,
695 vk::PipelineStageFlagBits::eComputeShader);
700 for (
const auto&
b : bindings) {
705 const bool is_shared =
m_shared->slots.contains({
b.set,
static_cast<size_t>(
b.binding) });
706 if (!
is_image && !is_shared &&
static_cast<size_t>(
b.binding) < unit.impl->buffers.size()
707 && unit.impl->buffers[
b.binding].buffer) {
708 foundry.buffer_barrier(
710 unit.impl->buffers[
b.binding].buffer,
711 vk::AccessFlagBits::eShaderWrite,
712 vk::AccessFlagBits::eHostRead,
713 vk::PipelineStageFlagBits::eComputeShader,
714 vk::PipelineStageFlagBits::eHost);
719 foundry.submit_and_wait(cmd_id);
724 uint32_t indirect_set,
size_t indirect_binding,
725 const std::array<uint32_t, 3>& groups,
726 const std::vector<GpuBufferBinding>& bindings,
727 size_t push_constant_size,
730 const auto& params = safe_variant_get_or_throw<ChainedIndirectParams>(ctx.
parameters,
731 "GpuResourceManager: dispatch_batched_indirect requires ChainedIndirectParams");
737 auto& indirect_slot =
m_shared->slots.at({ indirect_set, indirect_binding });
738 const vk::Buffer indirect_buffer = indirect_slot.buffer;
739 const uint32_t init_cmd[3] = { groups[0], groups[1], groups[2] };
740 std::memcpy(indirect_slot.mapped_ptr, init_cmd,
sizeof(init_cmd));
742 const uint32_t default_passes = std::max(1U, 65536U / std::max(1U, groups[0] * groups[1] * groups[2]));
743 const uint32_t effective_passes_per_batch = params.passes_per_batch.value_or(default_passes);
745 for (uint32_t base = 0; base < params.pass_count; base += effective_passes_per_batch) {
746 const uint32_t batch_end = std::min(base + effective_passes_per_batch, params.pass_count);
749 for (uint32_t pass = base; pass < batch_end; ++pass) {
750 std::vector<uint8_t> pc_data(push_constant_size);
751 params.pc_updater(pass, 1, pc_data.data());
752 compute_press.bind_all(cmd_id, unit.pipeline_id, unit.descriptor_set_ids, pc_data.data(), push_constant_size);
753 compute_press.dispatch_indirect(cmd_id, indirect_buffer);
755 for (
const auto&
b : bindings) {
756 const auto et =
b.element_type;
761 const bool is_shared =
m_shared->slots.contains({
b.set,
static_cast<size_t>(
b.binding) });
762 if (is_output && !
is_image && !is_shared
763 &&
static_cast<size_t>(
b.binding) < unit.impl->buffers.size()
764 && unit.impl->buffers[
b.binding].buffer) {
765 foundry.buffer_barrier(
767 unit.impl->buffers[
b.binding].buffer,
768 vk::AccessFlagBits::eShaderWrite,
769 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
770 vk::PipelineStageFlagBits::eComputeShader,
771 vk::PipelineStageFlagBits::eComputeShader);
775 foundry.submit_and_wait(cmd_id);
780 const std::array<uint32_t, 3>& groups,
781 const std::vector<GpuBufferBinding>& bindings,
782 const uint8_t* push_constant_data,
783 size_t push_constant_size)
789 auto cmd_id = foundry.begin_commands(
792 compute_press.bind_all(
793 cmd_id, unit.pipeline_id, unit.descriptor_set_ids,
794 push_constant_data, push_constant_size);
796 compute_press.dispatch(cmd_id, groups[0], groups[1], groups[2]);
798 for (
const auto&
b : bindings) {
799 const auto et =
b.element_type;
804 const bool is_shared =
m_shared->slots.contains({
b.set,
static_cast<size_t>(
b.binding) });
806 if (is_output && !
is_image && !is_shared
807 &&
static_cast<size_t>(
b.binding) < unit.impl->buffers.size()
808 && unit.impl->buffers[
b.binding].buffer) {
809 foundry.buffer_barrier(
811 unit.impl->buffers[
b.binding].buffer,
812 vk::AccessFlagBits::eShaderWrite,
813 vk::AccessFlagBits::eHostRead,
814 vk::PipelineStageFlagBits::eComputeShader,
815 vk::PipelineStageFlagBits::eHost);
819 return foundry.submit_async(cmd_id);
823 const std::vector<std::string>& keys,
824 const std::vector<std::array<uint32_t, 3>>& groups_per_key,
825 const std::vector<std::vector<uint8_t>>& push_constants_per_key,
826 const std::vector<std::vector<Portal::Graphics::HazardResource>>& hazards_per_key,
827 const std::vector<Portal::Graphics::IndirectDispatch>& indirect_per_key)
832 std::vector<Portal::Graphics::ComputeStage> stages;
833 stages.reserve(keys.size());
835 for (
size_t i = 0; i < keys.size(); ++i) {
839 .descriptor_set_ids = unit.descriptor_set_ids,
840 .groups = groups_per_key[i],
841 .push_constant_data = push_constants_per_key[i],
842 .hazard_resources = hazards_per_key[i],
847 auto cmd_id = foundry.begin_commands(
849 compute_press.record_sequence(cmd_id, stages);
854 const std::vector<std::string>& keys,
855 const std::vector<std::array<uint32_t, 3>>& groups_per_key,
856 const std::vector<std::vector<uint8_t>>& push_constants_per_key,
857 const std::vector<std::vector<Portal::Graphics::HazardResource>>& hazards_per_key,
858 const std::vector<Portal::Graphics::IndirectDispatch>& indirect_per_key)
861 foundry.submit_and_wait(
866 const std::vector<std::string>& keys,
867 const std::vector<std::array<uint32_t, 3>>& groups_per_key,
868 const std::vector<std::vector<uint8_t>>& push_constants_per_key,
869 const std::vector<std::vector<Portal::Graphics::HazardResource>>& hazards_per_key,
870 const std::vector<Portal::Graphics::IndirectDispatch>& indirect_per_key)
873 return foundry.submit_async(
#define MF_ERROR(comp, ctx,...)
std::shared_ptr< NetworkGeometryBuffer > buffer
vk::PhysicalDevice device
vk::PhysicalDeviceType type
Cycle Behavior: The for_cycles(N) configuration controls how many times the capture operation execute...
void bind_image_sampled(const std::string &key, size_t index, const std::shared_ptr< Core::VKImage > &image, vk::Sampler sampler, const GpuBufferBinding &spec)
Bind a combined image+sampler descriptor at the given slot index.
std::unique_ptr< SharedBuffers > m_shared
void dispatch_batched_indirect(const std::string &key, uint32_t indirect_set, size_t indirect_binding, const std::array< uint32_t, 3 > &groups, const std::vector< GpuBufferBinding > &bindings, size_t push_constant_size, const ExecutionContext &ctx)
void download(const std::string &key, size_t index, float *dest, size_t byte_size)
bool initialise(const std::string &key, const GpuComputeConfig &config, const std::vector< GpuBufferBinding > &bindings)
Create (or confirm existing) pipeline for the given key.
bool is_ready(const std::string &key) const
void download_shared(uint32_t set, size_t binding_index, void *dest, size_t byte_size)
void cleanup()
Destroy every key currently held.
void bind_descriptors_batch(const std::string &key, const std::vector< GpuBufferBinding > &bindings)
Bind every non-image buffer binding in one Vulkan call.
void upload_shared_raw(uint32_t set, size_t binding_index, const uint8_t *data, size_t byte_size)
void release(const std::string &key)
Destroy the pipeline, shader, descriptor sets, and buffers for a single key, without affecting any ot...
void bind_images_batch(const std::string &key, const std::vector< ImageBind > &images)
Bind every image in one Vulkan call.
Portal::Graphics::HazardResource make_shared_buffer_hazard(const GpuBufferBinding &spec) const
void dispatch_sequence(const std::vector< std::string > &keys, const std::vector< std::array< uint32_t, 3 > > &groups_per_key, const std::vector< std::vector< uint8_t > > &push_constants_per_key, const std::vector< std::vector< Portal::Graphics::HazardResource > > &hazards_per_key, const std::vector< Portal::Graphics::IndirectDispatch > &indirect_per_key={})
Record a dispatch for each requested key into one command buffer via ComputePress::record_sequence,...
PipelineUnit & unit_for(const std::string &key)
void upload(const std::string &key, size_t index, const float *data, size_t byte_size)
Portal::Graphics::CommandBufferID record_sequence_commands(const std::vector< std::string > &keys, const std::vector< std::array< uint32_t, 3 > > &groups_per_key, const std::vector< std::vector< uint8_t > > &push_constants_per_key, const std::vector< std::vector< Portal::Graphics::HazardResource > > &hazards_per_key, const std::vector< Portal::Graphics::IndirectDispatch > &indirect_per_key)
Record one command buffer holding a dispatch per key, with the barriers each stage's hazards owe the ...
void transition_image(const std::shared_ptr< Core::VKImage > &image, vk::ImageLayout old_layout, vk::ImageLayout new_layout)
Transition a VKImage layout via an immediate command submission.
void bind_descriptor(const std::string &key, size_t index, const GpuBufferBinding &spec)
void dispatch(const std::string &key, const std::array< uint32_t, 3 > &groups, const std::vector< GpuBufferBinding > &bindings, const uint8_t *push_constant_data, size_t push_constant_size)
Portal::Graphics::FenceID dispatch_async(const std::string &key, const std::array< uint32_t, 3 > &groups, const std::vector< GpuBufferBinding > &bindings, const uint8_t *push_constant_data, size_t push_constant_size)
Submit a compute dispatch without blocking.
std::unordered_map< std::string, std::unique_ptr< PipelineUnit > > m_units
Portal::Graphics::FenceID dispatch_sequence_async(const std::vector< std::string > &keys, const std::vector< std::array< uint32_t, 3 > > &groups_per_key, const std::vector< std::vector< uint8_t > > &push_constants_per_key, const std::vector< std::vector< Portal::Graphics::HazardResource > > &hazards_per_key, const std::vector< Portal::Graphics::IndirectDispatch > &indirect_per_key={})
Non-blocking counterpart of dispatch_sequence.
void bind_shared_descriptor(const std::string &key, uint32_t set, size_t binding_index, const GpuBufferBinding &spec)
void dispatch_batched(const std::string &key, const std::array< uint32_t, 3 > &groups, const std::vector< GpuBufferBinding > &bindings, size_t push_constant_size, const ExecutionContext &ctx)
void ensure_shared_buffer(uint32_t set, size_t binding_index, size_t element_count, GpuBufferBinding::ElementType element_type, Portal::Graphics::BufferUsageHint usage_hint=Portal::Graphics::BufferUsageHint::COMPUTE_STORAGE)
void ensure_buffer(const std::string &key, size_t index, size_t required_bytes, Portal::Graphics::BufferUsageHint usage_hint=Portal::Graphics::BufferUsageHint::COMPUTE_STORAGE)
void upload_raw(const std::string &key, size_t index, const uint8_t *data, size_t byte_size)
Portal::Graphics::GpuBufferHandle shared_buffer_handle(uint32_t set, size_t binding_index) const
Non-owning view of the shared buffer at (set, binding_index).
size_t buffer_allocated_bytes(const std::string &key, size_t index) const
const PipelineUnit * find_unit(const std::string &key) const
void bind_image_storage(const std::string &key, size_t index, const std::shared_ptr< Core::VKImage > &image, const GpuBufferBinding &spec)
Bind a storage image descriptor at the given slot index.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Yantra
DSP algorithms, computational units, matrix operations, Grammar.
MAYAFLUX_API TextureLoom & get_texture_manager()
Get the global texture manager instance.
constexpr ShaderID INVALID_SHADER
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.
constexpr ComputePipelineID INVALID_COMPUTE_PIPELINE
size_t element_type_bytes(GpuBufferBinding::ElementType et) noexcept
Byte width of one GpuBufferBinding::ElementType element.
BufferUsageHint
Semantic usage hint for buffer allocation and memory properties.
@ COMPUTE
Storage buffer for compute shaders (device-local)
@ DEVICE
Device-local GPU-only buffer.
vk::BufferUsageFlags to_buffer_usage_flags(BufferUsageHint hint)
Resolve the extra vk::BufferUsageFlags a BufferUsageHint requires, on top of whatever base usage the ...
MAYAFLUX_API ComputePress & get_compute_press()
bool is_image(const fs::path &filepath)
ComputePipelineID pipeline_id
Pipeline to bind for this stage.
One pipeline dispatch within a ComputePress::record_sequence call.
uint32_t set
Descriptor set index.
ElementType
Element type the shader expects in this binding.
uint32_t binding
Binding index within the set.
Declares a single storage buffer or image binding a compute shader expects.
Non-owning view of a GPU storage buffer produced by a compute path.
size_t push_constant_size
Plain-data description of the compute shader to dispatch.
vk::Buffer buffer
Valid when binding.element_type is anything else.
GpuBufferBinding binding
Direction/element_type describing this resource.
One resource this stage's dispatch reads/writes that a later stage in the sequence depends on,...
Optional GPU-resident source of a stage's workgroup counts.
ExecutionParams parameters
Optional parameters specific to the execution mode.
Context information controlling how a compute operation executes.
std::unordered_map< std::string, VulkanBufferSlot > shared_buffers
std::vector< VulkanBufferSlot > buffers
std::vector< BufferSlot > buffer_slots
std::unique_ptr< GpuResourceManagerImpl > impl
std::map< std::pair< uint32_t, size_t >, VulkanBufferSlot > slots