batched resource creation, vertex buffer macro
This commit is contained in:
parent
8f4296c4ff
commit
7660b8bf3f
@ -4,7 +4,7 @@ use darling::FromMeta;
|
|||||||
use inflector::Inflector;
|
use inflector::Inflector;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields};
|
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields, Type};
|
||||||
|
|
||||||
#[derive(FromMeta, Debug, Default)]
|
#[derive(FromMeta, Debug, Default)]
|
||||||
struct EntityArchetypeAttributeArgs {
|
struct EntityArchetypeAttributeArgs {
|
||||||
@ -67,7 +67,9 @@ struct UniformAttributeArgs {
|
|||||||
#[darling(default)]
|
#[darling(default)]
|
||||||
pub shader_def: Option<bool>,
|
pub shader_def: Option<bool>,
|
||||||
#[darling(default)]
|
#[darling(default)]
|
||||||
pub instanceable: Option<bool>,
|
pub instance: Option<bool>,
|
||||||
|
#[darling(default)]
|
||||||
|
pub vertex: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(Uniforms, attributes(uniform))]
|
#[proc_macro_derive(Uniforms, attributes(uniform))]
|
||||||
@ -152,6 +154,53 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
|
|||||||
.map(|field| field.ident.as_ref().unwrap().to_string())
|
.map(|field| field.ident.as_ref().unwrap().to_string())
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let vertex_buffer_fields = uniform_fields
|
||||||
|
.iter()
|
||||||
|
.map(|(field, attrs)| {
|
||||||
|
(
|
||||||
|
field,
|
||||||
|
match attrs {
|
||||||
|
Some(attrs) => (
|
||||||
|
(match attrs.instance {
|
||||||
|
Some(instance) => instance,
|
||||||
|
None => false,
|
||||||
|
}),
|
||||||
|
(match attrs.vertex {
|
||||||
|
Some(vertex) => vertex,
|
||||||
|
None => false,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
None => (false, false),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.filter(|(_f, (instance, vertex))| *instance || *vertex);
|
||||||
|
|
||||||
|
let vertex_buffer_field_types = vertex_buffer_fields
|
||||||
|
.clone()
|
||||||
|
.map(|(f, _)| &f.ty)
|
||||||
|
.collect::<Vec<&Type>>();
|
||||||
|
|
||||||
|
let vertex_buffer_field_names_pascal = vertex_buffer_fields
|
||||||
|
.map(|(f, (instance, _vertex))| {
|
||||||
|
let pascal_field = f.ident.as_ref().unwrap().to_string().to_pascal_case();
|
||||||
|
if instance {
|
||||||
|
format!(
|
||||||
|
"I_{}_{}",
|
||||||
|
struct_name,
|
||||||
|
pascal_field
|
||||||
|
)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"{}_{}",
|
||||||
|
struct_name,
|
||||||
|
pascal_field
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
let mut uniform_name_strings = Vec::new();
|
let mut uniform_name_strings = Vec::new();
|
||||||
let mut texture_and_sampler_name_strings = Vec::new();
|
let mut texture_and_sampler_name_strings = Vec::new();
|
||||||
let mut texture_and_sampler_name_idents = Vec::new();
|
let mut texture_and_sampler_name_idents = Vec::new();
|
||||||
@ -175,8 +224,8 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
|
|||||||
texture_and_sampler_name_idents.push(f.ident.clone());
|
texture_and_sampler_name_idents.push(f.ident.clone());
|
||||||
texture_and_sampler_name_idents.push(f.ident.clone());
|
texture_and_sampler_name_idents.push(f.ident.clone());
|
||||||
let is_instanceable = match attrs {
|
let is_instanceable = match attrs {
|
||||||
Some(attrs) => match attrs.instanceable {
|
Some(attrs) => match attrs.instance {
|
||||||
Some(instanceable) => instanceable,
|
Some(instance) => instance,
|
||||||
None => false,
|
None => false,
|
||||||
},
|
},
|
||||||
None => false,
|
None => false,
|
||||||
@ -197,16 +246,39 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
static #vertex_buffer_descriptor_ident: bevy::once_cell::sync::Lazy<bevy::render::pipeline::VertexBufferDescriptor> =
|
static #vertex_buffer_descriptor_ident: bevy::once_cell::sync::Lazy<bevy::render::pipeline::VertexBufferDescriptor> =
|
||||||
bevy::once_cell::sync::Lazy::new(|| {
|
bevy::once_cell::sync::Lazy::new(|| {
|
||||||
use bevy::render::pipeline::AsVertexFormats;
|
use bevy::render::pipeline::{VertexFormat, AsVertexFormats, VertexAttributeDescriptor};
|
||||||
// let vertex_formats = vec![
|
|
||||||
// #(#active_uniform_field_types::as_vertex_formats(),)*
|
let mut vertex_formats: Vec<(&str,&[VertexFormat])> = vec![
|
||||||
// ];
|
#((#vertex_buffer_field_names_pascal, <#vertex_buffer_field_types>::as_vertex_formats()),)*
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut shader_location = 0;
|
||||||
|
let mut offset = 0;
|
||||||
|
let vertex_attribute_descriptors = vertex_formats.drain(..).map(|(name, formats)| {
|
||||||
|
formats.iter().enumerate().map(|(i, format)| {
|
||||||
|
let size = format.get_size();
|
||||||
|
let formatted_name = if formats.len() > 1 {
|
||||||
|
format!("{}_{}", name, i)
|
||||||
|
} else {
|
||||||
|
format!("{}", name)
|
||||||
|
};
|
||||||
|
let descriptor = VertexAttributeDescriptor {
|
||||||
|
name: formatted_name,
|
||||||
|
offset,
|
||||||
|
format: *format,
|
||||||
|
shader_location,
|
||||||
|
};
|
||||||
|
offset += size;
|
||||||
|
shader_location += 1;
|
||||||
|
descriptor
|
||||||
|
}).collect::<Vec<VertexAttributeDescriptor>>()
|
||||||
|
}).flatten().collect::<Vec<VertexAttributeDescriptor>>();
|
||||||
|
|
||||||
bevy::render::pipeline::VertexBufferDescriptor {
|
bevy::render::pipeline::VertexBufferDescriptor {
|
||||||
attributes: Vec::new(),
|
attributes: vertex_attribute_descriptors,
|
||||||
name: #struct_name_string.to_string(),
|
name: #struct_name_string.to_string(),
|
||||||
step_mode: bevy::render::pipeline::InputStepMode::Instance,
|
step_mode: bevy::render::pipeline::InputStepMode::Instance,
|
||||||
stride: 0,
|
stride: offset,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -26,14 +26,14 @@ fn setup(world: &mut World, resources: &mut Resources) {
|
|||||||
.add_entity(MeshEntity {
|
.add_entity(MeshEntity {
|
||||||
mesh: plane_handle,
|
mesh: plane_handle,
|
||||||
material: plane_material_handle,
|
material: plane_material_handle,
|
||||||
// renderable: Renderable::instanced(),
|
renderable: Renderable::instanced(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// cube
|
// cube
|
||||||
.add_entity(MeshEntity {
|
.add_entity(MeshEntity {
|
||||||
mesh: cube_handle,
|
mesh: cube_handle,
|
||||||
material: cube_material_handle,
|
material: cube_material_handle,
|
||||||
// renderable: Renderable::instanced(),
|
renderable: Renderable::instanced(),
|
||||||
translation: Translation::new(-1.5, 0.0, 1.0),
|
translation: Translation::new(-1.5, 0.0, 1.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
@ -41,7 +41,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
|
|||||||
.add_entity(MeshEntity {
|
.add_entity(MeshEntity {
|
||||||
mesh: cube_handle,
|
mesh: cube_handle,
|
||||||
material: cube_material_handle,
|
material: cube_material_handle,
|
||||||
// renderable: Renderable::instanced(),
|
renderable: Renderable::instanced(),
|
||||||
translation: Translation::new(1.5, 0.0, 1.0),
|
translation: Translation::new(1.5, 0.0, 1.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
|
@ -6,7 +6,7 @@ use std::{
|
|||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{collections::HashMap, marker::PhantomData};
|
use std::{collections::HashMap, marker::PhantomData, any::TypeId};
|
||||||
|
|
||||||
pub type HandleId = usize;
|
pub type HandleId = usize;
|
||||||
|
|
||||||
@ -65,6 +65,32 @@ impl<T> Clone for Handle<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Hash, Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
|
pub struct HandleUntyped {
|
||||||
|
pub id: HandleId,
|
||||||
|
pub type_id: TypeId,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<T> From<Handle<T>> for HandleUntyped where T: 'static {
|
||||||
|
fn from(handle: Handle<T>) -> Self {
|
||||||
|
HandleUntyped {
|
||||||
|
id: handle.id,
|
||||||
|
type_id: TypeId::of::<T>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<HandleUntyped> for Handle<T> where T: 'static {
|
||||||
|
fn from(handle: HandleUntyped) -> Self {
|
||||||
|
if TypeId::of::<T>() != handle.type_id {
|
||||||
|
panic!("attempted to convert untyped handle to incorrect typed handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle::new(handle.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Asset<D> {
|
pub trait Asset<D> {
|
||||||
fn load(descriptor: D) -> Self;
|
fn load(descriptor: D) -> Self;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,33 @@ pub trait GetBytes {
|
|||||||
fn get_bytes_ref(&self) -> Option<&[u8]>;
|
fn get_bytes_ref(&self) -> Option<&[u8]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GetBytes for [f32; 2] {
|
||||||
|
fn get_bytes(&self) -> Vec<u8> {
|
||||||
|
self.as_bytes().to_vec()
|
||||||
|
}
|
||||||
|
fn get_bytes_ref(&self) -> Option<&[u8]> {
|
||||||
|
Some(self.as_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetBytes for [f32; 3] {
|
||||||
|
fn get_bytes(&self) -> Vec<u8> {
|
||||||
|
self.as_bytes().to_vec()
|
||||||
|
}
|
||||||
|
fn get_bytes_ref(&self) -> Option<&[u8]> {
|
||||||
|
Some(self.as_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetBytes for [f32; 4] {
|
||||||
|
fn get_bytes(&self) -> Vec<u8> {
|
||||||
|
self.as_bytes().to_vec()
|
||||||
|
}
|
||||||
|
fn get_bytes_ref(&self) -> Option<&[u8]> {
|
||||||
|
Some(self.as_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GetBytes for Vec4 {
|
impl GetBytes for Vec4 {
|
||||||
fn get_bytes(&self) -> Vec<u8> {
|
fn get_bytes(&self) -> Vec<u8> {
|
||||||
let vec4_array: [f32; 4] = (*self).into();
|
let vec4_array: [f32; 4] = (*self).into();
|
||||||
|
@ -17,15 +17,16 @@ impl DrawTarget for AssignedBatchesDrawTarget {
|
|||||||
&self,
|
&self,
|
||||||
_world: &World,
|
_world: &World,
|
||||||
resources: &Resources,
|
resources: &Resources,
|
||||||
_render_pass: &mut dyn RenderPass,
|
render_pass: &mut dyn RenderPass,
|
||||||
_pipeline_handle: Handle<PipelineDescriptor>,
|
_pipeline_handle: Handle<PipelineDescriptor>,
|
||||||
) {
|
) {
|
||||||
let asset_batches = resources.get::<AssetBatchers>().unwrap();
|
let asset_batches = resources.get::<AssetBatchers>().unwrap();
|
||||||
// let renderer = render_pass.get_renderer();
|
// let renderer = render_pass.get_renderer();
|
||||||
// println!("Drawing batches");
|
// println!("Drawing batches");
|
||||||
for batch in asset_batches.get_batches() {
|
for batch in asset_batches.get_batches() {
|
||||||
// render_resources.get
|
|
||||||
// println!("{:?}", batch);
|
// println!("{:?}", batch);
|
||||||
|
// render_pass.set_bind_groups(batch.render_resource_assignments.as_ref());
|
||||||
|
// render_pass.draw_indexed(0..1, 0, 0..1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// println!();
|
// println!();
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use crate::math::{Mat4, Vec2, Vec3, Vec4};
|
use crate::{
|
||||||
|
math::{Mat4, Vec2, Vec3, Vec4},
|
||||||
|
render::Color,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
pub enum VertexFormat {
|
pub enum VertexFormat {
|
||||||
@ -109,3 +112,27 @@ impl AsVertexFormats for Mat4 {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsVertexFormats for Color {
|
||||||
|
fn as_vertex_formats() -> &'static [VertexFormat] {
|
||||||
|
&[VertexFormat::Float4]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsVertexFormats for [f32; 2] {
|
||||||
|
fn as_vertex_formats() -> &'static [VertexFormat] {
|
||||||
|
&[VertexFormat::Float2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsVertexFormats for [f32; 3] {
|
||||||
|
fn as_vertex_formats() -> &'static [VertexFormat] {
|
||||||
|
&[VertexFormat::Float3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsVertexFormats for [f32; 4] {
|
||||||
|
fn as_vertex_formats() -> &'static [VertexFormat] {
|
||||||
|
&[VertexFormat::Float4]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::{RenderResourceAssignments};
|
use super::RenderResourceAssignments;
|
||||||
use crate::asset::{Handle, HandleId};
|
use crate::asset::{Handle, HandleId, HandleUntyped};
|
||||||
use legion::prelude::Entity;
|
use legion::prelude::Entity;
|
||||||
use std::{any::TypeId, collections::HashMap, hash::Hash};
|
use std::{any::TypeId, collections::HashMap, hash::Hash};
|
||||||
|
|
||||||
@ -30,6 +30,7 @@ impl EntitySetState2 {
|
|||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Default)]
|
#[derive(PartialEq, Eq, Debug, Default)]
|
||||||
pub struct Batch {
|
pub struct Batch {
|
||||||
|
pub handles: Vec<HandleUntyped>,
|
||||||
pub entity_indices: HashMap<Entity, usize>,
|
pub entity_indices: HashMap<Entity, usize>,
|
||||||
pub current_index: usize,
|
pub current_index: usize,
|
||||||
pub render_resource_assignments: Option<RenderResourceAssignments>,
|
pub render_resource_assignments: Option<RenderResourceAssignments>,
|
||||||
@ -73,6 +74,16 @@ impl AssetSetBatcher2 {
|
|||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let mut batch = Batch::default();
|
let mut batch = Batch::default();
|
||||||
|
|
||||||
|
batch.handles.push(HandleUntyped {
|
||||||
|
id: key.handle1,
|
||||||
|
type_id: self.key.handle1_type,
|
||||||
|
});
|
||||||
|
batch.handles.push(HandleUntyped {
|
||||||
|
id: key.handle2,
|
||||||
|
type_id: self.key.handle2_type,
|
||||||
|
});
|
||||||
|
|
||||||
batch.add_entity(entity);
|
batch.add_entity(entity);
|
||||||
self.set_batches.insert(key, batch);
|
self.set_batches.insert(key, batch);
|
||||||
}
|
}
|
||||||
@ -141,6 +152,10 @@ impl AssetBatcher for AssetSetBatcher2 {
|
|||||||
fn get_batches<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Batch> + 'a> {
|
fn get_batches<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Batch> + 'a> {
|
||||||
Box::new(self.set_batches.values())
|
Box::new(self.set_batches.values())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_batches_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &'a mut Batch> + 'a> {
|
||||||
|
Box::new(self.set_batches.values_mut())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AssetBatcher {
|
pub trait AssetBatcher {
|
||||||
@ -149,12 +164,14 @@ pub trait AssetBatcher {
|
|||||||
// TODO: add pipeline handle here
|
// TODO: add pipeline handle here
|
||||||
fn get_batches2(&self) -> std::collections::hash_map::Iter<'_, BatchKey2, Batch>;
|
fn get_batches2(&self) -> std::collections::hash_map::Iter<'_, BatchKey2, Batch>;
|
||||||
fn get_batches<'a>(&'a self) -> Box<dyn Iterator<Item = &Batch> + 'a>;
|
fn get_batches<'a>(&'a self) -> Box<dyn Iterator<Item = &Batch> + 'a>;
|
||||||
|
fn get_batches_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &mut Batch> + 'a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct AssetBatchers {
|
pub struct AssetBatchers {
|
||||||
asset_batchers: Vec<Box<dyn AssetBatcher + Send + Sync>>,
|
asset_batchers: Vec<Box<dyn AssetBatcher + Send + Sync>>,
|
||||||
asset_batcher_indices2: HashMap<AssetSetBatcherKey2, usize>,
|
asset_batcher_indices2: HashMap<AssetSetBatcherKey2, usize>,
|
||||||
|
handle_batchers: HashMap<TypeId, Vec<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssetBatchers {
|
impl AssetBatchers {
|
||||||
@ -163,8 +180,10 @@ impl AssetBatchers {
|
|||||||
T: 'static,
|
T: 'static,
|
||||||
{
|
{
|
||||||
let handle_type = TypeId::of::<T>();
|
let handle_type = TypeId::of::<T>();
|
||||||
for asset_batcher in self.asset_batchers.iter_mut() {
|
if let Some(batcher_indices) = self.handle_batchers.get(&handle_type) {
|
||||||
asset_batcher.set_entity_handle(entity, handle_type, handle.id);
|
for index in batcher_indices.iter() {
|
||||||
|
self.asset_batchers[*index].set_entity_handle(entity, handle_type, handle.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,8 +200,21 @@ impl AssetBatchers {
|
|||||||
self.asset_batchers
|
self.asset_batchers
|
||||||
.push(Box::new(AssetSetBatcher2::new(key.clone())));
|
.push(Box::new(AssetSetBatcher2::new(key.clone())));
|
||||||
|
|
||||||
self.asset_batcher_indices2
|
let index = self.asset_batchers.len() - 1;
|
||||||
.insert(key, self.asset_batchers.len() - 1);
|
|
||||||
|
let handle1_batchers = self
|
||||||
|
.handle_batchers
|
||||||
|
.entry(key.handle1_type.clone())
|
||||||
|
.or_insert_with(|| Vec::new());
|
||||||
|
handle1_batchers.push(index);
|
||||||
|
|
||||||
|
let handle2_batchers = self
|
||||||
|
.handle_batchers
|
||||||
|
.entry(key.handle2_type.clone())
|
||||||
|
.or_insert_with(|| Vec::new());
|
||||||
|
handle2_batchers.push(index);
|
||||||
|
|
||||||
|
self.asset_batcher_indices2.insert(key, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_batches2<T1, T2>(
|
pub fn get_batches2<T1, T2>(
|
||||||
@ -226,14 +258,58 @@ impl AssetBatchers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_batches<'a>(&'a self) -> Box<dyn Iterator<Item = &Batch> + 'a> {
|
pub fn get_batches(&self) -> impl Iterator<Item = &Batch> {
|
||||||
Box::new(
|
self.asset_batchers
|
||||||
self.asset_batchers
|
.iter()
|
||||||
.iter()
|
.map(|a| a.get_batches())
|
||||||
.map(|a| a.get_batches())
|
.flatten()
|
||||||
.flatten(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_batcher_indices<T>(&self) -> impl Iterator<Item = &usize>
|
||||||
|
where
|
||||||
|
T: 'static,
|
||||||
|
{
|
||||||
|
let handle_type = TypeId::of::<T>();
|
||||||
|
self.handle_batchers
|
||||||
|
.get(&handle_type)
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_batches_from_batcher(&self, index: usize) -> impl Iterator<Item = &Batch>
|
||||||
|
{
|
||||||
|
self.asset_batchers[index].get_batches()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_batches_from_batcher_mut(&mut self, index: usize) -> impl Iterator<Item = &mut Batch>
|
||||||
|
{
|
||||||
|
self.asset_batchers[index].get_batches_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn get_handle_batches<T>(&self) -> Option<impl Iterator<Item = &Batch>>
|
||||||
|
// where
|
||||||
|
// T: 'static,
|
||||||
|
// {
|
||||||
|
// let handle_type = TypeId::of::<T>();
|
||||||
|
// if let Some(batcher_indices) = self.handle_batchers.get(&handle_type) {
|
||||||
|
// Some(
|
||||||
|
// self.asset_batchers
|
||||||
|
// .iter()
|
||||||
|
// .enumerate()
|
||||||
|
// .filter(|(index, a)| {
|
||||||
|
// let handle_type = TypeId::of::<T>();
|
||||||
|
// self.handle_batchers
|
||||||
|
// .get(&handle_type)
|
||||||
|
// .unwrap()
|
||||||
|
// .contains(index)
|
||||||
|
// })
|
||||||
|
// .map(|(index, a)| a.get_batches())
|
||||||
|
// .flatten(),
|
||||||
|
// )
|
||||||
|
// } else {
|
||||||
|
// None
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -263,7 +339,10 @@ mod tests {
|
|||||||
assert_eq!(asset_batchers.get_batch2(a1, b1), None);
|
assert_eq!(asset_batchers.get_batch2(a1, b1), None);
|
||||||
asset_batchers.set_entity_handle(entities[0], b1);
|
asset_batchers.set_entity_handle(entities[0], b1);
|
||||||
// entity[0] is added to batch when it has both Handle<A> and Handle<B>
|
// entity[0] is added to batch when it has both Handle<A> and Handle<B>
|
||||||
let mut expected_batch = Batch::default();
|
let mut expected_batch = Batch {
|
||||||
|
handles: vec![a1.into(), b1.into()],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
expected_batch.add_entity(entities[0]);
|
expected_batch.add_entity(entities[0]);
|
||||||
assert_eq!(asset_batchers.get_batch2(a1, b1).unwrap(), &expected_batch);
|
assert_eq!(asset_batchers.get_batch2(a1, b1).unwrap(), &expected_batch);
|
||||||
asset_batchers.set_entity_handle(entities[0], c1);
|
asset_batchers.set_entity_handle(entities[0], c1);
|
||||||
@ -272,7 +351,10 @@ mod tests {
|
|||||||
asset_batchers.set_entity_handle(entities[1], b1);
|
asset_batchers.set_entity_handle(entities[1], b1);
|
||||||
|
|
||||||
// all entities with Handle<A> and Handle<B> are returned
|
// all entities with Handle<A> and Handle<B> are returned
|
||||||
let mut expected_batch = Batch::default();
|
let mut expected_batch = Batch {
|
||||||
|
handles: vec![a1.into(), b1.into()],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
expected_batch.add_entity(entities[0]);
|
expected_batch.add_entity(entities[0]);
|
||||||
expected_batch.add_entity(entities[1]);
|
expected_batch.add_entity(entities[1]);
|
||||||
assert_eq!(asset_batchers.get_batch2(a1, b1).unwrap(), &expected_batch);
|
assert_eq!(asset_batchers.get_batch2(a1, b1).unwrap(), &expected_batch);
|
||||||
@ -290,10 +372,16 @@ mod tests {
|
|||||||
.collect::<Vec<(&BatchKey2, &Batch)>>();
|
.collect::<Vec<(&BatchKey2, &Batch)>>();
|
||||||
|
|
||||||
batches.sort_by(|a, b| a.0.cmp(b.0));
|
batches.sort_by(|a, b| a.0.cmp(b.0));
|
||||||
let mut expected_batch1 = Batch::default();
|
let mut expected_batch1 = Batch {
|
||||||
|
handles: vec![a1.into(), b1.into()],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
expected_batch1.add_entity(entities[0]);
|
expected_batch1.add_entity(entities[0]);
|
||||||
expected_batch1.add_entity(entities[1]);
|
expected_batch1.add_entity(entities[1]);
|
||||||
let mut expected_batch2 = Batch::default();
|
let mut expected_batch2 = Batch {
|
||||||
|
handles: vec![a2.into(), b2.into()],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
expected_batch2.add_entity(entities[2]);
|
expected_batch2.add_entity(entities[2]);
|
||||||
let mut expected_batches = vec![
|
let mut expected_batches = vec![
|
||||||
(
|
(
|
||||||
|
@ -11,6 +11,8 @@ pub trait ResourceProvider {
|
|||||||
}
|
}
|
||||||
fn update(&mut self, _renderer: &mut dyn Renderer, _world: &mut World, _resources: &Resources) {
|
fn update(&mut self, _renderer: &mut dyn Renderer, _world: &mut World, _resources: &Resources) {
|
||||||
}
|
}
|
||||||
|
fn finish_update(&mut self, _renderer: &mut dyn Renderer, _world: &mut World, _resources: &Resources) {
|
||||||
|
}
|
||||||
fn resize(
|
fn resize(
|
||||||
&mut self,
|
&mut self,
|
||||||
_renderer: &mut dyn Renderer,
|
_renderer: &mut dyn Renderer,
|
||||||
|
@ -3,9 +3,10 @@ use crate::{
|
|||||||
render::{
|
render::{
|
||||||
pipeline::BindType,
|
pipeline::BindType,
|
||||||
render_resource::{
|
render_resource::{
|
||||||
AssetBatchers, BufferArrayInfo, BufferInfo, BufferUsage,
|
AssetBatchers, BufferArrayInfo, BufferDynamicUniformInfo, BufferInfo, BufferUsage,
|
||||||
EntityRenderResourceAssignments, RenderResource, RenderResourceAssignments,
|
EntityRenderResourceAssignments, RenderResource, RenderResourceAssignments,
|
||||||
RenderResourceAssignmentsProvider, ResourceInfo, ResourceProvider, BufferDynamicUniformInfo,
|
RenderResourceAssignmentsId, RenderResourceAssignmentsProvider, ResourceInfo,
|
||||||
|
ResourceProvider,
|
||||||
},
|
},
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
shader::{AsUniforms, UniformInfoIter},
|
shader::{AsUniforms, UniformInfoIter},
|
||||||
@ -27,8 +28,14 @@ where
|
|||||||
{
|
{
|
||||||
_marker: PhantomData<T>,
|
_marker: PhantomData<T>,
|
||||||
// PERF: somehow remove this HashSet
|
// PERF: somehow remove this HashSet
|
||||||
uniform_buffer_info_resources:
|
uniform_buffer_info_resources: HashMap<
|
||||||
HashMap<String, (Option<RenderResource>, usize, HashSet<Entity>)>,
|
String,
|
||||||
|
(
|
||||||
|
Option<RenderResource>,
|
||||||
|
usize,
|
||||||
|
HashSet<RenderResourceAssignmentsId>,
|
||||||
|
),
|
||||||
|
>,
|
||||||
asset_resources: HashMap<Handle<T>, HashMap<String, RenderResource>>,
|
asset_resources: HashMap<Handle<T>, HashMap<String, RenderResource>>,
|
||||||
resource_query: Query<
|
resource_query: Query<
|
||||||
(Read<T>, Read<Renderable>),
|
(Read<T>, Read<Renderable>),
|
||||||
@ -94,8 +101,7 @@ where
|
|||||||
entity_render_resource_assignments.get_mut(entity).unwrap()
|
entity_render_resource_assignments.get_mut(entity).unwrap()
|
||||||
};
|
};
|
||||||
if let Some(uniforms) = asset_storage.get(&handle) {
|
if let Some(uniforms) = asset_storage.get(&handle) {
|
||||||
self.setup_entity_uniform_resources(
|
self.setup_uniform_resources(
|
||||||
entity,
|
|
||||||
uniforms,
|
uniforms,
|
||||||
renderer,
|
renderer,
|
||||||
resources,
|
resources,
|
||||||
@ -111,9 +117,8 @@ where
|
|||||||
self.handle_query = Some(handle_query);
|
self.handle_query = Some(handle_query);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_entity_uniform_resources(
|
fn setup_uniform_resources(
|
||||||
&mut self,
|
&mut self,
|
||||||
entity: Entity,
|
|
||||||
uniforms: &T,
|
uniforms: &T,
|
||||||
renderer: &mut dyn Renderer,
|
renderer: &mut dyn Renderer,
|
||||||
resources: &Resources,
|
resources: &Resources,
|
||||||
@ -131,11 +136,12 @@ where
|
|||||||
.insert(uniform_info.name.to_string(), (None, 0, HashSet::new()));
|
.insert(uniform_info.name.to_string(), (None, 0, HashSet::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (_resource, counts, entities) = self
|
let (_resource, counts, render_resource_assignments_ids) = self
|
||||||
.uniform_buffer_info_resources
|
.uniform_buffer_info_resources
|
||||||
.get_mut(uniform_info.name)
|
.get_mut(uniform_info.name)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
entities.insert(entity);
|
render_resource_assignments_ids
|
||||||
|
.insert(render_resource_assignments.get_id());
|
||||||
*counts += 1;
|
*counts += 1;
|
||||||
} else {
|
} else {
|
||||||
let handle = asset_handle.expect(
|
let handle = asset_handle.expect(
|
||||||
@ -269,9 +275,8 @@ where
|
|||||||
world: &World,
|
world: &World,
|
||||||
resources: &Resources,
|
resources: &Resources,
|
||||||
) {
|
) {
|
||||||
let entity_render_resource_assignments = resources
|
let entity_render_resource_assignments =
|
||||||
.get::<EntityRenderResourceAssignments>()
|
resources.get::<EntityRenderResourceAssignments>().unwrap();
|
||||||
.unwrap();
|
|
||||||
// allocate uniform buffers
|
// allocate uniform buffers
|
||||||
for (name, (resource, count, _entities)) in self.uniform_buffer_info_resources.iter_mut() {
|
for (name, (resource, count, _entities)) in self.uniform_buffer_info_resources.iter_mut() {
|
||||||
let count = *count as u64;
|
let count = *count as u64;
|
||||||
@ -317,6 +322,7 @@ where
|
|||||||
..
|
..
|
||||||
})) = resource_info
|
})) = resource_info
|
||||||
{
|
{
|
||||||
|
// TODO: properly handle alignments > BIND_BUFFER_ALIGNMENT
|
||||||
let size = BIND_BUFFER_ALIGNMENT * *count as u64;
|
let size = BIND_BUFFER_ALIGNMENT * *count as u64;
|
||||||
let alignment = BIND_BUFFER_ALIGNMENT as usize;
|
let alignment = BIND_BUFFER_ALIGNMENT as usize;
|
||||||
let mut offset = 0usize;
|
let mut offset = 0usize;
|
||||||
@ -324,14 +330,21 @@ where
|
|||||||
// TODO: only mem-map entities if their data has changed
|
// TODO: only mem-map entities if their data has changed
|
||||||
// PERF: These hashmap inserts are pretty expensive (10 fps for 10000 entities)
|
// PERF: These hashmap inserts are pretty expensive (10 fps for 10000 entities)
|
||||||
for (entity, (_, renderable)) in self.resource_query.iter_entities(world) {
|
for (entity, (_, renderable)) in self.resource_query.iter_entities(world) {
|
||||||
if renderable.is_instanced || !entities.contains(&entity) {
|
if renderable.is_instanced {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(render_resource) = entity_render_resource_assignments.get(entity) {
|
// this unwrap is safe because the assignments were created in the calling function
|
||||||
dynamic_uniform_info.offsets.insert(render_resource.get_id(), offset as u32);
|
let render_resource_assignments =
|
||||||
|
entity_render_resource_assignments.get(entity).unwrap();
|
||||||
|
if !entities.contains(&render_resource_assignments.get_id()) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dynamic_uniform_info
|
||||||
|
.offsets
|
||||||
|
.insert(render_resource_assignments.get_id(), offset as u32);
|
||||||
|
|
||||||
offset += alignment;
|
offset += alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,9 +355,14 @@ where
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(render_resource) = entity_render_resource_assignments.get(entity) {
|
let render_resource_assignments =
|
||||||
dynamic_uniform_info.offsets.insert(render_resource.get_id(), offset as u32);
|
entity_render_resource_assignments.get(entity).unwrap();
|
||||||
|
if !entities.contains(&render_resource_assignments.get_id()) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
dynamic_uniform_info
|
||||||
|
.offsets
|
||||||
|
.insert(render_resource_assignments.get_id(), offset as u32);
|
||||||
|
|
||||||
offset += alignment;
|
offset += alignment;
|
||||||
}
|
}
|
||||||
@ -363,7 +381,13 @@ where
|
|||||||
for (entity, (uniforms, renderable)) in
|
for (entity, (uniforms, renderable)) in
|
||||||
self.resource_query.iter_entities(world)
|
self.resource_query.iter_entities(world)
|
||||||
{
|
{
|
||||||
if renderable.is_instanced || !entities.contains(&entity) {
|
if renderable.is_instanced {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let render_resource_assignments =
|
||||||
|
entity_render_resource_assignments.get(entity).unwrap();
|
||||||
|
if !entities.contains(&render_resource_assignments.get_id()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(uniform_bytes) = uniforms.get_uniform_bytes_ref(&name) {
|
if let Some(uniform_bytes) = uniforms.get_uniform_bytes_ref(&name) {
|
||||||
@ -381,7 +405,13 @@ where
|
|||||||
for (entity, (handle, renderable)) in
|
for (entity, (handle, renderable)) in
|
||||||
self.handle_query.as_ref().unwrap().iter_entities(world)
|
self.handle_query.as_ref().unwrap().iter_entities(world)
|
||||||
{
|
{
|
||||||
if renderable.is_instanced || !entities.contains(&entity) {
|
if renderable.is_instanced {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let render_resource_assignments =
|
||||||
|
entity_render_resource_assignments.get(entity).unwrap();
|
||||||
|
if !entities.contains(&render_resource_assignments.get_id()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,6 +442,7 @@ where
|
|||||||
let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor();
|
let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor();
|
||||||
if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor {
|
if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor {
|
||||||
if let None = renderer.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name) {
|
if let None = renderer.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name) {
|
||||||
|
println!("{:#?}", vertex_buffer_descriptor);
|
||||||
renderer.set_vertex_buffer_descriptor(vertex_buffer_descriptor.clone());
|
renderer.set_vertex_buffer_descriptor(vertex_buffer_descriptor.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -473,8 +504,7 @@ where
|
|||||||
.set(entity, render_resource_assignments_provider.next());
|
.set(entity, render_resource_assignments_provider.next());
|
||||||
entity_render_resource_assignments.get_mut(entity).unwrap()
|
entity_render_resource_assignments.get_mut(entity).unwrap()
|
||||||
};
|
};
|
||||||
self.setup_entity_uniform_resources(
|
self.setup_uniform_resources(
|
||||||
entity,
|
|
||||||
&uniforms,
|
&uniforms,
|
||||||
renderer,
|
renderer,
|
||||||
resources,
|
resources,
|
||||||
@ -508,4 +538,48 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn finish_update(
|
||||||
|
&mut self,
|
||||||
|
renderer: &mut dyn Renderer,
|
||||||
|
_world: &mut World,
|
||||||
|
resources: &Resources,
|
||||||
|
) {
|
||||||
|
if let Some(asset_storage) = resources.get::<AssetStorage<T>>() {
|
||||||
|
let handle_type = std::any::TypeId::of::<T>();
|
||||||
|
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
|
||||||
|
let mut render_resource_assignments_provider = resources
|
||||||
|
.get_mut::<RenderResourceAssignmentsProvider>()
|
||||||
|
.unwrap();
|
||||||
|
// TODO: work out lifetime issues here so allocation isn't necessary
|
||||||
|
for index in asset_batchers
|
||||||
|
.get_batcher_indices::<T>()
|
||||||
|
.map(|i| *i)
|
||||||
|
.collect::<Vec<usize>>()
|
||||||
|
{
|
||||||
|
for batch in asset_batchers.get_batches_from_batcher_mut(index) {
|
||||||
|
let handle: Handle<T> = batch
|
||||||
|
.handles
|
||||||
|
.iter()
|
||||||
|
.find(|h| h.type_id == handle_type)
|
||||||
|
.map(|h| (*h).into())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let render_resource_assignments = batch
|
||||||
|
.render_resource_assignments
|
||||||
|
.get_or_insert_with(|| render_resource_assignments_provider.next());
|
||||||
|
if let Some(uniforms) = asset_storage.get(&handle) {
|
||||||
|
self.setup_uniform_resources(
|
||||||
|
uniforms,
|
||||||
|
renderer,
|
||||||
|
resources,
|
||||||
|
render_resource_assignments,
|
||||||
|
false,
|
||||||
|
Some(handle),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ use crate::{
|
|||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
shader::{Shader},
|
shader::{Shader},
|
||||||
texture::{SamplerDescriptor, TextureDescriptor},
|
texture::{SamplerDescriptor, TextureDescriptor},
|
||||||
update_shader_assignments,
|
update_shader_assignments, Vertex,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, ops::Deref};
|
use std::{collections::HashMap, ops::Deref};
|
||||||
@ -428,6 +428,10 @@ impl Renderer for WgpuRenderer {
|
|||||||
resource_provider.update(self, world, resources);
|
resource_provider.update(self, world, resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for resource_provider in render_graph.resource_providers.iter_mut() {
|
||||||
|
resource_provider.finish_update(self, world, resources);
|
||||||
|
}
|
||||||
|
|
||||||
update_shader_assignments(world, resources, render_graph);
|
update_shader_assignments(world, resources, render_graph);
|
||||||
|
|
||||||
for (name, texture_descriptor) in render_graph.queued_textures.drain(..) {
|
for (name, texture_descriptor) in render_graph.queued_textures.drain(..) {
|
||||||
|
@ -8,6 +8,7 @@ use bevy_derive::Uniforms;
|
|||||||
|
|
||||||
#[derive(Uniforms)]
|
#[derive(Uniforms)]
|
||||||
pub struct StandardMaterial {
|
pub struct StandardMaterial {
|
||||||
|
#[uniform(instance)]
|
||||||
pub albedo: Color,
|
pub albedo: Color,
|
||||||
#[uniform(shader_def)]
|
#[uniform(shader_def)]
|
||||||
pub albedo_texture: Option<Handle<Texture>>,
|
pub albedo_texture: Option<Handle<Texture>>,
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use zerocopy::{AsBytes, FromBytes};
|
use zerocopy::{AsBytes, FromBytes};
|
||||||
|
|
||||||
|
use crate as bevy;
|
||||||
|
use bevy_derive::Uniforms;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, AsBytes, FromBytes)]
|
#[derive(Clone, Copy, AsBytes, FromBytes, Uniforms)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
|
#[uniform(vertex)]
|
||||||
pub position: [f32; 4],
|
pub position: [f32; 4],
|
||||||
|
#[uniform(vertex)]
|
||||||
pub normal: [f32; 4],
|
pub normal: [f32; 4],
|
||||||
|
#[uniform(vertex)]
|
||||||
pub uv: [f32; 2],
|
pub uv: [f32; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user