Shader reflection works for everything but dynamic uniforms

This commit is contained in:
Carter Anderson 2020-02-17 14:12:10 -08:00
parent c29a6f7dd2
commit 2fe9710c04
10 changed files with 289 additions and 163 deletions

8
.vscode/launch.json vendored
View file

@ -30,11 +30,11 @@
"cargo": {
"args": [
"build",
"--example=simple_new_graph",
"--example=simple_new",
"--package=bevy"
],
"filter": {
"name": "simple_new_graph",
"name": "simple_new",
"kind": "example"
}
},
@ -48,12 +48,12 @@
"cargo": {
"args": [
"run",
"--example=simple",
"--example=simple_new",
"--package=bevy",
"--release"
],
"filter": {
"name": "simple",
"name": "simple_new",
"kind": "example"
}
},

View file

@ -14,6 +14,9 @@ Here is the current list of planned features. All items are sorted in approximat
* Add runtime type safety to uniform bindings (and maybe compile time)
* Dynamic / user defined shaders
* consider using shaderc-rs. but this introduces compile complexity and requires other C++ build systems
* Error Handling
* Custom error type?
* Remove as many panics / unwraps as possible
* Input
* Keyboard and mouse events
* Gamepad events

View file

@ -20,10 +20,16 @@ impl<'a> Into<wgpu::VertexBufferDescriptor<'a>> for &'a VertexBufferDescriptor {
}
}
#[derive(Clone, Debug)]
pub enum PipelineLayoutType {
Manual(PipelineLayout),
Reflected(Option<PipelineLayout>),
}
#[derive(Clone, Debug)]
pub struct PipelineDescriptor {
pub draw_targets: Vec<String>,
pub pipeline_layout: PipelineLayout,
pub layout: PipelineLayoutType,
pub shader_stages: ShaderStages,
pub rasterization_state: Option<wgpu::RasterizationStateDescriptor>,
@ -59,7 +65,7 @@ pub struct PipelineDescriptor {
impl PipelineDescriptor {
fn new(vertex_shader: Handle<Shader>) -> Self {
PipelineDescriptor {
pipeline_layout: PipelineLayout::new(),
layout: PipelineLayoutType::Reflected(None),
color_states: Vec::new(),
depth_stencil_state: None,
draw_targets: Vec::new(),
@ -79,6 +85,20 @@ impl PipelineDescriptor {
alpha_to_coverage_enabled: false,
}
}
pub fn get_layout(&self) -> Option<&PipelineLayout> {
match self.layout {
PipelineLayoutType::Reflected(ref layout) => layout.as_ref(),
PipelineLayoutType::Manual(ref layout) => Some(layout),
}
}
pub fn get_layout_mut(&mut self) -> Option<&mut PipelineLayout> {
match self.layout {
PipelineLayoutType::Reflected(ref mut layout) => layout.as_mut(),
PipelineLayoutType::Manual(ref mut layout) => Some(layout),
}
}
}
impl PipelineDescriptor {
@ -128,7 +148,14 @@ impl<'a> PipelineBuilder<'a> {
}
pub fn add_bind_group(mut self, bind_group: BindGroup) -> Self {
self.pipeline.pipeline_layout.bind_groups.push(bind_group);
if let PipelineLayoutType::Reflected(_) = self.pipeline.layout {
self.pipeline.layout = PipelineLayoutType::Manual(PipelineLayout::new());
}
if let PipelineLayoutType::Manual(ref mut layout) = self.pipeline.layout {
layout.bind_groups.push(bind_group);
}
self
}

View file

@ -1,5 +1,6 @@
use crate::render::shader_reflect::ShaderLayout;
use std::{
collections::hash_map::DefaultHasher,
collections::{HashMap, hash_map::DefaultHasher, BTreeSet},
hash::{Hash, Hasher},
};
@ -14,23 +15,61 @@ impl PipelineLayout {
bind_groups: Vec::new(),
}
}
pub fn from_shader_layouts(shader_layouts: &mut [ShaderLayout]) -> Self {
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());
}
}
}
}
PipelineLayout {
bind_groups: bind_groups.drain().map(|(_, value)| value).collect()
}
}
}
#[derive(Hash, Clone, Debug)]
#[derive(Clone, Debug)]
pub struct BindGroup {
pub bindings: Vec<Binding>,
pub index: u32,
pub bindings: BTreeSet<Binding>,
hash: Option<u64>,
}
impl BindGroup {
pub fn new(bindings: Vec<Binding>) -> Self {
pub fn new(index: u32, bindings: Vec<Binding>) -> Self {
BindGroup {
bindings,
index,
bindings: bindings.iter().cloned().collect(),
hash: None,
}
}
pub fn get_hash(&self) -> u64 {
pub fn get_hash(&self) -> Option<u64> {
self.hash
}
pub fn get_or_update_hash(&mut self) -> u64 {
if self.hash.is_none() {
self.update_hash();
}
self.hash.unwrap()
}
@ -41,14 +80,22 @@ impl BindGroup {
}
}
#[derive(Hash, Clone, Debug)]
impl Hash for BindGroup {
fn hash<H: Hasher>(&self, state: &mut H) {
self.index.hash(state);
self.bindings.hash(state);
}
}
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct Binding {
pub name: String,
pub index: u32,
pub bind_type: BindType,
// TODO: ADD SHADER STAGE VISIBILITY
}
#[derive(Hash, Clone, Debug)]
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum BindType {
Uniform {
dynamic: bool,
@ -81,13 +128,13 @@ impl BindType {
}
}
#[derive(Hash, Clone, Debug)]
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct UniformProperty {
pub name: String,
pub property_type: UniformPropertyType,
}
#[derive(Hash, Clone, Debug)]
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum UniformPropertyType {
// TODO: Add all types here
Int,
@ -95,6 +142,7 @@ pub enum UniformPropertyType {
UVec4,
Vec3,
Vec4,
Mat3,
Mat4,
Struct(Vec<UniformProperty>),
Array(Box<UniformPropertyType>, usize),
@ -108,6 +156,7 @@ impl UniformPropertyType {
UniformPropertyType::UVec4 => 4 * 4,
UniformPropertyType::Vec3 => 4 * 3,
UniformPropertyType::Vec4 => 4 * 4,
UniformPropertyType::Mat3 => 4 * 4 * 3,
UniformPropertyType::Mat4 => 4 * 4 * 4,
UniformPropertyType::Struct(properties) => properties
.iter()
@ -118,7 +167,7 @@ impl UniformPropertyType {
}
}
#[derive(Copy, Clone, Debug, Hash)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum TextureViewDimension {
D1,
D2,

View file

@ -21,72 +21,76 @@ impl ForwardPipelineBuilder for RenderGraphBuilder {
include_str!("forward.frag"),
ShaderStage::Fragment,
))
.add_bind_group(BindGroup::new(vec![
Binding {
name: "Camera".to_string(),
bind_type: BindType::Uniform {
dynamic: false,
properties: vec![UniformProperty {
name: "ViewProj".to_string(),
property_type: UniformPropertyType::Mat4,
}],
},
},
Binding {
name: "Lights".to_string(),
bind_type: BindType::Uniform {
dynamic: false,
properties: vec![
UniformProperty {
name: "NumLights".to_string(),
property_type: UniformPropertyType::UVec4,
},
UniformProperty {
name: "SceneLights".to_string(),
property_type: UniformPropertyType::Array(
Box::new(UniformPropertyType::Struct(vec![
UniformProperty {
name: "proj".to_string(),
property_type: UniformPropertyType::Mat4,
},
UniformProperty {
name: "pos".to_string(),
property_type: UniformPropertyType::Vec4,
},
UniformProperty {
name: "color".to_string(),
property_type: UniformPropertyType::Vec4,
},
])),
10, // max lights
),
},
],
},
},
]))
.add_bind_group(BindGroup::new(vec![
Binding {
name: "Object".to_string(),
bind_type: BindType::Uniform {
dynamic: true,
properties: vec![UniformProperty {
name: "Model".to_string(),
property_type: UniformPropertyType::Mat4,
}],
},
},
Binding {
name: "StandardMaterial_albedo".to_string(),
bind_type: BindType::Uniform {
dynamic: true,
properties: vec![UniformProperty {
name: "Albedo".to_string(),
property_type: UniformPropertyType::Vec4,
}],
},
},
]))
// .add_bind_group(BindGroup::new(0, vec![
// Binding {
// index: 0,
// name: "Camera".to_string(),
// bind_type: BindType::Uniform {
// dynamic: false,
// properties: vec![UniformProperty {
// name: "ViewProj".to_string(),
// property_type: UniformPropertyType::Mat4,
// }],
// },
// },
// Binding {
// index: 1,
// name: "Lights".to_string(),
// bind_type: BindType::Uniform {
// dynamic: false,
// properties: vec![
// UniformProperty {
// name: "NumLights".to_string(),
// property_type: UniformPropertyType::UVec4,
// },
// UniformProperty {
// name: "SceneLights".to_string(),
// property_type: UniformPropertyType::Array(
// Box::new(UniformPropertyType::Struct(vec![
// UniformProperty {
// name: "proj".to_string(),
// property_type: UniformPropertyType::Mat4,
// },
// UniformProperty {
// name: "pos".to_string(),
// property_type: UniformPropertyType::Vec4,
// },
// UniformProperty {
// name: "color".to_string(),
// property_type: UniformPropertyType::Vec4,
// },
// ])),
// 10, // max lights
// ),
// },
// ],
// },
// },
// ]))
// .add_bind_group(BindGroup::new(1, vec![
// Binding {
// index: 0,
// name: "Object".to_string(),
// bind_type: BindType::Uniform {
// dynamic: true,
// properties: vec![UniformProperty {
// name: "Model".to_string(),
// property_type: UniformPropertyType::Mat4,
// }],
// },
// },
// Binding {
// index: 1,
// name: "StandardMaterial_albedo".to_string(),
// bind_type: BindType::Uniform {
// dynamic: true,
// properties: vec![UniformProperty {
// name: "Albedo".to_string(),
// property_type: UniformPropertyType::Vec4,
// }],
// },
// },
// ]))
.with_rasterization_state(wgpu::RasterizationStateDescriptor {
front_face: wgpu::FrontFace::Ccw,
cull_mode: wgpu::CullMode::Back,

View file

@ -34,7 +34,8 @@ impl ForwardFlatPipelineBuilder for RenderGraphBuilder {
include_str!("forward_flat.frag"),
ShaderStage::Fragment,
))
.add_bind_group(BindGroup::new(vec![Binding {
.add_bind_group(BindGroup::new(0, vec![Binding {
index: 0,
name: "Camera".to_string(),
bind_type: BindType::Uniform {
dynamic: false,
@ -44,8 +45,9 @@ impl ForwardFlatPipelineBuilder for RenderGraphBuilder {
}],
},
}]))
.add_bind_group(BindGroup::new(vec![
.add_bind_group(BindGroup::new(1, vec![
Binding {
index: 0,
name: "Object".to_string(),
bind_type: BindType::Uniform {
dynamic: true,
@ -56,6 +58,7 @@ impl ForwardFlatPipelineBuilder for RenderGraphBuilder {
},
},
Binding {
index: 1,
name: "StandardMaterial_albedo".to_string(),
bind_type: BindType::Uniform {
dynamic: true,

View file

@ -33,7 +33,8 @@ impl UiPipelineBuilder for RenderGraphBuilder {
include_str!("ui.frag"),
ShaderStage::Fragment,
))
.add_bind_group(BindGroup::new(vec![Binding {
.add_bind_group(BindGroup::new(0, vec![Binding {
index: 0,
name: "Camera2d".to_string(),
bind_type: BindType::Uniform {
dynamic: false,

View file

@ -4,9 +4,9 @@ use crate::{
render::{
render_graph_2::{
resource_name, update_shader_assignments, BindGroup, BindType,
DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, RenderGraph, RenderPass,
RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor,
Renderer, ResourceInfo, TextureDescriptor,
DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, PipelineLayout,
PipelineLayoutType, RenderGraph, RenderPass, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor, Renderer, ResourceInfo, TextureDescriptor,
},
Shader,
},
@ -76,25 +76,37 @@ impl WgpuRenderer {
vertex_shader: &Shader,
fragment_shader: Option<&Shader>,
) -> wgpu::RenderPipeline {
let vertex_shader_module = Self::create_shader_module(device, vertex_shader, None);
let vertex_spirv = vertex_shader.get_spirv_shader(None);
let fragment_spirv = fragment_shader.map(|f| f.get_spirv_shader(None));
let vertex_shader_module = Self::create_shader_module(device, &vertex_spirv, None);
let fragment_shader_module = match fragment_shader {
Some(fragment_shader) => {
Some(Self::create_shader_module(device, fragment_shader, None))
}
Some(fragment_spirv) => Some(Self::create_shader_module(device, fragment_spirv, None)),
None => None,
};
if let PipelineLayoutType::Reflected(None) = pipeline_descriptor.layout {
let mut layouts = vec![vertex_spirv.reflect_layout().unwrap()];
if let Some(ref fragment_spirv) = fragment_spirv {
layouts.push(fragment_spirv.reflect_layout().unwrap());
}
pipeline_descriptor.layout =
PipelineLayoutType::Reflected(Some(PipelineLayout::from_shader_layouts(&mut layouts)));
}
let layout = pipeline_descriptor.get_layout_mut().unwrap();
// setup new bind group layouts
for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter_mut() {
bind_group.update_hash();
let bind_group_id = bind_group.get_hash();
for bind_group in layout.bind_groups.iter_mut() {
let bind_group_id = bind_group.get_or_update_hash();
if let None = bind_group_layouts.get(&bind_group_id) {
let bind_group_layout_binding = bind_group
.bindings
.iter()
.enumerate()
.map(|(i, binding)| wgpu::BindGroupLayoutBinding {
binding: i as u32,
.map(|binding| wgpu::BindGroupLayoutBinding {
binding: binding.index,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: (&binding.bind_type).into(),
})
@ -109,12 +121,11 @@ impl WgpuRenderer {
}
// collect bind group layout references
let bind_group_layouts = pipeline_descriptor
.pipeline_layout
let bind_group_layouts = layout
.bind_groups
.iter()
.map(|bind_group| {
let bind_group_id = bind_group.get_hash();
let bind_group_id = bind_group.get_hash().unwrap();
bind_group_layouts.get(&bind_group_id).unwrap()
})
.collect::<Vec<&wgpu::BindGroupLayout>>();
@ -127,11 +138,11 @@ impl WgpuRenderer {
layout: &pipeline_layout,
vertex_stage: wgpu::ProgrammableStageDescriptor {
module: &vertex_shader_module,
entry_point: &vertex_shader.entry_point,
entry_point: "main",
},
fragment_stage: match fragment_shader {
Some(fragment_shader) => Some(wgpu::ProgrammableStageDescriptor {
entry_point: &fragment_shader.entry_point,
entry_point: "main",
module: fragment_shader_module.as_ref().unwrap(),
}),
None => None,
@ -233,7 +244,7 @@ impl WgpuRenderer {
// TODO: consider moving this to a resource provider
fn setup_bind_group(&mut self, bind_group: &BindGroup) -> u64 {
let bind_group_id = bind_group.get_hash();
let bind_group_id = bind_group.get_hash().unwrap();
if let None = self.bind_groups.get(&bind_group_id) {
let mut unset_uniforms = Vec::new();
@ -260,12 +271,11 @@ impl WgpuRenderer {
let bindings = bind_group
.bindings
.iter()
.enumerate()
.map(|(i, b)| {
let resource_info = self.resource_info.get(&b.name).unwrap();
.map(|binding| {
let resource_info = self.resource_info.get(&binding.name).unwrap();
wgpu::Binding {
binding: i as u32,
resource: match &b.bind_type {
binding: binding.index,
resource: match &binding.bind_type {
BindType::Uniform {
dynamic: _,
properties: _,
@ -275,7 +285,7 @@ impl WgpuRenderer {
buffer_usage: _,
} = resource_info
{
let buffer = self.buffers.get(&b.name).unwrap();
let buffer = self.buffers.get(&binding.name).unwrap();
wgpu::BindingResource::Buffer {
buffer,
range: 0..*size,
@ -426,7 +436,8 @@ impl Renderer for WgpuRenderer {
}
// create bind groups
for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter() {
let pipeline_layout = pipeline_descriptor.get_layout().unwrap();
for bind_group in pipeline_layout.bind_groups.iter() {
self.setup_bind_group(bind_group);
}
}
@ -641,14 +652,9 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
}
fn setup_bind_groups(&mut self, entity: Option<&Entity>) {
for (i, bind_group) in self
.pipeline_descriptor
.pipeline_layout
.bind_groups
.iter()
.enumerate()
{
let bind_group_id = bind_group.get_hash();
let pipeline_layout = self.pipeline_descriptor.get_layout().unwrap();
for bind_group in pipeline_layout.bind_groups.iter() {
let bind_group_id = bind_group.get_hash().unwrap();
let bind_group_info = self.renderer.bind_groups.get(&bind_group_id).unwrap();
let mut dynamic_uniform_indices = Vec::new();
@ -658,7 +664,7 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
continue;
}
// PERF: This hashmap get is pretty expensive (10 fps per 10000 entities)
// PERF: This hashmap get is pretty expensive (10 fps for 10000 entities)
if let Some(dynamic_uniform_buffer_info) =
self.renderer.dynamic_uniform_buffer_info.get(&binding.name)
{
@ -674,7 +680,7 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
// TODO: check to see if bind group is already set
self.render_pass.set_bind_group(
i as u32,
bind_group.index,
&bind_group_info.bind_group,
dynamic_uniform_indices.as_slice(),
);

View file

@ -1,4 +1,7 @@
use crate::{asset::Handle, render::shader_reflect::get_shader_layout};
use crate::{
asset::Handle,
render::shader_reflect::{get_shader_layout, ShaderLayout},
};
use std::marker::Copy;
#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
@ -50,11 +53,10 @@ pub enum ShaderSource {
Glsl(String),
}
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Clone, Debug)]
pub struct Shader {
pub source: ShaderSource,
pub stage: ShaderStage,
pub entry_point: String,
// TODO: add "precompile" flag?
}
@ -62,29 +64,31 @@ impl Shader {
pub fn from_glsl(glsl: &str, stage: ShaderStage) -> Shader {
Shader {
source: ShaderSource::Glsl(glsl.to_string()),
entry_point: "main".to_string(),
stage,
}
}
pub fn get_spirv(&self, macros: Option<&[String]>) -> Vec<u32> {
let result = match self.source {
match self.source {
ShaderSource::Spirv(ref bytes) => bytes.clone(),
ShaderSource::Glsl(ref source) => glsl_to_spirv(&source, self.stage, macros),
};
get_shader_layout(&result);
result
}
}
pub fn get_spirv_shader(&self, macros: Option<&[String]>) -> Shader {
Shader {
source: ShaderSource::Spirv(self.get_spirv(macros)),
entry_point: self.entry_point.clone(),
stage: self.stage,
}
}
pub fn reflect_layout(&self) -> Option<ShaderLayout> {
if let ShaderSource::Spirv(ref spirv) = self.source {
Some(get_shader_layout(spirv.as_slice()))
} else {
panic!("Cannot reflect layout of non-SpirV shader. Try compiling this shader to SpirV first using self.get_spirv_shader()");
}
}
}
#[derive(Clone, Debug)]

View file

@ -1,12 +1,17 @@
use crate::render::render_graph_2::{BindGroup, UniformPropertyType, Binding, BindType, UniformProperty};
use crate::render::render_graph_2::{
BindGroup, BindType, Binding, UniformProperty, UniformPropertyType,
};
use spirv_reflect::{
types::{ReflectDescriptorSet, ReflectTypeDescription, ReflectDescriptorBinding, ReflectDescriptorType, ReflectTypeFlags},
types::{
ReflectDescriptorBinding, ReflectDescriptorSet, ReflectDescriptorType,
ReflectTypeDescription, ReflectTypeFlags,
},
ShaderModule,
};
use zerocopy::AsBytes;
// use rspirv::{binary::Parser, dr::Loader, lift::LiftContext};
// TODO: pick rspirv vs spirv-reflect
// TODO: use rspirv when structured representation is ready. this way we can remove spirv_reflect, which is a non-rust dependency
// pub fn get_shader_layout(spirv_data: &[u32]) {
// let mut loader = Loader::new(); // You can use your own consumer here.
// {
@ -18,37 +23,39 @@ use zerocopy::AsBytes;
// println!("{:?}", structured.types);
// }
pub fn get_shader_layout(spirv_data: &[u32]) {
#[derive(Debug, Clone)]
pub struct ShaderLayout {
pub bind_groups: Vec<BindGroup>,
pub entry_point: String,
}
pub fn get_shader_layout(spirv_data: &[u32]) -> ShaderLayout {
match ShaderModule::load_u8_data(spirv_data.as_bytes()) {
Ok(ref mut module) => {
let entry_point_name = module.get_entry_point_name();
let shader_stage = module.get_shader_stage();
println!("entry point: {}", entry_point_name);
println!("shader stage: {:?}", shader_stage);
let mut bind_groups = Vec::new();
for descriptor_set in module.enumerate_descriptor_sets(None).unwrap() {
let bind_group = reflect_bind_group(&descriptor_set);
bind_groups.push(bind_group);
}
println!(" result {:?}", &bind_groups);
println!();
ShaderLayout {
bind_groups,
entry_point: entry_point_name,
}
}
_ => {}
Err(err) => panic!("Failed to reflect shader layout: {:?}", err)
}
}
fn reflect_bind_group(descriptor_set: &ReflectDescriptorSet) -> BindGroup {
println!(" set {}", descriptor_set.set);
let mut bindings = Vec::new();
for descriptor_binding in descriptor_set.bindings.iter() {
let binding = reflect_binding(descriptor_binding);
bindings.push(binding);
}
BindGroup::new(bindings)
BindGroup::new(descriptor_set.set, bindings)
}
fn reflect_binding(binding: &ReflectDescriptorBinding) -> Binding {
@ -61,10 +68,10 @@ fn reflect_binding(binding: &ReflectDescriptorBinding) -> Binding {
_ => panic!("unsupported bind type {:?}", binding.descriptor_type),
};
// println!(" {:?}", binding);
Binding{
bind_type: bind_type,
name: type_description.type_name.to_string()
Binding {
index: binding.binding,
bind_type,
name: type_description.type_name.to_string(),
}
}
@ -76,7 +83,10 @@ enum NumberType {
}
fn reflect_uniform(type_description: &ReflectTypeDescription) -> UniformProperty {
let uniform_property_type = if type_description.type_flags.contains(ReflectTypeFlags::STRUCT) {
let uniform_property_type = if type_description
.type_flags
.contains(ReflectTypeFlags::STRUCT)
{
reflect_uniform_struct(type_description)
} else {
reflect_uniform_numeric(type_description)
@ -89,8 +99,7 @@ fn reflect_uniform(type_description: &ReflectTypeDescription) -> UniformProperty
}
fn reflect_uniform_struct(type_description: &ReflectTypeDescription) -> UniformPropertyType {
println!("reflecting struct");
let mut properties = Vec::new();
let mut properties = Vec::new();
for member in type_description.members.iter() {
properties.push(reflect_uniform(member));
}
@ -104,9 +113,12 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform
match traits.numeric.scalar.signedness {
0 => NumberType::UInt,
1 => NumberType::Int,
signedness => panic!("unexpected signedness {}", signedness)
signedness => panic!("unexpected signedness {}", signedness),
}
} else if type_description.type_flags.contains(ReflectTypeFlags::FLOAT) {
} else if type_description
.type_flags
.contains(ReflectTypeFlags::FLOAT)
{
NumberType::Float
} else {
panic!("unexpected type flag {:?}", type_description.type_flags);
@ -114,11 +126,28 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform
// TODO: handle scalar width here
match (number_type, traits.numeric.vector.component_count) {
(NumberType::Int, 1) => UniformPropertyType::Int,
(NumberType::Float, 3) => UniformPropertyType::Vec3,
(NumberType::Float, 4) => UniformPropertyType::Vec4,
(NumberType::UInt, 4) => UniformPropertyType::UVec4,
(number_type, component_count) => panic!("unexpected uniform property format {:?} {}", number_type, component_count),
if type_description
.type_flags
.contains(ReflectTypeFlags::MATRIX)
{
match (number_type, traits.numeric.matrix.column_count, traits.numeric.matrix.row_count) {
(NumberType::Float, 3, 3) => UniformPropertyType::Mat3,
(NumberType::Float, 4, 4) => UniformPropertyType::Mat4,
(number_type, column_count, row_count) => panic!(
"unexpected uniform property matrix format {:?} {}x{}",
number_type, column_count, row_count
),
}
} else {
match (number_type, traits.numeric.vector.component_count) {
(NumberType::Int, 1) => UniformPropertyType::Int,
(NumberType::Float, 3) => UniformPropertyType::Vec3,
(NumberType::Float, 4) => UniformPropertyType::Vec4,
(NumberType::UInt, 4) => UniformPropertyType::UVec4,
(number_type, component_count) => panic!(
"unexpected uniform property format {:?} {}",
number_type, component_count
),
}
}
}