MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ShaderProcessor.cpp
Go to the documentation of this file.
1#include "ShaderProcessor.hpp"
2
4
5namespace MayaFlux::Buffers {
6
7//==============================================================================
8// Construction
9//==============================================================================
10
11ShaderProcessor::ShaderProcessor(const std::string& shader_path)
12 : m_config({ shader_path })
13{
14 m_processing_token = ProcessingToken::GRAPHICS_BACKEND;
15 initialize_buffer_service();
16 initialize_compute_service();
17}
18
26
31
32//==============================================================================
33// BufferProcessor Interface
34//==============================================================================
35
36void ShaderProcessor::processing_function(const std::shared_ptr<Buffer>& buffer)
37{
38 auto vk_buffer = std::dynamic_pointer_cast<VKBuffer>(buffer);
39 if (!vk_buffer) {
41 "ShaderProcessor can only process VKBuffers");
42 return;
43 }
44
45 if (!m_feeds.empty()) {
46 pump_feeds();
47 }
48
51 if (is_dispatch_pending()) {
52 return;
53 }
54 }
55
58 "on_before_execute() reported failure, skipping shader execution");
59 return;
60 }
61
62 if (!m_initialized) {
64 initialize_pipeline(vk_buffer);
66 m_initialized = true;
67 }
68
70 initialize_pipeline(vk_buffer);
73 }
74
76 initialize_descriptors(vk_buffer);
78 } else {
79 update_descriptors(vk_buffer);
80 }
81
82 execute_shader(vk_buffer);
84}
85
86void ShaderProcessor::on_attach(const std::shared_ptr<Buffer>& buffer)
87{
88 auto vk_buffer = std::dynamic_pointer_cast<VKBuffer>(buffer);
89 if (!vk_buffer)
90 return;
91
92 if (m_config.bindings.empty()) {
93 auto_bind_buffer(vk_buffer);
94 }
95
97 "ShaderProcessor attached to VKBuffer (size: {} bytes, modality: {})",
98 vk_buffer->get_size_bytes(),
99 static_cast<int>(vk_buffer->get_modality()));
100}
101
102void ShaderProcessor::on_detach(const std::shared_ptr<Buffer>& buffer)
103{
104 auto vk_buffer = std::dynamic_pointer_cast<VKBuffer>(buffer);
105 if (!vk_buffer)
106 return;
107
108 for (auto it = m_bound_buffers.begin(); it != m_bound_buffers.end();) {
109 if (it->second == vk_buffer) {
110 it = m_bound_buffers.erase(it);
111 } else {
112 ++it;
113 }
114 }
116}
117
118bool ShaderProcessor::is_compatible_with(const std::shared_ptr<Buffer>& buffer) const
119{
120 return std::dynamic_pointer_cast<VKBuffer>(buffer) != nullptr;
121}
122
123//==============================================================================
124// Buffer Binding
125//==============================================================================
126
127void ShaderProcessor::bind_buffer(const std::string& descriptor_name, const std::shared_ptr<VKBuffer>& buffer)
128{
129 if (!buffer) {
131 "Cannot bind null buffer to descriptor '{}'", descriptor_name);
132 return;
133 }
134
135 ensure_initialized(buffer);
136
137 if (m_config.bindings.find(descriptor_name) == m_config.bindings.end()) {
138 auto user_binding_count = static_cast<uint32_t>(
139 std::ranges::count_if(m_config.bindings, [](const auto& pair) {
140 return pair.second.set == 1;
141 }));
142
143 ShaderBinding default_binding;
144 default_binding.set = 1;
145 default_binding.binding = user_binding_count;
146 default_binding.type = vk::DescriptorType::eStorageBuffer;
147 m_config.bindings[descriptor_name] = default_binding;
148
150 "Created default binding for '{}': set={}, binding={}",
151 descriptor_name, default_binding.set, default_binding.binding);
152 }
153
154 m_bound_buffers[descriptor_name] = buffer;
156
158 "Bound buffer to descriptor '{}' (size: {} bytes)",
159 descriptor_name, buffer->get_size_bytes());
160}
161
162void ShaderProcessor::unbind_buffer(const std::string& descriptor_name)
163{
164 auto it = m_bound_buffers.find(descriptor_name);
165 if (it != m_bound_buffers.end()) {
166 m_bound_buffers.erase(it);
168 }
169}
170
171std::shared_ptr<VKBuffer> ShaderProcessor::get_bound_buffer(const std::string& descriptor_name) const
172{
173 auto it = m_bound_buffers.find(descriptor_name);
174 return it != m_bound_buffers.end() ? it->second : nullptr;
175}
176
177void ShaderProcessor::auto_bind_buffer(const std::shared_ptr<VKBuffer>& buffer)
178{
179 std::string descriptor_name;
180 if (m_auto_bind_index == 0) {
181 descriptor_name = "input";
182 } else if (m_auto_bind_index == 1) {
183 descriptor_name = "output";
184 } else {
185 descriptor_name = "buffer_" + std::to_string(m_auto_bind_index);
186 }
187
188 bind_buffer(descriptor_name, buffer);
190}
191
193 const std::string& descriptor_name,
194 void* data,
195 size_t size,
196 const std::shared_ptr<VKBuffer>& staging) const
197{
198 auto buffer = get_bound_buffer(descriptor_name);
199 if (!buffer) {
201 "download_bound: no buffer bound to descriptor '{}'", descriptor_name);
202 return false;
203 }
204
205 download_from_gpu(buffer, data, size, staging);
206 return true;
207}
208
209//==============================================================================
210// Feeds
211//==============================================================================
212
213void ShaderProcessor::feed(const std::string& name, FeedSource source)
214{
215 if (!source) {
217 "feed: null source for '{}'", name);
218 return;
219 }
220
221 if (m_config.bindings.contains(name)) {
222 auto& entry = m_feeds[name];
223 entry.source = std::move(source);
224 entry.is_storage = true;
225 entry.offset = 0;
226 entry.size = 0;
227 entry.descriptor_name = name;
228 entry.buffer.reset();
229 entry.mismatch_logged = false;
230 return;
231 }
232
233 uint32_t offset = 0;
234 for (const auto& field : m_config.pc_fields) {
235 const size_t width = Kakshya::gpu_data_format_bytes(field.format);
236 if (field.name == name) {
237 auto& entry = m_feeds[name];
238 entry.source = std::move(source);
239 entry.is_storage = false;
240 entry.offset = offset;
241 entry.size = width;
242 entry.descriptor_name.clear();
243 entry.buffer.reset();
244 entry.mismatch_logged = false;
245 return;
246 }
247 offset += static_cast<uint32_t>(width);
248 }
249
251 "feed: '{}' matches no descriptor and no push constant field. "
252 "File-shader processors must supply an explicit offset.",
253 name);
254}
255
256void ShaderProcessor::feed(const std::string& name, FeedSource source, uint32_t offset, size_t size)
257{
258 if (!source) {
260 "feed: null source for '{}'", name);
261 return;
262 }
263
264 if (size != sizeof(float) && size != sizeof(double)) {
266 "feed: '{}' requests {} bytes, only 4 or 8 are written", name, size);
267 return;
268 }
269
270 auto& entry = m_feeds[name];
271 entry.source = std::move(source);
272 entry.is_storage = false;
273 entry.offset = offset;
274 entry.size = size;
275 entry.descriptor_name.clear();
276 entry.buffer.reset();
277 entry.mismatch_logged = false;
278}
279
280void ShaderProcessor::remove_feed(const std::string& name)
281{
282 auto it = m_feeds.find(name);
283 if (it == m_feeds.end()) {
284 return;
285 }
286
287 if (it->second.is_storage) {
288 unbind_buffer(it->second.descriptor_name);
289 }
290
291 m_feeds.erase(it);
292}
293
294bool ShaderProcessor::has_feed(const std::string& name) const
295{
296 return m_feeds.contains(name);
297}
298
299std::vector<std::string> ShaderProcessor::get_feed_names() const
300{
301 std::vector<std::string> names;
302 names.reserve(m_feeds.size());
303 for (const auto& [name, _] : m_feeds) {
304 names.push_back(name);
305 }
306 return names;
307}
308
310{
311 for (auto& [name, entry] : m_feeds) {
312 FeedValue value = entry.source();
313
314 if (!entry.is_storage) {
315 const auto* scalar = std::get_if<double>(&value);
316 if (!scalar) {
317 if (!entry.mismatch_logged) {
319 "feed '{}' writes a push constant but returned a DataVariant", name);
320 entry.mismatch_logged = true;
321 }
322 continue;
323 }
324
325 auto& data = get_push_constant_data();
326 const size_t required = entry.offset + entry.size;
327 if (data.size() < required) {
328 data.resize(required);
329 }
330
331 if (entry.size == sizeof(float)) {
332 const auto narrowed = static_cast<float>(*scalar);
333 std::memcpy(data.data() + entry.offset, &narrowed, sizeof(float));
334 } else {
335 std::memcpy(data.data() + entry.offset, scalar, sizeof(double));
336 }
337 continue;
338 }
339
340 auto* variant = std::get_if<Kakshya::DataVariant>(&value);
341 if (!variant) {
342 if (!entry.mismatch_logged) {
344 "feed '{}' writes a storage descriptor but returned a double", name);
345 entry.mismatch_logged = true;
346 }
347 continue;
348 }
349
351 auto [ptr, bytes, format] = accessor.gpu_buffer();
352
353 if (!ptr || bytes == 0) {
355 "feed '{}' produced no bytes", name);
356 continue;
357 }
358
359 if (!entry.buffer) {
360 entry.buffer = std::make_shared<VKBuffer>(
361 static_cast<size_t>(static_cast<float>(bytes) * 1.5F),
362 m_config.bindings.at(entry.descriptor_name).type == vk::DescriptorType::eUniformBuffer
363 ? VKBuffer::Usage::UNIFORM
364 : VKBuffer::Usage::HOST_STORAGE,
366
367 bind_buffer(entry.descriptor_name, entry.buffer);
368
370 "feed '{}' backing buffer created at {} bytes",
371 name, entry.buffer->get_size_bytes());
372 } else if (entry.buffer->get_size_bytes() < bytes) {
373 const size_t grown = bytes * 3 / 2;
374
376 "feed '{}' backing buffer resized {} to {} bytes",
377 name, entry.buffer->get_size_bytes(), grown);
378
379 entry.buffer->resize(grown, false);
381 }
382
383 upload_host_visible(entry.buffer, *variant);
384 }
385}
386
387//==============================================================================
388// Shader Management
389//==============================================================================
390
392{
394 "Hot-reloading shader: {}", m_config.shader_path);
395
396 auto& foundry = Portal::Graphics::get_shader_foundry();
397 auto new_shader_id = foundry.reload_shader(m_config.shader_path);
398
399 if (new_shader_id == Portal::Graphics::INVALID_SHADER) {
401 "Hot-reload failed for shader: {}", m_config.shader_path);
402 return false;
403 }
404
406 foundry.destroy_shader(m_shader_id);
407 }
408
409 m_shader_id = new_shader_id;
412
414 "Shader hot-reloaded successfully (ID: {})", m_shader_id);
415 return true;
416}
417
418void ShaderProcessor::set_shader(const std::string& shader_path)
419{
420 m_config.shader_path = shader_path;
423}
424
425//==============================================================================
426// Push Constants
427//==============================================================================
428
435
436void ShaderProcessor::set_push_constant_data_raw(const void* data, size_t size)
437{
438 if (size > m_config.push_constant_size) {
440 "Push constant data size {} exceeds configured size {}",
442 return;
443 }
444
445 m_push_constant_data.resize(size);
446 std::memcpy(m_push_constant_data.data(), data, size);
447}
448
449size_t ShaderProcessor::resolve_push_constant_size(const std::shared_ptr<VKBuffer>& buffer) const
450{
451 size_t size = std::max(m_config.push_constant_size, m_push_constant_data.size());
452
453 for (const auto& entry : buffer->get_pipeline_context().push_constant_bindings) {
454 size = std::max(size, static_cast<size_t>(entry.offset) + entry.data.size());
455 }
456
457 return size;
458}
459
460std::vector<uint8_t> ShaderProcessor::resolve_push_constants(const std::shared_ptr<VKBuffer>& buffer) const
461{
462 std::vector<uint8_t> merged = m_push_constant_data;
463 merged.resize(resolve_push_constant_size(buffer));
464
465 for (const auto& entry : buffer->get_pipeline_context().push_constant_bindings) {
466 std::memcpy(merged.data() + entry.offset, entry.data.data(), entry.data.size());
467 }
468
469 return merged;
470}
471
472//==============================================================================
473// Submission
474//==============================================================================
475
477{
478 if (!deferred && is_dispatch_pending()) {
480 }
481 m_deferred_submission = deferred;
482}
483
485{
486 if (!is_dispatch_pending()) {
487 return false;
488 }
489
490 auto& foundry = Portal::Graphics::get_shader_foundry();
491
492 if (block) {
493 foundry.wait_for_fence(m_pending_fence);
494 } else if (!foundry.is_fence_signaled(m_pending_fence)) {
495 return false;
496 }
497
498 const auto fence = m_pending_fence;
499 auto buffer = m_pending_buffer;
500
502 m_pending_buffer.reset();
503
504 on_dispatch_complete(buffer);
505 foundry.release_fence(fence);
506
507 return true;
508}
509
512 const std::shared_ptr<VKBuffer>& buffer)
513{
514 auto& foundry = Portal::Graphics::get_shader_foundry();
515
517 foundry.submit_and_wait(cmd_id);
518 return;
519 }
520
521 m_pending_fence = foundry.submit_async(cmd_id);
522
525 "Deferred submission failed, no fence returned");
526 return;
527 }
528
529 m_pending_buffer = buffer;
530}
531
532//==============================================================================
533// Specialization Constants
534//==============================================================================
535
536void ShaderProcessor::set_specialization_constant(uint32_t constant_id, uint32_t value)
537{
540}
541
547
548//==============================================================================
549// Configuration
550//==============================================================================
551
553{
554 m_config = config;
558}
559
560void ShaderProcessor::add_binding(const std::string& descriptor_name, const ShaderBinding& binding)
561{
562 m_config.bindings[descriptor_name] = binding;
564}
565
566//==========================================================================
567// Data movement Queries
568//==========================================================================
569
570[[nodiscard]] ShaderProcessor::BufferUsageHint ShaderProcessor::get_buffer_usage_hint(const std::string& descriptor_name) const
571{
572 if (descriptor_name == "input")
574 if (descriptor_name == "output")
577}
578
579bool ShaderProcessor::is_in_place_operation(const std::string& descriptor_name) const
580{
581 auto hint = get_buffer_usage_hint(descriptor_name);
582 return hint == BufferUsageHint::BIDIRECTIONAL;
583}
584
585bool ShaderProcessor::has_binding(const std::string& descriptor_name) const
586{
587 return m_config.bindings.find(descriptor_name) != m_config.bindings.end();
588}
589
590std::vector<std::string> ShaderProcessor::get_binding_names() const
591{
592 std::vector<std::string> names;
593 names.reserve(m_config.bindings.size());
594 for (const auto& [name, _] : m_config.bindings) {
595 names.push_back(name);
596 }
597 return names;
598}
599
601{
602 return std::ranges::all_of(
604 [this](const auto& pair) {
605 return m_bound_buffers.find(pair.first) != m_bound_buffers.end();
606 });
607}
608
609//==============================================================================
610// Protected Hooks
611//==============================================================================
612
613void ShaderProcessor::on_before_compile(const std::string&) { }
618bool ShaderProcessor::on_before_execute(Portal::Graphics::CommandBufferID, const std::shared_ptr<VKBuffer>&) { return true; }
620void ShaderProcessor::on_dispatch_complete(const std::shared_ptr<VKBuffer>&) { }
621
622//==============================================================================
623// Private Implementation
624//==============================================================================
625
651
652std::optional<uint32_t> ShaderProcessor::resolve_ds_index(uint32_t set) const
653{
655 if (set == 0)
656 return std::nullopt;
657 const uint32_t idx = set - 1;
658 if (idx >= m_descriptor_set_ids.size())
659 return std::nullopt;
660 return idx;
661 }
662 if (set >= m_descriptor_set_ids.size())
663 return std::nullopt;
664 return set;
665}
666
667void ShaderProcessor::update_descriptors(const std::shared_ptr<VKBuffer>& buffer)
668{
669 if (m_descriptor_set_ids.empty()) {
670 return;
671 }
672
673 auto& foundry = Portal::Graphics::get_shader_foundry();
674 auto& descriptor_bindings = buffer->get_pipeline_context().descriptor_buffer_bindings;
675
676 std::set<std::pair<uint32_t, uint32_t>> updated_pairs;
677
678 for (const auto& binding : descriptor_bindings) {
679 auto ds_index = resolve_ds_index(binding.set);
680 if (!ds_index) {
682 "Descriptor set index {} out of range or reserved", binding.set);
683 continue;
684 }
685
686 foundry.update_descriptor_buffer(
687 m_descriptor_set_ids[*ds_index],
688 binding.binding,
689 binding.type,
690 binding.buffer_info.buffer,
691 binding.buffer_info.offset,
692 binding.buffer_info.range);
693
694 updated_pairs.emplace(binding.set, binding.binding);
695 }
696
697 for (const auto& [descriptor_name, buf] : m_bound_buffers) {
698 auto binding_it = m_config.bindings.find(descriptor_name);
699 if (binding_it == m_config.bindings.end()) {
700 continue;
701 }
702
703 const auto& binding = binding_it->second;
704 auto key = std::make_pair(binding.set, binding.binding);
705
706 if (updated_pairs.count(key)) {
707 continue;
708 }
709
710 auto ds_index = resolve_ds_index(binding.set);
711 if (!ds_index) {
713 "Invalid descriptor set index {} for binding '{}'",
714 binding.set, descriptor_name);
715 continue;
716 }
717
718 foundry.update_descriptor_buffer(
719 m_descriptor_set_ids[*ds_index],
720 binding.binding,
721 binding.type,
722 buf->get_buffer(),
723 0,
724 buf->get_size_bytes());
725 }
726}
727
729{
731 auto& foundry = Portal::Graphics::get_shader_foundry();
732 auto& compute_press = Portal::Graphics::get_compute_press();
733
735 foundry.destroy_shader(m_shader_id);
737 }
738
739 m_descriptor_set_ids.clear();
740 m_bound_buffers.clear();
741 m_feeds.clear();
742 m_initialized = false;
743}
744
745} // namespace MayaFlux::Buffers
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_RT_WARN(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_TRACE(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
#define MF_RT_DEBUG(comp, ctx,...)
vk::Fence fence
std::string name
Definition VKDevice.cpp:143
const uint8_t * ptr
float value
float offset
uint32_t width
bool download_bound(const std::string &descriptor_name, void *data, size_t size, const std::shared_ptr< VKBuffer > &staging=nullptr) const
Download the buffer currently bound to a named descriptor.
virtual void initialize_pipeline(const std::shared_ptr< VKBuffer > &buffer)=0
const std::vector< uint8_t > & get_push_constant_data() const
Get current push constant data.
bool has_feed(const std::string &name) const
Whether a feed of this name is registered.
ShaderProcessor(const std::string &shader_path)
Construct processor with shader path.
void pump_feeds()
Pull every feed and write its result.
Portal::Graphics::CommandBufferID m_last_command_buffer
bool are_bindings_complete() const
Check if all required bindings are satisfied.
std::optional< uint32_t > resolve_ds_index(uint32_t set) const
Resolve logical descriptor set index to actual index.
virtual void execute_shader(const std::shared_ptr< VKBuffer > &buffer)=0
std::unordered_map< std::string, std::shared_ptr< VKBuffer > > m_bound_buffers
void unbind_buffer(const std::string &descriptor_name)
Unbind a buffer from a descriptor.
Portal::Graphics::ShaderID m_shader_id
std::vector< uint8_t > m_push_constant_data
std::vector< std::string > get_feed_names() const
Names of every registered feed.
virtual void on_after_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr< VKBuffer > &buffer)
Called after each process callback.
virtual void on_descriptors_created()
Called after descriptor sets are created.
virtual void initialize_descriptors(const std::shared_ptr< VKBuffer > &buffer)=0
std::shared_ptr< VKBuffer > m_pending_buffer
Buffer retained for the outstanding submission.
std::shared_ptr< VKBuffer > get_bound_buffer(const std::string &descriptor_name) const
Get bound buffer for a descriptor name.
size_t resolve_push_constant_size(const std::shared_ptr< VKBuffer > &buffer) const
Byte width of this processor's push constant block, extended to cover any fragment staged on the buff...
virtual void update_descriptors(const std::shared_ptr< VKBuffer > &buffer)
virtual void on_before_compile(const std::string &shader_path)
Called before shader compilation.
virtual bool on_before_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr< VKBuffer > &buffer)
Called before each process callback.
void on_detach(const std::shared_ptr< Buffer > &buffer) override
Called when this processor is detached from a buffer.
void auto_bind_buffer(const std::shared_ptr< VKBuffer > &buffer)
Auto-bind buffer based on attachment order.
bool has_binding(const std::string &descriptor_name) const
Check if a descriptor binding exists.
void set_push_constant_size()
Set push constant size from type.
void processing_function(const std::shared_ptr< Buffer > &buffer) override
The core processing function that must be implemented by derived classes.
virtual void on_pipeline_created(Portal::Graphics::ComputePipelineID pipeline_id)
Called after pipeline is created.
Portal::Graphics::FenceID m_pending_fence
Outstanding async submission, if any.
virtual bool is_in_place_operation(const std::string &descriptor_name) const
Check if shader modifies a specific buffer in-place.
virtual void on_shader_loaded(Portal::Graphics::ShaderID shader_id)
Called after shader is loaded.
void submit_recorded(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr< VKBuffer > &buffer)
Submit a recorded command buffer honoring the submission mode.
void add_binding(const std::string &descriptor_name, const ShaderBinding &binding)
Add descriptor binding configuration.
bool m_deferred_submission
False submits synchronously, preserving pre-existing behaviour.
std::variant< double, Kakshya::DataVariant > FeedValue
What a feed callable returns.
void set_deferred_submission(bool deferred)
Submit asynchronously and resolve at the top of a later cycle.
bool hot_reload_shader()
Hot-reload shader from ShaderFoundry.
virtual void on_before_descriptors_create()
Called before descriptor sets are created.
void set_config(const ShaderConfig &config)
Update entire configuration.
void set_shader(const std::string &shader_path)
Update shader path and reload.
bool m_engine_owns_set_zero
Whether the engine reserves set=0 for global resources.
bool is_compatible_with(const std::shared_ptr< Buffer > &buffer) const override
Checks if this processor can handle the specified buffer type.
virtual void on_dispatch_complete(const std::shared_ptr< VKBuffer > &buffer)
Called once when an asynchronous submission is observed complete.
virtual BufferUsageHint get_buffer_usage_hint(const std::string &descriptor_name) const
Get buffer usage hint for a descriptor.
bool resolve_pending_dispatch(bool block)
Resolve an outstanding asynchronous submission.
BufferUsageHint
Get buffer usage characteristics needed for safe data flow.
@ OUTPUT_WRITE
Shader writes output (modifies)
std::vector< std::string > get_binding_names() const
Get all configured descriptor names.
bool is_dispatch_pending() const
True while an asynchronous submission is outstanding.
std::unordered_map< std::string, Feed > m_feeds
void remove_feed(const std::string &name)
Remove a feed.
void set_specialization_constant(uint32_t constant_id, uint32_t value)
Set specialization constant.
std::function< FeedValue()> FeedSource
A callable pulled once per processing cycle.
void on_attach(const std::shared_ptr< Buffer > &buffer) override
Called when this processor is attached to a buffer.
void bind_buffer(const std::string &descriptor_name, const std::shared_ptr< VKBuffer > &buffer)
Bind a VKBuffer to a named shader descriptor.
std::vector< Portal::Graphics::DescriptorSetID > m_descriptor_set_ids
void clear_specialization_constants()
Clear all specialization constants.
void feed(const std::string &name, FeedSource source)
Supply a shader input from a callable, resolved by name.
std::vector< uint8_t > resolve_push_constants(const std::shared_ptr< VKBuffer > &buffer) const
This processor's push constant data with buffer-staged fragments overlaid at their declared offsets.
virtual void set_push_constant_data_raw(const void *data, size_t size)
Update push constant data (raw bytes)
void ensure_initialized(const std::shared_ptr< VKBuffer > &buffer)
Definition VKBuffer.cpp:448
auto gpu_buffer() const
Get raw buffer info for GPU upload.
Type-erased accessor for NDData with semantic view construction.
@ GRAPHICS_BACKEND
Standard graphics processing backend configuration.
void download_from_gpu(const std::shared_ptr< VKBuffer > &source, void *data, size_t size, const std::shared_ptr< VKBuffer > &staging)
Download from GPU buffer to raw data (auto-detects host-visible vs device-local)
void upload_host_visible(const std::shared_ptr< VKBuffer > &target, const Kakshya::DataVariant &data, size_t dst_offset)
Upload data to a host-visible buffer.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Buffers
Buffers, Managers, processors and processing chains.
size_t gpu_data_format_bytes(GpuDataFormat fmt) noexcept
Byte size of one element of a GpuDataFormat.
Definition NDData.cpp:9
@ UNKNOWN
Unknown or undefined modality.
constexpr ShaderID INVALID_SHADER
constexpr FenceID INVALID_FENCE
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.
MAYAFLUX_API ComputePress & get_compute_press()
uint32_t binding
Binding point within set.
uint32_t set
Descriptor set index.
Describes how a VKBuffer binds to a shader descriptor.
std::string shader_path
Path to shader file.
std::unordered_map< uint32_t, uint32_t > specialization_constants
std::unordered_map< std::string, ShaderBinding > bindings
Portal::Graphics::ShaderStage stage
std::vector< Portal::Graphics::PushConstantField > pc_fields
Retained from a ShaderSpec so feeds can resolve a field name to an offset. Empty for file shaders.
Portal::Graphics::ShaderID shader_id