add RenderResources/RenderResource traits to replace Uniforms/Uniform

This commit is contained in:
Carter Anderson 2020-06-07 19:12:41 -07:00
parent 5add29f8cf
commit fd8f87400d
30 changed files with 528 additions and 347 deletions

View file

@ -3,7 +3,6 @@ use crate::{
Handle, HandleId,
};
use bevy_app::{AppBuilder, Events, FromResources};
use bevy_core::bytes::Bytes;
use bevy_type_registry::RegisterType;
use legion::prelude::*;
use std::collections::HashMap;
@ -108,13 +107,6 @@ impl<T> Assets<T> {
}
}
impl<T> Bytes for Handle<T> {
fn write_bytes(&self, _buffer: &mut [u8]) {}
fn byte_len(&self) -> usize {
0
}
}
pub trait AddAsset {
fn add_asset<T>(&mut self) -> &mut Self
where

View file

@ -1,4 +1,7 @@
use glam::{Mat4, Vec2, Vec3, Vec4};
pub use bevy_derive::Bytes;
pub trait Bytes {
fn write_bytes(&self, buffer: &mut [u8]);
fn byte_len(&self) -> usize;

View file

@ -2,8 +2,6 @@ pub mod bytes;
pub mod time;
pub mod transform;
pub use bevy_derive::Bytes;
use bevy_app::{stage, AppBuilder, AppPlugin};
use bevy_transform::{
components::{

View file

@ -1,9 +1,12 @@
use crate::modules::{get_modules, get_path};
use crate::{
attributes::get_field_attributes,
modules::{get_modules, get_path},
};
use darling::FromMeta;
use inflector::Inflector;
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields, Path};
use syn::{parse_macro_input, DeriveInput, Path};
#[derive(FromMeta, Debug, Default)]
struct VertexAttributeArgs {
@ -28,7 +31,7 @@ impl From<VertexAttributeArgs> for VertexAttributes {
}
}
static UNIFORM_ATTRIBUTE_NAME: &'static str = "uniform";
static VERTEX_ATTRIBUTE_NAME: &'static str = "vertex";
pub fn derive_as_vertex_buffer_descriptor(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
@ -36,34 +39,10 @@ pub fn derive_as_vertex_buffer_descriptor(input: TokenStream) -> TokenStream {
let bevy_render_path: Path = get_path(&modules.bevy_render);
let fields = match &ast.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => &fields.named,
_ => panic!("expected a struct with named fields"),
};
let field_attributes = fields
.iter()
.map(|f| {
(
f,
f.attrs
.iter()
.find(|a| {
a.path.get_ident().as_ref().unwrap().to_string() == UNIFORM_ATTRIBUTE_NAME
})
.map(|a| {
VertexAttributes::from(
VertexAttributeArgs::from_meta(&a.parse_meta().unwrap())
.unwrap_or_else(|_err| VertexAttributeArgs::default()),
)
})
.unwrap_or_else(|| VertexAttributes::default()),
)
})
.collect::<Vec<(&Field, VertexAttributes)>>();
let field_attributes = get_field_attributes::<VertexAttributes, VertexAttributeArgs>(
VERTEX_ATTRIBUTE_NAME,
&ast.data,
);
let struct_name = &ast.ident;
@ -133,4 +112,4 @@ pub fn derive_as_vertex_buffer_descriptor(input: TokenStream) -> TokenStream {
}
}
})
}
}

View file

@ -0,0 +1,50 @@
use darling::FromMeta;
use syn::{Attribute, Data, DataStruct, Field, Fields};
pub fn get_field_attributes<'a, T, TArgs>(
attribute_name: &str,
data: &'a Data,
) -> Vec<(&'a Field, T)>
where
T: Default,
TArgs: FromMeta + Into<T> + Default,
{
let fields = match data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => &fields.named,
_ => panic!("expected a struct with named fields"),
};
fields
.iter()
.map(|f| {
(
f,
f.attrs
.iter()
.find(|a| a.path.get_ident().as_ref().unwrap().to_string() == attribute_name)
.map(|a| {
TArgs::from_meta(&a.parse_meta().unwrap())
.unwrap_or_else(|_err| TArgs::default())
})
.unwrap_or_else(|| TArgs::default())
.into(),
)
})
.collect::<Vec<(&Field, T)>>()
}
pub fn get_attributes<'a, T, TArgs>(attribute_name: &str, attrs: &[Attribute]) -> T
where
T: Default,
TArgs: FromMeta + Into<T> + Default,
{
attrs
.iter()
.find(|a| a.path.get_ident().as_ref().unwrap().to_string() == attribute_name)
.map(|a| TArgs::from_meta(&a.parse_meta().unwrap()).unwrap_or_else(|_err| TArgs::default()))
.unwrap_or_else(|| TArgs::default())
.into()
}

View file

