17 const std::shared_ptr<VKBuffer>& buffer)
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);
28 if (info_it == buffer_info.end()) {
32 return &info_it->second.semantic_layout;
73 window->register_rendering_buffer(buffer);
147 const std::shared_ptr<Core::VKImage>& texture,
150 if (!texture || !texture->is_initialized() || !texture->get_image_view()) {
152 "Cannot bind null texture to binding {}", binding);
158 sampler = loom.get_default_sampler();
168 [binding](
const auto& pair) {
169 return binding >= pair.second.binding
170 && binding < pair.second.binding + pair.second.count;
174 const uint32_t cfg_set = cfg_it->second.set;
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;
181 foundry.update_descriptor_image(
183 cfg_it->second.binding,
184 texture->get_image_view(),
186 vk::ImageLayout::eShaderReadOnlyOptimal,
192 foundry.update_descriptor_image(
194 cfg_it->second.binding,
195 texture->get_image_view(),
197 vk::ImageLayout::eShaderReadOnlyOptimal);
204 "Bound texture to binding {}", binding);
208 const std::string& descriptor_name,
209 const std::shared_ptr<Core::VKImage>& texture,
215 "No binding configured for descriptor '{}'", descriptor_name);
219 bind_texture(binding_it->second.binding, texture, sampler);
226 "Vertex shader not loaded");
232 "Fragment shader not loaded");
238 "Target window not set");
266 if (buffer->has_vertex_layout()) {
267 auto vertex_layout = buffer->get_vertex_layout();
268 if (vertex_layout.has_value()) {
270 .semantic_layout = vertex_layout.value(),
271 .use_reflection =
false
280 "initialize_pipeline: layout not yet available, deferring");
289 auto& descriptor_bindings = buffer->get_pipeline_context().descriptor_buffer_bindings;
292 for (
const auto& binding : descriptor_bindings) {
293 unified_bindings[{ binding.set, binding.binding }] = binding;
297 auto key = std::make_pair(binding.set, binding.binding);
298 if (unified_bindings.find(key) == unified_bindings.end()) {
301 .binding = binding.binding,
302 .type = binding.type,
305 .count = binding.count
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);
315 for (
const auto& [set_index, set_bindings] : bindings_by_set) {
319 vk::Format swapchain_format =
static_cast<vk::Format
>(
323 ? vk::Format::eD32Sfloat
324 : vk::Format::eUndefined;
326 m_pipeline_id = flow.create_pipeline(pipeline_config, { swapchain_format }, depth_format);
330 "Failed to create render pipeline");
335 buffer->set_needs_depth_attachment(
true);
348 "Cannot allocate descriptor sets without pipeline");
357 auto vt_layout = flow.get_view_transform_layout(
m_pipeline_id);
363 VKBuffer::Usage::UNIFORM,
367 foundry.update_descriptor_buffer(
370 vk::DescriptorType::eUniformBuffer,
382 if (!tex_binding.texture
383 || !tex_binding.texture->is_initialized()
384 || !tex_binding.texture->get_image_view()) {
389 [binding](
const auto& pair) {
390 return binding >= pair.second.binding
391 && binding < pair.second.binding + pair.second.count;
396 "No config for binding {}", binding);
400 const uint32_t set_index = config_it->second.set;
402 if (set_index == 0) {
405 "Engine descriptor set not allocated for set=0 texture binding {}", binding);
408 foundry.update_descriptor_image(
410 config_it->second.binding,
411 tex_binding.texture->get_image_view(),
413 vk::ImageLayout::eShaderReadOnlyOptimal,
414 binding - config_it->second.binding);
421 "Descriptor set index {} out of range", binding);
425 foundry.update_descriptor_image(
427 config_it->second.binding,
428 tex_binding.texture->get_image_view(),
430 vk::ImageLayout::eShaderReadOnlyOptimal,
431 binding - config_it->second.binding);
435 "Allocated {} descriptor sets and updated {} texture bindings",
448 "RenderProcessor: Set vertex range [offset={}, count={}]",
449 first_vertex, vertex_count);
453 const std::shared_ptr<VKBuffer>& buffer,
457 .semantic_layout = layout,
458 .use_reflection =
false
467 "Target window not set");
476 if (buffer->has_vertex_layout()) {
477 auto vertex_layout = buffer->get_vertex_layout();
478 if (vertex_layout.has_value()) {
480 .semantic_layout = vertex_layout.value(),
481 .use_reflection =
false
498 "VKBuffer has no vertex layout set. Use buffer->set_vertex_layout()");
507 vk::Format color_format =
static_cast<vk::Format
>(
511 ? vk::Format::eD32Sfloat
512 : vk::Format::eUndefined;
514 auto cmd_id = foundry.begin_secondary_commands(color_format, depth_format);
515 auto cmd = foundry.get_command_buffer(cmd_id);
521 auto cmd = foundry.get_command_buffer(cmd_id);
523 vk::Viewport viewport {
525 static_cast<float>(
height),
526 static_cast<float>(
width),
527 -
static_cast<float>(
height),
531 cmd.setViewport(0, 1, &viewport);
533 vk::Rect2D scissor { { 0, 0 }, {
width,
height } };
534 cmd.setScissor(0, 1, &scissor);
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");
548 "Engine SSBO binding {} skipped: engine descriptor set not allocated", binding.binding);
551 foundry.update_descriptor_buffer(
555 binding.buffer_info.buffer,
556 binding.buffer_info.offset,
557 binding.buffer_info.range);
560 auto& descriptor_bindings = buffer->get_pipeline_context().descriptor_buffer_bindings;
561 if (!descriptor_bindings.empty()) {
562 for (
const auto& binding : descriptor_bindings) {
566 "Descriptor set index {} out of range or reserved", binding.set);
570 foundry.update_descriptor_buffer(
574 binding.buffer_info.buffer,
575 binding.buffer_info.offset,
576 binding.buffer_info.range);
601 flow.bind_descriptor_sets(
608 flow.bind_descriptor_sets(
615 if (!push_data.empty()) {
622 flow.bind_vertex_buffers(cmd_id, { buffer });
624 uint32_t draw_count = 0;
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");
634 draw_count = current_layout->vertex_count;
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);
646 foundry.end_commands(cmd_id);
652 "Recorded secondary command buffer {} for window '{}'",
658 auto vk_buffer = std::dynamic_pointer_cast<VKBuffer>(buffer);
663 "RenderProcessor attached to VKBuffer (size: {} bytes, modality: {})",
664 vk_buffer->get_size_bytes(),
665 static_cast<int>(vk_buffer->get_modality()));
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());
677 m_buffer_info[vk_buffer] = { .semantic_layout = vertex_layout.value(), .use_reflection =
false };
682 vk_buffer->set_needs_depth_attachment(
true);
733 "RenderProcessor cleanup complete");
#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,...)
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.
bool m_view_transform_active
std::optional< Portal::Graphics::BlendAttachmentConfig > m_blend_attachment
Registry::Service::DisplayService * m_display_service
uint32_t m_instance_count
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.
bool m_needs_descriptor_rebuild
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.
bool m_needs_pipeline_rebuild
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)
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.
CullMode
Face culling mode.
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.
static BlendAttachmentConfig alpha_blend()
Create standard alpha blending configuration.
Per-attachment blend configuration.
CompareOp depth_compare_op
std::vector< std::vector< DescriptorBindingInfo > > descriptor_sets
ShaderID tess_eval_shader
Optional.
std::optional< Kakshya::VertexLayout > semantic_vertex_layout
ShaderID tess_control_shader
Optional.
bool use_vertex_shader_reflection
std::vector< BlendAttachmentConfig > blend_attachments
DepthStencilConfig depth_stencil
size_t push_constant_size
PrimitiveTopology topology
ShaderID geometry_shader
Optional.
RasterizationConfig rasterization
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.