Unravel Engine C++ Reference
Loading...
Searching...
No Matches
pipeline.cpp
Go to the documentation of this file.
1#include "pipeline.h"
2#include "bx/bx.h"
4#include "glm/ext.hpp"
13
25#include <RmlUi/Core/ElementDocument.h>
26
27#include <graphics/graphics.h>
29
31#define POOLSTL_STD_SUPPLEMENT 1
32#include <poolstl/poolstl.hpp>
33
35
36#include <algorithm>
37#include <atomic>
38
39namespace unravel
40{
41namespace rendering
42{
43namespace
44{
45auto particle_blend_bgfx_state(ps_soa::blend_mode mode) -> uint64_t
46{
47 switch(mode)
48 {
50 return BGFX_STATE_BLEND_ADD;
52 return BGFX_STATE_BLEND_MULTIPLY;
53 default:
54 return BGFX_STATE_BLEND_NORMAL;
55 }
56}
57} // namespace
58auto pipeline::init(rtti::context& ctx) -> bool
59{
60 cache_entity_ = cache_registry_.create();
61
62 prefilter_pass_.init(ctx);
63 blit_pass_.init(ctx);
64 atmospheric_pass_perez_.init(ctx);
65 atmospheric_pass_skybox_.init(ctx);
66 auto_exposure_pass_.init(ctx);
67 bloom_pass_.init(ctx);
68 fxaa_pass_.init(ctx);
69 taa_pass_.init(ctx);
70 tonemapping_pass_.init(ctx);
71 assao_pass_.init(ctx);
72 ssr_pass_.init(ctx);
73 hiz_pass_.init(ctx);
74 ssil_pass_.init(ctx);
75
76 auto& am = ctx.get_cached<asset_manager>();
77
78 auto load_program = [&](const std::string& vs, const std::string& fs)
79 {
80 auto vs_shader = am.get_asset<gfx::shader>("engine:/data/shaders/" + vs + ".sc");
81 auto fs_shadfer = am.get_asset<gfx::shader>("engine:/data/shaders/" + fs + ".sc");
82
83 return std::make_unique<gpu_program>(vs_shader, fs_shadfer);
84 };
85
86 particle_program_ = load_program("particles/vs_particle", "particles/fs_particle");
87 particle_program_instanced_ = load_program("particles/instanced/vs_particle_instanced", "particles/instanced/fs_particle_instanced");
88 particle_program_instanced_mask_ = load_program("particles/instanced/vs_particle_instanced", "particles/instanced/fs_particle_instanced_mask");
89 world_quad_program_ = load_program("rmlui_world/vs_world_quad", "rmlui_world/fs_world_quad");
90
91 return true;
92}
93
94namespace
95{
96// LOD levels added on top of the main-view selection when rendering shadow maps.
97std::atomic<float> shadow_lod_bias{1.0f};
98} // namespace
99
101{
102 return shadow_lod_bias.load(std::memory_order_relaxed);
103}
104
106{
107 shadow_lod_bias.store(bias, std::memory_order_relaxed);
108}
109
111 const camera* cam,
112 visibility_flags query,
113 const layer_mask& render_mask,
114 delta_t dt,
115 const std::function<void(entt::handle entity, const lod_data& lod_data)>& lod_data_callback,
116 const camera* lod_reference_cam)
117{
118
119 APP_SCOPE_PERF(cam ? "Rendering/Cull Models" : "Rendering/Gather Models");
120 static const std::string thread_name = "Rendering/Gather Models Thread";
121 tpp::this_thread::register_this_thread(thread_name, true);
123
125
126 if(cam)
127 {
128 // first force get the frustum to ensure it is up to date. it is internally cached and we don't want
129 // to updated it in the loop since it is not thread safe. Force it here.
130 auto& frustum = cam->get_frustum();
131 BX_UNUSED(frustum);
132 }
133
134 //get_lod_data_for_camera is not thread safe but we are only operating on a single model once
135 //so we can use parallel execution here
136 std::for_each(poolstl::par,//std::execution::par,
137 view.begin(),
138 view.end(),
139 [&](auto entity)
140 {
141 tpp::this_thread::register_this_thread(thread_name, true);
142
143 auto&& [transform_comp, model_comp, layer_comp, active_comp] = view.get(entity);
144
145 // Get layer component if it exists, otherwise use default layer
146 auto entity_layer = layer_comp.layers;
147
148 // Layer filtering - check if entity's layer matches camera's render mask
149 if((entity_layer.mask & render_mask.mask) == 0)
150 {
151 return; // Entity's layer is not visible to this camera
152 }
153
154 // Early exit checks
155 if(!model_comp.is_enabled())
156 {
157 return;
158 }
159 if((query & visibility_query::is_static) && !model_comp.is_static())
160 {
161 return;
162 }
163 if((query & visibility_query::is_shadow_caster) && !model_comp.casts_shadow())
164 {
165 return;
166 }
167
168 auto& current_lod_data = model_comp.get_lod_data_for_camera(cam, gfx::get_render_frame());
169 bool is_visible = true;
170
171 if(cam)
172 {
173 const auto& model = model_comp.get_model();
174
175
176 if(!model.is_valid())
177 {
178 return;
179 }
180
181 // LOD and culling both measure the pose-aware world AABB (static bounds
182 // unioned with the cached per-submesh/skinned pose bounds) - one source of
183 // truth for "where the rendered geometry actually is". Refreshed by
184 // model_system::on_frame_before_render, which runs before any render path.
185 const auto& world_bounds = model_comp.get_world_bounds();
186
187 if(!model.calculate_lod_data(current_lod_data, world_bounds, *cam, dt.count()))
188 {
189 return;
190 }
191
192 // Bind-pose local bounds are never used for culling or LOD - they don't
193 // track node/bone animation.
194 is_visible = cam->get_frustum().test_aabb(world_bounds);
195 }
196 else if(lod_reference_cam)
197 {
198 // No frustum culling (e.g. shadow gathering renders casters outside the view),
199 // but select a distance-appropriate LOD from the reference camera plus the
200 // shadow bias instead of always rendering LOD 0.
201 const auto& model = model_comp.get_model();
202
203 if(model.is_valid())
204 {
205 const auto lod = model.compute_lod_index(model_comp.get_world_bounds(),
206 *lod_reference_cam,
207 get_shadow_lod_bias());
208 current_lod_data.current_lod_index = lod;
209 current_lod_data.target_lod_index = lod;
210 current_lod_data.current_time = 0.0f;
211 current_lod_data.transition_time = 0.0f;
212 }
213 }
214
215 if(is_visible)
216 {
217 // lod_data_callback(scn.create_handle(entity), current_lod_data);
218 queue.enqueue(std::make_pair(entity, current_lod_data));
219 }
220
221 });
222
223 std::pair<entt::entity, lod_data> entity_lod_data;
224 while(queue.try_dequeue_non_interleaved(entity_lod_data))
225 {
226 lod_data_callback(scn.create_handle(entity_lod_data.first), entity_lod_data.second);
227 }
228}
229
230
231auto pipeline::create_run_params(entt::handle camera_ent) const -> rendering::pipeline::run_params
232{
234
235 if(auto assao_comp = camera_ent.try_get<assao_component>(); assao_comp && assao_comp->enabled)
236 {
237 params.fill_assao_params = [camera_ent](assao_pass::run_params& params)
238 {
239 if(auto assao_comp = camera_ent.try_get<assao_component>())
240 {
241 params.params = assao_comp->settings;
242 }
243 };
244 }
245
246 if(auto ae_comp = camera_ent.try_get<auto_exposure_component>(); ae_comp && ae_comp->enabled)
247 {
248 params.fill_auto_exposure_params = [camera_ent](auto_exposure_pass::run_params& params)
249 {
250 if(auto ae_comp = camera_ent.try_get<auto_exposure_component>())
251 {
252 params.config = ae_comp->settings;
253 }
254 };
255 }
256 if(auto bloom_comp = camera_ent.try_get<bloom_component>(); bloom_comp && bloom_comp->enabled)
257 {
258 params.fill_bloom_params = [camera_ent](bloom_pass::run_params& params)
259 {
260 if(auto bloom_comp = camera_ent.try_get<bloom_component>())
261 {
262 params.config = bloom_comp->settings;
263 }
264 };
265 }
266 if(auto tonemapping_comp = camera_ent.try_get<tonemapping_component>(); tonemapping_comp && tonemapping_comp->enabled)
267 {
268 params.fill_hdr_params = [camera_ent](tonemapping_pass::run_params& params)
269 {
270 if(auto tonemapping_comp = camera_ent.try_get<tonemapping_component>())
271 {
272 params.config = tonemapping_comp->settings;
273 }
274 };
275 }
276 else
277 {
278 // Always set up tonemapping params but with disabled method if component is disabled
279 params.fill_hdr_params = [camera_ent](tonemapping_pass::run_params& params)
280 {
281 params.config.method = tonemapping_method::none;
282 };
283 }
284
285 if(auto taa_comp = camera_ent.try_get<taa_component>(); taa_comp && taa_comp->enabled)
286 {
287 params.fill_taa_params = [camera_ent](taa_pass::run_params& p) -> void
288 {
289 if(auto c = camera_ent.try_get<taa_component>())
290 {
291 p.config = c->settings;
292 }
293 };
294 params.apply_taa_params = [camera_ent](camera& cam, const usize32_t& viewport_size) -> void
295 {
296 if(auto c = camera_ent.try_get<taa_component>())
297 {
298 const std::uint32_t sample_count = (std::min)(std::uint32_t(16),
299 (std::max)(std::uint32_t(2), c->settings.temporal_sample_count));
300 cam.set_aa_data(viewport_size,
301 static_cast<std::uint32_t>(gfx::get_render_frame()),
302 sample_count,
303 c->settings.jitter_mode,
304 c->settings.jitter_amplitude,
305 c->settings.jitter_temporal_phase_scale);
306 }
307 };
308 }
309
310 if(auto fxaa_comp = camera_ent.try_get<fxaa_component>(); fxaa_comp && fxaa_comp->enabled && !params.fill_taa_params)
311 {
312 params.fill_fxaa_params = [camera_ent](fxaa_pass::run_params& params)
313 {
314 if(auto fxaa_comp = camera_ent.try_get<fxaa_component>())
315 {
316 // Fill FXAA parameters
317 }
318 };
319 }
320
321 if(auto ssr_comp = camera_ent.try_get<ssr_component>(); ssr_comp && ssr_comp->enabled)
322 {
323 params.fill_ssr_params = [camera_ent](ssr_pass::run_params& params)
324 {
325 if(auto ssr_comp = camera_ent.try_get<ssr_component>())
326 {
327 params.settings = ssr_comp->settings;
328 }
329 };
330 }
331
332 if(auto ssil_comp = camera_ent.try_get<ssil_component>(); ssil_comp && ssil_comp->enabled)
333 {
334 params.fill_ssil_params = [camera_ent](ssil_pass::run_params& params)
335 {
336 if(auto ssil_comp = camera_ent.try_get<ssil_component>())
337 {
338 params.settings = ssil_comp->settings;
339 }
340 };
341 }
342
343 return params;
344}
345
346auto pipeline::create_run_params(entt::handle camera_ent, scene* scn, const camera* cam) const -> rendering::pipeline::run_params
347{
348 auto params = create_run_params(camera_ent);
349 if(!scn || !cam)
350 {
351 return params;
352 }
353 auto resolved = resolve_post_process_volumes(*scn, cam->get_position(), camera_ent);
354 const bool has_any_volume = resolved.has_auto_exposure || resolved.has_bloom || resolved.has_tonemapping ||
355 resolved.has_fxaa || resolved.has_taa || resolved.has_ssr || resolved.has_assao || resolved.has_ssil;
356 if(!has_any_volume)
357 {
358 return params;
359 }
360 if(resolved.has_auto_exposure)
361 {
362 auto_exposure_pass::settings s = resolved.auto_exposure;
363 params.fill_auto_exposure_params = [s](auto_exposure_pass::run_params& p) { p.config = s; };
364 }
365 if(resolved.has_bloom)
366 {
367 bloom_pass::settings s = resolved.bloom;
368 params.fill_bloom_params = [s](bloom_pass::run_params& p) { p.config = s; };
369 }
370 if(resolved.has_tonemapping)
371 {
372 tonemapping_pass::settings s = resolved.tonemapping;
373 params.fill_hdr_params = [s](tonemapping_pass::run_params& p) { p.config = s; };
374 }
375 if(resolved.has_fxaa)
376 {
377 params.fill_fxaa_params = [](fxaa_pass::run_params&) {};
378 }
379 if(resolved.has_taa)
380 {
381 taa_pass::settings s = resolved.taa;
382 params.fill_taa_params = [s](taa_pass::run_params& p) -> void { p.config = s; };
383 params.apply_taa_params = [s](camera& cam, const usize32_t& viewport_size) -> void
384 {
385 const std::uint32_t sample_count =
386 (std::min)(std::uint32_t(16), (std::max)(std::uint32_t(2), s.temporal_sample_count));
387 cam.set_aa_data(viewport_size,
388 static_cast<std::uint32_t>(gfx::get_render_frame()),
389 sample_count,
390 s.jitter_mode,
391 s.jitter_amplitude,
392 s.jitter_temporal_phase_scale);
393 };
394 }
395 if(resolved.has_ssr)
396 {
397 ssr_pass::ssr_settings s = resolved.ssr;
398 params.fill_ssr_params = [s](ssr_pass::run_params& p) { p.settings = s; };
399 }
400 if(resolved.has_assao)
401 {
402 assao_pass::settings s = resolved.assao;
403 params.fill_assao_params = [s](assao_pass::run_params& p) { p.params = s; };
404 }
405 if(resolved.has_ssil)
406 {
407 ssil_pass::ssil_settings s = resolved.ssil;
408 params.fill_ssil_params = [s](ssil_pass::run_params& p) { p.settings = s; };
409 }
410 if(params.fill_taa_params)
411 {
412 params.fill_fxaa_params = {};
413 }
414 return params;
415}
416
417void pipeline::run_ui_pass(scene& scn, const camera& camera, gfx::render_view& rview, const gfx::frame_buffer::ptr& output)
418{
419 APP_SCOPE_PERF("Rendering/3D Text Pass");
420
421 const auto& view = camera.get_view();
422 const auto& proj = camera.get_projection();
423 auto& fbo = rview.fbo_get("OBUFFER_DEPTH");
424
425 gfx::render_pass pass("World UI/Elements Pass");
426 pass.bind(fbo.get());
427 pass.set_view_proj(view, proj);
428
429
430 struct world_space_ui_entry
431 {
432 entt::handle handle;
433 ui_document_component* comp = nullptr;
434 transform_component* transform_comp = nullptr;
435 float distance = 0.0f;
436 };
437 struct world_space_ui_cache
438 {
439 std::vector<world_space_ui_entry> entries;
440 };
441 auto& ui_cache = cache_registry_.get_or_emplace<world_space_ui_cache>(cache_entity_);
442 ui_cache.entries.clear();
443
444 // World-space UI documents: draw quad with framebuffer texture
445 if(world_quad_program_ && world_quad_program_->begin())
446 {
447 constexpr uint64_t world_ui_state = BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_WRITE_Z |
448 BGFX_STATE_DEPTH_TEST_LESS | BGFX_STATE_BLEND_NORMAL;
449
451 [&](auto e, auto&& transform_comp, auto&& ui_comp, auto&&)
452 {
453 if(ui_comp.render_mode != ui_render_mode::world_space)
454 {
455 return;
456 }
457 if(!ui_comp.is_enabled() || !ui_comp.framebuffer || !ui_comp.document || !ui_comp.document->IsVisible())
458 {
459 return;
460 }
461
462 const auto& world_transform = transform_comp.get_transform_global();
463 auto bbox = ui_comp.get_bounds();
464 if(!camera.test_obb(bbox, world_transform))
465 {
466 return;
467 }
468 auto handle = scn.create_handle(e);
469 float dist = math::distance2(camera.get_position(), world_transform.get_position());
470 ui_cache.entries.push_back({handle, &ui_comp, &transform_comp, dist});
471 });
472
473 std::sort(ui_cache.entries.begin(), ui_cache.entries.end(), [](const world_space_ui_entry& a, const world_space_ui_entry& b)
474 {
475 return a.distance > b.distance;
476 });
477
478 for(const auto& entry : ui_cache.entries)
479 {
480 auto& ui_comp = *entry.comp;
481 auto handle = entry.handle;
482 const auto& world_transform = entry.transform_comp->get_transform_global();
483 const auto scale = ui_comp.get_world_space_scale();
484 const auto model = world_transform * math::transform::scaling(scale);
485 auto topology = gfx::clip_quad(0.0f, 0.5f, 0.5f);
486 gfx::set_state(topology | world_ui_state);
487 world_quad_program_->set_texture(0, "s_tex", ui_comp.framebuffer.get(), 0);
489 gfx::submit(pass.id, world_quad_program_->native_handle()); }
490
491 ui_cache.entries.clear();
492
493 world_quad_program_->end();
494 }
495
496
497 struct world_space_text_entry
498 {
499 entt::handle handle;
500 text_component* comp = nullptr;
501 transform_component* transform_comp = nullptr;
502 float distance = 0.0f;
503 };
504 struct world_space_text_cache
505 {
506 std::vector<world_space_text_entry> entries;
507 };
508
509 //this approach preserves the capacities of the vector
510 auto& text_cache = cache_registry_.get_or_emplace<world_space_text_cache>(cache_entity_);
511 text_cache.entries.clear();
512
514 [&](auto e, auto&& transform_comp, auto&& text_comp, auto&& active)
515 {
516 const auto& world_transform = transform_comp.get_transform_global();
517 auto bbox = text_comp.get_bounds();
518
519 if(!camera.test_obb(bbox, world_transform))
520 {
521 return;
522 }
523
524 float dist = math::distance2(camera.get_position(), world_transform.get_position());
525 auto handle = scn.create_handle(e);
526 text_cache.entries.push_back({handle, &text_comp, &transform_comp, dist});
527 });
528
529 std::sort(text_cache.entries.begin(), text_cache.entries.end(), [](const world_space_text_entry& a, const world_space_text_entry& b)
530 {
531 return a.distance > b.distance;
532 });
533
534 for(const auto& entry : text_cache.entries)
535 {
536 auto& text_comp = *entry.comp;
537 auto handle = entry.handle;
538 const auto& world_transform = entry.transform_comp->get_transform_global();
539 text_comp.submit(pass.id, world_transform, BGFX_STATE_DEPTH_TEST_LESS);
540 }
541
542 text_cache.entries.clear();
543
544 gfx::discard();
545}
546
547
548void pipeline::run_particle_pass(scene& scn, const camera& camera, gfx::render_view& rview, const gfx::frame_buffer::ptr& output)
549{
550 APP_SCOPE_PERF("Rendering/Particle Pass");
551
552 auto lbuffer_depth = rview.fbo_get("LBUFFER_DEPTH");
553
554 // Set up render pass to render particles to the output framebuffer
555 gfx::render_pass pass("Particles/Pass");
556 pass.bind(lbuffer_depth.get());
557
558 const auto& view = camera.get_view();
559 const auto& proj = camera.get_projection();
560 pass.set_view_proj(view, proj);
561
562 stats_.drawn_particles = 0;
563 stats_.drawn_particles_batches = 0;
564
565 if(particle_program_instanced_ && particle_program_instanced_mask_ && particle_program_instanced_->begin() && particle_program_instanced_mask_->begin())
566 {
567 // Render particles using the particle system
568 auto cam_pos = camera.get_position();
569 auto cam_view = camera.get_view();
570
571
572 // Primary: material key (blend / texture / texture mode) so same-material emitters coalesce.
573 // Secondary: distance (far → near) within a material — does not split batches. Per-particle
574 // depth sort for Normal still runs inside ps_soa::render_emitter_batch.
575 struct sort_key
576 {
578 ps_soa::blend_mode blend_mode;
579 ps_soa::texture_mode texture_mode;
580 hpp::uuid texture_uid;
581 float distance;
582 };
583 hpp::small_vector<sort_key, 16> particle_emitters;
584
585 auto blend_draw_order = [](ps_soa::blend_mode mode) -> int
586 {
587 // Order-independent blends first; alpha (Normal) last so depth-sorted particles composite on top.
588 switch(mode)
589 {
590 case ps_soa::blend_mode::additive:
591 return 0;
592 case ps_soa::blend_mode::multiply:
593 return 1;
594 default:
595 return 2;
596 }
597 };
598
599 {
600 APP_SCOPE_PERF("Rendering/Particle Pass/Cull Emitters");
602 [&](auto e, auto&& transform_comp, auto&& particle_emitter_comp, auto&& active)
603 {
604 const auto& bounds = particle_emitter_comp.get_world_bounds();
605 if(!particle_emitter_comp.is_enabled() || !camera.test_aabb(bounds))
606 {
607 return;
608 }
609
610 // Renderer-based culling feedback (same as model_component).
611 particle_emitter_comp.set_last_render_frame(uint64_t(gfx::get_render_frame()));
612
613 const auto& tex = particle_emitter_comp.get_texture();
614 const float distance = math::distance2(bounds.get_center(), cam_pos);
615 particle_emitters.emplace_back(sort_key{&particle_emitter_comp,
616 particle_emitter_comp.get_blend_mode(),
617 particle_emitter_comp.get_texture_mode(),
618 tex.uid(),
619 distance});
620 });
621 }
622
623 {
624 APP_SCOPE_PERF("Rendering/Particle Pass/Sort Emitters by Material");
625 std::sort(particle_emitters.begin(),
626 particle_emitters.end(),
627 [&](const sort_key& a, const sort_key& b)
628 {
629 const int ao = blend_draw_order(a.blend_mode);
630 const int bo = blend_draw_order(b.blend_mode);
631 if(ao != bo)
632 {
633 return ao < bo;
634 }
635 if(a.texture_uid != b.texture_uid)
636 {
637 return a.texture_uid < b.texture_uid;
638 }
639 if(a.texture_mode != b.texture_mode)
640 {
641 return a.texture_mode < b.texture_mode;
642 }
643 // Same material: back-to-front (farther first).
644 return a.distance > b.distance;
645 });
646 }
647
648 {
649 APP_SCOPE_PERF("Rendering/Particle Pass/Submit Emitter Batches");
650 hpp::small_vector<ps_soa::emitter_handle, 16> current_batch;
651 asset_handle<gfx::texture> batch_texture;
652 ps_soa::texture_mode batch_texture_mode = ps_soa::texture_mode::multi_channel;
653 ps_soa::blend_mode batch_blend_mode = ps_soa::blend_mode::normal;
654 bool batch_open = false;
655
656 auto flush_particle_batch = [&]()
657 {
658 if(current_batch.empty() || !batch_texture.is_valid())
659 {
660 current_batch.clear();
661 batch_open = false;
662 return;
663 }
664 APP_SCOPE_PERF("Rendering/Particle Pass/Flush Emitter Batch");
665 const bgfx::ProgramHandle program = (batch_texture_mode == ps_soa::texture_mode::mask)
666 ? particle_program_instanced_mask_->native_handle()
667 : particle_program_instanced_->native_handle();
668 auto texture = batch_texture.get()->native_handle();
669 const uint64_t blend_state = particle_blend_bgfx_state(batch_blend_mode);
670 // Additive / Multiply are order-independent; skip expensive per-particle depth sort.
671 const bool sort_by_depth = (batch_blend_mode == ps_soa::blend_mode::normal);
672 stats_.drawn_particles += ps_soa::render_emitter_batch(current_batch.data(),
673 static_cast<uint32_t>(current_batch.size()),
674 pass.id,
675 program,
676 cam_view,
677 cam_pos,
678 texture,
680 sort_by_depth);
681 stats_.drawn_particles_batches++;
682 current_batch.clear();
683 batch_open = false;
684 };
685
686 for(const auto& particle_emitter : particle_emitters)
687 {
688 auto* comp = particle_emitter.component;
689 const auto& tex = comp->get_texture();
690 const ps_soa::texture_mode tm = particle_emitter.texture_mode;
691 const ps_soa::blend_mode bm = particle_emitter.blend_mode;
692 if(batch_open && (tex != batch_texture || tm != batch_texture_mode || bm != batch_blend_mode))
693 {
694 flush_particle_batch();
695 }
696 if(!batch_open)
697 {
698 batch_texture = tex;
699 batch_texture_mode = tm;
700 batch_blend_mode = bm;
701 batch_open = true;
702 }
703 if(comp->is_enabled())
704 {
705 auto emitter_handle = comp->get_emitter_handle();
706 if(ps_soa::is_valid(emitter_handle))
707 {
708 current_batch.push_back(emitter_handle);
709 }
710 }
711 }
712 flush_particle_batch();
713 }
714
715 particle_program_instanced_->end();
716 particle_program_instanced_mask_->end();
717 }
718}
719
720// pipeline_stats implementation
721void pipeline_stats::add_batch_stats(const batch_stats& stats)
722{
723 batching_stats.total_batches += stats.total_batches;
724 batching_stats.total_instances += stats.total_instances;
725 batching_stats.collection_time_ms += stats.collection_time_ms;
726 batching_stats.preparation_time_ms += stats.preparation_time_ms;
727 batching_stats.submission_time_ms += stats.submission_time_ms;
728 batching_stats.instance_buffer_memory_used += stats.instance_buffer_memory_used;
729 batching_stats.split_batches += stats.split_batches;
730
731 // Recalculate derived stats
732 batching_stats.calculate_derived_stats();
733}
734
735void pipeline_stats::add_stats(const pipeline_stats& stats)
736{
737 drawn_models += stats.drawn_models;
738 drawn_static_submeshes += stats.drawn_static_submeshes;
739 drawn_skinned_models += stats.drawn_skinned_models;
740 drawn_skinned_submeshes += stats.drawn_skinned_submeshes;
741 drawn_models_for_shadows += stats.drawn_models_for_shadows;
742 drawn_submeshes_for_shadows += stats.drawn_submeshes_for_shadows;
743 drawn_skinned_models_for_shadows += stats.drawn_skinned_models_for_shadows;
744 drawn_skinned_submeshes_for_shadows += stats.drawn_skinned_submeshes_for_shadows;
745 drawn_lights += stats.drawn_lights;
746 drawn_lights_casting_shadows += stats.drawn_lights_casting_shadows;
747 drawn_particles += stats.drawn_particles;
748 drawn_particles_batches += stats.drawn_particles_batches;
749
750 add_batch_stats(stats.batching_stats);
751}
752
753} // namespace rendering
754} // namespace unravel
entt::handle b
entt::handle a
auto fbo_get(const hpp::string_view &id) const -> const frame_buffer::ptr &
static auto scaling(const vec2_t &scale) noexcept -> transform_t
Create a scaling transform.
bool enabled
Whether ASSAO is enabled.
Manages assets, including loading, unloading, and storage.
Class representing a camera. Contains functionality for manipulating and updating a camera....
Definition camera.h:62
auto test_obb(const math::bbox &bounds, const math::transform &t) const -> bool
Tests if the specified OBB is within the frustum.
Definition camera.cpp:451
auto get_projection() const -> const math::transform &
Retrieves the current projection matrix.
Definition camera.cpp:205
auto get_view() const -> const math::transform &
Retrieves the current view matrix.
Definition camera.cpp:278
auto test_aabb(const math::bbox &bounds) const -> bool
Tests if the specified AABB is within the frustum.
Definition camera.cpp:433
void set_aa_data(const usize32_t &viewport_size, std::uint32_t temporal_frame_index, std::uint32_t temporal_aa_samples, taa_jitter_mode jitter_mode=taa_jitter_mode::progressive_golden, float jitter_amplitude=1.0f, float jitter_temporal_phase_scale=1.0f)
Sets the current jitter value for temporal anti-aliasing.
Definition camera.cpp:767
auto get_position() const -> const math::vec3 &
Retrieves the current position of the camera.
Definition camera.cpp:353
auto get_frustum() const -> const math::frustum &
Retrieves the current camera object frustum.
Definition camera.cpp:372
bool enabled
Whether FXAA is enabled.
Class that contains core data for meshes.
Structure describing a LOD group (set of meshes), LOD transitions, and their materials.
Definition model.h:275
auto is_valid() const -> bool
Checks if the model is valid.
Definition model.cpp:174
auto calculate_lod_data(lod_data &data, const math::bbox &world_bounds, const camera &cam, float dt) const -> bool
Calculates the LOD data for the model using distance-based hysteresis with time-based transitions....
Definition model.cpp:360
auto compute_lod_index(const math::bbox &world_bounds, const camera &cam, float extra_bias=0.0f) const -> uint32_t
Computes a LOD index for this model without hysteresis, transitions or visibility culling.
Definition model.cpp:567
Component that wraps the soa particle system emitter.
virtual auto init(rtti::context &ctx) -> bool
Definition pipeline.cpp:58
@ is_static
Query for static entities.
Definition pipeline.h:107
@ is_shadow_caster
Query for shadow casting entities.
Definition pipeline.h:108
static auto get_shadow_lod_bias() -> float
LOD bias applied on top of the main selection when rendering shadows. 0 = shadows use the same LOD th...
Definition pipeline.cpp:100
virtual void gather_visible_models(scene &scn, const camera *cam, visibility_flags query, const layer_mask &render_mask, delta_t dt, const std::function< void(entt::handle entity, const lod_data &lod_data)> &lod_data_callback, const camera *lod_reference_cam=nullptr)
Gathers visible models from the scene based on the given query.
Definition pipeline.cpp:110
static void set_shadow_lod_bias(float bias)
Definition pipeline.cpp:105
uint32_t visibility_flags
Type alias for visibility flags.
Definition pipeline.h:111
bool enabled
Whether SSR is enabled.
Temporal anti-aliasing (HDR, before tonemap). Mutually exclusive with FXAA when enabled.
bool enabled
Whether tonemapping is enabled.
Component that handles transformations (position, rotation, scale, etc.) in the ACE framework.
std::chrono::duration< float > delta_t
uint16_t view
std::vector< render_pass_entry > entries
Definition cache.hpp:11
void submit(view_id _id, program_handle _handle, int32_t _depth, bool _preserveState)
void set_state(uint64_t _state, uint32_t _rgba)
Definition graphics.cpp:937
void set_world_transform(const void *_mtx, uint16_t _num)
void discard(uint8_t _flags)
uint32_t get_render_frame()
auto clip_quad(float depth, float width, float height) -> uint64_t
auto queue(seq_action action, const seq_scope_policy &scope_policy, hpp::source_location location) -> seq_id_t
Queues a new action.
Definition seq.cpp:14
blend_mode
Blend mode. Ordinals match legacy BlendMode.
texture_mode
Texture interpretation. Ordinals match legacy TextureMode.
auto resolve_post_process_volumes(scene &scn, const math::vec3 &camera_pos, entt::handle camera_ent) -> resolved_post_process_settings
Resolves post-process volumes for a camera position.
std::vector< float > scale
#define APP_SCOPE_PERF(name_literal)
Create a scoped performance timer that records to the timeline profiler. Only accepts string literals...
Definition profiler.h:675
entt::handle entity
Thread-safe handle to an asset.
auto is_valid() const -> bool
Checks if the handle references a task.
auto get(bool wait=true) const -> std::shared_ptr< T >
Gets the shared pointer to the asset.
void set_view_proj(const float *v, const float *p)
gfx::view_id id
void bind(const frame_buffer *fb=nullptr) const
Component that provides a layer mask for an entity.
Contains level of detail (LOD) data for an entity per view. Uses distance-based hysteresis for stable...
Definition model.h:34
std::function< void(assao_pass::run_params &params)> fill_assao_params
Definition pipeline.h:135
std::function< void(auto_exposure_pass::run_params &params)> fill_auto_exposure_params
Definition pipeline.h:136
std::function< void(taa_pass::run_params &params)> fill_taa_params
Definition pipeline.h:140
std::function< void(ssr_pass::run_params &params)> fill_ssr_params
Definition pipeline.h:144
std::function< void(bloom_pass::run_params &params)> fill_bloom_params
Definition pipeline.h:137
std::function< void(tonemapping_pass::run_params &params)> fill_hdr_params
Definition pipeline.h:138
std::function< void(ssil_pass::run_params &params)> fill_ssil_params
Definition pipeline.h:145
std::function< void(fxaa_pass::run_params &params)> fill_fxaa_params
Definition pipeline.h:139
std::function< void(camera &, const usize32_t &viewport_size)> apply_taa_params
Definition pipeline.h:143
Represents a scene in the ACE framework, managing entities and their relationships.
Definition scene.h:70
std::unique_ptr< entt::registry > registry
The registry that manages all entities in the scene.
Definition scene.h:187
auto create_handle(entt::entity e) -> entt::handle
Creates an entity in the scene.
Definition scene.cpp:428
Combined SSR settings.
Definition ssr_pass.h:77
Component that holds a reference to a UI document for RmlUi rendering.
gfx::uniform_handle handle
Definition uniform.cpp:9