Compare commits

..

2 Commits

Author SHA1 Message Date
SeanOMik 2eeca335e2
game: run clippy 2024-06-28 13:25:48 -04:00
SeanOMik 96dea5b1f9
render: code cleanup 2024-06-28 13:16:47 -04:00
20 changed files with 182 additions and 184 deletions

View File

@ -160,6 +160,10 @@ impl<E: Event> EventReader<E> {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.buf.len() self.buf.len()
} }
pub fn is_empty(&self) -> bool {
self.len() == 0
}
} }
impl<E: Event> Iterator for EventReader<E> { impl<E: Event> Iterator for EventReader<E> {

View File

@ -92,10 +92,7 @@ impl<T: Button> InputButtons<T> {
pub fn was_just_pressed(&self, button: T) -> bool { pub fn was_just_pressed(&self, button: T) -> bool {
let hash = Self::get_button_hash(&button); let hash = Self::get_button_hash(&button);
match self.button_events.get(&hash) { match self.button_events.get(&hash) {
Some(button_event) => match button_event { Some(button_event) => matches!(button_event, ButtonEvent::JustPressed(b) if button == *b),
ButtonEvent::JustPressed(b) if button == *b => true,
_ => false,
},
None => false None => false
} }
} }
@ -105,11 +102,8 @@ impl<T: Button> InputButtons<T> {
/// This must be done so that a key does not stay as JustPressed between multiple ticks /// This must be done so that a key does not stay as JustPressed between multiple ticks
pub fn update(&mut self) { pub fn update(&mut self) {
for bev in self.button_events.values_mut() { for bev in self.button_events.values_mut() {
match bev { if let ButtonEvent::JustPressed(btn) = bev {
ButtonEvent::JustPressed(btn) => { *bev = ButtonEvent::Pressed(btn.clone());
*bev = ButtonEvent::Pressed(btn.clone());
},
_ => {},
} }
} }
} }

View File

@ -67,7 +67,7 @@ impl<T> AVec<T> {
#[inline(always)] #[inline(always)]
fn slot_size(&self) -> usize { fn slot_size(&self) -> usize {
let a = self.align - 1; let a = self.align - 1;
mem::align_of::<T>() + (a) & !a (mem::align_of::<T>() + (a)) & !a
} }
/// # Panics /// # Panics
@ -240,6 +240,11 @@ impl<T> AVec<T> {
self.len self.len
} }
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len == 0
}
/// Returns the capacity of the vector. /// Returns the capacity of the vector.
/// ///
/// The capacity is the amount of elements that the vector can store without reallocating. /// The capacity is the amount of elements that the vector can store without reallocating.

View File

@ -1,6 +1,6 @@
mod node; mod node;
use std::{ use std::{
cell::{Ref, RefCell, RefMut}, collections::{HashMap, VecDeque}, fmt::Debug, hash::Hash, rc::Rc, sync::Arc cell::{Ref, RefCell, RefMut}, collections::VecDeque, fmt::Debug, hash::Hash, rc::Rc, sync::Arc
}; };
use lyra_ecs::World; use lyra_ecs::World;
@ -20,14 +20,13 @@ pub use render_target::*;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use tracing::{debug_span, instrument, trace, warn}; use tracing::{debug_span, instrument, trace, warn};
use wgpu::{CommandEncoder, ComputePass}; use wgpu::CommandEncoder;
use super::resource::{ComputePipeline, Pipeline, RenderPipeline}; use super::resource::{ComputePipeline, Pass, Pipeline, RenderPipeline};
/// A trait that represents the label of a resource, slot, or node in the [`RenderGraph`].
pub trait RenderGraphLabel: Debug + 'static { pub trait RenderGraphLabel: Debug + 'static {
fn rc_clone(&self) -> Rc<dyn RenderGraphLabel>; fn rc_clone(&self) -> Rc<dyn RenderGraphLabel>;
//fn as_dyn(&self) -> &dyn RenderGraphLabel;
//fn as_partial_eq(&self) -> &dyn PartialEq<dyn RenderGraphLabel>;
fn as_label_hash(&self) -> u64; fn as_label_hash(&self) -> u64;
fn label_eq_rc(&self, other: &Rc<dyn RenderGraphLabel>) -> bool { fn label_eq_rc(&self, other: &Rc<dyn RenderGraphLabel>) -> bool {
@ -39,8 +38,7 @@ pub trait RenderGraphLabel: Debug + 'static {
} }
} }
pub struct RenderGraphHash(u64); /// An owned [`RenderGraphLabel`].
#[derive(Clone)] #[derive(Clone)]
pub struct RenderGraphLabelValue(Rc<dyn RenderGraphLabel>); pub struct RenderGraphLabelValue(Rc<dyn RenderGraphLabel>);
@ -82,45 +80,39 @@ impl PartialEq for RenderGraphLabelValue {
impl Eq for RenderGraphLabelValue {} impl Eq for RenderGraphLabelValue {}
struct PassEntry { struct NodeEntry {
/// The Node
inner: Arc<RefCell<dyn Node>>, inner: Arc<RefCell<dyn Node>>,
/// The Node descriptor
desc: Rc<RefCell<NodeDesc>>, desc: Rc<RefCell<NodeDesc>>,
/// The index of the pass in the execution graph /// The index of the node in the execution graph
graph_index: petgraph::matrix_graph::NodeIndex<usize>, graph_index: petgraph::matrix_graph::NodeIndex<usize>,
pipeline: Rc<RefCell<Option<PipelineResource>>>, /// The Node's optional pipeline
pipeline: Rc<RefCell<Option<Pipeline>>>,
} }
#[derive(Clone)] #[derive(Clone)]
pub struct BindGroupEntry { struct BindGroupEntry {
pub label: RenderGraphLabelValue, label: RenderGraphLabelValue,
/// BindGroup /// BindGroup
pub bg: Rc<wgpu::BindGroup>, bg: Rc<wgpu::BindGroup>,
/// BindGroupLayout /// BindGroupLayout
pub layout: Option<Rc<wgpu::BindGroupLayout>>, layout: Option<Rc<wgpu::BindGroupLayout>>,
} }
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Clone)] #[derive(Clone)]
struct ResourcedSlot { struct ResourceSlot {
label: RenderGraphLabelValue, label: RenderGraphLabelValue,
ty: SlotType, ty: SlotType,
value: SlotValue, value: SlotValue,
} }
/// Stores the pipeline and other resources it uses.
///
/// This stores the bind groups that have been created for it
pub struct PipelineResource {
pub pipeline: Pipeline,
/// Lookup map for bind groups using names
pub bg_layout_name_lookup: HashMap<String, u32>,
}
pub struct RenderGraph { pub struct RenderGraph {
device: Arc<wgpu::Device>, device: Arc<wgpu::Device>,
queue: Arc<wgpu::Queue>, queue: Arc<wgpu::Queue>,
slots: FxHashMap<RenderGraphLabelValue, ResourcedSlot>, slots: FxHashMap<RenderGraphLabelValue, ResourceSlot>,
nodes: FxHashMap<RenderGraphLabelValue, PassEntry>, nodes: FxHashMap<RenderGraphLabelValue, NodeEntry>,
sub_graphs: FxHashMap<RenderGraphLabelValue, RenderGraph>, sub_graphs: FxHashMap<RenderGraphLabelValue, RenderGraph>,
bind_groups: FxHashMap<RenderGraphLabelValue, BindGroupEntry>, bind_groups: FxHashMap<RenderGraphLabelValue, BindGroupEntry>,
/// A directed graph used to determine dependencies of nodes. /// A directed graph used to determine dependencies of nodes.
@ -143,7 +135,7 @@ impl RenderGraph {
} }
pub fn device(&self) -> &wgpu::Device { pub fn device(&self) -> &wgpu::Device {
&*self.device &self.device
} }
/// Add a [`Node`] to the RenderGraph. /// Add a [`Node`] to the RenderGraph.
@ -156,39 +148,28 @@ impl RenderGraph {
/// * This means that the id of insert slots **ARE NOT STABLE**. **DO NOT** rely on them to /// * This means that the id of insert slots **ARE NOT STABLE**. **DO NOT** rely on them to
/// not change. The IDs of output slots do stay the same. /// not change. The IDs of output slots do stay the same.
/// 3. Ensuring that no two slots share the same ID when the names do not match. /// 3. Ensuring that no two slots share the same ID when the names do not match.
#[instrument(skip(self, pass), level = "debug")] #[instrument(skip(self, node), level = "debug")]
pub fn add_node<P: Node>(&mut self, label: impl RenderGraphLabel, mut pass: P) { pub fn add_node<P: Node>(&mut self, label: impl RenderGraphLabel, mut node: P) {
let mut desc = pass.desc(self); let mut desc = node.desc(self);
// collect all the slots of the pass // collect all the slots of the node
for slot in &mut desc.slots { for slot in &mut desc.slots {
if let Some(other) = self if let Some(other) = self
.slots .slots
.get_mut(&slot.label) .get_mut(&slot.label)
//.map(|s| (id, s))
//.and_then(|id| self.slots.get_mut(id).map(|s| (id, s)))
{ {
debug_assert_eq!( debug_assert_eq!(
slot.ty, other.ty, slot.ty, other.ty,
"slot {:?} in pass {:?} does not match existing slot of same name", "slot {:?} in node {:?} does not match existing slot of same name",
slot.label, label slot.label, label
); );
/* trace!(
"Found existing slot for {:?}, changing id to {}",
slot.label,
id
); */
// if there is a slot of the same name
//slot.id = *id;
} else { } else {
debug_assert!(!self.slots.contains_key(&slot.label), debug_assert!(!self.slots.contains_key(&slot.label),
"Reuse of id detected in render graph! Pass: {:?}, slot: {:?}", "Reuse of id detected in render graph! Node: {:?}, slot: {:?}",
label, slot.label, label, slot.label,
); );
let res_slot = ResourcedSlot { let res_slot = ResourceSlot {
label: slot.label.clone(), label: slot.label.clone(),
ty: slot.ty, ty: slot.ty,
value: slot.value.clone().unwrap_or(SlotValue::None), value: slot.value.clone().unwrap_or(SlotValue::None),
@ -212,8 +193,8 @@ impl RenderGraph {
self.nodes.insert( self.nodes.insert(
label, label,
PassEntry { NodeEntry {
inner: Arc::new(RefCell::new(pass)), inner: Arc::new(RefCell::new(node)),
desc: Rc::new(RefCell::new(desc)), desc: Rc::new(RefCell::new(desc)),
graph_index: index, graph_index: index,
pipeline: Rc::new(RefCell::new(None)), pipeline: Rc::new(RefCell::new(None)),
@ -221,42 +202,38 @@ impl RenderGraph {
); );
} }
/// Creates all buffers required for the passes, also creates an internal execution path. /// Creates all buffers required for the nodes.
/// ///
/// This only needs to be ran when the [`Node`]s in the graph change, or they are removed or /// This only needs to be ran when the [`Node`]s in the graph change, or they are removed or
/// added. /// added.
#[instrument(skip(self, device))] #[instrument(skip(self, device))]
pub fn setup(&mut self, device: &wgpu::Device) { pub fn setup(&mut self, device: &wgpu::Device) {
// For all passes, create their pipelines // For all nodes, create their pipelines
for pass in self.nodes.values_mut() { for node in self.nodes.values_mut() {
let desc = (*pass.desc).borrow(); let desc = (*node.desc).borrow();
if let Some(pipeline_desc) = &desc.pipeline_desc { if let Some(pipeline_desc) = &desc.pipeline_desc {
let pipeline = match desc.ty { let pipeline = match desc.ty {
NodeType::Render => Pipeline::Render(RenderPipeline::create( NodeType::Render => Pipeline::Render(RenderPipeline::create(
device, device,
pipeline_desc pipeline_desc
.as_render_pipeline_descriptor() .as_render_pipeline_descriptor()
.expect("got compute pipeline descriptor in a render pass"), .expect("got compute pipeline descriptor in a render node"),
)), )),
NodeType::Compute => Pipeline::Compute(ComputePipeline::create( NodeType::Compute => Pipeline::Compute(ComputePipeline::create(
device, device,
pipeline_desc pipeline_desc
.as_compute_pipeline_descriptor() .as_compute_pipeline_descriptor()
.expect("got render pipeline descriptor in a compute pass"), .expect("got render pipeline descriptor in a compute node"),
)), )),
NodeType::Presenter | NodeType::Node | NodeType::Graph => { NodeType::Presenter | NodeType::Node | NodeType::Graph => {
panic!("Present or Node RenderGraph passes should not have a pipeline descriptor!"); panic!("Present or Node RenderGraph nodes should not have a pipeline descriptor!");
}, },
}; };
drop(desc); drop(desc);
let res = PipelineResource {
pipeline,
bg_layout_name_lookup: Default::default(),
};
let mut pipeline = pass.pipeline.borrow_mut(); let mut node_pipeline = node.pipeline.borrow_mut();
*pipeline = Some(res); *node_pipeline = Some(pipeline);
} }
} }
@ -275,18 +252,18 @@ impl RenderGraph {
let mut sorted: VecDeque<RenderGraphLabelValue> = petgraph::algo::toposort(&self.node_graph, None) let mut sorted: VecDeque<RenderGraphLabelValue> = petgraph::algo::toposort(&self.node_graph, None)
.expect("RenderGraph had cycled!") .expect("RenderGraph had cycled!")
.iter() .iter()
.map(|i| self.node_graph[i.clone()].clone()) .map(|i| self.node_graph[*i].clone())
.collect(); .collect();
while let Some(pass_label) = sorted.pop_front() { while let Some(node_label) = sorted.pop_front() {
let pass = self.nodes.get(&pass_label).unwrap(); let node = self.nodes.get(&node_label).unwrap();
let device = self.device.clone(); let device = self.device.clone();
let queue = self.queue.clone(); let queue = self.queue.clone();
let inner = pass.inner.clone(); let inner = node.inner.clone();
let mut inner = inner.borrow_mut(); let mut inner = inner.borrow_mut();
let mut context = RenderGraphContext::new(device, queue, None, pass_label.clone()); let mut context = RenderGraphContext::new(device, queue, None, node_label.clone());
inner.prepare(self, world, &mut context); inner.prepare(self, world, &mut context);
buffer_writes.append(&mut context.buffer_writes); buffer_writes.append(&mut context.buffer_writes);
} }
@ -300,14 +277,12 @@ impl RenderGraph {
let slot = self let slot = self
.slots .slots
.get(&bufwr.target_slot) .get(&bufwr.target_slot)
.expect(&format!( .unwrap_or_else(|| panic!("Failed to find slot '{:?}' for buffer write",
"Failed to find slot '{:?}' for buffer write", bufwr.target_slot));
bufwr.target_slot
));
let buf = slot let buf = slot
.value .value
.as_buffer() .as_buffer()
.expect(&format!("Slot '{:?}' is not a buffer", bufwr.target_slot)); .unwrap_or_else(|| panic!("Slot '{:?}' is not a buffer", bufwr.target_slot));
self.queue.write_buffer(buf, bufwr.offset, &bufwr.bytes); self.queue.write_buffer(buf, bufwr.offset, &bufwr.bytes);
} }
@ -325,7 +300,7 @@ impl RenderGraph {
let mut sorted: VecDeque<RenderGraphLabelValue> = petgraph::algo::toposort(&self.node_graph, None) let mut sorted: VecDeque<RenderGraphLabelValue> = petgraph::algo::toposort(&self.node_graph, None)
.expect("RenderGraph had cycled!") .expect("RenderGraph had cycled!")
.iter() .iter()
.map(|i| self.node_graph[i.clone()].clone()) .map(|i| self.node_graph[*i].clone())
.collect(); .collect();
// A bit of 'encoder hot potato' is played using this. // A bit of 'encoder hot potato' is played using this.
@ -335,12 +310,12 @@ impl RenderGraph {
// the encoder will be submitted and a new one will be made. // the encoder will be submitted and a new one will be made.
let mut encoder = Some(self.create_encoder()); let mut encoder = Some(self.create_encoder());
while let Some(pass_label) = sorted.pop_front() { while let Some(node_label) = sorted.pop_front() {
let pass = self.nodes.get(&pass_label).unwrap(); let node = self.nodes.get(&node_label).unwrap();
let pass_inn = pass.inner.clone(); let node_inn = node.inner.clone();
let pass_desc = pass.desc.clone(); let node_desc = node.desc.clone();
let pass_desc = (*pass_desc).borrow(); let node_desc = (*node_desc).borrow();
// clone of the Rc's is required to appease the borrow checker // clone of the Rc's is required to appease the borrow checker
let device = self.device.clone(); let device = self.device.clone();
@ -351,11 +326,11 @@ impl RenderGraph {
encoder = Some(self.create_encoder()); encoder = Some(self.create_encoder());
} }
let mut context = RenderGraphContext::new(device, queue, encoder.take(), pass_label.clone()); let mut context = RenderGraphContext::new(device, queue, encoder.take(), node_label.clone());
trace!("Executing {:?}", pass_label.0); trace!("Executing {:?}", node_label.0);
let mut inner = pass_inn.borrow_mut(); let mut inner = node_inn.borrow_mut();
inner.execute(self, &pass_desc, &mut context); inner.execute(self, &node_desc, &mut context);
// take back the encoder from the context // take back the encoder from the context
encoder = context.encoder; encoder = context.encoder;
@ -384,8 +359,9 @@ impl RenderGraph {
.and_then(|p| { .and_then(|p| {
let v = p.pipeline.borrow(); let v = p.pipeline.borrow();
#[allow(clippy::manual_map)]
match &*v { match &*v {
Some(_) => Some(Ref::map(v, |p| &p.as_ref().unwrap().pipeline)), Some(_) => Some(Ref::map(v, |p| p.as_ref().unwrap())),
None => None, None => None,
} }
}) })
@ -448,27 +424,26 @@ impl RenderGraph {
/// &mut pass, /// &mut pass,
/// &[ /// &[
/// // retrieves the `BasePassSlots::DepthTexture` bind group and sets the index 0 in the /// // retrieves the `BasePassSlots::DepthTexture` bind group and sets the index 0 in the
/// // pass to it. /// // node to it.
/// (&BasePassSlots::DepthTexture, 0), /// (&BaseNodeSlots::DepthTexture, 0),
/// (&BasePassSlots::Camera, 1), /// (&BaseNodeSlots::Camera, 1),
/// (&LightBasePassSlots::Lights, 2), /// (&LightBaseNodeSlots::Lights, 2),
/// (&LightCullComputePassSlots::LightIndicesGridGroup, 3), /// (&LightCullComputeNodeSlots::LightIndicesGridGroup, 3),
/// (&BasePassSlots::ScreenSize, 4), /// (&BaseNodeSlots::ScreenSize, 4),
/// ], /// ],
/// ); /// );
/// ``` /// ```
/// ///
/// # Panics /// # Panics
/// Panics if a bind group of a provided name is not found. /// Panics if a bind group of a provided name is not found.
pub fn set_bind_groups<'a>( pub fn set_bind_groups<'a, P: Pass<'a>>(
&'a self, &'a self,
pass: &mut ComputePass<'a>, pass: &mut P,
bind_groups: &[(&dyn RenderGraphLabel, u32)], bind_groups: &[(&dyn RenderGraphLabel, u32)],
) { ) {
for (label, index) in bind_groups { for (label, index) in bind_groups {
let bg = self let bg = self
.bind_group(label.rc_clone()); .bind_group(label.rc_clone());
//.expect(&format!("Could not find bind group '{:?}'", label));
pass.set_bind_group(*index, bg, &[]); pass.set_bind_group(*index, bg, &[]);
} }
@ -478,6 +453,9 @@ impl RenderGraph {
self.sub_graphs.get_mut(&label.into()) self.sub_graphs.get_mut(&label.into())
} }
/// Add a sub graph.
///
/// > Note: the sub graph is not ran unless you add a node that executes it. See [`SubGraphNode`].
pub fn add_sub_graph<L: Into<RenderGraphLabelValue>>(&mut self, label: L, sub: RenderGraph) { pub fn add_sub_graph<L: Into<RenderGraphLabelValue>>(&mut self, label: L, sub: RenderGraph) {
self.sub_graphs.insert(label.into(), sub); self.sub_graphs.insert(label.into(), sub);
} }
@ -548,7 +526,7 @@ impl SubGraphNode {
} }
impl Node for SubGraphNode { impl Node for SubGraphNode {
fn desc<'a, 'b>(&'a mut self, _: &'b mut RenderGraph) -> NodeDesc { fn desc(&mut self, _: &mut RenderGraph) -> NodeDesc {
NodeDesc::new(NodeType::Graph, None, vec![]) NodeDesc::new(NodeType::Graph, None, vec![])
} }

View File

@ -145,6 +145,7 @@ pub struct RenderGraphPipelineInfo {
pub multiview: Option<NonZeroU32>, pub multiview: Option<NonZeroU32>,
} }
#[allow(clippy::too_many_arguments)]
impl RenderGraphPipelineInfo { impl RenderGraphPipelineInfo {
pub fn new( pub fn new(
label: &str, label: &str,
@ -160,7 +161,7 @@ impl RenderGraphPipelineInfo {
label: Some(label.to_string()), label: Some(label.to_string()),
bind_group_layouts: bind_group_layouts bind_group_layouts: bind_group_layouts
.into_iter() .into_iter()
.map(|bgl| Rc::new(bgl)) .map(Rc::new)
.collect(), .collect(),
vertex, vertex,
primitive, primitive,
@ -355,7 +356,7 @@ impl NodeDesc {
/// describes all resources the node requires for execution during the `execute` phase. /// describes all resources the node requires for execution during the `execute` phase.
pub trait Node: 'static { pub trait Node: 'static {
/// Retrieve a descriptor of the Node. /// Retrieve a descriptor of the Node.
fn desc<'a, 'b>(&'a mut self, graph: &'b mut RenderGraph) -> NodeDesc; fn desc(&mut self, graph: &mut RenderGraph) -> NodeDesc;
/// Prepare the node for rendering. /// Prepare the node for rendering.
/// ///

View File

@ -55,7 +55,7 @@ impl Node for BasePass {
.visibility(wgpu::ShaderStages::COMPUTE) .visibility(wgpu::ShaderStages::COMPUTE)
.buffer_dynamic_offset(false) .buffer_dynamic_offset(false)
.contents(&[self.screen_size]) .contents(&[self.screen_size])
.finish_parts(&graph.device()); .finish_parts(graph.device());
let screen_size_bgl = Rc::new(screen_size_bgl); let screen_size_bgl = Rc::new(screen_size_bgl);
let screen_size_bg = Rc::new(screen_size_bg); let screen_size_bg = Rc::new(screen_size_bg);
@ -65,12 +65,12 @@ impl Node for BasePass {
.visibility(wgpu::ShaderStages::all()) .visibility(wgpu::ShaderStages::all())
.buffer_dynamic_offset(false) .buffer_dynamic_offset(false)
.contents(&[CameraUniform::default()]) .contents(&[CameraUniform::default()])
.finish_parts(&graph.device()); .finish_parts(graph.device());
let camera_bgl = Rc::new(camera_bgl); let camera_bgl = Rc::new(camera_bgl);
let camera_bg = Rc::new(camera_bg); let camera_bg = Rc::new(camera_bg);
// create the depth texture using the utility struct, then take all the required fields // create the depth texture using the utility struct, then take all the required fields
let mut depth_texture = RenderTexture::create_depth_texture(&graph.device(), self.screen_size, "depth_texture"); let mut depth_texture = RenderTexture::create_depth_texture(graph.device(), self.screen_size, "depth_texture");
depth_texture.create_bind_group(&graph.device); depth_texture.create_bind_group(&graph.device);
let dt_bg_pair = depth_texture.bindgroup_pair.unwrap(); let dt_bg_pair = depth_texture.bindgroup_pair.unwrap();
@ -135,7 +135,6 @@ impl Node for BasePass {
) { ) {
let mut vt = graph.view_target_mut(); let mut vt = graph.view_target_mut();
vt.primary.create_frame(); vt.primary.create_frame();
//vt.next_chain();
vt.primary.create_frame_view(); vt.primary.create_frame_view();
/* debug_assert!( /* debug_assert!(
!rt.current_texture.is_some(), !rt.current_texture.is_some(),

View File

@ -10,7 +10,7 @@ pub struct InitNode {
} }
impl Node for InitNode { impl Node for InitNode {
fn desc<'a, 'b>(&'a mut self, _: &'b mut crate::render::graph::RenderGraph) -> crate::render::graph::NodeDesc { fn desc(&mut self, _: &mut crate::render::graph::RenderGraph) -> crate::render::graph::NodeDesc {
let mut desc = NodeDesc::new(NodeType::Node, None, vec![]); let mut desc = NodeDesc::new(NodeType::Node, None, vec![]);
// the slots can just be cloned since the slot attribute doesn't really matter much. // the slots can just be cloned since the slot attribute doesn't really matter much.
desc.slots = self.slots.clone(); desc.slots = self.slots.clone();

View File

@ -59,7 +59,7 @@ impl Node for LightCullComputePass {
let light_index_counter_buffer = let light_index_counter_buffer =
device.create_buffer_init(&wgpu::util::BufferInitDescriptor { device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("light_index_counter_buffer"), label: Some("light_index_counter_buffer"),
contents: &bytemuck::cast_slice(&[0]), contents: bytemuck::cast_slice(&[0]),
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
}); });

View File

@ -174,12 +174,12 @@ impl MeshPass {
let material = self.material_buffers.entry(material.uuid()) let material = self.material_buffers.entry(material.uuid())
.or_insert_with(|| { .or_insert_with(|| {
debug!(uuid=material.uuid().to_string(), "Sending material to gpu"); debug!(uuid=material.uuid().to_string(), "Sending material to gpu");
Rc::new(Material::from_resource(&device, &queue, self.texture_bind_group_layout.clone().unwrap(), &material_ref)) Rc::new(Material::from_resource(device, queue, self.texture_bind_group_layout.clone().unwrap(), &material_ref))
}); });
// TODO: support material uniforms from multiple uniforms // TODO: support material uniforms from multiple uniforms
let uni = MaterialUniform::from(&**material); let uni = MaterialUniform::from(&**material);
queue.write_buffer(&self.material_buffer.as_ref().unwrap(), 0, bytemuck::bytes_of(&uni)); queue.write_buffer(self.material_buffer.as_ref().unwrap(), 0, bytemuck::bytes_of(&uni));
MeshBufferStorage { MeshBufferStorage {
buffer_vertex: vertex_buffer, buffer_vertex: vertex_buffer,
@ -215,7 +215,7 @@ impl Node for MeshPass {
//let transform_bgl = transforms.bindgroup_layout.clone(); //let transform_bgl = transforms.bindgroup_layout.clone();
self.transforms = Some(transforms); self.transforms = Some(transforms);
let texture_bind_group_layout = Rc::new(RenderTexture::create_layout(&device)); let texture_bind_group_layout = Rc::new(RenderTexture::create_layout(device));
self.texture_bind_group_layout = Some(texture_bind_group_layout.clone()); self.texture_bind_group_layout = Some(texture_bind_group_layout.clone());
let (material_bgl, material_bg, material_buf, _) = BufferWrapper::builder() let (material_bgl, material_bg, material_buf, _) = BufferWrapper::builder()
@ -232,7 +232,7 @@ impl Node for MeshPass {
// load the default texture // load the default texture
let bytes = include_bytes!("../../default_texture.png"); let bytes = include_bytes!("../../default_texture.png");
self.default_texture = Some(RenderTexture::from_bytes(&device, &graph.queue, texture_bind_group_layout.clone(), bytes, "default_texture").unwrap()); self.default_texture = Some(RenderTexture::from_bytes(device, &graph.queue, texture_bind_group_layout.clone(), bytes, "default_texture").unwrap());
// get surface config format // get surface config format
/* let main_rt = graph.slot_value(BasePassSlots::MainRenderTarget) /* let main_rt = graph.slot_value(BasePassSlots::MainRenderTarget)
@ -251,7 +251,9 @@ impl Node for MeshPass {
source: include_str!("../../shaders/base.wgsl").to_string(), source: include_str!("../../shaders/base.wgsl").to_string(),
}); */ }); */
let desc = NodeDesc::new(
NodeDesc::new(
NodeType::Render, NodeType::Render,
None, None,
/* Some(PipelineDescriptor::Render(RenderPipelineDescriptor { /* Some(PipelineDescriptor::Render(RenderPipelineDescriptor {
@ -296,9 +298,7 @@ impl Node for MeshPass {
vec![ vec![
(&MeshesPassSlots::Material, material_bg, Some(material_bgl)), (&MeshesPassSlots::Material, material_bg, Some(material_bgl)),
], ],
); )
desc
} }
#[instrument(skip(self, graph, world, context))] #[instrument(skip(self, graph, world, context))]
@ -368,7 +368,7 @@ impl Node for MeshPass {
let transforms = self.transforms.as_mut().unwrap(); let transforms = self.transforms.as_mut().unwrap();
if transforms.needs_expand() { if transforms.needs_expand() {
debug!("Expanding transform buffers"); debug!("Expanding transform buffers");
transforms.expand_buffers(&device); transforms.expand_buffers(device);
} }
} }
@ -377,14 +377,14 @@ impl Node for MeshPass {
// if process mesh did not just create a new mesh, and the epoch // if process mesh did not just create a new mesh, and the epoch
// shows that the scene has changed, verify that the mesh buffers // shows that the scene has changed, verify that the mesh buffers
// dont need to be resent to the gpu. // dont need to be resent to the gpu.
if !self.process_mesh(&device, &queue, entity, &*mesh, mesh_han.uuid()) if !self.process_mesh(device, queue, entity, &mesh, mesh_han.uuid())
&& mesh_epoch == last_epoch { && mesh_epoch == last_epoch {
self.check_mesh_buffers(&device, &queue, &mesh_han); self.check_mesh_buffers(device, queue, &mesh_han);
} }
let transforms = self.transforms.as_mut().unwrap(); let transforms = self.transforms.as_mut().unwrap();
let group = TransformGroup::EntityRes(entity, mesh_han.uuid()); let group = TransformGroup::EntityRes(entity, mesh_han.uuid());
let transform_id = transforms.update_or_push(&device, &queue, &render_limits, let transform_id = transforms.update_or_push(device, queue, &render_limits,
group, interp_transform.calculate_mat4(), glam::Mat3::from_quat(interp_transform.rotation)); group, interp_transform.calculate_mat4(), glam::Mat3::from_quat(interp_transform.rotation));
let material = mesh.material.as_ref().unwrap() let material = mesh.material.as_ref().unwrap()
@ -409,15 +409,15 @@ impl Node for MeshPass {
// if process mesh did not just create a new mesh, and the epoch // if process mesh did not just create a new mesh, and the epoch
// shows that the scene has changed, verify that the mesh buffers // shows that the scene has changed, verify that the mesh buffers
// dont need to be resent to the gpu. // dont need to be resent to the gpu.
if !self.process_mesh(&device, &queue, entity, &*mesh, mesh_han.uuid()) if !self.process_mesh(device, queue, entity, &mesh, mesh_han.uuid())
&& scene_epoch == last_epoch { && scene_epoch == last_epoch {
self.check_mesh_buffers(&device, &queue, &mesh_han); self.check_mesh_buffers(device, queue, &mesh_han);
} }
let transforms = self.transforms.as_mut().unwrap(); let transforms = self.transforms.as_mut().unwrap();
let scene_mesh_group = TransformGroup::Res(scene_han.uuid(), mesh_han.uuid()); let scene_mesh_group = TransformGroup::Res(scene_han.uuid(), mesh_han.uuid());
let group = TransformGroup::OwnedGroup(entity, scene_mesh_group.into()); let group = TransformGroup::OwnedGroup(entity, scene_mesh_group.into());
let transform_id = transforms.update_or_push(&device, &queue, &render_limits, let transform_id = transforms.update_or_push(device, queue, &render_limits,
group, mesh_interpo.calculate_mat4(), glam::Mat3::from_quat(mesh_interpo.rotation) ); group, mesh_interpo.calculate_mat4(), glam::Mat3::from_quat(mesh_interpo.rotation) );
let material = mesh.material.as_ref().unwrap() let material = mesh.material.as_ref().unwrap()
@ -436,7 +436,7 @@ impl Node for MeshPass {
} }
let transforms = self.transforms.as_mut().unwrap(); let transforms = self.transforms.as_mut().unwrap();
transforms.send_to_gpu(&queue); transforms.send_to_gpu(queue);
if self.pipeline.is_none() { if self.pipeline.is_none() {
let device = graph.device(); let device = graph.device();
@ -537,7 +537,7 @@ impl Node for MeshPass {
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"), label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment { color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view, view,
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color { load: wgpu::LoadOp::Clear(wgpu::Color {
@ -551,7 +551,7 @@ impl Node for MeshPass {
})], })],
// enable depth buffer // enable depth buffer
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &depth_view, view: depth_view,
depth_ops: Some(wgpu::Operations { depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0), load: wgpu::LoadOp::Clear(1.0),
store: true, store: true,
@ -560,7 +560,7 @@ impl Node for MeshPass {
}), }),
}); });
pass.set_pipeline(&pipeline); pass.set_pipeline(pipeline);
//let material_buffer_bg = self.material_buffer.as_ref().unwrap().bindgroup(); //let material_buffer_bg = self.material_buffer.as_ref().unwrap().bindgroup();
let default_texture = self.default_texture.as_ref().unwrap(); let default_texture = self.default_texture.as_ref().unwrap();
@ -596,11 +596,11 @@ impl Node for MeshPass {
let offset = transforms.buffer_offset(job.transform_id); let offset = transforms.buffer_offset(job.transform_id);
pass.set_bind_group(1, bindgroup, &[ offset, ]); pass.set_bind_group(1, bindgroup, &[ offset, ]);
pass.set_bind_group(2, &camera_bg, &[]); pass.set_bind_group(2, camera_bg, &[]);
pass.set_bind_group(3, &lights_bg, &[]); pass.set_bind_group(3, lights_bg, &[]);
pass.set_bind_group(4, &material_bg, &[]); pass.set_bind_group(4, material_bg, &[]);
pass.set_bind_group(6, &light_grid_bg, &[]); pass.set_bind_group(6, light_grid_bg, &[]);
// if this mesh uses indices, use them to draw the mesh // if this mesh uses indices, use them to draw the mesh
if let Some((idx_type, indices)) = buffers.buffer_indices.as_ref() { if let Some((idx_type, indices)) = buffers.buffer_indices.as_ref() {

View File

@ -15,7 +15,7 @@ pub struct PresentPass;
impl PresentPass { impl PresentPass {
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self
} }
} }

View File

@ -7,15 +7,6 @@ use crate::render::{
resource::{FragmentState, PipelineDescriptor, RenderPipelineDescriptor, Shader, VertexState}, resource::{FragmentState, PipelineDescriptor, RenderPipelineDescriptor, Shader, VertexState},
}; };
#[derive(Debug, Clone, Copy, Hash, RenderGraphLabel)]
pub enum TintPassSlots {
InputRenderTarget,
InputTextureView,
TextureViewBindGroup,
Frame,
}
#[derive(Default, Debug, Clone, Copy, Hash, RenderGraphLabel)] #[derive(Default, Debug, Clone, Copy, Hash, RenderGraphLabel)]
pub struct TintPassLabel; pub struct TintPassLabel;
@ -23,6 +14,9 @@ pub struct TintPassLabel;
pub struct TintPass { pub struct TintPass {
target_sampler: Option<wgpu::Sampler>, target_sampler: Option<wgpu::Sampler>,
bgl: Option<Rc<wgpu::BindGroupLayout>>, bgl: Option<Rc<wgpu::BindGroupLayout>>,
/// Store bind groups for the input textures.
/// The texture may change due to resizes, or changes to the view target chain
/// from other nodes.
bg_cache: HashMap<wgpu::Id, wgpu::BindGroup>, bg_cache: HashMap<wgpu::Id, wgpu::BindGroup>,
} }
@ -33,9 +27,9 @@ impl TintPass {
} }
impl Node for TintPass { impl Node for TintPass {
fn desc<'a, 'b>( fn desc(
&'a mut self, &mut self,
graph: &'b mut crate::render::graph::RenderGraph, graph: &mut crate::render::graph::RenderGraph,
) -> crate::render::graph::NodeDesc { ) -> crate::render::graph::NodeDesc {
let device = &graph.device; let device = &graph.device;
@ -70,7 +64,9 @@ impl Node for TintPass {
}); });
let vt = graph.view_target(); let vt = graph.view_target();
let desc = NodeDesc::new(
NodeDesc::new(
NodeType::Render, NodeType::Render,
Some(PipelineDescriptor::Render(RenderPipelineDescriptor { Some(PipelineDescriptor::Render(RenderPipelineDescriptor {
label: Some("tint_pass".into()), label: Some("tint_pass".into()),
@ -96,9 +92,7 @@ impl Node for TintPass {
multiview: None, multiview: None,
})), })),
vec![], vec![],
); )
desc
} }
fn prepare( fn prepare(
@ -118,7 +112,7 @@ impl Node for TintPass {
) { ) {
let pipeline = graph let pipeline = graph
.pipeline(context.label.clone()) .pipeline(context.label.clone())
.expect("Failed to find pipeline for MeshPass"); .expect("Failed to find pipeline for TintPass");
let mut vt = graph.view_target_mut(); let mut vt = graph.view_target_mut();
let chain = vt.get_chain(); let chain = vt.get_chain();
@ -154,7 +148,7 @@ impl Node for TintPass {
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("tint_pass"), label: Some("tint_pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment { color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &dest_view, view: dest_view,
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Load, load: wgpu::LoadOp::Load,
@ -163,7 +157,7 @@ impl Node for TintPass {
})], })],
depth_stencil_attachment: None, depth_stencil_attachment: None,
}); });
pass.set_pipeline(&pipeline.as_render()); pass.set_pipeline(pipeline.as_render());
pass.set_bind_group(0, bg, &[]); pass.set_bind_group(0, bg, &[]);
pass.draw(0..3, 0..1); pass.draw(0..3, 0..1);

View File

@ -116,8 +116,6 @@ pub enum FrameTexture {
/// Represents the current frame that is being rendered to. /// Represents the current frame that is being rendered to.
//#[allow(dead_code)] //#[allow(dead_code)]
pub struct Frame { pub struct Frame {
/* pub(crate) device: Arc<wgpu::Device>,
pub(crate) queue: Arc<wgpu::Queue>, */
pub(crate) size: math::UVec2, pub(crate) size: math::UVec2,
pub(crate) texture: FrameTexture, pub(crate) texture: FrameTexture,
} }
@ -189,8 +187,6 @@ impl FrameTarget {
} }
} }
//struct TargetViewChainPrimary
pub struct TargetViewChain<'a> { pub struct TargetViewChain<'a> {
pub source: &'a mut FrameTarget, pub source: &'a mut FrameTarget,
pub dest: &'a mut FrameTarget, pub dest: &'a mut FrameTarget,
@ -204,6 +200,7 @@ struct ViewChain {
} }
impl ViewChain { impl ViewChain {
/// Returns the currently active [`FrameTarget`].
fn active(&self) -> &FrameTarget { fn active(&self) -> &FrameTarget {
if self.active == 0 { if self.active == 0 {
&self.source &self.source
@ -234,14 +231,17 @@ impl ViewTarget {
s s
} }
/// Returns the size of the target.
pub fn size(&self) -> math::UVec2 { pub fn size(&self) -> math::UVec2 {
self.primary.size() self.primary.size()
} }
/// Returns the [`wgpu::TextureFormat`]
pub fn format(&self) -> wgpu::TextureFormat { pub fn format(&self) -> wgpu::TextureFormat {
self.primary.format() self.primary.format()
} }
/// Resize all the targets, causes the chain to be recreated.
pub fn resize(&mut self, device: &wgpu::Device, size: math::UVec2) { pub fn resize(&mut self, device: &wgpu::Device, size: math::UVec2) {
if size != self.primary.size() { if size != self.primary.size() {
self.primary.render_target.resize(device, size); self.primary.render_target.resize(device, size);
@ -300,7 +300,7 @@ impl ViewTarget {
} }
} }
/// Get the [`wgpu::TextureView`] to render to /// Get the [`wgpu::TextureView`] to render to.
pub fn render_view(&self) -> &wgpu::TextureView { pub fn render_view(&self) -> &wgpu::TextureView {
let chain = self.chain.as_ref().unwrap(); let chain = self.chain.as_ref().unwrap();
chain.active().frame_view.as_ref().unwrap() chain.active().frame_view.as_ref().unwrap()

View File

@ -116,9 +116,9 @@ impl BufferWrapper {
/// match the layout of this bind group. /// match the layout of this bind group.
/// ///
/// See [`wgpu::RenderPass::set_bind_group`](https://docs.rs/wgpu/latest/wgpu/struct.RenderPass.html#method.set_bind_group). /// See [`wgpu::RenderPass::set_bind_group`](https://docs.rs/wgpu/latest/wgpu/struct.RenderPass.html#method.set_bind_group).
pub fn render_pass_bind_at<'a, 'b>( pub fn render_pass_bind_at<'a>(
&'a self, &'a self,
pass: &'b mut wgpu::RenderPass<'a>, pass: &mut wgpu::RenderPass<'a>,
index: u32, index: u32,
offsets: &[wgpu::DynamicOffset], offsets: &[wgpu::DynamicOffset],
) { ) {

View File

@ -168,7 +168,7 @@ impl BasicRenderer {
main_graph.add_edge(TestSubGraphLabel, TintPassLabel); main_graph.add_edge(TestSubGraphLabel, TintPassLabel);
//let present_pass_label = PresentPassLabel::new(BasePassSlots::Frame);//TintPassSlots::Frame); //let present_pass_label = PresentPassLabel::new(BasePassSlots::Frame);//TintPassSlots::Frame);
let p = PresentPass::default(); let p = PresentPass;
main_graph.add_node(PresentPassLabel, p); main_graph.add_node(PresentPassLabel, p);
main_graph.add_edge(BasePassLabel, TestSubGraphLabel); main_graph.add_edge(BasePassLabel, TestSubGraphLabel);

View File

@ -74,7 +74,7 @@ impl ComputePipeline {
// they share the same shader. I tried to do it without an Rc but couldn't get past // they share the same shader. I tried to do it without an Rc but couldn't get past
// the borrow checker // the borrow checker
let compiled_shader = Rc::new(device.create_shader_module(wgpu::ShaderModuleDescriptor { let compiled_shader = Rc::new(device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: desc.shader.label.as_ref().map(|s| s.as_str()), label: desc.shader.label.as_deref(),
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(
&desc.shader.source, &desc.shader.source,
)), )),

View File

@ -8,4 +8,7 @@ mod compute_pipeline;
pub use compute_pipeline::*; pub use compute_pipeline::*;
mod render_pipeline; mod render_pipeline;
pub use render_pipeline::*; pub use render_pipeline::*;
mod pass;
pub use pass::*;

View File

@ -0,0 +1,16 @@
/// A trait that represents a [`wgpu::ComputePass`] or [`wgpu::RenderPass`].
pub trait Pass<'a> {
fn set_bind_group(&mut self, index: u32, bind_group: &'a wgpu::BindGroup, offsets: &[wgpu::DynamicOffset]);
}
impl<'a> Pass<'a> for wgpu::ComputePass<'a> {
fn set_bind_group(&mut self, index: u32, bind_group: &'a wgpu::BindGroup, offsets: &[wgpu::DynamicOffset]) {
self.set_bind_group(index, bind_group, offsets);
}
}
impl<'a> Pass<'a> for wgpu::RenderPass<'a> {
fn set_bind_group(&mut self, index: u32, bind_group: &'a wgpu::BindGroup, offsets: &[wgpu::DynamicOffset]) {
self.set_bind_group(index, bind_group, offsets);
}
}

View File

@ -1,5 +1,6 @@
use super::{compute_pipeline::ComputePipeline, render_pipeline::RenderPipeline, ComputePipelineDescriptor, RenderPipelineDescriptor}; use super::{compute_pipeline::ComputePipeline, render_pipeline::RenderPipeline, ComputePipelineDescriptor, RenderPipelineDescriptor};
#[allow(clippy::large_enum_variant)]
pub enum PipelineDescriptor { pub enum PipelineDescriptor {
Render(RenderPipelineDescriptor), Render(RenderPipelineDescriptor),
Compute(ComputePipelineDescriptor), Compute(ComputePipelineDescriptor),
@ -26,19 +27,19 @@ pub enum Pipeline {
Compute(ComputePipeline), Compute(ComputePipeline),
} }
impl Into<RenderPipeline> for Pipeline { impl From<Pipeline> for RenderPipeline {
fn into(self) -> RenderPipeline { fn from(val: Pipeline) -> Self {
match self { match val {
Self::Render(r) => r, Pipeline::Render(r) => r,
_ => panic!("Pipeline is not a RenderPipeline"), _ => panic!("Pipeline is not a RenderPipeline"),
} }
} }
} }
impl Into<ComputePipeline> for Pipeline { impl From<Pipeline> for ComputePipeline {
fn into(self) -> ComputePipeline { fn from(val: Pipeline) -> Self {
match self { match val {
Self::Compute(c) => c, Pipeline::Compute(c) => c,
_ => panic!("Pipeline is not a RenderPipeline"), _ => panic!("Pipeline is not a RenderPipeline"),
} }
} }

View File

@ -88,13 +88,13 @@ impl RenderPipeline {
// they share the same shader. I tried to do it without an Rc but couldn't get past // they share the same shader. I tried to do it without an Rc but couldn't get past
// the borrow checker // the borrow checker
let vrtx_shad = Rc::new(device.create_shader_module(wgpu::ShaderModuleDescriptor { let vrtx_shad = Rc::new(device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: desc.vertex.module.label.as_ref().map(|s| s.as_str()), label: desc.vertex.module.label.as_deref(),
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(
&desc.vertex.module.source, &desc.vertex.module.source,
)), )),
})); }));
let vrtx_state = wgpu::VertexState { let vrtx_state = wgpu::VertexState {
module: &*vrtx_shad, module: &vrtx_shad,
entry_point: &desc.vertex.entry_point, entry_point: &desc.vertex.entry_point,
buffers: &vrtx_buffs, buffers: &vrtx_buffs,
}; };
@ -104,7 +104,7 @@ impl RenderPipeline {
vrtx_shad.clone() vrtx_shad.clone()
} else { } else {
Rc::new(device.create_shader_module(wgpu::ShaderModuleDescriptor { Rc::new(device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: f.module.label.as_ref().map(|s| s.as_str()), label: f.module.label.as_deref(),
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(&f.module.source)), source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(&f.module.source)),
})) }))
} }

View File

@ -106,14 +106,17 @@ impl<K: Hash + Eq + PartialEq + Clone, V: Clone, S: BuildHasher> CachedValMap<K,
where where
F: FnMut() -> V F: FnMut() -> V
{ {
if self.latest.contains_key(&key) { match self.latest.entry(key) {
self.latest.insert(key, val_fn()); std::collections::hash_map::Entry::Occupied(mut e) => {
None e.insert(val_fn());
} else { None
let val = self.dead.pop_front() }
.unwrap_or_else(val_fn); std::collections::hash_map::Entry::Vacant(e) => {
self.latest.insert(key, val.clone()); let val = self.dead.pop_front()
Some(val) .unwrap_or_else(val_fn);
e.insert(val.clone());
Some(val)
}
} }
} }
@ -217,7 +220,7 @@ impl TransformBuffers {
entry.len = 0; entry.len = 0;
let p = entry.transforms.as_ptr(); let p = entry.transforms.as_ptr();
let bytes = unsafe { std::slice::from_raw_parts(p as *const u8, entry.transforms.len() * entry.transforms.align()) }; let bytes = unsafe { std::slice::from_raw_parts(p, entry.transforms.len() * entry.transforms.align()) };
queue.write_buffer(&entry.buffer, 0, bytes); queue.write_buffer(&entry.buffer, 0, bytes);
} }
@ -334,9 +337,9 @@ impl TransformBuffers {
pub fn buffer_offset(&self, transform_index: TransformIndex) -> u32 { pub fn buffer_offset(&self, transform_index: TransformIndex) -> u32 {
//Self::get_buffer_offset(&self.limits, transform_index) //Self::get_buffer_offset(&self.limits, transform_index)
let transform_index = transform_index.transform_index % self.max_transform_count; let transform_index = transform_index.transform_index % self.max_transform_count;
let t = transform_index as u32 * self.limits.min_uniform_buffer_offset_alignment as u32;
//debug!("offset: {t}"); //debug!("offset: {t}");
t transform_index as u32 * self.limits.min_uniform_buffer_offset_alignment
} }
/// Returns a boolean indicating if the buffers need to be expanded /// Returns a boolean indicating if the buffers need to be expanded