diff --git a/shaders/compaction.slang b/shaders/compaction.slang new file mode 100644 index 0000000..e0fc62e --- /dev/null +++ b/shaders/compaction.slang @@ -0,0 +1,124 @@ + +[[vk::binding(0, 0)]] +RWStructuredBuffer count_buffer; + +[[vk::binding(0, 1)]] +RWStructuredBuffer reduced_buffer; +[[vk::binding(1, 1)]] +RWStructuredBuffer sum_buffer; +[[vk::binding(2, 1)]] +RWStructuredBuffer compaction_buffer; + +groupshared uint32_t local_data[256 * 2]; +static uint32_t THREAD_WIDTH = 256; +static uint32_t DATA_WIDTH = THREAD_WIDTH * 2; + +[numthreads(256, 1, 1)] +[shader("compute")] +void block_sum( + uint32_t3 workgroup_id: SV_GroupID, + uint32_t3 local_thread_id: SV_GroupThreadID, + uint32_t3 global_thread_id: SV_DispatchThreadID) +{ + // Perform sum in current block + + // Copy local_datainto LDS with predicate + let thread_index = global_thread_id.x; + let local_thread_index = local_thread_id.x; + let total = count_buffer.getCount(); + + if (thread_index * 2 < total) + { + local_data[local_thread_index * 2] = select(count_buffer[thread_index * 2] != 0, 1, 0); + } + else + { + local_data[local_thread_index * 2] = 0; + } + + if (thread_index * 2 + 1 < total) + { + local_data[local_thread_index * 2 + 1] = select(count_buffer[thread_index * 2 + 1] != 0, 1, 0); + } + else + { + local_data[local_thread_index * 2 + 1] = 0; + } + + GroupMemoryBarrierWithGroupSync(); + + var width : uint32_t = 2; + while (width <= DATA_WIDTH) + { + let dest_index = width * (thread_index + 1) - 1; + let get_index = dest_index - (width / 2); + // println!("{}, {}", get_index, dest_index); + if (dest_index < DATA_WIDTH) + { + local_data[dest_index] += local_data[get_index]; + } + width *= 2; + GroupMemoryBarrierWithGroupSync(); + } + + local_data[DATA_WIDTH - 1] = 0; + while (width >= 2) + { + let dest_index = width * (thread_index + 1) - 1; + let get_index = dest_index - (width / 2); + // println!("{}, {}", get_index, dest_index); + if (dest_index < DATA_WIDTH) + { + let self_data = local_data[dest_index]; + local_data[dest_index] += local_data[get_index]; + local_data[get_index] = self_data; + } + width /= 2; + GroupMemoryBarrierWithGroupSync(); + } + + // Block now contains running local sum + // Dump back to sum buffer + sum_buffer[2 * thread_index] = local_data[2 * local_thread_index]; + sum_buffer[2 * thread_index + 1] = local_data[2 * local_thread_index + 1]; + + // Write to reduced buffer + reduced_buffer[workgroup_id.x] = local_data[DATA_WIDTH - 1]; +} + +[numthreads(1, 1, 1)] +[shader("compute")] +void linear_reduced_sum( + uint32_t3 workgroup_id: SV_GroupID, + uint32_t3 local_thread_id: SV_GroupThreadID, + uint32_t3 global_thread_id: SV_DispatchThreadID) +{ + let size = reduced_buffer.getCount(); + + // Perform exclusive sum + var running_sum : uint32_t = 0; + for (uint32_t i = 0; i < size; i++) + { + let value = reduced_buffer[i]; + reduced_buffer[i] = running_sum; + running_sum += value; + } +} + +[numthreads(256, 1, 1)] +[shader("compute")] +void uniform_add( + uint32_t3 workgroup_id: SV_GroupID, + uint32_t3 local_thread_id: SV_GroupThreadID, + uint32_t3 global_thread_id: SV_DispatchThreadID) +{ + let thread_index = global_thread_id.x; + let local_thread_index = local_thread_id.x; + + // Gather + let reduced_value = reduced_buffer[global_thread_id.x]; + // Apply + sum_buffer[thread_index * 2] += reduced_value; + sum_buffer[thread_index * 2 + 1] += reduced_value; +} + diff --git a/shaders/example.slang b/shaders/example.slang new file mode 100644 index 0000000..a191be2 --- /dev/null +++ b/shaders/example.slang @@ -0,0 +1,2 @@ +module example; + diff --git a/src/host_production.rs b/src/host_production.rs new file mode 100644 index 0000000..d385f25 --- /dev/null +++ b/src/host_production.rs @@ -0,0 +1,15 @@ +// Contains useful facilities to render data streamed in from the host + +// Can produce a voxel given +// - Its depth +// - Its position within the chunk +// - The chunks position +pub trait ChunkVoxelProducer +{ + fn produce_voxel( + &mut self, + depth: usize, + chunk_position: (usize, usize, usize), + voxel_position: (usize, usize, usize), + ); +} diff --git a/src/main.rs b/src/main.rs index 06154a8..a0afb0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -182,7 +182,7 @@ impl State let egui_renderer = EguiRenderer::new(&device, surface_format, &window); let mut voxel_cache = VoxelCache::<4>::new(100_000, device.clone(), queue.clone()); - let cache_interface = CacheProducerInterface::new(1024, &device); + let cache_interface = CacheProducerInterface::new(256, &device); let terrain_generator = TerrainGenerator::<4>::new(5, "vxls_height.tif", 0.2, "img.jpg"); // let terrain_generator = TerrainGenerator::<4>::new( diff --git a/src/voxel_cache.rs b/src/voxel_cache.rs index 22d31c5..70e42a7 100644 --- a/src/voxel_cache.rs +++ b/src/voxel_cache.rs @@ -8,6 +8,7 @@ pub mod request_buffer; pub mod structure_table; pub mod usage_buffer; pub mod producer_interface; +pub mod indirect_buffer; pub mod data; diff --git a/src/voxel_cache/indirect_buffer.rs b/src/voxel_cache/indirect_buffer.rs new file mode 100644 index 0000000..ec02f6b --- /dev/null +++ b/src/voxel_cache/indirect_buffer.rs @@ -0,0 +1,44 @@ +use wgpu::{Buffer, BufferUsages, Device, util::DeviceExt}; + +pub struct BufferCompactor +{ + size: usize, + block_count: usize, + reduced_buffer: Buffer, + sum_buffer: Buffer, + compaction_buffer: Buffer, +} + +impl BufferCompactor +{ + const THREAD_COUNT: usize = 256; + pub fn new(device: &Device, size: usize) -> Self + { + let block_count = size.div_ceil(size); + let reduced_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("indirect_buffer_reduced"), + contents: bytemuck::cast_slice(vec![0; block_count].as_slice()), + usage: BufferUsages::STORAGE, + }); + + let sum_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("indirect_buffer_sum"), + contents: bytemuck::cast_slice(vec![0; size].as_slice()), + usage: BufferUsages::STORAGE, + }); + + let compaction_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("indirect_buffer_compaction"), + contents: bytemuck::cast_slice(vec![0; size].as_slice()), + usage: BufferUsages::STORAGE, + }); + + BufferCompactor { + size, + block_count, + reduced_buffer, + sum_buffer, + compaction_buffer, + } + } +}