AsUniforms provide VertexBufferDescriptor. Initial macro work

This commit is contained in:
Carter Anderson 2020-03-17 18:25:27 -07:00
parent 28fb0fdfc8
commit d9663d740b
14 changed files with 233 additions and 94 deletions

10
.vscode/settings.json vendored
View file

@ -1,10 +1,18 @@
{
"cSpell.words": [
"Bitmask",
"MSAA",
"Wgpu",
"Zunstable",
"bools",
"chunkset",
"chunksets",
"eprintln",
"hashset",
"multizip",
"passthrough"
"passthrough",
"rspirv",
"rustc",
"spirv"
]
}

View file

@ -8,7 +8,6 @@ edition = "2018"
default = ["wgpu"]
[dependencies]
# Modified to use std::any::type_name instead of std::any::TypeId
legion = { path = "bevy_legion", features = ["serialize"] }
wgpu = { git = "https://github.com/gfx-rs/wgpu-rs.git", rev = "a7b0d5ae5bc0934439ef559ed145e93f0117c39a", optional = true }
bitflags = "1.0"
@ -27,10 +26,11 @@ type-uuid = "0.1"
shaderc = "0.6"
libloading = "0.5.2"
png = "0.16.0"
# rspirv = { git = "https://github.com/gfx-rs/rspirv.git", rev = "baa469eae2932271174593eb066894d7a7a38439" }
spirv-reflect = "0.2.3"
bevy_derive = { path = "bevy_derive" }
bevy_transform = { path = "bevy_transform" }
# TODO: replace once_cell with std equivalent if/when this lands: https://github.com/rust-lang/rfcs/pull/2788
once_cell = "1.3.1"
[profile.release]
debug = true

View file

@ -4,7 +4,7 @@ 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};
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields, Type};
#[proc_macro_derive(EntityArchetype)]
pub fn derive_entity_archetype(input: TokenStream) -> TokenStream {
@ -45,7 +45,7 @@ struct UniformAttributeArgs {
#[proc_macro_derive(Uniforms, attributes(uniform))]
pub fn derive_uniforms(input: TokenStream) -> TokenStream {
const UNIFORM_ATTRIBUTE_NAME: &'static str = "uniform";
static UNIFORM_ATTRIBUTE_NAME: &'static str = "uniform";
let ast = parse_macro_input!(input as DeriveInput);
let fields = match &ast.data {
@ -85,6 +85,10 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
})
.map(|(f, _attr)| *f)
.collect::<Vec<&Field>>();
let active_uniform_field_types = active_uniform_fields
.iter()
.map(|f| &f.ty)
.collect::<Vec<&Type>>();
let shader_def_fields = uniform_fields
.iter()
@ -109,8 +113,10 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
});
let struct_name = &ast.ident;
let struct_name_string = struct_name.to_string();
let struct_name_screaming_snake = struct_name.to_string().to_screaming_snake_case();
let field_infos_ident = format_ident!("{}_FIELD_INFO", struct_name_screaming_snake);
let vertex_buffer_descriptor_ident = format_ident!("{}_VERTEX_BUFFER_DESCRIPTOR", struct_name_screaming_snake);
let active_uniform_field_names = active_uniform_fields.iter().map(|field| {
&field.ident
@ -158,10 +164,25 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
});
TokenStream::from(quote! {
const #field_infos_ident: &[bevy::render::shader::FieldInfo] = &[
static #field_infos_ident: &[bevy::render::shader::FieldInfo] = &[
#(#field_infos,)*
];
static #vertex_buffer_descriptor_ident: bevy::once_cell::sync::Lazy<bevy::render::pipeline::VertexBufferDescriptor> =
bevy::once_cell::sync::Lazy::new(|| {
use bevy::render::pipeline::AsVertexFormats;
// let vertex_formats = vec![
// #(#active_uniform_field_types::as_vertex_formats(),)*
// ];
bevy::render::pipeline::VertexBufferDescriptor {
attributes: Vec::new(),
name: #struct_name_string.to_string(),
step_mode: bevy::render::pipeline::InputStepMode::Instance,
stride: 0,
}
});
impl bevy::render::shader::AsUniforms for #struct_name {
// TODO: max this an iterator that feeds on field_uniform_names_ident
fn get_field_infos(&self) -> &[bevy::render::shader::FieldInfo] {
@ -213,6 +234,10 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
.map(|(f, shader_def)| format!("{}_{}{}", #struct_name_screaming_snake, f, shader_def.unwrap()))
.collect::<Vec<String>>())
}
fn get_vertex_buffer_descriptor() -> Option<&'static bevy::render::pipeline::VertexBufferDescriptor> {
Some(&#vertex_buffer_descriptor_ident)
}
}
})
}

