blob: d684fd3602735ba1b821d30ebf7c2e89fcb49853 [file] [edit]
#version 450
#extension GL_EXT_buffer_reference : require
layout(local_size_x = 64) in;
layout(constant_id = 0) const uint c_field_count = 1;
layout(std430, buffer_reference, buffer_reference_align = 8)
buffer writeonly dst_queries_t {
uvec2 queries[];
};
layout(std430, buffer_reference, buffer_reference_align = 8)
readonly buffer src_queries_t {
uvec2 queries[];
};
struct query_map_entry_t {
uint dst_index;
uint src_index;
uint next;
};
layout(std430, buffer_reference, buffer_reference_align = 4)
readonly buffer query_map_t {
query_map_entry_t entries[];
};
layout(push_constant)
uniform u_info_t {
dst_queries_t dst_buffer;
src_queries_t src_buffer;
query_map_t query_map;
uint query_count;
};
uvec2 uadd64(uvec2 a, uvec2 b) {
uint carry;
uint lo = uaddCarry(a.x, b.x, carry);
uint hi = a.y + b.y + carry;
return uvec2(lo, hi);
}
void main() {
uint thread_id = gl_GlobalInvocationID.x;
if (thread_id >= query_count)
return;
// The query map is an array of linked lists, with the
// first query_count entries guaranteed to be list heads
query_map_entry_t entry = query_map.entries[thread_id];
uvec2 dst_data[c_field_count];
// By copying the first query we get the reset for free
for (uint i = 0; i < c_field_count; i++)
dst_data[i] = src_buffer.queries[c_field_count * entry.src_index + i];
// Accumulate data from additional queries
while (entry.next != ~0u) {
entry = query_map.entries[entry.next];
for (uint i = 0; i < c_field_count; i++)
dst_data[i] = uadd64(dst_data[i], src_buffer.queries[c_field_count * entry.src_index + i]);
}
// dst_index has the same value for all entries in the list
for (uint i = 0; i < c_field_count; i++)
dst_buffer.queries[c_field_count * entry.dst_index + i] = dst_data[i];
}