MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RenderProcessor.cpp
Go to the documentation of this file.
1#include "RenderProcessor.hpp"
2
12
13namespace MayaFlux::Buffers {
14
21
22void RenderProcessor::set_fragment_shader(const std::string& fragment_path)
23{
25 m_fragment_shader_id = foundry.load_shader(fragment_path, Portal::Graphics::ShaderStage::FRAGMENT);
27}
28
29void RenderProcessor::set_geometry_shader(const std::string& geometry_path)
30{
32 m_geometry_shader_id = foundry.load_shader(geometry_path, Portal::Graphics::ShaderStage::GEOMETRY);
34}
35
36void RenderProcessor::set_tess_control_shader(const std::string& tess_control_path)
37{
39 m_tess_control_shader_id = foundry.load_shader(tess_control_path, Portal::Graphics::ShaderStage::TESS_CONTROL);
41}
42
43void RenderProcessor::set_tess_eval_shader(const std::string& tess_eval_path)
44{
46 m_tess_eval_shader_id = foundry.load_shader(tess_eval_path, Portal::Graphics::ShaderStage::TESS_EVALUATION);
48}
49
55
56void RenderProcessor::set_target_window(std::shared_ptr<Core::Window> window)
57{
58 m_target_window = std::move(window);
59}
60
62 uint32_t binding,
63 const std::shared_ptr<Core::VKImage>& texture,
64 vk::Sampler sampler)
65{
66 if (!texture) {
68 "Cannot bind null texture to binding {}", binding);
69 return;
70 }
71
72 if (!sampler) {
74 sampler = loom.get_default_sampler();
75 }
76
77 m_texture_bindings[binding] = { .texture = texture, .sampler = sampler };
78
80
82 foundry.update_descriptor_image(
84 binding,
85 texture->get_image_view(),
86 sampler,
87 vk::ImageLayout::eShaderReadOnlyOptimal);
88 }
89
91 "Bound texture to binding {}", binding);
92}
93
95 const std::string& descriptor_name,
96 const std::shared_ptr<Core::VKImage>& texture,
97 vk::Sampler sampler)
98{
99 auto binding_it = m_config.bindings.find(descriptor_name);
100 if (binding_it == m_config.bindings.end()) {
102 "No binding configured for descriptor '{}'", descriptor_name);
103 return;
104 }
105
106 bind_texture(binding_it->second.binding, texture, sampler);
107}
108
109void RenderProcessor::initialize_pipeline(const std::shared_ptr<Buffer>& buffer)
110{
113 "Vertex shader not loaded");
114 return;
115 }
116
119 "Fragment shader not loaded");
120 return;
121 }
122
124
125 if (!m_target_window) {
127 "Target window not set");
128 return;
129 }
130
131 // vk::Format swapchain_format = vk::Format { m_display_service->get_swapchain_format(m_target_window) };
132 // m_render_pass_id = flow.create_simple_render_pass(swapchain_format);
133
135 vk::Format swapchain_format = vk::Format { m_display_service->get_swapchain_format(m_target_window) };
136 m_render_pass_id = flow.create_simple_render_pass(swapchain_format);
137
140 "Render pass not set");
141 return;
142 }
143 }
144
146
147 if (!buffer) {
149 "Cannot initialize pipeline: buffer is null");
150 return;
151 }
152 auto vk_buffer = std::dynamic_pointer_cast<VKBuffer>(buffer);
153
155 pipeline_config.vertex_shader = m_shader_id;
156 pipeline_config.fragment_shader = m_fragment_shader_id;
157 pipeline_config.geometry_shader = m_geometry_shader_id;
159 pipeline_config.tess_eval_shader = m_tess_eval_shader_id;
160 pipeline_config.render_pass = m_render_pass_id;
161
162 pipeline_config.topology = m_primitive_topology;
163 pipeline_config.rasterization.polygon_mode = m_polygon_mode;
164 pipeline_config.rasterization.cull_mode = m_cull_mode;
165
166 pipeline_config.blend_attachments.emplace_back();
167
168 auto it = m_buffer_info.find(vk_buffer);
169 if (it != m_buffer_info.end()) {
170 const auto& vertex_info = it->second;
171 pipeline_config.semantic_vertex_layout = vertex_info.semantic_layout;
172 pipeline_config.use_vertex_shader_reflection = vertex_info.use_reflection;
173 }
174
175 if (!m_config.bindings.empty()) {
176 std::map<uint32_t, std::vector<std::pair<std::string, ShaderBinding>>> bindings_by_set;
177 for (const auto& [name, binding] : m_config.bindings) {
178 bindings_by_set[binding.set].emplace_back(name, binding);
179 }
180
181 for (const auto& [set_index, set_bindings] : bindings_by_set) {
182 std::vector<Portal::Graphics::DescriptorBindingConfig> set_config;
183 for (const auto& [name, binding] : set_bindings) {
184 set_config.emplace_back(binding.set, binding.binding, binding.type);
185 }
186 pipeline_config.descriptor_sets.push_back(set_config);
187 }
188 }
189
190 m_render_pipeline_id = flow.create_pipeline(pipeline_config);
191
194 "Failed to create render pipeline");
195 return;
196 }
197
198 if (!pipeline_config.descriptor_sets.empty() && m_descriptor_set_ids.empty()) {
199 m_descriptor_set_ids = flow.allocate_pipeline_descriptors(m_render_pipeline_id);
200
201 if (m_descriptor_set_ids.empty()) {
203 "Failed to allocate descriptor sets for pipeline");
204 return;
205 }
206
207 for (const auto& [binding, tex_binding] : m_texture_bindings) {
208 auto& foundry = Portal::Graphics::get_shader_foundry();
209 foundry.update_descriptor_image(
211 binding,
212 tex_binding.texture->get_image_view(),
213 tex_binding.sampler,
214 vk::ImageLayout::eShaderReadOnlyOptimal);
215 }
216
218 "Allocated {} descriptor sets and updated {} texture bindings",
220 }
221
223}
224
225void RenderProcessor::processing_function(std::shared_ptr<Buffer> buffer)
226{
227 auto vk_buffer = std::dynamic_pointer_cast<VKBuffer>(buffer);
228 if (!vk_buffer || !m_target_window) {
229 return;
230 }
231
232 if (m_buffer_info.find(vk_buffer) == m_buffer_info.end()) {
233 if (vk_buffer->has_vertex_layout()) {
234 auto vertex_layout = vk_buffer->get_vertex_layout();
235 if (vertex_layout.has_value()) {
236 m_buffer_info[vk_buffer] = {
237 .semantic_layout = vertex_layout.value(),
238 .use_reflection = false
239 };
240 }
241 }
242 }
243
244 if (!m_target_window->is_graphics_registered()) {
245 return;
246 }
247
249 initialize_pipeline(buffer);
250 }
251
253 return;
254 }
255
256 auto vertex_layout = vk_buffer->get_vertex_layout();
257 if (!vertex_layout.has_value()) {
259 "VKBuffer has no vertex layout set. Use buffer->set_vertex_layout()");
260 return;
261 }
262
263 if (vertex_layout->vertex_count == 0) {
265 "Vertex layout has zero vertices, skipping draw");
266 return;
267 }
268
269 if (vertex_layout->attributes.empty()) {
271 "Vertex layout has no attributes");
272 return;
273 }
274
275 vk_buffer->set_pipeline_window(m_render_pipeline_id, m_target_window);
276
277 auto& foundry = Portal::Graphics::get_shader_foundry();
279
280 auto cmd_id = foundry.begin_commands(Portal::Graphics::ShaderFoundry::CommandBufferType::GRAPHICS);
281
282 flow.begin_render_pass(cmd_id, m_target_window);
283
284 uint32_t width = 0, height = 0;
286
287 if (width > 0 && height > 0) {
288 auto cmd = foundry.get_command_buffer(cmd_id);
289
290 vk::Viewport viewport { 0.0F, 0.0F, static_cast<float>(width), static_cast<float>(height), 0.0F, 1.0F };
291 cmd.setViewport(0, 1, &viewport);
292
293 vk::Rect2D scissor { { 0, 0 }, { width, height } };
294 cmd.setScissor(0, 1, &scissor);
295 }
296
297 flow.bind_pipeline(cmd_id, m_render_pipeline_id);
298
299 if (!m_descriptor_set_ids.empty()) {
300 flow.bind_descriptor_sets(cmd_id, m_render_pipeline_id, m_descriptor_set_ids);
301 }
302
303 flow.bind_vertex_buffers(cmd_id, { vk_buffer });
304
305 flow.draw(cmd_id, vertex_layout->vertex_count);
306
307 flow.end_render_pass(cmd_id);
308
309 vk_buffer->set_pipeline_command(m_render_pipeline_id, cmd_id);
310}
311
312void RenderProcessor::on_attach(std::shared_ptr<Buffer> buffer)
313{
315
316 auto vk_buffer = std::dynamic_pointer_cast<VKBuffer>(buffer);
317 if (vk_buffer && vk_buffer->has_vertex_layout()) {
318 auto vertex_layout = vk_buffer->get_vertex_layout();
319 if (vertex_layout.has_value()) {
321 "RenderProcessor: Auto-injecting vertex layout "
322 "({} vertices, {} attributes)",
323 vertex_layout->vertex_count,
324 vertex_layout->attributes.size());
325
327 m_buffer_info[vk_buffer] = { .semantic_layout = vertex_layout.value(), .use_reflection = false };
328 }
329 }
330
331 if (!m_display_service) {
334 }
335}
336
338{
339 auto& foundry = Portal::Graphics::get_shader_foundry();
341
343 flow.destroy_pipeline(m_render_pipeline_id);
345 }
346
348 flow.destroy_render_pass(m_render_pass_id);
350 }
351
353 foundry.destroy_shader(m_geometry_shader_id);
355 }
356
358 foundry.destroy_shader(m_tess_control_shader_id);
360 }
361
363 foundry.destroy_shader(m_tess_eval_shader_id);
365 }
366
368 foundry.destroy_shader(m_fragment_shader_id);
370 }
371
372 if (m_target_window) {
373 flow.unregister_window(m_target_window);
374 m_target_window.reset();
375 }
376
378
380 "RenderProcessor cleanup complete");
381}
382
383} // 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_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.
void initialize_pipeline(const std::shared_ptr< Buffer > &buffer) override
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
Portal::Graphics::RenderPassID m_render_pass_id
void set_tess_eval_shader(const std::string &tess_eval_path)
void set_target_window(std::shared_ptr< Core::Window > window)
void set_render_pass(Portal::Graphics::RenderPassID render_pass_id)
void processing_function(std::shared_ptr< Buffer > buffer) override
The core processing function that must be implemented by derived classes.
void set_tess_control_shader(const std::string &tess_control_path)
Portal::Graphics::ShaderID m_tess_control_shader_id
void on_attach(std::shared_ptr< Buffer > buffer) override
Called when this processor is attached to a buffer.
std::unordered_map< uint32_t, TextureBinding > m_texture_bindings
void set_geometry_shader(const std::string &geometry_path)
Portal::Graphics::PrimitiveTopology m_primitive_topology
void set_fragment_shader(const std::string &fragment_path)
Portal::Graphics::PolygonMode m_polygon_mode
Portal::Graphics::CullMode m_cull_mode
std::shared_ptr< Core::Window > m_target_window
RenderProcessor(const ShaderProcessorConfig &config)
Portal::Graphics::ShaderID m_tess_eval_shader_id
Portal::Graphics::RenderPipelineID m_render_pipeline_id
Portal::Graphics::ShaderID m_shader_id
void set_config(const ShaderProcessorConfig &config)
Update entire configuration.
void on_attach(std::shared_ptr< Buffer > buffer) override
Called when this processor is attached to a buffer.
std::vector< Portal::Graphics::DescriptorSetID > m_descriptor_set_ids
Generic compute shader processor for VKBuffers.
void register_window_for_rendering(const std::shared_ptr< Core::Window > &window, RenderPassID render_pass_id)
Associate a window with a render pass for 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.
@ GRAPHICS_BACKEND
Standard graphics processing backend configuration.
@ 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 RenderPassID INVALID_RENDER_PASS
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::unordered_map< std::string, ShaderBinding > bindings
std::string shader_path
Path to shader file.
Complete configuration for shader processor.
std::optional< Kakshya::VertexLayout > semantic_vertex_layout
std::vector< std::vector< DescriptorBindingConfig > > descriptor_sets
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.