validate VertexBufferDescriptors and fill in blanks when possible

This commit is contained in:
Carter Anderson 2020-03-21 21:10:58 -07:00
parent a4eed18800
commit fb496a6172
9 changed files with 103 additions and 29 deletions

View file

@ -9,7 +9,6 @@ Here is the current list of planned features. All items are sorted in approximat
* Textures
* Physically based rendering
* Skeletal animation
* Macro to produce vertex buffer attributes (and maybe descriptors) from structs
* Add runtime type safety to uniform bindings (and maybe compile time)
* Inject layout set/bindings into shader source so they don't need to be defined in-shader. Specify set / binding indices in resource providers?
* Pull as much logic as possible from wgpu_renderer into a "render orchestrator" struct/trait

View file

@ -334,7 +334,11 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
}
fn get_vertex_buffer_descriptor() -> Option<&'static bevy::render::pipeline::VertexBufferDescriptor> {
Some(&#vertex_buffer_descriptor_ident)
if #vertex_buffer_descriptor_ident.attributes.len() == 0 {
None
} else {
Some(&#vertex_buffer_descriptor_ident)
}
}
}
})

View file

@ -26,8 +26,6 @@ fn main() {
r#"
#version 450
layout(location = 0) in vec4 Vertex_Position;
layout(location = 1) in vec4 Vertex_Normal;
layout(location = 2) in vec2 Vertex_Uv;
layout(location = 0) out vec4 v_Position;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;

View file

@ -6,6 +6,15 @@ pub trait GetBytes {
fn get_bytes_ref(&self) -> Option<&[u8]>;
}
impl GetBytes for f32 {
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; 2] {
fn get_bytes(&self) -> Vec<u8> {
self.as_bytes().to_vec()

View file

@ -8,6 +8,26 @@ pub struct VertexBufferDescriptor {
pub attributes: Vec<VertexAttributeDescriptor>,
}
impl VertexBufferDescriptor {
pub fn sync_with_descriptor(&mut self, descriptor: &VertexBufferDescriptor) {
for attribute in self.attributes.iter_mut() {
let descriptor_attribute = descriptor
.attributes
.iter()
.find(|a| a.name == attribute.name)
.unwrap_or_else(|| {
panic!(
"Encountered unsupported Vertex Buffer Attribute: {}",
attribute.name
);
});
attribute.offset = descriptor_attribute.offset;
}
self.stride = descriptor.stride;
}
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum InputStepMode {
Vertex = 0,

View file

@ -3,8 +3,11 @@ use crate::{
prelude::Renderable,
render::{
mesh::Mesh,
render_graph::RenderGraph,
render_resource::{AssetBatchers, BufferInfo, BufferUsage, ResourceProvider},
renderer::Renderer,
shader::AsUniforms,
Vertex,
},
};
use legion::{filter::*, prelude::*};
@ -39,6 +42,16 @@ impl MeshResourceProvider {
}
impl ResourceProvider for MeshResourceProvider {
fn initialize(
&mut self,
_renderer: &mut dyn Renderer,
_world: &mut World,
resources: &Resources,
) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.set_vertex_buffer_descriptor(Vertex::get_vertex_buffer_descriptor().cloned().unwrap());
}
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {
let mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();

View file

@ -1,24 +1,32 @@
use crate as bevy;
use crate::{
ecs,
prelude::Node,
render::{
render_graph::RenderGraph,
render_resource::{
resource_name, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource,
ResourceProvider,
},
renderer::Renderer,
shader::AsUniforms,
},
};
use bevy_derive::Uniforms;
use bevy_transform::prelude::Parent;
use legion::prelude::*;
use zerocopy::{AsBytes, FromBytes};
#[repr(C)]
#[derive(Clone, Copy, Debug, AsBytes, FromBytes)]
pub struct RectData {
#[derive(Clone, Copy, Debug, AsBytes, FromBytes, Uniforms)]
pub struct Rect {
#[uniform(instance)]
pub position: [f32; 2],
#[uniform(instance)]
pub size: [f32; 2],
#[uniform(instance)]
pub color: [f32; 4],
#[uniform(instance)]
pub z_index: f32,
}
@ -44,7 +52,7 @@ impl UiResourceProvider {
let mut add_data: Box<dyn FnMut(&World, Entity, ()) -> Option<()>> =
Box::new(|world, entity, _| {
let node = world.get_component::<Node>(entity).unwrap();
data.push(RectData {
data.push(Rect {
position: node.global_position.into(),
size: node.size.into(),
color: node.color.into(),
@ -69,7 +77,7 @@ impl UiResourceProvider {
return;
}
let size = std::mem::size_of::<RectData>() as u64;
let size = std::mem::size_of::<Rect>() as u64;
let data_len = data.len() as u64;
if let Some(old_instance_buffer) = self.instance_buffer {
@ -102,8 +110,10 @@ impl ResourceProvider for UiResourceProvider {
&mut self,
_renderer: &mut dyn Renderer,
_world: &mut World,
_resources: &Resources,
resources: &Resources,
) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.set_vertex_buffer_descriptor(Rect::get_vertex_buffer_descriptor().cloned().unwrap());
}
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, _resources: &Resources) {

View file

@ -444,7 +444,6 @@ where
if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor {
if let None = render_graph.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name)
{
println!("{:#?}", vertex_buffer_descriptor);
render_graph.set_vertex_buffer_descriptor(vertex_buffer_descriptor.clone());
}
}
@ -461,13 +460,12 @@ where
world: &mut World,
resources: &Resources,
) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
self.initialize_vertex_buffer_descriptor(&mut render_graph);
self.update(renderer, world, resources);
}
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
self.initialize_vertex_buffer_descriptor(&mut render_graph);
// TODO: this breaks down in multiple ways:
// (SOLVED 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

View file

@ -67,10 +67,46 @@ impl WgpuRenderer {
}
}
pub fn setup_vertex_buffer_descriptors(
render_graph: &RenderGraph,
vertex_spirv: &Shader,
pipeline_descriptor: &PipelineDescriptor,
) -> Vec<OwnedWgpuVertexBufferDescriptor> {
let mut reflected_vertex_layout = if pipeline_descriptor.reflect_vertex_buffer_descriptors {
Some(vertex_spirv.reflect_layout().unwrap())
} else {
None
};
let vertex_buffer_descriptors = if let Some(ref mut layout) = reflected_vertex_layout {
for vertex_buffer_descriptor in layout.vertex_buffer_descriptors.iter_mut() {
if let Some(graph_descriptor) =
render_graph.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name)
{
vertex_buffer_descriptor.sync_with_descriptor(graph_descriptor);
} else {
panic!(
"Encountered unsupported Vertex Buffer: {}",
vertex_buffer_descriptor.name
);
}
}
&layout.vertex_buffer_descriptors
} else {
&pipeline_descriptor.vertex_buffer_descriptors
};
vertex_buffer_descriptors
.iter()
.map(|v| v.into())
.collect::<Vec<OwnedWgpuVertexBufferDescriptor>>()
}
pub fn create_render_pipeline(
wgpu_resources: &mut WgpuResources,
pipeline_descriptor: &mut PipelineDescriptor,
device: &wgpu::Device,
render_graph: &RenderGraph,
vertex_shader: &Shader,
fragment_shader: Option<&Shader>,
) -> wgpu::RenderPipeline {
@ -166,22 +202,8 @@ impl WgpuRenderer {
bind_group_layouts: bind_group_layouts.as_slice(),
});
let reflected_vertex_layout = if pipeline_descriptor.reflect_vertex_buffer_descriptors {
Some(vertex_spirv.reflect_layout().unwrap())
} else {
None
};
let vertex_buffer_descriptors = if let Some(ref layout) = reflected_vertex_layout {
&layout.vertex_buffer_descriptors
} else {
&pipeline_descriptor.vertex_buffer_descriptors
};
let owned_vertex_buffer_descriptors = vertex_buffer_descriptors
.iter()
.map(|v| v.into())
.collect::<Vec<OwnedWgpuVertexBufferDescriptor>>();
let owned_vertex_buffer_descriptors =
Self::setup_vertex_buffer_descriptors(render_graph, &vertex_spirv, pipeline_descriptor);
let color_states = pipeline_descriptor
.color_states
@ -462,6 +484,7 @@ impl Renderer for WgpuRenderer {
&mut self.wgpu_resources,
pipeline_descriptor,
&self.device,
&render_graph,
vertex_shader,
fragment_shader,
);