View file

@ -12,4 +12,5 @@ pub mod diagnostics;
pub use bevy_transform as transform;
pub use glam as math;
pub use legion;
pub use legion;
pub use once_cell;

View file

@ -4,6 +4,7 @@ mod pipeline;
mod pipeline_layout;
pub mod pipelines;
mod vertex_buffer_descriptor;
mod vertex_format;
pub mod state_descriptors;
pub use bind_group::*;
@ -11,3 +12,4 @@ pub use binding::*;
pub use pipeline::*;
pub use pipeline_layout::*;
pub use vertex_buffer_descriptor::*;
pub use vertex_format::*;

View file

@ -58,7 +58,7 @@ pub struct PipelineDescriptor {
pub sample_mask: u32,
/// When enabled, produces another sample mask per pixel based on the alpha output value, that
/// is ANDed with the sample_mask and the primitive coverage to restrict the set of samples
/// is AND-ed with the sample_mask and the primitive coverage to restrict the set of samples
/// affected by a primitive.
/// The implicit mask produced for alpha of zero is guaranteed to be zero, and for alpha of one
/// is guaranteed to be all 1-s.

View file

@ -1,3 +1,5 @@
use super::VertexFormat;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct VertexBufferDescriptor {
pub name: String,
@ -6,77 +8,6 @@ pub struct VertexBufferDescriptor {
pub attributes: Vec<VertexAttributeDescriptor>,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum VertexFormat {
Uchar2 = 1,
Uchar4 = 3,
Char2 = 5,
Char4 = 7,
Uchar2Norm = 9,
Uchar4Norm = 11,
Char2Norm = 14,
Char4Norm = 16,
Ushort2 = 18,
Ushort4 = 20,
Short2 = 22,
Short4 = 24,
Ushort2Norm = 26,
Ushort4Norm = 28,
Short2Norm = 30,
Short4Norm = 32,
Half2 = 34,
Half4 = 36,
Float = 37,
Float2 = 38,
Float3 = 39,
Float4 = 40,
Uint = 41,
Uint2 = 42,
Uint3 = 43,
Uint4 = 44,
Int = 45,
Int2 = 46,
Int3 = 47,
Int4 = 48,
}
impl VertexFormat {
pub fn get_size(&self) -> u64 {
match *self {
VertexFormat::Uchar2 => 2,
VertexFormat::Uchar4 => 4,
VertexFormat::Char2 => 2,
VertexFormat::Char4 => 4,
VertexFormat::Uchar2Norm => 2,
VertexFormat::Uchar4Norm => 4,
VertexFormat::Char2Norm => 2,
VertexFormat::Char4Norm => 4,
VertexFormat::Ushort2 => 2 * 2,
VertexFormat::Ushort4 => 2 * 4,
VertexFormat::Short2 => 2 * 2,
VertexFormat::Short4 => 2 * 4,
VertexFormat::Ushort2Norm => 2 * 2,
VertexFormat::Ushort4Norm => 2 * 4,
VertexFormat::Short2Norm => 2 * 2,
VertexFormat::Short4Norm => 2 * 4,
VertexFormat::Half2 => 2 * 2,
VertexFormat::Half4 => 2 * 4,
VertexFormat::Float => 4,
VertexFormat::Float2 => 4 * 2,
VertexFormat::Float3 => 4 * 3,
VertexFormat::Float4 => 4 * 4,
VertexFormat::Uint => 4,
VertexFormat::Uint2 => 4 * 2,
VertexFormat::Uint3 => 4 * 3,
VertexFormat::Uint4 => 4 * 4,
VertexFormat::Int => 4,
VertexFormat::Int2 => 4 * 2,
VertexFormat::Int3 => 4 * 3,
VertexFormat::Int4 => 4 * 4,
}
}
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum InputStepMode {
Vertex = 0,
@ -89,4 +20,4 @@ pub struct VertexAttributeDescriptor {
pub offset: u64,
pub format: VertexFormat,
pub shader_location: u32,
}
}

View file

@ -0,0 +1,111 @@
use crate::math::{Vec2, Vec3, Vec4, Mat4};
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum VertexFormat {
Uchar2 = 1,
Uchar4 = 3,
Char2 = 5,
Char4 = 7,
Uchar2Norm = 9,
Uchar4Norm = 11,
Char2Norm = 14,
Char4Norm = 16,
Ushort2 = 18,
Ushort4 = 20,
Short2 = 22,
Short4 = 24,
Ushort2Norm = 26,
Ushort4Norm = 28,
Short2Norm = 30,
Short4Norm = 32,
Half2 = 34,
Half4 = 36,
Float = 37,
Float2 = 38,
Float3 = 39,
Float4 = 40,
Uint = 41,
Uint2 = 42,
Uint3 = 43,
Uint4 = 44,
Int = 45,
Int2 = 46,
Int3 = 47,
Int4 = 48,
}
impl VertexFormat {
pub fn get_size(&self) -> u64 {
match *self {
VertexFormat::Uchar2 => 2,
VertexFormat::Uchar4 => 4,
VertexFormat::Char2 => 2,
VertexFormat::Char4 => 4,
VertexFormat::Uchar2Norm => 2,
VertexFormat::Uchar4Norm => 4,
VertexFormat::Char2Norm => 2,
VertexFormat::Char4Norm => 4,
VertexFormat::Ushort2 => 2 * 2,
VertexFormat::Ushort4 => 2 * 4,
VertexFormat::Short2 => 2 * 2,
VertexFormat::Short4 => 2 * 4,
VertexFormat::Ushort2Norm => 2 * 2,
VertexFormat::Ushort4Norm => 2 * 4,
VertexFormat::Short2Norm => 2 * 2,
VertexFormat::Short4Norm => 2 * 4,
VertexFormat::Half2 => 2 * 2,
VertexFormat::Half4 => 2 * 4,
VertexFormat::Float => 4,
VertexFormat::Float2 => 4 * 2,
VertexFormat::Float3 => 4 * 3,
VertexFormat::Float4 => 4 * 4,
VertexFormat::Uint => 4,
VertexFormat::Uint2 => 4 * 2,
VertexFormat::Uint3 => 4 * 3,
VertexFormat::Uint4 => 4 * 4,
VertexFormat::Int => 4,
VertexFormat::Int2 => 4 * 2,
VertexFormat::Int3 => 4 * 3,
VertexFormat::Int4 => 4 * 4,
}
}
}
pub trait AsVertexFormats {
fn as_vertex_formats() -> &'static [VertexFormat];
}
impl AsVertexFormats for f32 {
fn as_vertex_formats() -> &'static [VertexFormat] {
&[VertexFormat::Float]
}
}
impl AsVertexFormats for Vec2 {
fn as_vertex_formats() -> &'static [VertexFormat] {
&[VertexFormat::Float2]
}
}
impl AsVertexFormats for Vec3 {
fn as_vertex_formats() -> &'static [VertexFormat] {
&[VertexFormat::Float3]
}
}
impl AsVertexFormats for Vec4 {
fn as_vertex_formats() -> &'static [VertexFormat] {
&[VertexFormat::Float4]
}
}
impl AsVertexFormats for Mat4 {
fn as_vertex_formats() -> &'static [VertexFormat] {
&[
VertexFormat::Float4,
VertexFormat::Float4,
VertexFormat::Float4,
VertexFormat::Float4,
]
}
}

