Fix #113759: EEVEE-Next: NaN artifacts caused by raytracing denoising

This was caused by spatial denoising pass sampling invalid data.
This patch make it so that there is one padding tile all
around the denoise area.

This simplifies the denoise shader too.

This is a bit wasteful to dispatch tracing tiles for clearing
and a better solution would be to use a separate shader and
tile list only for this purpose.
This commit is contained in:
Clément Foucault
2023-10-16 15:10:41 +02:00
parent dae06c7562
commit 69e85382cd
2 changed files with 31 additions and 43 deletions

View File

@@ -37,21 +37,6 @@ float bxdf_eval(ClosureReflection closure, vec3 L, vec3 V)
return bsdf_ggx(closure.N, L, V, closure.roughness);
}
void neighbor_tile_mask_bit_set(inout uint tile_mask, ivec2 offset)
{
/* Only valid for a 3x3 neighborhood. */
offset += 1;
uint shift = offset.x + (offset.y << 2u);
tile_mask |= 1u << shift;
}
bool neighbor_tile_mask_bit_get(uint tile_mask, ivec2 offset)
{
offset += 1;
uint shift = offset.x + (offset.y << 2u);
return flag_test(tile_mask, 1u << shift);
}
void main()
{
const uint tile_size = RAYTRACE_GROUP_SIZE;
@@ -65,8 +50,6 @@ void main()
return;
}
/* Store invalid neighbor tiles to avoid sampling them in the resampling loop. */
uint invalid_neighbor_tile_mask = 0u;
/* Clear neighbor tiles that will not be processed. */
/* TODO(fclem): Optimize this. We don't need to clear the whole ring. */
for (int x = -1; x <= 1; x++) {
@@ -77,7 +60,6 @@ void main()
ivec2 tile_coord_neighbor = ivec2(tile_coord) + ivec2(x, y);
if (!in_image_range(tile_coord_neighbor, tile_mask_img)) {
neighbor_tile_mask_bit_set(invalid_neighbor_tile_mask, ivec2(x, y));
continue;
}
@@ -88,8 +70,6 @@ void main()
imageStore(out_radiance_img, texel_fullres_neighbor, vec4(FLT_11_11_10_MAX, 0.0));
imageStore(out_variance_img, texel_fullres_neighbor, vec4(0.0));
imageStore(out_hit_depth_img, texel_fullres_neighbor, vec4(0.0));
neighbor_tile_mask_bit_set(invalid_neighbor_tile_mask, ivec2(x, y));
}
}
}
@@ -150,14 +130,6 @@ void main()
ivec2 offset = ivec2(floor(offset_f + 0.5));
ivec2 sample_texel = texel + offset;
/* Reject samples outside of valid neighbor tiles. */
ivec2 sample_tile = ivec2(sample_texel * uniform_buf.raytrace.resolution_scale) /
int(tile_size);
ivec2 sample_tile_relative = sample_tile - ivec2(tile_coord);
if (neighbor_tile_mask_bit_get(invalid_neighbor_tile_mask, sample_tile_relative)) {
continue;
}
vec4 ray_data = imageLoad(ray_data_img, sample_texel);
float ray_time = imageLoad(ray_time_img, sample_texel).r;
vec4 ray_radiance = imageLoad(ray_radiance_img, sample_texel);

View File

@@ -15,27 +15,43 @@
void main()
{
int resolution_scale = uniform_buf.raytrace.resolution_scale;
ivec2 tile = ivec2(gl_GlobalInvocationID.xy);
bool tracing_tile_is_used = false;
for (int x = 0; x < uniform_buf.raytrace.resolution_scale; x++) {
for (int y = 0; y < uniform_buf.raytrace.resolution_scale; y++) {
ivec2 full_res_tile = tile * uniform_buf.raytrace.resolution_scale + ivec2(x, y);
if (any(greaterThanEqual(full_res_tile, imageSize(tile_mask_img)))) {
continue;
}
bool denoise_tile_is_used = imageLoad(tile_mask_img, full_res_tile).r != 0u;
if (denoise_tile_is_used) {
/* Dispatch full resolution denoise tile. */
uint tile_index = atomicAdd(denoise_dispatch_buf.num_groups_x, 1u);
denoise_tiles_buf[tile_index] = packUvec2x16(uvec2(full_res_tile));
tracing_tile_is_used = true;
/* True if an adjacent tile is tracing and will need this tile data for denoising. */
bool tile_is_sampled = false;
/* True if this tile is shooting and tracing rays. */
bool tile_is_tracing = false;
/* Could be optimized if that becomes an issue. */
for (int x_tile = -1; x_tile <= 1; x_tile++) {
for (int y_tile = -1; y_tile <= 1; y_tile++) {
ivec2 tile_adj = tile + ivec2(x_tile, y_tile);
for (int x = 0; x < resolution_scale; x++) {
for (int y = 0; y < resolution_scale; y++) {
ivec2 full_res_tile = tile_adj * resolution_scale + ivec2(x, y);
if (any(greaterThanEqual(full_res_tile, imageSize(tile_mask_img)))) {
continue;
}
bool denoise_tile_is_used = imageLoad(tile_mask_img, full_res_tile).r != 0u;
if (denoise_tile_is_used) {
if (x_tile == 0 && y_tile == 0) {
/* Dispatch full resolution denoise tile. */
uint tile_index = atomicAdd(denoise_dispatch_buf.num_groups_x, 1u);
denoise_tiles_buf[tile_index] = packUvec2x16(uvec2(full_res_tile));
tile_is_tracing = true;
}
else {
/* This denoise tile will sample the target tracing tile. Make sure it is cleared. */
tile_is_sampled = true;
}
}
}
}
}
}
if (tracing_tile_is_used) {
/* TODO(fclem): we might want to dispatch another type of shader only for clearing. */
if (tile_is_tracing || tile_is_sampled) {
/* Dispatch trace resolution tracing tile. */
uint tile_index = atomicAdd(ray_dispatch_buf.num_groups_x, 1u);
ray_tiles_buf[tile_index] = packUvec2x16(uvec2(tile));