merge csg and object buffers

This commit is contained in:
2026-02-05 13:21:33 +00:00
parent a7c475b0a2
commit c5e6c1c5d8
7 changed files with 160 additions and 147 deletions
+7 -20
View File
@@ -44,10 +44,16 @@ layout(set = 0, binding = 3, std430) restrict readonly buffer Indicies {
} indicies;
struct Object {
// MESH
uint vert_offset;
uint index_offset;
// CSG
vec3 dimensions;
vec3 lowest_corner;
uint subdivision_log2;
// MATERIAL
vec4 colour_and_roughness;
float metallic;
float subsurface;
@@ -59,26 +65,7 @@ struct Object {
float clear_coat;
};
struct Mesh {
uint vert_offset;
uint index_offset;
vec4 colour_and_roughness;
float metallic;
float subsurface;
float specular;
float specular_tint;
float sheen;
float sheen_tint;
float clear_coat_gloss;
float clear_coat;
};
layout(set = 0, binding = 4, std430) restrict readonly buffer Meshes {
Mesh meshes[];
} meshes;
layout(set = 0, binding = 5, std430) restrict readonly buffer Objects {
layout(set = 0, binding = 4, std430) restrict readonly buffer Objects {
Object objects[];
} objects;
+3 -3
View File
@@ -6,14 +6,14 @@
layout(location = 0) rayPayloadInEXT vec3 hit_value;
hitAttributeEXT vec2 baryCoord;
Mesh mesh;
Object obj;
OVertex load_vert(uint index) {
return verts.verts[mesh.vert_offset + indicies.indicies[mesh.index_offset + index]];
return verts.verts[obj.vert_offset + indicies.indicies[obj.index_offset + index]];
}
void main() {
mesh = meshes.meshes[gl_InstanceID];
obj = objects.objects[gl_InstanceID];
// get mesh vertex data in object space
OVertex v0 = load_vert((gl_PrimitiveID * 3) + 0);
+39 -17
View File
@@ -128,31 +128,40 @@ pub(crate) fn gui_up(gui: &mut Gui, state: &mut GState) {
);
let meshes_len = state.meshes.len();
let csg_len = state.csg.len();
let lights_len = state.lights.len();
let allow_mesh_delete = meshes_len > 1 || csg_len > 0;
let allow_csg_delete = meshes_len > 0 || csg_len > 1;
ui.heading(format!("Meshes ({})", meshes_len));
let mut meshdel = vec![];
for mesh in &mut state.meshes {
let mut meshdel = vec![false; meshes_len];
for (i, mesh) in state.meshes.iter_mut().enumerate() {
ui.collapsing(mesh.name.clone(), |ui| {
if meshes_len > 1 || csg_len > 0 {
meshdel.push(ui.small_button("remove mesh").clicked());
if allow_mesh_delete {
meshdel[i] = ui.small_button("remove mesh").clicked();
}
draw_position(ui, &mut mesh.position);
draw_material(ui, &mut mesh.material);
});
}
if allow_mesh_delete && ui.small_button("remove all meshes").clicked() {
for del in meshdel.iter_mut() {
*del = true;
}
}
for i in meshdel
.into_iter()
.enumerate()
.rev()
.filter_map(|(a, b)| if b { Some(a) } else { None })
{
state.meshes.remove(i);
}
ui.heading(format!("Implicit Surfaces ({})", csg_len));
let mut csgdel = vec![];
for csg in &mut state.csg {
let mut csgdel = vec![false; csg_len];
for (i, csg) in state.csg.iter_mut().enumerate() {
let mut csg = csg.write().unwrap();
ui.collapsing(csg.name.clone(), |ui| {
if meshes_len > 0 || csg_len > 1 {
csgdel.push(ui.small_button("remove csg").clicked());
csgdel[i] = ui.small_button("remove csg").clicked();
}
draw_position(ui, &mut csg.position);
draw_material(ui, &mut csg.material);
@@ -171,24 +180,30 @@ pub(crate) fn gui_up(gui: &mut Gui, state: &mut GState) {
});
});
}
for i in csgdel
.into_iter()
.enumerate()
.filter_map(|(a, b)| if b { Some(a) } else { None })
{
state.csg.remove(i);
}
if state.csg.len() < 32 && ui.small_button("add csg").clicked() {
state.new_csgs_needed += 1;
}
if state.csg.len() < 32 && ui.small_button("add all csgs").clicked() {
state.new_csgs_needed = (32 - state.csg.len()) as u8;
}
if allow_csg_delete && ui.small_button("remove all csgs").clicked() {
for del in csgdel.iter_mut() {
*del = true;
}
}
for i in csgdel
.into_iter()
.enumerate()
.rev()
.filter_map(|(a, b)| if b { Some(a) } else { None })
{
state.csg.remove(i);
}
ui.heading(format!("Lights ({})", state.lights.len()));
let mut lightdel = vec![];
let mut lightdel = vec![false; lights_len];
for (i, light) in state.lights.iter_mut().enumerate() {
ui.collapsing(format!("Light {i}"), |ui| {
lightdel.push(ui.small_button("remove light").clicked());
lightdel[i] = ui.small_button("remove light").clicked();
ui.add(
egui::Slider::new(&mut light.pos.x, -100.0..=100.0)
.text("Position.x"),
@@ -215,14 +230,21 @@ pub(crate) fn gui_up(gui: &mut Gui, state: &mut GState) {
);
});
}
let add_light = ui.small_button("add light").clicked();
if ui.small_button("remove all lights").clicked() {
for del in lightdel.iter_mut() {
*del = true;
}
}
for i in lightdel
.into_iter()
.enumerate()
.rev()
.filter_map(|(a, b)| if b { Some(a) } else { None })
{
state.lights.remove(i);
}
if state.lights.len() < 32 && ui.small_button("add light").clicked() {
if state.lights.len() < 32 && add_light {
state.lights.push(Light::default());
}
+16 -31
View File
@@ -16,8 +16,7 @@ const MINUMUM_SUBDIVISION: u32 = 8;
const MAX_VERTEX_BUFFER: DeviceSize = 1024 * 1024;
const MAX_INDEX_BUFFER: DeviceSize = 1024 * 1024;
const MAX_CSG_BUFFER: DeviceSize = 256;
const MAX_MESH_BUFFER: DeviceSize = 256;
const MAX_OBJECT_BUFFER: DeviceSize = 1024;
const MAX_TRANSFORM_BUFFER: DeviceSize = 1024;
use std::{
@@ -192,10 +191,7 @@ struct App {
vertex_buffer_pointer: Arc<AtomicU64>,
index_buffer: Subbuffer<[u32]>,
index_buffer_pointer: Arc<AtomicU64>,
csg_buffer: Subbuffer<[enable_gen_cs::Object]>,
_csg_buffer_pointer: Arc<AtomicU64>,
mesh_buffer: Subbuffer<[enable_gen_cs::Mesh]>,
_mesh_buffer_pointer: Arc<AtomicU64>,
object_buffer: Subbuffer<[enable_gen_cs::Object]>,
transform_buffer: Subbuffer<[[[f32; 4]; 3]]>,
transform_buffer_pointer: Arc<AtomicU64>,
pipeline_cache: Arc<PipelineCache>,
@@ -574,22 +570,18 @@ impl App {
let vertex_buffer;
let index_buffer;
let csg_buffer;
let mesh_buffer;
let object_buffer;
let transform_buffer;
{
let device_lock = uniform_buffer_allocator.lock().unwrap();
vertex_buffer = device_lock.allocate_slice(MAX_VERTEX_BUFFER).unwrap();
index_buffer = device_lock.allocate_slice(MAX_INDEX_BUFFER).unwrap();
csg_buffer = device_lock.allocate_slice(MAX_CSG_BUFFER).unwrap();
mesh_buffer = device_lock.allocate_slice(MAX_MESH_BUFFER).unwrap();
object_buffer = device_lock.allocate_slice(MAX_OBJECT_BUFFER).unwrap();
transform_buffer = device_lock.allocate_slice(MAX_TRANSFORM_BUFFER).unwrap();
};
let vertex_buffer_pointer = Arc::new(AtomicU64::new(0));
let index_buffer_pointer = Arc::new(AtomicU64::new(0));
let csg_buffer_pointer = Arc::new(AtomicU64::new(0));
let mesh_buffer_pointer = Arc::new(AtomicU64::new(0));
let transform_buffer_pointer = Arc::new(AtomicU64::new(0));
let pipeline_cache = get_pipeline_cache(device.clone());
@@ -706,13 +698,10 @@ impl App {
aabb_allocator,
vertex_buffer,
index_buffer,
csg_buffer,
mesh_buffer,
object_buffer,
transform_buffer,
vertex_buffer_pointer,
index_buffer_pointer,
_csg_buffer_pointer: csg_buffer_pointer,
_mesh_buffer_pointer: mesh_buffer_pointer,
transform_buffer_pointer,
pipeline_cache,
csg_count: gstate.csg.len(),
@@ -739,7 +728,7 @@ mod enable_gen_cs {
bytes: "shaders_out/replacement/enable_gen.comp.glsl.spv",
vulkan_version: "1.3",
spirv_version: "1.6",
custom_derives: [Debug, Clone, Copy],
custom_derives: [Debug, Clone, Copy, Default],
}
}
@@ -979,7 +968,7 @@ impl ApplicationHandler for App {
&self.vertex_buffer,
&self.index_buffer,
&self.transform_buffer,
&self.mesh_buffer,
&self.object_buffer,
0,
);
@@ -1290,8 +1279,7 @@ impl App {
WriteDescriptorSet::buffer(1, rcx.camera_buffers[index].clone()),
WriteDescriptorSet::buffer(2, self.vertex_buffer.clone()),
WriteDescriptorSet::buffer(3, self.index_buffer.clone()),
WriteDescriptorSet::buffer(4, self.mesh_buffer.clone()),
//WriteDescriptorSet::buffer(5, self.csg_buffer.clone()),
WriteDescriptorSet::buffer(4, self.object_buffer.clone()),
],
[],
)
@@ -1334,7 +1322,7 @@ impl App {
enable_gen_layout.clone(),
[
WriteDescriptorSet::buffer(1, rcx.camera_buffers[index].clone()),
WriteDescriptorSet::buffer(5, self.csg_buffer.clone()),
WriteDescriptorSet::buffer(4, self.object_buffer.clone()),
],
[],
)
@@ -1374,7 +1362,7 @@ impl App {
csg.enable_gen_pipeline.layout().clone(),
0,
enable_gen_cs::PushConstantData {
object_index: i as u32,
object_index: (self.gstate.meshes.len() + i) as u32,
},
)
.unwrap();
@@ -1921,13 +1909,7 @@ impl App {
let mut push_constants_left = self.gstate.csg.len();
for (i, csg) in self.gstate.csg.iter().enumerate() {
self.thread_work_creation
.send(WorkItem::GetPushConstants(
csg.clone(),
self.time,
self.transform_buffer.clone(),
self.csg_buffer.clone(),
i,
))
.send(WorkItem::GetPushConstants(csg.clone(), self.time, i))
.unwrap();
}
@@ -1962,7 +1944,10 @@ impl App {
while push_constants_left > 0 {
for work in self.thread_work_completion.try_iter() {
match work {
WorkComplete::GetPushConstants(_index) => {
WorkComplete::GetPushConstants(dimensions, lowest_corner, index) => {
let mut write = self.gstate.csg[index].write().unwrap();
write.dimensions = dimensions;
write.lowest_corner = lowest_corner;
push_constants_left -= 1;
},
other => work_for_later.push(other),
@@ -1983,7 +1968,7 @@ impl App {
&self.vertex_buffer,
&self.index_buffer,
&self.transform_buffer,
&self.mesh_buffer,
&self.object_buffer,
image_index,
);
+3
View File
@@ -76,6 +76,9 @@ pub(crate) struct CSG {
pub(crate) _seed: u64,
pub(crate) subdivision: u32,
pub(crate) dimensions: Vec3,
pub(crate) lowest_corner: Vec3,
pub(crate) replacement_modules: Arc<RwLock<HashMap<String, Arc<ShaderModule>>>>,
pub(crate) fuzz_pipeline: Arc<ComputePipeline>,
pub(crate) enable_gen_pipeline: Arc<ComputePipeline>,
+81 -28
View File
@@ -24,7 +24,7 @@ use vulkano::{
};
use crate::{
enable_gen_cs,
MAXIMUM_SUBDIVISION, MINUMUM_SUBDIVISION, enable_gen_cs,
gpu_upload::gpu_upload,
objects::{CSG, Mesh, OVertex, Position},
};
@@ -47,7 +47,7 @@ impl Scene {
vertex_buffer: &Subbuffer<[OVertex]>,
index_buffer: &Subbuffer<[u32]>,
transform_buffer: &Subbuffer<[[[f32; 4]; 3]]>,
mesh_buffer: &Subbuffer<[enable_gen_cs::Mesh]>,
object_buffer: &Subbuffer<[enable_gen_cs::Object]>,
image_index: usize,
) -> Self {
// Build the bottom-level acceleration structure and then the top-level
@@ -57,34 +57,42 @@ impl Scene {
// contains the instances of the bottom-level acceleration structures. In our
// shader, we will trace rays against the top-level acceleration
// structure.
let mut index = 0;
let mesh_blases: Vec<Arc<AccelerationStructure>> = meshes
.iter()
.enumerate()
.map(|(i, mesh)| unsafe {
build_acceleration_structure_triangles(
.map(|mesh| unsafe {
let s = build_acceleration_structure_triangles(
mesh,
vertex_buffer.clone(),
index_buffer.clone(),
transform_buffer.clone(),
mesh_buffer.clone(),
object_buffer.clone(),
memory_allocator.clone(),
device.clone(),
builder,
i,
)
index,
);
index += 1;
s
})
.collect();
let csg_blases: Vec<Arc<AccelerationStructure>> = csgs
.iter()
.map(|csg| unsafe {
build_acceleration_structure_boxes(
let s = build_acceleration_structure_boxes(
csg,
image_index,
transform_buffer.clone(),
object_buffer.clone(),
memory_allocator.clone(),
device.clone(),
builder,
)
image_index,
index,
);
index += 1;
s
})
.collect();
@@ -145,27 +153,66 @@ pub(crate) fn upload_transform(position: &Position, transform_buffer: Subbuffer<
);
}
fn upload_mesh_data(mesh: &Mesh, mesh_buffer: Subbuffer<[enable_gen_cs::Mesh]>, index: DeviceSize) {
let mesh = enable_gen_cs::Mesh {
vert_offset: (mesh.vert_offset as u32).into(),
index_offset: (mesh.index_offset as u32).into(),
fn upload_mesh_data(
mesh: &Mesh,
object_buffer: Subbuffer<[enable_gen_cs::Object]>,
index: DeviceSize,
) {
let mesh = enable_gen_cs::Object {
vert_offset: (mesh.vert_offset as u32).into(),
index_offset: (mesh.index_offset as u32).into(),
colour_and_roughness: [
mesh.material.colour[0],
mesh.material.colour[1],
mesh.material.colour[2],
mesh.material.roughness,
],
metallic: mesh.material.metallic,
subsurface: mesh.material.subsurface,
specular: mesh.material.specular,
specular_tint: mesh.material.specular_tint,
sheen: mesh.material.sheen,
sheen_tint: mesh.material.sheen_tint,
clear_coat_gloss: mesh.material.clear_coat_gloss,
clear_coat: mesh.material.clear_coat,
metallic: mesh.material.metallic,
subsurface: mesh.material.subsurface,
specular: mesh.material.specular,
specular_tint: mesh.material.specular_tint,
sheen: mesh.material.sheen,
sheen_tint: mesh.material.sheen_tint,
clear_coat_gloss: mesh.material.clear_coat_gloss,
clear_coat: mesh.material.clear_coat,
..Default::default()
};
gpu_upload(mesh, mesh_buffer.index(index));
gpu_upload(mesh, object_buffer.index(index));
}
fn upload_csg_data(
csg: &CSG,
object_buffer: Subbuffer<[enable_gen_cs::Object]>,
index: DeviceSize,
) {
// csg.subdivision must be a power of 2
assert_eq!(csg.subdivision.count_ones(), 1);
assert!(csg.subdivision <= MAXIMUM_SUBDIVISION);
assert!(csg.subdivision >= MINUMUM_SUBDIVISION);
let obj = enable_gen_cs::Object {
dimensions: csg.dimensions.to_array().into(),
lowest_corner: csg.lowest_corner.to_array().into(),
subdivision_log2: csg.subdivision.ilog2(),
colour_and_roughness: [
csg.material.colour[0],
csg.material.colour[1],
csg.material.colour[2],
csg.material.roughness,
],
metallic: csg.material.metallic,
subsurface: csg.material.subsurface,
specular: csg.material.specular,
specular_tint: csg.material.specular_tint,
sheen: csg.material.sheen,
sheen_tint: csg.material.sheen_tint,
clear_coat_gloss: csg.material.clear_coat_gloss,
clear_coat: csg.material.clear_coat,
..Default::default()
};
gpu_upload(obj, object_buffer.index(index))
}
/// A helper function to build a acceleration structure and wait for its
@@ -268,14 +315,14 @@ unsafe fn build_acceleration_structure_triangles(
vertex_buffer: Subbuffer<[OVertex]>,
index_buffer: Subbuffer<[u32]>,
transform_buffer: Subbuffer<[[[f32; 4]; 3]]>,
mesh_buffer: Subbuffer<[enable_gen_cs::Mesh]>,
object_buffer: Subbuffer<[enable_gen_cs::Object]>,
memory_allocator: Arc<dyn MemoryAllocator>,
device: Arc<Device>,
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
index: usize,
) -> Arc<AccelerationStructure> {
upload_transform(&mesh.position, transform_buffer.clone());
upload_mesh_data(&mesh, mesh_buffer, index as _);
upload_mesh_data(&mesh, object_buffer, index as _);
let primitive_count = (mesh.index_len / 3) as u32;
let as_geometry_triangles_data = AccelerationStructureGeometryTrianglesData {
@@ -309,16 +356,22 @@ unsafe fn build_acceleration_structure_triangles(
unsafe fn build_acceleration_structure_boxes(
csg: &Arc<RwLock<CSG>>,
index: usize,
transform_buffer: Subbuffer<[[[f32; 4]; 3]]>,
object_buffer: Subbuffer<[enable_gen_cs::Object]>,
memory_allocator: Arc<dyn MemoryAllocator>,
device: Arc<Device>,
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
image_index: usize,
index: usize,
) -> Arc<AccelerationStructure> {
let csg = csg.read().unwrap();
upload_transform(&csg.position, transform_buffer);
upload_csg_data(&csg, object_buffer, index as _);
let primitive_count = (csg.subdivision * csg.subdivision * csg.subdivision) as u32;
let as_geometry_aabb_data = AccelerationStructureGeometryAabbsData {
stride: 4 * 6, // six floats
data: Some(csg.aabb_buffer[index].clone()),
data: Some(csg.aabb_buffer[image_index].clone()),
..AccelerationStructureGeometryAabbsData::default()
};
+11 -48
View File
@@ -25,12 +25,10 @@ use vulkano::{
};
use crate::{
DUMP_SPV_TO_FILE, MAXIMUM_SUBDIVISION, MINUMUM_SUBDIVISION, enable_gen_cs, get_spec_constants,
gpu_upload,
DUMP_SPV_TO_FILE, MAXIMUM_SUBDIVISION, get_spec_constants,
gui::PreviousDebug,
interpreters::point::PointInterpreter,
objects::CSG,
scene::upload_transform,
ssa::{SSAInput, SSAOpcode, SSAOpcodeSized, SSATape},
};
@@ -48,13 +46,7 @@ pub enum WorkItem {
u64,
isize,
),
GetPushConstants(
Arc<RwLock<CSG>>,
f32,
Subbuffer<[[[f32; 4]; 3]]>,
Subbuffer<[enable_gen_cs::Object]>,
usize,
),
GetPushConstants(Arc<RwLock<CSG>>, f32, usize),
RecompileShaders(
Arc<RwLock<CSG>>,
Arc<Device>,
@@ -72,7 +64,7 @@ pub enum WorkItem {
pub enum WorkComplete {
CreateCSG(Arc<RwLock<CSG>>, isize),
GetPushConstants(usize),
GetPushConstants(Vec3, Vec3, usize),
RecompileShaders(usize),
RecompilePipelines(usize),
}
@@ -150,6 +142,8 @@ pub fn thread_loop(recv: mpmc::Receiver<WorkItem>, send: mpsc::SyncSender<WorkCo
subdivision,
aabb_buffer,
enable_gen_descriptor_set,
dimensions: Default::default(),
lowest_corner: Default::default(),
}));
send.send(WorkComplete::CreateCSG(csg, index)).unwrap();
@@ -160,14 +154,13 @@ pub fn thread_loop(recv: mpmc::Receiver<WorkItem>, send: mpsc::SyncSender<WorkCo
(csg_end - csg_start).as_secs_f64() * 1000.0
);
},
WorkItem::GetPushConstants(csg, time, transform_buffer, csg_buffer, index) => {
WorkItem::GetPushConstants(csg, time, index) => {
let csg = csg.read().unwrap();
upload_transform(&csg.position, transform_buffer);
let (dim, lowest) = interval_check(&csg, time);
interval_check(&csg, time, csg_buffer, index);
send.send(WorkComplete::GetPushConstants(index)).unwrap();
send.send(WorkComplete::GetPushConstants(dim, lowest, index))
.unwrap();
},
WorkItem::RecompileShaders(csg, device, replacement_modules, index) => {
let csg_start = Instant::now();
@@ -440,12 +433,7 @@ fn create_csg(seed: u64) -> SSATape {
tape
}
fn interval_check(
csg: &CSG,
time: f32,
csg_buffer: Subbuffer<[enable_gen_cs::Object]>,
index: usize,
) {
fn interval_check(csg: &CSG, time: f32) -> (Vec3, Vec3) {
const INTERPRET_INPUT_X: interpreters::Value =
interpreters::Value::from_array([10000.0, 0.0, 0.0, -10000.0, 0.0, 0.0, 0.0, 0.0]);
const INTERPRET_INPUT_Y: interpreters::Value =
@@ -476,32 +464,7 @@ fn interval_check(
let lowest_corner =
Vec3::new(interpreter_out[3], interpreter_out[4], interpreter_out[5]) - EPSILON;
// csg.subdivision must be a power of 2
assert_eq!(csg.subdivision.count_ones(), 1);
assert!(csg.subdivision <= MAXIMUM_SUBDIVISION);
assert!(csg.subdivision >= MINUMUM_SUBDIVISION);
let obj = enable_gen_cs::Object {
dimensions: (highest_corner - lowest_corner).to_array().into(),
lowest_corner: lowest_corner.into(),
subdivision_log2: csg.subdivision.ilog2(),
colour_and_roughness: [
csg.material.colour[0],
csg.material.colour[1],
csg.material.colour[2],
csg.material.roughness,
],
metallic: csg.material.metallic,
subsurface: csg.material.subsurface,
specular: csg.material.specular,
specular_tint: csg.material.specular_tint,
sheen: csg.material.sheen,
sheen_tint: csg.material.sheen_tint,
clear_coat_gloss: csg.material.clear_coat_gloss,
clear_coat: csg.material.clear_coat,
};
gpu_upload(obj, csg_buffer.index(index as _))
(highest_corner - lowest_corner, lowest_corner)
}
fn sdf_specialize_module(