Unravel Engine C++ Reference
Loading...
Searching...
No Matches
ssr_pass.cpp
Go to the documentation of this file.
1#include "ssr_pass.h"
2#include <algorithm>
5#include <graphics/graphics.h>
7#include <graphics/texture.h>
8
9namespace unravel
10{
11
12auto ssr_pass::init(rtti::context& ctx) -> bool
13{
14 auto& am = ctx.get_cached<asset_manager>();
15
16 // Load shaders
17 auto vs_clip_quad = am.get_asset<gfx::shader>("engine:/data/shaders/vs_clip_quad.sc");
18
19 // Load FidelityFX SSR shader (trace pass)
20 auto fs_ssr_fidelityfx = am.get_asset<gfx::shader>("engine:/data/shaders/ssr/fs_ssr_fidelityfx.sc");
21
22 // Load temporal resolve shader
23 auto fs_ssr_temporal_resolve = am.get_asset<gfx::shader>("engine:/data/shaders/ssr/fs_ssr_temporal_resolve.sc");
24
25 // Load composite shader
26 auto fs_ssr_composite = am.get_asset<gfx::shader>("engine:/data/shaders/ssr/fs_ssr_composite.sc");
27
28 // Load unified blur compute shader for cone tracing
29 auto cs_ssr_blur = am.get_asset<gfx::shader>("engine:/data/shaders/ssr/cs_ssr_blur.sc");
30
31 // Load spatial denoise compute shader
32 auto cs_ssr_spatial_denoise = am.get_asset<gfx::shader>("engine:/data/shaders/ssr/cs_ssr_spatial_denoise.sc");
33
34 // Create FidelityFX SSR programs
35 fidelityfx_pixel_program_.program = std::make_unique<gpu_program>(vs_clip_quad, fs_ssr_fidelityfx);
36 fidelityfx_pixel_program_.cache_uniforms();
37
38 // Create temporal resolve program
39 temporal_resolve_program_.program = std::make_unique<gpu_program>(vs_clip_quad, fs_ssr_temporal_resolve);
40 temporal_resolve_program_.cache_uniforms();
41
42 // Create composite program
43 composite_program_.program = std::make_unique<gpu_program>(vs_clip_quad, fs_ssr_composite);
44 composite_program_.cache_uniforms();
45
46 // Create unified blur compute program for cone tracing
47 blur_compute_program_.program = std::make_unique<gpu_program>(cs_ssr_blur);
48 blur_compute_program_.cache_uniforms();
49
50 // Create spatial denoise compute program
51 spatial_denoise_compute_program_.program = std::make_unique<gpu_program>(cs_ssr_spatial_denoise);
52 spatial_denoise_compute_program_.cache_uniforms();
53
54 // Validate all programs
55 bool all_valid = fidelityfx_pixel_program_.is_valid() && temporal_resolve_program_.is_valid() &&
56 composite_program_.is_valid() && blur_compute_program_.is_valid() &&
57 spatial_denoise_compute_program_.is_valid();
58
59 return all_valid;
60}
61
62auto ssr_pass::create_or_update_output_fb(gfx::render_view& rview,
63 const gfx::frame_buffer::ptr& reference,
65{
66 // If the caller provided an output framebuffer, just return it.
67 if(output)
68 {
69 return output;
70 }
71
72 // Otherwise, use the render_view to get or create the SSR output framebuffer
73 auto ref_sz = reference->get_size();
74 auto ref_format = gfx::texture_format::RGBA16F;
75
76 auto& ssr_output_tex = rview.tex_get_or_emplace("SSR_OUTPUT");
77 if(gfx::needs_recreate(ssr_output_tex, ref_sz, ref_format))
78 {
79 ssr_output_tex.reset();
80 ssr_output_tex = std::make_shared<gfx::texture>(ref_sz.width,
81 ref_sz.height,
82 false,
83 1,
84 ref_format,
85 BGFX_TEXTURE_RT | BGFX_SAMPLER_U_CLAMP |
86 BGFX_SAMPLER_V_CLAMP);
87 }
88
89 auto& ssr_output_fbo = rview.fbo_get_or_emplace("SSR_OUTPUT");
90 if(gfx::needs_recreate(ssr_output_fbo, ref_sz))
91 {
92 ssr_output_fbo.reset();
93 ssr_output_fbo = std::make_shared<gfx::frame_buffer>();
94 ssr_output_fbo->populate({ssr_output_tex});
95 }
96
97 return ssr_output_fbo;
98}
99
100auto ssr_pass::create_or_update_ssr_curr_fb(gfx::render_view& rview,
101 const gfx::frame_buffer::ptr& reference,
103{
104 const auto target_size = compute_trace_size(reference->get_size(), res);
105 const auto ref_format = gfx::texture_format::RGBA16F;
106
107 auto& ssr_curr_tex = rview.tex_get_or_emplace("SSR_CURR");
108 if(gfx::needs_recreate(ssr_curr_tex, target_size, ref_format))
109 {
110 ssr_curr_tex.reset();
111 ssr_curr_tex = std::make_shared<gfx::texture>(target_size.width,
112 target_size.height,
113 false,
114 1,
115 ref_format,
116 BGFX_TEXTURE_RT | BGFX_SAMPLER_U_CLAMP |
117 BGFX_SAMPLER_V_CLAMP);
118 }
119
120 auto& ssr_curr_fbo = rview.fbo_get_or_emplace("SSR_CURR");
121 if(gfx::needs_recreate(ssr_curr_fbo, target_size))
122 {
123 ssr_curr_fbo.reset();
124 ssr_curr_fbo = std::make_shared<gfx::frame_buffer>();
125 ssr_curr_fbo->populate({ssr_curr_tex});
126 }
127
128 return ssr_curr_fbo;
129}
130
131auto ssr_pass::create_or_update_ssr_history_tex(gfx::render_view& rview,
132 const gfx::frame_buffer::ptr& reference,
134{
135 const auto target_size = compute_trace_size(reference->get_size(), res);
136 const auto ref_format = gfx::texture_format::RGBA16F;
137
138 auto& history_tex = rview.tex_get_or_emplace("SSR_HISTORY");
139 if(gfx::needs_recreate(history_tex, target_size, ref_format))
140 {
141 history_tex.reset();
142 history_tex = std::make_shared<gfx::texture>(target_size.width,
143 target_size.height,
144 false,
145 1,
146 ref_format,
147 BGFX_TEXTURE_BLIT_DST | BGFX_TEXTURE_RT | BGFX_SAMPLER_U_CLAMP |
148 BGFX_SAMPLER_V_CLAMP);
149 }
150
151 return history_tex;
152}
153
154auto ssr_pass::create_or_update_ssr_history_temp_fb(gfx::render_view& rview,
155 const gfx::frame_buffer::ptr& reference,
157{
158 const auto target_size = compute_trace_size(reference->get_size(), res);
159 const auto ref_format = gfx::texture_format::RGBA16F;
160
161 auto& temp_tex = rview.tex_get_or_emplace("SSR_HISTORY_TEMP");
162 if(gfx::needs_recreate(temp_tex, target_size, ref_format))
163 {
164 temp_tex.reset();
165 temp_tex = std::make_shared<gfx::texture>(target_size.width,
166 target_size.height,
167 false,
168 1,
169 ref_format,
170 BGFX_TEXTURE_BLIT_DST | BGFX_TEXTURE_RT | BGFX_SAMPLER_U_CLAMP |
171 BGFX_SAMPLER_V_CLAMP);
172 }
173
174 auto& temp_fbo = rview.fbo_get_or_emplace("SSR_HISTORY_TEMP");
175 if(gfx::needs_recreate(temp_fbo, target_size))
176 {
177 temp_fbo.reset();
178 temp_fbo = std::make_shared<gfx::frame_buffer>();
179 temp_fbo->populate({temp_tex});
180 }
181
182 return temp_fbo;
183}
184
186{
187 // Ensure we have valid input
188 if(!params.g_buffer)
189 {
190 return nullptr;
191 }
192
193 // Dispatch to appropriate implementation based on settings
194 return run_fidelityfx(rview, params);
195}
196
198{
199 // Use the new three-pass pipeline by default
200 return run_fidelityfx_three_pass(rview, params);
201}
202
203
205 const gfx::texture::ptr& input_color,
206 const gfx::frame_buffer::ptr& g_buffer,
208{
209 APP_SCOPE_PERF("Rendering/SSR/Blur Color Pass");
210 // Early validation
211 if(!input_color)
212 {
213 return nullptr;
214 }
215
216 if(!blur_compute_program_.program || !blur_compute_program_.program->is_valid())
217 {
218 return input_color; // Fallback to input texture
219 }
220
221 auto input_size = input_color->get_size();
222
223 // Get or create blurred color texture with mip chain
224 auto& blurred_tex = rview.tex_get_or_emplace("SSR_BLURRED_COLOR");
225 if(gfx::needs_recreate(blurred_tex, input_size))
226 {
227 blurred_tex.reset();
228 blurred_tex = std::make_shared<gfx::texture>(input_size.width,
229 input_size.height,
230 true, // has mips
231 1, // num layers
232 gfx::texture_format::RGBA16F,
233 BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP |
234 BGFX_TEXTURE_COMPUTE_WRITE | BGFX_TEXTURE_RT);
235 }
236
237 const uint32_t num_mips = settings.cone_tracing.max_mip_level + 1;
238 gfx::render_pass pass("Blur Compute Pass");
239
240 // Process each mip level using unified blur shader
241 for(int mip = 0; mip < num_mips; ++mip)
242 {
243 // Calculate mip size
244 int mip_width = (input_size.width >> mip) > 1 ? (input_size.width >> mip) : 1;
245 int mip_height = (input_size.height >> mip) > 1 ? (input_size.height >> mip) : 1;
246
247 // Calculate sigma based on mip level and base sigma
248 float sigma = settings.cone_tracing.blur_base_sigma; // * (1.0f + float(mip));
249
250 // Use unified blur compute shader
251 blur_compute_program_.program->begin();
252
253 // Set blur parameters: mip_level, sigma, base_width, base_height
254 if(mip == 0)
255 {
256 // Bind input color texture as read-only image
257 gfx::set_image(1, input_color->native_handle(), 0, bgfx::Access::Read);
258 }
259 else
260 {
261 // Bind previous mip level as input read-only image
262 gfx::set_image(1, blurred_tex->native_handle(), mip - 1, bgfx::Access::Read);
263 }
264
265 float blur_params[4] = {float(mip), sigma, 0.0f, 0.0f};
266 gfx::set_uniform(blur_compute_program_.u_blur_params, blur_params);
267
268 // Bind output image (current mip level of blurred texture)
269 gfx::set_image(0, blurred_tex->native_handle(), mip, bgfx::Access::Write);
270
271 gfx::set_texture(blur_compute_program_.s_normal, 2, g_buffer->get_texture(1));
272
273 // Dispatch compute shader
274 uint32_t num_groups_x = (mip_width + 7) / 8;
275 uint32_t num_groups_y = (mip_height + 7) / 8;
276 gfx::dispatch(pass.id, blur_compute_program_.program->native_handle(), num_groups_x, num_groups_y, 1);
277
278 blur_compute_program_.program->end();
279 }
280
281 return blurred_tex;
282}
283
284auto ssr_pass::create_or_update_ssr_denoise_fb(gfx::render_view& rview,
285 const std::string& name,
286 const gfx::frame_buffer::ptr& reference,
288{
289 const auto target_size = compute_trace_size(reference->get_size(), res);
290
291 auto& denoised_tex = rview.tex_get_or_emplace(name);
292 if(gfx::needs_recreate(denoised_tex, target_size))
293 {
294 denoised_tex.reset();
295 denoised_tex = std::make_shared<gfx::texture>(target_size.width,
296 target_size.height,
297 false,
298 1,
299 gfx::texture_format::RGBA16F,
300 BGFX_TEXTURE_COMPUTE_WRITE | BGFX_TEXTURE_RT |
301 BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP);
302 }
303
304 auto& denoised_fbo = rview.fbo_get_or_emplace(name);
305 if(gfx::needs_recreate(denoised_fbo, target_size))
306 {
307 denoised_fbo.reset();
308 denoised_fbo = std::make_shared<gfx::frame_buffer>();
309 denoised_fbo->populate({denoised_tex});
310 }
311
312 return denoised_fbo;
313}
314
316 const gfx::frame_buffer::ptr& ssr_curr,
317 const gfx::frame_buffer::ptr& g_buffer,
319{
320 if(!spatial_denoise_compute_program_.is_valid())
321 {
322 return ssr_curr;
323 }
324
325 APP_SCOPE_PERF("Rendering/SSR/Spatial Denoise Pass");
326
327 const int num_passes = std::clamp(settings.spatial_denoise.passes, 1, 5);
328
329 // ssr_curr already carries the trace resolution; denoise buffers match it 1:1.
330 // Two ping-pong framebuffers so the a-trous step doubles each iteration
331 // (1, 2, 4, ...) without aliasing reads against writes.
332 auto fb_a = create_or_update_ssr_denoise_fb(rview, "SSR_DENOISED_A", ssr_curr, trace_resolution::full);
333 auto fb_b = create_or_update_ssr_denoise_fb(rview, "SSR_DENOISED_B", ssr_curr, trace_resolution::full);
334 auto sz = fb_a->get_size();
335 const uint32_t gx = (sz.width + 7) / 8;
336 const uint32_t gy = (sz.height + 7) / 8;
337
338 auto src_tex = ssr_curr->get_texture();
339 gfx::frame_buffer::ptr dst_fb = fb_a;
340
341 for(int i = 0; i < num_passes; ++i)
342 {
343 gfx::render_pass pass(fmt::format("Spatial Denoise Pass {}", i).c_str());
344
345 spatial_denoise_compute_program_.program->begin();
346
347 gfx::set_texture(spatial_denoise_compute_program_.s_ssr_input, 0, src_tex);
348 gfx::set_image(1, dst_fb->get_texture()->native_handle(), 0, bgfx::Access::Write);
349 gfx::set_texture(spatial_denoise_compute_program_.s_normal, 2, g_buffer->get_texture(1));
350 gfx::set_texture(spatial_denoise_compute_program_.s_depth, 3, g_buffer->get_texture(4));
351
352 float denoise_params[4] = {
353 float(1 << i),
354 settings.spatial_denoise.depth_sigma,
355 settings.spatial_denoise.normal_power,
356 settings.spatial_denoise.luma_sigma};
357 gfx::set_uniform(spatial_denoise_compute_program_.u_denoise_params, denoise_params);
358
359 gfx::dispatch(pass.id, spatial_denoise_compute_program_.program->native_handle(), gx, gy, 1);
360
361 spatial_denoise_compute_program_.program->end();
362
363 src_tex = dst_fb->get_texture();
364 dst_fb = (dst_fb == fb_a) ? fb_b : fb_a;
365 }
366
367 // The final result lives in whichever fb we last *wrote* to, which is the
368 // one NOT pointed at by dst_fb (we flipped at the end of the loop).
369 return (dst_fb == fb_a) ? fb_b : fb_a;
370}
371
373{
375 // Pass 1: SSR Trace - generates SSR_CURR
376 auto ssr_curr_fb = run_ssr_trace(rview, params);
377 if(!ssr_curr_fb)
378 {
380 return nullptr;
381 }
382
383 // Pass 1.5: Spatial Denoise (optional) - filters SSR_CURR before temporal resolve
384 auto temporal_input_fb = ssr_curr_fb;
385 if(params.settings.fidelityfx.enable_spatial_denoise)
386 {
387 temporal_input_fb = run_spatial_denoise(rview, ssr_curr_fb, params.g_buffer, params.settings.fidelityfx);
388 }
389 else
390 {
391 rview.fbo_remove("SSR_DENOISED_A");
392 rview.tex_remove("SSR_DENOISED_A");
393 rview.fbo_remove("SSR_DENOISED_B");
394 rview.tex_remove("SSR_DENOISED_B");
395 }
396
397 // Pass 2: Temporal Resolve - reads (denoised) SSR_CURR + SSR_HIST, writes new SSR_HIST
398 auto ssr_history_fb =
399 run_temporal_resolve(rview, temporal_input_fb, params.g_buffer, params.cam, params.settings.fidelityfx);
400 if(!ssr_history_fb)
401 {
403 return ssr_curr_fb; // Fallback to current frame
404 }
405
406 // Pass 3: Composite - blends SSR_HIST + SSR_CURR + probe, writes to output
407 auto composite_fb =
408 run_composite(rview, ssr_history_fb, ssr_curr_fb, params.output, params.g_buffer, params.output);
410 return composite_fb;
411}
412
414{
415 // SSR caps at half resolution: sub-half breaks Hi-Z, temporal clamp and the denoiser.
416 const auto trace_res = params.settings.fidelityfx.resolution;
417 auto ssr_curr_fbo = create_or_update_ssr_curr_fb(rview, params.g_buffer, trace_res);
418
419 // Generate blurred color buffer for cone tracing if enabled
420 gfx::texture::ptr blurred_color_buffer = nullptr;
421 if(params.settings.fidelityfx.enable_cone_tracing && params.previous_frame)
422 {
423 blurred_color_buffer =
424 generate_blurred_color_buffer(rview, params.previous_frame, params.g_buffer, params.settings.fidelityfx);
425 }
426 else
427 {
428 rview.tex_remove("SSR_BLURRED_COLOR");
429 }
430
431 // ============================================================================
432 // SSR Trace Pass
433 // ============================================================================
434 APP_SCOPE_PERF("Rendering/SSR/Trace Pass");
435
436 gfx::render_pass pass("Trace Pass");
437 pass.bind(ssr_curr_fbo.get());
438 pass.set_view_proj(params.cam->get_view(), params.cam->get_projection());
439
440 // Bind SSR trace program
441 fidelityfx_pixel_program_.program->begin();
442
443 // Set input textures
444 gfx::set_texture(fidelityfx_pixel_program_.s_color, 0, params.previous_frame);
445 gfx::set_texture(fidelityfx_pixel_program_.s_normal, 1, params.g_buffer->get_texture(1));
446 gfx::set_texture(fidelityfx_pixel_program_.s_depth, 2, params.g_buffer->get_texture(4));
447 gfx::set_texture(fidelityfx_pixel_program_.s_hiz, 3, params.hiz_buffer);
448
449 // Set blurred color buffer for cone tracing (fallback to previous frame if not available)
450 auto cone_tracing_texture = blurred_color_buffer ? blurred_color_buffer : params.previous_frame;
451 gfx::set_texture(fidelityfx_pixel_program_.s_color_blurred, 4, cone_tracing_texture);
452
453 // Set SSR parameters (max_steps, depth_tolerance, max_rays, brightness)
454 float ssr_params[4] = {float(params.settings.fidelityfx.max_steps),
455 params.settings.fidelityfx.depth_tolerance,
456 float(params.settings.fidelityfx.max_rays),
457 params.settings.fidelityfx.brightness};
458 gfx::set_uniform(fidelityfx_pixel_program_.u_ssr_params, ssr_params);
459
460
461 // Resolution scale MUST be per-axis. Computing a single scalar (e.g. full_w / half_w)
462 // and applying it to both axes silently breaks any case where the X and Y ratios
463 // disagree, which is exactly what happens at odd full-res W with even full-res H:
464 // e.g. (1233, 900) -> half (616, 450) gives X=2.00162 but Y=2.0. Reusing the X scale
465 // on the Y axis shifts the bottom half-res row's gbuffer fetch ~0.7 full-res pixels
466 // off, producing a garbage out-of-frustum ray origin and a visible noise band along
467 // the bottom of the viewport at odd widths.
468 auto ssr_size = ssr_curr_fbo->get_size();
469 auto g_buffer_size = params.g_buffer->get_size();
470 const float ssr_scale_x = float(g_buffer_size.width) / float(ssr_size.width);
471 const float ssr_scale_y = float(g_buffer_size.height) / float(ssr_size.height);
472 // u_hiz_params layout: (hiz_width, hiz_height, scale_x, scale_y).
473 // num_mips was previously stored in .z but is unused by the shader.
474 float hiz_params[4] = {0.0f, 0.0f, ssr_scale_x, ssr_scale_y};
475 if(params.hiz_buffer)
476 {
477 hiz_params[0] = float(params.hiz_buffer->info.width);
478 hiz_params[1] = float(params.hiz_buffer->info.height);
479 }
480 gfx::set_uniform(fidelityfx_pixel_program_.u_hiz_params, hiz_params);
481
482 // Set fade parameters (fade_in_start, fade_in_end, roughness_depth_tolerance, facing_reflections_fading)
483 float fade_params[4] = {params.settings.fidelityfx.fade_in_start,
484 params.settings.fidelityfx.fade_in_end,
485 params.settings.fidelityfx.roughness_depth_tolerance,
486 params.settings.fidelityfx.facing_reflections_fading};
487 gfx::set_uniform(fidelityfx_pixel_program_.u_fade_params, fade_params);
488
489 // Set cone tracing parameters (cone_angle_bias, max_mip_level, frame_number, enable_cone_tracing)
490 float cone_params[4] = {
491 params.settings.fidelityfx.cone_tracing.cone_angle_bias,
492 float(params.settings.fidelityfx.cone_tracing.max_mip_level),
493 float(gfx::get_render_frame() % 4), // frame number for temporal jitter
494 float(params.settings.fidelityfx.enable_cone_tracing ? 1.0f : 0.0f) // enable flag
495 };
496 gfx::set_uniform(fidelityfx_pixel_program_.u_cone_params, cone_params);
497
498 // Set previous frame view-projection matrix for temporal reprojection
499 auto prev_view_proj = params.cam->get_prev_view_projection();
500 gfx::set_uniform(fidelityfx_pixel_program_.u_prev_view_proj, prev_view_proj.get_matrix());
501
502 uint64_t topology = gfx::clip_fullscreen_triangle(1.0f);
503 if(topology == 0)
504 {
505 topology = gfx::clip_quad(1.0f);
506 }
507 gfx::set_state(topology | BGFX_STATE_DEPTH_TEST_NEVER | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A);
508 gfx::submit(pass.id, fidelityfx_pixel_program_.program->native_handle());
509
510 // Reset state
511 gfx::set_state(BGFX_STATE_DEFAULT);
512 fidelityfx_pixel_program_.program->end();
513 gfx::discard();
514
515 return ssr_curr_fbo;
516}
517
519 const gfx::frame_buffer::ptr& ssr_curr,
520 const gfx::frame_buffer::ptr& g_buffer,
521 const camera* cam,
523{
524 if(!temporal_resolve_program_.is_valid())
525 {
526 return nullptr;
527 }
528
529 // History buffers match ssr_curr's size exactly; ssr_curr already carries the trace
530 // resolution, so we ask the helpers not to downscale any further.
531 auto old_history = rview.tex_safe_get("SSR_HISTORY");
532 auto history_tex = create_or_update_ssr_history_tex(rview, ssr_curr, trace_resolution::full);
533 auto temp_fbo = create_or_update_ssr_history_temp_fb(rview, ssr_curr, trace_resolution::full);
534
535 // History was just allocated -- RGBA16F contains undefined data (possibly NaN).
536 // Seed it with the current frame and skip temporal this frame.
537 if(history_tex != old_history)
538 {
539 gfx::render_pass blit_pass("History Init Blit Pass");
540 gfx::blit(blit_pass.id, history_tex->native_handle(), 0, 0, ssr_curr->get_texture()->native_handle(), 0, 0);
541 return nullptr;
542 }
543
544 // ============================================================================
545 // Temporal Resolve Pass
546 // ============================================================================
547 APP_SCOPE_PERF("Rendering/SSR/Temporal Resolve Pass");
548
549 gfx::render_pass pass("Temporal Resolve Pass");
550 pass.bind(temp_fbo.get());
551 pass.set_view_proj(cam->get_view(), cam->get_projection());
552
553 // Bind temporal resolve program
554 temporal_resolve_program_.program->begin();
555
556 // Set input textures
557 gfx::set_texture(temporal_resolve_program_.s_ssr_curr, 0, ssr_curr->get_texture());
558 gfx::set_texture(temporal_resolve_program_.s_ssr_history, 1, history_tex);
559 gfx::set_texture(temporal_resolve_program_.s_normal, 2, g_buffer->get_texture(1));
560 gfx::set_texture(temporal_resolve_program_.s_depth, 3, g_buffer->get_texture(4));
561
562 // Set temporal parameters (enable_temporal, history_strength, depth_threshold, roughness_sensitivity)
563 float temporal_params[4] = {settings.enable_temporal_accumulation ? 1.0f : 0.0f,
564 settings.temporal.history_strength,
565 settings.temporal.depth_threshold,
566 settings.temporal.roughness_sensitivity};
567 gfx::set_uniform(temporal_resolve_program_.u_temporal_params, temporal_params);
568
569 // Set motion parameters (motion_scale_pixels, normal_dot_threshold, max_accum_frames, unused)
570 float motion_params[4] = {
571 settings.temporal.motion_scale_pixels,
572 settings.temporal.normal_dot_threshold,
573 float(settings.temporal.max_accum_frames),
574 0.0f // unused
575 };
576 gfx::set_uniform(temporal_resolve_program_.u_motion_params, motion_params);
577
578 // Per-axis scale; see ssr trace pass for why scalar scale is wrong at odd full-res W.
579 auto history_size = history_tex->get_size();
580 auto g_buffer_size = g_buffer->get_size();
581 const float ssr_scale_x = float(g_buffer_size.width) / float(history_size.width);
582 const float ssr_scale_y = float(g_buffer_size.height) / float(history_size.height);
583
584 float fade_params[4] = {settings.fade_in_start, settings.fade_in_end, ssr_scale_x, ssr_scale_y};
585 gfx::set_uniform(temporal_resolve_program_.u_fade_params, fade_params);
586
587 // Set previous frame view-projection matrix
588 auto prev_view_proj = cam->get_prev_view_projection();
589 gfx::set_uniform(temporal_resolve_program_.u_prev_view_proj, prev_view_proj.get_matrix());
590
591 // Draw fullscreen quad
592 auto topology = gfx::clip_quad(1.0f);
593 gfx::set_state(topology | BGFX_STATE_DEPTH_TEST_NEVER | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A);
594 gfx::submit(pass.id, temporal_resolve_program_.program->native_handle());
595
596 // Reset state
597 gfx::set_state(BGFX_STATE_DEFAULT);
598 temporal_resolve_program_.program->end();
599 gfx::discard();
600
601 // ============================================================================
602 // Blit temp_fbo texture into persistent history_tex for next frame
603 // ============================================================================
604 gfx::render_pass blit_pass("History Blit Pass");
605 gfx::blit(blit_pass.id, history_tex->native_handle(), 0, 0, temp_fbo->get_texture()->native_handle(), 0, 0);
606
607 return temp_fbo;
608}
609
611 const gfx::frame_buffer::ptr& ssr_history,
612 const gfx::frame_buffer::ptr& ssr_curr,
613 const gfx::frame_buffer::ptr& probe_buffer,
614 const gfx::frame_buffer::ptr& g_buffer,
616{
617 if(!composite_program_.is_valid())
618 {
619 return nullptr;
620 }
621
622 // Get or create output framebuffer using render_view
623 auto actual_output = create_or_update_output_fb(rview, g_buffer, output);
624
625 // ============================================================================
626 // Composite Pass
627 // ============================================================================
628 APP_SCOPE_PERF("Rendering/SSR/Composite Pass");
629
630 gfx::render_pass pass("Composite Pass");
631 pass.bind(actual_output.get());
632
633 // Bind composite program
634 composite_program_.program->begin();
635
636 // Set input textures
637 gfx::set_texture(composite_program_.s_ssr_history, 0, ssr_history->get_texture());
638 gfx::set_texture(composite_program_.s_ssr_curr, 1, ssr_curr->get_texture());
639 gfx::set_texture(composite_program_.s_normal, 2, g_buffer->get_texture(1));
640 gfx::set_texture(composite_program_.s_depth, 3, g_buffer->get_texture(4));
641
642 // Draw fullscreen quad with alpha blending
643 auto topology = gfx::clip_quad(1.0f);
644 gfx::set_state(topology | BGFX_STATE_DEPTH_TEST_NEVER | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A |
645 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
646 gfx::submit(pass.id, composite_program_.program->native_handle());
647
648 // Reset state
649 gfx::set_state(BGFX_STATE_DEFAULT);
650 composite_program_.program->end();
651 gfx::discard();
652
653 return actual_output;
654}
655
657{
658 rview.fbo_remove("SSR_OUTPUT");
659 rview.tex_remove("SSR_OUTPUT");
660 rview.fbo_remove("SSR_CURR");
661 rview.tex_remove("SSR_CURR");
662 rview.tex_remove("SSR_HISTORY");
663 rview.fbo_remove("SSR_HISTORY_TEMP");
664 rview.tex_remove("SSR_HISTORY_TEMP");
665 rview.tex_remove("SSR_BLURRED_COLOR");
666 rview.fbo_remove("SSR_DENOISED_A");
667 rview.tex_remove("SSR_DENOISED_A");
668 rview.fbo_remove("SSR_DENOISED_B");
669 rview.tex_remove("SSR_DENOISED_B");
670}
671
672} // namespace unravel
void tex_remove(const hpp::string_view &id)
void fbo_remove(const hpp::string_view &id)
Manages assets, including loading, unloading, and storage.
auto get_asset(const std::string &key, load_flags flags=load_flags::standard, load_mode mode=load_mode::immediate) -> asset_handle< T >
Gets an asset by its key.
Class representing a camera. Contains functionality for manipulating and updating a camera....
Definition camera.h:62
auto run_ssr_trace(gfx::render_view &rview, const run_params &params) -> gfx::frame_buffer::ptr
Executes the SSR trace pass only. Returns SSR current frame buffer.
Definition ssr_pass.cpp:413
auto generate_blurred_color_buffer(gfx::render_view &rview, const gfx::texture::ptr &input_color, const gfx::frame_buffer::ptr &g_buffer, const fidelityfx_ssr_settings &settings) -> gfx::texture::ptr
Generates blurred color buffer with mip chain for cone tracing.
Definition ssr_pass.cpp:204
auto run_fidelityfx(gfx::render_view &rview, const run_params &params) -> gfx::frame_buffer::ptr
Executes the FidelityFX SSR pass. Returns the actual output framebuffer.
Definition ssr_pass.cpp:197
auto run_fidelityfx_three_pass(gfx::render_view &rview, const run_params &params) -> gfx::frame_buffer::ptr
Executes the three-pass SSR pipeline (trace, temporal resolve, composite)
Definition ssr_pass.cpp:372
auto run_composite(gfx::render_view &rview, const gfx::frame_buffer::ptr &ssr_history, const gfx::frame_buffer::ptr &ssr_curr, const gfx::frame_buffer::ptr &probe_buffer, const gfx::frame_buffer::ptr &g_buffer, const gfx::frame_buffer::ptr &output) -> gfx::frame_buffer::ptr
Executes the composite pass. Returns final blended output.
Definition ssr_pass.cpp:610
auto init(rtti::context &ctx) -> bool
Must be called once (after bgfx::init() and after asset_manager is registered in context).
Definition ssr_pass.cpp:12
auto run(gfx::render_view &rview, const run_params &params) -> gfx::frame_buffer::ptr
Executes the SSR pass. Returns the actual output framebuffer.
Definition ssr_pass.cpp:185
auto run_spatial_denoise(gfx::render_view &rview, const gfx::frame_buffer::ptr &ssr_curr, const gfx::frame_buffer::ptr &g_buffer, const fidelityfx_ssr_settings &settings) -> gfx::frame_buffer::ptr
Executes spatial denoise on SSR result before temporal resolve.
Definition ssr_pass.cpp:315
auto run_temporal_resolve(gfx::render_view &rview, const gfx::frame_buffer::ptr &ssr_curr, const gfx::frame_buffer::ptr &g_buffer, const camera *cam, const fidelityfx_ssr_settings &settings) -> gfx::frame_buffer::ptr
Executes the temporal resolve pass. Returns updated SSR history buffer.
Definition ssr_pass.cpp:518
void release_resources(gfx::render_view &rview)
Releases all GPU resources owned by this pass from the render_view.
Definition ssr_pass.cpp:656
std::string name
Definition hub.cpp:33
void dispatch(view_id _id, program_handle _handle, uint32_t _numX, uint32_t _numY, uint32_t _numZ)
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
auto clip_fullscreen_triangle(float depth, float width, float height) -> uint64_t
auto needs_recreate(const gfx::frame_buffer::ptr &fbo, const usize32_t &size) -> bool
void blit(view_id _id, texture_handle _dst, uint16_t _dstX, uint16_t _dstY, texture_handle _src, uint16_t _srcX, uint16_t _srcY, uint16_t _width, uint16_t _height)
void discard(uint8_t _flags)
void set_image(uint8_t _stage, texture_handle _handle, uint8_t _mip, access _access, texture_format _format)
void set_uniform(uniform_handle _handle, const void *_value, uint16_t _num)
Definition graphics.cpp:977
uint32_t get_render_frame()
auto clip_quad(float depth, float width, float height) -> uint64_t
void set_texture(uint8_t _stage, uniform_handle _sampler, texture_handle _handle, uint32_t _flags)
auto compute_trace_size(const usize32_t &ref, trace_resolution res) -> usize32_t
Computes the trace-target size from a full-resolution reference, clamped to 1x1 min.
#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
static void pop_scope()
void set_view_proj(const float *v, const float *p)
gfx::view_id id
static void push_scope(const char *name)
void bind(const frame_buffer *fb=nullptr) const