From ac1069805ce33b0aa0a40cfbc80e4118d1424ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 11 Oct 2024 18:09:57 +0200 Subject: [PATCH] Fix: DRW: Broken multiview support with inverted scale object instances If a `DrawGroup` contained both inverted and non-inverted scale the command generate shader would output the `resource_id` content at conflicting indices. This is because the number of instances stored inside the `DrawGroup` are the original count before multiview. Actually, only `start` was taking the multi-view count into account. We cannot modify the value on CPU otherwise it would increase the instance count for each submission. So the fix is to pass the view count to the command generate shader and multiply the instance count where needed. Fix #128085 Pull Request: https://projects.blender.org/blender/blender/pulls/128854 --- source/blender/draw/intern/draw_command.cc | 5 +++-- source/blender/draw/intern/draw_command_shared.hh | 12 ++++++++++-- .../shaders/draw_command_generate_comp.glsl | 15 ++++++++------- .../blender/draw/intern/shaders/draw_view_info.hh | 1 + 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/source/blender/draw/intern/draw_command.cc b/source/blender/draw/intern/draw_command.cc index 06d503d0f2a..7da1a27d484 100644 --- a/source/blender/draw/intern/draw_command.cc +++ b/source/blender/draw/intern/draw_command.cc @@ -777,7 +777,7 @@ void DrawMultiBuf::bind(RecordingState &state, for (DrawGroup &group : MutableSpan(group_buf_.data(), group_count_)) { /* Compute prefix sum of all instance of previous group. */ group.start = resource_id_count_; - resource_id_count_ += group.len * view_len; + resource_id_count_ += group.len; int batch_vert_len, batch_vert_first, batch_base_index, batch_inst_len; /* Now that GPUBatches are guaranteed to be finished, extract their parameters. */ @@ -833,7 +833,7 @@ void DrawMultiBuf::bind(RecordingState &state, group_buf_.push_update(); prototype_buf_.push_update(); /* Allocate enough for the expansion pass. */ - resource_id_buf_.get_or_resize(resource_id_count_ * (use_custom_ids ? 2 : 1)); + resource_id_buf_.get_or_resize(resource_id_count_ * view_len * (use_custom_ids ? 2 : 1)); /* Two commands per group (inverted and non-inverted scale). */ command_buf_.get_or_resize(group_count_ * 2); @@ -842,6 +842,7 @@ void DrawMultiBuf::bind(RecordingState &state, GPU_shader_bind(shader); GPU_shader_uniform_1i(shader, "prototype_len", prototype_count_); GPU_shader_uniform_1i(shader, "visibility_word_per_draw", visibility_word_per_draw); + GPU_shader_uniform_1i(shader, "view_len", view_len); GPU_shader_uniform_1i(shader, "view_shift", log2_ceil_u(view_len)); GPU_shader_uniform_1b(shader, "use_custom_ids", use_custom_ids); GPU_storagebuf_bind(group_buf_, GPU_shader_get_ssbo_binding(shader, "group_buf")); diff --git a/source/blender/draw/intern/draw_command_shared.hh b/source/blender/draw/intern/draw_command_shared.hh index 64bb552bb2b..13f19805320 100644 --- a/source/blender/draw/intern/draw_command_shared.hh +++ b/source/blender/draw/intern/draw_command_shared.hh @@ -26,6 +26,12 @@ struct DrawGroup { /** Index of next #DrawGroup from the same header. */ uint next; + /** + * IMPORTANT: All the following 3 members do not take multi-view into account. + * They only count the number of input instances. The command generation shader must multiply + * them by view_len to get the correct indices for resource ids. + */ + /** Index of the first instances after sorting. */ uint start; /** Total number of instances (including inverted facing). Needed to issue the draw call. */ @@ -39,9 +45,11 @@ struct DrawGroup { /* Set to -1 if not an indexed draw. */ int base_index; - /** Atomic counters used during command sorting. */ - uint total_counter; + /** Atomic counters used during command sorting. GPU only. Reset on CPU. */ + /* Counts visible and invisble instances. Create drawcalls when it reaches `DrawGroup::len`. */ + uint total_counter; + /* Counts only visible instance (counting multi-view). Used to issue the drawcalls. */ uint front_facing_counter; uint back_facing_counter; diff --git a/source/blender/draw/intern/shaders/draw_command_generate_comp.glsl b/source/blender/draw/intern/shaders/draw_command_generate_comp.glsl index 29bc3d4e246..a2194f60d33 100644 --- a/source/blender/draw/intern/shaders/draw_command_generate_comp.glsl +++ b/source/blender/draw/intern/shaders/draw_command_generate_comp.glsl @@ -17,19 +17,21 @@ void write_draw_call(DrawGroup group, uint group_id) cmd.vertex_len = group.vertex_len; cmd.vertex_first = group.vertex_first; bool indexed_draw = group.base_index != -1; + + /* Back-facing command. */ + uint back_facing_start = group.start * view_len; if (indexed_draw) { cmd.base_index = group.base_index; - cmd.instance_first_indexed = group.start; + cmd.instance_first_indexed = back_facing_start; } else { - cmd._instance_first_array = group.start; + cmd._instance_first_array = back_facing_start; } - /* Back-facing command. */ cmd.instance_len = group_buf[group_id].back_facing_counter; command_buf[group_id * 2 + 0] = cmd; /* Front-facing command. */ - uint front_facing_start = group.start + (group.len - group.front_facing_len); + uint front_facing_start = (group.start + (group.len - group.front_facing_len)) * view_len; if (indexed_draw) { cmd.instance_first_indexed = front_facing_start; } @@ -85,9 +87,8 @@ void main() return; } - uint back_facing_len = group.len - group.front_facing_len; - uint front_facing_len = group.front_facing_len; - uint dst_index = group.start; + uint back_facing_len = (group.len - group.front_facing_len) * view_len; + uint dst_index = group.start * view_len; if (is_inverted) { uint offset = atomicAdd(group_buf[group_id].back_facing_counter, visible_instance_len); dst_index += offset; diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh index ac9a5e5c696..018b4bf6e9b 100644 --- a/source/blender/draw/intern/shaders/draw_view_info.hh +++ b/source/blender/draw/intern/shaders/draw_view_info.hh @@ -230,6 +230,7 @@ GPU_SHADER_CREATE_INFO(draw_command_generate) .push_constant(Type::INT, "prototype_len") .push_constant(Type::INT, "visibility_word_per_draw") .push_constant(Type::INT, "view_shift") + .push_constant(Type::INT, "view_len") .push_constant(Type::BOOL, "use_custom_ids") .compute_source("draw_command_generate_comp.glsl");