Reflect Vertex Buffer Attributes

Must follow VertexBufferDescriptorName_AttributeName format

I_VertexBufferDescriptorName_AttributeName indicates that an attribute is instanced

Currently all attributes must be defined in shaders or offsets will be incorrect.
This commit is contained in:
Carter Anderson 2020-03-17 13:09:51 -07:00
parent 62d1e710a5
commit 28fb0fdfc8
15 changed files with 597 additions and 249 deletions

View file

@ -25,7 +25,9 @@ fn main() {
ShaderStage::Vertex,
r#"
#version 450
layout(location = 0) in vec4 a_Pos;
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;
@ -34,7 +36,7 @@ fn main() {
mat4 Model;
};
void main() {
v_Position = Model * a_Pos;
v_Position = Model * Vertex_Position;
gl_Position = ViewProj * v_Position;
}
"#,

View file

@ -1,172 +1,107 @@
use bevy::prelude::*;
use rand::{random, rngs::StdRng, Rng, SeedableRng};
struct Person;
struct Velocity {
pub value: math::Vec3,
}
struct NavigationPoint {
pub target: math::Vec3,
}
struct Wander {
pub duration_bounds: math::Vec2,
pub distance_bounds: math::Vec2,
pub duration: f32,
pub elapsed: f32,
}
use rand::{rngs::StdRng, Rng, SeedableRng};
fn main() {
AppBuilder::new()
.setup_world(setup)
.add_system(build_wander_system())
.add_system(build_navigate_system())
.add_defaults()
.add_system(build_move_system())
.add_system(bevy::diagnostics::build_fps_printer_system())
.setup_world(setup)
.run();
}
fn setup(world: &mut World, resources: &mut Resources) {
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube));
world.insert(
(),
vec![
// lights
(
Light::default(),
LocalToWorld::identity(),
Translation::new(4.0, -4.0, 5.0),
Rotation::from_euler_angles(0.0, 0.0, 0.0),
),
],
);
world.insert(
(),
vec![
// camera
(
Camera::new(CameraType::Projection {
fov: std::f32::consts::PI / 4.0,
near: 1.0,
far: 1000.0,
aspect_ratio: 1.0,
}),
ActiveCamera,
LocalToWorld(Mat4::look_at_rh(
Vec3::new(6.0, -40.0, 20.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
)),
),
],
);
let mut rng = StdRng::from_entropy();
for _ in 0..70000 {
create_person(
world,
cube_handle,
Translation::new(rng.gen_range(-50.0, 50.0), 0.0, rng.gen_range(-50.0, 50.0)),
);
}
}
fn build_wander_system() -> Box<dyn Schedulable> {
let mut rng = StdRng::from_entropy();
SystemBuilder::new("Wander")
.read_resource::<Time>()
.with_query(<(
Read<Person>,
Read<Translation>,
Write<Wander>,
Write<NavigationPoint>,
)>::query())
.build(move |_, world, time, person_query| {
for (_, translation, mut wander, mut navigation_point) in person_query.iter_mut(world) {
wander.elapsed += time.delta_seconds;
if wander.elapsed >= wander.duration {
let direction = math::vec3(
rng.gen_range(-1.0, 1.0),
rng.gen_range(-1.0, 1.0),
rng.gen_range(0.0, 0.001),
)
.normalize();
let distance =
rng.gen_range(wander.distance_bounds.x(), wander.distance_bounds.y());
navigation_point.target = translation.0 + direction * distance;
wander.elapsed = 0.0;
wander.duration =
rng.gen_range(wander.duration_bounds.x(), wander.duration_bounds.y());
}
}
})
}
fn build_navigate_system() -> Box<dyn Schedulable> {
SystemBuilder::new("Navigate")
.with_query(<(
Read<Person>,
Write<Translation>,
Write<Velocity>,
Write<NavigationPoint>,
)>::query())
.build(move |_, world, _, person_query| {
for (_, translation, mut velocity, navigation_point) in person_query.iter_mut(world) {
let distance = navigation_point.target - translation.0;
if distance.length() > 0.01 {
let direction = distance.normalize();
velocity.value = direction * 2.0;
} else {
velocity.value = math::vec3(0.0, 0.0, 0.0);
}
}
})
}
fn build_move_system() -> Box<dyn Schedulable> {
SystemBuilder::new("Move")
.read_resource::<Time>()
.with_query(<(Write<Translation>, Read<Velocity>)>::query())
.build(move |_, world, time, person_query| {
for (mut translation, velocity) in person_query.iter_mut(world) {
translation.0 += velocity.value * time.delta_seconds;
.write_resource::<AssetStorage<StandardMaterial>>()
.with_query(<(Write<Translation>, Read<Handle<StandardMaterial>>)>::query())
.build(move |_, world, (time, material_storage), person_query| {
for (mut translation, material_handle) in person_query.iter_mut(world) {
let material = material_storage.get_mut(&material_handle).unwrap();
translation.0 += math::vec3(1.0, 0.0, 0.0) * time.delta_seconds;
if let ColorSource::Color(ref mut color) = material.albedo {
*color = *color
+ Color::rgb(-time.delta_seconds, -time.delta_seconds, time.delta_seconds);
}
}
})
}
fn create_person(world: &mut World, mesh_handle: Handle<Mesh>, translation: Translation) {
world.insert(
(),
vec![(
Person {},
Wander {
duration_bounds: math::vec2(3.0, 10.0),
distance_bounds: math::vec2(-50.0, 50.0),
elapsed: 0.0,
duration: 0.0,
},
NavigationPoint {
target: math::vec3(0.0, 0.0, 0.0),
},
Velocity {
value: math::vec3(0.0, 0.0, 0.0),
},
StandardMaterial {
albedo: (math::vec4(0.5, 0.3, 0.3, 1.0) * random::<f32>()).into(),
},
Renderable {
fn setup(world: &mut World, resources: &mut Resources) {
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.unwrap();
let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube));
let plane_handle = mesh_storage.add(Mesh::load(MeshType::Plane { size: 10.0 }));
let cube_material_handle = material_storage.add(StandardMaterial {
albedo: Color::rgb(0.5, 0.4, 0.3).into(),
});
let plane_material_handle = material_storage.add(StandardMaterial {
albedo: Color::rgb(0.1, 0.2, 0.1).into(),
});
let mut builder = world
.build()
// plane
.add_entity(MeshEntity {
mesh: plane_handle,
material: plane_material_handle,
..Default::default()
})
// cube
.add_entity(MeshEntity {
mesh: cube_handle,
material: cube_material_handle,
translation: Translation::new(0.0, 0.0, 1.0),
..Default::default()
})
// light
.add_entity(LightEntity {
translation: Translation::new(4.0, -4.0, 5.0),
..Default::default()
})
// camera
.add_entity(CameraEntity {
camera: Camera::new(CameraType::Projection {
fov: std::f32::consts::PI / 4.0,
near: 1.0,
far: 1000.0,
aspect_ratio: 1.0,
}),
active_camera: ActiveCamera,
local_to_world: LocalToWorld(Mat4::look_at_rh(
Vec3::new(3.0, 8.0, 5.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
)),
});
let mut rng = StdRng::from_entropy();
for _ in 0..500 {
let spawned_material_handle = material_storage.add(StandardMaterial {
albedo: Color::rgb(
rng.gen_range(0.0, 1.0),
rng.gen_range(0.0, 1.0),
rng.gen_range(0.0, 1.0),
)
.into(),
});
builder = builder.add_entity(MeshEntity {
mesh: cube_handle,
material: spawned_material_handle,
translation: Translation::new(
rng.gen_range(-50.0, 50.0),
rng.gen_range(-50.0, 50.0),
0.0,
),
renderable: Renderable {
instanced: true,
..Default::default()
},
mesh_handle,
LocalToWorld::identity(),
translation,
)],
);
..Default::default()
})
}
builder.build();
}

172
examples/instancing_old.rs Normal file
View file

@ -0,0 +1,172 @@
use bevy::prelude::*;
use rand::{random, rngs::StdRng, Rng, SeedableRng};
struct Person;
struct Velocity {
pub value: math::Vec3,
}
struct NavigationPoint {
pub target: math::Vec3,
}
struct Wander {
pub duration_bounds: math::Vec2,
pub distance_bounds: math::Vec2,
pub duration: f32,
pub elapsed: f32,
}
fn main() {
AppBuilder::new()
.setup_world(setup)
.add_system(build_wander_system())
.add_system(build_navigate_system())
.add_system(build_move_system())
.add_system(bevy::diagnostics::build_fps_printer_system())
.run();
}
fn setup(world: &mut World, resources: &mut Resources) {
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube));
world.insert(
(),
vec![
// lights
(
Light::default(),
LocalToWorld::identity(),
Translation::new(4.0, -4.0, 5.0),
Rotation::from_euler_angles(0.0, 0.0, 0.0),
),
],
);
world.insert(
(),
vec![
// camera
(
Camera::new(CameraType::Projection {
fov: std::f32::consts::PI / 4.0,
near: 1.0,
far: 1000.0,
aspect_ratio: 1.0,
}),
ActiveCamera,
LocalToWorld(Mat4::look_at_rh(
Vec3::new(6.0, -40.0, 20.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
)),
),
],
);
let mut rng = StdRng::from_entropy();
for _ in 0..70000 {
create_person(
world,
cube_handle,
Translation::new(rng.gen_range(-50.0, 50.0), 0.0, rng.gen_range(-50.0, 50.0)),
);
}
}
fn build_wander_system() -> Box<dyn Schedulable> {
let mut rng = StdRng::from_entropy();
SystemBuilder::new("Wander")
.read_resource::<Time>()
.with_query(<(
Read<Person>,
Read<Translation>,
Write<Wander>,
Write<NavigationPoint>,
)>::query())
.build(move |_, world, time, person_query| {
for (_, translation, mut wander, mut navigation_point) in person_query.iter_mut(world) {
wander.elapsed += time.delta_seconds;
if wander.elapsed >= wander.duration {
let direction = math::vec3(
rng.gen_range(-1.0, 1.0),
rng.gen_range(-1.0, 1.0),
rng.gen_range(0.0, 0.001),
)
.normalize();
let distance =
rng.gen_range(wander.distance_bounds.x(), wander.distance_bounds.y());
navigation_point.target = translation.0 + direction * distance;
wander.elapsed = 0.0;
wander.duration =
rng.gen_range(wander.duration_bounds.x(), wander.duration_bounds.y());
}
}
})
}
fn build_navigate_system() -> Box<dyn Schedulable> {
SystemBuilder::new("Navigate")
.with_query(<(
Read<Person>,
Write<Translation>,
Write<Velocity>,
Write<NavigationPoint>,
)>::query())
.build(move |_, world, _, person_query| {
for (_, translation, mut velocity, navigation_point) in person_query.iter_mut(world) {
let distance = navigation_point.target - translation.0;
if distance.length() > 0.01 {
let direction = distance.normalize();
velocity.value = direction * 2.0;
} else {
velocity.value = math::vec3(0.0, 0.0, 0.0);
}
}
})
}
fn build_move_system() -> Box<dyn Schedulable> {
SystemBuilder::new("Move")
.read_resource::<Time>()
.with_query(<(Write<Translation>, Read<Velocity>)>::query())
.build(move |_, world, time, person_query| {
for (mut translation, velocity) in person_query.iter_mut(world) {
translation.0 += velocity.value * time.delta_seconds;
}
})
}
fn create_person(world: &mut World, mesh_handle: Handle<Mesh>, translation: Translation) {
world.insert(
(),
vec![(
Person {},
Wander {
duration_bounds: math::vec2(3.0, 10.0),
distance_bounds: math::vec2(-50.0, 50.0),
elapsed: 0.0,
duration: 0.0,
},
NavigationPoint {
target: math::vec3(0.0, 0.0, 0.0),
},
Velocity {
value: math::vec3(0.0, 0.0, 0.0),
},
StandardMaterial {
albedo: (math::vec4(0.5, 0.3, 0.3, 1.0) * random::<f32>()).into(),
},
Renderable {
instanced: true,
..Default::default()
},
mesh_handle,
LocalToWorld::identity(),
translation,
)],
);
}

View file

@ -12,7 +12,6 @@ use crate::{
render_resource::resource_name,
shader::{Shader, ShaderStages},
texture::TextureFormat,
Vertex,
},
};
@ -22,12 +21,19 @@ pub enum PipelineLayoutType {
Reflected(Option<PipelineLayout>),
}
#[derive(Clone, Debug)]
pub enum DescriptorType<T> {
Manual(T),
Reflected(Option<T>),
}
#[derive(Clone, Debug)]
pub struct PipelineDescriptor {
pub name: Option<String>,
pub draw_targets: Vec<String>,
pub layout: PipelineLayoutType,
pub shader_stages: ShaderStages,
pub reflect_vertex_buffer_descriptors: bool,
pub rasterization_state: Option<RasterizationStateDescriptor>,
/// The primitive topology used to interpret vertices.
@ -76,6 +82,7 @@ impl PipelineDescriptor {
depth_bias_slope_scale: 0.0,
depth_bias_clamp: 0.0,
}),
reflect_vertex_buffer_descriptors: true,
primitive_topology: PrimitiveTopology::TriangleList,
index_format: IndexFormat::Uint16,
sample_count: 1,
@ -169,6 +176,7 @@ impl<'a> PipelineBuilder<'a> {
mut self,
vertex_buffer_descriptor: VertexBufferDescriptor,
) -> Self {
self.pipeline.reflect_vertex_buffer_descriptors = false;
self.pipeline
.vertex_buffer_descriptors
.push(vertex_buffer_descriptor);
@ -229,7 +237,6 @@ impl<'a> PipelineBuilder<'a> {
alpha_blend: BlendDescriptor::REPLACE,
write_mask: ColorWrite::ALL,
})
.add_vertex_buffer_descriptor(Vertex::get_vertex_buffer_descriptor())
.add_draw_target(resource_name::draw_target::ASSIGNED_MESHES)
}
}

