Render a triangle!
- Refactor `RenderPass` and `RenderPassBox` APIs - Add basic `mesh_shader.wgsl` - Decouple `MeshLayoutBindingIndices` from `MeshLayoutBindings` - Create `MeshPass` render pipeline - `MeshPass` creates an example mesh - `MeshPass` flushes `MeshPool` - `MeshPass` actually draws meshes
This commit is contained in:
parent
257acf56d2
commit
f590edb77f
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bytemuck = { version = "^1.0", features = ["derive"] }
|
||||
multimap = "0.8"
|
||||
pollster = "0.2"
|
||||
rayon = "1"
|
||||
|
|
48
src/lib.rs
48
src/lib.rs
|
@ -36,11 +36,11 @@ impl Renderer {
|
|||
}
|
||||
|
||||
pub fn add_pass<T: 'static + RenderPass>(&mut self, pass: T) {
|
||||
let pass = Arc::new(RwLock::new(pass));
|
||||
let pass = Arc::new(pass);
|
||||
self.add_pass_arc(pass);
|
||||
}
|
||||
|
||||
pub fn add_pass_arc<T: 'static + RenderPass>(&mut self, pass: Arc<RwLock<T>>) {
|
||||
pub fn add_pass_arc<T: 'static + RenderPass>(&mut self, pass: Arc<T>) {
|
||||
let pass = RenderPassBox::new(pass, self.frames_in_flight);
|
||||
self.add_pass_box(pass);
|
||||
}
|
||||
|
@ -99,32 +99,26 @@ impl Renderer {
|
|||
});
|
||||
}
|
||||
|
||||
let opaque_cmds = Mutex::new(Vec::new());
|
||||
if let Some(opaque) = phase_passes.get_vec(&Phase::Opaque) {
|
||||
opaque.par_iter().for_each(|pass_index| {
|
||||
let pass = &self.render_passes[*pass_index];
|
||||
|
||||
let frame_data = IndexedPhaseData {
|
||||
phase: Phase::Opaque,
|
||||
frame_data: frame_index,
|
||||
viewport: &viewport,
|
||||
};
|
||||
|
||||
if let Some(cmd) = pass.record_render(frame_data) {
|
||||
opaque_cmds.lock().unwrap().push(cmd);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let opaque_cmds = opaque_cmds.into_inner().unwrap();
|
||||
|
||||
{
|
||||
let mut opaque_cmds = Vec::new();
|
||||
if let Some(opaque) = phase_passes.get_vec(&Phase::Opaque) {
|
||||
opaque.iter().for_each(|pass_index| {
|
||||
let frame_data = IndexedPhaseData {
|
||||
phase: Phase::Opaque,
|
||||
frame_data: frame_index,
|
||||
viewport: &viewport,
|
||||
};
|
||||
|
||||
let pass = &self.render_passes[*pass_index];
|
||||
let mut cmds = self.device.create_render_bundle_encoder(
|
||||
&wgpu::RenderBundleEncoderDescriptor {
|
||||
label: Some("Opaque Pass Render Bundle"),
|
||||
color_formats: &[format],
|
||||
depth_stencil: None,
|
||||
sample_count: 1,
|
||||
multiview: None,
|
||||
},
|
||||
);
|
||||
|
||||
pass.record_render(frame_data, &mut cmds);
|
||||
opaque_cmds.push(cmds.finish(&wgpu::RenderBundleDescriptor::default()));
|
||||
})
|
||||
}
|
||||
|
||||
let mut rp = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("Render Pass"),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachment {
|
||||
|
|
|
@ -73,7 +73,7 @@ fn main() {
|
|||
let (mut renderer, mut viewport) = pollster::block_on(make_window_renderer(&window));
|
||||
|
||||
let device = renderer.get_device();
|
||||
let mesh_pass = pass::mesh::MeshPass::new(device.to_owned());
|
||||
let mesh_pass = pass::mesh::MeshPass::new(device.to_owned(), viewport.config.format);
|
||||
renderer.add_pass(mesh_pass);
|
||||
|
||||
event_loop.run(move |event, _, control_flow| match event {
|
||||
|
|
63
src/mesh.rs
63
src/mesh.rs
|
@ -133,10 +133,10 @@ pub struct AttrAllocKey {
|
|||
/// Info about an array of attributes that has been allocated in an [AttrPool].
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct AttrAlloc {
|
||||
offset: usize,
|
||||
count: usize,
|
||||
offset_bytes: usize,
|
||||
count_bytes: usize,
|
||||
pub offset: usize,
|
||||
pub count: usize,
|
||||
pub offset_bytes: usize,
|
||||
pub count_bytes: usize,
|
||||
}
|
||||
|
||||
/// An unused space range in an [AttrPool].
|
||||
|
@ -305,17 +305,21 @@ impl AttrPool {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets the offset (in elements) of an allocation, passed by key.
|
||||
pub fn get_offset(&self, key: usize) -> Result<usize, PoolError> {
|
||||
let alloc = self.allocs.get(key).ok_or(PoolError::InvalidIndex)?;
|
||||
Ok(alloc.offset)
|
||||
/// Retrieves an [AttrAlloc] by key.
|
||||
pub fn get(&self, key: usize) -> Option<AttrAlloc> {
|
||||
self.allocs.get(key).copied()
|
||||
}
|
||||
|
||||
/// Gets this pool's internal GPU buffer.
|
||||
pub fn get_buffer(&self) -> &wgpu::Buffer {
|
||||
&self.buffer
|
||||
}
|
||||
|
||||
/// Gets a [CopyDest] for an allocation, by key.
|
||||
pub fn get_copy_dest(&self, key: usize) -> Result<CopyDest, PoolError> {
|
||||
let offset = self.get_offset(key)?;
|
||||
let offset = self.get(key).ok_or(PoolError::InvalidIndex)?.offset_bytes;
|
||||
Ok(CopyDest {
|
||||
buffer: &self.buffer,
|
||||
buffer: self.get_buffer(),
|
||||
offset,
|
||||
})
|
||||
}
|
||||
|
@ -347,17 +351,31 @@ pub type MeshLayoutDesc = smallmap::Set<AttrId>;
|
|||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct MeshLayoutId(usize);
|
||||
|
||||
/// Mappings of the attributes in a [MeshLayout] to specific pool indices.
|
||||
pub type MeshLayoutBindingIndices = smallmap::Map<AttrId, usize>;
|
||||
|
||||
/// Mappings of the attributes in a [MeshLayout] to specific pools.
|
||||
pub type MeshLayoutBindings = smallmap::Map<AttrId, usize>;
|
||||
pub struct MeshLayoutBindings<'a> {
|
||||
lock: std::sync::RwLockReadGuard<'a, HashMap<AttrId, Vec<AttrPool>>>,
|
||||
indices: MeshLayoutBindingIndices,
|
||||
}
|
||||
|
||||
impl<'a> MeshLayoutBindings<'a> {
|
||||
pub fn get(&self, attr: AttrId) -> Option<&AttrPool> {
|
||||
let pool_id = self.indices.get(&attr)?;
|
||||
let pools = self.lock.get(&attr)?;
|
||||
pools.get(*pool_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Mappings of the attributes in a [MeshAlloc] to specific pool offsets.
|
||||
pub type MeshAllocOffsets = SmallVec<[(AttrId, usize); MAX_MESH_INLINE_ATTRIBUTES]>;
|
||||
pub type MeshAllocInfos = SmallVec<[(AttrId, AttrAlloc); MAX_MESH_INLINE_ATTRIBUTES]>;
|
||||
|
||||
/// A set of mesh instances fitting a common [MeshLayoutDesc].
|
||||
#[derive(Default)]
|
||||
pub struct MeshLayoutInstances<T> {
|
||||
pub bindings: MeshLayoutBindings,
|
||||
pub instances: Vec<(T, MeshAllocOffsets)>,
|
||||
pub bindings: MeshLayoutBindingIndices,
|
||||
pub instances: Vec<(T, MeshAllocInfos)>,
|
||||
}
|
||||
|
||||
/// A mesh data pool.
|
||||
|
@ -476,7 +494,7 @@ impl MeshPool {
|
|||
) -> Result<Vec<MeshLayoutInstances<T>>, PoolError>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
F: Fn(&T) -> &'static MeshHandle,
|
||||
F: Fn(&T) -> &MeshHandle,
|
||||
{
|
||||
let layout = self
|
||||
.mesh_layouts
|
||||
|
@ -511,8 +529,8 @@ impl MeshPool {
|
|||
continue;
|
||||
}
|
||||
|
||||
let mut layout_bindings = MeshLayoutBindings::default();
|
||||
let mut alloc_offsets = MeshAllocOffsets::default();
|
||||
let mut layout_bindings = MeshLayoutBindingIndices::default();
|
||||
let mut alloc_infos = MeshAllocInfos::default();
|
||||
for alloc in attr_allocs.iter() {
|
||||
let pools_read = self.pools.read().unwrap();
|
||||
let pools = pools_read
|
||||
|
@ -520,13 +538,13 @@ impl MeshPool {
|
|||
.ok_or(PoolError::AttrUnregistered)?;
|
||||
|
||||
let pool = pools.get(alloc.pool).ok_or(PoolError::InvalidIndex)?;
|
||||
let alloc_offset = pool.get_offset(alloc.alloc)?;
|
||||
let alloc_info = pool.get(alloc.alloc).ok_or(PoolError::InvalidIndex)?;
|
||||
|
||||
layout_bindings.insert(alloc.attr, alloc.pool);
|
||||
alloc_offsets.push((alloc.attr, alloc_offset));
|
||||
alloc_infos.push((alloc.attr, alloc_info));
|
||||
}
|
||||
|
||||
let instance = (mesh, alloc_offsets);
|
||||
let instance = (mesh, alloc_infos);
|
||||
|
||||
match layouts
|
||||
.iter_mut()
|
||||
|
@ -542,4 +560,9 @@ impl MeshPool {
|
|||
|
||||
Ok(layouts)
|
||||
}
|
||||
|
||||
pub fn get_bindings<'a>(&'a self, indices: MeshLayoutBindingIndices) -> MeshLayoutBindings<'a> {
|
||||
let lock = self.pools.read().unwrap();
|
||||
MeshLayoutBindings { lock, indices }
|
||||
}
|
||||
}
|
||||
|
|
44
src/pass.rs
44
src/pass.rs
|
@ -32,24 +32,24 @@ pub trait RenderPass: Send + Sync {
|
|||
/// Sets up a new instance of [Self::FrameData].
|
||||
///
|
||||
/// Called when a render pass is added to [crate::Renderer].
|
||||
fn create_frame_data(&mut self) -> Self::FrameData;
|
||||
fn create_frame_data(&self) -> Self::FrameData;
|
||||
|
||||
/// Initializes this frame's [Self::FrameData], and queries the pass for
|
||||
/// which phases to execute.
|
||||
///
|
||||
/// This is the only opportunity the render pass has to mutate this frame's
|
||||
/// data this frame, so all setup for future phases should be done here.
|
||||
fn begin_frame(&mut self, data: &mut Self::FrameData, phases: &mut Vec<Phase>);
|
||||
fn begin_frame(&self, data: &mut Self::FrameData, phases: &mut Vec<Phase>);
|
||||
|
||||
fn record_commands(&self, data: PhaseData<&Self::FrameData>, cmds: &mut wgpu::CommandEncoder);
|
||||
|
||||
fn record_compute(&self, data: PhaseData<&Self::FrameData>, cmds: &mut wgpu::ComputePass);
|
||||
|
||||
fn record_render(
|
||||
&self,
|
||||
fn record_compute<'a>(
|
||||
&'a self,
|
||||
data: PhaseData<&Self::FrameData>,
|
||||
cmds: &mut wgpu::RenderBundleEncoder,
|
||||
cmds: &mut wgpu::ComputePass<'a>,
|
||||
);
|
||||
|
||||
fn record_render(&self, data: PhaseData<&Self::FrameData>) -> Option<wgpu::RenderBundle>;
|
||||
}
|
||||
|
||||
/// The interface trait for [RenderPassBox], allowing use of a statically-sized
|
||||
|
@ -62,14 +62,14 @@ pub trait RenderPassBoxTrait: Send + Sync {
|
|||
|
||||
fn record_commands(&self, data: IndexedPhaseData, cmds: &mut wgpu::CommandEncoder);
|
||||
|
||||
fn record_compute(&self, data: IndexedPhaseData, cmds: &mut wgpu::ComputePass);
|
||||
fn record_compute<'a>(&'a self, data: IndexedPhaseData, cmds: &mut wgpu::ComputePass<'a>);
|
||||
|
||||
fn record_render(&self, data: IndexedPhaseData, cmds: &mut wgpu::RenderBundleEncoder);
|
||||
fn record_render(&self, data: IndexedPhaseData) -> Option<wgpu::RenderBundle>;
|
||||
}
|
||||
|
||||
/// A container for a reference-counted render pass instance and its frame data.
|
||||
pub struct RenderPassBox<T: RenderPass> {
|
||||
render_pass: Arc<RwLock<T>>,
|
||||
render_pass: Arc<T>,
|
||||
frame_data: Vec<T::FrameData>,
|
||||
}
|
||||
|
||||
|
@ -78,10 +78,11 @@ impl<T: 'static + RenderPass> RenderPassBox<T> {
|
|||
///
|
||||
/// Calls to [RenderPassBoxTrait] functions with frame indices greater
|
||||
/// than or equal to `frame_num` are out-of-bounds and will panic.
|
||||
pub fn new(render_pass: Arc<RwLock<T>>, frame_num: usize) -> Box<dyn RenderPassBoxTrait> {
|
||||
pub fn new(render_pass: Arc<T>, frame_num: usize) -> Box<dyn RenderPassBoxTrait> {
|
||||
let frame_data = {
|
||||
let mut lock = render_pass.write().unwrap();
|
||||
(0..frame_num).map(|_| lock.create_frame_data()).collect()
|
||||
(0..frame_num)
|
||||
.map(|_| render_pass.create_frame_data())
|
||||
.collect()
|
||||
};
|
||||
|
||||
Box::new(Self {
|
||||
|
@ -115,25 +116,22 @@ impl<T: RenderPass> RenderPassBox<T> {
|
|||
impl<T: RenderPass> RenderPassBoxTrait for RenderPassBox<T> {
|
||||
fn begin_frame(&mut self, data_index: usize, phases: &mut Vec<Phase>) {
|
||||
let frame_data = &mut self.frame_data[data_index];
|
||||
let mut render_pass = self.render_pass.write().unwrap();
|
||||
render_pass.begin_frame(frame_data, phases)
|
||||
self.render_pass.begin_frame(frame_data, phases)
|
||||
}
|
||||
|
||||
fn record_commands(&self, data: IndexedPhaseData, cmds: &mut wgpu::CommandEncoder) {
|
||||
let frame_data = self.get_frame_data(data);
|
||||
let render_pass = self.render_pass.read().unwrap();
|
||||
render_pass.record_commands(frame_data, cmds)
|
||||
self.render_pass.record_commands(frame_data, cmds)
|
||||
}
|
||||
|
||||
fn record_compute(&self, data: IndexedPhaseData, cmds: &mut wgpu::ComputePass) {
|
||||
fn record_compute<'a>(&'a self, data: IndexedPhaseData, cmds: &mut wgpu::ComputePass<'a>) {
|
||||
let frame_data = self.get_frame_data(data);
|
||||
let render_pass = self.render_pass.read().unwrap();
|
||||
render_pass.record_compute(frame_data, cmds)
|
||||
self.render_pass.record_compute(frame_data, cmds)
|
||||
}
|
||||
|
||||
fn record_render(&self, data: IndexedPhaseData, cmds: &mut wgpu::RenderBundleEncoder) {
|
||||
fn record_render(&self, data: IndexedPhaseData) -> Option<wgpu::RenderBundle> {
|
||||
let frame_data = self.get_frame_data(data);
|
||||
let render_pass = self.render_pass.read().unwrap();
|
||||
render_pass.record_render(frame_data, cmds)
|
||||
// let render_pass = self.render_pass.read().unwrap();
|
||||
self.render_pass.record_render(frame_data)
|
||||
}
|
||||
}
|
||||
|
|
205
src/pass/mesh.rs
205
src/pass/mesh.rs
|
@ -1,21 +1,154 @@
|
|||
use super::*;
|
||||
use crate::mesh::*;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct Vertex {
|
||||
pub position: [f32; 3],
|
||||
pub color: [f32; 3],
|
||||
}
|
||||
|
||||
impl Attribute for Vertex {
|
||||
fn get_usages() -> wgpu::BufferUsages {
|
||||
wgpu::BufferUsages::VERTEX
|
||||
}
|
||||
}
|
||||
|
||||
const VERTEX_ATTRS: &[wgpu::VertexAttribute] =
|
||||
&wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x3];
|
||||
|
||||
impl Vertex {
|
||||
pub fn desc() -> wgpu::VertexBufferLayout<'static> {
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
|
||||
step_mode: wgpu::VertexStepMode::Vertex,
|
||||
attributes: VERTEX_ATTRS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Index = u32;
|
||||
|
||||
pub struct FrameData {}
|
||||
|
||||
pub struct MeshPass {
|
||||
device: Arc<wgpu::Device>,
|
||||
attr_store: Arc<AttrStore>,
|
||||
mesh_pool: Arc<MeshPool>,
|
||||
vertex_attr_id: AttrId,
|
||||
index_attr_id: AttrId,
|
||||
mesh_layout_id: MeshLayoutId,
|
||||
example_mesh: MeshHandle,
|
||||
opaque_pipeline: wgpu::RenderPipeline,
|
||||
target_format: wgpu::TextureFormat,
|
||||
}
|
||||
|
||||
impl MeshPass {
|
||||
pub fn new(device: Arc<wgpu::Device>) -> Self {
|
||||
pub fn new(device: Arc<wgpu::Device>, target_format: wgpu::TextureFormat) -> Self {
|
||||
let attr_store = AttrStore::new();
|
||||
let mesh_pool = MeshPool::new(device, attr_store.to_owned());
|
||||
let mesh_pool = MeshPool::new(device.clone(), attr_store.to_owned());
|
||||
|
||||
let vertex_attr_id = attr_store.get_type::<Vertex>();
|
||||
let index_attr_id = attr_store.add(AttrInfo {
|
||||
layout: AttrLayout {
|
||||
size: std::mem::size_of::<Index>(),
|
||||
},
|
||||
usages: wgpu::BufferUsages::INDEX,
|
||||
default_pool_size: 1_000_000,
|
||||
});
|
||||
|
||||
let mut mesh_layout = MeshLayoutDesc::new();
|
||||
mesh_layout.insert(vertex_attr_id, ());
|
||||
mesh_layout.insert(index_attr_id, ());
|
||||
let mesh_layout_id = mesh_pool.add_layout(mesh_layout).unwrap();
|
||||
|
||||
let example_vertices = vec![
|
||||
Vertex {
|
||||
position: [-0.5, 0.5, 0.0],
|
||||
color: [1.0, 0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5, 0.0],
|
||||
color: [0.0, 1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, -0.5, 0.0],
|
||||
color: [0.0, 0.0, 1.0],
|
||||
},
|
||||
];
|
||||
|
||||
let example_vertices = AttrBuffer {
|
||||
id: vertex_attr_id,
|
||||
count: example_vertices.len(),
|
||||
data: bytemuck::cast_slice(&example_vertices).to_vec(),
|
||||
};
|
||||
|
||||
let example_indices = vec![0u32, 1u32, 2u32];
|
||||
let example_indices = AttrBuffer {
|
||||
id: index_attr_id,
|
||||
count: example_indices.len(),
|
||||
data: bytemuck::cast_slice(&example_indices).to_vec(),
|
||||
};
|
||||
|
||||
let mut example_mesh = MeshBuffer::default();
|
||||
example_mesh.attributes.push(example_vertices);
|
||||
example_mesh.attributes.push(example_indices);
|
||||
let example_mesh = mesh_pool.load(example_mesh).unwrap();
|
||||
|
||||
let render_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Render Pipeline Layout"),
|
||||
bind_group_layouts: &[],
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
let shader = device.create_shader_module(&wgpu::include_wgsl!("mesh_shader.wgsl"));
|
||||
|
||||
let opaque_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Render Pipeline"),
|
||||
layout: Some(&render_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader,
|
||||
entry_point: "vs_main",
|
||||
buffers: &[Vertex::desc()],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader,
|
||||
entry_point: "fs_main",
|
||||
targets: &[wgpu::ColorTargetState {
|
||||
format: target_format,
|
||||
blend: Some(wgpu::BlendState::REPLACE),
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
}],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: None, // Some(wgpu::Face::Back),
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
unclipped_depth: false,
|
||||
conservative: false,
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: 1,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
});
|
||||
|
||||
Self {
|
||||
device,
|
||||
attr_store,
|
||||
mesh_pool,
|
||||
index_attr_id,
|
||||
vertex_attr_id,
|
||||
mesh_layout_id,
|
||||
example_mesh,
|
||||
opaque_pipeline,
|
||||
target_format,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,13 +156,14 @@ impl MeshPass {
|
|||
impl RenderPass for MeshPass {
|
||||
type FrameData = FrameData;
|
||||
|
||||
fn create_frame_data(&mut self) -> FrameData {
|
||||
fn create_frame_data(&self) -> FrameData {
|
||||
FrameData {}
|
||||
}
|
||||
|
||||
fn begin_frame(&mut self, data: &mut FrameData, phases: &mut Vec<Phase>) {
|
||||
fn begin_frame(&self, data: &mut FrameData, phases: &mut Vec<Phase>) {
|
||||
println!("MeshPass::begin_frame()");
|
||||
|
||||
phases.push(Phase::Upload);
|
||||
phases.push(Phase::Depth);
|
||||
phases.push(Phase::Opaque);
|
||||
phases.push(Phase::Transparent);
|
||||
|
@ -37,13 +171,74 @@ impl RenderPass for MeshPass {
|
|||
|
||||
fn record_commands(&self, data: PhaseData<&FrameData>, cmds: &mut wgpu::CommandEncoder) {
|
||||
println!("MeshPass::record_commands(phase: {:?})", data.phase);
|
||||
match data.phase {
|
||||
Phase::Upload => self.mesh_pool.flush(cmds),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn record_compute(&self, data: PhaseData<&FrameData>, cmds: &mut wgpu::ComputePass) {
|
||||
println!("MeshPass::record_compute(phase: {:?})", data.phase);
|
||||
}
|
||||
|
||||
fn record_render(&self, data: PhaseData<&FrameData>, cmds: &mut wgpu::RenderBundleEncoder) {
|
||||
fn record_render(&self, data: PhaseData<&FrameData>) -> Option<wgpu::RenderBundle> {
|
||||
println!("MeshPass::record_render(phase: {:?})", data.phase);
|
||||
|
||||
let mut cmds =
|
||||
self.device
|
||||
.create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor {
|
||||
label: Some("Opaque Pass Render Bundle"),
|
||||
color_formats: &[self.target_format],
|
||||
depth_stencil: None,
|
||||
sample_count: 1,
|
||||
multiview: None,
|
||||
});
|
||||
|
||||
let pipeline = match data.phase {
|
||||
Phase::Opaque => &self.opaque_pipeline,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let meshes = &[&self.example_mesh, &self.example_mesh];
|
||||
|
||||
// yikes
|
||||
let mesh_bindings: Vec<(MeshLayoutBindings, Vec<(&&MeshHandle, MeshAllocInfos)>)> = self
|
||||
.mesh_pool
|
||||
.iter_meshes(self.mesh_layout_id, meshes.iter(), |v| v)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(
|
||||
|MeshLayoutInstances {
|
||||
bindings,
|
||||
instances,
|
||||
}| (self.mesh_pool.get_bindings(bindings), instances),
|
||||
)
|
||||
.collect();
|
||||
|
||||
cmds.set_pipeline(pipeline);
|
||||
|
||||
for (bindings, instances) in mesh_bindings.iter() {
|
||||
let vertices_pool = bindings.get(self.vertex_attr_id).unwrap();
|
||||
let indices_pool = bindings.get(self.index_attr_id).unwrap();
|
||||
|
||||
cmds.set_vertex_buffer(0, vertices_pool.get_buffer().slice(..));
|
||||
cmds.set_index_buffer(
|
||||
indices_pool.get_buffer().slice(..),
|
||||
wgpu::IndexFormat::Uint32,
|
||||
);
|
||||
|
||||
for (mesh, infos) in instances {
|
||||
let vertices = infos.iter().find(|i| i.0 == self.vertex_attr_id).unwrap().1;
|
||||
let indices = infos.iter().find(|i| i.0 == self.index_attr_id).unwrap().1;
|
||||
|
||||
let is_start = indices.offset as u32;
|
||||
let is_end = is_start + indices.count as u32;
|
||||
|
||||
cmds.draw_indexed(is_start..is_end, vertices.offset as i32, 0..1);
|
||||
println!("drew a mesh! {}..{} + {}", is_start, is_end, vertices.offset);
|
||||
}
|
||||
}
|
||||
|
||||
Some(cmds.finish(&wgpu::RenderBundleDescriptor::default()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
struct VertexInput {
|
||||
[[location(0)]] position: vec3<f32>;
|
||||
[[location(1)]] color: vec3<f32>;
|
||||
};
|
||||
|
||||
struct VertexOutput {
|
||||
[[builtin(position)]] clip_position: vec4<f32>;
|
||||
[[location(0)]] position: vec3<f32>;
|
||||
[[location(1)]] color: vec3<f32>;
|
||||
};
|
||||
|
||||
[[stage(vertex)]]
|
||||
fn vs_main(
|
||||
[[builtin(instance_index)]] mesh_idx: u32,
|
||||
[[builtin(vertex_index)]] vertex_idx: u32,
|
||||
vertex: VertexInput,
|
||||
) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.clip_position = vec4<f32>(vertex.position, 1.0);
|
||||
out.position = vertex.position;
|
||||
out.color = vertex.color;
|
||||
return out;
|
||||
}
|
||||
|
||||
[[stage(fragment)]]
|
||||
fn fs_main(
|
||||
frag: VertexOutput,
|
||||
) -> [[location(0)]] vec4<f32> {
|
||||
return vec4<f32>(frag.color, 1.0);
|
||||
}
|
|
@ -64,6 +64,9 @@ impl<T: Clone> StagingPool<T> {
|
|||
on_complete(copy.target);
|
||||
}
|
||||
}
|
||||
|
||||
drop(src_view);
|
||||
src.unmap();
|
||||
}
|
||||
|
||||
pub fn queue_copies(&self, copies: Vec<CopyBuffer<T>>) {
|
||||
|
|
Loading…
Reference in New Issue