Files
test2/source/blender/draw/engines/eevee/eevee_raytrace.cc
Clément Foucault 9a9fec7f03 EEVEE: Only request raytracing shader specialization if needed
This improves opengl startup time with default settings
or when rendering with raytracing turned off.

Fix #139188

Pull Request: https://projects.blender.org/blender/blender/pulls/139201
2025-05-21 15:57:00 +02:00

725 lines
31 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup eevee
*
* The ray-tracing module class handles ray generation, scheduling, tracing and denoising.
*/
#include "GPU_debug.hh"
#include "eevee_instance.hh"
#include "eevee_raytrace.hh"
namespace blender::eevee {
/* -------------------------------------------------------------------- */
/** \name Raytracing
*
* \{ */
void RayTraceModule::init()
{
const SceneEEVEE &sce_eevee = inst_.scene->eevee;
ray_tracing_options_ = sce_eevee.ray_tracing_options;
if ((sce_eevee.flag & SCE_EEVEE_FAST_GI_ENABLED) == 0) {
ray_tracing_options_.trace_max_roughness = 1.0f;
}
tracing_method_ = RaytraceEEVEE_Method(sce_eevee.ray_tracing_method);
fast_gi_ray_count_ = sce_eevee.fast_gi_ray_count;
fast_gi_step_count_ = sce_eevee.fast_gi_step_count;
fast_gi_ao_only_ = (sce_eevee.fast_gi_method == FAST_GI_AO_ONLY);
use_raytracing_ = (sce_eevee.flag & SCE_EEVEE_SSR_ENABLED) != 0;
float4 data(0.0f);
radiance_dummy_black_tx_.ensure_2d(
RAYTRACE_RADIANCE_FORMAT, int2(1), GPU_TEXTURE_USAGE_SHADER_READ, data);
}
void RayTraceModule::sync()
{
Texture &depth_tx = inst_.render_buffers.depth_tx;
if (!use_raytracing_) {
/* Do not request raytracing shaders if not needed. */
return;
}
#define PASS_VARIATION(_pass_name, _index, _suffix) \
((_index == 0) ? _pass_name##reflect##_suffix : \
(_index == 1) ? _pass_name##refract##_suffix : \
_pass_name##diffuse##_suffix)
/* Setup. */
{
PassSimple &pass = tile_classify_ps_;
pass.init();
pass.shader_set(inst_.shaders.static_shader_get(RAY_TILE_CLASSIFY));
pass.bind_image("tile_raytrace_denoise_img", &tile_raytrace_denoise_tx_);
pass.bind_image("tile_raytrace_tracing_img", &tile_raytrace_tracing_tx_);
pass.bind_image("tile_horizon_denoise_img", &tile_horizon_denoise_tx_);
pass.bind_image("tile_horizon_tracing_img", &tile_horizon_tracing_tx_);
pass.bind_resources(inst_.uniform_data);
pass.bind_resources(inst_.gbuffer);
pass.dispatch(&tile_classify_dispatch_size_);
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS | GPU_BARRIER_SHADER_STORAGE);
}
{
PassSimple &pass = tile_compact_ps_;
GPUShader *sh = inst_.shaders.static_shader_get(RAY_TILE_COMPACT);
pass.init();
pass.specialize_constant(sh, "closure_index", &data_.closure_index);
pass.specialize_constant(sh, "resolution_scale", &data_.resolution_scale);
pass.shader_set(sh);
pass.bind_image("tile_raytrace_denoise_img", &tile_raytrace_denoise_tx_);
pass.bind_image("tile_raytrace_tracing_img", &tile_raytrace_tracing_tx_);
pass.bind_ssbo("raytrace_tracing_dispatch_buf", &raytrace_tracing_dispatch_buf_);
pass.bind_ssbo("raytrace_denoise_dispatch_buf", &raytrace_denoise_dispatch_buf_);
pass.bind_ssbo("raytrace_tracing_tiles_buf", &raytrace_tracing_tiles_buf_);
pass.bind_ssbo("raytrace_denoise_tiles_buf", &raytrace_denoise_tiles_buf_);
pass.bind_resources(inst_.uniform_data);
pass.dispatch(&tile_compact_dispatch_size_);
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
}
{
PassSimple &pass = generate_ps_;
pass.init();
GPUShader *sh = inst_.shaders.static_shader_get(RAY_GENERATE);
pass.specialize_constant(sh, "closure_index", &data_.closure_index);
pass.shader_set(sh);
pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
pass.bind_image("out_ray_data_img", &ray_data_tx_);
pass.bind_ssbo("tiles_coord_buf", &raytrace_tracing_tiles_buf_);
pass.bind_resources(inst_.uniform_data);
pass.bind_resources(inst_.sampling);
pass.bind_resources(inst_.gbuffer);
pass.dispatch(raytrace_tracing_dispatch_buf_);
pass.barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_TEXTURE_FETCH |
GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
/* Tracing. */
{
PassSimple &pass = trace_planar_ps_;
pass.init();
GPUShader *sh = inst_.shaders.static_shader_get(RAY_TRACE_PLANAR);
pass.specialize_constant(sh, "closure_index", &data_.closure_index);
pass.shader_set(sh);
pass.bind_ssbo("tiles_coord_buf", &raytrace_tracing_tiles_buf_);
pass.bind_image("ray_data_img", &ray_data_tx_);
pass.bind_image("ray_time_img", &ray_time_tx_);
pass.bind_image("ray_radiance_img", &ray_radiance_tx_);
pass.bind_texture("depth_tx", &depth_tx);
pass.bind_resources(inst_.uniform_data);
pass.bind_resources(inst_.sampling);
pass.bind_resources(inst_.planar_probes);
pass.bind_resources(inst_.volume_probes);
pass.bind_resources(inst_.sphere_probes);
pass.bind_resources(inst_.gbuffer);
/* TODO(@fclem): Use another dispatch with only tiles that touches planar captures. */
pass.dispatch(raytrace_tracing_dispatch_buf_);
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
{
PassSimple &pass = trace_screen_ps_;
pass.init();
GPUShader *sh = inst_.shaders.static_shader_get(RAY_TRACE_SCREEN);
pass.specialize_constant(
sh, "trace_refraction", reinterpret_cast<bool *>(&data_.trace_refraction));
pass.specialize_constant(sh, "closure_index", &data_.closure_index);
pass.shader_set(sh);
pass.bind_ssbo("tiles_coord_buf", &raytrace_tracing_tiles_buf_);
pass.bind_image("ray_data_img", &ray_data_tx_);
pass.bind_image("ray_time_img", &ray_time_tx_);
pass.bind_texture("radiance_front_tx", &screen_radiance_front_tx_);
pass.bind_texture("radiance_back_tx", &screen_radiance_back_tx_);
pass.bind_texture("hiz_front_tx", &inst_.hiz_buffer.front.ref_tx_);
pass.bind_texture("hiz_back_tx", &inst_.hiz_buffer.back.ref_tx_);
/* Still bind front to hiz_tx for validation layers. */
pass.bind_resources(inst_.hiz_buffer.front);
pass.bind_texture("depth_tx", &depth_tx);
pass.bind_image("ray_radiance_img", &ray_radiance_tx_);
pass.bind_resources(inst_.uniform_data);
pass.bind_resources(inst_.sampling);
pass.bind_resources(inst_.volume_probes);
pass.bind_resources(inst_.sphere_probes);
pass.bind_resources(inst_.gbuffer);
pass.dispatch(raytrace_tracing_dispatch_buf_);
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
{
PassSimple &pass = trace_fallback_ps_;
pass.init();
GPUShader *sh = inst_.shaders.static_shader_get(RAY_TRACE_FALLBACK);
pass.specialize_constant(sh, "closure_index", &data_.closure_index);
pass.shader_set(sh);
pass.bind_ssbo("tiles_coord_buf", &raytrace_tracing_tiles_buf_);
pass.bind_image("ray_data_img", &ray_data_tx_);
pass.bind_image("ray_time_img", &ray_time_tx_);
pass.bind_image("ray_radiance_img", &ray_radiance_tx_);
pass.bind_texture("depth_tx", &depth_tx);
pass.bind_resources(inst_.uniform_data);
pass.bind_resources(inst_.volume_probes);
pass.bind_resources(inst_.sphere_probes);
pass.bind_resources(inst_.sampling);
pass.bind_resources(inst_.gbuffer);
pass.dispatch(raytrace_tracing_dispatch_buf_);
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
/* Denoise. */
{
PassSimple &pass = denoise_spatial_ps_;
GPUShader *sh = inst_.shaders.static_shader_get(RAY_DENOISE_SPATIAL);
pass.init();
pass.specialize_constant(sh, "closure_index", &data_.closure_index);
pass.specialize_constant(sh, "raytrace_resolution_scale", &data_.resolution_scale);
pass.specialize_constant(sh, "skip_denoise", reinterpret_cast<bool *>(&data_.skip_denoise));
pass.shader_set(sh);
pass.bind_ssbo("tiles_coord_buf", &raytrace_denoise_tiles_buf_);
pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
pass.bind_texture("depth_tx", &depth_tx);
pass.bind_image("ray_data_img", &ray_data_tx_);
pass.bind_image("ray_time_img", &ray_time_tx_);
pass.bind_image("ray_radiance_img", &ray_radiance_tx_);
pass.bind_image("out_radiance_img", &denoised_spatial_tx_);
pass.bind_image("out_variance_img", &hit_variance_tx_);
pass.bind_image("out_hit_depth_img", &hit_depth_tx_);
pass.bind_image("tile_mask_img", &tile_raytrace_denoise_tx_);
pass.bind_resources(inst_.uniform_data);
pass.bind_resources(inst_.sampling);
pass.bind_resources(inst_.gbuffer);
pass.dispatch(raytrace_denoise_dispatch_buf_);
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
{
PassSimple &pass = denoise_temporal_ps_;
GPUShader *sh = inst_.shaders.static_shader_get(RAY_DENOISE_TEMPORAL);
pass.init();
pass.specialize_constant(sh, "closure_index", &data_.closure_index);
pass.shader_set(sh);
pass.bind_resources(inst_.uniform_data);
pass.bind_texture("radiance_history_tx", &radiance_history_tx_);
pass.bind_texture("variance_history_tx", &variance_history_tx_);
pass.bind_texture("tilemask_history_tx", &tilemask_history_tx_);
pass.bind_texture("depth_tx", &depth_tx);
pass.bind_image("hit_depth_img", &hit_depth_tx_);
pass.bind_image("in_radiance_img", &denoised_spatial_tx_);
pass.bind_image("out_radiance_img", &denoised_temporal_tx_);
pass.bind_image("in_variance_img", &hit_variance_tx_);
pass.bind_image("out_variance_img", &denoise_variance_tx_);
pass.bind_ssbo("tiles_coord_buf", &raytrace_denoise_tiles_buf_);
pass.bind_resources(inst_.sampling);
pass.dispatch(raytrace_denoise_dispatch_buf_);
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
{
PassSimple &pass = denoise_bilateral_ps_;
pass.init();
GPUShader *sh = inst_.shaders.static_shader_get(RAY_DENOISE_BILATERAL);
pass.specialize_constant(sh, "closure_index", &data_.closure_index);
pass.shader_set(sh);
pass.bind_texture("depth_tx", &depth_tx);
pass.bind_image("in_radiance_img", &denoised_temporal_tx_);
pass.bind_image("out_radiance_img", &denoised_bilateral_tx_);
pass.bind_image("in_variance_img", &denoise_variance_tx_);
pass.bind_image("tile_mask_img", &tile_raytrace_denoise_tx_);
pass.bind_ssbo("tiles_coord_buf", &raytrace_denoise_tiles_buf_);
pass.bind_resources(inst_.uniform_data);
pass.bind_resources(inst_.sampling);
pass.bind_resources(inst_.gbuffer);
pass.dispatch(raytrace_denoise_dispatch_buf_);
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
{
PassSimple &pass = horizon_schedule_ps_;
/* Reuse tile compaction shader but feed it with horizon scan specific buffers. */
GPUShader *sh = inst_.shaders.static_shader_get(RAY_TILE_COMPACT);
pass.init();
pass.specialize_constant(sh, "closure_index", 0);
pass.specialize_constant(sh, "resolution_scale", &data_.horizon_resolution_scale);
pass.shader_set(sh);
pass.bind_image("tile_raytrace_denoise_img", &tile_horizon_denoise_tx_);
pass.bind_image("tile_raytrace_tracing_img", &tile_horizon_tracing_tx_);
pass.bind_ssbo("raytrace_tracing_dispatch_buf", &horizon_tracing_dispatch_buf_);
pass.bind_ssbo("raytrace_denoise_dispatch_buf", &horizon_denoise_dispatch_buf_);
pass.bind_ssbo("raytrace_tracing_tiles_buf", &horizon_tracing_tiles_buf_);
pass.bind_ssbo("raytrace_denoise_tiles_buf", &horizon_denoise_tiles_buf_);
pass.bind_resources(inst_.uniform_data);
pass.dispatch(&horizon_schedule_dispatch_size_);
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
}
{
PassSimple &pass = horizon_setup_ps_;
pass.init();
pass.shader_set(inst_.shaders.static_shader_get(HORIZON_SETUP));
pass.bind_resources(inst_.uniform_data);
pass.bind_texture("depth_tx", &depth_tx);
pass.bind_texture(
"in_radiance_tx", &screen_radiance_front_tx_, GPUSamplerState::default_sampler());
pass.bind_image("out_radiance_img", &downsampled_in_radiance_tx_);
pass.bind_image("out_normal_img", &downsampled_in_normal_tx_);
pass.bind_resources(inst_.uniform_data);
pass.bind_resources(inst_.gbuffer);
pass.dispatch(&horizon_tracing_dispatch_size_);
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
{
PassSimple &pass = horizon_scan_ps_;
pass.init();
GPUShader *sh = inst_.shaders.static_shader_get(HORIZON_SCAN);
pass.specialize_constant(sh, "fast_gi_slice_count", fast_gi_ray_count_);
pass.specialize_constant(sh, "fast_gi_step_count", fast_gi_step_count_);
pass.specialize_constant(sh, "fast_gi_ao_only", fast_gi_ao_only_);
pass.shader_set(sh);
pass.bind_texture("screen_radiance_tx", &downsampled_in_radiance_tx_);
pass.bind_texture("screen_normal_tx", &downsampled_in_normal_tx_);
pass.bind_image("horizon_radiance_0_img", &horizon_radiance_tx_[0]);
pass.bind_image("horizon_radiance_1_img", &horizon_radiance_tx_[1]);
pass.bind_image("horizon_radiance_2_img", &horizon_radiance_tx_[2]);
pass.bind_image("horizon_radiance_3_img", &horizon_radiance_tx_[3]);
pass.bind_ssbo("tiles_coord_buf", &horizon_tracing_tiles_buf_);
pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
pass.bind_resources(inst_.uniform_data);
pass.bind_resources(inst_.hiz_buffer.front);
pass.bind_resources(inst_.sampling);
pass.bind_resources(inst_.gbuffer);
pass.dispatch(horizon_tracing_dispatch_buf_);
pass.barrier(GPU_BARRIER_TEXTURE_FETCH);
}
{
PassSimple &pass = horizon_denoise_ps_;
pass.init();
GPUShader *sh = inst_.shaders.static_shader_get(HORIZON_DENOISE);
pass.shader_set(sh);
pass.bind_texture("in_sh_0_tx", &horizon_radiance_tx_[0]);
pass.bind_texture("in_sh_1_tx", &horizon_radiance_tx_[1]);
pass.bind_texture("in_sh_2_tx", &horizon_radiance_tx_[2]);
pass.bind_texture("in_sh_3_tx", &horizon_radiance_tx_[3]);
pass.bind_texture("screen_normal_tx", &downsampled_in_normal_tx_);
pass.bind_image("out_sh_0_img", &horizon_radiance_denoised_tx_[0]);
pass.bind_image("out_sh_1_img", &horizon_radiance_denoised_tx_[1]);
pass.bind_image("out_sh_2_img", &horizon_radiance_denoised_tx_[2]);
pass.bind_image("out_sh_3_img", &horizon_radiance_denoised_tx_[3]);
pass.bind_ssbo("tiles_coord_buf", &horizon_tracing_tiles_buf_);
pass.bind_resources(inst_.uniform_data);
pass.bind_resources(inst_.sampling);
pass.bind_resources(inst_.hiz_buffer.front);
pass.dispatch(horizon_tracing_dispatch_buf_);
pass.barrier(GPU_BARRIER_TEXTURE_FETCH);
}
{
PassSimple &pass = horizon_resolve_ps_;
pass.init();
GPUShader *sh = inst_.shaders.static_shader_get(HORIZON_RESOLVE);
pass.shader_set(sh);
pass.bind_texture("depth_tx", &depth_tx);
pass.bind_texture("horizon_radiance_0_tx", &horizon_radiance_denoised_tx_[0]);
pass.bind_texture("horizon_radiance_1_tx", &horizon_radiance_denoised_tx_[1]);
pass.bind_texture("horizon_radiance_2_tx", &horizon_radiance_denoised_tx_[2]);
pass.bind_texture("horizon_radiance_3_tx", &horizon_radiance_denoised_tx_[3]);
pass.bind_texture("screen_normal_tx", &downsampled_in_normal_tx_);
pass.bind_image("closure0_img", &horizon_scan_output_tx_[0]);
pass.bind_image("closure1_img", &horizon_scan_output_tx_[1]);
pass.bind_image("closure2_img", &horizon_scan_output_tx_[2]);
pass.bind_ssbo("tiles_coord_buf", &horizon_denoise_tiles_buf_);
pass.bind_resources(inst_.uniform_data);
pass.bind_resources(inst_.sampling);
pass.bind_resources(inst_.gbuffer);
pass.bind_resources(inst_.volume_probes);
pass.bind_resources(inst_.sphere_probes);
pass.dispatch(horizon_denoise_dispatch_buf_);
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
for (int i : IndexRange(3)) {
const bool use_denoise = (ray_tracing_options_.flag & RAYTRACE_EEVEE_USE_DENOISE);
const bool use_spatial_denoise = (ray_tracing_options_.denoise_stages &
RAYTRACE_EEVEE_DENOISE_SPATIAL) &&
use_denoise;
const bool use_temporal_denoise = (ray_tracing_options_.denoise_stages &
RAYTRACE_EEVEE_DENOISE_TEMPORAL) &&
use_spatial_denoise;
const bool use_bilateral_denoise = (ray_tracing_options_.denoise_stages &
RAYTRACE_EEVEE_DENOISE_BILATERAL) &&
use_temporal_denoise;
data_.closure_index = i;
inst_.manager->warm_shader_specialization(tile_classify_ps_);
inst_.manager->warm_shader_specialization(tile_compact_ps_);
inst_.manager->warm_shader_specialization(generate_ps_);
if (tracing_method_ == RAYTRACE_EEVEE_METHOD_SCREEN) {
if (inst_.planar_probes.enabled()) {
inst_.manager->warm_shader_specialization(trace_planar_ps_);
}
for (int j : IndexRange(2)) {
data_.trace_refraction = bool(j);
inst_.manager->warm_shader_specialization(trace_screen_ps_);
}
}
else {
inst_.manager->warm_shader_specialization(trace_fallback_ps_);
}
if (use_spatial_denoise) {
inst_.manager->warm_shader_specialization(denoise_spatial_ps_);
}
if (use_temporal_denoise) {
inst_.manager->warm_shader_specialization(denoise_temporal_ps_);
}
if (use_bilateral_denoise) {
inst_.manager->warm_shader_specialization(denoise_bilateral_ps_);
}
bool use_horizon_scan = ray_tracing_options_.trace_max_roughness < 1.0f;
if (use_horizon_scan) {
inst_.manager->warm_shader_specialization(horizon_schedule_ps_);
inst_.manager->warm_shader_specialization(horizon_setup_ps_);
inst_.manager->warm_shader_specialization(horizon_scan_ps_);
inst_.manager->warm_shader_specialization(horizon_denoise_ps_);
inst_.manager->warm_shader_specialization(horizon_resolve_ps_);
}
}
}
void RayTraceModule::debug_pass_sync() {}
void RayTraceModule::debug_draw(View & /*view*/, GPUFrameBuffer * /*view_fb*/) {}
RayTraceResult RayTraceModule::render(RayTraceBuffer &rt_buffer,
GPUTexture *screen_radiance_back_tx,
eClosureBits active_closures,
/* TODO(fclem): Maybe wrap these two in some other class. */
View &main_view,
View &render_view)
{
using namespace blender::math;
BLI_assert(use_raytracing_);
screen_radiance_front_tx_ = rt_buffer.radiance_feedback_tx.is_valid() ?
rt_buffer.radiance_feedback_tx :
radiance_dummy_black_tx_;
screen_radiance_back_tx_ = screen_radiance_back_tx ? screen_radiance_back_tx :
screen_radiance_front_tx_;
RaytraceEEVEE options = ray_tracing_options_;
bool use_horizon_scan = options.trace_max_roughness < 1.0f;
const int resolution_scale = max_ii(1, power_of_2_max_i(options.resolution_scale));
const int horizon_resolution_scale = max_ii(
1, power_of_2_max_i(inst_.scene->eevee.gtao_resolution));
const int2 extent = inst_.film.render_extent_get();
const int2 tracing_res = math::divide_ceil(extent, int2(resolution_scale));
const int2 tracing_res_horizon = math::divide_ceil(extent, int2(horizon_resolution_scale));
const int2 dummy_extent(1, 1);
const int2 group_size(RAYTRACE_GROUP_SIZE);
const int2 denoise_tiles = divide_ceil(extent, group_size);
const int2 raytrace_tiles = divide_ceil(tracing_res, group_size);
const int2 raytrace_tiles_horizon = divide_ceil(tracing_res_horizon, group_size);
const int denoise_tile_count = denoise_tiles.x * denoise_tiles.y;
const int raytrace_tile_count = raytrace_tiles.x * raytrace_tiles.y;
const int raytrace_tile_count_horizon = raytrace_tiles_horizon.x * raytrace_tiles_horizon.y;
tile_classify_dispatch_size_ = int3(denoise_tiles, 1);
horizon_schedule_dispatch_size_ = int3(divide_ceil(raytrace_tiles_horizon, group_size), 1);
tile_compact_dispatch_size_ = int3(divide_ceil(raytrace_tiles, group_size), 1);
tracing_dispatch_size_ = int3(raytrace_tiles, 1);
horizon_tracing_dispatch_size_ = int3(raytrace_tiles_horizon, 1);
/* TODO(fclem): Use real max closure count from shader. */
const int closure_count = 3;
eGPUTextureFormat format = RAYTRACE_TILEMASK_FORMAT;
eGPUTextureUsage usage_rw = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
tile_raytrace_denoise_tx_.ensure_2d_array(format, denoise_tiles, closure_count, usage_rw);
tile_raytrace_tracing_tx_.ensure_2d_array(format, raytrace_tiles, closure_count, usage_rw);
/* Kept as 2D array for compatibility with the tile compaction shader. */
tile_horizon_denoise_tx_.ensure_2d_array(format, denoise_tiles, 1, usage_rw);
tile_horizon_tracing_tx_.ensure_2d_array(format, raytrace_tiles_horizon, 1, usage_rw);
tile_raytrace_denoise_tx_.clear(uint4(0u));
tile_raytrace_tracing_tx_.clear(uint4(0u));
tile_horizon_denoise_tx_.clear(uint4(0u));
tile_horizon_tracing_tx_.clear(uint4(0u));
horizon_tracing_tiles_buf_.resize(ceil_to_multiple_u(raytrace_tile_count_horizon, 512));
horizon_denoise_tiles_buf_.resize(ceil_to_multiple_u(denoise_tile_count, 512));
raytrace_tracing_tiles_buf_.resize(ceil_to_multiple_u(raytrace_tile_count, 512));
raytrace_denoise_tiles_buf_.resize(ceil_to_multiple_u(denoise_tile_count, 512));
/* Data for tile classification. */
float roughness_mask_start = options.trace_max_roughness;
float roughness_mask_fade = 0.2f;
data_.roughness_mask_scale = 1.0 / roughness_mask_fade;
data_.roughness_mask_bias = data_.roughness_mask_scale * roughness_mask_start;
/* Data for the radiance setup. */
data_.resolution_scale = resolution_scale;
data_.resolution_bias = int2(inst_.sampling.rng_2d_get(SAMPLING_RAYTRACE_V) * resolution_scale);
data_.radiance_persmat = render_view.persmat();
data_.full_resolution = extent;
data_.full_resolution_inv = 1.0f / float2(extent);
data_.horizon_resolution_scale = horizon_resolution_scale;
data_.horizon_resolution_bias = int2(inst_.sampling.rng_2d_get(SAMPLING_RAYTRACE_V) *
horizon_resolution_scale);
/* TODO(fclem): Eventually all uniform data is setup here. */
inst_.uniform_data.push_update();
RayTraceResult result;
GPU_debug_group_begin("Raytracing");
const bool has_active_closure = active_closures != CLOSURE_NONE;
if (has_active_closure) {
inst_.manager->submit(tile_classify_ps_);
}
data_.trace_refraction = screen_radiance_back_tx != nullptr;
for (int i = 0; i < 3; i++) {
result.closures[i] = trace(i, (closure_count > i), options, rt_buffer, main_view, render_view);
}
if (has_active_closure) {
if (use_horizon_scan) {
GPU_debug_group_begin("Horizon Scan");
downsampled_in_radiance_tx_.acquire(tracing_res_horizon, RAYTRACE_RADIANCE_FORMAT, usage_rw);
downsampled_in_normal_tx_.acquire(tracing_res_horizon, GPU_RGB10_A2, usage_rw);
horizon_radiance_tx_[0].acquire(tracing_res_horizon, GPU_RGBA16F, usage_rw);
horizon_radiance_denoised_tx_[0].acquire(tracing_res_horizon, GPU_RGBA16F, usage_rw);
for (int i : IndexRange(1, 3)) {
horizon_radiance_tx_[i].acquire(tracing_res_horizon, GPU_RGBA8, usage_rw);
horizon_radiance_denoised_tx_[i].acquire(tracing_res_horizon, GPU_RGBA8, usage_rw);
}
for (int i : IndexRange(3)) {
horizon_scan_output_tx_[i] = result.closures[i];
}
horizon_tracing_dispatch_buf_.clear_to_zero();
horizon_denoise_dispatch_buf_.clear_to_zero();
inst_.manager->submit(horizon_schedule_ps_);
inst_.manager->submit(horizon_setup_ps_, render_view);
inst_.manager->submit(horizon_scan_ps_, render_view);
inst_.manager->submit(horizon_denoise_ps_, render_view);
inst_.manager->submit(horizon_resolve_ps_, render_view);
for (int i : IndexRange(4)) {
horizon_radiance_tx_[i].release();
horizon_radiance_denoised_tx_[i].release();
}
downsampled_in_radiance_tx_.release();
downsampled_in_normal_tx_.release();
GPU_debug_group_end();
}
}
GPU_debug_group_end();
rt_buffer.history_persmat = render_view.persmat();
return result;
}
RayTraceResultTexture RayTraceModule::trace(
int closure_index,
bool active_layer,
RaytraceEEVEE options,
RayTraceBuffer &rt_buffer,
/* TODO(fclem): Maybe wrap these two in some other class. */
View &main_view,
View &render_view)
{
RayTraceBuffer::DenoiseBuffer *denoise_buf = &rt_buffer.closures[closure_index];
if (!active_layer) {
/* Early out. Release persistent buffers. Still acquire one dummy resource for validation. */
denoise_buf->denoised_spatial_tx.acquire(int2(1), RAYTRACE_RADIANCE_FORMAT);
denoise_buf->radiance_history_tx.free();
denoise_buf->variance_history_tx.free();
denoise_buf->tilemask_history_tx.free();
return {denoise_buf->denoised_spatial_tx};
}
const int resolution_scale = max_ii(1, power_of_2_max_i(options.resolution_scale));
const int2 extent = inst_.film.render_extent_get();
const int2 tracing_res = math::divide_ceil(extent, int2(resolution_scale));
renderbuf_depth_view_ = inst_.render_buffers.depth_tx;
const bool use_denoise = (options.flag & RAYTRACE_EEVEE_USE_DENOISE);
const bool use_spatial_denoise = (options.denoise_stages & RAYTRACE_EEVEE_DENOISE_SPATIAL) &&
use_denoise;
const bool use_temporal_denoise = (options.denoise_stages & RAYTRACE_EEVEE_DENOISE_TEMPORAL) &&
use_spatial_denoise;
const bool use_bilateral_denoise = (options.denoise_stages & RAYTRACE_EEVEE_DENOISE_BILATERAL) &&
use_temporal_denoise;
eGPUTextureUsage usage_rw = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
GPU_debug_group_begin("Raytracing");
data_.thickness = options.screen_trace_thickness;
data_.quality = 1.0f - 0.95f * options.screen_trace_quality;
float roughness_mask_start = options.trace_max_roughness;
float roughness_mask_fade = 0.2f;
data_.roughness_mask_scale = 1.0 / roughness_mask_fade;
data_.roughness_mask_bias = data_.roughness_mask_scale * roughness_mask_start;
data_.resolution_scale = resolution_scale;
data_.resolution_bias = int2(inst_.sampling.rng_2d_get(SAMPLING_RAYTRACE_V) * resolution_scale);
data_.history_persmat = denoise_buf->history_persmat;
data_.radiance_persmat = render_view.persmat();
data_.full_resolution = extent;
data_.full_resolution_inv = 1.0f / float2(extent);
data_.skip_denoise = !use_spatial_denoise;
data_.closure_index = closure_index;
inst_.uniform_data.push_update();
/* Ray setup. */
raytrace_tracing_dispatch_buf_.clear_to_zero();
raytrace_denoise_dispatch_buf_.clear_to_zero();
inst_.manager->submit(tile_compact_ps_);
{
/* Tracing rays. */
ray_data_tx_.acquire(tracing_res, GPU_RGBA16F);
ray_time_tx_.acquire(tracing_res, RAYTRACE_RAYTIME_FORMAT);
ray_radiance_tx_.acquire(tracing_res, RAYTRACE_RADIANCE_FORMAT);
inst_.manager->submit(generate_ps_, render_view);
if (tracing_method_ == RAYTRACE_EEVEE_METHOD_SCREEN) {
if (inst_.planar_probes.enabled()) {
inst_.manager->submit(trace_planar_ps_, render_view);
}
inst_.manager->submit(trace_screen_ps_, render_view);
}
else {
inst_.manager->submit(trace_fallback_ps_, render_view);
}
}
RayTraceResultTexture result;
/* Spatial denoise pass is required to resolve at least one ray per pixel. */
{
denoise_buf->denoised_spatial_tx.acquire(extent, RAYTRACE_RADIANCE_FORMAT);
hit_variance_tx_.acquire(use_temporal_denoise ? extent : int2(1), RAYTRACE_VARIANCE_FORMAT);
hit_depth_tx_.acquire(use_temporal_denoise ? extent : int2(1), GPU_R32F);
denoised_spatial_tx_ = denoise_buf->denoised_spatial_tx;
inst_.manager->submit(denoise_spatial_ps_, render_view);
result = {denoise_buf->denoised_spatial_tx};
}
ray_data_tx_.release();
ray_time_tx_.release();
ray_radiance_tx_.release();
if (use_temporal_denoise) {
denoise_buf->denoised_temporal_tx.acquire(extent, RAYTRACE_RADIANCE_FORMAT, usage_rw);
denoise_variance_tx_.acquire(
use_bilateral_denoise ? extent : int2(1), RAYTRACE_VARIANCE_FORMAT, usage_rw);
denoise_buf->variance_history_tx.ensure_2d(
RAYTRACE_VARIANCE_FORMAT, use_bilateral_denoise ? extent : int2(1), usage_rw);
denoise_buf->tilemask_history_tx.ensure_2d_array(RAYTRACE_TILEMASK_FORMAT,
tile_raytrace_denoise_tx_.size().xy(),
tile_raytrace_denoise_tx_.size().z,
usage_rw);
if (denoise_buf->radiance_history_tx.ensure_2d(RAYTRACE_RADIANCE_FORMAT, extent, usage_rw) ||
denoise_buf->valid_history == false)
{
/* If viewport resolution changes, do not try to use history. */
denoise_buf->tilemask_history_tx.clear(uint4(0u));
}
radiance_history_tx_ = denoise_buf->radiance_history_tx;
variance_history_tx_ = denoise_buf->variance_history_tx;
tilemask_history_tx_ = denoise_buf->tilemask_history_tx;
denoised_temporal_tx_ = denoise_buf->denoised_temporal_tx;
inst_.manager->submit(denoise_temporal_ps_, render_view);
/* Save view-projection matrix for next reprojection. */
denoise_buf->history_persmat = main_view.persmat();
/* Radiance will be swapped with history in #RayTraceResult::release().
* Variance is swapped with history after bilateral denoise.
* It keeps data-flow easier to follow. */
result = {denoise_buf->denoised_temporal_tx, denoise_buf->radiance_history_tx};
/* Not referenced by result anymore. */
denoise_buf->denoised_spatial_tx.release();
GPU_texture_copy(denoise_buf->tilemask_history_tx, tile_raytrace_denoise_tx_);
}
/* Only use history buffer for the next frame if temporal denoise was used by the current one. */
denoise_buf->valid_history = use_temporal_denoise;
hit_variance_tx_.release();
hit_depth_tx_.release();
if (use_bilateral_denoise) {
denoise_buf->denoised_bilateral_tx.acquire(extent, RAYTRACE_RADIANCE_FORMAT, usage_rw);
denoised_bilateral_tx_ = denoise_buf->denoised_bilateral_tx;
inst_.manager->submit(denoise_bilateral_ps_, render_view);
/* Swap after last use. */
TextureFromPool::swap(denoise_buf->denoised_temporal_tx, denoise_buf->radiance_history_tx);
TextureFromPool::swap(denoise_variance_tx_, denoise_buf->variance_history_tx);
result = {denoise_buf->denoised_bilateral_tx};
/* Not referenced by result anymore. */
denoise_buf->denoised_temporal_tx.release();
}
denoise_variance_tx_.release();
GPU_debug_group_end();
return result;
}
RayTraceResult RayTraceModule::alloc_only(RayTraceBuffer &rt_buffer)
{
const int2 extent = inst_.film.render_extent_get();
eGPUTextureUsage usage_rw = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
RayTraceResult result;
for (int i = 0; i < 3; i++) {
RayTraceBuffer::DenoiseBuffer *denoise_buf = &rt_buffer.closures[i];
denoise_buf->denoised_bilateral_tx.acquire(extent, RAYTRACE_RADIANCE_FORMAT, usage_rw);
result.closures[i] = {denoise_buf->denoised_bilateral_tx};
}
return result;
}
RayTraceResult RayTraceModule::alloc_dummy(RayTraceBuffer &rt_buffer)
{
eGPUTextureUsage usage_rw = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
RayTraceResult result;
for (int i = 0; i < 3; i++) {
RayTraceBuffer::DenoiseBuffer *denoise_buf = &rt_buffer.closures[i];
denoise_buf->denoised_bilateral_tx.acquire(int2(1), RAYTRACE_RADIANCE_FORMAT, usage_rw);
result.closures[i] = {denoise_buf->denoised_bilateral_tx};
}
return result;
}
/** \} */
} // namespace blender::eevee