View file

@ -1,8 +1,15 @@
#version 450
layout(location = 0) in vec4 a_Pos;
layout(location = 1) in vec4 a_Normal;
layout(location = 2) in vec2 a_Uv;
layout(location = 0) in vec4 Vertex_Position;
layout(location = 1) in vec4 Vertex_Normal;
layout(location = 2) in vec2 Vertex_Uv;
# ifdef INSTANCING
layout(location = 3) in vec4 I_Object_Model_0;
layout(location = 4) in vec4 I_Object_Model_1;
layout(location = 5) in vec4 I_Object_Model_2;
layout(location = 6) in vec4 I_Object_Model_3;
# endif
layout(location = 0) out vec4 v_Position;
layout(location = 1) out vec3 v_Normal;
@ -12,13 +19,24 @@ layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
# ifndef INSTANCING
layout(set = 1, binding = 0) uniform Object {
mat4 Model;
};
# endif
void main() {
v_Normal = mat3(Model) * vec3(a_Normal.xyz);
v_Position = Model * a_Pos;
v_Uv = a_Uv;
# ifdef INSTANCING
mat4 Model = mat4(
I_Object_Model_0,
I_Object_Model_1,
I_Object_Model_2,
I_Object_Model_3
);
# endif
v_Normal = mat3(Model) * vec3(Vertex_Normal.xyz);
v_Position = Model * Vertex_Position;
v_Uv = Vertex_Uv;
gl_Position = ViewProj * v_Position;
}

