Shader reflection works for everything but dynamic uniforms
This commit is contained in:
parent
c29a6f7dd2
commit
2fe9710c04
8
.vscode/launch.json
vendored
8
.vscode/launch.json
vendored
@ -30,11 +30,11 @@
|
|||||||
"cargo": {
|
"cargo": {
|
||||||
"args": [
|
"args": [
|
||||||
"build",
|
"build",
|
||||||
"--example=simple_new_graph",
|
"--example=simple_new",
|
||||||
"--package=bevy"
|
"--package=bevy"
|
||||||
],
|
],
|
||||||
"filter": {
|
"filter": {
|
||||||
"name": "simple_new_graph",
|
"name": "simple_new",
|
||||||
"kind": "example"
|
"kind": "example"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -48,12 +48,12 @@
|
|||||||
"cargo": {
|
"cargo": {
|
||||||
"args": [
|
"args": [
|
||||||
"run",
|
"run",
|
||||||
"--example=simple",
|
"--example=simple_new",
|
||||||
"--package=bevy",
|
"--package=bevy",
|
||||||
"--release"
|
"--release"
|
||||||
],
|
],
|
||||||
"filter": {
|
"filter": {
|
||||||
"name": "simple",
|
"name": "simple_new",
|
||||||
"kind": "example"
|
"kind": "example"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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)
|
* Add runtime type safety to uniform bindings (and maybe compile time)
|
||||||
* Dynamic / user defined shaders
|
* Dynamic / user defined shaders
|
||||||
* consider using shaderc-rs. but this introduces compile complexity and requires other C++ build systems
|
* 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
|
* Input
|
||||||
* Keyboard and mouse events
|
* Keyboard and mouse events
|
||||||
* Gamepad events
|
* Gamepad events
|
||||||
|
@ -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)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PipelineDescriptor {
|
pub struct PipelineDescriptor {
|
||||||
pub draw_targets: Vec<String>,
|
pub draw_targets: Vec<String>,
|
||||||
pub pipeline_layout: PipelineLayout,
|
pub layout: PipelineLayoutType,
|
||||||
pub shader_stages: ShaderStages,
|
pub shader_stages: ShaderStages,
|
||||||
pub rasterization_state: Option<wgpu::RasterizationStateDescriptor>,
|
pub rasterization_state: Option<wgpu::RasterizationStateDescriptor>,
|
||||||
|
|
||||||
@ -59,7 +65,7 @@ pub struct PipelineDescriptor {
|
|||||||
impl PipelineDescriptor {
|
impl PipelineDescriptor {
|
||||||
fn new(vertex_shader: Handle<Shader>) -> Self {
|
fn new(vertex_shader: Handle<Shader>) -> Self {
|
||||||
PipelineDescriptor {
|
PipelineDescriptor {
|
||||||
pipeline_layout: PipelineLayout::new(),
|
layout: PipelineLayoutType::Reflected(None),
|
||||||
color_states: Vec::new(),
|
color_states: Vec::new(),
|
||||||
depth_stencil_state: None,
|
depth_stencil_state: None,
|
||||||
draw_targets: Vec::new(),
|
draw_targets: Vec::new(),
|
||||||
@ -79,6 +85,20 @@ impl PipelineDescriptor {
|
|||||||
alpha_to_coverage_enabled: false,
|
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 {
|
impl PipelineDescriptor {
|
||||||
@ -128,7 +148,14 @@ impl<'a> PipelineBuilder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_bind_group(mut self, bind_group: BindGroup) -> Self {
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
use crate::render::shader_reflect::ShaderLayout;
|
||||||
use std::{
|
use std::{
|
||||||
collections::hash_map::DefaultHasher,
|
collections::{HashMap, hash_map::DefaultHasher, BTreeSet},
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -14,23 +15,61 @@ impl PipelineLayout {
|
|||||||
bind_groups: Vec::new(),
|
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 struct BindGroup {
|
||||||
pub bindings: Vec<Binding>,
|
pub index: u32,
|
||||||
|
pub bindings: BTreeSet<Binding>,
|
||||||
hash: Option<u64>,
|
hash: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BindGroup {
|
impl BindGroup {
|
||||||
pub fn new(bindings: Vec<Binding>) -> Self {
|
pub fn new(index: u32, bindings: Vec<Binding>) -> Self {
|
||||||
BindGroup {
|
BindGroup {
|
||||||
bindings,
|
index,
|
||||||
|
bindings: bindings.iter().cloned().collect(),
|
||||||
hash: None,
|
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()
|
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 struct Binding {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub index: u32,
|
||||||
pub bind_type: BindType,
|
pub bind_type: BindType,
|
||||||
// TODO: ADD SHADER STAGE VISIBILITY
|
// TODO: ADD SHADER STAGE VISIBILITY
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Hash, Clone, Debug)]
|
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
pub enum BindType {
|
pub enum BindType {
|
||||||
Uniform {
|
Uniform {
|
||||||
dynamic: bool,
|
dynamic: bool,
|
||||||
@ -81,13 +128,13 @@ impl BindType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Hash, Clone, Debug)]
|
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
pub struct UniformProperty {
|
pub struct UniformProperty {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub property_type: UniformPropertyType,
|
pub property_type: UniformPropertyType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Hash, Clone, Debug)]
|
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
pub enum UniformPropertyType {
|
pub enum UniformPropertyType {
|
||||||
// TODO: Add all types here
|
// TODO: Add all types here
|
||||||
Int,
|
Int,
|
||||||
@ -95,6 +142,7 @@ pub enum UniformPropertyType {
|
|||||||
UVec4,
|
UVec4,
|
||||||
Vec3,
|
Vec3,
|
||||||
Vec4,
|
Vec4,
|
||||||
|
Mat3,
|
||||||
Mat4,
|
Mat4,
|
||||||
Struct(Vec<UniformProperty>),
|
Struct(Vec<UniformProperty>),
|
||||||
Array(Box<UniformPropertyType>, usize),
|
Array(Box<UniformPropertyType>, usize),
|
||||||
@ -108,6 +156,7 @@ impl UniformPropertyType {
|
|||||||
UniformPropertyType::UVec4 => 4 * 4,
|
UniformPropertyType::UVec4 => 4 * 4,
|
||||||
UniformPropertyType::Vec3 => 4 * 3,
|
UniformPropertyType::Vec3 => 4 * 3,
|
||||||
UniformPropertyType::Vec4 => 4 * 4,
|
UniformPropertyType::Vec4 => 4 * 4,
|
||||||
|
UniformPropertyType::Mat3 => 4 * 4 * 3,
|
||||||
UniformPropertyType::Mat4 => 4 * 4 * 4,
|
UniformPropertyType::Mat4 => 4 * 4 * 4,
|
||||||
UniformPropertyType::Struct(properties) => properties
|
UniformPropertyType::Struct(properties) => properties
|
||||||
.iter()
|
.iter()
|
||||||
@ -118,7 +167,7 @@ impl UniformPropertyType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash)]
|
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
pub enum TextureViewDimension {
|
pub enum TextureViewDimension {
|
||||||
D1,
|
D1,
|
||||||
D2,
|
D2,
|
||||||
|
@ -21,72 +21,76 @@ impl ForwardPipelineBuilder for RenderGraphBuilder {
|
|||||||
include_str!("forward.frag"),
|
include_str!("forward.frag"),
|
||||||
ShaderStage::Fragment,
|
ShaderStage::Fragment,
|
||||||
))
|
))
|
||||||
.add_bind_group(BindGroup::new(vec![
|
// .add_bind_group(BindGroup::new(0, vec![
|
||||||
Binding {
|
// Binding {
|
||||||
name: "Camera".to_string(),
|
// index: 0,
|
||||||
bind_type: BindType::Uniform {
|
// name: "Camera".to_string(),
|
||||||
dynamic: false,
|
// bind_type: BindType::Uniform {
|
||||||
properties: vec![UniformProperty {
|
// dynamic: false,
|
||||||
name: "ViewProj".to_string(),
|
// properties: vec![UniformProperty {
|
||||||
property_type: UniformPropertyType::Mat4,
|
// name: "ViewProj".to_string(),
|
||||||
}],
|
// property_type: UniformPropertyType::Mat4,
|
||||||
},
|
// }],
|
||||||
},
|
// },
|
||||||
Binding {
|
// },
|
||||||
name: "Lights".to_string(),
|
// Binding {
|
||||||
bind_type: BindType::Uniform {
|
// index: 1,
|
||||||
dynamic: false,
|
// name: "Lights".to_string(),
|
||||||
properties: vec![
|
// bind_type: BindType::Uniform {
|
||||||
UniformProperty {
|
// dynamic: false,
|
||||||
name: "NumLights".to_string(),
|
// properties: vec![
|
||||||
property_type: UniformPropertyType::UVec4,
|
// UniformProperty {
|
||||||
},
|
// name: "NumLights".to_string(),
|
||||||
UniformProperty {
|
// property_type: UniformPropertyType::UVec4,
|
||||||
name: "SceneLights".to_string(),
|
// },
|
||||||
property_type: UniformPropertyType::Array(
|
// UniformProperty {
|
||||||
Box::new(UniformPropertyType::Struct(vec![
|
// name: "SceneLights".to_string(),
|
||||||
UniformProperty {
|
// property_type: UniformPropertyType::Array(
|
||||||
name: "proj".to_string(),
|
// Box::new(UniformPropertyType::Struct(vec![
|
||||||
property_type: UniformPropertyType::Mat4,
|
// UniformProperty {
|
||||||
},
|
// name: "proj".to_string(),
|
||||||
UniformProperty {
|
// property_type: UniformPropertyType::Mat4,
|
||||||
name: "pos".to_string(),
|
// },
|
||||||
property_type: UniformPropertyType::Vec4,
|
// UniformProperty {
|
||||||
},
|
// name: "pos".to_string(),
|
||||||
UniformProperty {
|
// property_type: UniformPropertyType::Vec4,
|
||||||
name: "color".to_string(),
|
// },
|
||||||
property_type: UniformPropertyType::Vec4,
|
// UniformProperty {
|
||||||
},
|
// name: "color".to_string(),
|
||||||
])),
|
// property_type: UniformPropertyType::Vec4,
|
||||||
10, // max lights
|
// },
|
||||||
),
|
// ])),
|
||||||
},
|
// 10, // max lights
|
||||||
],
|
// ),
|
||||||
},
|
// },
|
||||||
},
|
// ],
|
||||||
]))
|
// },
|
||||||
.add_bind_group(BindGroup::new(vec![
|
// },
|
||||||
Binding {
|
// ]))
|
||||||
name: "Object".to_string(),
|
// .add_bind_group(BindGroup::new(1, vec![
|
||||||
bind_type: BindType::Uniform {
|
// Binding {
|
||||||
dynamic: true,
|
// index: 0,
|
||||||
properties: vec![UniformProperty {
|
// name: "Object".to_string(),
|
||||||
name: "Model".to_string(),
|
// bind_type: BindType::Uniform {
|
||||||
property_type: UniformPropertyType::Mat4,
|
// 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,
|
// Binding {
|
||||||
properties: vec![UniformProperty {
|
// index: 1,
|
||||||
name: "Albedo".to_string(),
|
// name: "StandardMaterial_albedo".to_string(),
|
||||||
property_type: UniformPropertyType::Vec4,
|
// bind_type: BindType::Uniform {
|
||||||
}],
|
// dynamic: true,
|
||||||
},
|
// properties: vec![UniformProperty {
|
||||||
},
|
// name: "Albedo".to_string(),
|
||||||
]))
|
// property_type: UniformPropertyType::Vec4,
|
||||||
|
// }],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ]))
|
||||||
.with_rasterization_state(wgpu::RasterizationStateDescriptor {
|
.with_rasterization_state(wgpu::RasterizationStateDescriptor {
|
||||||
front_face: wgpu::FrontFace::Ccw,
|
front_face: wgpu::FrontFace::Ccw,
|
||||||
cull_mode: wgpu::CullMode::Back,
|
cull_mode: wgpu::CullMode::Back,
|
||||||
|
@ -34,7 +34,8 @@ impl ForwardFlatPipelineBuilder for RenderGraphBuilder {
|
|||||||
include_str!("forward_flat.frag"),
|
include_str!("forward_flat.frag"),
|
||||||
ShaderStage::Fragment,
|
ShaderStage::Fragment,
|
||||||
))
|
))
|
||||||
.add_bind_group(BindGroup::new(vec![Binding {
|
.add_bind_group(BindGroup::new(0, vec![Binding {
|
||||||
|
index: 0,
|
||||||
name: "Camera".to_string(),
|
name: "Camera".to_string(),
|
||||||
bind_type: BindType::Uniform {
|
bind_type: BindType::Uniform {
|
||||||
dynamic: false,
|
dynamic: false,
|
||||||
@ -44,8 +45,9 @@ impl ForwardFlatPipelineBuilder for RenderGraphBuilder {
|
|||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
}]))
|
}]))
|
||||||
.add_bind_group(BindGroup::new(vec![
|
.add_bind_group(BindGroup::new(1, vec![
|
||||||
Binding {
|
Binding {
|
||||||
|
index: 0,
|
||||||
name: "Object".to_string(),
|
name: "Object".to_string(),
|
||||||
bind_type: BindType::Uniform {
|
bind_type: BindType::Uniform {
|
||||||
dynamic: true,
|
dynamic: true,
|
||||||
@ -56,6 +58,7 @@ impl ForwardFlatPipelineBuilder for RenderGraphBuilder {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Binding {
|
Binding {
|
||||||
|
index: 1,
|
||||||
name: "StandardMaterial_albedo".to_string(),
|
name: "StandardMaterial_albedo".to_string(),
|
||||||
bind_type: BindType::Uniform {
|
bind_type: BindType::Uniform {
|
||||||
dynamic: true,
|
dynamic: true,
|
||||||
|
@ -33,7 +33,8 @@ impl UiPipelineBuilder for RenderGraphBuilder {
|
|||||||
include_str!("ui.frag"),
|
include_str!("ui.frag"),
|
||||||
ShaderStage::Fragment,
|
ShaderStage::Fragment,
|
||||||
))
|
))
|
||||||
.add_bind_group(BindGroup::new(vec![Binding {
|
.add_bind_group(BindGroup::new(0, vec![Binding {
|
||||||
|
index: 0,
|
||||||
name: "Camera2d".to_string(),
|
name: "Camera2d".to_string(),
|
||||||
bind_type: BindType::Uniform {
|
bind_type: BindType::Uniform {
|
||||||
dynamic: false,
|
dynamic: false,
|
||||||
|
@ -4,9 +4,9 @@ use crate::{
|
|||||||
render::{
|
render::{
|
||||||
render_graph_2::{
|
render_graph_2::{
|
||||||
resource_name, update_shader_assignments, BindGroup, BindType,
|
resource_name, update_shader_assignments, BindGroup, BindType,
|
||||||
DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, RenderGraph, RenderPass,
|
DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, PipelineLayout,
|
||||||
RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor,
|
PipelineLayoutType, RenderGraph, RenderPass, RenderPassColorAttachmentDescriptor,
|
||||||
Renderer, ResourceInfo, TextureDescriptor,
|
RenderPassDepthStencilAttachmentDescriptor, Renderer, ResourceInfo, TextureDescriptor,
|
||||||
},
|
},
|
||||||
Shader,
|
Shader,
|
||||||
},
|
},
|
||||||
@ -76,25 +76,37 @@ impl WgpuRenderer {
|
|||||||
vertex_shader: &Shader,
|
vertex_shader: &Shader,
|
||||||
fragment_shader: Option<&Shader>,
|
fragment_shader: Option<&Shader>,
|
||||||
) -> wgpu::RenderPipeline {
|
) -> 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 {
|
let fragment_shader_module = match fragment_shader {
|
||||||
Some(fragment_shader) => {
|
Some(fragment_spirv) => Some(Self::create_shader_module(device, fragment_spirv, None)),
|
||||||
Some(Self::create_shader_module(device, fragment_shader, None))
|
|
||||||
}
|
|
||||||
None => 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
|
// setup new bind group layouts
|
||||||
for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter_mut() {
|
for bind_group in layout.bind_groups.iter_mut() {
|
||||||
bind_group.update_hash();
|
let bind_group_id = bind_group.get_or_update_hash();
|
||||||
let bind_group_id = bind_group.get_hash();
|
|
||||||
if let None = bind_group_layouts.get(&bind_group_id) {
|
if let None = bind_group_layouts.get(&bind_group_id) {
|
||||||
let bind_group_layout_binding = bind_group
|
let bind_group_layout_binding = bind_group
|
||||||
.bindings
|
.bindings
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.map(|binding| wgpu::BindGroupLayoutBinding {
|
||||||
.map(|(i, binding)| wgpu::BindGroupLayoutBinding {
|
binding: binding.index,
|
||||||
binding: i as u32,
|
|
||||||
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||||
ty: (&binding.bind_type).into(),
|
ty: (&binding.bind_type).into(),
|
||||||
})
|
})
|
||||||
@ -109,12 +121,11 @@ impl WgpuRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// collect bind group layout references
|
// collect bind group layout references
|
||||||
let bind_group_layouts = pipeline_descriptor
|
let bind_group_layouts = layout
|
||||||
.pipeline_layout
|
|
||||||
.bind_groups
|
.bind_groups
|
||||||
.iter()
|
.iter()
|
||||||
.map(|bind_group| {
|
.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()
|
bind_group_layouts.get(&bind_group_id).unwrap()
|
||||||
})
|
})
|
||||||
.collect::<Vec<&wgpu::BindGroupLayout>>();
|
.collect::<Vec<&wgpu::BindGroupLayout>>();
|
||||||
@ -127,11 +138,11 @@ impl WgpuRenderer {
|
|||||||
layout: &pipeline_layout,
|
layout: &pipeline_layout,
|
||||||
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
||||||
module: &vertex_shader_module,
|
module: &vertex_shader_module,
|
||||||
entry_point: &vertex_shader.entry_point,
|
entry_point: "main",
|
||||||
},
|
},
|
||||||
fragment_stage: match fragment_shader {
|
fragment_stage: match fragment_shader {
|
||||||
Some(fragment_shader) => Some(wgpu::ProgrammableStageDescriptor {
|
Some(fragment_shader) => Some(wgpu::ProgrammableStageDescriptor {
|
||||||
entry_point: &fragment_shader.entry_point,
|
entry_point: "main",
|
||||||
module: fragment_shader_module.as_ref().unwrap(),
|
module: fragment_shader_module.as_ref().unwrap(),
|
||||||
}),
|
}),
|
||||||
None => None,
|
None => None,
|
||||||
@ -233,7 +244,7 @@ impl WgpuRenderer {
|
|||||||
|
|
||||||
// TODO: consider moving this to a resource provider
|
// TODO: consider moving this to a resource provider
|
||||||
fn setup_bind_group(&mut self, bind_group: &BindGroup) -> u64 {
|
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) {
|
if let None = self.bind_groups.get(&bind_group_id) {
|
||||||
let mut unset_uniforms = Vec::new();
|
let mut unset_uniforms = Vec::new();
|
||||||
@ -260,12 +271,11 @@ impl WgpuRenderer {
|
|||||||
let bindings = bind_group
|
let bindings = bind_group
|
||||||
.bindings
|
.bindings
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.map(|binding| {
|
||||||
.map(|(i, b)| {
|
let resource_info = self.resource_info.get(&binding.name).unwrap();
|
||||||
let resource_info = self.resource_info.get(&b.name).unwrap();
|
|
||||||
wgpu::Binding {
|
wgpu::Binding {
|
||||||
binding: i as u32,
|
binding: binding.index,
|
||||||
resource: match &b.bind_type {
|
resource: match &binding.bind_type {
|
||||||
BindType::Uniform {
|
BindType::Uniform {
|
||||||
dynamic: _,
|
dynamic: _,
|
||||||
properties: _,
|
properties: _,
|
||||||
@ -275,7 +285,7 @@ impl WgpuRenderer {
|
|||||||
buffer_usage: _,
|
buffer_usage: _,
|
||||||
} = resource_info
|
} = resource_info
|
||||||
{
|
{
|
||||||
let buffer = self.buffers.get(&b.name).unwrap();
|
let buffer = self.buffers.get(&binding.name).unwrap();
|
||||||
wgpu::BindingResource::Buffer {
|
wgpu::BindingResource::Buffer {
|
||||||
buffer,
|
buffer,
|
||||||
range: 0..*size,
|
range: 0..*size,
|
||||||
@ -426,7 +436,8 @@ impl Renderer for WgpuRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create bind groups
|
// 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);
|
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>) {
|
fn setup_bind_groups(&mut self, entity: Option<&Entity>) {
|
||||||
for (i, bind_group) in self
|
let pipeline_layout = self.pipeline_descriptor.get_layout().unwrap();
|
||||||
.pipeline_descriptor
|
for bind_group in pipeline_layout.bind_groups.iter() {
|
||||||
.pipeline_layout
|
let bind_group_id = bind_group.get_hash().unwrap();
|
||||||
.bind_groups
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
let bind_group_id = bind_group.get_hash();
|
|
||||||
let bind_group_info = self.renderer.bind_groups.get(&bind_group_id).unwrap();
|
let bind_group_info = self.renderer.bind_groups.get(&bind_group_id).unwrap();
|
||||||
|
|
||||||
let mut dynamic_uniform_indices = Vec::new();
|
let mut dynamic_uniform_indices = Vec::new();
|
||||||
@ -658,7 +664,7 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
|
|||||||
continue;
|
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) =
|
if let Some(dynamic_uniform_buffer_info) =
|
||||||
self.renderer.dynamic_uniform_buffer_info.get(&binding.name)
|
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
|
// TODO: check to see if bind group is already set
|
||||||
self.render_pass.set_bind_group(
|
self.render_pass.set_bind_group(
|
||||||
i as u32,
|
bind_group.index,
|
||||||
&bind_group_info.bind_group,
|
&bind_group_info.bind_group,
|
||||||
dynamic_uniform_indices.as_slice(),
|
dynamic_uniform_indices.as_slice(),
|
||||||
);
|
);
|
||||||
|
@ -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;
|
use std::marker::Copy;
|
||||||
|
|
||||||
#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
|
#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
|
||||||
@ -50,11 +53,10 @@ pub enum ShaderSource {
|
|||||||
Glsl(String),
|
Glsl(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Shader {
|
pub struct Shader {
|
||||||
pub source: ShaderSource,
|
pub source: ShaderSource,
|
||||||
pub stage: ShaderStage,
|
pub stage: ShaderStage,
|
||||||
pub entry_point: String,
|
|
||||||
// TODO: add "precompile" flag?
|
// TODO: add "precompile" flag?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,29 +64,31 @@ impl Shader {
|
|||||||
pub fn from_glsl(glsl: &str, stage: ShaderStage) -> Shader {
|
pub fn from_glsl(glsl: &str, stage: ShaderStage) -> Shader {
|
||||||
Shader {
|
Shader {
|
||||||
source: ShaderSource::Glsl(glsl.to_string()),
|
source: ShaderSource::Glsl(glsl.to_string()),
|
||||||
entry_point: "main".to_string(),
|
|
||||||
stage,
|
stage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_spirv(&self, macros: Option<&[String]>) -> Vec<u32> {
|
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::Spirv(ref bytes) => bytes.clone(),
|
||||||
ShaderSource::Glsl(ref source) => glsl_to_spirv(&source, self.stage, macros),
|
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 {
|
pub fn get_spirv_shader(&self, macros: Option<&[String]>) -> Shader {
|
||||||
Shader {
|
Shader {
|
||||||
source: ShaderSource::Spirv(self.get_spirv(macros)),
|
source: ShaderSource::Spirv(self.get_spirv(macros)),
|
||||||
entry_point: self.entry_point.clone(),
|
|
||||||
stage: self.stage,
|
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)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -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::{
|
use spirv_reflect::{
|
||||||
types::{ReflectDescriptorSet, ReflectTypeDescription, ReflectDescriptorBinding, ReflectDescriptorType, ReflectTypeFlags},
|
types::{
|
||||||
|
ReflectDescriptorBinding, ReflectDescriptorSet, ReflectDescriptorType,
|
||||||
|
ReflectTypeDescription, ReflectTypeFlags,
|
||||||
|
},
|
||||||
ShaderModule,
|
ShaderModule,
|
||||||
};
|
};
|
||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
// use rspirv::{binary::Parser, dr::Loader, lift::LiftContext};
|
// 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]) {
|
// pub fn get_shader_layout(spirv_data: &[u32]) {
|
||||||
// let mut loader = Loader::new(); // You can use your own consumer here.
|
// let mut loader = Loader::new(); // You can use your own consumer here.
|
||||||
// {
|
// {
|
||||||
@ -18,37 +23,39 @@ use zerocopy::AsBytes;
|
|||||||
// println!("{:?}", structured.types);
|
// 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()) {
|
match ShaderModule::load_u8_data(spirv_data.as_bytes()) {
|
||||||
Ok(ref mut module) => {
|
Ok(ref mut module) => {
|
||||||
let entry_point_name = module.get_entry_point_name();
|
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();
|
let mut bind_groups = Vec::new();
|
||||||
for descriptor_set in module.enumerate_descriptor_sets(None).unwrap() {
|
for descriptor_set in module.enumerate_descriptor_sets(None).unwrap() {
|
||||||
let bind_group = reflect_bind_group(&descriptor_set);
|
let bind_group = reflect_bind_group(&descriptor_set);
|
||||||
bind_groups.push(bind_group);
|
bind_groups.push(bind_group);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(" result {:?}", &bind_groups);
|
ShaderLayout {
|
||||||
|
bind_groups,
|
||||||
println!();
|
entry_point: entry_point_name,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
Err(err) => panic!("Failed to reflect shader layout: {:?}", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reflect_bind_group(descriptor_set: &ReflectDescriptorSet) -> BindGroup {
|
fn reflect_bind_group(descriptor_set: &ReflectDescriptorSet) -> BindGroup {
|
||||||
println!(" set {}", descriptor_set.set);
|
|
||||||
let mut bindings = Vec::new();
|
let mut bindings = Vec::new();
|
||||||
for descriptor_binding in descriptor_set.bindings.iter() {
|
for descriptor_binding in descriptor_set.bindings.iter() {
|
||||||
let binding = reflect_binding(descriptor_binding);
|
let binding = reflect_binding(descriptor_binding);
|
||||||
bindings.push(binding);
|
bindings.push(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
BindGroup::new(bindings)
|
BindGroup::new(descriptor_set.set, bindings)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reflect_binding(binding: &ReflectDescriptorBinding) -> Binding {
|
fn reflect_binding(binding: &ReflectDescriptorBinding) -> Binding {
|
||||||
@ -61,10 +68,10 @@ fn reflect_binding(binding: &ReflectDescriptorBinding) -> Binding {
|
|||||||
_ => panic!("unsupported bind type {:?}", binding.descriptor_type),
|
_ => panic!("unsupported bind type {:?}", binding.descriptor_type),
|
||||||
};
|
};
|
||||||
|
|
||||||
// println!(" {:?}", binding);
|
Binding {
|
||||||
Binding{
|
index: binding.binding,
|
||||||
bind_type: bind_type,
|
bind_type,
|
||||||
name: type_description.type_name.to_string()
|
name: type_description.type_name.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +83,10 @@ enum NumberType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn reflect_uniform(type_description: &ReflectTypeDescription) -> UniformProperty {
|
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)
|
reflect_uniform_struct(type_description)
|
||||||
} else {
|
} else {
|
||||||
reflect_uniform_numeric(type_description)
|
reflect_uniform_numeric(type_description)
|
||||||
@ -89,8 +99,7 @@ fn reflect_uniform(type_description: &ReflectTypeDescription) -> UniformProperty
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn reflect_uniform_struct(type_description: &ReflectTypeDescription) -> UniformPropertyType {
|
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() {
|
for member in type_description.members.iter() {
|
||||||
properties.push(reflect_uniform(member));
|
properties.push(reflect_uniform(member));
|
||||||
}
|
}
|
||||||
@ -104,9 +113,12 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform
|
|||||||
match traits.numeric.scalar.signedness {
|
match traits.numeric.scalar.signedness {
|
||||||
0 => NumberType::UInt,
|
0 => NumberType::UInt,
|
||||||
1 => NumberType::Int,
|
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
|
NumberType::Float
|
||||||
} else {
|
} else {
|
||||||
panic!("unexpected type flag {:?}", type_description.type_flags);
|
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
|
// TODO: handle scalar width here
|
||||||
|
|
||||||
match (number_type, traits.numeric.vector.component_count) {
|
if type_description
|
||||||
(NumberType::Int, 1) => UniformPropertyType::Int,
|
.type_flags
|
||||||
(NumberType::Float, 3) => UniformPropertyType::Vec3,
|
.contains(ReflectTypeFlags::MATRIX)
|
||||||
(NumberType::Float, 4) => UniformPropertyType::Vec4,
|
{
|
||||||
(NumberType::UInt, 4) => UniformPropertyType::UVec4,
|
match (number_type, traits.numeric.matrix.column_count, traits.numeric.matrix.row_count) {
|
||||||
(number_type, component_count) => panic!("unexpected uniform property format {:?} {}", number_type, component_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
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user