This implements the base needed for supporting multiple view concurently inside the same drawcall. The view used by common macros and view related functions is indexed using a global variable `drw_view_id` which can be set arbitrarly or read from the `drw_ResourceID`. This is needed for EEVEE-Next shadow but can be used for other purpose in the future. Note that a shader specialization is needed for it to work. `DRW_VIEW_LEN` needs to be defined to the amount of view the shader will access. The number of views contained in a `draw::View` is set at construction time. Note that the maximum number of object correctly drawn by the shaders using multiple views will be lower than thoses who don't.
113 lines
3.6 KiB
GLSL
113 lines
3.6 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;
|
|
if (group.base_index != -1) {
|
|
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. */
|
|
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++) {
|
|
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;
|
|
}
|
|
}
|
|
}
|