Fix: EEVEE-Next: Shadow: Fix infinite loop in shadow rendering

The render shadow loop would always tag new casters to update
the tiles that were already rendered. This patch split the
caster tagging into it's own pass and move it out of the loop.

Also adds a needed `async_flush_to_host` to make sure the
statistic buffer is up to date.
This commit is contained in:
Clément Foucault
2024-02-02 19:04:45 +01:00
parent 1159da5f36
commit 9e015f703c
2 changed files with 32 additions and 21 deletions

View File

@@ -1008,6 +1008,28 @@ void ShadowModule::end_sync()
{
Manager &manager = *inst_.manager;
{
/* Mark for update all shadow pages touching an updated shadow caster. */
PassSimple &pass = caster_update_ps_;
pass.init();
pass.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_UPDATE));
pass.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
pass.bind_ssbo("tiles_buf", tilemap_pool.tiles_data);
/* Past caster transforms. */
if (past_casters_updated_.size() > 0) {
pass.bind_ssbo("bounds_buf", &manager.bounds_buf.previous());
pass.bind_ssbo("resource_ids_buf", past_casters_updated_);
pass.dispatch(int3(past_casters_updated_.size(), 1, tilemap_pool.tilemaps_data.size()));
}
/* Current caster transforms. */
if (curr_casters_updated_.size() > 0) {
pass.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
pass.bind_ssbo("resource_ids_buf", curr_casters_updated_);
pass.dispatch(int3(curr_casters_updated_.size(), 1, tilemap_pool.tilemaps_data.size()));
}
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
}
{
PassSimple &pass = tilemap_setup_ps_;
pass.init();
@@ -1055,26 +1077,6 @@ void ShadowModule::end_sync()
}
sub.barrier(GPU_BARRIER_SHADER_STORAGE);
}
{
/* Mark for update all shadow pages touching an updated shadow caster. */
PassSimple::Sub &sub = pass.sub("CasterUpdate");
sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_UPDATE));
sub.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
sub.bind_ssbo("tiles_buf", tilemap_pool.tiles_data);
/* Past caster transforms. */
if (past_casters_updated_.size() > 0) {
sub.bind_ssbo("bounds_buf", &manager.bounds_buf.previous());
sub.bind_ssbo("resource_ids_buf", past_casters_updated_);
sub.dispatch(int3(past_casters_updated_.size(), 1, tilemap_pool.tilemaps_data.size()));
}
/* Current caster transforms. */
if (curr_casters_updated_.size() > 0) {
sub.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
sub.bind_ssbo("resource_ids_buf", curr_casters_updated_);
sub.dispatch(int3(curr_casters_updated_.size(), 1, tilemap_pool.tilemaps_data.size()));
}
sub.barrier(GPU_BARRIER_SHADER_STORAGE);
}
}
/* Non volume usage tagging happens between these two steps.
@@ -1275,7 +1277,7 @@ bool ShadowModule::shadow_update_finished()
return true;
}
int max_updated_view_count = tilemap_pool.tilemaps_data.size();
int max_updated_view_count = tilemap_pool.tilemaps_data.size() * SHADOW_TILEMAP_LOD;
if (max_updated_view_count <= SHADOW_VIEW_MAX) {
/* There is enough shadow views to cover all tilemap updates.
* No readback needed as it is guaranteed that all of them will be updated. */
@@ -1283,6 +1285,7 @@ bool ShadowModule::shadow_update_finished()
}
/* Read back and check if there is still tile-map to update. */
statistics_buf_.current().async_flush_to_host();
statistics_buf_.current().read();
ShadowStatistics stats = statistics_buf_.current();
/* Rendering is finished if we rendered all the remaining pages. */
@@ -1335,6 +1338,13 @@ void ShadowModule::set_view(View &view, GPUTexture *depth_tx)
inst_.hiz_buffer.update();
/* Run caster update once and before the update loop.
* This is valid even before the view update since only the static tilemaps
* are concerned about this tagging. */
/* TODO(fclem): There is an optimization opportunity here where we can
* test casters only against the static tilemaps instead of all of them. */
inst_.manager->submit(caster_update_ps_, view);
do {
DRW_stats_group_start("Shadow");
{

View File

@@ -228,6 +228,7 @@ class ShadowModule {
Framebuffer usage_tag_fb;
PassSimple caster_update_ps_ = {"CasterUpdate"};
/** List of Resource IDs (to get bounds) for tagging passes. */
StorageVectorBuffer<uint, 128> past_casters_updated_ = {"PastCastersUpdated"};
StorageVectorBuffer<uint, 128> curr_casters_updated_ = {"CurrCastersUpdated"};