@ -1,15 +1,8 @@
use crate::modules::{get_modules, get_path};
use darling::FromMeta;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields, Ident};
#[derive(FromMeta, Debug, Default)]
struct EntityArchetypeAttributeArgs {
#[darling(default)]
pub tag: Option<bool>,
}
pub fn derive_entity_archetype(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let fields = match &ast.data {
@ -24,25 +17,8 @@ pub fn derive_entity_archetype(input: TokenStream) -> TokenStream {
let bevy_app_path = get_path(&modules.bevy_app);
let legion_path = get_path(&modules.legion);
let tag_fields = fields
.iter()
.filter(|f| {
f.attrs
.iter()
.find(|a| a.path.get_ident().as_ref().unwrap().to_string() == "tag")
.is_some()
})
.map(|field| field.ident.as_ref().unwrap())
.collect::<Vec<&Ident>>();
let component_fields = fields
.iter()
.filter(|f| {
f.attrs
.iter()
.find(|a| a.path.get_ident().as_ref().unwrap().to_string() == "tag")
.is_none()
})
.map(|field| field.ident.as_ref().unwrap())
.collect::<Vec<&Ident>>();
@ -54,7 +30,7 @@ pub fn derive_entity_archetype(input: TokenStream) -> TokenStream {
TokenStream::from(quote! {
impl #impl_generics #bevy_app_path::EntityArchetype for #struct_name#ty_generics {
fn insert(self, world: &mut #legion_path::prelude::World) -> #legion_path::prelude::Entity {
*world.insert((#(self.#tag_fields,)*),
*world.insert((),
vec![(
#(self.#component_fields,)*
)
@ -62,7 +38,7 @@ pub fn derive_entity_archetype(input: TokenStream) -> TokenStream {
}
fn insert_command_buffer(self, command_buffer: &mut #legion_path::prelude::CommandBuffer) -> #legion_path::prelude::Entity {
*command_buffer.insert((#(self.#tag_fields,)*),
*command_buffer.insert((),
vec![(
#(self.#component_fields,)*
)

View file

@ -1,9 +1,12 @@
extern crate proc_macro;
mod app_plugin;
mod attributes;
mod bytes;
mod entity_archetype;
mod modules;
mod render_resources;
mod render_resource;
mod resource;
mod uniforms;
mod as_vertex_buffer_descriptor;
@ -30,6 +33,16 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
uniforms::derive_uniforms(input)
}
#[proc_macro_derive(RenderResources, attributes(render_resources, module))]
pub fn derive_render_resources(input: TokenStream) -> TokenStream {
render_resources::derive_render_resources(input)
}
#[proc_macro_derive(RenderResource, attributes(module))]
pub fn derive_render_resource(input: TokenStream) -> TokenStream {
render_resource::derive_render_resource(input)
}
#[proc_macro_derive(AsVertexBufferDescriptor, attributes(vertex, module))]
pub fn derive_as_vertex_buffer_descriptor(input: TokenStream) -> TokenStream {
as_vertex_buffer_descriptor::derive_as_vertex_buffer_descriptor(input)
@ -44,4 +57,4 @@ pub fn derive_entity_archetype(input: TokenStream) -> TokenStream {
#[proc_macro_derive(DynamicAppPlugin)]
pub fn derive_app_plugin(input: TokenStream) -> TokenStream {
app_plugin::derive_dynamic_app_plugin(input)
}
}

View file

@ -0,0 +1,33 @@
use crate::modules::{get_modules, get_path};
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Path};
pub fn derive_render_resource(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let modules = get_modules(&ast);
let bevy_render_path: Path = get_path(&modules.bevy_render);
let bevy_asset_path: Path = get_path(&modules.bevy_asset);
let bevy_core_path: Path = get_path(&modules.bevy_core);
let struct_name = &ast.ident;
TokenStream::from(quote! {
impl #bevy_render_path::render_resource::RenderResource for #struct_name {
fn resource_info(&self) -> Option<#bevy_render_path::render_resource::ResourceInfo> {
Some(#bevy_render_path::render_resource::ResourceInfo::Buffer(None))
}
fn write_buffer_bytes(&self, buffer: &mut [u8]) {
use #bevy_core_path::bytes::Bytes;
self.write_bytes(buffer);
}
fn buffer_byte_len(&self) -> Option<usize> {
Some(self.byte_len())
}
fn texture(&self) -> Option<#bevy_asset_path::Handle<#bevy_render_path::texture::Texture>> {
None
}
}
})
}

View file

@ -0,0 +1,148 @@
use crate::{
attributes::{get_attributes, get_field_attributes},
modules::{get_modules, get_path},
};
use darling::FromMeta;
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{parse_macro_input, DeriveInput, Path};
#[derive(FromMeta, Debug, Default)]
struct RenderResourceAttributeArgs {
#[darling(default)]
pub ignore: Option<bool>,
#[darling(default)]
pub buffer: Option<bool>,
#[darling(default)]
pub from_self: Option<bool>,
}
#[derive(Default)]
struct RenderResourceAttributes {
pub ignore: bool,
pub buffer: bool,
pub from_self: bool,
}
impl From<RenderResourceAttributeArgs> for RenderResourceAttributes {
fn from(args: RenderResourceAttributeArgs) -> Self {
Self {
ignore: args.ignore.unwrap_or(false),
buffer: args.buffer.unwrap_or(false),
from_self: args.from_self.unwrap_or(false),
}
}
}
static RENDER_RESOURCE_ATTRIBUTE_NAME: &'static str = "render_resources";
pub fn derive_render_resources(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let modules = get_modules(&ast);
let bevy_render_path: Path = get_path(&modules.bevy_render);
let attributes = get_attributes::<RenderResourceAttributes, RenderResourceAttributeArgs>(
RENDER_RESOURCE_ATTRIBUTE_NAME,
&ast.attrs,
);
let struct_name = &ast.ident;
let struct_name_string = struct_name.to_string();
if attributes.from_self {
TokenStream::from(quote! {
impl #bevy_render_path::render_resource::RenderResources for #struct_name {
fn render_resources_len(&self) -> usize {
1
}
fn get_render_resource(&self, index: usize) -> Option<&dyn #bevy_render_path::render_resource::RenderResource> {
if index == 0 {
Some(self)
} else {
None
}
}
fn get_render_resource_name(&self, index: usize) -> Option<&str> {
if index == 0 {
Some(#struct_name_string)
} else {
None
}
}
fn iter_render_resources(&self) -> #bevy_render_path::render_resource::RenderResourceIterator {
#bevy_render_path::render_resource::RenderResourceIterator::new(self)
}
}
})
} else {
let field_attributes = get_field_attributes::<
RenderResourceAttributes,
RenderResourceAttributeArgs,
>(RENDER_RESOURCE_ATTRIBUTE_NAME, &ast.data);
let mut render_resource_names = Vec::new();
let mut render_resource_fields = Vec::new();
let mut render_resource_hints = Vec::new();
for (field, attrs) in field_attributes.iter() {
if attrs.ignore {
continue;
}
let field_ident = field.ident.as_ref().unwrap();
let field_name = field_ident.to_string();
render_resource_fields.push(field_ident);
render_resource_names.push(format!("{}_{}", struct_name, field_name));
if attrs.buffer {
render_resource_hints.push(quote! {Some(#bevy_render_path::render_resource::RenderResourceHints::BUFFER)})
} else {
render_resource_hints.push(quote! {None})
}
}
let render_resource_count = render_resource_names.len();
let render_resource_indices = 0..render_resource_count;
let struct_name_uppercase = struct_name_string.to_uppercase();
let render_resource_names_ident =
format_ident!("{}_RENDER_RESOURCE_NAMES", struct_name_uppercase);
let render_resource_hints_ident =
format_ident!("{}_RENDER_RESOURCE_HINTS", struct_name_uppercase);
TokenStream::from(quote! {
static #render_resource_names_ident: &[&str] = &[
#(#render_resource_names,)*
];
static #render_resource_hints_ident: &[Option<#bevy_render_path::render_resource::RenderResourceHints>] = &[
#(#render_resource_hints,)*
];
impl #bevy_render_path::render_resource::RenderResources for #struct_name {
fn render_resources_len(&self) -> usize {
#render_resource_count
}
fn get_render_resource(&self, index: usize) -> Option<&dyn #bevy_render_path::render_resource::RenderResource> {
match index {
#(#render_resource_indices => Some(&self.#render_resource_fields),)*
_ => None,
}
}
fn get_render_resource_name(&self, index: usize) -> Option<&str> {
Some(#render_resource_names_ident[index])
}
fn get_render_resource_hints(&self, index: usize) -> Option<#bevy_render_path::render_resource::RenderResourceHints> {
#render_resource_hints_ident[index].clone()
}
fn iter_render_resources(&self) -> #bevy_render_path::render_resource::RenderResourceIterator {
#bevy_render_path::render_resource::RenderResourceIterator::new(self)
}
}
})
}
}

View file

@ -1,9 +1,12 @@
use crate::modules::{get_modules, get_path};
use crate::{
attributes::get_field_attributes,
modules::{get_modules, get_path},
};
use darling::FromMeta;
use inflector::Inflector;
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields, Path};
use syn::{parse_macro_input, DeriveInput, Path};
#[derive(FromMeta, Debug, Default)]
struct UniformAttributeArgs {
@ -42,34 +45,10 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
let bevy_core_path: Path = get_path(&modules.bevy_core);
let bevy_asset_path: Path = get_path(&modules.bevy_asset);
let fields = match &ast.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => &fields.named,
_ => panic!("expected a struct with named fields"),
};
let field_attributes = fields
.iter()
.map(|f| {
(
f,
f.attrs
.iter()
.find(|a| {
a.path.get_ident().as_ref().unwrap().to_string() == UNIFORM_ATTRIBUTE_NAME
})
.map(|a| {
UniformAttributes::from(
UniformAttributeArgs::from_meta(&a.parse_meta().unwrap())
.unwrap_or_else(|_err| UniformAttributeArgs::default()),
)
})
.unwrap_or_else(|| UniformAttributes::default()),
)
})
.collect::<Vec<(&Field, UniformAttributes)>>();
let field_attributes = get_field_attributes::<UniformAttributes, UniformAttributeArgs>(
UNIFORM_ATTRIBUTE_NAME,
&ast.data,
);
let struct_name = &ast.ident;
@ -141,34 +120,18 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
}
fn get_field_bind_type(&self, name: &str) -> Option<#bevy_render_path::shader::FieldBindType> {
use #bevy_render_path::shader::GetFieldBindType;
match name {
#(#active_uniform_field_name_strings => #get_field_bind_types,)*
_ => None,
}
None
}
fn get_uniform_texture(&self, name: &str) -> Option<#bevy_asset_path::Handle<#bevy_render_path::texture::Texture>> {
use #bevy_render_path::shader::GetTexture;
match name {
#(#texture_and_sampler_name_strings => self.#texture_and_sampler_name_idents.get_texture(),)*
_ => None,
}
None
}
fn write_uniform_bytes(&self, name: &str, buffer: &mut [u8]) {
use #bevy_core_path::bytes::Bytes;
match name {
#(#uniform_name_strings => self.#active_uniform_field_names.write_bytes(buffer),)*
_ => {},
}
}
fn uniform_byte_len(&self, name: &str) -> usize {
use #bevy_core_path::bytes::Bytes;
match name {
#(#uniform_name_strings => self.#active_uniform_field_names.byte_len(),)*
_ => 0,
}
0
}
// TODO: move this to field_info and add has_shader_def(&self, &str) -> bool
@ -194,7 +157,6 @@ pub fn derive_uniform(input: TokenStream) -> TokenStream {
let modules = get_modules(&ast);
let bevy_asset_path = get_path(&modules.bevy_asset);
let bevy_core_path = get_path(&modules.bevy_core);
let bevy_render_path = get_path(&modules.bevy_render);
let generics = ast.generics;
@ -218,26 +180,13 @@ pub fn derive_uniform(input: TokenStream) -> TokenStream {
}
fn get_field_bind_type(&self, name: &str) -> Option<#bevy_render_path::shader::FieldBindType> {
use #bevy_render_path::shader::GetFieldBindType;
match name {
#struct_name_string => self.get_bind_type(),
_ => None,
}
None
}
fn write_uniform_bytes(&self, name: &str, buffer: &mut [u8]) {
use #bevy_core_path::bytes::Bytes;
match name {
#struct_name_string => self.write_bytes(buffer),
_ => {},
}
}
fn uniform_byte_len(&self, name: &str) -> usize {
use #bevy_core_path::bytes::Bytes;
match name {
#struct_name_string => self.byte_len(),
_ => 0,
}
0
}
fn get_uniform_texture(&self, name: &str) -> Option<#bevy_asset_path::Handle<#bevy_render_path::texture::Texture>> {

View file

@ -1,8 +1,7 @@
use bevy_asset::{self, Handle};
use bevy_derive::Uniforms;
use bevy_render::{texture::Texture, Color};
use bevy_render::{render_resource::RenderResources, shader::Uniforms, texture::Texture, Color};
#[derive(Uniforms)]
#[derive(Uniforms, RenderResources)]
pub struct StandardMaterial {
pub albedo: Color,
#[uniform(shader_def)]

View file

@ -1,5 +1,5 @@
use super::texture::Texture;
use crate::shader::ShaderDefSuffixProvider;
use crate::{render_resource::{ResourceInfo, RenderResource}, shader::ShaderDefSuffixProvider, impl_render_resource_bytes};
use bevy_asset::Handle;
use bevy_core::bytes::{Byteable, Bytes};
use bevy_property::Property;
@ -138,3 +138,5 @@ impl ShaderDefSuffixProvider for ColorSource {
}
}
}
impl_render_resource_bytes!(Color);

View file

@ -45,7 +45,7 @@ impl DrawTarget for MeshesDrawTarget {
render_resources.get_resource_info(
index_buffer_resource,
&mut |resource_info| match resource_info {
Some(ResourceInfo::Buffer(buffer_info)) => {
Some(ResourceInfo::Buffer(Some(buffer_info))) => {
current_mesh_index_len = (buffer_info.size / 2) as u32
}
_ => panic!("expected a buffer type"),

View file

@ -1,16 +1,16 @@
use crate::{
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
render_resource::{
BufferInfo, BufferUsage, EntitiesWaitingForAssets, RenderResourceId,
RenderResourceAssignment, RenderResourceAssignments, RenderResourceAssignmentsId,
self, BufferInfo, BufferUsage, EntitiesWaitingForAssets, RenderResourceAssignment,
RenderResourceAssignments, RenderResourceAssignmentsId, RenderResourceId, RenderResourceHints,
},
renderer::{RenderContext, RenderResourceContext, RenderResources},
shader::{Uniforms, FieldBindType},
texture, Renderable,
};
use bevy_asset::{Assets, Handle};
use legion::prelude::*;
use render_resource::ResourceInfo;
use std::{collections::HashMap, marker::PhantomData};
pub const BIND_BUFFER_ALIGNMENT: usize = 256;
@ -53,25 +53,28 @@ impl BufferArrayStatus {
struct UniformBufferArrays<T>
where
T: Uniforms,
T: render_resource::RenderResources,
{
uniform_arrays: Vec<Option<(String, BufferArrayStatus)>>,
_marker: PhantomData<T>,
}
impl<T> UniformBufferArrays<T>
impl<T> Default for UniformBufferArrays<T>
where
T: Uniforms,
T: render_resource::RenderResources,
{
fn new() -> Self {
let mut uniform_arrays = Vec::new();
let field_infos = T::get_field_infos();
uniform_arrays.resize_with(field_infos.len(), || None);
UniformBufferArrays {
uniform_arrays,
_marker: PhantomData::default(),
fn default() -> Self {
Self {
uniform_arrays: Default::default(),
_marker: Default::default(),
}
}
}
impl<T> UniformBufferArrays<T>
where
T: render_resource::RenderResources,
{
fn reset_new_item_counts(&mut self) {
for buffer_status in self.uniform_arrays.iter_mut() {
if let Some((_name, buffer_status)) = buffer_status {
@ -81,15 +84,19 @@ where
}
fn increment_uniform_counts(&mut self, uniforms: &T) {
for (i, field_info) in T::get_field_infos().iter().enumerate() {
if let Some(FieldBindType::Uniform { size }) | Some(FieldBindType::Buffer { size }) =
uniforms.get_field_bind_type(&field_info.name)
{
if self.uniform_arrays.len() != uniforms.render_resources_len() {
self.uniform_arrays
.resize_with(uniforms.render_resources_len(), || None);
}
for (i, render_resource) in uniforms.iter_render_resources().enumerate() {
if let Some(ResourceInfo::Buffer(_)) = render_resource.resource_info() {
let render_resource_name = uniforms.get_render_resource_name(i).unwrap();
let size = render_resource.buffer_byte_len().unwrap();
if let Some((ref _name, ref mut buffer_array_status)) = self.uniform_arrays[i] {
buffer_array_status.new_item_count += 1;
} else {
self.uniform_arrays[i] = Some((
field_info.uniform_name.to_string(),
render_resource_name.to_string(),
BufferArrayStatus {
new_item_count: 1,
queued_buffer_writes: Vec::new(),
@ -182,10 +189,11 @@ where
render_resource_assignments: &mut RenderResourceAssignments,
staging_buffer: &mut [u8],
) {
for (i, field_info) in T::get_field_infos().iter().enumerate() {
let bind_type = uniforms.get_field_bind_type(&field_info.name);
match bind_type {
Some(FieldBindType::Uniform { size }) | Some(FieldBindType::Buffer { size }) => {
for (i, render_resource) in uniforms.iter_render_resources().enumerate() {
match render_resource.resource_info() {
Some(ResourceInfo::Buffer(_)) => {
let size = render_resource.buffer_byte_len().unwrap();
let render_resource_name = uniforms.get_render_resource_name(i).unwrap();
let (_name, uniform_buffer_status) = self.uniform_arrays[i].as_mut().unwrap();
let range = 0..size as u64;
let (target_buffer, target_offset) = if dynamic_uniforms {
@ -193,7 +201,7 @@ where
let index = uniform_buffer_status
.get_or_assign_index(render_resource_assignments.id);
render_resource_assignments.set(
&field_info.uniform_name,
render_resource_name,
RenderResourceAssignment::Buffer {
resource: buffer,
dynamic_index: Some(
@ -204,16 +212,18 @@ where
);
(buffer, index * uniform_buffer_status.aligned_size)
} else {
let resource = match render_resource_assignments
.get(field_info.uniform_name)
{
let resource = match render_resource_assignments.get(render_resource_name) {
Some(assignment) => assignment.get_resource(),
None => {
let usage = if let Some(FieldBindType::Buffer { .. }) = bind_type {
BufferUsage::STORAGE
} else {
BufferUsage::UNIFORM
};
// TODO: RE-ADD support for BufferUsage::STORAGE type
let mut usage = BufferUsage::UNIFORM;
if let Some(render_resource_hints) = uniforms.get_render_resource_hints(i) {
if render_resource_hints.contains(RenderResourceHints::BUFFER) {
usage = BufferUsage::STORAGE
}
}
let resource = render_resources.create_buffer(BufferInfo {
size,
buffer_usage: BufferUsage::COPY_DST | usage,
@ -221,7 +231,7 @@ where
});
render_resource_assignments.set(
&field_info.uniform_name,
render_resource_name,
RenderResourceAssignment::Buffer {
resource,
range,
@ -238,23 +248,9 @@ where
let staging_buffer_start = uniform_buffer_status.staging_buffer_offset
+ (uniform_buffer_status.queued_buffer_writes.len()
* uniform_buffer_status.item_size);
let uniform_byte_len = uniforms.uniform_byte_len(&field_info.uniform_name);
if uniform_byte_len > 0 {
if size != uniform_byte_len {
panic!("The number of bytes produced for {} do not match the expected count. Actual: {}. Expected: {}.", field_info.uniform_name, uniform_byte_len, size);
}
uniforms.write_uniform_bytes(
&field_info.uniform_name,
&mut staging_buffer
[staging_buffer_start..(staging_buffer_start + uniform_byte_len)],
);
} else {
panic!(
"failed to get data from uniform: {}",
field_info.uniform_name
);
};
render_resource.write_buffer_bytes(
&mut staging_buffer[staging_buffer_start..(staging_buffer_start + size)],
);
uniform_buffer_status
.queued_buffer_writes
@ -263,7 +259,8 @@ where
offset: target_offset,
});
}
Some(FieldBindType::Texture) => { /* ignore textures */ }
Some(ResourceInfo::Texture(_)) => { /* ignore textures */ }
Some(ResourceInfo::Sampler) => { /* ignore samplers */ }
None => { /* ignore None */ }
}
}
@ -347,7 +344,7 @@ where
#[derive(Default)]
pub struct UniformNode<T>
where
T: Uniforms,
T: render_resource::RenderResources,
{
command_queue: CommandQueue,
dynamic_uniforms: bool,
@ -356,7 +353,7 @@ where
impl<T> UniformNode<T>
where
T: Uniforms,
T: render_resource::RenderResources,
{
pub fn new(dynamic_uniforms: bool) -> Self {
UniformNode {
@ -369,7 +366,7 @@ where
impl<T> Node for UniformNode<T>
where
T: Uniforms,
T: render_resource::RenderResources,
{
fn update(
&mut self,
@ -385,11 +382,11 @@ where
impl<T> SystemNode for UniformNode<T>
where
T: Uniforms,
T: render_resource::RenderResources,
{
fn get_system(&self) -> Box<dyn Schedulable> {
let mut command_queue = self.command_queue.clone();
let mut uniform_buffer_arrays = UniformBufferArrays::<T>::new();
let mut uniform_buffer_arrays = UniformBufferArrays::<T>::default();
let dynamic_uniforms = self.dynamic_uniforms;
// TODO: maybe run "update" here
SystemBuilder::new(format!(
@ -505,7 +502,7 @@ where
#[derive(Default)]
pub struct AssetUniformNode<T>
where
T: Uniforms,
T: render_resource::RenderResources,
{
command_queue: CommandQueue,
dynamic_uniforms: bool,
@ -514,7 +511,7 @@ where
impl<T> AssetUniformNode<T>
where
T: Uniforms,
T: render_resource::RenderResources,
{
pub fn new(dynamic_uniforms: bool) -> Self {
AssetUniformNode {
@ -527,7 +524,7 @@ where
impl<T> Node for AssetUniformNode<T>
where
T: Uniforms,
T: render_resource::RenderResources,
{
fn update(
&mut self,
@ -543,11 +540,11 @@ where
impl<T> SystemNode for AssetUniformNode<T>
where
T: Uniforms,
T: render_resource::RenderResources,
{
fn get_system(&self) -> Box<dyn Schedulable> {
let mut command_queue = self.command_queue.clone();
let mut uniform_buffer_arrays = UniformBufferArrays::<T>::new();
let mut uniform_buffer_arrays = UniformBufferArrays::<T>::default();
let dynamic_uniforms = self.dynamic_uniforms;
// TODO: maybe run "update" here
SystemBuilder::new("uniform_resource_provider")
@ -677,12 +674,13 @@ fn setup_uniform_texture_resources<T>(
entities_waiting_for_assets: &EntitiesWaitingForAssets,
render_resource_assignments: &mut RenderResourceAssignments,
) where
T: Uniforms,
T: render_resource::RenderResources,
{
for field_info in T::get_field_infos().iter() {
let bind_type = uniforms.get_field_bind_type(&field_info.name);
if let Some(FieldBindType::Texture) = bind_type {
if let Some(texture_handle) = uniforms.get_uniform_texture(&field_info.texture_name) {
for (i, render_resource) in uniforms.iter_render_resources().enumerate() {
if let Some(ResourceInfo::Texture(_)) = render_resource.resource_info() {
let render_resource_name = uniforms.get_render_resource_name(i).unwrap();
let sampler_name = format!("{}_sampler", render_resource_name);
if let Some(texture_handle) = render_resource.texture() {
if let Some(texture_resource) = render_resource_context
.get_asset_resource(texture_handle, texture::TEXTURE_ASSET_INDEX)
{
@ -690,11 +688,11 @@ fn setup_uniform_texture_resources<T>(
.get_asset_resource(texture_handle, texture::SAMPLER_ASSET_INDEX)
.unwrap();
render_resource_assignments.set(
field_info.texture_name,
render_resource_name,
RenderResourceAssignment::Texture(texture_resource),
);
render_resource_assignments.set(
field_info.sampler_name,
&sampler_name,
RenderResourceAssignment::Sampler(sampler_resource),
);
continue;

View file

@ -1,6 +1,12 @@
use super::ResourceInfo;
use crate::texture::Texture;
use bevy_asset::Handle;
use uuid::Uuid;
// TODO: Rename to RenderResourceId
use bevy_core::bytes::{Byteable, Bytes};
pub use bevy_derive::{RenderResource, RenderResources};
use glam::{Mat4, Vec2, Vec3, Vec4};
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
pub struct RenderResourceId(Uuid);
@ -9,3 +15,101 @@ impl RenderResourceId {
RenderResourceId(Uuid::new_v4())
}
}
bitflags::bitflags! {
#[repr(transparent)]
pub struct RenderResourceHints: u32 {
const BUFFER = 1;
}
}
pub trait RenderResource {
fn resource_info(&self) -> Option<ResourceInfo>;
fn write_buffer_bytes(&self, buffer: &mut [u8]);
fn buffer_byte_len(&self) -> Option<usize>;
// TODO: consider making these panic by default, but return non-options
fn texture(&self) -> Option<Handle<Texture>>;
}
pub trait RenderResources: Send + Sync + 'static {
fn render_resources_len(&self) -> usize;
fn get_render_resource(&self, index: usize) -> Option<&dyn RenderResource>;
fn get_render_resource_name(&self, index: usize) -> Option<&str>;
fn get_render_resource_hints(&self, _index: usize) -> Option<RenderResourceHints> {
None
}
fn iter_render_resources(&self) -> RenderResourceIterator;
}
pub struct RenderResourceIterator<'a> {
render_resources: &'a dyn RenderResources,
index: usize,
}
impl<'a> RenderResourceIterator<'a> {
pub fn new(render_resources: &'a dyn RenderResources) -> Self {
Self {
render_resources,
index: 0,
}
}
}
impl<'a> Iterator for RenderResourceIterator<'a> {
type Item = &'a dyn RenderResource;
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.render_resources.render_resources_len() {
None
} else {
let render_resource = self
.render_resources
.get_render_resource(self.index)
.unwrap();
self.index += 1;
Some(render_resource)
}
}
}
#[macro_export]
macro_rules! impl_render_resource_bytes {
($ty:ident) => {
impl RenderResource for $ty {
fn resource_info(&self) -> Option<ResourceInfo> {
Some(ResourceInfo::Buffer(None))
}
fn write_buffer_bytes(&self, buffer: &mut [u8]) {
self.write_bytes(buffer);
}
fn buffer_byte_len(&self) -> Option<usize> {
Some(self.byte_len())
}
fn texture(&self) -> Option<Handle<Texture>> {
None
}
}
};
}
// TODO: when specialization lands, replace these with impl<T> RenderResource for T where T: Bytes
impl_render_resource_bytes!(Vec2);
impl_render_resource_bytes!(Vec3);
impl_render_resource_bytes!(Vec4);
impl_render_resource_bytes!(Mat4);
impl<T> RenderResource for Vec<T>
where
T: Sized + Byteable,
{
fn resource_info(&self) -> Option<ResourceInfo> {
Some(ResourceInfo::Buffer(None))
}
fn write_buffer_bytes(&self, buffer: &mut [u8]) {
self.write_bytes(buffer);
}
fn buffer_byte_len(&self) -> Option<usize> {
Some(self.byte_len())
}
fn texture(&self) -> Option<Handle<Texture>> {
None
}
}

View file

@ -17,7 +17,7 @@ impl Default for BufferInfo {
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ResourceInfo {
Buffer(BufferInfo),
Texture(TextureDescriptor),
Buffer(Option<BufferInfo>),
Texture(Option<TextureDescriptor>),
Sampler,
}
}

View file

@ -43,12 +43,12 @@ impl RenderResourceContext for HeadlessRenderResourceContext {
}
fn create_texture(&self, texture_descriptor: TextureDescriptor) -> RenderResourceId {
let resource = RenderResourceId::new();
self.add_resource_info(resource, ResourceInfo::Texture(texture_descriptor));
self.add_resource_info(resource, ResourceInfo::Texture(Some(texture_descriptor)));
resource
}
fn create_buffer(&self, buffer_info: BufferInfo) -> RenderResourceId {
let resource = RenderResourceId::new();
self.add_resource_info(resource, ResourceInfo::Buffer(buffer_info));
self.add_resource_info(resource, ResourceInfo::Buffer(Some(buffer_info)));
resource
}
fn create_buffer_mapped(
@ -62,7 +62,7 @@ impl RenderResourceContext for HeadlessRenderResourceContext {
}
fn create_buffer_with_data(&self, buffer_info: BufferInfo, _data: &[u8]) -> RenderResourceId {
let resource = RenderResourceId::new();
self.add_resource_info(resource, ResourceInfo::Buffer(buffer_info));
self.add_resource_info(resource, ResourceInfo::Buffer(Some(buffer_info)));
resource
}
fn create_shader_module(&self, _shader_handle: Handle<Shader>, _shaders: &Assets<Shader>) {}

View file

@ -1,7 +1,5 @@
use crate::{color::ColorSource, pipeline::BindType, texture::Texture, Renderable};
use crate::{pipeline::BindType, texture::Texture, Renderable};
use bevy_asset::{Assets, Handle};
use bevy_core::bytes::Bytes;
use legion::prelude::*;
pub use bevy_derive::{Uniform, Uniforms};
@ -78,82 +76,6 @@ pub struct FieldInfo {
pub sampler_name: &'static str,
}
pub trait GetFieldBindType {
fn get_bind_type(&self) -> Option<FieldBindType>;
}
impl GetFieldBindType for ColorSource {
fn get_bind_type(&self) -> Option<FieldBindType> {
match *self {
ColorSource::Texture(_) => Some(FieldBindType::Texture),
ColorSource::Color(color) => color.get_bind_type(),
}
}
}
impl GetFieldBindType for Option<Handle<Texture>> {
fn get_bind_type(&self) -> Option<FieldBindType> {
match *self {
Some(_) => Some(FieldBindType::Texture),
None => None,
}
}
}
impl GetFieldBindType for Handle<Texture> {
fn get_bind_type(&self) -> Option<FieldBindType> {
Some(FieldBindType::Texture)
}
}
impl<T> GetFieldBindType for T
where
T: Bytes,
{
// TODO: this breaks if get_bytes_ref() isn't supported for a datatype
default fn get_bind_type(&self) -> Option<FieldBindType> {
Some(FieldBindType::Uniform {
size: self.byte_len(),
})
}
}
pub trait GetTexture {
fn get_texture(&self) -> Option<Handle<Texture>> {
None
}
}
impl<T> GetTexture for T
where
T: Bytes,
{
default fn get_texture(&self) -> Option<Handle<Texture>> {
None
}
}
impl GetTexture for Handle<Texture> {
fn get_texture(&self) -> Option<Handle<Texture>> {
Some(self.clone())
}
}
impl GetTexture for Option<Handle<Texture>> {
fn get_texture(&self) -> Option<Handle<Texture>> {
*self
}
}
impl GetTexture for ColorSource {
fn get_texture(&self) -> Option<Handle<Texture>> {
match self {
ColorSource::Color(_) => None,
ColorSource::Texture(texture) => Some(texture.clone()),
}
}
}
pub struct UniformInfo<'a> {
pub name: &'a str,
pub bind_type: BindType,

View file

@ -1,45 +1,27 @@
use crate::{
shader::{FieldBindType, FieldInfo, GetFieldBindType, Uniforms},
texture::Texture,
};
use bevy_asset::Handle;
use bevy_core::bytes::Bytes;
use crate::render_resource::{RenderResource, RenderResourceIterator, RenderResources};
static TRANSFORM_FIELD_INFOS: &[FieldInfo] = &[FieldInfo {
name: "transform",
uniform_name: "Transform",
texture_name: "",
sampler_name: "",
}];
impl Uniforms for bevy_transform::prelude::Transform {
fn get_field_infos() -> &'static [FieldInfo] {
TRANSFORM_FIELD_INFOS
impl RenderResources for bevy_transform::prelude::Transform {
fn render_resources_len(&self) -> usize {
1
}
fn get_shader_defs(&self) -> Option<Vec<String>> {
None
}
fn get_field_bind_type(&self, name: &str) -> Option<FieldBindType> {
match name {
"transform" => self.value.get_bind_type(),
_ => None,
fn get_render_resource(&self, index: usize) -> Option<&dyn RenderResource> {
if index == 0 {
Some(&self.value)
} else {
None
}
}
fn get_uniform_texture(&self, _name: &str) -> Option<Handle<Texture>> {
None
fn get_render_resource_name(&self, index: usize) -> Option<&str> {
if index == 0 {
Some("Transform")
} else {
None
}
}
fn write_uniform_bytes(&self, name: &str, buffer: &mut [u8]) {
match name {
"Transform" => self.value.write_bytes(buffer),
_ => {}
}
}
fn uniform_byte_len(&self, name: &str) -> usize {
match name {
"Transform" => self.value.byte_len(),
_ => 0,
}
fn iter_render_resources(&self) -> RenderResourceIterator {
RenderResourceIterator::new(self)
}
}

View file

@ -1,7 +1,7 @@
use super::{SamplerDescriptor, TextureDescriptor};
use crate::{
renderer::{RenderResourceContext, RenderResources},
shader::ShaderDefSuffixProvider,
shader::ShaderDefSuffixProvider, render_resource::{ResourceInfo, RenderResource},
};
use bevy_app::{EventReader, Events};
use bevy_asset::{AssetEvent, Assets, Handle};
@ -121,3 +121,31 @@ impl ShaderDefSuffixProvider for Option<Handle<Texture>> {
}
}
}
impl RenderResource for Option<Handle<Texture>> {
fn resource_info(&self) -> Option<ResourceInfo> {
self.map(|_texture| ResourceInfo::Texture(None))
}
fn write_buffer_bytes(&self, _buffer: &mut [u8]) {
}
fn buffer_byte_len(&self) -> Option<usize> {
None
}
fn texture(&self) -> Option<Handle<Texture>> {
self.clone()
}
}
impl RenderResource for Handle<Texture> {
fn resource_info(&self) -> Option<ResourceInfo> {
Some(ResourceInfo::Texture(None))
}
fn write_buffer_bytes(&self, _buffer: &mut [u8]) {
}
fn buffer_byte_len(&self) -> Option<usize> {
None
}
fn texture(&self) -> Option<Handle<Texture>> {
Some(self.clone())
}
}

View file

@ -11,7 +11,6 @@ bevy_app = { path = "../bevy_app" }
bevy_core = { path = "../bevy_core" }
bevy_asset = { path = "../bevy_asset" }
bevy_type_registry = { path = "../bevy_type_registry" }
bevy_derive = { path = "../bevy_derive" }
bevy_render = { path = "../bevy_render" }
bevy_transform = { path = "../bevy_transform" }

View file

@ -1,8 +1,7 @@
use bevy_asset::{self, Handle};
use bevy_derive::Uniforms;
use bevy_render::{texture::Texture, Color};
use bevy_render::{texture::Texture, Color, render_resource::RenderResources, shader::Uniforms};
#[derive(Uniforms)]
#[derive(Uniforms, RenderResources)]
pub struct ColorMaterial {
pub color: Color,
#[uniform(shader_def)]

View file

@ -3,7 +3,7 @@ use crate::{
TextureAtlasSprite, QUAD_HANDLE, SPRITE_SHEET_PIPELINE_HANDLE,
};
use bevy_asset::Handle;
use bevy_derive::EntityArchetype;
use bevy_app::EntityArchetype;
use bevy_render::{mesh::Mesh, Renderable};
#[derive(EntityArchetype)]

View file

@ -1,7 +1,9 @@
use bevy_derive::{Bytes, Uniform};
use glam::Vec2;
use bevy_render::{shader::Uniform, render_resource::{RenderResources, RenderResource}};
use bevy_core::bytes::Bytes;
#[repr(C)]
#[derive(Default, Clone, Copy, Debug, Uniform, Bytes)]
#[derive(Default, Clone, Copy, Debug, Uniform, RenderResources, RenderResource, Bytes)]
#[render_resources(from_self)]
pub struct Quad {
pub position: Vec2,
pub size: Vec2,

View file

@ -1,24 +1,27 @@
use crate::Rect;
use bevy_asset::Handle;
use bevy_derive::{Bytes, Uniform, Uniforms};
use bevy_render::texture::Texture;
use bevy_render::{texture::Texture, render_resource::{RenderResources, RenderResource}, shader::{Uniforms, Uniform}};
use bevy_core::bytes::Bytes;
use glam::{Vec2, Vec3};
use std::collections::HashMap;
#[derive(Uniforms)]
#[derive(Uniforms, RenderResources)]
pub struct TextureAtlas {
pub texture: Handle<Texture>,
// TODO: add support to Uniforms derive to write dimensions and sprites to the same buffer
pub dimensions: Vec2,
#[uniform(buffer)]
#[render_resources(buffer)]
pub textures: Vec<Rect>,
#[uniform(ignore)]
#[render_resources(ignore)]
pub texture_handles: Option<HashMap<Handle<Texture>, usize>>,
}
// NOTE: cannot do `unsafe impl Byteable` here because Vec3 takes up the space of a Vec4. If/when glam changes this we can swap out
// Bytes for Byteable as a micro-optimization. https://github.com/bitshifter/glam-rs/issues/36
#[derive(Uniform, Bytes, Default)]
#[derive(Uniform, Bytes, RenderResources, RenderResource, Default)]
#[render_resources(from_self)]
pub struct TextureAtlasSprite {
pub position: Vec3,
pub scale: f32,

View file

@ -152,7 +152,7 @@ impl RenderResourceContext for WgpuRenderResourceContext {
let texture_view = texture.create_default_view();
let resource = RenderResourceId::new();
resource_info.insert(resource, ResourceInfo::Texture(texture_descriptor));
resource_info.insert(resource, ResourceInfo::Texture(Some(texture_descriptor)));
texture_views.insert(resource, texture_view);
textures.insert(resource, texture);
resource
@ -171,7 +171,7 @@ impl RenderResourceContext for WgpuRenderResourceContext {
});
let resource = RenderResourceId::new();
resource_info.insert(resource, ResourceInfo::Buffer(buffer_info));
resource_info.insert(resource, ResourceInfo::Buffer(Some(buffer_info)));
buffers.insert(resource, buffer);
resource
}
@ -202,7 +202,7 @@ impl RenderResourceContext for WgpuRenderResourceContext {
let resource = RenderResourceId::new();
let mut resource_info = self.resources.resource_info.write().unwrap();
let mut buffers = self.resources.buffers.write().unwrap();
resource_info.insert(resource, ResourceInfo::Buffer(buffer_info));
resource_info.insert(resource, ResourceInfo::Buffer(Some(buffer_info)));
buffers.insert(resource, buffer);
resource
}
@ -218,7 +218,7 @@ impl RenderResourceContext for WgpuRenderResourceContext {
.create_buffer_with_data(data, buffer_info.buffer_usage.wgpu_into());
let resource = RenderResourceId::new();
resource_info.insert(resource, ResourceInfo::Buffer(buffer_info));
resource_info.insert(resource, ResourceInfo::Buffer(Some(buffer_info)));
buffers.insert(resource, buffer);
resource
}

View file

@ -83,7 +83,7 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
self.render_context.resources().get_resource_info(
index_buffer,
&mut |resource_info| match resource_info {
Some(ResourceInfo::Buffer(buffer_info)) => {
Some(ResourceInfo::Buffer(Some(buffer_info))) => {
indices = Some(0..(buffer_info.size / 2) as u32)
}
_ => panic!("expected a buffer type"),

View file

@ -8,7 +8,7 @@ fn main() {
.run();
}
#[derive(Uniforms, Default)]
#[derive(Uniforms, RenderResources, Default)]
struct MyMaterial {
pub color: Color,
}

View file

@ -12,10 +12,11 @@ fn main() {
.run();
}
#[derive(Uniforms, Default)]
#[derive(Uniforms, RenderResources, Default)]
struct MyMaterial {
pub color: Color,
#[uniform(ignore, shader_def)]
#[render_resources(ignore)]
pub always_red: bool,
}

View file

@ -26,6 +26,7 @@ pub use crate::{
RenderGraph,
},
shader::{Shader, ShaderDefSuffixProvider, ShaderStage, ShaderStages, Uniforms},
render_resource::RenderResources,
texture::Texture,
Camera, Color, ColorSource, OrthographicProjection, PerspectiveProjection, Renderable,
},