mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
Port Mesh to RenderAsset, add Slab and FrameSlabMap garbage collection for Bind Groups
This commit is contained in:
parent
3ef951dcbc
commit
25de2d1819
16 changed files with 591 additions and 418 deletions
|
@ -1,7 +1,8 @@
|
|||
mod enum_variant_meta;
|
||||
pub use enum_variant_meta::*;
|
||||
pub mod slab;
|
||||
|
||||
pub use ahash::AHasher;
|
||||
pub use enum_variant_meta::*;
|
||||
pub use instant::{Duration, Instant};
|
||||
pub use tracing;
|
||||
pub use uuid::Uuid;
|
||||
|
|
214
crates/bevy_utils/src/slab.rs
Normal file
214
crates/bevy_utils/src/slab.rs
Normal file
|
@ -0,0 +1,214 @@
|
|||
use std::{
|
||||
marker::PhantomData,
|
||||
ops::{Index, IndexMut},
|
||||
};
|
||||
|
||||
use crate::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SlabKey<V> {
|
||||
index: usize,
|
||||
marker: PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<V> Copy for SlabKey<V> {}
|
||||
|
||||
impl<V> Clone for SlabKey<V> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
index: self.index,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> SlabKey<V> {
|
||||
#[inline]
|
||||
pub fn index(&self) -> usize {
|
||||
self.index
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Slab<V> {
|
||||
values: Vec<Option<V>>,
|
||||
empty_indices: Vec<usize>,
|
||||
}
|
||||
|
||||
impl<V> Default for Slab<V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
values: Default::default(),
|
||||
empty_indices: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> Slab<V> {
|
||||
pub fn get(&self, key: SlabKey<V>) -> Option<&V> {
|
||||
self.values[key.index].as_ref()
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, key: SlabKey<V>) -> Option<&mut V> {
|
||||
self.values[key.index].as_mut()
|
||||
}
|
||||
|
||||
pub fn add(&mut self, value: V) -> SlabKey<V> {
|
||||
let index = if let Some(index) = self.empty_indices.pop() {
|
||||
self.values[index] = Some(value);
|
||||
index
|
||||
} else {
|
||||
let index = self.values.len();
|
||||
self.values.push(Some(value));
|
||||
index
|
||||
};
|
||||
SlabKey {
|
||||
index,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, key: SlabKey<V>) -> Option<V> {
|
||||
if let Some(value) = self.values[key.index].take() {
|
||||
self.empty_indices.push(key.index);
|
||||
Some(value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &V> {
|
||||
self.values.iter().filter_map(|v| v.as_ref())
|
||||
}
|
||||
|
||||
/// Retains any items matching the given predicate. Removed items will be dropped and their indices will be
|
||||
/// made available for future items.
|
||||
pub fn retain_in_place(&mut self, mut predicate: impl FnMut(&mut V) -> bool) {
|
||||
for (i, value) in self.values.iter_mut().enumerate() {
|
||||
if let Some(value) = value {
|
||||
if predicate(value) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
*value = None;
|
||||
self.empty_indices.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> Index<SlabKey<V>> for Slab<V> {
|
||||
type Output = V;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: SlabKey<V>) -> &Self::Output {
|
||||
self.get(index).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> IndexMut<SlabKey<V>> for Slab<V> {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: SlabKey<V>) -> &mut Self::Output {
|
||||
self.get_mut(index).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FrameSlabMapValue<K, V> {
|
||||
value: V,
|
||||
key: K,
|
||||
frames_since_last_use: usize,
|
||||
}
|
||||
|
||||
pub struct FrameSlabMap<K, V> {
|
||||
slab: Slab<FrameSlabMapValue<K, V>>,
|
||||
keys: HashMap<K, FrameSlabMapKey<K, V>>,
|
||||
}
|
||||
|
||||
impl<K, V> Default for FrameSlabMap<K, V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
slab: Default::default(),
|
||||
keys: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type FrameSlabMapKey<K, V> = SlabKey<FrameSlabMapValue<K, V>>;
|
||||
|
||||
impl<K: std::hash::Hash + Eq + Clone, V> FrameSlabMap<K, V> {
|
||||
pub fn get_value(&self, slab_key: FrameSlabMapKey<K, V>) -> Option<&V> {
|
||||
let value = self.slab.get(slab_key)?;
|
||||
Some(&value.value)
|
||||
}
|
||||
|
||||
pub fn get_value_mut(&mut self, slab_key: FrameSlabMapKey<K, V>) -> Option<&mut V> {
|
||||
let value = self.slab.get_mut(slab_key)?;
|
||||
Some(&mut value.value)
|
||||
}
|
||||
|
||||
pub fn get_or_insert_with(
|
||||
&mut self,
|
||||
key: K,
|
||||
f: impl FnOnce() -> V,
|
||||
) -> SlabKey<FrameSlabMapValue<K, V>> {
|
||||
match self.keys.entry(key.clone()) {
|
||||
std::collections::hash_map::Entry::Occupied(mut entry) => {
|
||||
let slab_key = *entry.get();
|
||||
match self.slab.get_mut(slab_key) {
|
||||
Some(value) => {
|
||||
value.frames_since_last_use = 0;
|
||||
slab_key
|
||||
}
|
||||
None => {
|
||||
let key = self.slab.add(FrameSlabMapValue {
|
||||
frames_since_last_use: 0,
|
||||
value: f(),
|
||||
key,
|
||||
});
|
||||
entry.insert(key);
|
||||
key
|
||||
}
|
||||
}
|
||||
}
|
||||
std::collections::hash_map::Entry::Vacant(entry) => {
|
||||
let key = self.slab.add(FrameSlabMapValue {
|
||||
frames_since_last_use: 0,
|
||||
value: f(),
|
||||
key,
|
||||
});
|
||||
entry.insert(key);
|
||||
key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_frame(&mut self) {
|
||||
let keys = &mut self.keys;
|
||||
self.slab.retain_in_place(|v| {
|
||||
v.frames_since_last_use += 1;
|
||||
if v.frames_since_last_use < 3 {
|
||||
true
|
||||
} else {
|
||||
keys.remove(&v.key);
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: std::hash::Hash + Eq + Clone, V> Index<FrameSlabMapKey<K, V>> for FrameSlabMap<K, V> {
|
||||
type Output = V;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: FrameSlabMapKey<K, V>) -> &Self::Output {
|
||||
self.get_value(index).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: std::hash::Hash + Eq + Clone, V> IndexMut<FrameSlabMapKey<K, V>> for FrameSlabMap<K, V> {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: FrameSlabMapKey<K, V>) -> &mut Self::Output {
|
||||
self.get_value_mut(index).unwrap()
|
||||
}
|
||||
}
|
|
@ -242,7 +242,7 @@ impl Default for CountTimer {
|
|||
|
||||
fn counter_system(
|
||||
mut timer: Local<CountTimer>,
|
||||
diagnostics: Res<Diagnostics>,
|
||||
_diagnostics: Res<Diagnostics>,
|
||||
time: Res<Time>,
|
||||
counter: Res<BevyCounter>,
|
||||
) {
|
||||
|
@ -255,7 +255,7 @@ fn counter_system(
|
|||
///
|
||||
/// Because there is no `Mul<Color> for Color` instead `[f32; 3]` is
|
||||
/// used.
|
||||
fn gen_color(rng: &mut impl Rng) -> [f32; 3] {
|
||||
fn _gen_color(rng: &mut impl Rng) -> [f32; 3] {
|
||||
let r = rng.gen_range(0.2..1.0);
|
||||
let g = rng.gen_range(0.2..1.0);
|
||||
let b = rng.gen_range(0.2..1.0);
|
||||
|
|
|
@ -48,7 +48,6 @@ impl Plugin for PbrPlugin {
|
|||
)
|
||||
.init_resource::<PbrShaders>()
|
||||
.init_resource::<ShadowShaders>()
|
||||
.init_resource::<MaterialMeta>()
|
||||
.init_resource::<MeshMeta>()
|
||||
.init_resource::<LightMeta>();
|
||||
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
use bevy_app::{App, CoreStage, EventReader, Plugin};
|
||||
use bevy_asset::{AddAsset, AssetEvent, Assets, Handle};
|
||||
use bevy_asset::{AddAsset, AssetEvent, Assets};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_math::Vec4;
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_render2::{color::Color, render_resource::{Buffer, BufferId, BufferInitDescriptor, BufferUsage}, renderer::{RenderDevice, RenderQueue}};
|
||||
use bevy_render2::{
|
||||
color::Color,
|
||||
render_resource::{Buffer, BufferInitDescriptor, BufferUsage},
|
||||
renderer::RenderDevice,
|
||||
};
|
||||
use bevy_utils::HashSet;
|
||||
use crevice::std140::{AsStd140, Std140};
|
||||
|
||||
|
@ -103,7 +107,6 @@ impl Plugin for StandardMaterialPlugin {
|
|||
|
||||
pub fn standard_material_resource_system(
|
||||
render_device: Res<RenderDevice>,
|
||||
render_queue: Res<RenderQueue>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
mut material_events: EventReader<AssetEvent<StandardMaterial>>,
|
||||
) {
|
||||
|
@ -144,8 +147,6 @@ pub fn standard_material_resource_system(
|
|||
};
|
||||
let value_std140 = value.as_std140();
|
||||
|
||||
let size = StandardMaterialUniformData::std140_size_static();
|
||||
|
||||
let buffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
|
||||
label: None,
|
||||
usage: BufferUsage::UNIFORM | BufferUsage::COPY_DST,
|
||||
|
|
|
@ -4,6 +4,8 @@ use bevy_math::{Mat4, Vec3, Vec4};
|
|||
use bevy_render2::{
|
||||
color::Color,
|
||||
core_pipeline::Transparent3dPhase,
|
||||
mesh::Mesh,
|
||||
render_asset::RenderAssets,
|
||||
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
|
||||
render_phase::{Draw, DrawFunctions, RenderPhase, TrackedRenderPass},
|
||||
render_resource::*,
|
||||
|
@ -82,10 +84,7 @@ impl FromWorld for ShadowShaders {
|
|||
let pipeline_layout = render_device.create_pipeline_layout(&PipelineLayoutDescriptor {
|
||||
label: None,
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[
|
||||
&view_layout,
|
||||
&pbr_shaders.mesh_layout,
|
||||
],
|
||||
bind_group_layouts: &[&view_layout, &pbr_shaders.mesh_layout],
|
||||
});
|
||||
|
||||
let pipeline = render_device.create_render_pipeline(&RenderPipelineDescriptor {
|
||||
|
@ -378,6 +377,7 @@ type DrawShadowMeshParams<'s, 'w> = (
|
|||
Res<'w, ExtractedMeshes>,
|
||||
Res<'w, LightMeta>,
|
||||
Res<'w, MeshMeta>,
|
||||
Res<'w, RenderAssets<Mesh>>,
|
||||
Query<'w, 's, &'w ViewUniformOffset>,
|
||||
);
|
||||
pub struct DrawShadowMesh {
|
||||
|
@ -401,7 +401,7 @@ impl Draw for DrawShadowMesh {
|
|||
draw_key: usize,
|
||||
_sort_key: usize,
|
||||
) {
|
||||
let (shadow_shaders, extracted_meshes, light_meta, mesh_meta, views) =
|
||||
let (shadow_shaders, extracted_meshes, light_meta, mesh_meta, meshes, views) =
|
||||
self.params.get(world);
|
||||
let view_uniform_offset = views.get(view).unwrap();
|
||||
let extracted_mesh = &extracted_meshes.into_inner().meshes[draw_key];
|
||||
|
@ -425,8 +425,10 @@ impl Draw for DrawShadowMesh {
|
|||
.unwrap(),
|
||||
&[extracted_mesh.transform_binding_offset],
|
||||
);
|
||||
pass.set_vertex_buffer(0, extracted_mesh.vertex_buffer.slice(..));
|
||||
if let Some(index_info) = &extracted_mesh.index_info {
|
||||
|
||||
let gpu_mesh = meshes.into_inner().get(&extracted_mesh.mesh).unwrap();
|
||||
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
|
||||
if let Some(index_info) = &gpu_mesh.index_info {
|
||||
pass.set_index_buffer(index_info.buffer.slice(..), 0, IndexFormat::Uint32);
|
||||
pass.draw_indexed(0..index_info.count, 0, 0..1);
|
||||
} else {
|
||||
|
|
|
@ -7,6 +7,7 @@ use bevy_math::Mat4;
|
|||
use bevy_render2::{
|
||||
core_pipeline::Transparent3dPhase,
|
||||
mesh::Mesh,
|
||||
render_asset::RenderAssets,
|
||||
render_graph::{Node, NodeRunError, RenderGraphContext},
|
||||
render_phase::{Draw, DrawFunctions, Drawable, RenderPhase, TrackedRenderPass},
|
||||
render_resource::*,
|
||||
|
@ -16,7 +17,7 @@ use bevy_render2::{
|
|||
view::{ViewMeta, ViewUniform, ViewUniformOffset},
|
||||
};
|
||||
use bevy_transform::components::GlobalTransform;
|
||||
use bevy_utils::HashMap;
|
||||
use bevy_utils::slab::{FrameSlabMap, FrameSlabMapKey};
|
||||
use crevice::std140::AsStd140;
|
||||
use std::borrow::Cow;
|
||||
|
||||
|
@ -233,15 +234,9 @@ impl FromWorld for PbrShaders {
|
|||
|
||||
struct ExtractedMesh {
|
||||
transform: Mat4,
|
||||
vertex_buffer: Buffer,
|
||||
index_info: Option<IndexInfo>,
|
||||
transform_binding_offset: u32,
|
||||
mesh: Handle<Mesh>,
|
||||
material_buffer: Buffer,
|
||||
}
|
||||
|
||||
struct IndexInfo {
|
||||
buffer: Buffer,
|
||||
count: u32,
|
||||
transform_binding_offset: u32,
|
||||
}
|
||||
|
||||
pub struct ExtractedMeshes {
|
||||
|
@ -256,22 +251,17 @@ pub fn extract_meshes(
|
|||
) {
|
||||
let mut extracted_meshes = Vec::new();
|
||||
for (transform, mesh_handle, material_handle) in query.iter() {
|
||||
if let Some(mesh) = meshes.get(mesh_handle) {
|
||||
if let Some(mesh_gpu_data) = &mesh.gpu_data() {
|
||||
if let Some(material) = materials.get(material_handle) {
|
||||
if let Some(material_gpu_data) = &material.gpu_data() {
|
||||
extracted_meshes.push(ExtractedMesh {
|
||||
transform: transform.compute_matrix(),
|
||||
vertex_buffer: mesh_gpu_data.vertex_buffer.clone(),
|
||||
index_info: mesh_gpu_data.index_buffer.as_ref().map(|i| IndexInfo {
|
||||
buffer: i.clone(),
|
||||
count: mesh.indices().unwrap().len() as u32,
|
||||
}),
|
||||
transform_binding_offset: 0,
|
||||
material_buffer: material_gpu_data.buffer.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
if !meshes.contains(mesh_handle) {
|
||||
continue;
|
||||
}
|
||||
if let Some(material) = materials.get(material_handle) {
|
||||
if let Some(material_gpu_data) = &material.gpu_data() {
|
||||
extracted_meshes.push(ExtractedMesh {
|
||||
transform: transform.compute_matrix(),
|
||||
mesh: mesh_handle.clone_weak(),
|
||||
material_buffer: material_gpu_data.buffer.clone(),
|
||||
transform_binding_offset: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -281,10 +271,17 @@ pub fn extract_meshes(
|
|||
});
|
||||
}
|
||||
|
||||
struct MeshDrawInfo {
|
||||
// TODO: compare cost of doing this vs cloning the BindGroup?
|
||||
material_bind_group_key: FrameSlabMapKey<BufferId, BindGroup>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MeshMeta {
|
||||
transform_uniforms: DynamicUniformVec<Mat4>,
|
||||
material_bind_groups: FrameSlabMap<BufferId, BindGroup>,
|
||||
mesh_transform_bind_group: Option<BindGroup>,
|
||||
mesh_draw_info: Vec<MeshDrawInfo>,
|
||||
}
|
||||
|
||||
pub fn prepare_meshes(
|
||||
|
@ -304,11 +301,6 @@ pub fn prepare_meshes(
|
|||
.transform_uniforms
|
||||
.write_to_staging_buffer(&render_device);
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct MaterialMeta {
|
||||
material_bind_groups: Vec<BindGroup>,
|
||||
material_bind_group_indices: HashMap<BufferId, usize>,
|
||||
}
|
||||
|
||||
pub struct MeshViewBindGroups {
|
||||
view: BindGroup,
|
||||
|
@ -321,7 +313,6 @@ pub fn queue_meshes(
|
|||
pbr_shaders: Res<PbrShaders>,
|
||||
shadow_shaders: Res<ShadowShaders>,
|
||||
mesh_meta: ResMut<MeshMeta>,
|
||||
material_meta: ResMut<MaterialMeta>,
|
||||
mut light_meta: ResMut<LightMeta>,
|
||||
view_meta: Res<ViewMeta>,
|
||||
mut extracted_meshes: ResMut<ExtractedMeshes>,
|
||||
|
@ -329,7 +320,6 @@ pub fn queue_meshes(
|
|||
mut view_light_shadow_phases: Query<&mut RenderPhase<ShadowPhase>>,
|
||||
) {
|
||||
let mesh_meta = mesh_meta.into_inner();
|
||||
let material_meta = material_meta.into_inner();
|
||||
|
||||
light_meta.shadow_view_bind_group.get_or_insert_with(|| {
|
||||
render_device.create_bind_group(&BindGroupDescriptor {
|
||||
|
@ -385,34 +375,34 @@ pub fn queue_meshes(
|
|||
view: view_bind_group,
|
||||
});
|
||||
|
||||
// TODO: free old bind groups after a few frames without use?
|
||||
|
||||
let draw_pbr = draw_functions.read().get_id::<DrawPbr>().unwrap();
|
||||
let material_bind_groups = &mut material_meta.material_bind_groups;
|
||||
mesh_meta.mesh_draw_info.clear();
|
||||
mesh_meta.material_bind_groups.next_frame();
|
||||
|
||||
for (i, mesh) in extracted_meshes.meshes.iter_mut().enumerate() {
|
||||
let material_bind_group_index = *material_meta
|
||||
.material_bind_group_indices
|
||||
.entry(mesh.material_buffer.id())
|
||||
.or_insert_with(|| {
|
||||
let index = material_bind_groups.len();
|
||||
let material_bind_group =
|
||||
render_device.create_bind_group(&BindGroupDescriptor {
|
||||
entries: &[BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: mesh.material_buffer.as_entire_binding(),
|
||||
}],
|
||||
label: None,
|
||||
layout: &pbr_shaders.material_layout,
|
||||
});
|
||||
material_bind_groups.push(material_bind_group);
|
||||
index
|
||||
});
|
||||
let material_bind_group_key = mesh_meta.material_bind_groups.get_or_insert_with(
|
||||
mesh.material_buffer.id(),
|
||||
|| {
|
||||
render_device.create_bind_group(&BindGroupDescriptor {
|
||||
entries: &[BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: mesh.material_buffer.as_entire_binding(),
|
||||
}],
|
||||
label: None,
|
||||
layout: &pbr_shaders.material_layout,
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
mesh_meta.mesh_draw_info.push(MeshDrawInfo {
|
||||
material_bind_group_key,
|
||||
});
|
||||
|
||||
// TODO: currently there is only "transparent phase". this should pick transparent vs opaque according to the mesh material
|
||||
transparent_phase.add(Drawable {
|
||||
draw_function: draw_pbr,
|
||||
draw_key: i,
|
||||
sort_key: material_bind_group_index, // TODO: sort back-to-front, sorting by material for now
|
||||
sort_key: material_bind_group_key.index(), // TODO: sort back-to-front, sorting by material for now
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -456,9 +446,9 @@ impl Node for PbrNode {
|
|||
|
||||
type DrawPbrParams<'s, 'w> = (
|
||||
Res<'w, PbrShaders>,
|
||||
Res<'w, MaterialMeta>,
|
||||
Res<'w, MeshMeta>,
|
||||
Res<'w, ExtractedMeshes>,
|
||||
Res<'w, RenderAssets<Mesh>>,
|
||||
Query<
|
||||
'w,
|
||||
's,
|
||||
|
@ -489,12 +479,12 @@ impl Draw for DrawPbr {
|
|||
pass: &mut TrackedRenderPass<'w>,
|
||||
view: Entity,
|
||||
draw_key: usize,
|
||||
sort_key: usize,
|
||||
_sort_key: usize,
|
||||
) {
|
||||
let (pbr_shaders, material_meta, mesh_meta, extracted_meshes, views) =
|
||||
self.params.get(world);
|
||||
let (pbr_shaders, mesh_meta, extracted_meshes, meshes, views) = self.params.get(world);
|
||||
let (view_uniforms, view_lights, mesh_view_bind_groups) = views.get(view).unwrap();
|
||||
let extracted_mesh = &extracted_meshes.into_inner().meshes[draw_key];
|
||||
let mesh_meta = mesh_meta.into_inner();
|
||||
pass.set_render_pipeline(&pbr_shaders.into_inner().pipeline);
|
||||
pass.set_bind_group(
|
||||
0,
|
||||
|
@ -503,20 +493,19 @@ impl Draw for DrawPbr {
|
|||
);
|
||||
pass.set_bind_group(
|
||||
1,
|
||||
mesh_meta
|
||||
.into_inner()
|
||||
.mesh_transform_bind_group
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
mesh_meta.mesh_transform_bind_group.as_ref().unwrap(),
|
||||
&[extracted_mesh.transform_binding_offset],
|
||||
);
|
||||
let mesh_draw_info = &mesh_meta.mesh_draw_info[draw_key];
|
||||
pass.set_bind_group(
|
||||
2,
|
||||
&material_meta.into_inner().material_bind_groups[sort_key],
|
||||
&mesh_meta.material_bind_groups[mesh_draw_info.material_bind_group_key],
|
||||
&[],
|
||||
);
|
||||
pass.set_vertex_buffer(0, extracted_mesh.vertex_buffer.slice(..));
|
||||
if let Some(index_info) = &extracted_mesh.index_info {
|
||||
|
||||
let gpu_mesh = meshes.into_inner().get(&extracted_mesh.mesh).unwrap();
|
||||
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
|
||||
if let Some(index_info) = &gpu_mesh.index_info {
|
||||
pass.set_index_buffer(index_info.buffer.slice(..), 0, IndexFormat::Uint32);
|
||||
pass.draw_indexed(0..index_info.count, 0, 0..1);
|
||||
} else {
|
||||
|
|
|
@ -5,13 +5,12 @@ mod main_pass_driver;
|
|||
pub use main_pass_2d::*;
|
||||
pub use main_pass_3d::*;
|
||||
pub use main_pass_driver::*;
|
||||
use wgpu::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage};
|
||||
|
||||
use crate::{
|
||||
camera::{ActiveCameras, CameraPlugin},
|
||||
render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType},
|
||||
render_phase::{sort_phase_system, RenderPhase},
|
||||
render_resource::{Texture, TextureId, TextureView, TextureViewId},
|
||||
render_resource::{Texture, TextureView},
|
||||
renderer::RenderDevice,
|
||||
texture::TextureCache,
|
||||
view::{ExtractedView, ViewPlugin},
|
||||
|
@ -19,6 +18,7 @@ use crate::{
|
|||
};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::prelude::*;
|
||||
use wgpu::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage};
|
||||
|
||||
// Plugins that contribute to the RenderGraph should use the following label conventions:
|
||||
// 1. Graph modules should have a NAME, input module, and node module (where relevant)
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
use crate::{
|
||||
mesh::{Mesh, MeshGpuData},
|
||||
render_resource::Buffer,
|
||||
renderer::RenderDevice,
|
||||
};
|
||||
use bevy_asset::{AssetEvent, Assets};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_utils::HashSet;
|
||||
use wgpu::{util::BufferInitDescriptor, BufferUsage};
|
||||
|
||||
pub fn mesh_resource_provider_system(
|
||||
render_device: Res<RenderDevice>,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut mesh_events: EventReader<AssetEvent<Mesh>>,
|
||||
) {
|
||||
let mut changed_meshes = HashSet::default();
|
||||
for event in mesh_events.iter() {
|
||||
match event {
|
||||
AssetEvent::Created { ref handle } => {
|
||||
changed_meshes.insert(handle.clone_weak());
|
||||
}
|
||||
AssetEvent::Modified { ref handle } => {
|
||||
changed_meshes.insert(handle.clone_weak());
|
||||
// TODO: uncomment this to support mutated meshes
|
||||
// remove_current_mesh_resources(render_resource_context, handle, &mut meshes);
|
||||
}
|
||||
AssetEvent::Removed { ref handle } => {
|
||||
// if mesh was modified and removed in the same update, ignore the modification
|
||||
// events are ordered so future modification events are ok
|
||||
changed_meshes.remove(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update changed mesh data
|
||||
for changed_mesh_handle in changed_meshes.iter() {
|
||||
if let Some(mesh) = meshes.get_mut(changed_mesh_handle) {
|
||||
// TODO: this avoids creating new meshes each frame because storing gpu data in the mesh flags it as
|
||||
// modified. this prevents hot reloading and therefore can't be used in an actual impl.
|
||||
if mesh.gpu_data.is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let vertex_buffer_data = mesh.get_vertex_buffer_data();
|
||||
let vertex_buffer = Buffer::from(render_device.create_buffer_with_data(
|
||||
&BufferInitDescriptor {
|
||||
usage: BufferUsage::VERTEX,
|
||||
label: None,
|
||||
contents: &vertex_buffer_data,
|
||||
},
|
||||
));
|
||||
|
||||
let index_buffer = mesh.get_index_buffer_bytes().map(|data| {
|
||||
Buffer::from(
|
||||
render_device.create_buffer_with_data(&BufferInitDescriptor {
|
||||
usage: BufferUsage::INDEX,
|
||||
contents: &data,
|
||||
label: None,
|
||||
}),
|
||||
)
|
||||
});
|
||||
|
||||
mesh.gpu_data = Some(MeshGpuData {
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,229 +1,20 @@
|
|||
mod conversions;
|
||||
mod mesh_resource_provider;
|
||||
|
||||
pub use mesh_resource_provider::*;
|
||||
use wgpu::{IndexFormat, PrimitiveTopology, VertexFormat};
|
||||
|
||||
use crate::{
|
||||
render_asset::RenderAsset,
|
||||
render_resource::Buffer,
|
||||
renderer::{RenderDevice, RenderQueue},
|
||||
};
|
||||
use bevy_core::cast_slice;
|
||||
use bevy_math::*;
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_utils::EnumVariantMeta;
|
||||
use std::{borrow::Cow, collections::BTreeMap, sync::Arc};
|
||||
use std::{borrow::Cow, collections::BTreeMap};
|
||||
use wgpu::{util::BufferInitDescriptor, BufferUsage, IndexFormat, PrimitiveTopology, VertexFormat};
|
||||
|
||||
pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
|
||||
pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
|
||||
|
||||
/// An array where each entry describes a property of a single vertex.
|
||||
#[derive(Clone, Debug, EnumVariantMeta)]
|
||||
pub enum VertexAttributeValues {
|
||||
Float32(Vec<f32>),
|
||||
Sint32(Vec<i32>),
|
||||
Uint32(Vec<u32>),
|
||||
Float32x2(Vec<[f32; 2]>),
|
||||
Sint32x2(Vec<[i32; 2]>),
|
||||
Uint32x2(Vec<[u32; 2]>),
|
||||
Float32x3(Vec<[f32; 3]>),
|
||||
Sint32x3(Vec<[i32; 3]>),
|
||||
Uint32x3(Vec<[u32; 3]>),
|
||||
Float32x4(Vec<[f32; 4]>),
|
||||
Sint32x4(Vec<[i32; 4]>),
|
||||
Uint32x4(Vec<[u32; 4]>),
|
||||
Sint16x2(Vec<[i16; 2]>),
|
||||
Snorm16x2(Vec<[i16; 2]>),
|
||||
Uint16x2(Vec<[u16; 2]>),
|
||||
Unorm16x2(Vec<[u16; 2]>),
|
||||
Sint16x4(Vec<[i16; 4]>),
|
||||
Snorm16x4(Vec<[i16; 4]>),
|
||||
Uint16x4(Vec<[u16; 4]>),
|
||||
Unorm16x4(Vec<[u16; 4]>),
|
||||
Sint8x2(Vec<[i8; 2]>),
|
||||
Snorm8x2(Vec<[i8; 2]>),
|
||||
Uint8x2(Vec<[u8; 2]>),
|
||||
Unorm8x2(Vec<[u8; 2]>),
|
||||
Sint8x4(Vec<[i8; 4]>),
|
||||
Snorm8x4(Vec<[i8; 4]>),
|
||||
Uint8x4(Vec<[u8; 4]>),
|
||||
Unorm8x4(Vec<[u8; 4]>),
|
||||
}
|
||||
|
||||
impl VertexAttributeValues {
|
||||
/// Returns the number of vertices in this VertexAttribute. For a single
|
||||
/// mesh, all of the VertexAttributeValues must have the same length.
|
||||
pub fn len(&self) -> usize {
|
||||
match *self {
|
||||
VertexAttributeValues::Float32(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint32(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint32(ref values) => values.len(),
|
||||
VertexAttributeValues::Float32x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint32x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint32x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Float32x3(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint32x3(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint32x3(ref values) => values.len(),
|
||||
VertexAttributeValues::Float32x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint32x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint32x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint16x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Snorm16x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint16x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Unorm16x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint16x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Snorm16x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint16x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Unorm16x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint8x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Snorm8x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint8x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Unorm8x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint8x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Snorm8x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint8x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Unorm8x4(ref values) => values.len(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if there are no vertices in this VertexAttributeValue
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
fn as_float3(&self) -> Option<&[[f32; 3]]> {
|
||||
match self {
|
||||
VertexAttributeValues::Float32x3(values) => Some(values),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add vertex format as parameter here and perform type conversions
|
||||
/// Flattens the VertexAttributeArray into a sequence of bytes. This is
|
||||
/// useful for serialization and sending to the GPU.
|
||||
pub fn get_bytes(&self) -> &[u8] {
|
||||
match self {
|
||||
VertexAttributeValues::Float32(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint32(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint32(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Float32x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint32x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint32x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Float32x3(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint32x3(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint32x3(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Float32x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint32x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint32x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint16x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Snorm16x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint16x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Unorm16x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint16x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Snorm16x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint16x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Unorm16x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint8x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Snorm8x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint8x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Unorm8x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint8x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Snorm8x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint8x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Unorm8x4(values) => cast_slice(&values[..]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&VertexAttributeValues> for VertexFormat {
|
||||
fn from(values: &VertexAttributeValues) -> Self {
|
||||
match values {
|
||||
VertexAttributeValues::Float32(_) => VertexFormat::Float32,
|
||||
VertexAttributeValues::Sint32(_) => VertexFormat::Sint32,
|
||||
VertexAttributeValues::Uint32(_) => VertexFormat::Uint32,
|
||||
VertexAttributeValues::Float32x2(_) => VertexFormat::Float32x2,
|
||||
VertexAttributeValues::Sint32x2(_) => VertexFormat::Sint32x2,
|
||||
VertexAttributeValues::Uint32x2(_) => VertexFormat::Uint32x2,
|
||||
VertexAttributeValues::Float32x3(_) => VertexFormat::Float32x3,
|
||||
VertexAttributeValues::Sint32x3(_) => VertexFormat::Sint32x3,
|
||||
VertexAttributeValues::Uint32x3(_) => VertexFormat::Uint32x3,
|
||||
VertexAttributeValues::Float32x4(_) => VertexFormat::Float32x4,
|
||||
VertexAttributeValues::Sint32x4(_) => VertexFormat::Sint32x4,
|
||||
VertexAttributeValues::Uint32x4(_) => VertexFormat::Uint32x4,
|
||||
VertexAttributeValues::Sint16x2(_) => VertexFormat::Sint16x2,
|
||||
VertexAttributeValues::Snorm16x2(_) => VertexFormat::Snorm16x2,
|
||||
VertexAttributeValues::Uint16x2(_) => VertexFormat::Uint16x2,
|
||||
VertexAttributeValues::Unorm16x2(_) => VertexFormat::Unorm16x2,
|
||||
VertexAttributeValues::Sint16x4(_) => VertexFormat::Sint16x4,
|
||||
VertexAttributeValues::Snorm16x4(_) => VertexFormat::Snorm16x4,
|
||||
VertexAttributeValues::Uint16x4(_) => VertexFormat::Uint16x4,
|
||||
VertexAttributeValues::Unorm16x4(_) => VertexFormat::Unorm16x4,
|
||||
VertexAttributeValues::Sint8x2(_) => VertexFormat::Sint8x2,
|
||||
VertexAttributeValues::Snorm8x2(_) => VertexFormat::Snorm8x2,
|
||||
VertexAttributeValues::Uint8x2(_) => VertexFormat::Uint8x2,
|
||||
VertexAttributeValues::Unorm8x2(_) => VertexFormat::Unorm8x2,
|
||||
VertexAttributeValues::Sint8x4(_) => VertexFormat::Sint8x4,
|
||||
VertexAttributeValues::Snorm8x4(_) => VertexFormat::Snorm8x4,
|
||||
VertexAttributeValues::Uint8x4(_) => VertexFormat::Uint8x4,
|
||||
VertexAttributeValues::Unorm8x4(_) => VertexFormat::Unorm8x4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An array of indices into the VertexAttributeValues for a mesh.
|
||||
///
|
||||
/// It describes the order in which the vertex attributes should be joined into faces.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Indices {
|
||||
U16(Vec<u16>),
|
||||
U32(Vec<u32>),
|
||||
}
|
||||
|
||||
impl Indices {
|
||||
fn iter(&self) -> impl Iterator<Item = usize> + '_ {
|
||||
match self {
|
||||
Indices::U16(vec) => IndicesIter::U16(vec.iter()),
|
||||
Indices::U32(vec) => IndicesIter::U32(vec.iter()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Indices::U16(vec) => vec.len(),
|
||||
Indices::U32(vec) => vec.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
enum IndicesIter<'a> {
|
||||
U16(std::slice::Iter<'a, u16>),
|
||||
U32(std::slice::Iter<'a, u32>),
|
||||
}
|
||||
impl Iterator for IndicesIter<'_> {
|
||||
type Item = usize;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self {
|
||||
IndicesIter::U16(iter) => iter.next().map(|val| *val as usize),
|
||||
IndicesIter::U32(iter) => iter.next().map(|val| *val as usize),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Indices> for IndexFormat {
|
||||
fn from(indices: &Indices) -> Self {
|
||||
match indices {
|
||||
Indices::U16(_) => IndexFormat::Uint16,
|
||||
Indices::U32(_) => IndexFormat::Uint32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this shouldn't live in the Mesh type
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MeshGpuData {
|
||||
pub vertex_buffer: Buffer,
|
||||
pub index_buffer: Option<Buffer>,
|
||||
}
|
||||
|
||||
// TODO: allow values to be unloaded after been submitting to the GPU to conserve memory
|
||||
#[derive(Debug, TypeUuid, Clone)]
|
||||
#[uuid = "8ecbac0f-f545-4473-ad43-e1f4243af51e"]
|
||||
|
@ -235,7 +26,6 @@ pub struct Mesh {
|
|||
/// which allows easy stable VertexBuffers (i.e. same buffer order)
|
||||
attributes: BTreeMap<Cow<'static, str>, VertexAttributeValues>,
|
||||
indices: Option<Indices>,
|
||||
gpu_data: Option<MeshGpuData>,
|
||||
}
|
||||
|
||||
/// Contains geometry in the form of a mesh.
|
||||
|
@ -282,7 +72,6 @@ impl Mesh {
|
|||
primitive_topology,
|
||||
attributes: Default::default(),
|
||||
indices: None,
|
||||
gpu_data: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,10 +79,6 @@ impl Mesh {
|
|||
self.primitive_topology
|
||||
}
|
||||
|
||||
pub fn gpu_data(&self) -> Option<&MeshGpuData> {
|
||||
self.gpu_data.as_ref()
|
||||
}
|
||||
|
||||
/// Sets the data for a vertex attribute (position, normal etc.). The name will
|
||||
/// often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`]
|
||||
pub fn set_attribute(
|
||||
|
@ -530,4 +315,257 @@ impl VertexFormatSize for wgpu::VertexFormat {
|
|||
VertexFormat::Float64x4 => 8 * 4,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An array where each entry describes a property of a single vertex.
|
||||
#[derive(Clone, Debug, EnumVariantMeta)]
|
||||
pub enum VertexAttributeValues {
|
||||
Float32(Vec<f32>),
|
||||
Sint32(Vec<i32>),
|
||||
Uint32(Vec<u32>),
|
||||
Float32x2(Vec<[f32; 2]>),
|
||||
Sint32x2(Vec<[i32; 2]>),
|
||||
Uint32x2(Vec<[u32; 2]>),
|
||||
Float32x3(Vec<[f32; 3]>),
|
||||
Sint32x3(Vec<[i32; 3]>),
|
||||
Uint32x3(Vec<[u32; 3]>),
|
||||
Float32x4(Vec<[f32; 4]>),
|
||||
Sint32x4(Vec<[i32; 4]>),
|
||||
Uint32x4(Vec<[u32; 4]>),
|
||||
Sint16x2(Vec<[i16; 2]>),
|
||||
Snorm16x2(Vec<[i16; 2]>),
|
||||
Uint16x2(Vec<[u16; 2]>),
|
||||
Unorm16x2(Vec<[u16; 2]>),
|
||||
Sint16x4(Vec<[i16; 4]>),
|
||||
Snorm16x4(Vec<[i16; 4]>),
|
||||
Uint16x4(Vec<[u16; 4]>),
|
||||
Unorm16x4(Vec<[u16; 4]>),
|
||||
Sint8x2(Vec<[i8; 2]>),
|
||||
Snorm8x2(Vec<[i8; 2]>),
|
||||
Uint8x2(Vec<[u8; 2]>),
|
||||
Unorm8x2(Vec<[u8; 2]>),
|
||||
Sint8x4(Vec<[i8; 4]>),
|
||||
Snorm8x4(Vec<[i8; 4]>),
|
||||
Uint8x4(Vec<[u8; 4]>),
|
||||
Unorm8x4(Vec<[u8; 4]>),
|
||||
}
|
||||
|
||||
impl VertexAttributeValues {
|
||||
/// Returns the number of vertices in this VertexAttribute. For a single
|
||||
/// mesh, all of the VertexAttributeValues must have the same length.
|
||||
pub fn len(&self) -> usize {
|
||||
match *self {
|
||||
VertexAttributeValues::Float32(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint32(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint32(ref values) => values.len(),
|
||||
VertexAttributeValues::Float32x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint32x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint32x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Float32x3(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint32x3(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint32x3(ref values) => values.len(),
|
||||
VertexAttributeValues::Float32x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint32x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint32x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint16x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Snorm16x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint16x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Unorm16x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint16x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Snorm16x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint16x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Unorm16x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint8x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Snorm8x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint8x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Unorm8x2(ref values) => values.len(),
|
||||
VertexAttributeValues::Sint8x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Snorm8x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Uint8x4(ref values) => values.len(),
|
||||
VertexAttributeValues::Unorm8x4(ref values) => values.len(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if there are no vertices in this VertexAttributeValue
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
fn as_float3(&self) -> Option<&[[f32; 3]]> {
|
||||
match self {
|
||||
VertexAttributeValues::Float32x3(values) => Some(values),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add vertex format as parameter here and perform type conversions
|
||||
/// Flattens the VertexAttributeArray into a sequence of bytes. This is
|
||||
/// useful for serialization and sending to the GPU.
|
||||
pub fn get_bytes(&self) -> &[u8] {
|
||||
match self {
|
||||
VertexAttributeValues::Float32(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint32(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint32(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Float32x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint32x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint32x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Float32x3(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint32x3(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint32x3(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Float32x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint32x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint32x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint16x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Snorm16x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint16x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Unorm16x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint16x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Snorm16x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint16x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Unorm16x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint8x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Snorm8x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint8x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Unorm8x2(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Sint8x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Snorm8x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Uint8x4(values) => cast_slice(&values[..]),
|
||||
VertexAttributeValues::Unorm8x4(values) => cast_slice(&values[..]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&VertexAttributeValues> for VertexFormat {
|
||||
fn from(values: &VertexAttributeValues) -> Self {
|
||||
match values {
|
||||
VertexAttributeValues::Float32(_) => VertexFormat::Float32,
|
||||
VertexAttributeValues::Sint32(_) => VertexFormat::Sint32,
|
||||
VertexAttributeValues::Uint32(_) => VertexFormat::Uint32,
|
||||
VertexAttributeValues::Float32x2(_) => VertexFormat::Float32x2,
|
||||
VertexAttributeValues::Sint32x2(_) => VertexFormat::Sint32x2,
|
||||
VertexAttributeValues::Uint32x2(_) => VertexFormat::Uint32x2,
|
||||
VertexAttributeValues::Float32x3(_) => VertexFormat::Float32x3,
|
||||
VertexAttributeValues::Sint32x3(_) => VertexFormat::Sint32x3,
|
||||
VertexAttributeValues::Uint32x3(_) => VertexFormat::Uint32x3,
|
||||
VertexAttributeValues::Float32x4(_) => VertexFormat::Float32x4,
|
||||
VertexAttributeValues::Sint32x4(_) => VertexFormat::Sint32x4,
|
||||
VertexAttributeValues::Uint32x4(_) => VertexFormat::Uint32x4,
|
||||
VertexAttributeValues::Sint16x2(_) => VertexFormat::Sint16x2,
|
||||
VertexAttributeValues::Snorm16x2(_) => VertexFormat::Snorm16x2,
|
||||
VertexAttributeValues::Uint16x2(_) => VertexFormat::Uint16x2,
|
||||
VertexAttributeValues::Unorm16x2(_) => VertexFormat::Unorm16x2,
|
||||
VertexAttributeValues::Sint16x4(_) => VertexFormat::Sint16x4,
|
||||
VertexAttributeValues::Snorm16x4(_) => VertexFormat::Snorm16x4,
|
||||
VertexAttributeValues::Uint16x4(_) => VertexFormat::Uint16x4,
|
||||
VertexAttributeValues::Unorm16x4(_) => VertexFormat::Unorm16x4,
|
||||
VertexAttributeValues::Sint8x2(_) => VertexFormat::Sint8x2,
|
||||
VertexAttributeValues::Snorm8x2(_) => VertexFormat::Snorm8x2,
|
||||
VertexAttributeValues::Uint8x2(_) => VertexFormat::Uint8x2,
|
||||
VertexAttributeValues::Unorm8x2(_) => VertexFormat::Unorm8x2,
|
||||
VertexAttributeValues::Sint8x4(_) => VertexFormat::Sint8x4,
|
||||
VertexAttributeValues::Snorm8x4(_) => VertexFormat::Snorm8x4,
|
||||
VertexAttributeValues::Uint8x4(_) => VertexFormat::Uint8x4,
|
||||
VertexAttributeValues::Unorm8x4(_) => VertexFormat::Unorm8x4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An array of indices into the VertexAttributeValues for a mesh.
|
||||
///
|
||||
/// It describes the order in which the vertex attributes should be joined into faces.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Indices {
|
||||
U16(Vec<u16>),
|
||||
U32(Vec<u32>),
|
||||
}
|
||||
|
||||
impl Indices {
|
||||
fn iter(&self) -> impl Iterator<Item = usize> + '_ {
|
||||
match self {
|
||||
Indices::U16(vec) => IndicesIter::U16(vec.iter()),
|
||||
Indices::U32(vec) => IndicesIter::U32(vec.iter()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Indices::U16(vec) => vec.len(),
|
||||
Indices::U32(vec) => vec.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
enum IndicesIter<'a> {
|
||||
U16(std::slice::Iter<'a, u16>),
|
||||
U32(std::slice::Iter<'a, u32>),
|
||||
}
|
||||
impl Iterator for IndicesIter<'_> {
|
||||
type Item = usize;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self {
|
||||
IndicesIter::U16(iter) => iter.next().map(|val| *val as usize),
|
||||
IndicesIter::U32(iter) => iter.next().map(|val| *val as usize),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Indices> for IndexFormat {
|
||||
fn from(indices: &Indices) -> Self {
|
||||
match indices {
|
||||
Indices::U16(_) => IndexFormat::Uint16,
|
||||
Indices::U32(_) => IndexFormat::Uint32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GpuMesh {
|
||||
pub vertex_buffer: Buffer,
|
||||
pub index_info: Option<GpuIndexInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GpuIndexInfo {
|
||||
pub buffer: Buffer,
|
||||
pub count: u32,
|
||||
}
|
||||
|
||||
impl RenderAsset for Mesh {
|
||||
type ExtractedAsset = Mesh;
|
||||
type PreparedAsset = GpuMesh;
|
||||
|
||||
fn extract_asset(&self) -> Self::ExtractedAsset {
|
||||
self.clone()
|
||||
}
|
||||
|
||||
fn prepare_asset(
|
||||
mesh: Self::ExtractedAsset,
|
||||
render_device: &RenderDevice,
|
||||
_render_queue: &RenderQueue,
|
||||
) -> Self::PreparedAsset {
|
||||
let vertex_buffer_data = mesh.get_vertex_buffer_data();
|
||||
let vertex_buffer = Buffer::from(render_device.create_buffer_with_data(
|
||||
&BufferInitDescriptor {
|
||||
usage: BufferUsage::VERTEX,
|
||||
label: None,
|
||||
contents: &vertex_buffer_data,
|
||||
},
|
||||
));
|
||||
|
||||
let index_info = mesh.get_index_buffer_bytes().map(|data| GpuIndexInfo {
|
||||
buffer: Buffer::from(render_device.create_buffer_with_data(
|
||||
&BufferInitDescriptor {
|
||||
usage: BufferUsage::INDEX,
|
||||
contents: &data,
|
||||
label: None,
|
||||
},
|
||||
)),
|
||||
count: mesh.indices().unwrap().len() as u32,
|
||||
});
|
||||
|
||||
GpuMesh {
|
||||
vertex_buffer,
|
||||
index_info,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,19 +3,17 @@ mod mesh;
|
|||
/// Generation for some primitive shape meshes.
|
||||
pub mod shape;
|
||||
|
||||
use bevy_asset::AddAsset;
|
||||
pub use mesh::*;
|
||||
|
||||
use bevy_app::{App, CoreStage, Plugin};
|
||||
use bevy_ecs::system::IntoSystem;
|
||||
use crate::render_asset::RenderAssetPlugin;
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_asset::AddAsset;
|
||||
|
||||
pub struct MeshPlugin;
|
||||
|
||||
impl Plugin for MeshPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_asset::<Mesh>().add_system_to_stage(
|
||||
CoreStage::PostUpdate,
|
||||
mesh_resource_provider_system.system(),
|
||||
);
|
||||
app.add_asset::<Mesh>()
|
||||
.add_plugin(RenderAssetPlugin::<Mesh>::default());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,14 @@ pub trait RenderAsset: Asset {
|
|||
}
|
||||
|
||||
/// Extracts assets into gpu-usable data
|
||||
#[derive(Default)]
|
||||
pub struct RenderAssetPlugin<A: RenderAsset>(PhantomData<fn() -> A>);
|
||||
|
||||
impl<A: RenderAsset> Default for RenderAssetPlugin<A> {
|
||||
fn default() -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: RenderAsset> Plugin for RenderAssetPlugin<A> {
|
||||
fn build(&self, app: &mut App) {
|
||||
let render_app = app.sub_app_mut(0);
|
||||
|
@ -49,7 +54,7 @@ impl<A: RenderAsset> Default for ExtractedAssets<A> {
|
|||
}
|
||||
}
|
||||
|
||||
pub type RenderAssets<A: RenderAsset> = HashMap<Handle<A>, A::PreparedAsset>;
|
||||
pub type RenderAssets<A> = HashMap<Handle<A>, <A as RenderAsset>::PreparedAsset>;
|
||||
|
||||
fn extract_render_asset<A: RenderAsset>(
|
||||
mut commands: Commands,
|
||||
|
|
|
@ -357,7 +357,6 @@ impl RenderAsset for Image {
|
|||
let texture = render_device.create_texture(&image.texture_descriptor);
|
||||
let sampler = render_device.create_sampler(&image.sampler_descriptor);
|
||||
|
||||
let width = image.texture_descriptor.size.width as usize;
|
||||
let format_size = image.texture_descriptor.format.pixel_size();
|
||||
render_queue.write_texture(
|
||||
ImageCopyTexture {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::{
|
||||
render_resource::{Texture, TextureView, TextureViewId},
|
||||
render_resource::{Texture, TextureView},
|
||||
renderer::RenderDevice,
|
||||
};
|
||||
use bevy_ecs::prelude::{Res, ResMut};
|
||||
use bevy_ecs::prelude::ResMut;
|
||||
use bevy_utils::HashMap;
|
||||
use wgpu::{TextureDescriptor, TextureViewDescriptor};
|
||||
|
||||
|
@ -72,7 +72,7 @@ impl TextureCache {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, device: &RenderDevice) {
|
||||
pub fn update(&mut self) {
|
||||
for textures in self.textures.values_mut() {
|
||||
for texture in textures.iter_mut() {
|
||||
texture.frames_since_last_use += 1;
|
||||
|
@ -84,9 +84,6 @@ impl TextureCache {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn update_texture_cache_system(
|
||||
mut texture_cache: ResMut<TextureCache>,
|
||||
render_device: Res<RenderDevice>,
|
||||
) {
|
||||
texture_cache.update(&render_device);
|
||||
pub fn update_texture_cache_system(mut texture_cache: ResMut<TextureCache>) {
|
||||
texture_cache.update();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::{
|
||||
render_resource::TextureView,
|
||||
renderer::{RenderDevice, RenderInstance},
|
||||
|
@ -10,7 +8,8 @@ use bevy_app::{App, Plugin};
|
|||
use bevy_ecs::prelude::*;
|
||||
use bevy_utils::HashMap;
|
||||
use bevy_window::{RawWindowHandleWrapper, WindowId, Windows};
|
||||
use wgpu::{SwapChainFrame, TextureFormat};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use wgpu::TextureFormat;
|
||||
|
||||
pub struct WindowRenderPlugin;
|
||||
|
||||
|
@ -77,10 +76,6 @@ pub struct WindowSurfaces {
|
|||
swap_chains: HashMap<WindowId, wgpu::SwapChain>,
|
||||
}
|
||||
|
||||
pub struct WindowSwapChain {
|
||||
value: TextureView,
|
||||
}
|
||||
|
||||
pub fn prepare_windows(
|
||||
mut windows: ResMut<ExtractedWindows>,
|
||||
mut window_surfaces: ResMut<WindowSurfaces>,
|
||||
|
|
|
@ -15,7 +15,7 @@ use bevy_render2::{
|
|||
view::{ViewMeta, ViewUniform, ViewUniformOffset},
|
||||
};
|
||||
use bevy_transform::components::GlobalTransform;
|
||||
use bevy_utils::HashMap;
|
||||
use bevy_utils::slab::{FrameSlabMap, FrameSlabMapKey};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use std::borrow::Cow;
|
||||
|
||||
|
@ -56,7 +56,6 @@ impl FromWorld for SpriteShaders {
|
|||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
// TODO: verify this is correct
|
||||
min_binding_size: BufferSize::new(std::mem::size_of::<ViewUniform>() as u64),
|
||||
},
|
||||
count: None,
|
||||
|
@ -204,9 +203,8 @@ pub struct SpriteMeta {
|
|||
indices: BufferVec<u32>,
|
||||
quad: Mesh,
|
||||
view_bind_group: Option<BindGroup>,
|
||||
// TODO: these should be garbage collected if unused across X frames
|
||||
texture_bind_groups: Vec<BindGroup>,
|
||||
texture_bind_group_indices: HashMap<Handle<Image>, usize>,
|
||||
texture_bind_group_keys: Vec<FrameSlabMapKey<Handle<Image>, BindGroup>>,
|
||||
texture_bind_groups: FrameSlabMap<Handle<Image>, BindGroup>,
|
||||
}
|
||||
|
||||
impl Default for SpriteMeta {
|
||||
|
@ -214,8 +212,8 @@ impl Default for SpriteMeta {
|
|||
Self {
|
||||
vertices: BufferVec::new(BufferUsage::VERTEX),
|
||||
indices: BufferVec::new(BufferUsage::INDEX),
|
||||
texture_bind_groups: Vec::new(),
|
||||
texture_bind_group_indices: HashMap::default(),
|
||||
texture_bind_groups: Default::default(),
|
||||
texture_bind_group_keys: Default::default(),
|
||||
view_bind_group: None,
|
||||
quad: Quad {
|
||||
size: Vec2::new(1.0, 1.0),
|
||||
|
@ -320,16 +318,15 @@ pub fn queue_sprites(
|
|||
});
|
||||
let sprite_meta = &mut *sprite_meta;
|
||||
let draw_sprite_function = draw_functions.read().get_id::<DrawSprite>().unwrap();
|
||||
sprite_meta.texture_bind_groups.next_frame();
|
||||
sprite_meta.texture_bind_group_keys.clear();
|
||||
for mut transparent_phase in views.iter_mut() {
|
||||
let texture_bind_groups = &mut sprite_meta.texture_bind_groups;
|
||||
for (i, sprite) in extracted_sprites.sprites.iter().enumerate() {
|
||||
let bind_group_index = *sprite_meta
|
||||
.texture_bind_group_indices
|
||||
.entry(sprite.handle.clone_weak())
|
||||
.or_insert_with(|| {
|
||||
let texture_bind_group_key = sprite_meta.texture_bind_groups.get_or_insert_with(
|
||||
sprite.handle.clone_weak(),
|
||||
|| {
|
||||
let gpu_image = gpu_images.get(&sprite.handle).unwrap();
|
||||
let index = texture_bind_groups.len();
|
||||
let bind_group = render_device.create_bind_group(&BindGroupDescriptor {
|
||||
render_device.create_bind_group(&BindGroupDescriptor {
|
||||
entries: &[
|
||||
BindGroupEntry {
|
||||
binding: 0,
|
||||
|
@ -342,14 +339,17 @@ pub fn queue_sprites(
|
|||
],
|
||||
label: None,
|
||||
layout: &sprite_shaders.material_layout,
|
||||
});
|
||||
texture_bind_groups.push(bind_group);
|
||||
index
|
||||
});
|
||||
})
|
||||
},
|
||||
);
|
||||
sprite_meta
|
||||
.texture_bind_group_keys
|
||||
.push(texture_bind_group_key);
|
||||
|
||||
transparent_phase.add(Drawable {
|
||||
draw_function: draw_sprite_function,
|
||||
draw_key: i,
|
||||
sort_key: bind_group_index,
|
||||
sort_key: texture_bind_group_key.index(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -400,7 +400,7 @@ impl Draw for DrawSprite {
|
|||
pass: &mut TrackedRenderPass<'w>,
|
||||
view: Entity,
|
||||
draw_key: usize,
|
||||
sort_key: usize,
|
||||
_sort_key: usize,
|
||||
) {
|
||||
const INDICES: usize = 6;
|
||||
let (sprite_shaders, sprite_meta, views) = self.params.get(world);
|
||||
|
@ -418,7 +418,11 @@ impl Draw for DrawSprite {
|
|||
sprite_meta.view_bind_group.as_ref().unwrap(),
|
||||
&[view_uniform.offset],
|
||||
);
|
||||
pass.set_bind_group(1, &sprite_meta.texture_bind_groups[sort_key], &[]);
|
||||
pass.set_bind_group(
|
||||
1,
|
||||
&sprite_meta.texture_bind_groups[sprite_meta.texture_bind_group_keys[draw_key]],
|
||||
&[],
|
||||
);
|
||||
|
||||
pass.draw_indexed(
|
||||
(draw_key * INDICES) as u32..(draw_key * INDICES + INDICES) as u32,
|
||||
|
|
Loading…
Reference in a new issue