mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
Make PipelineDescriptor an Asset that references Handle<Shader>
This commit is contained in:
parent
478d475219
commit
4de039eb71
17 changed files with 275 additions and 255 deletions
|
@ -16,7 +16,7 @@ use crate::{
|
|||
};
|
||||
|
||||
use bevy_transform::{prelude::LocalToWorld, transform_system_bundle};
|
||||
use render_graph_2::CompiledShaderMap;
|
||||
use render_graph_2::{CompiledShaderMap, PipelineDescriptor};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct AppBuilder {
|
||||
|
@ -166,6 +166,7 @@ impl AppBuilder {
|
|||
resources.insert(AssetStorage::<Mesh>::new());
|
||||
resources.insert(AssetStorage::<Texture>::new());
|
||||
resources.insert(AssetStorage::<Shader>::new());
|
||||
resources.insert(AssetStorage::<PipelineDescriptor>::new());
|
||||
resources.insert(ShaderAssignments::new());
|
||||
resources.insert(CompiledShaderMap::new());
|
||||
self
|
||||
|
@ -181,17 +182,29 @@ impl AppBuilder {
|
|||
}
|
||||
|
||||
pub fn add_render_graph_defaults(mut self) -> Self {
|
||||
self.render_graph_builder = self
|
||||
.render_graph_builder
|
||||
.add_resource_provider(Box::new(CameraResourceProvider))
|
||||
.add_resource_provider(Box::new(Camera2dResourceProvider))
|
||||
.add_resource_provider(Box::new(LightResourceProvider::new(10)))
|
||||
.add_resource_provider(Box::new(UiResourceProvider::new()))
|
||||
.add_resource_provider(Box::new(UniformResourceProvider::<StandardMaterial>::new()))
|
||||
.add_resource_provider(Box::new(UniformResourceProvider::<LocalToWorld>::new()))
|
||||
.add_forward_pass()
|
||||
.add_forward_pipeline()
|
||||
.add_ui_pipeline();
|
||||
{
|
||||
let mut pipeline_storage = self
|
||||
.world
|
||||
.resources
|
||||
.get_mut::<AssetStorage<PipelineDescriptor>>()
|
||||
.unwrap();
|
||||
let mut shader_storage = self
|
||||
.world
|
||||
.resources
|
||||
.get_mut::<AssetStorage<Shader>>()
|
||||
.unwrap();
|
||||
self.render_graph_builder = self
|
||||
.render_graph_builder
|
||||
.add_resource_provider(Box::new(CameraResourceProvider))
|
||||
.add_resource_provider(Box::new(Camera2dResourceProvider))
|
||||
.add_resource_provider(Box::new(LightResourceProvider::new(10)))
|
||||
.add_resource_provider(Box::new(UiResourceProvider::new()))
|
||||
.add_resource_provider(Box::new(UniformResourceProvider::<StandardMaterial>::new()))
|
||||
.add_resource_provider(Box::new(UniformResourceProvider::<LocalToWorld>::new()))
|
||||
.add_forward_pass()
|
||||
.add_forward_pipeline(&mut pipeline_storage, &mut shader_storage)
|
||||
.add_ui_pipeline(&mut pipeline_storage, &mut shader_storage);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
|
|
@ -3,17 +3,31 @@ mod mesh;
|
|||
mod texture;
|
||||
|
||||
pub use self::gltf::load_gltf;
|
||||
use std::hash::{Hash, Hasher};
|
||||
pub use mesh::*;
|
||||
pub use texture::*;
|
||||
|
||||
use std::{collections::HashMap, marker::PhantomData};
|
||||
|
||||
#[derive(Hash, Eq, PartialEq)]
|
||||
pub struct Handle<T> {
|
||||
pub id: usize,
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Hash for Handle<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialEq for Handle<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Eq for Handle<T> {}
|
||||
|
||||
// TODO: somehow handle this gracefully in asset managers. or alternatively remove Default
|
||||
impl<T> Default for Handle<T> {
|
||||
fn default() -> Self {
|
||||
|
@ -75,11 +89,19 @@ impl<T> AssetStorage<T> {
|
|||
handle
|
||||
}
|
||||
|
||||
pub fn get_id(&mut self, id: usize) -> Option<&mut T> {
|
||||
pub fn get_id(&self, id: usize) -> Option<&T> {
|
||||
self.assets.get(&id)
|
||||
}
|
||||
|
||||
pub fn get_id_mut(&mut self, id: usize) -> Option<&mut T> {
|
||||
self.assets.get_mut(&id)
|
||||
}
|
||||
|
||||
pub fn get(&mut self, handle: &Handle<T>) -> Option<&mut T> {
|
||||
pub fn get(&self, handle: &Handle<T>) -> Option<&T> {
|
||||
self.assets.get(&handle.id)
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, handle: &Handle<T>) -> Option<&mut T> {
|
||||
self.assets.get_mut(&handle.id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ impl Pipeline for ForwardPipeline {
|
|||
}
|
||||
|
||||
if should_load_mesh {
|
||||
if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) {
|
||||
if let Some(mesh_asset) = mesh_storage.get_id_mut(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)]);
|
||||
|
|
|
@ -285,7 +285,7 @@ impl Pipeline for ForwardInstancedPipeline {
|
|||
|
||||
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
for instance_buffer_info in self.instance_buffer_infos.as_ref().unwrap().iter() {
|
||||
if let Some(mesh_asset) = mesh_storage.get_id(instance_buffer_info.mesh_id) {
|
||||
if let Some(mesh_asset) = mesh_storage.get_id_mut(instance_buffer_info.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)]);
|
||||
|
|
|
@ -176,7 +176,7 @@ impl Pipeline for ForwardShadowPassNew {
|
|||
|
||||
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
for (material, mesh) in mesh_query.iter(world) {
|
||||
if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) {
|
||||
if let Some(mesh_asset) = mesh_storage.get_id_mut(mesh.id) {
|
||||
mesh_asset.setup_buffers(&render_graph.device);
|
||||
pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]);
|
||||
pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0);
|
||||
|
|
|
@ -166,7 +166,7 @@ impl Pipeline for ShadowPipeline {
|
|||
|
||||
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
for (material, mesh) in mesh_query.iter(world) {
|
||||
if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) {
|
||||
if let Some(mesh_asset) = mesh_storage.get_id_mut(mesh.id) {
|
||||
mesh_asset.setup_buffers(&render_graph.device);
|
||||
|
||||
pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]);
|
||||
|
|
|
@ -242,7 +242,7 @@ impl Pipeline for UiPipeline {
|
|||
|
||||
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
for instance_buffer_info in instance_buffer_infos.as_ref().unwrap().iter() {
|
||||
if let Some(mesh_asset) = mesh_storage.get_id(instance_buffer_info.mesh_id) {
|
||||
if let Some(mesh_asset) = mesh_storage.get_id_mut(instance_buffer_info.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)]);
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
use zerocopy::AsBytes;
|
||||
|
||||
pub fn mesh_draw_target(world: &World, render_pass: &mut dyn RenderPass) {
|
||||
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
let mut current_mesh_id = None;
|
||||
let mut current_mesh_index_length = 0;
|
||||
let mesh_query = <(Read<ShaderUniforms>, Read<Handle<Mesh>>, Read<Renderable>)>::query()
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
use zerocopy::AsBytes;
|
||||
|
||||
pub fn ui_draw_target(world: &World, render_pass: &mut dyn RenderPass) {
|
||||
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
// NOTE: this is ugly and borrowing is stupid
|
||||
let result = {
|
||||
let renderer = render_pass.get_renderer();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::render::{
|
||||
use crate::{asset::{AssetStorage, Handle}, render::{
|
||||
render_graph_2::{BindGroup, DrawTarget, PipelineLayout},
|
||||
shader::{Shader, ShaderStages},
|
||||
};
|
||||
}};
|
||||
|
||||
pub struct VertexBufferDescriptor {
|
||||
pub stride: wgpu::BufferAddress,
|
||||
|
@ -55,7 +55,7 @@ pub struct PipelineDescriptor {
|
|||
}
|
||||
|
||||
impl PipelineDescriptor {
|
||||
fn new(vertex_shader: Shader) -> Self {
|
||||
fn new(vertex_shader: Handle<Shader>) -> Self {
|
||||
PipelineDescriptor {
|
||||
pipeline_layout: PipelineLayout::new(),
|
||||
color_states: Vec::new(),
|
||||
|
@ -80,19 +80,22 @@ impl PipelineDescriptor {
|
|||
}
|
||||
|
||||
impl PipelineDescriptor {
|
||||
pub fn build(vertex_shader: Shader) -> PipelineBuilder {
|
||||
PipelineBuilder::new(vertex_shader)
|
||||
pub fn build(shader_storage: &mut AssetStorage<Shader>, vertex_shader: Shader) -> PipelineBuilder {
|
||||
PipelineBuilder::new(shader_storage, vertex_shader)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PipelineBuilder {
|
||||
pub struct PipelineBuilder<'a> {
|
||||
pipeline: PipelineDescriptor,
|
||||
shader_storage: &'a mut AssetStorage<Shader>,
|
||||
}
|
||||
|
||||
impl PipelineBuilder {
|
||||
pub fn new(vertex_shader: Shader) -> Self {
|
||||
impl<'a> PipelineBuilder<'a> {
|
||||
pub fn new(shader_storage: &'a mut AssetStorage<Shader>, vertex_shader: Shader) -> Self {
|
||||
let vertex_shader_handle = shader_storage.add(vertex_shader);
|
||||
PipelineBuilder {
|
||||
pipeline: PipelineDescriptor::new(vertex_shader),
|
||||
pipeline: PipelineDescriptor::new(vertex_shader_handle),
|
||||
shader_storage,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +104,8 @@ impl PipelineBuilder {
|
|||
}
|
||||
|
||||
pub fn with_fragment_shader(mut self, fragment_shader: Shader) -> Self {
|
||||
self.pipeline.shader_stages.fragment = Some(fragment_shader);
|
||||
let fragment_shader_handle = self.shader_storage.add(fragment_shader);
|
||||
self.pipeline.shader_stages.fragment = Some(fragment_shader_handle);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
use crate::render::{
|
||||
use crate::{asset::AssetStorage, render::{
|
||||
render_graph_2::{
|
||||
draw_targets::mesh_draw_target, pipeline_layout::*, PipelineDescriptor, RenderGraphBuilder,
|
||||
},
|
||||
shader::{Shader, ShaderStage},
|
||||
Vertex,
|
||||
};
|
||||
}};
|
||||
pub trait ForwardPipelineBuilder {
|
||||
fn add_forward_pipeline(self) -> Self;
|
||||
fn add_forward_pipeline(self, pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, shader_storage: &mut AssetStorage<Shader>) -> Self;
|
||||
}
|
||||
|
||||
impl ForwardPipelineBuilder for RenderGraphBuilder {
|
||||
fn add_forward_pipeline(self) -> Self {
|
||||
fn add_forward_pipeline(self, pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, shader_storage: &mut AssetStorage<Shader>) -> Self {
|
||||
self.add_pipeline(
|
||||
"forward",
|
||||
PipelineDescriptor::build(Shader::from_glsl(
|
||||
include_str!("forward.vert"),
|
||||
ShaderStage::Vertex,
|
||||
))
|
||||
pipeline_descriptor_storage,
|
||||
PipelineDescriptor::build(
|
||||
shader_storage,
|
||||
Shader::from_glsl(include_str!("forward.vert"), ShaderStage::Vertex),
|
||||
)
|
||||
.with_fragment_shader(Shader::from_glsl(
|
||||
include_str!("forward.frag"),
|
||||
ShaderStage::Fragment,
|
||||
|
|
|
@ -1,22 +1,35 @@
|
|||
use crate::render::{
|
||||
render_graph_2::{
|
||||
draw_targets::mesh_draw_target, pipeline_layout::*, PipelineDescriptor, RenderGraphBuilder,
|
||||
use crate::{
|
||||
asset::AssetStorage,
|
||||
render::{
|
||||
render_graph_2::{
|
||||
draw_targets::mesh_draw_target, pipeline_layout::*, PipelineDescriptor,
|
||||
RenderGraphBuilder,
|
||||
},
|
||||
shader::{Shader, ShaderStage},
|
||||
Vertex,
|
||||
},
|
||||
shader::{Shader, ShaderStage},
|
||||
Vertex,
|
||||
};
|
||||
|
||||
pub trait ForwardFlatPipelineBuilder {
|
||||
fn add_forward_flat_pipeline(self) -> Self;
|
||||
fn add_forward_flat_pipeline(
|
||||
self,
|
||||
pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>,
|
||||
shader_storage: &mut AssetStorage<Shader>,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
impl ForwardFlatPipelineBuilder for RenderGraphBuilder {
|
||||
fn add_forward_flat_pipeline(self) -> Self {
|
||||
fn add_forward_flat_pipeline(
|
||||
self,
|
||||
pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>,
|
||||
shader_storage: &mut AssetStorage<Shader>,
|
||||
) -> Self {
|
||||
self.add_pipeline(
|
||||
"forward_flat",
|
||||
PipelineDescriptor::build(Shader::from_glsl(
|
||||
include_str!("forward_flat.vert"),
|
||||
ShaderStage::Vertex,
|
||||
))
|
||||
pipeline_descriptor_storage,
|
||||
PipelineDescriptor::build(
|
||||
shader_storage,
|
||||
Shader::from_glsl(include_str!("forward_flat.vert"), ShaderStage::Vertex),
|
||||
)
|
||||
.with_fragment_shader(Shader::from_glsl(
|
||||
include_str!("forward_flat.frag"),
|
||||
ShaderStage::Fragment,
|
||||
|
|
|
@ -1,23 +1,34 @@
|
|||
use crate::render::{
|
||||
render_graph_2::{
|
||||
draw_targets::ui_draw_target, pipeline_layout::*, resource_providers::RectData,
|
||||
PipelineDescriptor, RenderGraphBuilder, VertexBufferDescriptor,
|
||||
use crate::{
|
||||
asset::AssetStorage,
|
||||
render::{
|
||||
render_graph_2::{
|
||||
draw_targets::ui_draw_target, pipeline_layout::*, resource_providers::RectData,
|
||||
PipelineDescriptor, RenderGraphBuilder, VertexBufferDescriptor,
|
||||
},
|
||||
shader::{Shader, ShaderStage},
|
||||
Vertex,
|
||||
},
|
||||
shader::{Shader, ShaderStage},
|
||||
Vertex,
|
||||
};
|
||||
pub trait UiPipelineBuilder {
|
||||
fn add_ui_pipeline(self) -> Self;
|
||||
fn add_ui_pipeline(
|
||||
self,
|
||||
pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>,
|
||||
shader_storage: &mut AssetStorage<Shader>,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
impl UiPipelineBuilder for RenderGraphBuilder {
|
||||
fn add_ui_pipeline(self) -> Self {
|
||||
fn add_ui_pipeline(
|
||||
self,
|
||||
pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>,
|
||||
shader_storage: &mut AssetStorage<Shader>,
|
||||
) -> Self {
|
||||
self.add_pipeline(
|
||||
"ui",
|
||||
PipelineDescriptor::build(Shader::from_glsl(
|
||||
include_str!("ui.vert"),
|
||||
ShaderStage::Vertex,
|
||||
))
|
||||
pipeline_descriptor_storage,
|
||||
PipelineDescriptor::build(
|
||||
shader_storage,
|
||||
Shader::from_glsl(include_str!("ui.vert"), ShaderStage::Vertex),
|
||||
)
|
||||
.with_fragment_shader(Shader::from_glsl(
|
||||
include_str!("ui.frag"),
|
||||
ShaderStage::Fragment,
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
use crate::render::render_graph_2::{
|
||||
PassDescriptor, PipelineDescriptor, ResourceProvider, TextureDescriptor,
|
||||
use crate::{
|
||||
asset::{AssetStorage, Handle},
|
||||
render::{
|
||||
render_graph_2::{PassDescriptor, PipelineDescriptor, ResourceProvider, TextureDescriptor},
|
||||
},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
pub struct RenderGraph {
|
||||
pub pipeline_descriptors: HashMap<String, PipelineDescriptor>,
|
||||
pub pipeline_descriptors: HashSet<Handle<PipelineDescriptor>>,
|
||||
// TODO: make this ordered
|
||||
pub pass_descriptors: HashMap<String, PassDescriptor>,
|
||||
pub pass_pipelines: HashMap<String, Vec<String>>,
|
||||
pub pass_pipelines: HashMap<String, Vec<Handle<PipelineDescriptor>>>,
|
||||
pub resource_providers: Vec<Box<dyn ResourceProvider>>,
|
||||
pub queued_textures: Vec<(String, TextureDescriptor)>,
|
||||
}
|
||||
|
@ -15,7 +18,7 @@ pub struct RenderGraph {
|
|||
impl Default for RenderGraph {
|
||||
fn default() -> Self {
|
||||
RenderGraph {
|
||||
pipeline_descriptors: HashMap::new(),
|
||||
pipeline_descriptors: HashSet::new(),
|
||||
pass_descriptors: HashMap::new(),
|
||||
pass_pipelines: HashMap::new(),
|
||||
resource_providers: Vec::new(),
|
||||
|
@ -24,9 +27,23 @@ impl Default for RenderGraph {
|
|||
}
|
||||
}
|
||||
|
||||
impl RenderGraph {
|
||||
pub fn add_pipeline(&mut self, pass: &str, pipeline: Handle<PipelineDescriptor>) {
|
||||
self.pipeline_descriptors.insert(pipeline.clone());
|
||||
|
||||
if let None = self.pass_pipelines.get(pass) {
|
||||
self.pass_pipelines.insert(pass.to_string(), Vec::new());
|
||||
}
|
||||
|
||||
let pass_pipelines = self.pass_pipelines.get_mut(pass).unwrap();
|
||||
pass_pipelines.push(pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RenderGraphBuilder {
|
||||
render_graph: RenderGraph,
|
||||
current_pass: Option<String>,
|
||||
|
||||
}
|
||||
|
||||
impl RenderGraphBuilder {
|
||||
|
@ -45,24 +62,10 @@ impl RenderGraphBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn add_pipeline(mut self, name: &str, pipeline: PipelineDescriptor) -> Self {
|
||||
self.render_graph
|
||||
.pipeline_descriptors
|
||||
.insert(name.to_string(), pipeline);
|
||||
|
||||
if let Some(current_pass) = self.current_pass.as_ref() {
|
||||
if let None = self.render_graph.pass_pipelines.get(current_pass) {
|
||||
self.render_graph
|
||||
.pass_pipelines
|
||||
.insert(current_pass.to_string(), Vec::new());
|
||||
}
|
||||
|
||||
let pass_pipelines = self
|
||||
.render_graph
|
||||
.pass_pipelines
|
||||
.get_mut(current_pass)
|
||||
.unwrap();
|
||||
pass_pipelines.push(name.to_string());
|
||||
pub fn add_pipeline(mut self, pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, pipeline: PipelineDescriptor) -> Self {
|
||||
if let Some(ref pass) = self.current_pass {
|
||||
let pipeline_descriptor_handle = pipeline_descriptor_storage.add(pipeline);
|
||||
self.render_graph.add_pipeline(&pass, pipeline_descriptor_handle);
|
||||
}
|
||||
|
||||
self
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
use crate::{
|
||||
asset::{AssetStorage, Handle},
|
||||
render::{render_graph_2::RenderGraph, Shader},
|
||||
render::{render_graph_2::RenderGraph, Shader, ShaderStages},
|
||||
};
|
||||
use legion::prelude::*;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use super::PipelineDescriptor;
|
||||
|
||||
pub struct Renderable {
|
||||
pub is_visible: bool,
|
||||
pub shaders: Vec<Handle<Shader>>,
|
||||
pub pipelines: Vec<Handle<PipelineDescriptor>>,
|
||||
pub shader_defs: HashSet<String>,
|
||||
}
|
||||
|
||||
|
@ -15,7 +16,7 @@ impl Default for Renderable {
|
|||
fn default() -> Self {
|
||||
Renderable {
|
||||
is_visible: true,
|
||||
shaders: Vec::new(),
|
||||
pipelines: Vec::new(),
|
||||
shader_defs: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
@ -53,24 +54,28 @@ pub fn update_shader_assignments(world: &mut World, render_graph: &mut RenderGra
|
|||
let shader_assignments = world.resources.get_mut::<ShaderAssignments>().unwrap();
|
||||
let mut compiled_shader_map = world.resources.get_mut::<CompiledShaderMap>().unwrap();
|
||||
let mut shader_storage = world.resources.get_mut::<AssetStorage<Shader>>().unwrap();
|
||||
let pipeline_descriptor_storage = world.resources.get_mut::<AssetStorage<PipelineDescriptor>>().unwrap();
|
||||
for (entity, renderable) in <Read<Renderable>>::query().iter_entities(world) {
|
||||
for shader in renderable.shaders.iter() {
|
||||
if let None = compiled_shader_map.source_to_compiled.get(shader) {
|
||||
compiled_shader_map
|
||||
.source_to_compiled
|
||||
.insert(shader.clone(), Vec::new());
|
||||
}
|
||||
for pipeline_handle in renderable.pipelines.iter() {
|
||||
let pipeline_descriptor = pipeline_descriptor_storage.get(pipeline_handle).unwrap();
|
||||
for shader_handle in pipeline_descriptor.shader_stages.iter() {
|
||||
if let None = compiled_shader_map.source_to_compiled.get(shader_handle) {
|
||||
compiled_shader_map
|
||||
.source_to_compiled
|
||||
.insert(shader_handle.clone(), Vec::new());
|
||||
}
|
||||
|
||||
let compiled_shaders = compiled_shader_map.source_to_compiled.get_mut(shader).unwrap();
|
||||
if let None = compiled_shaders.iter().find(|(shader_defs, _shader)| *shader_defs == renderable.shader_defs) {
|
||||
let shader_resource = shader_storage.get(shader).unwrap();
|
||||
let shader_def_vec = renderable.shader_defs.iter().cloned().collect::<Vec<String>>();
|
||||
let compiled_shader = shader_resource.get_spirv_shader(Some(&shader_def_vec));
|
||||
compiled_shaders.push((renderable.shader_defs.clone(), shader.clone()));
|
||||
let compiled_shader_handle = shader_storage.add(compiled_shader);
|
||||
// TODO: collecting assigments in a map means they won't be removed when the macro changes
|
||||
// TODO: need to somehow grab base shader's pipeline, then copy it
|
||||
// shader_assignments.assignments.insert()
|
||||
let compiled_shaders = compiled_shader_map.source_to_compiled.get_mut(shader_handle).unwrap();
|
||||
if let None = compiled_shaders.iter().find(|(shader_defs, _shader)| *shader_defs == renderable.shader_defs) {
|
||||
let shader_resource = shader_storage.get(shader_handle).unwrap();
|
||||
let shader_def_vec = renderable.shader_defs.iter().cloned().collect::<Vec<String>>();
|
||||
let compiled_shader = shader_resource.get_spirv_shader(Some(&shader_def_vec));
|
||||
compiled_shaders.push((renderable.shader_defs.clone(), shader_handle.clone()));
|
||||
let compiled_shader_handle = shader_storage.add(compiled_shader);
|
||||
// TODO: collecting assigments in a map means they won't be removed when the macro changes
|
||||
// TODO: need to somehow grab base shader's pipeline, then copy it
|
||||
// shader_assignments.assignments.insert()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
use crate::{
|
||||
asset::{AssetStorage, Handle},
|
||||
legion::prelude::*,
|
||||
render::{Shader, render_graph_2::{
|
||||
resource_name, update_shader_assignments, BindGroup, BindType, DynamicUniformBufferInfo,
|
||||
PassDescriptor, PipelineDescriptor, RenderGraph, RenderPass,
|
||||
RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor, Renderer,
|
||||
ResourceInfo, ShaderUniforms, TextureDescriptor,
|
||||
}},
|
||||
render::{
|
||||
render_graph_2::{
|
||||
resource_name, update_shader_assignments, BindGroup, BindType,
|
||||
DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, RenderGraph, RenderPass,
|
||||
RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor,
|
||||
Renderer, ResourceInfo, TextureDescriptor,
|
||||
},
|
||||
Shader,
|
||||
},
|
||||
};
|
||||
use std::{collections::HashMap, ops::Deref};
|
||||
|
||||
|
@ -15,7 +19,7 @@ pub struct WgpuRenderer {
|
|||
pub surface: Option<wgpu::Surface>,
|
||||
pub encoder: Option<wgpu::CommandEncoder>,
|
||||
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
|
||||
pub render_pipelines: HashMap<String, wgpu::RenderPipeline>,
|
||||
pub render_pipelines: HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
|
||||
pub buffers: HashMap<String, wgpu::Buffer>,
|
||||
pub textures: HashMap<String, wgpu::TextureView>,
|
||||
pub resource_info: HashMap<String, ResourceInfo>,
|
||||
|
@ -69,12 +73,14 @@ impl WgpuRenderer {
|
|||
pipeline_descriptor: &mut PipelineDescriptor,
|
||||
bind_group_layouts: &mut HashMap<u64, wgpu::BindGroupLayout>,
|
||||
device: &wgpu::Device,
|
||||
vertex_shader: &Shader,
|
||||
fragment_shader: Option<&Shader>,
|
||||
) -> wgpu::RenderPipeline {
|
||||
let vertex_shader_module = Self::create_shader_module(device, &pipeline_descriptor
|
||||
.shader_stages
|
||||
.vertex, None);
|
||||
let fragment_shader_module = match pipeline_descriptor.shader_stages.fragment {
|
||||
Some(ref fragment_shader) => Some(Self::create_shader_module(device, fragment_shader, None)),
|
||||
let vertex_shader_module = Self::create_shader_module(device, vertex_shader, None);
|
||||
let fragment_shader_module = match fragment_shader {
|
||||
Some(fragment_shader) => {
|
||||
Some(Self::create_shader_module(device, fragment_shader, None))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
|
@ -121,10 +127,10 @@ impl WgpuRenderer {
|
|||
layout: &pipeline_layout,
|
||||
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
||||
module: &vertex_shader_module,
|
||||
entry_point: &pipeline_descriptor.shader_stages.vertex.entry_point,
|
||||
entry_point: &vertex_shader.entry_point,
|
||||
},
|
||||
fragment_stage: match pipeline_descriptor.shader_stages.fragment {
|
||||
Some(ref fragment_shader) => Some(wgpu::ProgrammableStageDescriptor {
|
||||
fragment_stage: match fragment_shader {
|
||||
Some(fragment_shader) => Some(wgpu::ProgrammableStageDescriptor {
|
||||
entry_point: &fragment_shader.entry_point,
|
||||
module: fragment_shader_module.as_ref().unwrap(),
|
||||
}),
|
||||
|
@ -303,115 +309,11 @@ impl WgpuRenderer {
|
|||
bind_group_id
|
||||
}
|
||||
|
||||
// TODO: remove me
|
||||
#[allow(dead_code)]
|
||||
fn setup_dynamic_entity_shader_uniforms(
|
||||
&mut self,
|
||||
world: &World,
|
||||
render_graph: &RenderGraph,
|
||||
encoder: &mut wgpu::CommandEncoder,
|
||||
) {
|
||||
// retrieve all uniforms buffers that aren't aleady set. these are "dynamic" uniforms, which are set by the user in ShaderUniforms
|
||||
// TODO: this breaks down in multiple ways:
|
||||
// (1) resource_info will be set after the first run so this won't update.
|
||||
// (2) if we create new buffers, the old bind groups will be invalid
|
||||
for pipeline in render_graph.pipeline_descriptors.values() {
|
||||
for bind_group in pipeline.pipeline_layout.bind_groups.iter() {
|
||||
for binding in bind_group.bindings.iter() {
|
||||
// if let None = self.resource_info.get(&binding.name) {
|
||||
if let BindType::Uniform { dynamic: true, .. } = &binding.bind_type {
|
||||
if self.dynamic_uniform_buffer_info.contains_key(&binding.name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
self.dynamic_uniform_buffer_info.insert(
|
||||
binding.name.to_string(),
|
||||
DynamicUniformBufferInfo {
|
||||
capacity: 0,
|
||||
count: 0,
|
||||
size: binding.bind_type.get_uniform_size().unwrap(),
|
||||
indices: HashMap::new(),
|
||||
offsets: HashMap::new(),
|
||||
},
|
||||
);
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// count the number of entities providing each uniform
|
||||
for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() {
|
||||
info.count = 0;
|
||||
for (entity, shader_uniforms) in <Read<ShaderUniforms>>::query().iter_entities(world) {
|
||||
if let Some(_) = shader_uniforms.get_uniform_info(world, entity, name) {
|
||||
info.count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// allocate uniform buffers
|
||||
for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() {
|
||||
if self.buffers.contains_key(name) && info.count < info.capacity {
|
||||
continue;
|
||||
}
|
||||
|
||||
if info.count >= info.capacity && info.capacity != 0 {
|
||||
panic!("resizing dynamic uniform buffers isn't supported yet. we still need to support updating bind groups");
|
||||
}
|
||||
|
||||
// allocate enough space for twice as many entities as there are currently;
|
||||
info.capacity = info.count * 2;
|
||||
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.capacity;
|
||||
|
||||
// TODO: remove this code duplication in favor of self.create_buffer(). this will likely require a refactor
|
||||
// the following is a flattening of the content in self.create_buffer(), which can't be called because
|
||||
// of rust's ownership rules. sometimes rust makes me unhappy
|
||||
|
||||
let buffer_usage = wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM;
|
||||
let buffer = self.device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size,
|
||||
usage: buffer_usage,
|
||||
});
|
||||
|
||||
self.resource_info.insert(
|
||||
name.to_string(),
|
||||
ResourceInfo::Buffer { buffer_usage, size },
|
||||
);
|
||||
|
||||
self.buffers.insert(name.to_string(), buffer);
|
||||
}
|
||||
|
||||
// copy entity uniform data to buffers
|
||||
for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() {
|
||||
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.count;
|
||||
let mapped = self
|
||||
.device
|
||||
.create_buffer_mapped(size as usize, wgpu::BufferUsage::COPY_SRC);
|
||||
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
|
||||
let mut offset = 0usize;
|
||||
|
||||
for (i, (entity, shader_uniforms)) in <Read<ShaderUniforms>>::query()
|
||||
.iter_entities(world)
|
||||
.enumerate()
|
||||
{
|
||||
// TODO: check if index has changed. if it has, then entity should be updated
|
||||
// TODO: only mem-map entities if their data has changed
|
||||
info.offsets.insert(entity, offset as u64);
|
||||
info.indices.insert(i, entity);
|
||||
if let Some(bytes) = shader_uniforms.get_uniform_bytes(world, entity, name) {
|
||||
mapped.data[offset..(offset + bytes.len())].copy_from_slice(bytes.as_slice());
|
||||
offset += alignment;
|
||||
}
|
||||
}
|
||||
|
||||
let temp_buffer = mapped.finish();
|
||||
let uniform_buffer = self.buffers.get(name);
|
||||
encoder.copy_buffer_to_buffer(&temp_buffer, 0, uniform_buffer.unwrap(), 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_shader_module(device: &wgpu::Device, shader: &Shader, macros: Option<&[String]>) -> wgpu::ShaderModule {
|
||||
pub fn create_shader_module(
|
||||
device: &wgpu::Device,
|
||||
shader: &Shader,
|
||||
macros: Option<&[String]>,
|
||||
) -> wgpu::ShaderModule {
|
||||
device.create_shader_module(&shader.get_spirv(macros))
|
||||
}
|
||||
}
|
||||
|
@ -489,16 +391,38 @@ impl Renderer for WgpuRenderer {
|
|||
// self.setup_dynamic_entity_shader_uniforms(world, render_graph, &mut encoder);
|
||||
|
||||
// setup, pipelines, bind groups, and resources
|
||||
for (pipeline_name, pipeline_descriptor) in render_graph.pipeline_descriptors.iter_mut() {
|
||||
let mut pipeline_storage = world
|
||||
.resources
|
||||
.get_mut::<AssetStorage<PipelineDescriptor>>()
|
||||
.unwrap();
|
||||
let shader_storage = world.resources.get::<AssetStorage<Shader>>().unwrap();
|
||||
|
||||
for pipeline_descriptor_handle in render_graph.pipeline_descriptors.iter() {
|
||||
let pipeline_descriptor = pipeline_storage
|
||||
.get_mut(pipeline_descriptor_handle)
|
||||
.unwrap();
|
||||
// create pipelines
|
||||
if let None = self.render_pipelines.get(pipeline_name) {
|
||||
if !self
|
||||
.render_pipelines
|
||||
.contains_key(pipeline_descriptor_handle)
|
||||
{
|
||||
let vertex_shader = shader_storage
|
||||
.get(&pipeline_descriptor.shader_stages.vertex)
|
||||
.unwrap();
|
||||
let fragment_shader = pipeline_descriptor
|
||||
.shader_stages
|
||||
.fragment
|
||||
.as_ref()
|
||||
.map(|handle| &*shader_storage.get(&handle).unwrap());
|
||||
let render_pipeline = WgpuRenderer::create_render_pipeline(
|
||||
pipeline_descriptor,
|
||||
&mut self.bind_group_layouts,
|
||||
&self.device,
|
||||
vertex_shader,
|
||||
fragment_shader,
|
||||
);
|
||||
self.render_pipelines
|
||||
.insert(pipeline_name.to_string(), render_pipeline);
|
||||
.insert(pipeline_descriptor_handle.clone(), render_pipeline);
|
||||
}
|
||||
|
||||
// create bind groups
|
||||
|
@ -512,21 +436,18 @@ impl Renderer for WgpuRenderer {
|
|||
let mut render_pass = self.create_render_pass(pass_descriptor, &mut encoder, &frame);
|
||||
if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) {
|
||||
for pass_pipeline in pass_pipelines.iter() {
|
||||
if let Some(pipeline_descriptor) =
|
||||
render_graph.pipeline_descriptors.get(pass_pipeline)
|
||||
{
|
||||
let render_pipeline = self.render_pipelines.get(pass_pipeline).unwrap();
|
||||
render_pass.set_pipeline(render_pipeline);
|
||||
let pipeline_descriptor = pipeline_storage.get(pass_pipeline).unwrap();
|
||||
let render_pipeline = self.render_pipelines.get(pass_pipeline).unwrap();
|
||||
render_pass.set_pipeline(render_pipeline);
|
||||
|
||||
let mut render_pass = WgpuRenderPass {
|
||||
render_pass: &mut render_pass,
|
||||
renderer: self,
|
||||
pipeline_descriptor,
|
||||
};
|
||||
let mut render_pass = WgpuRenderPass {
|
||||
render_pass: &mut render_pass,
|
||||
renderer: self,
|
||||
pipeline_descriptor,
|
||||
};
|
||||
|
||||
for draw_target in pipeline_descriptor.draw_targets.iter() {
|
||||
draw_target(world, &mut render_pass);
|
||||
}
|
||||
for draw_target in pipeline_descriptor.draw_targets.iter() {
|
||||
draw_target(world, &mut render_pass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::asset::Handle;
|
||||
use std::marker::Copy;
|
||||
|
||||
#[derive(Hash, Eq, PartialEq, Copy, Clone)]
|
||||
|
@ -69,9 +70,7 @@ impl Shader {
|
|||
pub fn get_spirv(&self, macros: Option<&[String]>) -> Vec<u32> {
|
||||
match self.source {
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,15 +84,44 @@ impl Shader {
|
|||
}
|
||||
|
||||
pub struct ShaderStages {
|
||||
pub vertex: Shader,
|
||||
pub fragment: Option<Shader>,
|
||||
pub vertex: Handle<Shader>,
|
||||
pub fragment: Option<Handle<Shader>>,
|
||||
}
|
||||
|
||||
impl ShaderStages {
|
||||
pub fn new(vertex_shader: Shader) -> Self {
|
||||
pub fn new(vertex_shader: Handle<Shader>) -> Self {
|
||||
ShaderStages {
|
||||
vertex: vertex_shader,
|
||||
fragment: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> ShaderStagesIter {
|
||||
ShaderStagesIter {
|
||||
shader_stages: self,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ShaderStagesIter<'a> {
|
||||
pub shader_stages: &'a ShaderStages,
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ShaderStagesIter<'a> {
|
||||
type Item = &'a Handle<Shader>;
|
||||
fn next(&mut self) -> Option<&'a Handle<Shader>> {
|
||||
match self.index {
|
||||
0 => Some(&self.shader_stages.vertex),
|
||||
1 => {
|
||||
if let Some(ref fragment) = self.shader_stages.fragment {
|
||||
Some(fragment)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue