more graph work

This commit is contained in:
Carter Anderson 2020-01-23 00:31:56 -08:00
parent 8967e35230
commit 2226292ce0
19 changed files with 348 additions and 384 deletions

View file

@ -1,4 +1,4 @@
use bevy::{prelude::*, asset, render::{Albedo, render_graph_2::{StandardMaterial, ShaderMaterials, ShaderMaterial, ShaderValue}}};
use bevy::{prelude::*, asset, render::{Albedo, render_graph_2::{StandardMaterial, ShaderUniforms}}};
fn main() {
AppBuilder::new().add_defaults_legacy().setup_world(setup).run();
@ -11,53 +11,54 @@ fn setup(world: &mut World) {
(texture_storage.add(texture))
};
let mut color_shader_materials = ShaderMaterials::new();
let mut color_shader_uniforms = ShaderUniforms::new();
let color_material = StandardMaterial {
albedo: Albedo::Color(math::vec4(1.0, 0.0, 0.0, 0.0))
// albedo: Albedo::Color(math::vec4(1.0, 0.0, 0.0, 0.0))
albedo: math::vec4(1.0, 0.0, 0.0, 0.0)
};
color_shader_materials.add(color_material.get_selector());
// color_shader_materials.add(color_material.get_selector());
world.insert(
(),
vec![(
color_shader_materials,
color_material,
)],
);
// world.insert(
// (),
// vec![(
// color_shader_materials,
// color_material,
// )],
// );
let mut texture_shader_materials = ShaderMaterials::new();
let texture_material = StandardMaterial {
albedo: Albedo::Texture(texture_handle)
};
// let mut texture_shader_materials = ShaderMaterials::new();
// let texture_material = StandardMaterial {
// albedo: Albedo::Texture(texture_handle)
// };
texture_shader_materials.add(texture_material.get_selector());
// texture_shader_materials.add(texture_material.get_selector());
world.insert(
(),
vec![(
texture_shader_materials,
texture_material,
)],
);
// world.insert(
// (),
// vec![(
// texture_shader_materials,
// texture_material,
// )],
// );
for (entity, materials) in <Read<ShaderMaterials>>::query().iter_entities(world) {
println!("entity {}", entity);
for selector in materials.materials.iter() {
let shader_material = selector(entity, world).unwrap();
print!(" ");
for property in shader_material.iter_properties() {
println!("property: {}", property);
print!(" ");
match shader_material.get_property(property) {
Some(a) => match a {
ShaderValue::Vec4(color) => println!("color {}", color),
ShaderValue::Texture(ref handle) => println!("tex {}", handle.id),
_ => println!("other"),
},
None => println!("none"),
}
}
}
}
// for (entity, materials) in <Read<ShaderMaterials>>::query().iter_entities(world) {
// println!("entity {}", entity);
// for selector in materials.materials.iter() {
// let shader_material = selector(entity, world).unwrap();
// print!(" ");
// for property in shader_material.iter_properties() {
// println!("property: {}", property);
// print!(" ");
// match shader_material.get_property(property) {
// Some(a) => match a {
// ShaderValue::Vec4(color) => println!("color {}", color),
// ShaderValue::Texture(ref handle) => println!("tex {}", handle.id),
// _ => println!("other"),
// },
// None => println!("none"),
// }
// }
// }
// }
}

View file

@ -1,19 +0,0 @@
#version 450
layout(location = 0) in vec3 v_Normal;
layout(location = 1) in vec4 v_Position;
layout(location = 0) out vec4 o_Target;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 1) uniform Material {
vec4 Albedo;
};
void main() {
// multiply the light by material color
o_Target = Color;
}

View file

@ -1,26 +0,0 @@
#version 450
layout(location = 0) in vec4 a_Pos;
layout(location = 1) in vec4 a_Normal;
layout(location = 2) in vec4 a_Uv;
layout(location = 0) out vec3 v_Normal;
layout(location = 1) out vec4 v_Position;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 0) uniform Object {
mat4 Model;
};
layout(set = 1, binding = 1) uniform Material {
vec4 Albedo;
};
void main() {
v_Normal = mat3(Model) * vec3(a_Normal.xyz);
v_Position = Model * vec4(a_Pos);
gl_Position = ViewProj * v_Position;
}

View file

@ -1,174 +0,0 @@
use crate::{asset::*, render::*};
use legion::prelude::*;
use wgpu::SwapChainOutput;
pub struct ForwardFlatPipeline {
pub pipeline: Option<wgpu::RenderPipeline>,
pub depth_format: wgpu::TextureFormat,
pub bind_group: Option<wgpu::BindGroup>,
pub msaa_samples: usize,
}
impl ForwardFlatPipeline {
pub fn new(msaa_samples: usize) -> Self {
ForwardFlatPipeline {
pipeline: None,
bind_group: None,
msaa_samples,
depth_format: wgpu::TextureFormat::Depth32Float,
}
}
}
impl Pipeline for ForwardFlatPipeline {
fn initialize(&mut self, render_graph: &mut RenderGraphData, _: &mut World) {
let vs_bytes = shader::glsl_to_spirv(include_str!("forward_flat.vert"), shader::ShaderStage::Vertex);
let fs_bytes =
shader::glsl_to_spirv(include_str!("forward_flat.frag"), shader::ShaderStage::Fragment);
let bind_group_layout =
render_graph
.device
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[
wgpu::BindGroupLayoutBinding {
binding: 0, // global
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
},
wgpu::BindGroupLayoutBinding {
binding: 1, // lights
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
},
],
});
self.bind_group = Some({
let forward_uniform_buffer = render_graph
.get_uniform_buffer(render_resources::FORWARD_UNIFORM_BUFFER_NAME)
.unwrap();
let light_uniform_buffer = render_graph
.get_uniform_buffer(render_resources::LIGHT_UNIFORM_BUFFER_NAME)
.unwrap();
// Create bind group
render_graph
.device
.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &bind_group_layout,
bindings: &[
wgpu::Binding {
binding: 0,
resource: forward_uniform_buffer.get_binding_resource(),
},
wgpu::Binding {
binding: 1,
resource: light_uniform_buffer.get_binding_resource(),
},
],
})
});
let material_bind_group_layout = render_graph
.get_bind_group_layout(render_resources::MATERIAL_BIND_GROUP_LAYOUT_NAME)
.unwrap();
let pipeline_layout =
render_graph
.device
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: &[&bind_group_layout, material_bind_group_layout],
});
let vertex_buffer_descriptor = get_vertex_buffer_descriptor();
let vs_module = render_graph.device.create_shader_module(&vs_bytes);
let fs_module = render_graph.device.create_shader_module(&fs_bytes);
self.pipeline = Some(render_graph.device.create_render_pipeline(
&wgpu::RenderPipelineDescriptor {
layout: &pipeline_layout,
vertex_stage: wgpu::ProgrammableStageDescriptor {
module: &vs_module,
entry_point: "main",
},
fragment_stage: Some(wgpu::ProgrammableStageDescriptor {
module: &fs_module,
entry_point: "main",
}),
rasterization_state: Some(wgpu::RasterizationStateDescriptor {
front_face: wgpu::FrontFace::Ccw,
cull_mode: wgpu::CullMode::Back,
depth_bias: 0,
depth_bias_slope_scale: 0.0,
depth_bias_clamp: 0.0,
}),
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
color_states: &[wgpu::ColorStateDescriptor {
format: render_graph.swap_chain_descriptor.format,
color_blend: wgpu::BlendDescriptor::REPLACE,
alpha_blend: wgpu::BlendDescriptor::REPLACE,
write_mask: wgpu::ColorWrite::ALL,
}],
depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor {
format: self.depth_format,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Less,
stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE,
stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE,
stencil_read_mask: 0,
stencil_write_mask: 0,
}),
index_format: wgpu::IndexFormat::Uint16,
vertex_buffers: &[vertex_buffer_descriptor],
sample_count: self.msaa_samples as u32,
sample_mask: !0,
alpha_to_coverage_enabled: false,
},
));
}
fn render(
&mut self,
render_graph: &RenderGraphData,
pass: &mut wgpu::RenderPass,
_: &SwapChainOutput,
world: &mut World,
) {
pass.set_bind_group(0, self.bind_group.as_ref().unwrap(), &[]);
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut last_mesh_id = None;
let mesh_query =
<(Read<Material>, Read<Handle<Mesh>>)>::query().filter(!component::<Instanced>());
for (material, mesh) in mesh_query.iter(world) {
let current_mesh_id = mesh.id;
let mut should_load_mesh = last_mesh_id == None;
if let Some(last) = last_mesh_id {
should_load_mesh = last != current_mesh_id;
}
if should_load_mesh {
if let Some(mesh_asset) = mesh_storage.get(mesh.id) {
mesh_asset.setup_buffers(&render_graph.device);
pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0);
pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]);
};
}
if let Some(ref mesh_asset) = mesh_storage.get(mesh.id) {
pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]);
pass.draw_indexed(0..mesh_asset.indices.len() as u32, 0, 0..1);
};
last_mesh_id = Some(current_mesh_id);
}
}
fn resize(&mut self, _: &RenderGraphData) {}
fn get_pipeline(&self) -> &wgpu::RenderPipeline {
self.pipeline.as_ref().unwrap()
}
}

