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
This commit is contained in:
Clément Foucault
2024-10-11 18:09:57 +02:00
committed by Clément Foucault
parent 3764f53b1b
commit ac1069805c
4 changed files with 22 additions and 11 deletions

View File

@@ -777,7 +777,7 @@ void DrawMultiBuf::bind(RecordingState &state,
for (DrawGroup &group : MutableSpan<DrawGroup>(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"));

View File

@@ -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;

View File

@@ -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;

View File

@@ -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");