View file

@ -346,11 +346,18 @@ where
);
renderer.copy_buffer_to_buffer(mapped_buffer_resource, 0, resource, 0, size);
// TODO: uncomment this to free resource?
renderer.remove_buffer(mapped_buffer_resource);
}
}
fn initialize_vertex_buffer_descriptor(&self, renderer: &mut dyn Renderer) {
let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor();
if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor {
if let None = renderer.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name) {
renderer.set_vertex_buffer_descriptor(vertex_buffer_descriptor.clone());
}
}
}
}
impl<T> ResourceProvider for UniformResourceProvider<T>
@ -367,12 +374,14 @@ where
}
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {
let query = <(Read<T>, Read<Renderable>)>::query();
self.initialize_vertex_buffer_descriptor(renderer);
// 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
// reset all uniform buffer info counts
let query = <(Read<T>, Read<Renderable>)>::query();
for (_name, (resource, count, _entities)) in self.uniform_buffer_info_resources.iter_mut() {
renderer
.get_dynamic_uniform_buffer_info_mut(resource.unwrap())

View file

@ -84,7 +84,7 @@ fn try_compiling_shader_with_macros(
.unwrap();
let shader = shader_storage.get(shader_handle).unwrap();
// don't produce new shader if the input source is already spriv
// don't produce new shader if the input source is already spirv
if let ShaderSource::Spirv(_) = shader.source {
return None;
}
@ -203,7 +203,7 @@ pub fn update_shader_assignments(
macroed_pipeline_handle
};
// TODO: this will break down if pipeline layout changes. fix this with "autolayout"
// TODO: this will break down if pipeline layout changes. fix this with "auto-layout"
if let None = shader_pipeline_assignments.assignments.get(&final_handle) {
shader_pipeline_assignments
.assignments

View file

@ -1,7 +1,7 @@
use crate::{
legion::prelude::*,
render::{
pipeline::PipelineDescriptor,
pipeline::{VertexBufferDescriptor, PipelineDescriptor},
render_graph::RenderGraph,
render_resource::{BufferUsage, RenderResource, RenderResources, ResourceInfo},
shader::DynamicUniformBufferInfo,
@ -105,6 +105,8 @@ pub trait Renderer {
entity: Entity,
pipeline_descriptor: &PipelineDescriptor,
);
fn set_vertex_buffer_descriptor(&mut self, vertex_buffer_descriptor: VertexBufferDescriptor);
fn get_vertex_buffer_descriptor(&self, name: &str) -> Option<&VertexBufferDescriptor>;
}
pub trait RenderPass {

View file

@ -7,9 +7,7 @@ use crate::{
PassDescriptor, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor,
},
pipeline::{
BindType, PipelineDescriptor, PipelineLayout, PipelineLayoutType,
},
pipeline::{BindType, PipelineDescriptor, PipelineLayout, PipelineLayoutType, VertexBufferDescriptor},
render_graph::RenderGraph,
render_resource::{
resource_name, BufferUsage, RenderResource, RenderResources, ResourceInfo,
@ -29,6 +27,7 @@ pub struct WgpuRenderer {
pub encoder: Option<wgpu::CommandEncoder>,
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
pub render_pipelines: HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
pub vertex_buffer_descriptors: HashMap<String, VertexBufferDescriptor>,
pub wgpu_resources: WgpuResources,
}
@ -65,6 +64,7 @@ impl WgpuRenderer {
swap_chain_descriptor,
wgpu_resources: WgpuResources::new(),
render_pipelines: HashMap::new(),
vertex_buffer_descriptors: HashMap::new(),
}
}
@ -124,8 +124,6 @@ impl WgpuRenderer {
}
let layout = pipeline_descriptor.get_layout_mut().unwrap();
// println!("{:#?}", layout);
// println!();
// setup new bind group layouts
for bind_group in layout.bind_groups.iter_mut() {
@ -714,4 +712,16 @@ impl Renderer for WgpuRenderer {
}
}
}
fn set_vertex_buffer_descriptor(
&mut self,
vertex_buffer_descriptor: VertexBufferDescriptor,
) {
self.vertex_buffer_descriptors.insert(vertex_buffer_descriptor.name.to_string(), vertex_buffer_descriptor);
}
fn get_vertex_buffer_descriptor(
&self,
name: &str
) -> Option<&VertexBufferDescriptor> {
self.vertex_buffer_descriptors.get(name)
}
}

View file

@ -3,7 +3,7 @@ use crate::{
core::GetBytes,
render::{
color::ColorSource,
pipeline::BindType,
pipeline::{VertexBufferDescriptor, BindType},
texture::{Texture, TextureViewDimension},
},
};
@ -17,6 +17,7 @@ pub trait AsUniforms {
fn get_shader_defs(&self) -> Option<Vec<String>>;
fn get_field_bind_type(&self, name: &str) -> Option<FieldBindType>;
fn get_uniform_bytes_ref(&self, name: &str) -> Option<&[u8]>;
fn get_vertex_buffer_descriptor() -> Option<&'static VertexBufferDescriptor>;
}
pub trait ShaderDefSuffixProvider {

View file

@ -1,14 +1,17 @@
use crate::{
asset::Handle,
render::{
pipeline::{
InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat,
},
shader::{AsUniforms, FieldBindType, FieldInfo},
texture::Texture,
},
};
use once_cell::sync::Lazy;
use zerocopy::AsBytes;
const LOCAL_TO_WORLD_FIELD_INFOS: &[FieldInfo] = &[FieldInfo {
static LOCAL_TO_WORLD_FIELD_INFOS: &[FieldInfo] = &[FieldInfo {
name: "object",
uniform_name: "Object",
texture_name: "",
@ -16,6 +19,38 @@ const LOCAL_TO_WORLD_FIELD_INFOS: &[FieldInfo] = &[FieldInfo {
is_instanceable: true,
}];
static VERTEX_BUFFER_DESCRIPTOR: Lazy<VertexBufferDescriptor> = Lazy::new(|| VertexBufferDescriptor {
attributes: vec![
VertexAttributeDescriptor {
name: "I_Object_Matrix_0".to_string(),
format: VertexFormat::Float4,
offset: 0,
shader_location: 0,
},
VertexAttributeDescriptor {
name: "I_Object_Matrix_1".to_string(),
format: VertexFormat::Float4,
offset: 16,
shader_location: 0,
},
VertexAttributeDescriptor {
name: "I_Object_Matrix_2".to_string(),
format: VertexFormat::Float4,
offset: 32,
shader_location: 0,
},
VertexAttributeDescriptor {
name: "I_Object_Matrix_3".to_string(),
format: VertexFormat::Float4,
offset: 48,
shader_location: 0,
},
],
name: "Object".to_string(),
step_mode: InputStepMode::Instance,
stride: 64,
});
impl AsUniforms for bevy_transform::prelude::LocalToWorld {
fn get_field_infos(&self) -> &[FieldInfo] {
LOCAL_TO_WORLD_FIELD_INFOS
@ -47,4 +82,8 @@ impl AsUniforms for bevy_transform::prelude::LocalToWorld {
_ => None,
}
}
fn get_vertex_buffer_descriptor() -> Option<&'static VertexBufferDescriptor> {
Some(&VERTEX_BUFFER_DESCRIPTOR)
}
}