View file

@ -13,7 +13,6 @@ use crate::{
render_resource::resource_name,
shader::{Shader, ShaderStage},
texture::TextureFormat,
Vertex,
},
};
pub trait ForwardPipelineBuilder {
@ -71,7 +70,6 @@ impl ForwardPipelineBuilder for RenderGraphBuilder {
},
write_mask: ColorWrite::ALL,
})
.add_vertex_buffer_descriptor(Vertex::get_vertex_buffer_descriptor())
.add_draw_target(resource_name::draw_target::ASSIGNED_MESHES)
.finish(),
)

View file

@ -13,7 +13,6 @@ use crate::{
render_resource::resource_name,
shader::{Shader, ShaderStage},
texture::TextureFormat,
Vertex,
},
};
@ -64,7 +63,6 @@ impl ForwardFlatPipelineBuilder for RenderGraphBuilder {
alpha_blend: BlendDescriptor::REPLACE,
write_mask: ColorWrite::ALL,
})
.add_vertex_buffer_descriptor(Vertex::get_vertex_buffer_descriptor())
.add_draw_target(resource_name::draw_target::MESHES)
.finish(),
)

View file

@ -6,15 +6,12 @@ use crate::{
BlendDescriptor, BlendFactor, BlendOperation, ColorStateDescriptor, ColorWrite,
CompareFunction, CullMode, DepthStencilStateDescriptor, FrontFace,
RasterizationStateDescriptor, StencilStateFaceDescriptor,
},
InputStepMode, PipelineDescriptor, VertexAttributeDescriptor, VertexBufferDescriptor,
VertexFormat,
}, PipelineDescriptor,
},
render_graph::RenderGraphBuilder,
render_resource::{resource_name, resource_providers::RectData},
render_resource::{resource_name},
shader::{Shader, ShaderStage},
texture::TextureFormat,
Vertex,
},
};
pub trait UiPipelineBuilder {
@ -72,33 +69,6 @@ impl UiPipelineBuilder for RenderGraphBuilder {
},
write_mask: ColorWrite::ALL,
})
.add_vertex_buffer_descriptor(Vertex::get_vertex_buffer_descriptor())
.add_vertex_buffer_descriptor(VertexBufferDescriptor {
stride: std::mem::size_of::<RectData>() as u64,
step_mode: InputStepMode::Instance,
attributes: vec![
VertexAttributeDescriptor {
format: VertexFormat::Float2,
offset: 0,
shader_location: 3,
},
VertexAttributeDescriptor {
format: VertexFormat::Float2,
offset: 2 * 4,
shader_location: 4,
},
VertexAttributeDescriptor {
format: VertexFormat::Float4,
offset: 4 * 4,
shader_location: 5,
},
VertexAttributeDescriptor {
format: VertexFormat::Float,
offset: 8 * 4,
shader_location: 6,
},
],
})
.add_draw_target(resource_name::draw_target::UI)
.finish(),
)