View file

@ -1,12 +1,10 @@
mod forward;
mod forward_flat;
mod forward_instanced;
mod forward_shadow;
mod shadow;
mod ui;
pub use forward::{ForwardPass, ForwardPipeline, ForwardUniforms};
pub use forward_flat::*;
pub use forward_instanced::ForwardInstancedPipeline;
pub use forward_shadow::ForwardShadowPassNew;
pub use shadow::ShadowPass;

View file

@ -2,7 +2,7 @@ use crate::{
asset::{AssetStorage, Handle, Mesh},
legion::prelude::*,
render::{
render_graph_2::{ShaderMaterials, RenderPass},
render_graph_2::{ShaderUniforms, RenderPass},
Instanced,
},
};
@ -14,7 +14,7 @@ pub fn mesh_draw_target(world: &World, _render_pass: &mut dyn RenderPass) {
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut last_mesh_id = None;
let mesh_query =
<(Read<ShaderMaterials>, Read<Handle<Mesh>>)>::query().filter(!component::<Instanced>());
<(Read<ShaderUniforms>, Read<Handle<Mesh>>)>::query().filter(!component::<Instanced>());
for (_material, mesh) in mesh_query.iter(world) {
let current_mesh_id = mesh.id;

View file

@ -1,6 +1,8 @@
pub mod pipelines;
pub mod resource;
pub mod resource_name;
pub mod wgpu_renderer;
mod resource_provider;
mod resource;
mod pipeline;
mod pipeline_layout;
mod pass;
@ -15,4 +17,6 @@ pub use pass::*;
pub use renderer::*;
pub use shader::*;
pub use render_graph::*;
pub use draw_target::*;
pub use draw_target::*;
pub use resource::*;
pub use resource_provider::*;

View file

@ -22,7 +22,7 @@ pub struct Binding {
pub enum BindType {
Uniform {
// dynamic: bool,
dynamic: bool,
properties: Vec<UniformProperty>
},
Buffer {
@ -45,6 +45,7 @@ pub struct UniformProperty {
}
pub enum UniformPropertyType {
// TODO: Add all types here
Int,
Float,
UVec4,
@ -55,6 +56,7 @@ pub enum UniformPropertyType {
Array(Box<UniformPropertyType>, usize),
}
#[derive(Copy, Clone)]
pub enum TextureDimension {
D1,
D2,

View file

@ -9,11 +9,11 @@ layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 1) uniform Material {
layout(set = 1, binding = 1) uniform StandardMaterial {
vec4 Albedo;
};
void main() {
// multiply the light by material color
o_Target = Color;
o_Target = Albedo;
}

View file

@ -15,7 +15,7 @@ layout(set = 1, binding = 0) uniform Object {
mat4 Model;
};
layout(set = 1, binding = 1) uniform Material {
layout(set = 1, binding = 1) uniform StandardMaterial {
vec4 Albedo;
};

View file

@ -2,7 +2,7 @@ use crate::render::{
Vertex,
{
render_graph_2::{
mesh_draw_target, resource, pipeline_layout::*, PassDescriptor, PipelineDescriptor,
mesh_draw_target, resource_name, pipeline_layout::*, PassDescriptor, PipelineDescriptor,
RenderGraphBuilder, RenderPassColorAttachmentDescriptor,
},
shader::{Shader, ShaderStage},
@ -27,54 +27,40 @@ impl ForwardPipelineBuilder for RenderGraphBuilder {
.add_bind_group(BindGroup {
bindings: vec![
Binding {
name: "Globals".to_string(),
name: "Camera".to_string(),
bind_type: BindType::Uniform {
dynamic: false,
properties: vec![
UniformProperty {
name: "ViewProj".to_string(),
property_type: UniformPropertyType::Mat4,
},
UniformProperty {
name: "NumLights".to_string(),
property_type: UniformPropertyType::UVec4,
},
]
}
},
Binding {
name: "Lights".to_string(),
bind_type: BindType::Uniform {
properties: vec![
UniformProperty {
name: "SceneLights".to_string(),
property_type: UniformPropertyType::Array(
Box::new(UniformPropertyType::Struct(
vec![
UniformPropertyType::Mat4,
UniformPropertyType::Vec4,
UniformPropertyType::Vec4,
]
)),
10
),
},
]
}
}
]
})
.add_bind_group(BindGroup {
bindings: vec![
Binding {
name: "Entity".to_string(),
name: "Object".to_string(),
bind_type: BindType::Uniform {
dynamic: false,
properties: vec![
UniformProperty {
name: "World".to_string(),
name: "Model".to_string(),
property_type: UniformPropertyType::Mat4,
},
]
}
},
Binding {
name: "StandardMaterial".to_string(),
bind_type: BindType::Uniform {
dynamic: false,
properties: vec![
UniformProperty {
name: "Color".to_string(),
name: "Albedo".to_string(),
property_type: UniformPropertyType::Vec4,
},
]
@ -121,7 +107,7 @@ impl ForwardPassBuilder for RenderGraphBuilder {
"main",
PassDescriptor {
color_attachments: vec![RenderPassColorAttachmentDescriptor {
attachment: resource::texture::SWAP_CHAIN.to_string(),
attachment: resource_name::texture::SWAP_CHAIN.to_string(),
resolve_target: None,
load_op: wgpu::LoadOp::Clear,
store_op: wgpu::StoreOp::Store,

View file

@ -1,10 +1,12 @@
use crate::{asset::Mesh, legion::prelude::*, render::render_graph_2::RenderGraph};
use crate::{asset::Mesh, legion::prelude::*, render::render_graph_2::{RenderGraph, Buffer, ResourceId}};
pub trait Renderer {
fn initialize(&mut self, world: &mut World);
fn resize(&mut self, world: &mut World, width: u32, height: u32);
fn process_render_graph(&mut self, render_graph: &RenderGraph, world: &mut World);
fn load_mesh(&mut self, asset_id: usize, mesh: &Mesh);
// TODO: swap out wgpu::BufferUsage for custom type
fn create_buffer_with_data(&mut self, data: &[u8], buffer_usage: wgpu::BufferUsage) -> Buffer;
fn free_buffer(&mut self, id: ResourceId) -> Buffer;
}
pub trait RenderPass {

View file

@ -0,0 +1,8 @@
pub type ResourceId = u64;
pub struct Buffer {
pub id: ResourceId,
pub size: u64,
pub buffer_usage: wgpu::BufferUsage,
// pub layout: Option<
}

View file

@ -1 +0,0 @@
pub mod texture;

View file

@ -1 +0,0 @@
pub const SWAP_CHAIN: &str = "swap_chain";

View file

@ -0,0 +1,3 @@
pub mod texture {
pub const SWAP_CHAIN: &str = "SwapChain";
}

View file

@ -0,0 +1,41 @@
use crate::render::{render_graph_2::Renderer, ActiveCamera, Camera};
use bevy_transform::prelude::LocalToWorld;
use legion::prelude::*;
use zerocopy::AsBytes;
use std::mem;
trait ResourceProvider {
fn update(renderer: &mut dyn Renderer, world: &mut World);
fn resize(renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32);
}
pub struct CameraResourceProvider;
impl ResourceProvider for CameraResourceProvider {
fn update(renderer: &mut dyn Renderer, world: &mut World) {}
fn resize(renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32) {
for (mut camera, local_to_world, _) in
<(Write<Camera>, Read<LocalToWorld>, Read<ActiveCamera>)>::query().iter_mut(world)
{
camera.update(width, height);
let camera_matrix: [[f32; 4]; 4] =
(camera.view_matrix * local_to_world.0).to_cols_array_2d();
let matrix_size = mem::size_of::<[[f32; 4]; 4]>() as u64;
// TODO: use staging buffer?
let buffer = renderer.create_buffer_with_data(camera_matrix.as_bytes(), wgpu::BufferUsage::UNIFORM);
// let temp_camera_buffer = render_graph
// .device
// .create_buffer_with_data(camera_matrix.as_bytes(), wgpu::BufferUsage::COPY_SRC);
// let forward_uniform_buffer = render_graph
// .get_uniform_buffer(FORWARD_UNIFORM_BUFFER_NAME)
// .unwrap();
// encoder.copy_buffer_to_buffer(
// &temp_camera_buffer,
// 0,
// &forward_uniform_buffer.buffer,
// 0,
// matrix_size,
// );
}
}
}

View file

@ -1,67 +1,134 @@
use crate::prelude::*;
use crate::{asset::Texture, legion::{prelude::{Entity, World}, borrow::{Ref, RefMap}}, render::Albedo};
use crate::{
asset::Texture,
legion::{
borrow::{Ref, RefMap},
prelude::{Entity, World},
},
render::render_graph_2::{UniformPropertyType, Binding, BindType},
render::Albedo,
math::Vec4,
};
use zerocopy::AsBytes;
pub enum ShaderValue<'a> {
Int(u32),
Float(f32),
Vec4(Vec4),
Uniform(&'a [u8]),
Texture(&'a Handle<Texture>),
pub type ShaderUniformSelector = fn(Entity, &World) -> Option<RefMap<&dyn AsUniforms>>;
pub struct ShaderUniforms {
// used for distinguishing
pub uniform_selectors: Vec<ShaderUniformSelector>,
}
pub type ShaderMaterialSelector = fn(Entity, &World) -> Option<RefMap<&dyn ShaderMaterial>>;
pub struct ShaderMaterials {
// used for distinguishing
pub materials: Vec<ShaderMaterialSelector>
}
impl<'a> ShaderMaterials {
pub fn new() -> Self {
ShaderMaterials {
materials: Vec::new(),
impl<'a> ShaderUniforms {
pub fn new() -> Self {
ShaderUniforms {
uniform_selectors: Vec::new(),
}
}
}
pub fn add(&mut self, selector: ShaderMaterialSelector) {
self.materials.push(selector);
}
}
pub trait ShaderMaterial {
fn iter_properties(&self) -> std::slice::Iter<&'static str> ;
fn get_property(&self, name: &str) -> Option<ShaderValue>;
fn get_selector(&self) -> ShaderMaterialSelector;
pub fn add(&mut self, selector: ShaderUniformSelector) {
self.uniform_selectors.push(selector);
}
}
pub struct StandardMaterial {
pub albedo: Albedo
pub albedo: Vec4,
}
// create this from a derive macro
const STANDARD_MATERIAL_PROPERTIES: &[&str] = &["albedo"];
impl ShaderMaterial for StandardMaterial {
fn iter_properties(&self) -> std::slice::Iter<&'static str> {
STANDARD_MATERIAL_PROPERTIES.iter()
pub trait GetBytes {
fn get_bytes(&self) -> Vec<u8>;
fn get_bytes_ref(&self) -> Option<&[u8]>;
}
impl GetBytes for dyn AsBytes {
fn get_bytes(&self) -> Vec<u8> {
self.as_bytes().into()
}
fn get_property(&self, name: &str) -> Option<ShaderValue> {
match name {
"albedo" => Some(match self.albedo {
Albedo::Color(color) => ShaderValue::Vec4(color),
Albedo::Texture(ref texture) => ShaderValue::Texture(texture)
}),
_ => None,
}
}
fn get_selector(&self) -> ShaderMaterialSelector {
|entity, world| {
world.get_component::<Self>(entity).map(
|c: Ref<StandardMaterial>| {
c.map_into(|s| {
s as &dyn ShaderMaterial
})
}
)
}
fn get_bytes_ref(&self) -> Option<&[u8]> {
Some(self.as_bytes())
}
}
impl GetBytes for Vec4 {
fn get_bytes(&self) -> Vec<u8> {
let vec4_array: [f32; 4] = (*self).into();
vec4_array.as_bytes().into()
}
fn get_bytes_ref(&self) -> Option<&[u8]> {
None
}
}
pub trait AsUniforms {
fn get_uniform_info(&self) -> &[UniformInfo];
fn get_uniform_layouts(&self) -> &[&[UniformPropertyType]];
fn get_uniform_value(&self, index: usize) -> Vec<u8>;
// TODO: support zero-copy uniforms
// fn get_uniform_value_ref(&self, index: usize) -> &[u8];
}
// pub struct UniformInfo<'a> {
// pub name: &'a str,
// pub
// }
// create this from a derive macro
const STANDARD_MATERIAL_UNIFORM_INFO: &[UniformInfo] = &[
UniformInfo {
name: "StandardMaterial",
bind_type: BindType::Uniform {
dynamic: false,
properties: Vec::new()
},
}
];
// these are separate from BindType::Uniform{properties} because they need to be const
const STANDARD_MATERIAL_UNIFORM_LAYOUTS: &[&[UniformPropertyType]] = &[&[]];
pub struct UniformInfo<'a> {
pub name: &'a str,
pub bind_type: BindType,
}
// const ST
impl AsUniforms for StandardMaterial {
fn get_uniform_info(&self) -> &[UniformInfo] {
STANDARD_MATERIAL_UNIFORM_INFO
}
fn get_uniform_layouts(&self) -> &[&[UniformPropertyType]] {
STANDARD_MATERIAL_UNIFORM_LAYOUTS
}
fn get_uniform_value(&self, index: usize) -> Vec<u8> {
match index {
0 => self.albedo.get_bytes(),
_ => panic!("index out of bounds"),
}
}
// fn iter_properties(&self) -> std::slice::Iter<&'static str> {
// STANDARD_MATERIAL_PROPERTIES.iter()
// }
// fn get_property(&self, name: &str) -> Option<ShaderValue> {
// match name {
// "albedo" => Some(match self.albedo {
// Albedo::Color(color) => ShaderValue::Vec4(color),
// Albedo::Texture(ref texture) => ShaderValue::Texture(texture)
// }),
// _ => None,
// }
// }
// fn get_selector(&self) -> ShaderMaterialSelector {
// |entity, world| {
// world.get_component::<Self>(entity).map(
// |c: Ref<StandardMaterial>| {
// c.map_into(|s| {
// s as &dyn ShaderMaterial
// })
// }
// )
// }
// }
}

View file

@ -1,13 +1,12 @@
use crate::{
asset::Mesh,
legion::prelude::*,
render::render_graph_2::{
resource, PassDescriptor, PipelineDescriptor, RenderGraph, RenderPass,
RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor, Renderer,
resource_name, BindType, Buffer, PassDescriptor, PipelineDescriptor, RenderGraph,
RenderPass, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor, Renderer, TextureDimension,
},
};
use std::{collections::HashMap, ops::Deref};
use zerocopy::AsBytes;
pub struct WgpuRenderer {
pub device: wgpu::Device,
@ -68,9 +67,34 @@ impl WgpuRenderer {
None => None,
};
let bind_group_layouts = pipeline_descriptor
.pipeline_layout
.bind_groups
.iter()
.map(|bind_group| {
let bind_group_layout_binding = bind_group
.bindings
.iter()
.enumerate()
.map(|(i, binding)| wgpu::BindGroupLayoutBinding {
binding: i as u32,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: (&binding.bind_type).into()
})
.collect::<Vec<wgpu::BindGroupLayoutBinding>>();
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: bind_group_layout_binding.as_slice(),
})
})
.collect::<Vec<wgpu::BindGroupLayout>>();
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: &[],
bind_group_layouts: bind_group_layouts
.iter()
.collect::<Vec<&wgpu::BindGroupLayout>>()
.as_slice(),
});
let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
layout: &pipeline_layout,
vertex_stage: wgpu::ProgrammableStageDescriptor {
@ -108,7 +132,6 @@ impl WgpuRenderer {
encoder: &'a mut wgpu::CommandEncoder,
frame: &'a wgpu::SwapChainOutput,
) -> wgpu::RenderPass<'a> {
// TODO: fill this in
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &pass_descriptor
.color_attachments
@ -128,7 +151,7 @@ impl WgpuRenderer {
frame: &'a wgpu::SwapChainOutput,
) -> wgpu::RenderPassColorAttachmentDescriptor<'a> {
let attachment = match color_attachment_descriptor.attachment.as_str() {
resource::texture::SWAP_CHAIN => &frame.view,
resource_name::texture::SWAP_CHAIN => &frame.view,
_ => self
.textures
.get(&color_attachment_descriptor.attachment)
@ -137,7 +160,7 @@ impl WgpuRenderer {
let resolve_target = match color_attachment_descriptor.resolve_target {
Some(ref target) => match target.as_str() {
resource::texture::SWAP_CHAIN => Some(&frame.view),
resource_name::texture::SWAP_CHAIN => Some(&frame.view),
_ => Some(&frame.view),
},
None => None,
@ -158,7 +181,7 @@ impl WgpuRenderer {
frame: &'a wgpu::SwapChainOutput,
) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<&'a wgpu::TextureView> {
let attachment = match depth_stencil_attachment_descriptor.attachment.as_str() {
resource::texture::SWAP_CHAIN => &frame.view,
resource_name::texture::SWAP_CHAIN => &frame.view,
_ => self
.textures
.get(&depth_stencil_attachment_descriptor.attachment)
@ -197,7 +220,7 @@ impl Renderer for WgpuRenderer {
.device
.create_swap_chain(self.surface.as_ref().unwrap(), &self.swap_chain_descriptor);
// WgpuRenderer can't own swap_chain without creating lifetime ergonomics issues
// WgpuRenderer can't own swap_chain without creating lifetime ergonomics issues, so lets just store it in World.
world.resources.insert(swap_chain);
}
@ -242,24 +265,36 @@ impl Renderer for WgpuRenderer {
let command_buffer = encoder.finish();
self.queue.submit(&[command_buffer]);
}
fn load_mesh(&mut self, asset_id: usize, mesh: &Mesh) {
if let None = mesh.vertex_buffer {
self.buffers.insert(
format!("meshv{}", asset_id),
self.device
.create_buffer_with_data(mesh.vertices.as_bytes(), wgpu::BufferUsage::VERTEX),
);
}
if let None = mesh.index_buffer {
self.buffers.insert(
format!("meshi{}", asset_id),
self.device
.create_buffer_with_data(mesh.indices.as_bytes(), wgpu::BufferUsage::INDEX),
);
fn create_buffer_with_data(&mut self, data: &[u8], buffer_usage: wgpu::BufferUsage) -> Buffer {
let buffer = self.device.create_buffer_with_data(data, buffer_usage);
// TODO: FILL THIS IN
Buffer {
buffer_usage,
size: data.len() as u64,
id: 0,
}
}
fn free_buffer(&mut self, id: super::ResourceId) -> super::Buffer {
unimplemented!()
}
// fn load_mesh(&mut self, asset_id: usize, mesh: &Mesh) {
// if let None = mesh.vertex_buffer {
// self.buffers.insert(
// format!("meshv{}", asset_id),
// self.device
// .create_buffer_with_data(mesh.vertices.as_bytes(), wgpu::BufferUsage::VERTEX),
// );
// }
// if let None = mesh.index_buffer {
// self.buffers.insert(
// format!("meshi{}", asset_id),
// self.device
// .create_buffer_with_data(mesh.indices.as_bytes(), wgpu::BufferUsage::INDEX),
// );
// }
// }
}
pub struct WgpuRenderPass<'a, 'b, 'c> {
@ -272,3 +307,41 @@ impl<'a, 'b, 'c> RenderPass for WgpuRenderPass<'a, 'b, 'c> {
self.render_pass.set_index_buffer(buffer, offset);
}
}
impl From<TextureDimension> for wgpu::TextureViewDimension {
fn from(dimension: TextureDimension) -> Self {
match dimension {
TextureDimension::D1 => wgpu::TextureViewDimension::D1,
TextureDimension::D2 => wgpu::TextureViewDimension::D2,
TextureDimension::D2Array => wgpu::TextureViewDimension::D2Array,
TextureDimension::Cube => wgpu::TextureViewDimension::Cube,
TextureDimension::CubeArray => wgpu::TextureViewDimension::CubeArray,
TextureDimension::D3 => wgpu::TextureViewDimension::D3,
}
}
}
impl From<&BindType> for wgpu::BindingType {
fn from(bind_type: &BindType) -> Self {
match bind_type {
BindType::Uniform { dynamic, properties: _ } => {
wgpu::BindingType::UniformBuffer { dynamic: *dynamic }
}
BindType::Buffer { dynamic, readonly } => {
wgpu::BindingType::StorageBuffer { dynamic: *dynamic, readonly: *readonly }
}
BindType::SampledTexture {
dimension,
multisampled,
} => wgpu::BindingType::SampledTexture {
dimension: (*dimension).into(),
multisampled: *multisampled,
},
BindType::Sampler => wgpu::BindingType::Sampler,
BindType::StorageTexture { dimension } => {
wgpu::BindingType::StorageTexture { dimension: (*dimension).into() }
},
}
}
}