summaryrefslogtreecommitdiff
path: root/servers/rendering/renderer_rd/shaders/cluster_store.glsl
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/renderer_rd/shaders/cluster_store.glsl')
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_store.glsl119
1 files changed, 119 insertions, 0 deletions
diff --git a/servers/rendering/renderer_rd/shaders/cluster_store.glsl b/servers/rendering/renderer_rd/shaders/cluster_store.glsl
new file mode 100644
index 0000000000..5be0893c4f
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cluster_store.glsl
@@ -0,0 +1,119 @@
+#[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+layout(push_constant, binding = 0, std430) uniform Params {
+ uint cluster_render_data_size; // how much data for a single cluster takes
+ uint max_render_element_count_div_32; //divided by 32
+ uvec2 cluster_screen_size;
+ uint render_element_count_div_32; //divided by 32
+
+ uint max_cluster_element_count_div_32; //divided by 32
+ uint pad1;
+ uint pad2;
+}
+params;
+
+layout(set = 0, binding = 1, std430) buffer restrict readonly ClusterRender {
+ uint data[];
+}
+cluster_render;
+
+layout(set = 0, binding = 2, std430) buffer restrict ClusterStore {
+ uint data[];
+}
+cluster_store;
+
+struct RenderElement {
+ uint type; //0-4
+ bool touches_near;
+ bool touches_far;
+ uint original_index;
+ mat3x4 transform_inv;
+ vec3 scale;
+ uint pad;
+};
+
+layout(set = 0, binding = 3, std430) buffer restrict readonly RenderElements {
+ RenderElement data[];
+}
+render_elements;
+
+void main() {
+ uvec2 pos = gl_GlobalInvocationID.xy;
+ if (any(greaterThanEqual(pos, params.cluster_screen_size))) {
+ return;
+ }
+
+ //counter for each type of render_element
+
+ //base offset for this cluster
+ uint base_offset = (pos.x + params.cluster_screen_size.x * pos.y);
+ uint src_offset = base_offset * params.cluster_render_data_size;
+
+ uint render_element_offset = 0;
+
+ //check all render_elements and see which one was written to
+ while (render_element_offset < params.render_element_count_div_32) {
+ uint bits = cluster_render.data[src_offset + render_element_offset];
+ while (bits != 0) {
+ //if bits exist, check the render_element
+ uint index_bit = findLSB(bits);
+ uint index = render_element_offset * 32 + index_bit;
+ uint type = render_elements.data[index].type;
+
+ uint z_range_offset = src_offset + params.max_render_element_count_div_32 + index;
+ uint z_range = cluster_render.data[z_range_offset];
+
+ //if object was written, z was written, but check just in case
+ if (z_range != 0) { //should always be > 0
+
+ uint from_z = findLSB(z_range);
+ uint to_z = findMSB(z_range) + 1;
+
+ if (render_elements.data[index].touches_near) {
+ from_z = 0;
+ }
+
+ if (render_elements.data[index].touches_far) {
+ to_z = 32;
+ }
+
+ // find cluster offset in the buffer used for indexing in the renderer
+ uint dst_offset = (base_offset + type * (params.cluster_screen_size.x * params.cluster_screen_size.y)) * (params.max_cluster_element_count_div_32 + 32);
+
+ uint orig_index = render_elements.data[index].original_index;
+ //store this index in the Z slices by setting the relevant bit
+ for (uint i = from_z; i < to_z; i++) {
+ uint slice_ofs = dst_offset + params.max_cluster_element_count_div_32 + i;
+
+ uint minmax = cluster_store.data[slice_ofs];
+
+ if (minmax == 0) {
+ minmax = 0xFFFF; //min 0, max 0xFFFF
+ }
+
+ uint elem_min = min(orig_index, minmax & 0xFFFF);
+ uint elem_max = max(orig_index + 1, minmax >> 16); //always store plus one, so zero means range is empty when not written to
+
+ minmax = elem_min | (elem_max << 16);
+ cluster_store.data[slice_ofs] = minmax;
+ }
+
+ uint store_word = orig_index >> 5;
+ uint store_bit = orig_index & 0x1F;
+
+ //store the actual render_element index at the end, so the rendering code can reference it
+ cluster_store.data[dst_offset + store_word] |= 1 << store_bit;
+ }
+
+ bits &= ~(1 << index_bit); //clear the bit to continue iterating
+ }
+
+ render_element_offset++;
+ }
+}