267{
270 "Vertex shader not loaded");
271 return;
272 }
273
276 "Fragment shader not loaded");
277 return;
278 }
279
282 "Target window not set");
283 return;
284 }
285
287 if (!state) {
289 "initialize_pipeline: layout not yet available, deferring");
291 return;
292 }
293
295
297
298 Portal::Graphics::RenderPipelineConfig pipeline_config;
304
307 pipeline_config.rasterization.cull_mode =
m_cull_mode;
308
311 } else {
312 pipeline_config.blend_attachments.emplace_back();
313 }
314
316
317 pipeline_config.semantic_vertex_layout = state->semantic_layout;
318 pipeline_config.use_vertex_shader_reflection = state->use_reflection;
319
321
322 auto& descriptor_bindings =
buffer->get_pipeline_context().descriptor_buffer_bindings;
323 std::map<std::pair<uint32_t, uint32_t>, Portal::Graphics::DescriptorBindingInfo> unified_bindings;
324
325 for (const auto& binding : descriptor_bindings) {
326 unified_bindings[{ binding.set, binding.binding }] = binding;
327 }
328
330 auto key = std::make_pair(binding.set, binding.binding);
331 if (unified_bindings.find(key) == unified_bindings.end()) {
332 unified_bindings[key] = Portal::Graphics::DescriptorBindingInfo {
333 .set = binding.set,
334 .binding = binding.binding,
335 .type = binding.type,
336 .buffer_info = {},
338 .count = binding.count
339 };
340 }
341 }
342
343 std::vector<Portal::Graphics::DescriptorBindingInfo> unregistered;
346 continue;
347 }
349 if (used.set == 0 || unified_bindings.contains({ used.set, used.binding })) {
350 continue;
351 }
352 unregistered.push_back(used);
353 }
354 }
355
357 const auto slot = *it;
358 const bool pending = std::ranges::any_of(unregistered, [&slot](const auto& used) {
359 return used.set == slot.first && used.binding == slot.second;
360 });
361 if (pending) {
362 ++it;
363 continue;
364 }
366 "Set {} binding {} is now registered, the shader's binding is supplied",
367 slot.first, slot.second);
369 }
370
371 if (!unregistered.empty()) {
372 constexpr uint32_t k_binding_grace_ticks = 30;
375
376 for (const auto& used : unregistered) {
378 if (waiting && first_seen) {
380 "Waiting for set {} binding {} ({}), which the shader uses, to be registered before creating the pipeline",
381 used.set, used.binding, vk::to_string(used.type));
382 }
383 }
384
385 if (waiting) {
388 return;
389 }
390
391 for (const auto& used : unregistered) {
393 "Set {} binding {} ({}), which the shader uses, is not registered. "
394 "Creating the pipeline with an empty slot that is filled once a processor registers it",
395 used.set, used.binding, vk::to_string(used.type));
396 unified_bindings.emplace(std::make_pair(used.set, used.binding),
397 Portal::Graphics::DescriptorBindingInfo {
398 .set = used.set,
399 .binding = used.binding,
400 .type = used.type,
401 .buffer_info = {},
402 .name = used.name });
403 }
404 }
406
407 std::map<uint32_t, std::vector<Portal::Graphics::DescriptorBindingInfo>> bindings_by_set;
408 for (const auto& [key, binding] : unified_bindings) {
409 bindings_by_set[binding.set].push_back(binding);
410 }
411
412 for (const auto& [set_index, set_bindings] : bindings_by_set) {
413 pipeline_config.descriptor_sets.push_back(set_bindings);
414 }
415
416 vk::Format swapchain_format = static_cast<vk::Format>(
418
420 ? vk::Format::eD32Sfloat
421 : vk::Format::eUndefined;
422
424
425 m_pipeline_id = flow.create_pipeline(pipeline_config, { swapchain_format }, depth_format);
426
429 "Failed to create render pipeline");
430 return;
431 }
432
434 buffer->set_needs_depth_attachment(
true);
435 }
436
439
441}
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
std::shared_ptr< NetworkGeometryBuffer > buffer
Portal::Graphics::ShaderID m_fragment_shader_id
std::optional< Portal::Graphics::BlendAttachmentConfig > m_blend_attachment
Registry::Service::DisplayService * m_display_service
Portal::Graphics::ShaderID m_geometry_shader_id
uint32_t m_binding_wait_ticks
Portal::Graphics::RenderPipelineID m_pipeline_id
Portal::Graphics::ShaderID m_tess_control_shader_id
BufferState * get_or_cache_buffer_state(const std::shared_ptr< VKBuffer > &buffer)
Portal::Graphics::DepthStencilConfig m_depth_stencil
Portal::Graphics::PrimitiveTopology pipeline_topology() const
Topology the pipeline is built with, as opposed to the topology m_runs are declared in.
std::set< std::pair< uint32_t, uint32_t > > m_awaited_bindings
void retire_current_pipeline()
Move the current pipeline to the retired list and drop its buffer associations.
Portal::Graphics::PolygonMode m_polygon_mode
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
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 on_pipeline_created(Portal::Graphics::ComputePipelineID pipeline_id)
Called after pipeline is created.
bool m_needs_pipeline_rebuild
std::vector< Portal::Graphics::DescriptorSetID > m_descriptor_set_ids
void register_window_for_rendering(const std::shared_ptr< Core::Window > &window)
Register a window for dynamic rendering.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Portal
High-level user-facing API layer.
@ Buffers
Buffers, Managers, processors and processing chains.
constexpr RenderPipelineID INVALID_RENDER_PIPELINE
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.
static constexpr DomainSpec Graphics
Domain constant for Graphics domain.
std::function< int(const std::shared_ptr< void > &)> get_swapchain_format
Get actual swapchain format for a window.