feature: add a producer_interface struct to cleanly represent the $ interface

This commit is contained in:
2026-09-05 21:06:38 +02:00
parent a241b7fd83
commit f8087c3a2c
3 changed files with 519 additions and 322 deletions
+80 -110
View File
@@ -59,6 +59,8 @@ use crate::voxel_cache::data::CacheResponse;
use crate::voxel_cache::data::ColorBytes;
use crate::voxel_cache::data::DestinationElement;
use crate::voxel_cache::data::LocationPoolElement;
use crate::voxel_cache::producer_interface::CacheProducerInterface;
use crate::voxel_cache::producer_interface::CacheRequest;
mod camera;
mod egui_renderer;
@@ -81,6 +83,7 @@ struct State
pipeline: RenderPipeline,
voxel_cache: Arc<Mutex<VoxelCache<4>>>,
cache_interface: Arc<CacheProducerInterface<4>>,
terrain_generator: Arc<TerrainGenerator<4>>,
chunk_pos_map: Arc<HashMap<u32, (usize, usize, usize)>>,
instance_buffer: Buffer,
@@ -156,20 +159,21 @@ impl State
let egui_renderer = EguiRenderer::new(&device, surface_format, &window);
let mut voxel_cache = VoxelCache::<4>::new(200_000, device.clone(), queue.clone());
let cache_interface = CacheProducerInterface::new(1024, &device);
//let terrain_generator = TerrainGenerator::<4>::new(5, "vxls_height.tif", 0.2, "img.jpg");
let terrain_generator = TerrainGenerator::<4>::new(5, "vxls_height.tif", 0.2, "img.jpg");
// let terrain_generator = TerrainGenerator::<4>::new(
// 5,
// "./pointe_percee/height.tif",
// 0.2,
// "./pointe_percee/ortho.jpg",
// );
let terrain_generator = TerrainGenerator::<4>::new(
5,
"/home/albin/Documents/vxls_maps/lapiz/height.tif",
0.2,
"/home/albin/Documents/vxls_maps/lapiz/ortho.jpg",
);
// let terrain_generator = TerrainGenerator::<4>::new(
// 5,
// "/home/albin/Documents/vxls_maps/lapiz/height.tif",
// 0.2,
// "/home/albin/Documents/vxls_maps/lapiz/ortho.jpg",
// );
let mut chunk_pos_map = HashMap::new();
let chunk_instances = (0..terrain_generator.chunk_width)
@@ -280,6 +284,7 @@ impl State
usage_vec: Arc::new(Mutex::new(vec![])),
pipeline: chunk_pipeline,
voxel_cache: Arc::new(Mutex::new(voxel_cache)),
cache_interface: cache_interface.into(),
insertion_debounce: false,
camera: Default::default(),
instance_buffer,
@@ -380,6 +385,7 @@ impl State
// Create texture view.
// NOTE: We must handle Timeout because the surface may be unavailable
// (e.g., when the window is occluded on macOS).
// ~~ Texture view creation ~~
let surface_texture = match self.surface.get_current_texture()
{
wgpu::CurrentSurfaceTexture::Success(texture) => texture,
@@ -407,6 +413,16 @@ impl State
}
};
let texture_view = surface_texture
.texture
.create_view(&wgpu::TextureViewDescriptor {
// Without add_srgb_suffix() the image we will be working with
// might not be "gamma correct".
format: Some(self.surface_format.add_srgb_suffix()),
..Default::default()
});
// ~~ Ray-marching timestamp query setup ~~
let timestamp_query = self.device.create_query_set(&wgpu::QuerySetDescriptor {
label: Some("timestamp_query_set"),
ty: wgpu::QueryType::Timestamp,
@@ -420,18 +436,8 @@ impl State
mapped_at_creation: false,
});
let texture_view = surface_texture
.texture
.create_view(&wgpu::TextureViewDescriptor {
// Without add_srgb_suffix() the image we will be working with
// might not be "gamma correct".
format: Some(self.surface_format.add_srgb_suffix()),
..Default::default()
});
// Renders a GREEN screen
// ~~ Main render pass ~~
let mut encoder = self.device.create_command_encoder(&Default::default());
{
let mut renderpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
@@ -440,7 +446,12 @@ impl State
depth_slice: None,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.,
g: 2. / 255.,
b: 15. / 255.,
a: 1.,
}),
store: wgpu::StoreOp::Store,
},
})],
@@ -478,24 +489,7 @@ impl State
encoder.resolve_query_set(&timestamp_query, 0..2, &timestamp_buffer, 0);
}
let requests = self.device.create_buffer(&wgpu::BufferDescriptor {
label: Some("dummy_dumb_dinky_aaaahhh_buffer"),
size: 16 * 2000,
usage: BufferUsages::STORAGE | BufferUsages::COPY_SRC,
mapped_at_creation: false,
});
if !self
.camera
.pressed_keyset
.contains(&winit::keyboard::KeyCode::KeyF)
{
self.voxel_cache
.lock()
.cache_post_render(&mut encoder, requests.clone());
}
// If you wanted to call any drawing commands, they would go here.
// ~~ EGUI Render pass ~~
{
self.egui_renderer.begin_frame(&self.window);
egui::Window::new("Window ! ").resizable(true).show(
@@ -547,7 +541,7 @@ impl State
);
}
// Report usage
// ~~ Build usage buffer histogram
let time_stamp = self.voxel_cache.lock().current_timestamp();
let cloned_usage_histogram = self.usage_vec.clone();
DownloadBuffer::read_buffer(
@@ -567,27 +561,7 @@ impl State
},
);
// Submit the command in the queue to execute
self.queue.submit([encoder.finish()]);
self.window.pre_present_notify();
self.queue.present(surface_texture);
if !self
.camera
.pressed_keyset
.contains(&winit::keyboard::KeyCode::KeyF)
&& self.insertion_debounce
{
self.insertion_debounce = false;
}
// if (self
// .camera
// .pressed_keyset
// .contains(&winit::keyboard::KeyCode::KeyF))
// && !self.insertion_debounce
// {
// Report frame time
// ~~ Get Ray-marching timestamps, report time ~~
let cloned_rm_time = self.rm_time.clone();
let cloned_queue = self.queue.clone();
DownloadBuffer::read_buffer(
@@ -602,30 +576,52 @@ impl State
},
);
// ~~ Do cache managment
if !self
.camera
.pressed_keyset
.contains(&winit::keyboard::KeyCode::KeyF)
{
self.voxel_cache
.lock()
.cache_post_render(&mut encoder, &self.cache_interface);
}
// ~~ Submit command buffer ~~
self.queue.submit([encoder.finish()]);
self.window.pre_present_notify();
self.queue.present(surface_texture);
// ~~ Do cache managment
if !self
.camera
.pressed_keyset
.contains(&winit::keyboard::KeyCode::KeyF)
{
self.insertion_debounce = true;
let request_count = self.voxel_cache.lock().total_request_count();
let request_count = self
.cache_interface
.total_request_count(&self.device, &self.queue);
let cloned_cache = self.voxel_cache.clone();
let cloned_device = self.device.clone();
let cloned_queue = self.queue.clone();
let cloned_generator = self.terrain_generator.clone();
let cloned_map = self.chunk_pos_map.clone();
let cloned_cache_interface = self.cache_interface.clone();
let (tx, rx) = sync_channel(1);
// ~~ Download request buffer, fullfill requests, writeback to cache ~~
DownloadBuffer::read_buffer(
&self.device.clone(),
&self.queue.clone(),
&requests.slice(0..),
&self.cache_interface.requests_buffer().slice(..),
move |buffer| {
if tx.try_send(()).is_err()
{
return;
}
let cache_node_requests: Vec<CacheNodeRequest> =
let cache_node_requests: Vec<CacheRequest> =
bytemuck::pod_collect_to_vec(&buffer.unwrap());
let generator = cloned_generator;
@@ -634,7 +630,6 @@ impl State
let mut structure_nodes = vec![];
let mut color_nodes: Vec<[ColorBytes; 64]> = vec![];
let mut location_nodes = vec![];
let mut destinations = vec![];
cache_node_requests
.par_iter()
@@ -646,7 +641,7 @@ impl State
let location;
let node;
if request.child_index == u32::MAX
if request.locator == 0
{
// Produce root node
node =
@@ -660,9 +655,8 @@ impl State
else
{
// Figure out depth of request
let locator = NTreeNodeLocator::<4>::from_usize(
request.structure_locator as usize,
);
let locator =
NTreeNodeLocator::<4>::from_usize(request.locator as usize);
let depth = locator.depth();
//let (x, y, z) = locator.node_location();
@@ -692,15 +686,7 @@ impl State
};
}
(
node.structure,
node.colors,
location,
DestinationElement {
node: request.node_index,
child: request.child_index,
},
)
(node.structure, node.colors, location)
})
.collect::<Vec<_>>()
.into_iter()
@@ -708,46 +694,30 @@ impl State
structure_nodes.push(data.0);
color_nodes.push(std::array::from_fn(|i| data.1[i].into()));
location_nodes.push(data.2);
destinations.push(data.3);
});
if structure_nodes.len() != 0
{
let structre_node_buffer =
cloned_device.create_buffer_init(&BufferInitDescriptor {
label: None,
contents: unsafe { as_raw_bytes(structure_nodes.as_slice()) },
usage: BufferUsages::STORAGE,
});
let color_node_buffer =
cloned_device.create_buffer_init(&BufferInitDescriptor {
label: None,
contents: unsafe { as_raw_bytes(color_nodes.as_slice()) },
usage: BufferUsages::STORAGE,
});
let location_node_buffer =
cloned_device.create_buffer_init(&BufferInitDescriptor {
label: None,
contents: unsafe { as_raw_bytes(location_nodes.as_slice()) },
usage: BufferUsages::STORAGE,
});
let destinations_buffer =
cloned_device.create_buffer_init(&BufferInitDescriptor {
label: None,
contents: unsafe { as_raw_bytes(destinations.as_slice()) },
usage: BufferUsages::STORAGE,
});
cloned_queue.write_buffer(
cloned_cache_interface.structure_nodes_buffer(),
0,
unsafe { as_raw_bytes(structure_nodes.as_slice()) },
);
cloned_queue.write_buffer(
cloned_cache_interface.color_nodes_buffer(),
0,
unsafe { as_raw_bytes(&color_nodes.as_slice()) },
);
cloned_queue.write_buffer(
cloned_cache_interface.location_nodes_buffer(),
0,
unsafe { as_raw_bytes(&&location_nodes.as_slice()) },
);
let mut encoder = cloned_device.create_command_encoder(&Default::default());
cloned_cache.lock().cache_insert(
&mut encoder,
&CacheResponse {
structure_nodes: structre_node_buffer,
color_nodes: color_node_buffer,
locations: location_node_buffer,
parents: destinations_buffer,
},
);
cloned_cache
.lock()
.cache_insert(&mut encoder, &cloned_cache_interface);
cloned_queue.submit([encoder.finish()]);
}
},