more work on texture bindings

This commit is contained in:
Carter Anderson 2020-02-21 00:15:24 -08:00
parent fb61204d53
commit 65284fcacb
6 changed files with 118 additions and 71 deletions

View file

@ -41,6 +41,13 @@ struct UniformAttributeArgs {
pub shader_def: Option<bool>,
}
struct FieldUniformName {
field: &'static str,
uniform: &'static str,
texture: &'static str,
sampler: &'static str,
}
#[proc_macro_derive(Uniforms, attributes(uniform))]
pub fn derive_uniforms(input: TokenStream) -> TokenStream {
const UNIFORM_ATTRIBUTE_NAME: &'static str = "uniform";
@ -109,12 +116,25 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
let struct_name = &ast.ident;
let struct_name_screaming_snake = struct_name.to_string().to_screaming_snake_case();
let info_ident = format_ident!("{}_UNIFORM_INFO", struct_name_screaming_snake);
let layout_ident = format_ident!("{}_UNIFORM_LAYOUTS", struct_name_screaming_snake);
let field_uniform_names_ident = format_ident!("{}_FIELD_UNIFORM_NAMES", struct_name_screaming_snake);
let get_uniform_bytes_field_name = active_uniform_fields.iter().map(|field| {
let active_uniform_field_names = active_uniform_fields.iter().map(|field| {
&field.ident
});
eprintln!("hitit");
let field_uniform_names = active_uniform_fields.iter().map(|f| {
let name = f.ident.as_ref().unwrap().to_string();
let texture = format!("{}_texture", name);
let sampler = format!("{}_sampler", name);
quote!(FieldUniformName {
field: #name,
uniform: #name,
texture: #texture,
sampler: #sampler,
})
});
let mut uniform_info = Vec::new();
let mut uniform_name_uniform_info = Vec::new();
for field in active_uniform_fields.iter() {
@ -122,7 +142,6 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
if let Type::Path(ref type_path) = field.ty {
let field_type_name = type_path.path.get_ident().unwrap().to_string();
if field_type_name == "ColorSource" || field_type_name == "Handle<Texture>" {
eprintln!("madeit");
let texture_name = format!("{}_texture", name);
let sampler_name = format!("{}_sampler", name);
uniform_name_uniform_info.push(texture_name.clone());
@ -142,6 +161,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
}
}
uniform_name_uniform_info.push(name.clone());
uniform_info.push(quote!(bevy::render::render_graph::UniformInfo {
name: #name,
bind_type: bevy::render::render_graph::BindType::Uniform {
@ -152,28 +172,54 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
}));
};
let layout_arrays = (0..uniform_info.len()).map(|_| quote!(&[]));
let get_uniform_info_array_refs =
(0..uniform_info.len()).map(|i| quote!(&#info_ident[#i]));
/*
uniform infos
x: ColorSource
y: Vec4
infos: [
"x_color",
"x_texture",
"x_sampler",
"y"
]
field_names = ["x", "y"]
InfoIter { field_names, index = 0, needs_sampler = false}
uniform-provider
for entity in entities
for info in entity.t.get_uniform_info_iter()
if info.bind_type == Uniform
entity.t.get_bytes()
elif info.bind_type == Texture
entity.get_texture()
*/
TokenStream::from(quote! {
const #info_ident: &[bevy::render::render_graph::UniformInfo] = &[
#(#uniform_info,)*
];
const #layout_ident: &[&[bevy::render::render_graph::UniformPropertyType]] = &[
#(#layout_arrays,)*
const #field_uniform_names_ident: &[FieldUniformName] = &[
#(#field_uniform_names,)*
];
impl bevy::render::render_graph::AsUniforms for #struct_name {
// TODO: max this an iterator that feeds on field_uniform_names_ident
fn get_uniform_infos(&self) -> &[bevy::render::render_graph::UniformInfo] {
#info_ident
}
fn get_uniform_layouts(&self) -> &[&[bevy::render::render_graph::UniformPropertyType]] {
#layout_ident
fn get_field_bind_type(&self, name: &str) -> bevy::render::render_graph::FieldBindType {
#(#field_names => #get_uniform_bytes_field_name,)*
}
// TODO: Fix this so uniform_name_uniform_info lines up with getbytes
fn get_uniform_bytes(&self, name: &str) -> Option<Vec<u8>> {
use bevy::core::bytes::GetBytes;
match name {
@ -181,12 +227,6 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
_ => None,
}
}
fn get_uniform_info(&self, name: &str) -> Option<&bevy::render::render_graph::UniformInfo> {
match name {
#(#uniform_name_uniform_info => Some(#get_uniform_info_array_refs),)*
_ => None,
}
}
// TODO: this will be very allocation heavy. find a way to either make this allocation free
// or alternatively only run it when the shader_defs have changed

View file

@ -1,6 +1,6 @@
use crate::render::shader_reflect::ShaderLayout;
use std::{
collections::{HashMap, hash_map::DefaultHasher, BTreeSet},
collections::{hash_map::DefaultHasher, BTreeSet, HashMap},
hash::{Hash, Hasher},
};
@ -20,30 +20,37 @@ impl PipelineLayout {
let mut bind_groups = HashMap::<u32, BindGroup>::new();
for shader_layout in shader_layouts {
for shader_bind_group in shader_layout.bind_groups.iter_mut() {
match bind_groups.get_mut(&shader_bind_group.index) {
Some(bind_group) => {
for shader_binding in shader_bind_group.bindings.iter() {
if let Some(binding) = bind_group.bindings.iter().find(|binding| binding.index == shader_binding.index) {
if binding != shader_binding {
panic!("Binding {} in BindGroup {} does not match across all shader types: {:?} {:?}", binding.index, bind_group.index, binding, shader_binding);
}
} else {
bind_group.bindings.insert(shader_binding.clone());
}
}
},
None => {
bind_groups.insert(shader_bind_group.index, shader_bind_group.clone());
}
}
match bind_groups.get_mut(&shader_bind_group.index) {
Some(bind_group) => {
for shader_binding in shader_bind_group.bindings.iter() {
if let Some(binding) = bind_group
.bindings
.iter()
.find(|binding| binding.index == shader_binding.index)
{
if binding != shader_binding {
panic!("Binding {} in BindGroup {} does not match across all shader types: {:?} {:?}", binding.index, bind_group.index, binding, shader_binding);
}
} else {
bind_group.bindings.insert(shader_binding.clone());
}
}
}
None => {
bind_groups.insert(shader_bind_group.index, shader_bind_group.clone());
}
}
}
}
let mut bind_groups_result = bind_groups.drain().map(|(_, value)| value).collect::<Vec<BindGroup>>();
let mut bind_groups_result = bind_groups
.drain()
.map(|(_, value)| value)
.collect::<Vec<BindGroup>>();
// NOTE: for some reason bind groups need to be sorted by index. this is likely an issue with bevy and not with wgpu
bind_groups_result.sort_by(|a, b| a.index.partial_cmp(&b.index).unwrap());
PipelineLayout {
bind_groups: bind_groups_result
bind_groups: bind_groups_result,
}
}
}

View file

@ -1,5 +1,5 @@
use crate::{
asset::{AssetStorage, Handle, Texture},
asset::{AssetStorage, Handle},
legion::prelude::*,
render::{
render_graph::{

View file

@ -46,10 +46,8 @@ where
.count = 0;
}
let mut sizes = Vec::new();
let mut counts = Vec::new();
for (uniforms, _renderable) in query.iter(world) {
let uniform_layouts = uniforms.get_uniform_layouts();
for (i, uniform_info) in uniforms
.get_uniform_infos()
.iter()
@ -64,15 +62,6 @@ where
{
// only add the first time a uniform info is processed
if self.uniform_buffer_info_names.len() <= i {
let uniform_layout = uniform_layouts[i];
// TODO: size is 0 right now because uniform layout isn't populated
// also size isn't even being used right now?
let size = uniform_layout
.iter()
.map(|u| u.get_size())
.fold(0, |total, current| total + current);
sizes.push(size);
self.uniform_buffer_info_names
.push(uniform_info.name.to_string());
}
@ -89,8 +78,7 @@ where
// the expense of hashing for large numbers of entities
for (i, name) in self.uniform_buffer_info_names.iter().enumerate() {
if let None = renderer.get_dynamic_uniform_buffer_info(name) {
let mut info = DynamicUniformBufferInfo::new();
info.size = sizes[i];
let info = DynamicUniformBufferInfo::new();
renderer.add_dynamic_uniform_buffer_info(name, info);
}

View file

@ -1,16 +1,13 @@
use crate::{
render::render_graph::{BindType, UniformPropertyType},
};
use crate::render::{color::ColorSource, render_graph::BindType};
use legion::prelude::Entity;
use std::collections::HashMap;
// TODO: add ability to specify specific pipeline for uniforms
pub trait AsUniforms {
fn get_uniform_infos(&self) -> &[UniformInfo];
fn get_uniform_info(&self, name: &str) -> Option<&UniformInfo>;
fn get_uniform_layouts(&self) -> &[&[UniformPropertyType]];
fn get_uniform_bytes(&self, name: &str) -> Option<Vec<u8>>;
fn get_shader_defs(&self) -> Option<Vec<String>>;
fn get_field_bind_type(&self, name: &str) -> FieldBindType;
// TODO: support zero-copy uniforms
// fn get_uniform_bytes_ref(&self, name: &str) -> Option<&[u8]>;
}
@ -28,6 +25,33 @@ impl ShaderDefSuffixProvider for bool {
}
}
pub enum FieldBindType {
Uniform,
Texture,
}
pub trait AsFieldBindType {
fn get_field_uniform_type(&self) -> FieldBindType;
}
impl AsFieldBindType for ColorSource {
fn get_field_uniform_type(&self) -> FieldBindType {
match *self {
ColorSource::Texture(_) => FieldBindType::Texture,
ColorSource::Color(_) => FieldBindType::Uniform,
}
}
}
// impl<T> AsFieldBindType for T
// where
// T: GetBytes,
// {
// fn get_field_uniform_type(&self) -> FieldBindType {
// FieldBindType::Uniform
// }
// }
pub struct UniformInfo<'a> {
pub name: &'a str,
pub bind_type: BindType,
@ -38,7 +62,6 @@ pub struct DynamicUniformBufferInfo {
pub offsets: HashMap<Entity, u64>,
pub capacity: u64,
pub count: u64,
pub size: u64,
}
impl DynamicUniformBufferInfo {
@ -48,7 +71,6 @@ impl DynamicUniformBufferInfo {
count: 0,
indices: HashMap::new(),
offsets: HashMap::new(),
size: 0,
}
}
}

View file

@ -1,6 +1,6 @@
use crate::render::render_graph::{
uniform::{AsUniforms, UniformInfo},
BindType, UniformPropertyType,
BindType, FieldBindType,
};
use zerocopy::AsBytes;
@ -14,32 +14,22 @@ const LOCAL_TO_WORLD_UNIFORM_INFO: &[UniformInfo] = &[UniformInfo {
},
}];
// these are separate from BindType::Uniform{properties} because they need to be const
const LOCAL_TO_WORLD_UNIFORM_LAYOUTS: &[&[UniformPropertyType]] = &[&[]];
impl AsUniforms for bevy_transform::prelude::LocalToWorld {
fn get_uniform_infos(&self) -> &[UniformInfo] {
LOCAL_TO_WORLD_UNIFORM_INFO
}
fn get_uniform_layouts(&self) -> &[&[UniformPropertyType]] {
LOCAL_TO_WORLD_UNIFORM_LAYOUTS
}
fn get_uniform_bytes(&self, name: &str) -> Option<Vec<u8>> {
match name {
"Object" => Some(self.0.to_cols_array_2d().as_bytes().into()),
_ => None,
}
}
fn get_uniform_info(&self, name: &str) -> Option<&UniformInfo> {
match name {
"Object" => Some(&LOCAL_TO_WORLD_UNIFORM_INFO[0]),
_ => None,
}
}
fn get_shader_defs(&self) -> Option<Vec<String>> {
None
}
fn get_field_bind_type(&self, name: &str) -> FieldBindType {
FieldBindType::Uniform
}
}