View file

@ -1,15 +1,13 @@
#version 450
// vertex attributes
layout(location = 0) in vec4 a_Pos;
layout(location = 1) in vec4 a_Normal;
layout(location = 2) in vec2 a_Uv;
layout(location = 0) in vec4 Vertex_Position;
layout(location = 1) in vec4 Vertex_Normal;
layout(location = 2) in vec2 Vertex_Uv;
// instanced attributes (RectData)
layout (location = 3) in vec2 a_RectPosition;
layout (location = 4) in vec2 a_RectSize;
layout (location = 5) in vec4 a_RectColor;
layout (location = 6) in float a_RectZIndex;
layout (location = 3) in vec2 I_Rect_Position;
layout (location = 4) in vec2 I_Rect_Size;
layout (location = 5) in vec4 I_Rect_Color;
layout (location = 6) in float I_Rect_ZIndex;
layout(location = 0) out vec4 v_Color;
@ -18,8 +16,8 @@ layout(set = 0, binding = 0) uniform Camera2d {
};
void main() {
v_Color = a_RectColor;
vec4 position = a_Pos * vec4(a_RectSize, 0.0, 1.0);
position = position + vec4(a_RectPosition + a_RectSize / 2.0, -a_RectZIndex, 0.0);
v_Color = I_Rect_Color;
vec4 position = Vertex_Position * vec4(I_Rect_Size, 0.0, 1.0);
position = position + vec4(I_Rect_Position + I_Rect_Size / 2.0, -I_Rect_ZIndex, 0.0);
gl_Position = ViewProj * position;
}

