render: improve fix for rendering shared 3d modules
This commit is contained in:
parent
dd61e8e66c
commit
0a9e5ebcdb
|
@ -1,14 +1,16 @@
|
||||||
use lyra_ecs::Entity;
|
use lyra_ecs::Entity;
|
||||||
|
|
||||||
|
use super::transform_buffer_storage::TransformIndex;
|
||||||
|
|
||||||
pub struct RenderJob {
|
pub struct RenderJob {
|
||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
pub shader_id: u64,
|
pub shader_id: u64,
|
||||||
pub mesh_uuid: uuid::Uuid,
|
pub mesh_uuid: uuid::Uuid,
|
||||||
pub transform_id: u32,
|
pub transform_id: TransformIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderJob {
|
impl RenderJob {
|
||||||
pub fn new(entity: Entity, shader_id: u64, mesh_buffer_id: uuid::Uuid, transform_id: u32) -> Self {
|
pub fn new(entity: Entity, shader_id: u64, mesh_buffer_id: uuid::Uuid, transform_id: TransformIndex) -> Self {
|
||||||
Self {
|
Self {
|
||||||
entity,
|
entity,
|
||||||
shader_id,
|
shader_id,
|
||||||
|
|
|
@ -29,7 +29,7 @@ use super::light_cull_compute::LightCullCompute;
|
||||||
use super::material::Material;
|
use super::material::Material;
|
||||||
use super::render_buffer::BufferWrapper;
|
use super::render_buffer::BufferWrapper;
|
||||||
use super::texture::RenderTexture;
|
use super::texture::RenderTexture;
|
||||||
use super::transform_buffer_storage::TransformBuffers;
|
use super::transform_buffer_storage::{TransformBuffers, TransformGroup};
|
||||||
use super::vertex::Vertex;
|
use super::vertex::Vertex;
|
||||||
use super::{render_pipeline::FullRenderPipeline, render_buffer::BufferStorage, render_job::RenderJob};
|
use super::{render_pipeline::FullRenderPipeline, render_buffer::BufferStorage, render_job::RenderJob};
|
||||||
|
|
||||||
|
@ -452,8 +452,10 @@ impl Renderer for BasicRenderer {
|
||||||
self.check_mesh_buffers(entity, &mesh_han);
|
self.check_mesh_buffers(entity, &mesh_han);
|
||||||
}
|
}
|
||||||
|
|
||||||
let transform_id = self.transform_buffers.push_transform(&self.queue, &self.render_limits, interop_pos.calculate_mat4(), glam::Mat3::from_quat(interop_pos.rotation));
|
let group = TransformGroup::EntityRes(entity, mesh_han.uuid());
|
||||||
|
let transform_id = self.transform_buffers.update_or_push(&self.queue, &self.render_limits,
|
||||||
|
group, || ( interop_pos.calculate_mat4(), glam::Mat3::from_quat(interop_pos.rotation) ));
|
||||||
|
|
||||||
let material = mesh.material.as_ref().unwrap()
|
let material = mesh.material.as_ref().unwrap()
|
||||||
.data_ref().unwrap();
|
.data_ref().unwrap();
|
||||||
let shader = material.shader_uuid.unwrap_or(0);
|
let shader = material.shader_uuid.unwrap_or(0);
|
||||||
|
@ -482,7 +484,10 @@ impl Renderer for BasicRenderer {
|
||||||
self.check_mesh_buffers(entity, &mesh_han);
|
self.check_mesh_buffers(entity, &mesh_han);
|
||||||
}
|
}
|
||||||
|
|
||||||
let transform_id = self.transform_buffers.push_transform(&self.queue, &self.render_limits, mesh_interpo.calculate_mat4(), glam::Mat3::from_quat(mesh_interpo.rotation));
|
let scene_mesh_group = TransformGroup::Res(scene_han.uuid(), mesh_han.uuid());
|
||||||
|
let group = TransformGroup::OwnedGroup(entity, scene_mesh_group.into());
|
||||||
|
let transform_id = self.transform_buffers.update_or_push(&self.queue, &self.render_limits,
|
||||||
|
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()
|
||||||
.data_ref().unwrap();
|
.data_ref().unwrap();
|
||||||
|
@ -581,11 +586,8 @@ impl Renderer for BasicRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the bindgroup for job's transform and bind to it using an offset.
|
// Get the bindgroup for job's transform and bind to it using an offset.
|
||||||
/* let transform_indices = *self.transform_buffers.transform_indices(job.entity).unwrap();
|
|
||||||
let bindgroup = self.transform_buffers.bind_group(transform_indices).unwrap(); */
|
|
||||||
|
|
||||||
let bindgroup = self.transform_buffers.bind_group(job.transform_id);
|
let bindgroup = self.transform_buffers.bind_group(job.transform_id);
|
||||||
let offset = self.transform_buffers.buffer_offset(job.transform_id);//TransformBuffers::index_offset(&self.render_limits, transform_indices) as u32;
|
let offset = self.transform_buffers.buffer_offset(job.transform_id);
|
||||||
render_pass.set_bind_group(1, bindgroup, &[ offset, offset, ]);
|
render_pass.set_bind_group(1, bindgroup, &[ offset, offset, ]);
|
||||||
|
|
||||||
render_pass.set_bind_group(2, &self.camera_buffer.bindgroup(), &[]);
|
render_pass.set_bind_group(2, &self.camera_buffer.bindgroup(), &[]);
|
||||||
|
|
|
@ -1,37 +1,167 @@
|
||||||
use std::num::NonZeroU64;
|
use std::{collections::{HashMap, VecDeque}, hash::{BuildHasher, DefaultHasher, Hash, Hasher, RandomState}, num::NonZeroU64};
|
||||||
|
|
||||||
|
use lyra_ecs::Entity;
|
||||||
|
use uuid::Uuid;
|
||||||
use wgpu::Limits;
|
use wgpu::Limits;
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
/// A group id created from a [`TransformGroup`].
|
||||||
|
///
|
||||||
|
/// This is mainly created so that [`TransformGroup::OwnedGroup`] can use another group inside of it.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct TransformGroupId(u64);
|
||||||
|
|
||||||
|
impl From<TransformGroup> for TransformGroupId {
|
||||||
|
fn from(value: TransformGroup) -> Self {
|
||||||
|
let mut hasher = DefaultHasher::new();
|
||||||
|
value.hash(&mut hasher);
|
||||||
|
let hash = hasher.finish();
|
||||||
|
|
||||||
|
TransformGroupId(hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used as a key into the [`TransformBuffers`].
|
||||||
|
///
|
||||||
|
/// This enum is used as a key to identify a transform for a RenderJob. The renderer uses this
|
||||||
|
/// to differentiate a transform between two entities that share a resource handle to the same
|
||||||
|
/// scene:
|
||||||
|
/// ```nobuild
|
||||||
|
/// // The group of the mesh in the scene.
|
||||||
|
/// let scene_mesh_group = TransformGroup::Res(scene_handle.uuid(), mesh_handle.uuid());
|
||||||
|
/// // The group of the owned entity that has mesh in a scene.
|
||||||
|
/// let finished_group = TransformGroup::OwnedGroup(entity, scene_mesh_group.into());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// A simpler example of the use of a transform group is when processing lone mesh handles
|
||||||
|
/// owned by entities:
|
||||||
|
/// ```nobuild
|
||||||
|
/// let group = TransformGroup::EntityRes(entity, mesh_handle.uuid());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// These were made to fix [#6](https://git.seanomik.net/SeanOMik/lyra-engine/issues/6).
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum TransformGroup {
|
||||||
|
/// Just an entity.
|
||||||
|
Entity(Entity),
|
||||||
|
/// An entity that owns another group.
|
||||||
|
OwnedGroup(Entity, TransformGroupId),
|
||||||
|
/// A resource uuid grouped with an owning Entity.
|
||||||
|
EntityRes(Entity, Uuid),
|
||||||
|
/// A resource uuid grouped with another resource uuid.
|
||||||
|
Res(Uuid, Uuid),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The index of a specific Transform inside of the buffers.
|
||||||
#[derive(Default, Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Default, Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub(crate) struct TransformBufferIndices {
|
pub struct TransformIndex {
|
||||||
pub buffer_index: usize,
|
/// The index of the entry in the buffer chain.
|
||||||
pub transform_index: usize,
|
entry_index: usize,
|
||||||
|
/// The index of the transform in the entry.
|
||||||
|
transform_index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct representing a single transform buffer. There can be multiple of these
|
/// A struct representing a single transform buffer. There can be multiple of these
|
||||||
pub(crate) struct TransformBufferEntry {
|
struct BufferEntry {
|
||||||
pub len: usize,
|
pub len: usize,
|
||||||
pub bindgroup: wgpu::BindGroup,
|
pub bindgroup: wgpu::BindGroup,
|
||||||
pub transform_buffer: wgpu::Buffer,
|
pub transform_buffer: wgpu::Buffer,
|
||||||
pub normal_buffer: wgpu::Buffer,
|
pub normal_buffer: wgpu::Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A HashMap that caches values for reuse.
|
||||||
|
///
|
||||||
|
/// The map detects dead values by tracking which entries were not updated since the last time
|
||||||
|
/// [`CachedValMap::update`] was ran. When dead values are collected, they can be reused on an
|
||||||
|
/// [`insert`](CachedValMap::insert) into the map.
|
||||||
|
struct CachedValMap<K, V, S = RandomState> {
|
||||||
|
latest: HashMap<K, V, S>,
|
||||||
|
old: HashMap<K, V, S>,
|
||||||
|
dead: VecDeque<V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V, S: Default> Default for CachedValMap<K, V, S> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
latest: Default::default(),
|
||||||
|
old: Default::default(),
|
||||||
|
dead: Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl<K: Hash + Eq + PartialEq + Clone, V: Clone, S: BuildHasher> CachedValMap<K, V, S> {
|
||||||
|
/// Insert a key, possibly reusing a value in the map.
|
||||||
|
///
|
||||||
|
/// Returns the reused value, if one was reused. If its `None`, then the value was retrieved
|
||||||
|
/// from running `val_fn`.
|
||||||
|
pub fn insert<F>(&mut self, key: K, mut val_fn: F) -> Option<V>
|
||||||
|
where
|
||||||
|
F: FnMut() -> V
|
||||||
|
{
|
||||||
|
if self.latest.contains_key(&key) {
|
||||||
|
self.latest.insert(key, val_fn());
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let val = self.dead.pop_front()
|
||||||
|
.unwrap_or_else(val_fn);
|
||||||
|
self.latest.insert(key, val.clone());
|
||||||
|
Some(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the value corresponding to the key.
|
||||||
|
pub fn get(&mut self, key: K) -> Option<&V> {
|
||||||
|
if let Some(v) = self.old.remove(&key) {
|
||||||
|
self.latest.insert(key.clone(), v);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.latest.get(&key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Keep a key alive without updating its value.
|
||||||
|
pub fn keep_alive(&mut self, key: K) {
|
||||||
|
if let Some(v) = self.old.remove(&key) {
|
||||||
|
self.latest.insert(key, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the map contains a value for the specified key.
|
||||||
|
pub fn contains(&self, key: K) -> bool {
|
||||||
|
self.old.contains_key(&key) || self.latest.contains_key(&key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects the now dead values for reuse.
|
||||||
|
///
|
||||||
|
/// This detects dead values by tracking which entries were not updated since the last time
|
||||||
|
/// update was ran.
|
||||||
|
pub fn update(&mut self) {
|
||||||
|
// drain the dead values into the dead queue
|
||||||
|
self.dead.extend(self.old.drain().map(|(_, v)| v));
|
||||||
|
|
||||||
|
// now drain the latest entries into the old entries
|
||||||
|
self.old.extend(self.latest.drain());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A helper struct for managing the Transform buffers for meshes.
|
/// A helper struct for managing the Transform buffers for meshes.
|
||||||
///
|
///
|
||||||
/// This struct manages a "chain" of uniform buffers that store Transform for meshes. When
|
/// This struct manages a "chain" of uniform buffers that store Transform for [`TransformGroup`]s.
|
||||||
/// first created it only has a single "chain-link" with a buffer that is the maximum length
|
/// When first created it only has a single "chain-link" with a buffer that is the maximum length
|
||||||
/// the GPU supports. When the first buffer fills up, a new one should be created which will also
|
/// the GPU supports. When the first buffer fills up, a new one should be created which will also
|
||||||
/// be the maximum length the GPU supports. When the new buffer fills up, a new one will be
|
/// be the maximum length the GPU supports. When the new buffer fills up, a new one will be
|
||||||
/// created once again, and so on.
|
/// created once again, and so on.
|
||||||
///
|
///
|
||||||
/// `Uuid`'s are used to represent entries (usually Meshes) in the buffer. The Uuid's can be used
|
/// [`TransformGroup`]s are used to represent entries in the buffer. They are used to insert,
|
||||||
/// to insert, update, and retrieve the transforms.
|
/// update, and retrieve the transforms.
|
||||||
pub(crate) struct TransformBuffers {
|
pub struct TransformBuffers {
|
||||||
pub bindgroup_layout: wgpu::BindGroupLayout,
|
pub bindgroup_layout: wgpu::BindGroupLayout,
|
||||||
pub entries: Vec<TransformBufferEntry>,
|
groups: CachedValMap<TransformGroupId, TransformIndex>,
|
||||||
|
entries: Vec<BufferEntry>,
|
||||||
limits: wgpu::Limits,
|
limits: wgpu::Limits,
|
||||||
|
max_transform_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TransformBuffers {
|
impl TransformBuffers {
|
||||||
|
@ -66,7 +196,9 @@ impl TransformBuffers {
|
||||||
|
|
||||||
let mut s = Self {
|
let mut s = Self {
|
||||||
bindgroup_layout,
|
bindgroup_layout,
|
||||||
entries: vec![],
|
groups: Default::default(),
|
||||||
|
entries: Default::default(),
|
||||||
|
max_transform_count: (limits.max_uniform_buffer_binding_size / 2) as usize / (mem::size_of::<glam::Mat4>()),
|
||||||
limits,
|
limits,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,26 +208,70 @@ impl TransformBuffers {
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_transform(&mut self, queue: &wgpu::Queue, limits: &Limits, transform: glam::Mat4, normal_matrix: glam::Mat3) -> u32 {
|
/// Update an existing transform in the buffers.
|
||||||
let entry = self.entries.iter_mut().next().unwrap(); // TODO: use other buffers than just the first
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// Panics if the `entity_group` is not already inside of the buffers.
|
||||||
|
pub fn update_transform(&mut self, queue: &wgpu::Queue, limits: &Limits, entity_group: TransformGroup, transform: glam::Mat4, normal_matrix: glam::Mat3) -> TransformIndex {
|
||||||
|
let index = *self.groups.get(entity_group.into())
|
||||||
|
.expect("Use 'push_transform' for new entities");
|
||||||
|
let entry = self.entries.get_mut(index.entry_index).unwrap();
|
||||||
|
|
||||||
let normal_matrix = glam::Mat4::from_mat3(normal_matrix);
|
let normal_matrix = glam::Mat4::from_mat3(normal_matrix);
|
||||||
|
|
||||||
// write the transform and normal to the end of the transform
|
// write the transform and normal to the end of the transform
|
||||||
//let offset = (mem::size_of::<glam::Mat4>() * entry.len) as u64;
|
let offset = Self::get_buffer_offset(limits, index) as _;
|
||||||
let offset = Self::get_buffer_offset(limits, entry.len as u32) as _;
|
|
||||||
queue.write_buffer(&entry.transform_buffer, offset, bytemuck::bytes_of(&transform));
|
queue.write_buffer(&entry.transform_buffer, offset, bytemuck::bytes_of(&transform));
|
||||||
queue.write_buffer(&entry.normal_buffer, offset, bytemuck::bytes_of(&normal_matrix));
|
queue.write_buffer(&entry.normal_buffer, offset, bytemuck::bytes_of(&normal_matrix));
|
||||||
|
|
||||||
let index = entry.len;
|
index
|
||||||
entry.len += 1;
|
}
|
||||||
index as _
|
|
||||||
|
/// Push a new transform into the buffers.
|
||||||
|
pub fn push_transform(&mut self, queue: &wgpu::Queue, limits: &Limits, entity_group: TransformGroup, transform: glam::Mat4, normal_matrix: glam::Mat3) -> TransformIndex {
|
||||||
|
self.groups.insert(entity_group.into(), || {
|
||||||
|
// this closure is only called when there are no values that can be reused,
|
||||||
|
// so we get a brand new index at the end of the last entry in the chain.
|
||||||
|
let last = self.entries.last_mut().unwrap();
|
||||||
|
|
||||||
|
// ensure the gpu buffer is not overflown
|
||||||
|
debug_assert!(last.len < self.max_transform_count,
|
||||||
|
"Transform buffer is filled and 'next_indices' was not incremented! \
|
||||||
|
Was a new buffer created?");
|
||||||
|
|
||||||
|
let tidx = last.len;
|
||||||
|
last.len += 1;
|
||||||
|
|
||||||
|
TransformIndex {
|
||||||
|
entry_index: self.entries.len() - 1,
|
||||||
|
transform_index: tidx
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.update_transform(queue, limits, entity_group, transform, normal_matrix)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collect the dead transforms and prepare self to check next time.
|
/// Collect the dead transforms and prepare self to check next time.
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
for entry in self.entries.iter_mut() {
|
self.groups.update();
|
||||||
entry.len = 0;
|
}
|
||||||
|
|
||||||
|
/// Returns a boolean indicating if the buffer contains this group.
|
||||||
|
pub fn contains(&self, group: TransformGroup) -> bool {
|
||||||
|
self.groups.contains(group.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update an existing transform group or if its not existing yet, pushes it to the buffer.
|
||||||
|
///
|
||||||
|
/// Returns: the index that the transform is at in the buffers.
|
||||||
|
pub fn update_or_push<F>(&mut self, queue: &wgpu::Queue, limits: &Limits, group: TransformGroup, transform_fn: F) -> TransformIndex
|
||||||
|
where F: Fn() -> (glam::Mat4, glam::Mat3)
|
||||||
|
{
|
||||||
|
let (transform, normal_matrix) = transform_fn();
|
||||||
|
if self.contains(group) {
|
||||||
|
self.update_transform(queue, limits, group, transform, normal_matrix)
|
||||||
|
} else {
|
||||||
|
self.push_transform(queue, limits, group, transform, normal_matrix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +281,7 @@ impl TransformBuffers {
|
||||||
/// "chain-link" is created.
|
/// "chain-link" is created.
|
||||||
pub fn expand_buffers(&mut self, device: &wgpu::Device) {
|
pub fn expand_buffers(&mut self, device: &wgpu::Device) {
|
||||||
let limits = device.limits();
|
let limits = device.limits();
|
||||||
let max_buffer_sizes = (limits.max_uniform_buffer_binding_size as u64) / 2;
|
let max_buffer_sizes = self.max_transform_count as u64 * limits.min_uniform_buffer_offset_alignment as u64;
|
||||||
|
|
||||||
let transform_buffer = device.create_buffer(
|
let transform_buffer = device.create_buffer(
|
||||||
&wgpu::BufferDescriptor {
|
&wgpu::BufferDescriptor {
|
||||||
|
@ -157,7 +333,7 @@ impl TransformBuffers {
|
||||||
label: Some("BG_Transforms"),
|
label: Some("BG_Transforms"),
|
||||||
});
|
});
|
||||||
|
|
||||||
let entry = TransformBufferEntry {
|
let entry = BufferEntry {
|
||||||
bindgroup: transform_bind_group,
|
bindgroup: transform_bind_group,
|
||||||
transform_buffer,
|
transform_buffer,
|
||||||
normal_buffer: normal_mat_buffer,
|
normal_buffer: normal_mat_buffer,
|
||||||
|
@ -166,24 +342,28 @@ impl TransformBuffers {
|
||||||
self.entries.push(entry);
|
self.entries.push(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind_group(&self, transform_id: u32) -> &wgpu::BindGroup {
|
/// Returns the bind group for the transform index.
|
||||||
let _ = transform_id;
|
pub fn bind_group(&self, transform_id: TransformIndex) -> &wgpu::BindGroup {
|
||||||
|
let entry = self.entries.get(transform_id.entry_index).unwrap();
|
||||||
let entry = self.entries.iter().next().unwrap(); // TODO: use other buffers than just the first
|
|
||||||
&entry.bindgroup
|
&entry.bindgroup
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the buffer offset for a transform using wgpu limits.
|
/// Get the buffer offset for a transform using wgpu limits.
|
||||||
///
|
///
|
||||||
/// If its possible to borrow immutably, use [`TransformBuffers::buffer_offset`].
|
/// If its possible to borrow immutably, use [`TransformBuffers::buffer_offset`].
|
||||||
fn get_buffer_offset(limits: &wgpu::Limits, transform_id: u32) -> u32 {
|
fn get_buffer_offset(limits: &wgpu::Limits, transform_index: TransformIndex) -> u32 {
|
||||||
//let entry = self.entries.iter().next().unwrap(); // TODO: use other buffers than just the first
|
transform_index.transform_index as u32 * limits.min_uniform_buffer_offset_alignment as u32
|
||||||
|
|
||||||
transform_id * limits.min_uniform_buffer_offset_alignment as u32//mem::size_of::<glam::Mat4>() as u32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buffer_offset(&self, transform_id: u32) -> u32 {
|
/// Returns the offset of the transform inside the bind group buffer.
|
||||||
Self::get_buffer_offset(&self.limits, transform_id)
|
///
|
||||||
|
/// ```nobuild
|
||||||
|
/// let bindgroup = transform_buffers.bind_group(job.transform_id);
|
||||||
|
/// let offset = transform_buffers.buffer_offset(job.transform_id);
|
||||||
|
/// render_pass.set_bind_group(1, bindgroup, &[ offset, offset, ]);
|
||||||
|
/// ```
|
||||||
|
pub fn buffer_offset(&self, transform_index: TransformIndex) -> u32 {
|
||||||
|
Self::get_buffer_offset(&self.limits, transform_index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue