This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/draw/intern/shaders/draw_command_generate_comp.glsl
Miguel Pozo b44a8f6749 Fix: Draw: Negative scaled objects cause wrong resource indexing
In the new Draw Manager, when the same DrawGroup has both front and back facing instances, the front facing instances don't offset their indices accordingly.

Differential Revision: https://developer.blender.org/D17069
2023-01-23 16:42:37 +01:00

124 lines
4.0 KiB
GLSL

/**
* Convert DrawPrototype into draw commands.
*/
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#define atomicAddAndGet(dst, val) (atomicAdd(dst, val) + val)
/* This is only called by the last thread executed over the group's prototype draws. */
void write_draw_call(DrawGroup group, uint group_id)
{
DrawCommand cmd;
cmd.vertex_len = group.vertex_len;
cmd.vertex_first = group.vertex_first;
bool indexed_draw = group.base_index != -1;
if (indexed_draw) {
cmd.base_index = group.base_index;
cmd.instance_first_indexed = group.start;
}
else {
cmd._instance_first_array = group.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);
if (indexed_draw) {
cmd.instance_first_indexed = front_facing_start;
}
else {
cmd._instance_first_array = front_facing_start;
}
cmd.instance_len = group_buf[group_id].front_facing_counter;
command_buf[group_id * 2 + 1] = cmd;
/* Reset the counters for a next command gen dispatch. Avoids resending the whole data just
* for this purpose. Only the last thread will execute this so it is thread-safe. */
group_buf[group_id].front_facing_counter = 0u;
group_buf[group_id].back_facing_counter = 0u;
group_buf[group_id].total_counter = 0u;
}
void main()
{
uint proto_id = gl_GlobalInvocationID.x;
if (proto_id >= prototype_len) {
return;
}
DrawPrototype proto = prototype_buf[proto_id];
uint group_id = proto.group_id;
bool is_inverted = (proto.resource_handle & 0x80000000u) != 0;
uint resource_index = (proto.resource_handle & 0x7FFFFFFFu);
/* Visibility test result. */
uint visible_instance_len = 0;
if (visibility_word_per_draw > 0) {
uint visibility_word = resource_index * visibility_word_per_draw;
for (uint i = 0; i < visibility_word_per_draw; i++, visibility_word++) {
/* NOTE: This assumes `proto.instance_len` is 1. */
/* TODO: Assert. */
visible_instance_len += bitCount(visibility_buf[visibility_word]);
}
}
else {
if ((visibility_buf[resource_index / 32u] & (1u << (resource_index % 32u))) != 0) {
visible_instance_len = proto.instance_len;
}
}
bool is_visible = visible_instance_len > 0;
DrawGroup group = group_buf[group_id];
if (!is_visible) {
/* Skip the draw but still count towards the completion. */
if (atomicAddAndGet(group_buf[group_id].total_counter, proto.instance_len) == group.len) {
write_draw_call(group, group_id);
}
return;
}
uint back_facing_len = group.len - group.front_facing_len;
uint front_facing_len = group.front_facing_len;
uint dst_index = group.start;
if (is_inverted) {
uint offset = atomicAdd(group_buf[group_id].back_facing_counter, visible_instance_len);
dst_index += offset;
if (atomicAddAndGet(group_buf[group_id].total_counter, proto.instance_len) == group.len) {
write_draw_call(group, group_id);
}
}
else {
uint offset = atomicAdd(group_buf[group_id].front_facing_counter, visible_instance_len);
dst_index += back_facing_len + offset;
if (atomicAddAndGet(group_buf[group_id].total_counter, proto.instance_len) == group.len) {
write_draw_call(group, group_id);
}
}
/* Fill resource_id buffer for each instance of this draw. */
if (visibility_word_per_draw > 0) {
uint visibility_word = resource_index * visibility_word_per_draw;
for (uint i = 0; i < visibility_word_per_draw; i++, visibility_word++) {
uint word = visibility_buf[visibility_word];
uint view_index = i * 32u;
while (word != 0u) {
if ((word & 1u) != 0u) {
resource_id_buf[dst_index++] = view_index | (resource_index << view_shift);
}
view_index++;
word >>= 1u;
}
}
}
else {
for (uint i = dst_index; i < dst_index + visible_instance_len; i++) {
resource_id_buf[i] = resource_index;
}
}
}