bevy/src/render/render_graph_2/shader.rs

341 lines
11 KiB
Rust
Raw Normal View History

2020-01-23 08:31:56 +00:00
use crate::{
legion::{
2020-01-24 07:39:56 +00:00
borrow::RefMap,
2020-01-23 08:31:56 +00:00
prelude::{Entity, World},
},
math::Vec4,
render::render_graph_2::{
wgpu_renderer::DynamicUniformBufferInfo, BindType, ResourceProvider, UniformPropertyType,
},
2020-01-23 08:31:56 +00:00
};
use legion::{prelude::*, storage::Component};
use std::collections::HashSet;
use std::marker::PhantomData;
use zerocopy::AsBytes;
2020-01-18 22:09:53 +00:00
2020-01-23 08:31:56 +00:00
pub type ShaderUniformSelector = fn(Entity, &World) -> Option<RefMap<&dyn AsUniforms>>;
pub struct ShaderUniforms {
// used for distinguishing
pub uniform_selectors: Vec<ShaderUniformSelector>,
}
impl ShaderUniforms {
2020-01-23 08:31:56 +00:00
pub fn new() -> Self {
ShaderUniforms {
uniform_selectors: Vec::new(),
}
}
pub fn add(&mut self, selector: ShaderUniformSelector) {
self.uniform_selectors.push(selector);
}
pub fn get_uniform_info<'a>(
&'a self,
world: &'a World,
entity: Entity,
uniform_name: &str,
) -> Option<&'a UniformInfo> {
for uniform_selector in self.uniform_selectors.iter().rev() {
let uniforms = uniform_selector(entity, world).unwrap_or_else(|| {
panic!(
"ShaderUniform selector points to a missing component. Uniform: {}",
uniform_name
)
});
let info = uniforms.get_uniform_info(uniform_name);
if let Some(_) = info {
return info;
}
}
None
}
pub fn get_uniform_bytes<'a>(
&'a self,
world: &'a World,
entity: Entity,
uniform_name: &str,
) -> Option<Vec<u8>> {
for uniform_selector in self.uniform_selectors.iter().rev() {
let uniforms = uniform_selector(entity, world).unwrap_or_else(|| {
panic!(
"ShaderUniform selector points to a missing component. Uniform: {}",
uniform_name
)
});
let bytes = uniforms.get_uniform_bytes(uniform_name);
if let Some(_) = bytes {
return bytes;
}
}
None
}
2020-01-23 08:31:56 +00:00
}
2020-01-18 22:09:53 +00:00
2020-01-23 08:31:56 +00:00
pub struct StandardMaterial {
pub albedo: Vec4,
2020-01-18 22:09:53 +00:00
}
2020-01-23 08:31:56 +00:00
pub trait GetBytes {
fn get_bytes(&self) -> Vec<u8>;
fn get_bytes_ref(&self) -> Option<&[u8]>;
2020-01-18 22:09:53 +00:00
}
2020-01-24 07:39:56 +00:00
// TODO: might need to add zerocopy to this crate to impl AsBytes for external crates
// impl<T> GetBytes for T where T : AsBytes {
2020-01-24 07:39:56 +00:00
// fn get_bytes(&self) -> Vec<u8> {
// self.as_bytes().into()
// }
2020-01-18 22:09:53 +00:00
2020-01-24 07:39:56 +00:00
// fn get_bytes_ref(&self) -> Option<&[u8]> {
// Some(self.as_bytes())
// }
// }
2020-01-18 22:09:53 +00:00
2020-01-23 08:31:56 +00:00
impl GetBytes for Vec4 {
fn get_bytes(&self) -> Vec<u8> {
let vec4_array: [f32; 4] = (*self).into();
vec4_array.as_bytes().into()
}
fn get_bytes_ref(&self) -> Option<&[u8]> {
None
}
2020-01-18 22:09:53 +00:00
}
2020-01-23 08:31:56 +00:00
pub trait AsUniforms {
fn get_uniform_infos(&self) -> &[UniformInfo];
fn get_uniform_info(&self, name: &str) -> Option<&UniformInfo>;
2020-01-23 08:31:56 +00:00
fn get_uniform_layouts(&self) -> &[&[UniformPropertyType]];
fn get_uniform_bytes(&self, name: &str) -> Option<Vec<u8>>;
2020-01-23 08:31:56 +00:00
// TODO: support zero-copy uniforms
// fn get_uniform_bytes_ref(&self, name: &str) -> Option<&[u8]>;
2020-01-18 22:09:53 +00:00
}
2020-01-23 08:31:56 +00:00
// pub struct UniformInfo<'a> {
// pub name: &'a str,
// pub
2020-01-23 08:31:56 +00:00
// }
pub struct UniformInfo<'a> {
pub name: &'a str,
pub bind_type: BindType,
}
pub fn uniform_selector<T>(entity: Entity, world: &World) -> Option<RefMap<&dyn AsUniforms>>
where
T: AsUniforms + Component,
{
world
.get_component::<T>(entity)
.map(|c| c.map_into(|s| s as &dyn AsUniforms))
}
2020-01-23 08:31:56 +00:00
2020-01-18 22:09:53 +00:00
// create this from a derive macro
const STANDARD_MATERIAL_UNIFORM_INFO: &[UniformInfo] = &[UniformInfo {
2020-01-23 08:31:56 +00:00
name: "StandardMaterial",
bind_type: BindType::Uniform {
dynamic: false,
// TODO: fill this in with properties
properties: Vec::new(),
2020-01-23 08:31:56 +00:00
},
}];
2020-01-23 08:31:56 +00:00
// these are separate from BindType::Uniform{properties} because they need to be const
const STANDARD_MATERIAL_UNIFORM_LAYOUTS: &[&[UniformPropertyType]] = &[&[]];
// const
2020-01-23 08:31:56 +00:00
impl AsUniforms for StandardMaterial {
fn get_uniform_infos(&self) -> &[UniformInfo] {
2020-01-23 08:31:56 +00:00
STANDARD_MATERIAL_UNIFORM_INFO
2020-01-18 22:09:53 +00:00
}
2020-01-23 08:31:56 +00:00
fn get_uniform_layouts(&self) -> &[&[UniformPropertyType]] {
STANDARD_MATERIAL_UNIFORM_LAYOUTS
2020-01-18 22:09:53 +00:00
}
2020-01-23 08:31:56 +00:00
fn get_uniform_bytes(&self, name: &str) -> Option<Vec<u8>> {
match name {
"StandardMaterial" => Some(self.albedo.get_bytes()),
_ => None,
}
}
fn get_uniform_info(&self, name: &str) -> Option<&UniformInfo> {
match name {
"StandardMaterial" => Some(&STANDARD_MATERIAL_UNIFORM_INFO[0]),
_ => None,
}
}
// fn iter_properties(&self) -> std::slice::Iter<&'static str> {
// STANDARD_MATERIAL_PROPERTIES.iter()
// }
// fn get_property(&self, name: &str) -> Option<ShaderValue> {
// match name {
// "albedo" => Some(match self.albedo {
// Albedo::Color(color) => ShaderValue::Vec4(color),
// Albedo::Texture(ref texture) => ShaderValue::Texture(texture)
// }),
// _ => None,
// }
// }
}
// create this from a derive macro
const LOCAL_TO_WORLD_UNIFORM_INFO: &[UniformInfo] = &[UniformInfo {
name: "Object",
bind_type: BindType::Uniform {
dynamic: false,
// TODO: maybe fill this in with properties (vec.push cant be const though)
properties: Vec::new(),
},
}];
// these are separate from BindType::Uniform{properties} because they need to be const
const LOCAL_TO_WORLD_UNIFORM_LAYOUTS: &[&[UniformPropertyType]] = &[&[]];
// const ST
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,
}
2020-01-18 22:09:53 +00:00
}
2020-01-23 08:31:56 +00:00
// fn iter_properties(&self) -> std::slice::Iter<&'static str> {
// STANDARD_MATERIAL_PROPERTIES.iter()
// }
// fn get_property(&self, name: &str) -> Option<ShaderValue> {
// match name {
// "albedo" => Some(match self.albedo {
// Albedo::Color(color) => ShaderValue::Vec4(color),
// Albedo::Texture(ref texture) => ShaderValue::Texture(texture)
// }),
// _ => None,
// }
// }
2020-01-18 22:09:53 +00:00
}
pub struct UniformResourceProvider<T>
where
T: AsUniforms + Send + Sync,
{
_marker: PhantomData<T>,
uniform_buffer_info_names: HashSet<String>,
// dynamic_uniform_buffer_infos: HashMap<String, DynamicUniformBufferInfo>,
}
impl<T> UniformResourceProvider<T>
where
T: AsUniforms + Send + Sync,
{
pub fn new() -> Self {
UniformResourceProvider {
// dynamic_uniform_buffer_infos: HashMap::new(),
uniform_buffer_info_names: HashSet::new(),
_marker: PhantomData,
}
}
}
impl<T> ResourceProvider for UniformResourceProvider<T>
where
T: AsUniforms + Send + Sync + 'static,
{
fn initialize(&mut self, renderer: &mut dyn super::Renderer, world: &mut World) {
}
fn update(&mut self, renderer: &mut dyn super::Renderer, world: &mut World) {
let query = <Read<T>>::query();
// retrieve all uniforms buffers that aren't aleady set. these are "dynamic" uniforms, which are set by the user in ShaderUniforms
// TODO: this breaks down in multiple ways:
// (1) resource_info will be set after the first run so this won't update.
// (2) if we create new buffers, the old bind groups will be invalid
for uniforms in query.iter(world) {
let uniform_layouts = uniforms.get_uniform_layouts();
for (i, uniform_info) in uniforms.get_uniform_infos().iter().enumerate() {
if let None = renderer.get_dynamic_uniform_buffer_info(uniform_info.name) {
let uniform_layout = uniform_layouts[i];
let mut info = DynamicUniformBufferInfo::new();
info.size = uniform_layout.iter().map(|u| u.get_size()).fold(0, |total, current| total + current);
self.uniform_buffer_info_names.insert(uniform_info.name.to_string());
renderer.add_dynamic_uniform_buffer_info(uniform_info.name, info);
}
let mut info = renderer.get_dynamic_uniform_buffer_info_mut(uniform_info.name)
.unwrap();
info.count += 1;
}
}
// allocate uniform buffers
// for (name, info) in self.dynamic_uniform_buffer_infos.iter_mut() {
// if let Some(_) = renderer.get_resource_info(name) {
// continue;
// }
// // allocate enough space for twice as many entities as there are currently;
// info.capacity = info.count * 2;
// let size = wgpu::BIND_BUFFER_ALIGNMENT * info.capacity;
// renderer.create_buffer(name, size, wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM)
// }
// copy entity uniform data to buffers
for name in self.uniform_buffer_info_names.iter() {
let info = renderer.get_dynamic_uniform_buffer_info_mut(name).unwrap();
info.capacity = info.count;
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.count;
let mut data = vec![Default::default(); size as usize];
// renderer
// .create_buffer_mapped("tmp_uniform_mapped", size as usize, wgpu::BufferUsage::COPY_SRC, &mut |mapped| {
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
let mut offset = 0usize;
for (i, (entity, uniforms)) in query.iter_entities(world).enumerate() {
// TODO: check if index has changed. if it has, then entity should be updated
// TODO: only mem-map entities if their data has changed
info.offsets.insert(entity, offset as u64);
info.indices.insert(i, entity);
// TODO: try getting ref first
if let Some(uniform_bytes) = uniforms.get_uniform_bytes(name) {
data[offset..(offset + uniform_bytes.len())].copy_from_slice(uniform_bytes.as_slice());
offset += alignment;
}
}
// });
// TODO: port me
// let uniform_buffer = self.buffers.get(name);
renderer.create_buffer_with_data(name, &data, wgpu::BufferUsage::UNIFORM);
}
}
fn resize(
&mut self,
renderer: &mut dyn super::Renderer,
world: &mut World,
width: u32,
height: u32,
) {
}
}