View file

@ -1,5 +1,6 @@
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct VertexBufferDescriptor {
pub name: String,
pub stride: u64,
pub step_mode: InputStepMode,
pub attributes: Vec<VertexAttributeDescriptor>,
@ -39,14 +40,52 @@ pub enum VertexFormat {
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,
Instance = 1,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct VertexAttributeDescriptor {
pub name: String,
pub offset: u64,
pub format: VertexFormat,
pub shader_location: u32,

View file

@ -16,6 +16,15 @@ pub struct Renderable {
pub instanced: bool,
}
impl Renderable {
pub fn instanced() -> Self {
Renderable {
instanced: false,
..Default::default()
}
}
}
impl Default for Renderable {
fn default() -> Self {
Renderable {
@ -116,7 +125,12 @@ pub fn update_shader_assignments(
// reset assignments so they are updated every frame
shader_pipeline_assignments.assignments = HashMap::new();
for (entity, renderable) in <Read<Renderable>>::query().iter_entities(world) {
for (entity, mut renderable) in <Write<Renderable>>::query().iter_entities_mut(world) {
// if instancing is enabled, set the def here
if renderable.instanced {
renderable.shader_defs.insert("INSTANCING".to_string());
}
for pipeline_handle in renderable.pipelines.iter() {
if let None = compiled_shader_map
.pipeline_to_macro_pipelines

View file

@ -7,7 +7,9 @@ use crate::{
PassDescriptor, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor,
},
pipeline::{BindType, PipelineDescriptor, PipelineLayout, PipelineLayoutType},
pipeline::{
BindType, PipelineDescriptor, PipelineLayout, PipelineLayoutType,
},
render_graph::RenderGraph,
render_resource::{
resource_name, BufferUsage, RenderResource, RenderResources, ResourceInfo,
@ -161,8 +163,19 @@ impl WgpuRenderer {
bind_group_layouts: bind_group_layouts.as_slice(),
});
let owned_vertex_buffer_descriptors = pipeline_descriptor
.vertex_buffer_descriptors
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>>();

View file

@ -1,14 +1,18 @@
use crate::render::{
pipeline::{BindGroup, BindType, Binding, UniformProperty, UniformPropertyType},
pipeline::{
BindGroup, BindType, Binding, InputStepMode, UniformProperty, UniformPropertyType,
VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat,
},
texture::TextureViewDimension,
};
use spirv_reflect::{
types::{
ReflectDescriptorBinding, ReflectDescriptorSet, ReflectDescriptorType, ReflectDimension,
ReflectTypeDescription, ReflectTypeFlags,
ReflectInterfaceVariable, ReflectTypeDescription, ReflectTypeFlags,
},
ShaderModule,
};
use std::collections::HashSet;
use zerocopy::AsBytes;
// use rspirv::{binary::Parser, dr::Loader, lift::LiftContext};
@ -27,6 +31,7 @@ use zerocopy::AsBytes;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ShaderLayout {
pub bind_groups: Vec<BindGroup>,
pub vertex_buffer_descriptors: Vec<VertexBufferDescriptor>,
pub entry_point: String,
}
@ -41,8 +46,80 @@ impl ShaderLayout {
bind_groups.push(bind_group);
}
let mut vertex_attribute_descriptors = Vec::new();
for input_variable in module.enumerate_input_variables(None).unwrap() {
let vertex_attribute_descriptor =
reflect_vertex_attribute_descriptor(&input_variable);
vertex_attribute_descriptors.push(vertex_attribute_descriptor);
}
vertex_attribute_descriptors
.sort_by(|a, b| a.shader_location.cmp(&b.shader_location));
let mut visited_buffer_descriptors = HashSet::new();
let mut vertex_buffer_descriptors = Vec::new();
let mut current_descriptor: Option<VertexBufferDescriptor> = None;
for vertex_attribute_descriptor in vertex_attribute_descriptors.drain(..) {
let mut instance = false;
let current_buffer_name = {
let parts = vertex_attribute_descriptor
.name
.splitn(3, "_")
.collect::<Vec<&str>>();
if parts.len() == 3 {
if parts[0] == "I" {
instance = true;
parts[1].to_string()
} else {
parts[0].to_string()
}
} else if parts.len() == 2 {
parts[0].to_string()
} else {
panic!("Vertex attributes must follow the form BUFFERNAME_PROPERTYNAME. For example: Vertex_Position");
}
};
if let Some(current) = current_descriptor.as_mut() {
if &current.name == &current_buffer_name {
current.attributes.push(vertex_attribute_descriptor);
continue;
} else {
if visited_buffer_descriptors.contains(&current_buffer_name) {
panic!("Vertex attribute buffer names must be consecutive.")
}
}
}
if let Some(current) = current_descriptor.take() {
visited_buffer_descriptors.insert(current.name.to_string());
vertex_buffer_descriptors.push(current);
}
current_descriptor = Some(VertexBufferDescriptor {
attributes: vec![vertex_attribute_descriptor],
name: current_buffer_name,
step_mode: if instance {
InputStepMode::Instance
} else {
InputStepMode::Vertex
},
stride: 0,
})
}
if let Some(current) = current_descriptor.take() {
visited_buffer_descriptors.insert(current.name.to_string());
vertex_buffer_descriptors.push(current);
}
for vertex_buffer_descriptor in vertex_buffer_descriptors.iter_mut() {
calculate_offsets(vertex_buffer_descriptor);
}
ShaderLayout {
bind_groups,
vertex_buffer_descriptors,
entry_point: entry_point_name,
}
}
@ -51,6 +128,27 @@ impl ShaderLayout {
}
}
fn calculate_offsets(vertex_buffer_descriptor: &mut VertexBufferDescriptor) {
let mut offset = 0;
for attribute in vertex_buffer_descriptor.attributes.iter_mut() {
attribute.offset = offset;
offset += attribute.format.get_size();
}
vertex_buffer_descriptor.stride = offset;
}
fn reflect_vertex_attribute_descriptor(
input_variable: &ReflectInterfaceVariable,
) -> VertexAttributeDescriptor {
VertexAttributeDescriptor {
name: input_variable.name.clone(),
format: reflect_vertex_format(input_variable.type_description.as_ref().unwrap()),
offset: 0,
shader_location: input_variable.location,
}
}
fn reflect_bind_group(descriptor_set: &ReflectDescriptorSet) -> BindGroup {
let mut bindings = Vec::new();
for descriptor_binding in descriptor_set.bindings.iter() {
@ -180,6 +278,55 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform
}
}
fn reflect_vertex_format(type_description: &ReflectTypeDescription) -> VertexFormat {
let traits = &type_description.traits;
let number_type = if type_description.type_flags.contains(ReflectTypeFlags::INT) {
match traits.numeric.scalar.signedness {
0 => NumberType::UInt,
1 => NumberType::Int,
signedness => panic!("unexpected signedness {}", signedness),
}
} else if type_description
.type_flags
.contains(ReflectTypeFlags::FLOAT)
{
NumberType::Float
} else {
panic!("unexpected type flag {:?}", type_description.type_flags);
};
let width = traits.numeric.scalar.width;
match (number_type, traits.numeric.vector.component_count, width) {
(NumberType::UInt, 2, 8) => VertexFormat::Uchar2,
(NumberType::UInt, 4, 8) => VertexFormat::Uchar4,
(NumberType::Int, 2, 8) => VertexFormat::Char2,
(NumberType::Int, 4, 8) => VertexFormat::Char4,
(NumberType::UInt, 2, 16) => VertexFormat::Ushort2,
(NumberType::UInt, 4, 16) => VertexFormat::Ushort4,
(NumberType::Int, 2, 16) => VertexFormat::Short2,
(NumberType::Int, 8, 16) => VertexFormat::Short4,
(NumberType::Float, 2, 16) => VertexFormat::Half2,
(NumberType::Float, 4, 16) => VertexFormat::Half4,
(NumberType::Float, 0, 32) => VertexFormat::Float,
(NumberType::Float, 2, 32) => VertexFormat::Float2,
(NumberType::Float, 3, 32) => VertexFormat::Float3,
(NumberType::Float, 4, 32) => VertexFormat::Float4,
(NumberType::UInt, 0, 32) => VertexFormat::Uint,
(NumberType::UInt, 2, 32) => VertexFormat::Uint2,
(NumberType::UInt, 3, 32) => VertexFormat::Uint3,
(NumberType::UInt, 4, 32) => VertexFormat::Uint4,
(NumberType::Int, 0, 32) => VertexFormat::Int,
(NumberType::Int, 2, 32) => VertexFormat::Int2,
(NumberType::Int, 3, 32) => VertexFormat::Int3,
(NumberType::Int, 4, 32) => VertexFormat::Int4,
(number_type, component_count, width) => panic!(
"unexpected uniform property format {:?} {} {}",
number_type, component_count, width
),
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -191,7 +338,10 @@ mod tests {
ShaderStage::Vertex,
r#"
#version 450
layout(location = 0) in vec4 a_Pos;
layout(location = 0) in vec4 Vertex_Position;
layout(location = 1) in uvec4 Vertex_Normal;
layout(location = 2) in uvec4 I_TestInstancing_Property;
layout(location = 0) out vec4 v_Position;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
@ -199,7 +349,7 @@ mod tests {
layout(set = 1, binding = 0) uniform texture2D Texture;
void main() {
v_Position = a_Pos;
v_Position = Vertex_Position;
gl_Position = ViewProj * v_Position;
}
"#,
@ -211,6 +361,40 @@ mod tests {
layout,
ShaderLayout {
entry_point: "main".to_string(),
vertex_buffer_descriptors: vec![
VertexBufferDescriptor {
name: "Vertex".to_string(),
attributes: vec![
VertexAttributeDescriptor {
name: "Vertex_Position".to_string(),
format: VertexFormat::Float4,
offset: 0,
shader_location: 0,
},
VertexAttributeDescriptor {
name: "Vertex_Normal".to_string(),
format: VertexFormat::Uint4,
offset: 16,
shader_location: 1,
}
],
step_mode: InputStepMode::Vertex,
stride: 32,
},
VertexBufferDescriptor {
name: "TestInstancing".to_string(),
attributes: vec![
VertexAttributeDescriptor {
name: "I_TestInstancing_Property".to_string(),
format: VertexFormat::Uint4,
offset: 0,
shader_location: 2,
},
],
step_mode: InputStepMode::Instance,
stride: 16,
}
],
bind_groups: vec![
BindGroup::new(
0,
@ -246,4 +430,32 @@ mod tests {
}
);
}
#[test]
#[should_panic(expected = "Vertex attribute buffer names must be consecutive.")]
fn test_reflection_consecutive_buffer_validation() {
let vertex_shader = Shader::from_glsl(
ShaderStage::Vertex,
r#"
#version 450
layout(location = 0) in vec4 Vertex_Position;
layout(location = 1) in uvec4 Other_Property;
layout(location = 2) in uvec4 Vertex_Normal;
layout(location = 0) out vec4 v_Position;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 0) uniform texture2D Texture;
void main() {
v_Position = Vertex_Position;
gl_Position = ViewProj * v_Position;
}
"#,
)
.get_spirv_shader(None);
let _layout = vertex_shader.reflect_layout().unwrap();
}
}

View file

@ -13,7 +13,7 @@ const LOCAL_TO_WORLD_FIELD_INFOS: &[FieldInfo] = &[FieldInfo {
uniform_name: "Object",
texture_name: "",
sampler_name: "",
is_instanceable: false,
is_instanceable: true,
}];
impl AsUniforms for bevy_transform::prelude::LocalToWorld {

View file

@ -1,5 +1,3 @@
use super::pipeline::{InputStepMode, VertexBufferDescriptor, VertexFormat};
use crate::render::pipeline::VertexAttributeDescriptor;
use std::convert::From;
use zerocopy::{AsBytes, FromBytes};
@ -11,32 +9,6 @@ pub struct Vertex {
pub uv: [f32; 2],
}
impl Vertex {
pub fn get_vertex_buffer_descriptor() -> VertexBufferDescriptor {
VertexBufferDescriptor {
stride: std::mem::size_of::<Vertex>() as u64,
step_mode: InputStepMode::Vertex,
attributes: vec![
VertexAttributeDescriptor {
format: VertexFormat::Float4,
offset: 0,
shader_location: 0,
},
VertexAttributeDescriptor {
format: VertexFormat::Float4,
offset: 4 * 4,
shader_location: 1,
},
VertexAttributeDescriptor {
format: VertexFormat::Float2,
offset: 8 * 4,
shader_location: 2,
},
],
}
}
}
impl From<([f32; 4], [f32; 4], [f32; 2])> for Vertex {
fn from((position, normal, uv): ([f32; 4], [f32; 4], [f32; 2])) -> Self {
Vertex {