Port Mesh to RenderAsset, add Slab and FrameSlabMap garbage collection for Bind Groups

This commit is contained in:
Carter Anderson 2021-06-26 15:35:07 -07:00
parent 3ef951dcbc
commit 25de2d1819
16 changed files with 591 additions and 418 deletions

View file

@ -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;

View 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()
}
}

View file

@ -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);

View file

@ -48,7 +48,6 @@ impl Plugin for PbrPlugin {
)
.init_resource::<PbrShaders>()
.init_resource::<ShadowShaders>()
.init_resource::<MaterialMeta>()
.init_resource::<MeshMeta>()
.init_resource::<LightMeta>();

View file

@ -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,

View file

@ -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 {

View file

@ -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 {

View file

@ -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)

View file

@ -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,
});
}
}
}

View file

@ -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,
}
}
}

View file

@ -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());
}
}

View file

@ -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,

View file

@ -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 {

View file

@ -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();
}

View file

@ -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>,

View file

@ -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,