MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RenderProcessor.cpp
Go to the documentation of this file.
1#include "RenderProcessor.hpp"
2
7
12
13namespace MayaFlux::Buffers {
14
16 std::unordered_map<std::shared_ptr<VKBuffer>, RenderProcessor::VertexInfo>& buffer_info,
17 const std::shared_ptr<VKBuffer>& buffer)
18{
19 auto info_it = buffer_info.find(buffer);
20 if (info_it == buffer_info.end()) {
21 if (buffer->has_vertex_layout()) {
22 auto vertex_layout = buffer->get_vertex_layout();
23 if (vertex_layout.has_value()) {
24 buffer_info[buffer] = { .semantic_layout = vertex_layout.value(), .use_reflection = false };
25 info_it = buffer_info.find(buffer);
26 }
27 }
28 if (info_it == buffer_info.end()) {
29 return nullptr;
30 }
31 }
32 return &info_it->second.semantic_layout;
33}
34
41
42void RenderProcessor::set_fragment_shader(const std::string& fragment_path)
43{
45 m_fragment_shader_id = foundry.load_shader(fragment_path, Portal::Graphics::ShaderStage::FRAGMENT);
47}
48
49void RenderProcessor::set_geometry_shader(const std::string& geometry_path)
50{
52 m_geometry_shader_id = foundry.load_shader(geometry_path, Portal::Graphics::ShaderStage::GEOMETRY);
54}
55
56void RenderProcessor::set_tess_control_shader(const std::string& tess_control_path)
57{
59 m_tess_control_shader_id = foundry.load_shader(tess_control_path, Portal::Graphics::ShaderStage::TESS_CONTROL);
61}
62
63void RenderProcessor::set_tess_eval_shader(const std::string& tess_eval_path)
64{
66 m_tess_eval_shader_id = foundry.load_shader(tess_eval_path, Portal::Graphics::ShaderStage::TESS_EVALUATION);
68}
69
70void RenderProcessor::set_target_window(const std::shared_ptr<Core::Window>& window, const std::shared_ptr<VKBuffer>& buffer)
71{
72 m_target_window = window;
73 window->register_rendering_buffer(buffer);
74}
75
80
87
89{
90 if (enabled) {
92 } else {
94 }
95}
96
103
112
114 const Kinesis::ViewTransform& vt,
115 bool enable_depth,
117{
118 m_view_transform = vt;
119 m_view_transform_source = nullptr;
121
122 if (enable_depth && !m_depth_enabled) {
124 }
125
126 set_cull_mode(cull);
127}
128
130 std::function<Kinesis::ViewTransform()> fn,
131 bool enable_depth,
133{
134 m_view_transform_source = std::move(fn);
135 m_view_transform.reset();
137
138 if (enable_depth && !m_depth_enabled) {
140 }
141
142 set_cull_mode(cull);
143}
144
146 uint32_t binding,
147 const std::shared_ptr<Core::VKImage>& texture,
148 vk::Sampler sampler)
149{
150 if (!texture || !texture->is_initialized() || !texture->get_image_view()) {
152 "Cannot bind null texture to binding {}", binding);
153 return;
154 }
155
156 if (!sampler) {
158 sampler = loom.get_default_sampler();
159 }
160
161 m_texture_bindings[binding] = { .texture = texture, .sampler = sampler };
163
165
166 auto& foundry = Portal::Graphics::get_shader_foundry();
167 auto cfg_it = std::ranges::find_if(m_config.bindings,
168 [binding](const auto& pair) {
169 return binding >= pair.second.binding
170 && binding < pair.second.binding + pair.second.count;
171 });
172
173 if (cfg_it != m_config.bindings.end() && !m_descriptor_set_ids.empty()) {
174 const uint32_t cfg_set = cfg_it->second.set;
175 if (cfg_set == 0) {
177 uint32_t array_idx = 0;
178 if (cfg_it->second.count > 1 && binding >= cfg_it->second.binding) {
179 array_idx = binding - cfg_it->second.binding;
180 }
181 foundry.update_descriptor_image(
183 cfg_it->second.binding,
184 texture->get_image_view(),
185 sampler,
186 vk::ImageLayout::eShaderReadOnlyOptimal,
187 array_idx);
188 }
189 } else {
190 auto ds_index = resolve_ds_index(cfg_set);
191 if (ds_index && *ds_index < m_descriptor_set_ids.size()) {
192 foundry.update_descriptor_image(
193 m_descriptor_set_ids[*ds_index],
194 cfg_it->second.binding,
195 texture->get_image_view(),
196 sampler,
197 vk::ImageLayout::eShaderReadOnlyOptimal);
198 }
199 }
200 }
201 }
202
204 "Bound texture to binding {}", binding);
205}
206
208 const std::string& descriptor_name,
209 const std::shared_ptr<Core::VKImage>& texture,
210 vk::Sampler sampler)
211{
212 auto binding_it = m_config.bindings.find(descriptor_name);
213 if (binding_it == m_config.bindings.end()) {
215 "No binding configured for descriptor '{}'", descriptor_name);
216 return;
217 }
218
219 bind_texture(binding_it->second.binding, texture, sampler);
220}
221
222void RenderProcessor::initialize_pipeline(const std::shared_ptr<VKBuffer>& buffer)
223{
226 "Vertex shader not loaded");
227 return;
228 }
229
232 "Fragment shader not loaded");
233 return;
234 }
235
236 if (!m_target_window) {
238 "Target window not set");
239 return;
240 }
241
243
245
247 pipeline_config.vertex_shader = m_shader_id;
248 pipeline_config.fragment_shader = m_fragment_shader_id;
249 pipeline_config.geometry_shader = m_geometry_shader_id;
251 pipeline_config.tess_eval_shader = m_tess_eval_shader_id;
252
253 pipeline_config.topology = m_primitive_topology;
254 pipeline_config.rasterization.polygon_mode = m_polygon_mode;
255 pipeline_config.rasterization.cull_mode = m_cull_mode;
256
257 if (m_blend_attachment.has_value()) {
258 pipeline_config.blend_attachments.push_back(m_blend_attachment.value());
259 } else {
260 pipeline_config.blend_attachments.emplace_back();
261 }
262
263 pipeline_config.depth_stencil = m_depth_stencil;
264
265 if (m_buffer_info.find(buffer) == m_buffer_info.end()) {
266 if (buffer->has_vertex_layout()) {
267 auto vertex_layout = buffer->get_vertex_layout();
268 if (vertex_layout.has_value()) {
269 m_buffer_info[buffer] = {
270 .semantic_layout = vertex_layout.value(),
271 .use_reflection = false
272 };
273 }
274 }
275 }
276
278 if (!local_layout) {
280 "initialize_pipeline: layout not yet available, deferring");
281 return;
282 }
283
284 pipeline_config.semantic_vertex_layout = *local_layout;
285 pipeline_config.use_vertex_shader_reflection = m_buffer_info[buffer].use_reflection;
286
287 pipeline_config.push_constant_size = resolve_push_constant_size(buffer);
288
289 auto& descriptor_bindings = buffer->get_pipeline_context().descriptor_buffer_bindings;
290 std::map<std::pair<uint32_t, uint32_t>, Portal::Graphics::DescriptorBindingInfo> unified_bindings;
291
292 for (const auto& binding : descriptor_bindings) {
293 unified_bindings[{ binding.set, binding.binding }] = binding;
294 }
295
296 for (const auto& [name, binding] : m_config.bindings) {
297 auto key = std::make_pair(binding.set, binding.binding);
298 if (unified_bindings.find(key) == unified_bindings.end()) {
299 unified_bindings[key] = Portal::Graphics::DescriptorBindingInfo {
300 .set = binding.set,
301 .binding = binding.binding,
302 .type = binding.type,
303 .buffer_info = {},
304 .name = name,
305 .count = binding.count
306 };
307 }
308 }
309
310 std::map<uint32_t, std::vector<Portal::Graphics::DescriptorBindingInfo>> bindings_by_set;
311 for (const auto& [key, binding] : unified_bindings) {
312 bindings_by_set[binding.set].push_back(binding);
313 }
314
315 for (const auto& [set_index, set_bindings] : bindings_by_set) {
316 pipeline_config.descriptor_sets.push_back(set_bindings);
317 }
318
319 vk::Format swapchain_format = static_cast<vk::Format>(
321
322 vk::Format depth_format = m_depth_enabled
323 ? vk::Format::eD32Sfloat
324 : vk::Format::eUndefined;
325
326 m_pipeline_id = flow.create_pipeline(pipeline_config, { swapchain_format }, depth_format);
327
330 "Failed to create render pipeline");
331 return;
332 }
333
334 if (m_depth_enabled) {
335 buffer->set_needs_depth_attachment(true);
336 }
337
340
342}
343
344void RenderProcessor::initialize_descriptors(const std::shared_ptr<VKBuffer>& buffer)
345{
348 "Cannot allocate descriptor sets without pipeline");
349 return;
350 }
351
353
355 auto& foundry = Portal::Graphics::get_shader_foundry();
356
357 auto vt_layout = flow.get_view_transform_layout(m_pipeline_id);
358 if (vt_layout) {
359 m_view_transform_descriptor_set_id = foundry.allocate_descriptor_set(vt_layout);
360
361 m_view_transform_ubo = std::make_shared<VKBuffer>(
363 VKBuffer::Usage::UNIFORM,
366
367 foundry.update_descriptor_buffer(
369 0,
370 vk::DescriptorType::eUniformBuffer,
371 m_view_transform_ubo->get_buffer(),
372 0,
373 sizeof(Kinesis::ViewTransform));
374
376 "ViewTransform UBO allocated (pipeline {})", m_pipeline_id);
377 }
378
379 m_descriptor_set_ids = flow.allocate_pipeline_descriptors(m_pipeline_id, 1);
380
381 for (const auto& [binding, tex_binding] : m_texture_bindings) {
382 if (!tex_binding.texture
383 || !tex_binding.texture->is_initialized()
384 || !tex_binding.texture->get_image_view()) {
385 continue;
386 }
387
388 auto config_it = std::ranges::find_if(m_config.bindings,
389 [binding](const auto& pair) {
390 return binding >= pair.second.binding
391 && binding < pair.second.binding + pair.second.count;
392 });
393
394 if (config_it == m_config.bindings.end()) {
396 "No config for binding {}", binding);
397 continue;
398 }
399
400 const uint32_t set_index = config_it->second.set;
401
402 if (set_index == 0) {
405 "Engine descriptor set not allocated for set=0 texture binding {}", binding);
406 continue;
407 }
408 foundry.update_descriptor_image(
410 config_it->second.binding,
411 tex_binding.texture->get_image_view(),
412 tex_binding.sampler,
413 vk::ImageLayout::eShaderReadOnlyOptimal,
414 binding - config_it->second.binding);
415 continue;
416 }
417
418 auto ds_index = resolve_ds_index(set_index);
419 if (!ds_index) {
421 "Descriptor set index {} out of range", binding);
422 continue;
423 }
424
425 foundry.update_descriptor_image(
426 m_descriptor_set_ids[*ds_index],
427 config_it->second.binding,
428 tex_binding.texture->get_image_view(),
429 tex_binding.sampler,
430 vk::ImageLayout::eShaderReadOnlyOptimal,
431 binding - config_it->second.binding);
432 }
433
435 "Allocated {} descriptor sets and updated {} texture bindings",
437
438 update_descriptors(buffer);
440}
441
442void RenderProcessor::set_vertex_range(uint32_t first_vertex, uint32_t vertex_count)
443{
444 m_first_vertex = first_vertex;
445 m_vertex_count = vertex_count;
446
448 "RenderProcessor: Set vertex range [offset={}, count={}]",
449 first_vertex, vertex_count);
450}
451
453 const std::shared_ptr<VKBuffer>& buffer,
454 const Kakshya::VertexLayout& layout)
455{
456 m_buffer_info[buffer] = {
457 .semantic_layout = layout,
458 .use_reflection = false
459 };
461}
462
463bool RenderProcessor::on_before_execute(Portal::Graphics::CommandBufferID /*cmd_id*/, const std::shared_ptr<VKBuffer>& /*buffer*/)
464{
465 if (!m_target_window) {
467 "Target window not set");
468 return false;
469 }
470 return m_target_window->is_graphics_registered();
471}
472
473void RenderProcessor::execute_shader(const std::shared_ptr<VKBuffer>& buffer)
474{
475 if (m_buffer_info.find(buffer) == m_buffer_info.end()) {
476 if (buffer->has_vertex_layout()) {
477 auto vertex_layout = buffer->get_vertex_layout();
478 if (vertex_layout.has_value()) {
479 m_buffer_info[buffer] = {
480 .semantic_layout = vertex_layout.value(),
481 .use_reflection = false
482 };
483 }
484 }
485 }
486
487 if (!m_target_window->is_graphics_registered()) {
488 return;
489 }
490
492 return;
493 }
494
496 if (!local_layout) {
498 "VKBuffer has no vertex layout set. Use buffer->set_vertex_layout()");
499 return;
500 }
501
502 buffer->set_pipeline_window(m_pipeline_id, m_target_window);
503
504 auto& foundry = Portal::Graphics::get_shader_foundry();
506
507 vk::Format color_format = static_cast<vk::Format>(
509
510 vk::Format depth_format = m_depth_enabled
511 ? vk::Format::eD32Sfloat
512 : vk::Format::eUndefined;
513
514 auto cmd_id = foundry.begin_secondary_commands(color_format, depth_format);
515 auto cmd = foundry.get_command_buffer(cmd_id);
516
517 uint32_t width = 0, height = 0;
519
520 if (width > 0 && height > 0) {
521 auto cmd = foundry.get_command_buffer(cmd_id);
522
523 vk::Viewport viewport {
524 0.0F,
525 static_cast<float>(height),
526 static_cast<float>(width),
527 -static_cast<float>(height),
528 0.0F,
529 1.0F
530 };
531 cmd.setViewport(0, 1, &viewport);
532
533 vk::Rect2D scissor { { 0, 0 }, { width, height } };
534 cmd.setScissor(0, 1, &scissor);
535 }
536
537 flow.bind_pipeline(cmd_id, m_pipeline_id);
538
539 auto& engine_bindings = buffer->get_engine_context().ssbo_bindings;
540 for (const auto& binding : engine_bindings) {
541 if (binding.set == 0 && binding.binding == 0) {
543 "Engine SSBO at binding=0 is reserved for ViewTransform UBO");
544 continue;
545 }
548 "Engine SSBO binding {} skipped: engine descriptor set not allocated", binding.binding);
549 continue;
550 }
551 foundry.update_descriptor_buffer(
553 binding.binding,
554 binding.type,
555 binding.buffer_info.buffer,
556 binding.buffer_info.offset,
557 binding.buffer_info.range);
558 }
559
560 auto& descriptor_bindings = buffer->get_pipeline_context().descriptor_buffer_bindings;
561 if (!descriptor_bindings.empty()) {
562 for (const auto& binding : descriptor_bindings) {
563 auto ds_index = resolve_ds_index(binding.set);
564 if (!ds_index) {
566 "Descriptor set index {} out of range or reserved", binding.set);
567 continue;
568 }
569
570 foundry.update_descriptor_buffer(
571 m_descriptor_set_ids[*ds_index],
572 binding.binding,
573 binding.type,
574 binding.buffer_info.buffer,
575 binding.buffer_info.offset,
576 binding.buffer_info.range);
577 }
578 }
579
580 if (!m_descriptor_set_ids.empty()) {
581 flow.bind_descriptor_sets(cmd_id, m_pipeline_id, m_descriptor_set_ids);
582 }
583
584 {
590 }
591
592 if (m_view_transform_ubo && m_view_transform_ubo->get_mapped_ptr()) {
593 std::memcpy(
594 m_view_transform_ubo->get_mapped_ptr(),
595 &vt,
596 sizeof(Kinesis::ViewTransform));
597 }
598 }
599
601 flow.bind_descriptor_sets(
602 cmd_id, m_pipeline_id,
604 0);
605 }
606
607 if (!m_descriptor_set_ids.empty()) {
608 flow.bind_descriptor_sets(
609 cmd_id, m_pipeline_id,
611 1);
612 }
613
614 const auto push_data = resolve_push_constants(buffer);
615 if (!push_data.empty()) {
616 flow.push_constants(
617 cmd_id, m_pipeline_id, push_data.data(), push_data.size());
618 }
619
620 on_before_execute(cmd_id, buffer);
621
622 flow.bind_vertex_buffers(cmd_id, { buffer });
623
624 uint32_t draw_count = 0;
625 if (m_vertex_count > 0) {
626 draw_count = m_vertex_count;
627 } else {
628 auto current_layout = buffer->get_vertex_layout();
629 if (!current_layout.has_value() || current_layout->vertex_count == 0) {
631 "Vertex layout has zero vertices, skipping draw");
632 return;
633 }
634 draw_count = current_layout->vertex_count;
635 }
636
637 if (buffer->has_index_buffer()) {
638 const auto index_count = static_cast<uint32_t>(
639 buffer->get_index_buffer_size() / sizeof(uint32_t));
640 flow.bind_index_buffer(cmd_id, buffer);
641 flow.draw_indexed(cmd_id, index_count, m_instance_count, 0, 0, 0);
642 } else {
643 flow.draw(cmd_id, draw_count, m_instance_count, m_first_vertex, 0);
644 }
645
646 foundry.end_commands(cmd_id);
647
648 buffer->set_pipeline_command(m_pipeline_id, cmd_id);
649 m_target_window->track_frame_command(cmd_id);
650
652 "Recorded secondary command buffer {} for window '{}'",
653 cmd_id, m_target_window->get_create_info().title);
654}
655
656void RenderProcessor::on_attach(const std::shared_ptr<Buffer>& buffer)
657{
658 auto vk_buffer = std::dynamic_pointer_cast<VKBuffer>(buffer);
659 if (!vk_buffer)
660 return;
661
663 "RenderProcessor attached to VKBuffer (size: {} bytes, modality: {})",
664 vk_buffer->get_size_bytes(),
665 static_cast<int>(vk_buffer->get_modality()));
666
667 if (vk_buffer && vk_buffer->has_vertex_layout()) {
668 auto vertex_layout = vk_buffer->get_vertex_layout();
669 if (vertex_layout.has_value()) {
671 "RenderProcessor: Auto-injecting vertex layout "
672 "({} vertices, {} attributes)",
673 vertex_layout->vertex_count,
674 vertex_layout->attributes.size());
675
677 m_buffer_info[vk_buffer] = { .semantic_layout = vertex_layout.value(), .use_reflection = false };
678 }
679 }
680
681 if (m_depth_enabled) {
682 vk_buffer->set_needs_depth_attachment(true);
683 }
684
685 if (!m_display_service) {
688 }
689}
690
692{
693 auto& foundry = Portal::Graphics::get_shader_foundry();
695
697 flow.destroy_pipeline(m_pipeline_id);
699 }
700
702 foundry.destroy_shader(m_geometry_shader_id);
704 }
705
707 foundry.destroy_shader(m_tess_control_shader_id);
709 }
710
712 foundry.destroy_shader(m_tess_eval_shader_id);
714 }
715
717 foundry.destroy_shader(m_fragment_shader_id);
719 }
720
721 m_view_transform_ubo.reset();
724
725 if (m_target_window) {
726 flow.unregister_window(m_target_window);
727 m_target_window.reset();
728 }
729
731
733 "RenderProcessor cleanup complete");
734}
735
736} // namespace MayaFlux::Buffers
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_RT_TRACE(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
#define MF_RT_DEBUG(comp, ctx,...)
vk::CommandBuffer cmd
std::string name
Definition VKDevice.cpp:143
uint32_t width
uint32_t height
void set_cull_mode(Portal::Graphics::CullMode mode)
Set cull mode (e.g., none, front, back)
void bind_texture(uint32_t binding, const std::shared_ptr< Core::VKImage > &texture, vk::Sampler sampler=nullptr)
Bind a texture to a descriptor binding point.
Portal::Graphics::DescriptorSetID m_view_transform_descriptor_set_id
void set_blend_attachment(const Portal::Graphics::BlendAttachmentConfig &config)
Set blend mode for color attachment.
Portal::Graphics::ShaderID m_fragment_shader_id
std::unordered_map< std::shared_ptr< VKBuffer >, VertexInfo > m_buffer_info
void disable_alpha_blending()
Disable blending on the color attachment, restoring opaque writes.
void set_buffer_vertex_layout(const std::shared_ptr< VKBuffer > &buffer, const Kakshya::VertexLayout &layout)
Override the vertex layout used when building the pipeline for buffer.
std::optional< Portal::Graphics::BlendAttachmentConfig > m_blend_attachment
Registry::Service::DisplayService * m_display_service
Portal::Graphics::ShaderID m_geometry_shader_id
void set_tess_eval_shader(const std::string &tess_eval_path)
bool on_before_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr< VKBuffer > &buffer) override
Called before each process callback.
void enable_alpha_blending()
Enable standard alpha blending (src_alpha, one_minus_src_alpha).
std::function< Kinesis::ViewTransform()> m_view_transform_source
void set_tess_control_shader(const std::string &tess_control_path)
Portal::Graphics::RenderPipelineID m_pipeline_id
void enable_depth_test(Portal::Graphics::CompareOp compare_op=Portal::Graphics::CompareOp::LESS)
Enable depth testing for this processor's pipeline.
Portal::Graphics::ShaderID m_tess_control_shader_id
void on_attach(const std::shared_ptr< Buffer > &buffer) override
Called when this processor is attached to a buffer.
void initialize_descriptors(const std::shared_ptr< VKBuffer > &buffer) override
std::optional< Kinesis::ViewTransform > m_view_transform
Portal::Graphics::DepthStencilConfig m_depth_stencil
void initialize_pipeline(const std::shared_ptr< VKBuffer > &buffer) override
std::unordered_map< uint32_t, TextureBinding > m_texture_bindings
void disable_depth_test()
Disable depth testing and depth writes for this processor's pipeline.
void set_view_transform_source(std::function< Kinesis::ViewTransform()> fn, bool enable_depth=true, Portal::Graphics::CullMode cull=Portal::Graphics::CullMode::BACK)
Set dynamic view transform source (evaluated every frame)
void set_geometry_shader(const std::string &geometry_path)
void set_vertex_range(uint32_t first_vertex, uint32_t vertex_count)
Set vertex range for drawing subset of buffer.
Portal::Graphics::PrimitiveTopology m_primitive_topology
RenderProcessor(const ShaderConfig &config)
void set_fragment_shader(const std::string &fragment_path)
Portal::Graphics::PolygonMode m_polygon_mode
void execute_shader(const std::shared_ptr< VKBuffer > &buffer) override
void set_target_window(const std::shared_ptr< Core::Window > &window, const std::shared_ptr< VKBuffer > &buffer)
void set_view_transform(const Kinesis::ViewTransform &vt, bool enable_depth=true, Portal::Graphics::CullMode cull=Portal::Graphics::CullMode::BACK)
Set static view transform (evaluated once)
void set_alpha_blending(bool enabled)
Toggle standard alpha blending.
Portal::Graphics::CullMode m_cull_mode
const Kakshya::VertexLayout * get_or_cache_vertex_layout(std::unordered_map< std::shared_ptr< VKBuffer >, VertexInfo > &buffer_info, const std::shared_ptr< VKBuffer > &buffer)
std::shared_ptr< Core::Window > m_target_window
Portal::Graphics::ShaderID m_tess_eval_shader_id
std::shared_ptr< VKBuffer > m_view_transform_ubo
std::optional< uint32_t > resolve_ds_index(uint32_t set) const
Resolve logical descriptor set index to actual index.
Portal::Graphics::ShaderID m_shader_id
virtual void on_descriptors_created()
Called after descriptor sets are created.
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_pipeline_created(Portal::Graphics::ComputePipelineID pipeline_id)
Called after pipeline is created.
virtual void on_before_descriptors_create()
Called before descriptor sets are created.
bool m_engine_owns_set_zero
Whether the engine reserves set=0 for global resources.
std::vector< Portal::Graphics::DescriptorSetID > m_descriptor_set_ids
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.
Abstract base class for shader-based buffer processing.
void ensure_initialized(const std::shared_ptr< VKBuffer > &buffer)
Definition VKBuffer.cpp:448
void register_window_for_rendering(const std::shared_ptr< Core::Window > &window)
Register a window for dynamic rendering.
ShaderID load_shader(const std::string &content, std::optional< ShaderStage > stage=std::nullopt, const std::string &entry_point="main")
Universal shader loader - auto-detects source type.
Interface * get_service()
Query for a backend service.
static BackendRegistry & instance()
Get the global registry instance.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Buffers
Buffers, Managers, processors and processing chains.
@ UNKNOWN
Unknown or undefined modality.
constexpr RenderPipelineID INVALID_RENDER_PIPELINE
MAYAFLUX_API TextureLoom & get_texture_manager()
Get the global texture manager instance.
constexpr ShaderID INVALID_SHADER
MAYAFLUX_API RenderFlow & get_render_flow()
Get the global render flow instance.
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.
CompareOp
Depth/stencil comparison operation.
constexpr DescriptorSetID INVALID_DESCRIPTOR_SET
std::string shader_path
Path to shader file.
std::unordered_map< std::string, ShaderBinding > bindings
Complete description of vertex data layout in a buffer.
View and projection matrices as a named push constant slot.
static BlendAttachmentConfig alpha_blend()
Create standard alpha blending configuration.
Per-attachment blend configuration.
std::vector< std::vector< DescriptorBindingInfo > > descriptor_sets
std::optional< Kakshya::VertexLayout > semantic_vertex_layout
std::vector< BlendAttachmentConfig > blend_attachments
Complete render pipeline configuration.
std::function< int(const std::shared_ptr< void > &)> get_swapchain_format
Get actual swapchain format for a window.
std::function< void(const std::shared_ptr< void > &, uint32_t &, uint32_t &)> get_swapchain_extent
Get swapchain extent for a window.
Backend display and presentation service interface.