58 const std::shared_ptr<Core::VKImage>& texture,
63 "Cannot bind null texture to binding {}", binding);
69 sampler = loom.get_default_sampler();
77 foundry.update_descriptor_image(
80 texture->get_image_view(),
82 vk::ImageLayout::eShaderReadOnlyOptimal);
86 "Bound texture to binding {}", binding);
90 const std::string& descriptor_name,
91 const std::shared_ptr<Core::VKImage>& texture,
97 "No binding configured for descriptor '{}'", descriptor_name);
101 bind_texture(binding_it->second.binding, texture, sampler);
108 "Vertex shader not loaded");
114 "Fragment shader not loaded");
120 "Target window not set");
142 if (buffer->has_vertex_layout()) {
143 auto vertex_layout = buffer->get_vertex_layout();
144 if (vertex_layout.has_value()) {
146 .semantic_layout = vertex_layout.value(),
147 .use_reflection =
false
153 const auto& vertex_info =
m_buffer_info.find(buffer)->second;
158 const auto& staging = buffer->get_pipeline_context().push_constant_staging;
159 if (!staging.empty()) {
165 auto& descriptor_bindings = buffer->get_pipeline_context().descriptor_buffer_bindings;
168 for (
const auto& binding : descriptor_bindings) {
169 unified_bindings[{ binding.set, binding.binding }] = binding;
173 auto key = std::make_pair(binding.set, binding.binding);
174 if (unified_bindings.find(key) == unified_bindings.end()) {
177 .binding = binding.binding,
178 .type = binding.type,
185 std::map<uint32_t, std::vector<Portal::Graphics::DescriptorBindingInfo>> bindings_by_set;
186 for (
const auto& [key, binding] : unified_bindings) {
187 bindings_by_set[binding.set].push_back(binding);
190 for (
const auto& [set_index, set_bindings] : bindings_by_set) {
194 vk::Format swapchain_format =
static_cast<vk::Format
>(
197 m_pipeline_id = flow.create_pipeline(pipeline_config, { swapchain_format });
201 "Failed to create render pipeline");
215 "Cannot allocate descriptor sets without pipeline");
227 "Failed to allocate descriptor sets for pipeline");
233 [binding](
const auto& pair) {
234 return pair.second.binding == binding;
239 "No config for binding {}", binding);
242 uint32_t set_index = config_it->second.set;
246 "Descriptor set index {} out of range", binding);
251 foundry.update_descriptor_image(
253 config_it->second.binding,
254 tex_binding.texture->get_image_view(),
256 vk::ImageLayout::eShaderReadOnlyOptimal);
260 "Allocated {} descriptor sets and updated {} texture bindings",
271 "Target window not set");
280 if (buffer->has_vertex_layout()) {
281 auto vertex_layout = buffer->get_vertex_layout();
282 if (vertex_layout.has_value()) {
284 .semantic_layout = vertex_layout.value(),
285 .use_reflection =
false
299 auto vertex_layout = buffer->get_vertex_layout();
300 if (!vertex_layout.has_value()) {
302 "VKBuffer has no vertex layout set. Use buffer->set_vertex_layout()");
306 if (vertex_layout->vertex_count == 0) {
308 "Vertex layout has zero vertices, skipping draw");
312 if (vertex_layout->attributes.empty()) {
314 "Vertex layout has no attributes");
323 vk::Format color_format =
static_cast<vk::Format
>(
326 auto cmd_id = foundry.begin_secondary_commands(color_format);
327 auto cmd = foundry.get_command_buffer(cmd_id);
329 uint32_t width = 0, height = 0;
332 if (width > 0 && height > 0) {
333 auto cmd = foundry.get_command_buffer(cmd_id);
335 vk::Viewport viewport { 0.0F, 0.0F,
static_cast<float>(width),
static_cast<float>(height), 0.0F, 1.0F };
336 cmd.setViewport(0, 1, &viewport);
338 vk::Rect2D scissor { { 0, 0 }, { width, height } };
339 cmd.setScissor(0, 1, &scissor);
344 auto& descriptor_bindings = buffer->get_pipeline_context().descriptor_buffer_bindings;
345 if (!descriptor_bindings.empty()) {
346 for (
const auto& binding : descriptor_bindings) {
349 "Descriptor set index {} out of range", binding.set);
353 foundry.update_descriptor_buffer(
357 binding.buffer_info.buffer,
358 binding.buffer_info.offset,
359 binding.buffer_info.range);
367 const auto& staging = buffer->get_pipeline_context();
368 if (!staging.push_constant_staging.empty()) {
372 staging.push_constant_staging.data(),
373 staging.push_constant_staging.size());
384 flow.bind_vertex_buffers(cmd_id, { buffer });
386 flow.draw(cmd_id, vertex_layout->vertex_count);
388 foundry.end_commands(cmd_id);
394 "Recorded secondary command buffer {} for window '{}'",
402 auto vk_buffer = std::dynamic_pointer_cast<VKBuffer>(buffer);
403 if (vk_buffer && vk_buffer->has_vertex_layout()) {
404 auto vertex_layout = vk_buffer->get_vertex_layout();
405 if (vertex_layout.has_value()) {
407 "RenderProcessor: Auto-injecting vertex layout "
408 "({} vertices, {} attributes)",
409 vertex_layout->vertex_count,
410 vertex_layout->attributes.size());
413 m_buffer_info[vk_buffer] = { .semantic_layout = vertex_layout.value(), .use_reflection =
false };
461 "RenderProcessor cleanup complete");
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_RT_WARN(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_RT_TRACE(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
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::ShaderID m_fragment_shader_id
std::unordered_map< std::shared_ptr< VKBuffer >, VertexInfo > m_buffer_info
Registry::Service::DisplayService * m_display_service
Portal::Graphics::ShaderID m_geometry_shader_id
void set_tess_eval_shader(const std::string &tess_eval_path)
void set_target_window(std::shared_ptr< Core::Window > window)
bool on_before_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr< VKBuffer > &buffer) override
Called before each process callback.
void set_tess_control_shader(const std::string &tess_control_path)
Portal::Graphics::RenderPipelineID m_pipeline_id
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
void initialize_pipeline(const std::shared_ptr< VKBuffer > &buffer) override
std::unordered_map< uint32_t, TextureBinding > m_texture_bindings
void set_geometry_shader(const std::string &geometry_path)
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
Portal::Graphics::CullMode m_cull_mode
std::shared_ptr< Core::Window > m_target_window
Portal::Graphics::ShaderID m_tess_eval_shader_id
Portal::Graphics::ShaderID m_shader_id
std::vector< uint8_t > m_push_constant_data
virtual void on_descriptors_created()
Called after descriptor sets are created.
bool m_needs_descriptor_rebuild
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_needs_pipeline_rebuild
void on_attach(const std::shared_ptr< Buffer > &buffer) override
Called when this processor is attached to a buffer.
std::vector< Portal::Graphics::DescriptorSetID > m_descriptor_set_ids
Abstract base class for shader-based buffer processing.
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.
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.
std::string shader_path
Path to shader file.
std::unordered_map< std::string, ShaderBinding > bindings
size_t push_constant_size
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
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.