MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
GpuResourceManager.cpp
Go to the documentation of this file.
2
5
7
8namespace MayaFlux::Yantra {
9
10//==============================================================================
11// Buffer slot
12//==============================================================================
13
15 vk::Buffer buffer;
16 vk::DeviceMemory memory;
17 void* mapped_ptr { nullptr };
18 size_t allocated_bytes {};
19};
20
21//==============================================================================
22// PIMPL — one per pipeline unit
23//==============================================================================
24
26 std::vector<VulkanBufferSlot> buffers;
27 std::unordered_map<std::string, VulkanBufferSlot> shared_buffers;
28};
29
30//==============================================================================
31// File-local helpers
32//==============================================================================
33
34namespace {
35
36 uint32_t find_memory_type(vk::PhysicalDevice phys,
37 uint32_t type_filter,
38 vk::MemoryPropertyFlags props,
39 vk::MemoryPropertyFlags fallback_props = {})
40 {
41 auto mem_props = phys.getMemoryProperties();
42 for (uint32_t i = 0; i < mem_props.memoryTypeCount; ++i) {
43 if ((type_filter & (1U << i))
44 && (mem_props.memoryTypes[i].propertyFlags & props) == props) {
45 return i;
46 }
47 }
48 if (fallback_props) {
49 for (uint32_t i = 0; i < mem_props.memoryTypeCount; ++i) {
50 if ((type_filter & (1U << i))
51 && (mem_props.memoryTypes[i].propertyFlags & fallback_props) == fallback_props) {
52 return i;
53 }
54 }
55 }
56 error<std::runtime_error>(
59 std::source_location::current(),
60 "GpuResourceManager: no suitable memory type found");
61 }
62
63 void free_slot(vk::Device device, VulkanBufferSlot& slot)
64 {
65 if (slot.mapped_ptr) {
66 device.unmapMemory(slot.memory);
67 slot.mapped_ptr = nullptr;
68 }
69 if (slot.buffer) {
70 device.destroyBuffer(slot.buffer);
71 slot.buffer = vk::Buffer {};
72 }
73 if (slot.memory) {
74 device.freeMemory(slot.memory);
75 slot.memory = vk::DeviceMemory {};
76 }
77 slot.allocated_bytes = 0;
78 }
79
80 void allocate_slot(vk::Device device, vk::PhysicalDevice phys,
81 VulkanBufferSlot& slot, size_t byte_size,
82 vk::BufferUsageFlags extra_usage = vk::BufferUsageFlagBits::eStorageBuffer)
83 {
84 free_slot(device, slot);
85
86 vk::BufferCreateInfo bi;
87 bi.size = byte_size;
88 bi.usage = extra_usage;
89 bi.sharingMode = vk::SharingMode::eExclusive;
90 slot.buffer = device.createBuffer(bi);
91
92 auto req = device.getBufferMemoryRequirements(slot.buffer);
93
94 vk::MemoryAllocateInfo ai;
95 ai.allocationSize = req.size;
96 ai.memoryTypeIndex = find_memory_type(phys, req.memoryTypeBits,
97 vk::MemoryPropertyFlagBits::eHostVisible
98 | vk::MemoryPropertyFlagBits::eHostCoherent
99 | vk::MemoryPropertyFlagBits::eHostCached,
100 vk::MemoryPropertyFlagBits::eHostVisible
101 | vk::MemoryPropertyFlagBits::eHostCoherent);
102
103 slot.memory = device.allocateMemory(ai);
104 device.bindBufferMemory(slot.buffer, slot.memory, 0);
105 slot.mapped_ptr = device.mapMemory(slot.memory, 0, VK_WHOLE_SIZE);
106 slot.allocated_bytes = byte_size;
107 }
108
109 [[nodiscard]] vk::DescriptorType element_type_to_vk(GpuBufferBinding::ElementType et)
110 {
111 switch (et) {
113 return vk::DescriptorType::eStorageImage;
115 return vk::DescriptorType::eCombinedImageSampler;
116 default:
117 return vk::DescriptorType::eStorageBuffer;
118 }
119 }
120
121} // anonymous namespace
122
124 std::map<std::pair<uint32_t, size_t>, VulkanBufferSlot> slots;
125};
126
127//==============================================================================
128// Lifecycle
129//==============================================================================
130
132 : m_shared(std::make_unique<SharedBuffers>())
133{
134}
135
140
142{
143 auto it = m_units.find(key);
144 if (it == m_units.end()) {
145 error<std::runtime_error>(
148 std::source_location::current(),
149 "GpuResourceManager: no unit for key '{}' — call initialise() first", key);
150 }
151 return *it->second;
152}
153
155{
156 auto it = m_units.find(key);
157 return it == m_units.end() ? nullptr : it->second.get();
158}
159
160bool GpuResourceManager::is_ready(const std::string& key) const
161{
162 const auto* unit = find_unit(key);
163 return unit && unit->ready;
164}
165
166bool GpuResourceManager::initialise(const std::string& key,
167 const GpuComputeConfig& config,
168 const std::vector<GpuBufferBinding>& bindings)
169{
170 if (const auto* existing = find_unit(key); existing && existing->ready)
171 return true;
172
173 auto& foundry = Portal::Graphics::get_shader_foundry();
174 auto& compute_press = Portal::Graphics::get_compute_press();
175
176 auto unit = std::make_unique<PipelineUnit>();
177
179 unit->shader_id = config.shader_id;
180 } else {
181 unit->shader_id = foundry.load_shader(config.shader_path);
182 }
183
184 if (unit->shader_id == Portal::Graphics::INVALID_SHADER) {
186 "GpuResourceManager: failed to load shader '{}' for key '{}'",
187 config.shader_path.empty() ? "<generated>" : config.shader_path, key);
188 return false;
189 }
190
191 std::map<uint32_t, std::vector<Portal::Graphics::DescriptorBindingInfo>> by_set;
192 for (const auto& b : bindings) {
193 const auto et = b.element_type;
196 if (is_image) {
197 by_set[b.set].push_back({
198 .set = b.set,
199 .binding = b.binding,
200 .type = element_type_to_vk(et),
201 });
202 }
203 }
204
205 for (const auto& b : bindings) {
206 const auto et = b.element_type;
209 if (!is_image) {
210 by_set[b.set].push_back({
211 .set = b.set,
212 .binding = b.binding,
213 .type = vk::DescriptorType::eStorageBuffer,
214 });
215 }
216 }
217
218 std::vector<std::vector<Portal::Graphics::DescriptorBindingInfo>> descriptor_sets;
219 descriptor_sets.reserve(by_set.size());
220 for (auto& [set_idx, set_bindings] : by_set)
221 descriptor_sets.push_back(std::move(set_bindings));
222
223 unit->pipeline_id = compute_press.create_pipeline(
224 unit->shader_id, descriptor_sets, config.push_constant_size);
225
226 if (unit->pipeline_id == Portal::Graphics::INVALID_COMPUTE_PIPELINE) {
228 "GpuResourceManager: failed to create pipeline for key '{}'", key);
229 foundry.destroy_shader(unit->shader_id);
230 return false;
231 }
232
233 unit->descriptor_set_ids = compute_press.allocate_pipeline_descriptors(unit->pipeline_id);
234 if (unit->descriptor_set_ids.empty()) {
236 "GpuResourceManager: failed to allocate descriptor sets for key '{}'", key);
237 compute_press.destroy_pipeline(unit->pipeline_id);
238 foundry.destroy_shader(unit->shader_id);
239 return false;
240 }
241
242 unit->impl = std::make_unique<GpuResourceManagerImpl>();
243 size_t max_binding = 0;
244 for (const auto& b : bindings)
245 max_binding = std::max(max_binding, static_cast<size_t>(b.binding));
246 const size_t capacity = bindings.empty() ? 0 : max_binding + 1;
247 unit->impl->buffers.resize(capacity);
248 unit->buffer_slots.resize(capacity);
249 unit->image_slots.resize(capacity);
250 unit->ready = true;
251
252 m_units[key] = std::move(unit);
253 return true;
254}
255
256void GpuResourceManager::release(const std::string& key)
257{
258 auto it = m_units.find(key);
259 if (it == m_units.end())
260 return;
261
262 auto& unit = *it->second;
263 if (!unit.ready) {
264 m_units.erase(it);
265 return;
266 }
267
268 auto& foundry = Portal::Graphics::get_shader_foundry();
269 auto& compute_press = Portal::Graphics::get_compute_press();
270 auto device = foundry.get_device();
271
272 if (unit.impl) {
273 for (auto& slot : unit.impl->buffers)
274 free_slot(device, slot);
275 }
276 unit.impl.reset();
277 unit.buffer_slots.clear();
278 unit.image_slots.clear();
279
280 if (unit.pipeline_id != Portal::Graphics::INVALID_COMPUTE_PIPELINE)
281 compute_press.destroy_pipeline(unit.pipeline_id);
282
283 if (unit.shader_id != Portal::Graphics::INVALID_SHADER)
284 foundry.destroy_shader(unit.shader_id);
285
286 m_units.erase(it);
287}
288
290{
291 std::vector<std::string> keys;
292 keys.reserve(m_units.size());
293 for (const auto& [k, v] : m_units)
294 keys.push_back(k);
295 for (const auto& k : keys)
296 release(k);
297}
298
299//==============================================================================
300// Buffer operations
301//==============================================================================
302
303void GpuResourceManager::ensure_buffer(const std::string& key, size_t index,
304 size_t required_bytes, Portal::Graphics::BufferUsageHint usage_hint)
305{
306 auto& unit = unit_for(key);
307 auto& vk_slot = unit.impl->buffers[index];
308 if (vk_slot.allocated_bytes >= required_bytes) {
309 return;
310 }
311
312 auto& foundry = Portal::Graphics::get_shader_foundry();
313 allocate_slot(foundry.get_device(), foundry.get_physical_device(),
314 vk_slot, required_bytes, Portal::Graphics::to_buffer_usage_flags(usage_hint));
315
316 unit.buffer_slots[index].allocated_bytes = required_bytes;
317}
318
319void GpuResourceManager::upload(const std::string& key, size_t index, const float* data, size_t byte_size)
320{
321 auto& vk_slot = unit_for(key).impl->buffers[index];
322 std::memcpy(vk_slot.mapped_ptr, data, byte_size);
323}
324
325void GpuResourceManager::upload_raw(const std::string& key, size_t index, const uint8_t* data, size_t byte_size)
326{
327 auto& vk_slot = unit_for(key).impl->buffers[index];
328 std::memcpy(vk_slot.mapped_ptr, data, byte_size);
329}
330
331void GpuResourceManager::download(const std::string& key, size_t index, float* dest, size_t byte_size)
332{
333 auto& vk_slot = unit_for(key).impl->buffers[index];
334 std::memcpy(dest, vk_slot.mapped_ptr, byte_size);
335}
336
337void GpuResourceManager::bind_descriptor(const std::string& key, size_t index, const GpuBufferBinding& spec)
338{
339 auto& unit = unit_for(key);
340 auto& foundry = Portal::Graphics::get_shader_foundry();
341 auto& vk_slot = unit.impl->buffers[index];
342
343 foundry.update_descriptor_buffer(
344 unit.descriptor_set_ids[spec.set],
345 spec.binding,
346 vk::DescriptorType::eStorageBuffer,
347 vk_slot.buffer, 0, vk_slot.allocated_bytes);
348}
349
350size_t GpuResourceManager::buffer_allocated_bytes(const std::string& key, size_t index) const
351{
352 return find_unit(key)->buffer_slots[index].allocated_bytes;
353}
354
355void GpuResourceManager::ensure_shared_buffer(uint32_t set, size_t binding_index, size_t element_count,
358{
359 const size_t width = Portal::Graphics::element_type_bytes(element_type);
360 if (width == 0) {
361 error<std::runtime_error>(
364 std::source_location::current(),
365 "GpuResourceManager: ensure_shared_buffer requires a sized element_type");
366 }
367
368 auto& slot = m_shared->slots[{ set, binding_index }];
369 const size_t required_bytes = element_count * width;
370 if (slot.allocated_bytes >= required_bytes)
371 return;
372
373 auto& foundry = Portal::Graphics::get_shader_foundry();
374 allocate_slot(foundry.get_device(), foundry.get_physical_device(),
375 slot, required_bytes, Portal::Graphics::to_buffer_usage_flags(usage_hint));
376}
377
378void GpuResourceManager::bind_shared_descriptor(const std::string& key, uint32_t set, size_t binding_index, const GpuBufferBinding& spec)
379{
380 auto& unit = unit_for(key);
381 auto& foundry = Portal::Graphics::get_shader_foundry();
382 auto& slot = m_shared->slots.at({ set, binding_index });
383
384 foundry.update_descriptor_buffer(
385 unit.descriptor_set_ids[spec.set],
386 spec.binding,
387 vk::DescriptorType::eStorageBuffer,
388 slot.buffer, 0, slot.allocated_bytes);
389}
390
391void GpuResourceManager::download_shared(uint32_t set, size_t binding_index, void* dest, size_t byte_size)
392{
393 auto& slot = m_shared->slots.at({ set, binding_index });
394 std::memcpy(dest, slot.mapped_ptr, byte_size);
395}
396
397void GpuResourceManager::upload_shared_raw(uint32_t set, size_t binding_index, const uint8_t* data, size_t byte_size)
398{
399 auto& slot = m_shared->slots.at({ set, binding_index });
400 std::memcpy(slot.mapped_ptr, data, byte_size);
401}
402
404 const GpuBufferBinding& spec) const
405{
406 const auto it = m_shared->slots.find({ spec.set, static_cast<size_t>(spec.binding) });
407 vk::Buffer handle = it != m_shared->slots.end() ? it->second.buffer : vk::Buffer {};
409 .binding = spec,
410 .image = nullptr,
411 .buffer = handle,
412 };
413}
414
416 const std::string& key, size_t index,
417 const std::shared_ptr<Core::VKImage>& image,
418 const GpuBufferBinding& spec)
419{
420 auto& unit = unit_for(key);
421 auto& foundry = Portal::Graphics::get_shader_foundry();
422
423 if (index >= unit.image_slots.size())
424 unit.image_slots.resize(index + 1);
425 unit.image_slots[index] = image;
426
427 foundry.update_descriptor_storage_image(
428 unit.descriptor_set_ids[spec.set],
429 spec.binding,
430 image->get_image_view(),
431 vk::ImageLayout::eGeneral);
432}
433
435 const std::string& key, size_t index,
436 const std::shared_ptr<Core::VKImage>& image,
437 vk::Sampler sampler,
438 const GpuBufferBinding& spec)
439{
440 auto& unit = unit_for(key);
441 auto& foundry = Portal::Graphics::get_shader_foundry();
442
443 if (index >= unit.image_slots.size())
444 unit.image_slots.resize(index + 1);
445 unit.image_slots[index] = image;
446
447 foundry.update_descriptor_image(
448 unit.descriptor_set_ids[spec.set],
449 spec.binding,
450 image->get_image_view(),
451 sampler,
452 vk::ImageLayout::eShaderReadOnlyOptimal);
453}
454
456 const std::shared_ptr<Core::VKImage>& image,
457 vk::ImageLayout old_layout,
458 vk::ImageLayout new_layout)
459{
460 auto& foundry = Portal::Graphics::get_shader_foundry();
461 auto& backend = Portal::Graphics::get_texture_manager(); // TextureLoom -> backend ref
462
463 backend.transition_layout(
464 image,
465 old_layout,
466 new_layout,
467 1, 1, vk::ImageAspectFlagBits::eColor);
468}
469
470//==============================================================================
471// Dispatch
472//==============================================================================
473
474void GpuResourceManager::dispatch(const std::string& key,
475 const std::array<uint32_t, 3>& groups,
476 const std::vector<GpuBufferBinding>& bindings,
477 const uint8_t* push_constant_data,
478 size_t push_constant_size)
479{
480 auto& unit = unit_for(key);
481 auto& foundry = Portal::Graphics::get_shader_foundry();
482 auto& compute_press = Portal::Graphics::get_compute_press();
483
484 auto cmd_id = foundry.begin_commands(
486
487 compute_press.bind_all(
488 cmd_id, unit.pipeline_id, unit.descriptor_set_ids,
489 push_constant_data, push_constant_size);
490
491 compute_press.dispatch(cmd_id, groups[0], groups[1], groups[2]);
492
493 for (const auto& b : bindings) {
494 const auto et = b.element_type;
497 const bool is_output = b.direction == GpuBufferBinding::Direction::OUTPUT
499
500 const bool is_shared = m_shared->slots.contains({ b.set, static_cast<size_t>(b.binding) });
501 if (is_output && !is_image && !is_shared
502 && static_cast<size_t>(b.binding) < unit.impl->buffers.size()) {
503 foundry.buffer_barrier(
504 cmd_id,
505 unit.impl->buffers[b.binding].buffer,
506 vk::AccessFlagBits::eShaderWrite,
507 vk::AccessFlagBits::eHostRead,
508 vk::PipelineStageFlagBits::eComputeShader,
509 vk::PipelineStageFlagBits::eHost);
510 }
511 }
512
513 foundry.submit_and_wait(cmd_id);
514}
515
516void GpuResourceManager::dispatch_batched(const std::string& key,
517 const std::array<uint32_t, 3>& groups,
518 const std::vector<GpuBufferBinding>& bindings,
519 size_t push_constant_size,
520 const ExecutionContext& ctx)
521{
522 const auto& params = safe_variant_get_or_throw<ChainedParams>(ctx.parameters,
523 "GpuResourceManager: dispatch_batched requires ChainedParams");
524
525 auto& unit = unit_for(key);
526 auto& foundry = Portal::Graphics::get_shader_foundry();
527 auto& compute_press = Portal::Graphics::get_compute_press();
528
529 const uint32_t workgroups_per_pass = groups[0] * groups[1] * groups[2];
530
531 const uint32_t default_passes = std::max(1U, 65536U / std::max(1U, workgroups_per_pass));
532
533 const uint32_t effective_passes_per_batch = params.passes_per_batch.value_or(default_passes);
534 for (uint32_t base = 0; base < params.pass_count; base += effective_passes_per_batch) {
535 const uint32_t batch_end = std::min(base + effective_passes_per_batch, params.pass_count);
536 auto cmd_id = foundry.begin_commands(
538
539 for (uint32_t pass = base; pass < batch_end; ++pass) {
540 std::vector<uint8_t> pc_data(push_constant_size);
541 params.pc_updater(pass, pc_data.data());
542 compute_press.bind_all(
543 cmd_id, unit.pipeline_id, unit.descriptor_set_ids,
544 pc_data.data(), push_constant_size);
545 compute_press.dispatch(cmd_id, groups[0], groups[1], groups[2]);
546
547 for (const auto& b : bindings) {
549 continue;
550
551 const bool is_image = b.element_type == GpuBufferBinding::ElementType::IMAGE_STORAGE
553 const bool is_shared = m_shared->slots.contains({ b.set, static_cast<size_t>(b.binding) });
554
555 if (is_image) {
556 if (static_cast<size_t>(b.binding) < unit.image_slots.size() && unit.image_slots[b.binding]) {
557 foundry.image_barrier(
558 cmd_id,
559 unit.image_slots[b.binding]->get_image(),
560 vk::ImageLayout::eGeneral,
561 vk::ImageLayout::eGeneral,
562 vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
563 vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
564 vk::PipelineStageFlagBits::eComputeShader,
565 vk::PipelineStageFlagBits::eComputeShader);
566 }
567 } else if (!is_shared && static_cast<size_t>(b.binding) < unit.impl->buffers.size()) {
568 foundry.buffer_barrier(
569 cmd_id,
570 unit.impl->buffers[b.binding].buffer,
571 vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
572 vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
573 vk::PipelineStageFlagBits::eComputeShader,
574 vk::PipelineStageFlagBits::eComputeShader);
575 }
576 }
577 }
578
579 for (const auto& b : bindings) {
582 const bool is_image = b.element_type == GpuBufferBinding::ElementType::IMAGE_STORAGE
584 const bool is_shared = m_shared->slots.contains({ b.set, static_cast<size_t>(b.binding) });
585 if (!is_image && !is_shared && static_cast<size_t>(b.binding) < unit.impl->buffers.size()) {
586 foundry.buffer_barrier(
587 cmd_id,
588 unit.impl->buffers[b.binding].buffer,
589 vk::AccessFlagBits::eShaderWrite,
590 vk::AccessFlagBits::eHostRead,
591 vk::PipelineStageFlagBits::eComputeShader,
592 vk::PipelineStageFlagBits::eHost);
593 }
594 }
595 }
596
597 foundry.submit_and_wait(cmd_id);
598 }
599}
600
602 uint32_t indirect_set, size_t indirect_binding,
603 const std::array<uint32_t, 3>& groups,
604 const std::vector<GpuBufferBinding>& bindings,
605 size_t push_constant_size,
606 const ExecutionContext& ctx)
607{
608 const auto& params = safe_variant_get_or_throw<ChainedIndirectParams>(ctx.parameters,
609 "GpuResourceManager: dispatch_batched_indirect requires ChainedIndirectParams");
610
611 auto& unit = unit_for(key);
612 auto& foundry = Portal::Graphics::get_shader_foundry();
613 auto& compute_press = Portal::Graphics::get_compute_press();
614
615 auto& indirect_slot = m_shared->slots.at({ indirect_set, indirect_binding });
616 const vk::Buffer indirect_buffer = indirect_slot.buffer;
617 const uint32_t init_cmd[3] = { groups[0], groups[1], groups[2] };
618 std::memcpy(indirect_slot.mapped_ptr, init_cmd, sizeof(init_cmd));
619
620 const uint32_t default_passes = std::max(1U, 65536U / std::max(1U, groups[0] * groups[1] * groups[2]));
621 const uint32_t effective_passes_per_batch = params.passes_per_batch.value_or(default_passes);
622
623 for (uint32_t base = 0; base < params.pass_count; base += effective_passes_per_batch) {
624 const uint32_t batch_end = std::min(base + effective_passes_per_batch, params.pass_count);
625 auto cmd_id = foundry.begin_commands(Portal::Graphics::ShaderFoundry::CommandBufferType::COMPUTE);
626
627 for (uint32_t pass = base; pass < batch_end; ++pass) {
628 std::vector<uint8_t> pc_data(push_constant_size);
629 params.pc_updater(pass, 1, pc_data.data());
630 compute_press.bind_all(cmd_id, unit.pipeline_id, unit.descriptor_set_ids, pc_data.data(), push_constant_size);
631 compute_press.dispatch_indirect(cmd_id, indirect_buffer);
632
633 for (const auto& b : bindings) {
634 const auto et = b.element_type;
637 const bool is_output = b.direction == GpuBufferBinding::Direction::OUTPUT
639 const bool is_shared = m_shared->slots.contains({ b.set, static_cast<size_t>(b.binding) });
640 if (is_output && !is_image && !is_shared
641 && static_cast<size_t>(b.binding) < unit.impl->buffers.size()) {
642 foundry.buffer_barrier(
643 cmd_id,
644 unit.impl->buffers[b.binding].buffer,
645 vk::AccessFlagBits::eShaderWrite,
646 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
647 vk::PipelineStageFlagBits::eComputeShader,
648 vk::PipelineStageFlagBits::eComputeShader);
649 }
650 }
651 }
652 foundry.submit_and_wait(cmd_id);
653 }
654}
655
657 const std::array<uint32_t, 3>& groups,
658 const std::vector<GpuBufferBinding>& bindings,
659 const uint8_t* push_constant_data,
660 size_t push_constant_size)
661{
662 auto& unit = unit_for(key);
663 auto& foundry = Portal::Graphics::get_shader_foundry();
664 auto& compute_press = Portal::Graphics::get_compute_press();
665
666 auto cmd_id = foundry.begin_commands(
668
669 compute_press.bind_all(
670 cmd_id, unit.pipeline_id, unit.descriptor_set_ids,
671 push_constant_data, push_constant_size);
672
673 compute_press.dispatch(cmd_id, groups[0], groups[1], groups[2]);
674
675 for (const auto& b : bindings) {
676 const auto et = b.element_type;
679 const bool is_output = b.direction == GpuBufferBinding::Direction::OUTPUT
681 if (is_output && !is_image) {
682 foundry.buffer_barrier(
683 cmd_id,
684 unit.impl->buffers[b.binding].buffer,
685 vk::AccessFlagBits::eShaderWrite,
686 vk::AccessFlagBits::eHostRead,
687 vk::PipelineStageFlagBits::eComputeShader,
688 vk::PipelineStageFlagBits::eHost);
689 }
690 }
691
692 return foundry.submit_async(cmd_id);
693}
694
696 const std::vector<std::string>& keys,
697 const std::vector<std::array<uint32_t, 3>>& groups_per_key,
698 const std::vector<std::vector<uint8_t>>& push_constants_per_key,
699 const std::vector<std::vector<Portal::Graphics::HazardResource>>& hazards_per_key)
700{
701 auto& foundry = Portal::Graphics::get_shader_foundry();
702 auto& compute_press = Portal::Graphics::get_compute_press();
703
704 std::vector<Portal::Graphics::ComputeStage> stages;
705 stages.reserve(keys.size());
706
707 for (size_t i = 0; i < keys.size(); ++i) {
708 auto& unit = unit_for(keys[i]);
709 stages.push_back(Portal::Graphics::ComputeStage {
710 .pipeline_id = unit.pipeline_id,
711 .descriptor_set_ids = unit.descriptor_set_ids,
712 .groups = groups_per_key[i],
713 .push_constant_data = push_constants_per_key[i],
714 .hazard_resources = hazards_per_key[i],
715 });
716 }
717
718 auto cmd_id = foundry.begin_commands(
720 compute_press.record_sequence(cmd_id, stages);
721 foundry.submit_and_wait(cmd_id);
722}
723
724} // namespace MayaFlux::Yantra
#define MF_ERROR(comp, ctx,...)
IO::ImageData image
Definition Decoder.cpp:64
uint32_t width
Definition Decoder.cpp:66
size_t b
uint32_t pass
float k
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 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...
Portal::Graphics::HazardResource make_shared_buffer_hazard(const GpuBufferBinding &spec) const
PipelineUnit & unit_for(const std::string &key)
void upload(const std::string &key, size_t index, const float *data, size_t byte_size)
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.
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)
Record a dispatch for each requested key into one command buffer via ComputePress::record_sequence,...
std::unordered_map< std::string, std::unique_ptr< PipelineUnit > > m_units
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)
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.
size_t element_type_bytes(GpuBufferBinding::ElementType et) noexcept
Byte width of one GpuBufferBinding::ElementType element.
constexpr ShaderID INVALID_SHADER
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.
constexpr ComputePipelineID INVALID_COMPUTE_PIPELINE
BufferUsageHint
Semantic usage hint for buffer allocation and memory properties.
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)
Definition Depot.cpp:108
ComputePipelineID pipeline_id
Pipeline to bind for this stage.
One pipeline dispatch within a ComputePress::record_sequence call.
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.
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,...
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::unique_ptr< GpuResourceManagerImpl > impl
std::map< std::pair< uint32_t, size_t >, VulkanBufferSlot > slots