refactor pipeline compilation into PipelineCompiler
This commit is contained in:
parent
d1db46ef54
commit
0073f4a58b
@ -12,6 +12,8 @@ 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)
|
||||||
* Inject layout set/bindings into shader source so they don't need to be defined in-shader. Specify set / binding indices in resource providers?
|
* Inject layout set/bindings into shader source so they don't need to be defined in-shader. Specify set / binding indices in resource providers?
|
||||||
* Pull as much logic as possible from wgpu_renderer into a "render orchestrator" struct/trait
|
* Pull as much logic as possible from wgpu_renderer into a "render orchestrator" struct/trait
|
||||||
|
* Separate original/uncompiled/no_defs PipelineDescriptor from compiled PipelineDescriptor conceptually
|
||||||
|
* Try to make Renderer a resource + system
|
||||||
* Docs
|
* Docs
|
||||||
* Add doc comments to code
|
* Add doc comments to code
|
||||||
* Add tutorials
|
* Add tutorials
|
||||||
|
|||||||
@ -6,7 +6,11 @@ use winit::{
|
|||||||
|
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
|
|
||||||
use crate::{app::AppBuilder, core::{Window, Time}, render::renderer::Renderer};
|
use crate::{
|
||||||
|
app::AppBuilder,
|
||||||
|
core::{Time, Window},
|
||||||
|
render::renderer::Renderer,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
pub universe: Universe,
|
pub universe: Universe,
|
||||||
@ -90,7 +94,12 @@ impl App {
|
|||||||
window.height = size.height;
|
window.height = size.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.resize(&mut self.world, &mut self.resources, size.width, size.height);
|
renderer.resize(
|
||||||
|
&mut self.world,
|
||||||
|
&mut self.resources,
|
||||||
|
size.width,
|
||||||
|
size.height,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
println!("no renderer {} {}", size.width, size.height);
|
println!("no renderer {} {}", size.width, size.height);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,10 +13,11 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use bevy_transform::{prelude::LocalToWorld, transform_system_bundle};
|
use bevy_transform::{prelude::LocalToWorld, transform_system_bundle};
|
||||||
use pipeline::PipelineDescriptor;
|
use pipeline::{PipelineCompiler, PipelineDescriptor, ShaderPipelineAssignments};
|
||||||
use render_graph::{RenderGraph, RenderGraphBuilder};
|
use render_graph::{RenderGraph, RenderGraphBuilder};
|
||||||
use render_resource::{
|
use render_resource::{
|
||||||
build_entity_render_resource_assignments_system, AssetBatchers, EntityRenderResourceAssignments,
|
build_entity_render_resource_assignments_system, AssetBatchers,
|
||||||
|
EntityRenderResourceAssignments, RenderResourceAssignments,
|
||||||
};
|
};
|
||||||
use shader::Shader;
|
use shader::Shader;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -165,7 +166,8 @@ impl AppBuilder {
|
|||||||
resources.insert(AssetStorage::<StandardMaterial>::new());
|
resources.insert(AssetStorage::<StandardMaterial>::new());
|
||||||
resources.insert(AssetStorage::<PipelineDescriptor>::new());
|
resources.insert(AssetStorage::<PipelineDescriptor>::new());
|
||||||
resources.insert(ShaderPipelineAssignments::new());
|
resources.insert(ShaderPipelineAssignments::new());
|
||||||
resources.insert(CompiledShaderMap::new());
|
resources.insert(PipelineCompiler::new());
|
||||||
|
resources.insert(RenderResourceAssignments::default());
|
||||||
resources.insert(EntityRenderResourceAssignments::default());
|
resources.insert(EntityRenderResourceAssignments::default());
|
||||||
self.batch_types2::<Mesh, StandardMaterial>();
|
self.batch_types2::<Mesh, StandardMaterial>();
|
||||||
self
|
self
|
||||||
@ -212,11 +214,11 @@ impl AppBuilder {
|
|||||||
.add_resource_provider(LightResourceProvider::new(10))
|
.add_resource_provider(LightResourceProvider::new(10))
|
||||||
.add_resource_provider(UiResourceProvider::new())
|
.add_resource_provider(UiResourceProvider::new())
|
||||||
.add_resource_provider(MeshResourceProvider::new())
|
.add_resource_provider(MeshResourceProvider::new())
|
||||||
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(true))
|
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(false))
|
||||||
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(true))
|
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(false))
|
||||||
.add_forward_pass()
|
.add_forward_pass()
|
||||||
.add_forward_pipeline()
|
.add_forward_pipeline();
|
||||||
.add_ui_pipeline();
|
// .add_ui_pipeline();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
pub struct Window {
|
pub struct Window {
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
pub height: u32,
|
pub height: u32,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,10 +4,12 @@ use crate::{
|
|||||||
render::{
|
render::{
|
||||||
draw_target::DrawTarget,
|
draw_target::DrawTarget,
|
||||||
mesh::Mesh,
|
mesh::Mesh,
|
||||||
pipeline::PipelineDescriptor,
|
pipeline::{PipelineDescriptor, ShaderPipelineAssignments},
|
||||||
render_resource::{resource_name, EntityRenderResourceAssignments, ResourceInfo},
|
render_resource::{
|
||||||
|
resource_name, EntityRenderResourceAssignments, RenderResourceAssignments, ResourceInfo,
|
||||||
|
},
|
||||||
renderer::{RenderPass, Renderer},
|
renderer::{RenderPass, Renderer},
|
||||||
Renderable, ShaderPipelineAssignments,
|
Renderable,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,6 +29,9 @@ impl DrawTarget for AssignedMeshesDrawTarget {
|
|||||||
resources.get::<EntityRenderResourceAssignments>().unwrap();
|
resources.get::<EntityRenderResourceAssignments>().unwrap();
|
||||||
let mut current_mesh_handle = None;
|
let mut current_mesh_handle = None;
|
||||||
let mut current_mesh_index_len = 0;
|
let mut current_mesh_index_len = 0;
|
||||||
|
let global_render_resource_assignments =
|
||||||
|
resources.get::<RenderResourceAssignments>().unwrap();
|
||||||
|
render_pass.set_render_resources(&global_render_resource_assignments);
|
||||||
|
|
||||||
let assigned_render_resource_assignments = shader_pipeline_assignments
|
let assigned_render_resource_assignments = shader_pipeline_assignments
|
||||||
.assignments
|
.assignments
|
||||||
@ -87,6 +92,9 @@ impl DrawTarget for AssignedMeshesDrawTarget {
|
|||||||
.get(&pipeline_handle);
|
.get(&pipeline_handle);
|
||||||
let pipeline_storage = resources.get::<AssetStorage<PipelineDescriptor>>().unwrap();
|
let pipeline_storage = resources.get::<AssetStorage<PipelineDescriptor>>().unwrap();
|
||||||
let pipeline_descriptor = pipeline_storage.get(&pipeline_handle).unwrap();
|
let pipeline_descriptor = pipeline_storage.get(&pipeline_handle).unwrap();
|
||||||
|
let mut global_render_resource_assignments =
|
||||||
|
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||||
|
renderer.setup_bind_groups(&mut global_render_resource_assignments, pipeline_descriptor);
|
||||||
if let Some(assigned_render_resource_assignments) = assigned_render_resource_assignments {
|
if let Some(assigned_render_resource_assignments) = assigned_render_resource_assignments {
|
||||||
for assignment_id in assigned_render_resource_assignments.iter() {
|
for assignment_id in assigned_render_resource_assignments.iter() {
|
||||||
// TODO: hopefully legion has better random access apis that are more like queries?
|
// TODO: hopefully legion has better random access apis that are more like queries?
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
asset::{Asset, Handle},
|
asset::{Asset, AssetStorage, Handle},
|
||||||
legion::prelude::*,
|
legion::prelude::*,
|
||||||
math,
|
math,
|
||||||
prelude::MeshType,
|
prelude::MeshType,
|
||||||
@ -7,7 +7,10 @@ use crate::{
|
|||||||
draw_target::DrawTarget,
|
draw_target::DrawTarget,
|
||||||
mesh::Mesh,
|
mesh::Mesh,
|
||||||
pipeline::PipelineDescriptor,
|
pipeline::PipelineDescriptor,
|
||||||
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResource, ResourceInfo},
|
render_resource::{
|
||||||
|
resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
|
||||||
|
ResourceInfo,
|
||||||
|
},
|
||||||
renderer::{RenderPass, Renderer},
|
renderer::{RenderPass, Renderer},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -30,12 +33,9 @@ impl DrawTarget for UiDrawTarget {
|
|||||||
render_pass: &mut dyn RenderPass,
|
render_pass: &mut dyn RenderPass,
|
||||||
_pipeline_handle: Handle<PipelineDescriptor>,
|
_pipeline_handle: Handle<PipelineDescriptor>,
|
||||||
) {
|
) {
|
||||||
|
let render_resource_assignments = resources.get::<RenderResourceAssignments>().unwrap();
|
||||||
let ui_instances_buffer = {
|
let ui_instances_buffer = {
|
||||||
let renderer = render_pass.get_renderer();
|
match render_resource_assignments.get(resource_name::buffer::UI_INSTANCES) {
|
||||||
match renderer
|
|
||||||
.get_render_resources()
|
|
||||||
.get_named_resource(resource_name::buffer::UI_INSTANCES)
|
|
||||||
{
|
|
||||||
Some(buffer) => buffer,
|
Some(buffer) => buffer,
|
||||||
None => return,
|
None => return,
|
||||||
}
|
}
|
||||||
@ -54,24 +54,25 @@ impl DrawTarget for UiDrawTarget {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: set global render resources
|
let global_render_resource_assignments =
|
||||||
// render_pass.set_render_resources(None);
|
resources.get::<RenderResourceAssignments>().unwrap();
|
||||||
// render_pass.set_index_buffer(self.mesh_index_buffer.unwrap(), 0);
|
render_pass.set_render_resources(&global_render_resource_assignments);
|
||||||
// render_pass.set_vertex_buffer(0, self.mesh_vertex_buffer.unwrap(), 0);
|
render_pass.set_index_buffer(self.mesh_index_buffer.unwrap(), 0);
|
||||||
// render_pass.set_vertex_buffer(1, ui_instances_buffer, 0);
|
render_pass.set_vertex_buffer(0, self.mesh_vertex_buffer.unwrap(), 0);
|
||||||
// render_pass.draw_indexed(
|
render_pass.set_vertex_buffer(1, ui_instances_buffer, 0);
|
||||||
// 0..self.mesh_index_length as u32,
|
render_pass.draw_indexed(
|
||||||
// 0,
|
0..self.mesh_index_length as u32,
|
||||||
// 0..(index_count.unwrap() as u32),
|
0,
|
||||||
// );
|
0..(index_count.unwrap() as u32),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(
|
fn setup(
|
||||||
&mut self,
|
&mut self,
|
||||||
_world: &mut World,
|
_world: &mut World,
|
||||||
_resources: &Resources,
|
resources: &Resources,
|
||||||
renderer: &mut dyn Renderer,
|
renderer: &mut dyn Renderer,
|
||||||
_pipeline_handle: Handle<PipelineDescriptor>,
|
pipeline_handle: Handle<PipelineDescriptor>,
|
||||||
) {
|
) {
|
||||||
// don't create meshes if they have already been created
|
// don't create meshes if they have already been created
|
||||||
if let Some(_) = self.mesh_vertex_buffer {
|
if let Some(_) = self.mesh_vertex_buffer {
|
||||||
@ -99,6 +100,12 @@ impl DrawTarget for UiDrawTarget {
|
|||||||
quad.indices.as_bytes(),
|
quad.indices.as_bytes(),
|
||||||
));
|
));
|
||||||
self.mesh_index_length = quad.indices.len();
|
self.mesh_index_length = quad.indices.len();
|
||||||
|
|
||||||
|
let mut global_render_resource_assignments =
|
||||||
|
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||||
|
let pipeline_storage = resources.get::<AssetStorage<PipelineDescriptor>>().unwrap();
|
||||||
|
let pipeline_descriptor = pipeline_storage.get(&pipeline_handle).unwrap();
|
||||||
|
renderer.setup_bind_groups(&mut global_render_resource_assignments, pipeline_descriptor);
|
||||||
}
|
}
|
||||||
fn get_name(&self) -> String {
|
fn get_name(&self) -> String {
|
||||||
resource_name::draw_target::UI.to_string()
|
resource_name::draw_target::UI.to_string()
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
mod bind_group;
|
mod bind_group;
|
||||||
mod binding;
|
mod binding;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
|
mod pipeline_compiler;
|
||||||
mod pipeline_layout;
|
mod pipeline_layout;
|
||||||
pub mod pipelines;
|
pub mod pipelines;
|
||||||
pub mod state_descriptors;
|
pub mod state_descriptors;
|
||||||
@ -10,6 +11,7 @@ mod vertex_format;
|
|||||||
pub use bind_group::*;
|
pub use bind_group::*;
|
||||||
pub use binding::*;
|
pub use binding::*;
|
||||||
pub use pipeline::*;
|
pub use pipeline::*;
|
||||||
|
pub use pipeline_compiler::*;
|
||||||
pub use pipeline_layout::*;
|
pub use pipeline_layout::*;
|
||||||
pub use vertex_buffer_descriptor::*;
|
pub use vertex_buffer_descriptor::*;
|
||||||
pub use vertex_format::*;
|
pub use vertex_format::*;
|
||||||
|
|||||||
@ -33,7 +33,6 @@ pub struct PipelineDescriptor {
|
|||||||
pub draw_targets: Vec<String>,
|
pub draw_targets: Vec<String>,
|
||||||
pub layout: PipelineLayoutType,
|
pub layout: PipelineLayoutType,
|
||||||
pub shader_stages: ShaderStages,
|
pub shader_stages: ShaderStages,
|
||||||
pub reflect_vertex_buffer_descriptors: bool,
|
|
||||||
pub rasterization_state: Option<RasterizationStateDescriptor>,
|
pub rasterization_state: Option<RasterizationStateDescriptor>,
|
||||||
|
|
||||||
/// The primitive topology used to interpret vertices.
|
/// The primitive topology used to interpret vertices.
|
||||||
@ -48,9 +47,6 @@ pub struct PipelineDescriptor {
|
|||||||
/// The format of any index buffers used with this pipeline.
|
/// The format of any index buffers used with this pipeline.
|
||||||
pub index_format: IndexFormat,
|
pub index_format: IndexFormat,
|
||||||
|
|
||||||
/// The format of any vertex buffers used with this pipeline.
|
|
||||||
pub vertex_buffer_descriptors: Vec<VertexBufferDescriptor>,
|
|
||||||
|
|
||||||
/// The number of samples calculated per pixel (for MSAA).
|
/// The number of samples calculated per pixel (for MSAA).
|
||||||
pub sample_count: u32,
|
pub sample_count: u32,
|
||||||
|
|
||||||
@ -74,7 +70,6 @@ impl PipelineDescriptor {
|
|||||||
depth_stencil_state: None,
|
depth_stencil_state: None,
|
||||||
draw_targets: Vec::new(),
|
draw_targets: Vec::new(),
|
||||||
shader_stages: ShaderStages::new(vertex_shader),
|
shader_stages: ShaderStages::new(vertex_shader),
|
||||||
vertex_buffer_descriptors: Vec::new(),
|
|
||||||
rasterization_state: Some(RasterizationStateDescriptor {
|
rasterization_state: Some(RasterizationStateDescriptor {
|
||||||
front_face: FrontFace::Ccw,
|
front_face: FrontFace::Ccw,
|
||||||
cull_mode: CullMode::Back,
|
cull_mode: CullMode::Back,
|
||||||
@ -82,7 +77,6 @@ impl PipelineDescriptor {
|
|||||||
depth_bias_slope_scale: 0.0,
|
depth_bias_slope_scale: 0.0,
|
||||||
depth_bias_clamp: 0.0,
|
depth_bias_clamp: 0.0,
|
||||||
}),
|
}),
|
||||||
reflect_vertex_buffer_descriptors: true,
|
|
||||||
primitive_topology: PrimitiveTopology::TriangleList,
|
primitive_topology: PrimitiveTopology::TriangleList,
|
||||||
index_format: IndexFormat::Uint16,
|
index_format: IndexFormat::Uint16,
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
@ -170,12 +164,12 @@ impl<'a> PipelineBuilder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_bind_group(&mut self, bind_group: BindGroupDescriptor) -> &mut Self {
|
pub fn add_bind_group(&mut self, bind_group: BindGroupDescriptor) -> &mut Self {
|
||||||
if let PipelineLayoutType::Reflected(_) = self.pipeline.as_ref().unwrap().layout {
|
let pipeline = self.pipeline.as_mut().unwrap();
|
||||||
self.pipeline.as_mut().unwrap().layout =
|
if let PipelineLayoutType::Reflected(_) = pipeline.layout {
|
||||||
PipelineLayoutType::Manual(PipelineLayout::new());
|
pipeline.layout = PipelineLayoutType::Manual(PipelineLayout::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let PipelineLayoutType::Manual(ref mut layout) = self.pipeline.as_mut().unwrap().layout {
|
if let PipelineLayoutType::Manual(ref mut layout) = pipeline.layout {
|
||||||
layout.bind_groups.push(bind_group);
|
layout.bind_groups.push(bind_group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,10 +181,16 @@ impl<'a> PipelineBuilder<'a> {
|
|||||||
vertex_buffer_descriptor: VertexBufferDescriptor,
|
vertex_buffer_descriptor: VertexBufferDescriptor,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
let pipeline = self.pipeline.as_mut().unwrap();
|
let pipeline = self.pipeline.as_mut().unwrap();
|
||||||
pipeline.reflect_vertex_buffer_descriptors = false;
|
if let PipelineLayoutType::Reflected(_) = pipeline.layout {
|
||||||
pipeline
|
pipeline.layout = PipelineLayoutType::Manual(PipelineLayout::default());
|
||||||
.vertex_buffer_descriptors
|
}
|
||||||
.push(vertex_buffer_descriptor);
|
|
||||||
|
if let PipelineLayoutType::Manual(ref mut layout) = pipeline.layout {
|
||||||
|
layout
|
||||||
|
.vertex_buffer_descriptors
|
||||||
|
.push(vertex_buffer_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
242
src/render/pipeline/pipeline_compiler.rs
Normal file
242
src/render/pipeline/pipeline_compiler.rs
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
use super::{PipelineDescriptor, PipelineLayout, PipelineLayoutType};
|
||||||
|
use crate::{
|
||||||
|
asset::{AssetStorage, Handle},
|
||||||
|
prelude::{Renderable, Resources, Shader, World},
|
||||||
|
render::{
|
||||||
|
render_graph::RenderGraph,
|
||||||
|
render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId},
|
||||||
|
shader::ShaderSource,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
use legion::prelude::*;
|
||||||
|
|
||||||
|
// TODO: consider using (Typeid, fieldinfo.index) in place of string for hashes
|
||||||
|
pub struct PipelineCompiler {
|
||||||
|
pub shader_source_to_compiled: HashMap<Handle<Shader>, Vec<(HashSet<String>, Handle<Shader>)>>,
|
||||||
|
pub pipeline_source_to_compiled:
|
||||||
|
HashMap<Handle<PipelineDescriptor>, Vec<(HashSet<String>, Handle<PipelineDescriptor>)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PipelineCompiler {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
PipelineCompiler {
|
||||||
|
shader_source_to_compiled: HashMap::new(),
|
||||||
|
pipeline_source_to_compiled: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reflect_layout(
|
||||||
|
shader_storage: &AssetStorage<Shader>,
|
||||||
|
render_graph: &RenderGraph,
|
||||||
|
pipeline_descriptor: &mut PipelineDescriptor,
|
||||||
|
) {
|
||||||
|
let vertex_spirv = shader_storage
|
||||||
|
.get(&pipeline_descriptor.shader_stages.vertex)
|
||||||
|
.unwrap();
|
||||||
|
let fragment_spirv = pipeline_descriptor
|
||||||
|
.shader_stages
|
||||||
|
.fragment
|
||||||
|
.as_ref()
|
||||||
|
.map(|handle| &*shader_storage.get(&handle).unwrap());
|
||||||
|
|
||||||
|
let mut layouts = vec![vertex_spirv.reflect_layout().unwrap()];
|
||||||
|
if let Some(ref fragment_spirv) = fragment_spirv {
|
||||||
|
layouts.push(fragment_spirv.reflect_layout().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut layout = PipelineLayout::from_shader_layouts(&mut layouts);
|
||||||
|
layout.sync_vertex_buffer_descriptors_with_render_graph(render_graph);
|
||||||
|
|
||||||
|
for mut _bind_group in layout.bind_groups.iter_mut() {
|
||||||
|
// TODO: set dynamic here
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline_descriptor.layout = PipelineLayoutType::Reflected(Some(layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_shader(
|
||||||
|
&mut self,
|
||||||
|
shader_storage: &mut AssetStorage<Shader>,
|
||||||
|
shader_handle: &Handle<Shader>,
|
||||||
|
shader_defs: &HashSet<String>,
|
||||||
|
) -> Handle<Shader> {
|
||||||
|
let compiled_shaders = self
|
||||||
|
.shader_source_to_compiled
|
||||||
|
.entry(*shader_handle)
|
||||||
|
.or_insert_with(|| Vec::new());
|
||||||
|
|
||||||
|
let shader = shader_storage.get(shader_handle).unwrap();
|
||||||
|
|
||||||
|
// don't produce new shader if the input source is already spirv
|
||||||
|
if let ShaderSource::Spirv(_) = shader.source {
|
||||||
|
return *shader_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((_compiled_shader_defs, compiled_shader)) = compiled_shaders
|
||||||
|
.iter()
|
||||||
|
.find(|(compiled_shader_defs, _compiled_shader)| *compiled_shader_defs == *shader_defs)
|
||||||
|
{
|
||||||
|
// if shader has already been compiled with current configuration, use existing shader
|
||||||
|
*compiled_shader
|
||||||
|
} else {
|
||||||
|
// if no shader exists with the current configuration, create new shader and compile
|
||||||
|
let shader_def_vec = shader_defs.iter().cloned().collect::<Vec<String>>();
|
||||||
|
let compiled_shader = shader.get_spirv_shader(Some(&shader_def_vec));
|
||||||
|
compiled_shaders.push((shader_defs.clone(), *shader_handle));
|
||||||
|
shader_storage.add(compiled_shader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_pipeline(
|
||||||
|
&mut self,
|
||||||
|
render_graph: &RenderGraph,
|
||||||
|
shader_storage: &mut AssetStorage<Shader>,
|
||||||
|
pipeline_descriptor: &PipelineDescriptor,
|
||||||
|
shader_defs: &HashSet<String>,
|
||||||
|
) -> PipelineDescriptor {
|
||||||
|
let mut compiled_pipeline_descriptor = pipeline_descriptor.clone();
|
||||||
|
|
||||||
|
compiled_pipeline_descriptor.shader_stages.vertex = self.compile_shader(
|
||||||
|
shader_storage,
|
||||||
|
&pipeline_descriptor.shader_stages.vertex,
|
||||||
|
&shader_defs,
|
||||||
|
);
|
||||||
|
compiled_pipeline_descriptor.shader_stages.fragment = pipeline_descriptor
|
||||||
|
.shader_stages
|
||||||
|
.fragment
|
||||||
|
.as_ref()
|
||||||
|
.map(|fragment| self.compile_shader(shader_storage, fragment, &shader_defs));
|
||||||
|
|
||||||
|
Self::reflect_layout(
|
||||||
|
shader_storage,
|
||||||
|
render_graph,
|
||||||
|
&mut compiled_pipeline_descriptor,
|
||||||
|
);
|
||||||
|
|
||||||
|
compiled_pipeline_descriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_shader_assignments(
|
||||||
|
&mut self,
|
||||||
|
render_graph: &RenderGraph,
|
||||||
|
shader_pipeline_assignments: &mut ShaderPipelineAssignments,
|
||||||
|
pipeline_storage: &mut AssetStorage<PipelineDescriptor>,
|
||||||
|
shader_storage: &mut AssetStorage<Shader>,
|
||||||
|
pipelines: &[Handle<PipelineDescriptor>],
|
||||||
|
render_resource_assignments: &RenderResourceAssignments,
|
||||||
|
) {
|
||||||
|
for pipeline_handle in pipelines.iter() {
|
||||||
|
if let None = self.pipeline_source_to_compiled.get(pipeline_handle) {
|
||||||
|
self.pipeline_source_to_compiled
|
||||||
|
.insert(*pipeline_handle, Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
let final_handle = if let Some((_shader_defs, macroed_pipeline_handle)) = self
|
||||||
|
.pipeline_source_to_compiled
|
||||||
|
.get_mut(pipeline_handle)
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.find(|(shader_defs, _macroed_pipeline_handle)| {
|
||||||
|
*shader_defs == render_resource_assignments.shader_defs
|
||||||
|
}) {
|
||||||
|
*macroed_pipeline_handle
|
||||||
|
} else {
|
||||||
|
let pipeline_descriptor = pipeline_storage.get(pipeline_handle).unwrap();
|
||||||
|
let compiled_pipeline = self.compile_pipeline(
|
||||||
|
render_graph,
|
||||||
|
shader_storage,
|
||||||
|
pipeline_descriptor,
|
||||||
|
&render_resource_assignments.shader_defs,
|
||||||
|
);
|
||||||
|
let compiled_pipeline_handle = pipeline_storage.add(compiled_pipeline);
|
||||||
|
|
||||||
|
let macro_pipelines = self
|
||||||
|
.pipeline_source_to_compiled
|
||||||
|
.get_mut(pipeline_handle)
|
||||||
|
.unwrap();
|
||||||
|
macro_pipelines.push((
|
||||||
|
render_resource_assignments.shader_defs.clone(),
|
||||||
|
compiled_pipeline_handle,
|
||||||
|
));
|
||||||
|
compiled_pipeline_handle
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: this will break down if pipeline layout changes. fix this with "auto-layout"
|
||||||
|
if let None = shader_pipeline_assignments.assignments.get(&final_handle) {
|
||||||
|
shader_pipeline_assignments
|
||||||
|
.assignments
|
||||||
|
.insert(final_handle, Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
let assignments = shader_pipeline_assignments
|
||||||
|
.assignments
|
||||||
|
.get_mut(&final_handle)
|
||||||
|
.unwrap();
|
||||||
|
assignments.push(render_resource_assignments.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_compiled_pipelines(
|
||||||
|
&self,
|
||||||
|
pipeline_handle: Handle<PipelineDescriptor>,
|
||||||
|
) -> Option<impl Iterator<Item = &Handle<PipelineDescriptor>>> {
|
||||||
|
if let Some(compiled_pipelines) = self.pipeline_source_to_compiled.get(&pipeline_handle) {
|
||||||
|
Some(compiled_pipelines.iter().map(|(_, handle)| handle))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ShaderPipelineAssignments {
|
||||||
|
pub assignments: HashMap<Handle<PipelineDescriptor>, Vec<RenderResourceAssignmentsId>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShaderPipelineAssignments {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
ShaderPipelineAssignments {
|
||||||
|
assignments: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make this a system
|
||||||
|
pub fn update_shader_assignments(world: &mut World, resources: &mut Resources) {
|
||||||
|
// PERF: this seems like a lot of work for things that don't change that often.
|
||||||
|
// lots of string + hashset allocations. sees uniform_resource_provider for more context
|
||||||
|
{
|
||||||
|
let mut shader_pipeline_assignments =
|
||||||
|
resources.get_mut::<ShaderPipelineAssignments>().unwrap();
|
||||||
|
let mut pipeline_compiler = resources.get_mut::<PipelineCompiler>().unwrap();
|
||||||
|
let mut shader_storage = resources.get_mut::<AssetStorage<Shader>>().unwrap();
|
||||||
|
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
||||||
|
let mut pipeline_descriptor_storage = resources
|
||||||
|
.get_mut::<AssetStorage<PipelineDescriptor>>()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// reset assignments so they are updated every frame
|
||||||
|
shader_pipeline_assignments.assignments = HashMap::new();
|
||||||
|
|
||||||
|
// TODO: only update when renderable is changed
|
||||||
|
for mut renderable in <Write<Renderable>>::query().iter_mut(world) {
|
||||||
|
// skip instanced entities. their batched RenderResourceAssignments will handle shader assignments
|
||||||
|
if renderable.is_instanced {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline_compiler.update_shader_assignments(
|
||||||
|
&mut render_graph,
|
||||||
|
&mut shader_pipeline_assignments,
|
||||||
|
&mut pipeline_descriptor_storage,
|
||||||
|
&mut shader_storage,
|
||||||
|
&renderable.pipelines,
|
||||||
|
&renderable.render_resource_assignments,
|
||||||
|
);
|
||||||
|
|
||||||
|
// reset shader_defs so they can be changed next frame
|
||||||
|
renderable.render_resource_assignments.shader_defs.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,22 +1,18 @@
|
|||||||
use super::BindGroupDescriptor;
|
use super::{BindGroupDescriptor, VertexBufferDescriptor};
|
||||||
use crate::render::shader::ShaderLayout;
|
use crate::render::{render_graph::RenderGraph, shader::ShaderLayout};
|
||||||
use std::{collections::HashMap, hash::Hash};
|
use std::{collections::HashMap, hash::Hash};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct PipelineLayout {
|
pub struct PipelineLayout {
|
||||||
pub bind_groups: Vec<BindGroupDescriptor>,
|
pub bind_groups: Vec<BindGroupDescriptor>,
|
||||||
|
pub vertex_buffer_descriptors: Vec<VertexBufferDescriptor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PipelineLayout {
|
impl PipelineLayout {
|
||||||
pub fn new() -> Self {
|
|
||||||
PipelineLayout {
|
|
||||||
bind_groups: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_shader_layouts(shader_layouts: &mut [ShaderLayout]) -> Self {
|
pub fn from_shader_layouts(shader_layouts: &mut [ShaderLayout]) -> Self {
|
||||||
let mut bind_groups = HashMap::<u32, BindGroupDescriptor>::new();
|
let mut bind_groups = HashMap::<u32, BindGroupDescriptor>::new();
|
||||||
for shader_layout in shader_layouts {
|
let mut vertex_buffer_descriptors = Vec::new();
|
||||||
|
for shader_layout in shader_layouts.iter_mut() {
|
||||||
for shader_bind_group in shader_layout.bind_groups.iter_mut() {
|
for shader_bind_group in shader_layout.bind_groups.iter_mut() {
|
||||||
match bind_groups.get_mut(&shader_bind_group.index) {
|
match bind_groups.get_mut(&shader_bind_group.index) {
|
||||||
Some(bind_group) => {
|
Some(bind_group) => {
|
||||||
@ -40,15 +36,38 @@ impl PipelineLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for vertex_buffer_descriptor in shader_layouts[0].vertex_buffer_descriptors.iter() {
|
||||||
|
vertex_buffer_descriptors.push(vertex_buffer_descriptor.clone());
|
||||||
|
}
|
||||||
|
|
||||||
let mut bind_groups_result = bind_groups
|
let mut bind_groups_result = bind_groups
|
||||||
.drain()
|
.drain()
|
||||||
.map(|(_, value)| value)
|
.map(|(_, value)| value)
|
||||||
.collect::<Vec<BindGroupDescriptor>>();
|
.collect::<Vec<BindGroupDescriptor>>();
|
||||||
|
|
||||||
// NOTE: for some reason bind groups need to be sorted by index. this is likely an issue with bevy and not with wgpu
|
// NOTE: for some reason bind groups need to be sorted by index. this is likely an issue with bevy and not with wgpu
|
||||||
|
// TODO: try removing this
|
||||||
bind_groups_result.sort_by(|a, b| a.index.partial_cmp(&b.index).unwrap());
|
bind_groups_result.sort_by(|a, b| a.index.partial_cmp(&b.index).unwrap());
|
||||||
|
|
||||||
PipelineLayout {
|
PipelineLayout {
|
||||||
bind_groups: bind_groups_result,
|
bind_groups: bind_groups_result,
|
||||||
|
vertex_buffer_descriptors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sync_vertex_buffer_descriptors_with_render_graph(&mut self, render_graph: &RenderGraph) {
|
||||||
|
for vertex_buffer_descriptor in self.vertex_buffer_descriptors.iter_mut() {
|
||||||
|
if let Some(graph_descriptor) =
|
||||||
|
render_graph.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name)
|
||||||
|
{
|
||||||
|
vertex_buffer_descriptor.sync_with_descriptor(graph_descriptor);
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"Encountered unsupported Vertex Buffer: {}",
|
||||||
|
vertex_buffer_descriptor.name
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,7 @@ layout(set = 0, binding = 1) uniform Lights {
|
|||||||
Light SceneLights[MAX_LIGHTS];
|
Light SceneLights[MAX_LIGHTS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: this should be binding = 0 right?
|
||||||
layout(set = 2, binding = 1) uniform StandardMaterial_albedo {
|
layout(set = 2, binding = 1) uniform StandardMaterial_albedo {
|
||||||
vec4 Albedo;
|
vec4 Albedo;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -56,7 +56,7 @@ impl<'a> ForwardPipelineBuilder for RenderGraphBuilder<'a> {
|
|||||||
write_mask: ColorWrite::ALL,
|
write_mask: ColorWrite::ALL,
|
||||||
})
|
})
|
||||||
.add_draw_target(resource_name::draw_target::ASSIGNED_MESHES);
|
.add_draw_target(resource_name::draw_target::ASSIGNED_MESHES);
|
||||||
// .add_draw_target(resource_name::draw_target::ASSIGNED_BATCHES);
|
// .add_draw_target(resource_name::draw_target::ASSIGNED_BATCHES);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
use crate::{
|
use super::{AssetBatcher, Batch};
|
||||||
asset::{HandleId, HandleUntyped},
|
use crate::asset::{HandleId, HandleUntyped};
|
||||||
};
|
|
||||||
use legion::prelude::Entity;
|
use legion::prelude::Entity;
|
||||||
use std::{any::TypeId, collections::HashMap, hash::Hash};
|
use std::{any::TypeId, collections::HashMap, hash::Hash};
|
||||||
use super::{AssetBatcher, Batch};
|
|
||||||
|
|
||||||
// TODO: if/when const generics land, revisit this design in favor of generic array lengths
|
// TODO: if/when const generics land, revisit this design in favor of generic array lengths
|
||||||
|
|
||||||
@ -141,4 +139,4 @@ impl AssetBatcher for AssetSetBatcher2 {
|
|||||||
fn get_batches_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &'a mut Batch> + 'a> {
|
fn get_batches_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &'a mut Batch> + 'a> {
|
||||||
Box::new(self.set_batches.values_mut())
|
Box::new(self.set_batches.values_mut())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::{asset::HandleUntyped, render::render_resource::RenderResourceAssignments};
|
use crate::{asset::HandleUntyped, render::render_resource::RenderResourceAssignments};
|
||||||
use legion::prelude::Entity;
|
use legion::prelude::Entity;
|
||||||
use std::collections::{HashSet, HashMap};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Default)]
|
#[derive(PartialEq, Eq, Debug, Default)]
|
||||||
pub struct Batch {
|
pub struct Batch {
|
||||||
@ -18,7 +18,8 @@ impl Batch {
|
|||||||
|
|
||||||
pub fn add_instanced_entity(&mut self, entity: Entity) {
|
pub fn add_instanced_entity(&mut self, entity: Entity) {
|
||||||
if let None = self.instanced_entity_indices.get(&entity) {
|
if let None = self.instanced_entity_indices.get(&entity) {
|
||||||
self.instanced_entity_indices.insert(entity, self.current_instanced_entity_index);
|
self.instanced_entity_indices
|
||||||
|
.insert(entity, self.current_instanced_entity_index);
|
||||||
self.current_instanced_entity_index += 1;
|
self.current_instanced_entity_index += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,4 +4,4 @@ mod batch;
|
|||||||
|
|
||||||
pub use asset_batcher::*;
|
pub use asset_batcher::*;
|
||||||
pub use asset_batcher2::*;
|
pub use asset_batcher2::*;
|
||||||
pub use batch::*;
|
pub use batch::*;
|
||||||
|
|||||||
@ -25,7 +25,7 @@ pub fn build_entity_render_resource_assignments_system() -> Box<dyn Schedulable>
|
|||||||
.with_query(<Write<Renderable>>::query().filter(changed::<Renderable>()))
|
.with_query(<Write<Renderable>>::query().filter(changed::<Renderable>()))
|
||||||
.build(|_, world, entity_assignments, query| {
|
.build(|_, world, entity_assignments, query| {
|
||||||
for (entity, renderable) in query.iter_entities_mut(world) {
|
for (entity, renderable) in query.iter_entities_mut(world) {
|
||||||
entity_assignments.set(renderable.render_resource_assignments.id, entity);
|
entity_assignments.set(renderable.render_resource_assignments.id, entity);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ use crate::{
|
|||||||
render::{mesh::Mesh, texture::Texture},
|
render::{mesh::Mesh, texture::Texture},
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use super::RenderResourceAssignments;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)]
|
||||||
pub struct RenderResource(pub u64);
|
pub struct RenderResource(pub u64);
|
||||||
@ -12,7 +11,6 @@ pub struct RenderResource(pub u64);
|
|||||||
// the overlap could cause accidents.
|
// the overlap could cause accidents.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct RenderResources {
|
pub struct RenderResources {
|
||||||
pub global_assignments: RenderResourceAssignments,
|
|
||||||
pub texture_to_resource: HashMap<Handle<Texture>, RenderResource>,
|
pub texture_to_resource: HashMap<Handle<Texture>, RenderResource>,
|
||||||
pub texture_to_sampler_resource: HashMap<Handle<Texture>, RenderResource>,
|
pub texture_to_sampler_resource: HashMap<Handle<Texture>, RenderResource>,
|
||||||
pub mesh_to_vertices_resource: HashMap<Handle<Mesh>, RenderResource>,
|
pub mesh_to_vertices_resource: HashMap<Handle<Mesh>, RenderResource>,
|
||||||
@ -21,14 +19,6 @@ pub struct RenderResources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RenderResources {
|
impl RenderResources {
|
||||||
pub fn set_named_resource(&mut self, name: &str, resource: RenderResource) {
|
|
||||||
self.global_assignments.set(name, resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_named_resource(&self, name: &str) -> Option<RenderResource> {
|
|
||||||
self.global_assignments.get(name).map(|(r, _i)| r)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_texture_resource(&mut self, texture: Handle<Texture>, resource: RenderResource) {
|
pub fn set_texture_resource(&mut self, texture: Handle<Texture>, resource: RenderResource) {
|
||||||
self.texture_to_resource.insert(texture, resource);
|
self.texture_to_resource.insert(texture, resource);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,11 @@ pub struct RenderResourceAssignments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RenderResourceAssignments {
|
impl RenderResourceAssignments {
|
||||||
pub fn get(&self, name: &str) -> Option<(RenderResource, Option<u32>)> {
|
pub fn get(&self, name: &str) -> Option<RenderResource> {
|
||||||
|
self.render_resources.get(name).map(|(r, _i)| *r)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_indexed(&self, name: &str) -> Option<(RenderResource, Option<u32>)> {
|
||||||
self.render_resources.get(name).cloned()
|
self.render_resources.get(name).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +88,7 @@ impl RenderResourceAssignments {
|
|||||||
} else {
|
} else {
|
||||||
self.bind_group_resource_sets
|
self.bind_group_resource_sets
|
||||||
.get(&bind_group_descriptor.id)
|
.get(&bind_group_descriptor.id)
|
||||||
.map(|(set_id, indices)| *set_id)
|
.map(|(set_id, _indices)| *set_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +106,7 @@ impl RenderResourceAssignments {
|
|||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
let mut indices = Vec::new();
|
let mut indices = Vec::new();
|
||||||
for binding_descriptor in bind_group_descriptor.bindings.iter() {
|
for binding_descriptor in bind_group_descriptor.bindings.iter() {
|
||||||
if let Some((render_resource, index)) = self.get(&binding_descriptor.name) {
|
if let Some((render_resource, index)) = self.get_indexed(&binding_descriptor.name) {
|
||||||
render_resource.hash(&mut hasher);
|
render_resource.hash(&mut hasher);
|
||||||
if let Some(index) = index {
|
if let Some(index) = index {
|
||||||
indices.push(index);
|
indices.push(index);
|
||||||
@ -112,7 +116,14 @@ impl RenderResourceAssignments {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some((RenderResourceSetId(hasher.finish()), if indices.is_empty() { None } else { Some(indices) }))
|
Some((
|
||||||
|
RenderResourceSetId(hasher.finish()),
|
||||||
|
if indices.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(indices)
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +199,8 @@ mod tests {
|
|||||||
assert_ne!(different_set_id, None);
|
assert_ne!(different_set_id, None);
|
||||||
assert_ne!(different_set_id, set_id);
|
assert_ne!(different_set_id, set_id);
|
||||||
|
|
||||||
let equal_set_id = equal_assignments.get_or_update_render_resource_set_id(&bind_group_descriptor);
|
let equal_set_id =
|
||||||
|
equal_assignments.get_or_update_render_resource_set_id(&bind_group_descriptor);
|
||||||
assert_ne!(equal_set_id, None);
|
assert_ne!(equal_set_id, None);
|
||||||
assert_eq!(equal_set_id, set_id);
|
assert_eq!(equal_set_id, set_id);
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
use crate::render::{
|
use crate::render::{
|
||||||
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResource, ResourceProvider},
|
render_resource::{
|
||||||
|
resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
|
||||||
|
ResourceProvider,
|
||||||
|
},
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
ActiveCamera2d, Camera,
|
ActiveCamera2d, Camera,
|
||||||
};
|
};
|
||||||
@ -17,7 +20,7 @@ impl ResourceProvider for Camera2dResourceProvider {
|
|||||||
&mut self,
|
&mut self,
|
||||||
renderer: &mut dyn Renderer,
|
renderer: &mut dyn Renderer,
|
||||||
_world: &mut World,
|
_world: &mut World,
|
||||||
_resources: &Resources,
|
resources: &Resources,
|
||||||
) {
|
) {
|
||||||
let buffer = renderer.create_buffer(BufferInfo {
|
let buffer = renderer.create_buffer(BufferInfo {
|
||||||
size: std::mem::size_of::<[[f32; 4]; 4]>(),
|
size: std::mem::size_of::<[[f32; 4]; 4]>(),
|
||||||
@ -25,9 +28,9 @@ impl ResourceProvider for Camera2dResourceProvider {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
renderer
|
let mut render_resource_assignments =
|
||||||
.get_render_resources_mut()
|
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||||
.set_named_resource(resource_name::uniform::CAMERA2D, buffer);
|
render_resource_assignments.set(resource_name::uniform::CAMERA2D, buffer);
|
||||||
self.camera_buffer = Some(buffer);
|
self.camera_buffer = Some(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
use crate::render::{
|
use crate::render::{
|
||||||
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResource, ResourceProvider},
|
render_resource::{
|
||||||
|
resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
|
||||||
|
ResourceProvider,
|
||||||
|
},
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
ActiveCamera, Camera,
|
ActiveCamera, Camera,
|
||||||
};
|
};
|
||||||
@ -18,7 +21,7 @@ impl ResourceProvider for CameraResourceProvider {
|
|||||||
&mut self,
|
&mut self,
|
||||||
renderer: &mut dyn Renderer,
|
renderer: &mut dyn Renderer,
|
||||||
_world: &mut World,
|
_world: &mut World,
|
||||||
_resources: &Resources,
|
resources: &Resources,
|
||||||
) {
|
) {
|
||||||
let buffer = renderer.create_buffer(BufferInfo {
|
let buffer = renderer.create_buffer(BufferInfo {
|
||||||
size: std::mem::size_of::<[[f32; 4]; 4]>(),
|
size: std::mem::size_of::<[[f32; 4]; 4]>(),
|
||||||
@ -26,9 +29,9 @@ impl ResourceProvider for CameraResourceProvider {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
renderer
|
let mut render_resource_assignments =
|
||||||
.get_render_resources_mut()
|
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||||
.set_named_resource(resource_name::uniform::CAMERA, buffer);
|
render_resource_assignments.set(resource_name::uniform::CAMERA, buffer);
|
||||||
self.camera_buffer = Some(buffer);
|
self.camera_buffer = Some(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
core::Window,
|
core::Window,
|
||||||
prelude::World,
|
prelude::World,
|
||||||
render::{render_resource::ResourceProvider, renderer::Renderer, texture::TextureDescriptor},
|
render::{
|
||||||
|
render_resource::{RenderResourceAssignments, ResourceProvider},
|
||||||
|
renderer::Renderer,
|
||||||
|
texture::TextureDescriptor,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use legion::prelude::Resources;
|
use legion::prelude::Resources;
|
||||||
|
|
||||||
@ -23,17 +27,14 @@ impl FrameTextureResourceProvider {
|
|||||||
self.descriptor.size.width = window.width;
|
self.descriptor.size.width = window.width;
|
||||||
self.descriptor.size.height = window.height;
|
self.descriptor.size.height = window.height;
|
||||||
|
|
||||||
if let Some(old_resource) = renderer
|
let mut render_resource_assignments =
|
||||||
.get_render_resources()
|
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||||
.get_named_resource(&self.name)
|
if let Some(old_resource) = render_resource_assignments.get(&self.name) {
|
||||||
{
|
|
||||||
renderer.remove_texture(old_resource);
|
renderer.remove_texture(old_resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
let texture_resource = renderer.create_texture(&self.descriptor, None);
|
let texture_resource = renderer.create_texture(&self.descriptor, None);
|
||||||
renderer
|
render_resource_assignments.set(&self.name, texture_resource);
|
||||||
.get_render_resources_mut()
|
|
||||||
.set_named_resource(&self.name, texture_resource);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
use crate::render::{
|
use crate::render::{
|
||||||
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResource, ResourceProvider},
|
render_resource::{
|
||||||
|
resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
|
||||||
|
ResourceProvider,
|
||||||
|
},
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
Light, LightRaw,
|
Light, LightRaw,
|
||||||
};
|
};
|
||||||
@ -38,7 +41,7 @@ impl ResourceProvider for LightResourceProvider {
|
|||||||
&mut self,
|
&mut self,
|
||||||
renderer: &mut dyn Renderer,
|
renderer: &mut dyn Renderer,
|
||||||
_world: &mut World,
|
_world: &mut World,
|
||||||
_resources: &Resources,
|
resources: &Resources,
|
||||||
) {
|
) {
|
||||||
let light_uniform_size =
|
let light_uniform_size =
|
||||||
std::mem::size_of::<LightCount>() + self.max_lights * std::mem::size_of::<LightRaw>();
|
std::mem::size_of::<LightCount>() + self.max_lights * std::mem::size_of::<LightRaw>();
|
||||||
@ -48,9 +51,9 @@ impl ResourceProvider for LightResourceProvider {
|
|||||||
buffer_usage: BufferUsage::UNIFORM | BufferUsage::COPY_SRC | BufferUsage::COPY_DST,
|
buffer_usage: BufferUsage::UNIFORM | BufferUsage::COPY_SRC | BufferUsage::COPY_DST,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
renderer
|
let mut render_resource_assignments =
|
||||||
.get_render_resources_mut()
|
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||||
.set_named_resource(resource_name::uniform::LIGHTS, buffer);
|
render_resource_assignments.set(resource_name::uniform::LIGHTS, buffer);
|
||||||
self.light_buffer = Some(buffer);
|
self.light_buffer = Some(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -89,12 +89,12 @@ impl ResourceProvider for MeshResourceProvider {
|
|||||||
&mut self,
|
&mut self,
|
||||||
_renderer: &mut dyn Renderer,
|
_renderer: &mut dyn Renderer,
|
||||||
_world: &mut World,
|
_world: &mut World,
|
||||||
resources: &Resources,
|
_resources: &Resources,
|
||||||
) {
|
) {
|
||||||
let mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
// TODO: assign vertex buffers
|
||||||
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
|
// let mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||||
for batch in asset_batchers.get_handle_batches::<Mesh>() {
|
// let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
|
||||||
// batch.render_resource_assignments.
|
// for batch in asset_batchers.get_handle_batches::<Mesh>() {
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use crate::{
|
|||||||
render_graph::RenderGraph,
|
render_graph::RenderGraph,
|
||||||
render_resource::{
|
render_resource::{
|
||||||
resource_name, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource,
|
resource_name, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource,
|
||||||
ResourceProvider,
|
RenderResourceAssignments, ResourceProvider,
|
||||||
},
|
},
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
shader::AsUniforms,
|
shader::AsUniforms,
|
||||||
@ -41,7 +41,7 @@ impl UiResourceProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, renderer: &mut dyn Renderer, world: &World) {
|
pub fn update(&mut self, renderer: &mut dyn Renderer, world: &World, resources: &Resources) {
|
||||||
let node_query = <Read<Node>>::query().filter(!component::<Parent>());
|
let node_query = <Read<Node>>::query().filter(!component::<Parent>());
|
||||||
|
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
@ -99,9 +99,9 @@ impl UiResourceProvider {
|
|||||||
data.as_bytes(),
|
data.as_bytes(),
|
||||||
);
|
);
|
||||||
|
|
||||||
renderer
|
let mut render_resource_assignments =
|
||||||
.get_render_resources_mut()
|
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||||
.set_named_resource(resource_name::buffer::UI_INSTANCES, buffer);
|
render_resource_assignments.set(resource_name::buffer::UI_INSTANCES, buffer);
|
||||||
self.instance_buffer = Some(buffer);
|
self.instance_buffer = Some(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,7 +118,7 @@ impl ResourceProvider for UiResourceProvider {
|
|||||||
.set_vertex_buffer_descriptor(Rect::get_vertex_buffer_descriptor().cloned().unwrap());
|
.set_vertex_buffer_descriptor(Rect::get_vertex_buffer_descriptor().cloned().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, _resources: &Resources) {
|
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {
|
||||||
self.update(renderer, world);
|
self.update(renderer, world, resources);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,7 @@ use crate::{
|
|||||||
render_graph::RenderGraph,
|
render_graph::RenderGraph,
|
||||||
render_resource::{
|
render_resource::{
|
||||||
AssetBatchers, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource,
|
AssetBatchers, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource,
|
||||||
RenderResourceAssignments, ResourceInfo,
|
RenderResourceAssignments, ResourceInfo, ResourceProvider,
|
||||||
ResourceProvider,
|
|
||||||
},
|
},
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
shader::{AsUniforms, FieldBindType},
|
shader::{AsUniforms, FieldBindType},
|
||||||
@ -122,10 +121,7 @@ where
|
|||||||
self.increment_uniform_counts(&uniforms);
|
self.increment_uniform_counts(&uniforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::update_shader_defs(
|
Self::update_shader_defs(&uniforms, &mut renderable.render_resource_assignments);
|
||||||
&uniforms,
|
|
||||||
&mut renderable.render_resource_assignments,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.query = Some(query);
|
self.query = Some(query);
|
||||||
@ -158,10 +154,7 @@ where
|
|||||||
let uniforms = assets
|
let uniforms = assets
|
||||||
.get(&handle)
|
.get(&handle)
|
||||||
.expect("Handle points to a non-existent resource");
|
.expect("Handle points to a non-existent resource");
|
||||||
Self::update_shader_defs(
|
Self::update_shader_defs(uniforms, &mut renderable.render_resource_assignments);
|
||||||
uniforms,
|
|
||||||
&mut renderable.render_resource_assignments,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.increment_uniform_counts(&uniforms);
|
self.increment_uniform_counts(&uniforms);
|
||||||
}
|
}
|
||||||
@ -264,9 +257,13 @@ where
|
|||||||
..
|
..
|
||||||
})) = renderer.get_resource_info_mut(buffer)
|
})) = renderer.get_resource_info_mut(buffer)
|
||||||
{
|
{
|
||||||
let index = array_info
|
let index =
|
||||||
.get_or_assign_index(render_resource_assignments.id);
|
array_info.get_or_assign_index(render_resource_assignments.id);
|
||||||
render_resource_assignments.set_indexed(&field_info.uniform_name, buffer, index as u32);
|
render_resource_assignments.set_indexed(
|
||||||
|
&field_info.uniform_name,
|
||||||
|
buffer,
|
||||||
|
(index * array_info.item_size) as u32,
|
||||||
|
);
|
||||||
(buffer, index * uniform_buffer_status.aligned_size)
|
(buffer, index * uniform_buffer_status.aligned_size)
|
||||||
} else {
|
} else {
|
||||||
panic!("Expected a dynamic uniform buffer");
|
panic!("Expected a dynamic uniform buffer");
|
||||||
@ -275,7 +272,7 @@ where
|
|||||||
let resource = match render_resource_assignments
|
let resource = match render_resource_assignments
|
||||||
.get(field_info.uniform_name)
|
.get(field_info.uniform_name)
|
||||||
{
|
{
|
||||||
Some((render_resource, _index)) => render_resource,
|
Some(render_resource) => render_resource,
|
||||||
None => {
|
None => {
|
||||||
let resource = renderer.create_buffer(BufferInfo {
|
let resource = renderer.create_buffer(BufferInfo {
|
||||||
size,
|
size,
|
||||||
@ -470,12 +467,9 @@ where
|
|||||||
|
|
||||||
fn setup_buffer_arrays(&mut self, renderer: &mut dyn Renderer) {
|
fn setup_buffer_arrays(&mut self, renderer: &mut dyn Renderer) {
|
||||||
for buffer_array_status in self.uniform_buffer_status.iter_mut() {
|
for buffer_array_status in self.uniform_buffer_status.iter_mut() {
|
||||||
if let Some((name, buffer_array_status)) = buffer_array_status {
|
if let Some((_name, buffer_array_status)) = buffer_array_status {
|
||||||
if self.use_dynamic_uniforms {
|
if self.use_dynamic_uniforms {
|
||||||
Self::setup_buffer_array(buffer_array_status, renderer, true);
|
Self::setup_buffer_array(buffer_array_status, renderer, true);
|
||||||
renderer
|
|
||||||
.get_render_resources_mut()
|
|
||||||
.set_named_resource(name, buffer_array_status.buffer.unwrap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_array_status.queued_buffer_writes =
|
buffer_array_status.queued_buffer_writes =
|
||||||
@ -623,7 +617,7 @@ where
|
|||||||
let mut staging_buffer: [u8; 0] = [];
|
let mut staging_buffer: [u8; 0] = [];
|
||||||
self.setup_uniforms_resources(world, resources, renderer, &mut staging_buffer);
|
self.setup_uniforms_resources(world, resources, renderer, &mut staging_buffer);
|
||||||
self.setup_handles_resources(world, resources, renderer, &mut staging_buffer);
|
self.setup_handles_resources(world, resources, renderer, &mut staging_buffer);
|
||||||
// self.setup_batched_resources(world, resources, renderer, &mut staging_buffer);
|
// self.setup_batched_resources(world, resources, renderer, &mut staging_buffer);
|
||||||
} else {
|
} else {
|
||||||
let staging_buffer = renderer.create_buffer_mapped(
|
let staging_buffer = renderer.create_buffer_mapped(
|
||||||
BufferInfo {
|
BufferInfo {
|
||||||
|
|||||||
@ -1,14 +1,5 @@
|
|||||||
use super::{
|
use super::render_resource::RenderResourceAssignments;
|
||||||
pipeline::PipelineDescriptor,
|
use crate::{asset::Handle, prelude::PipelineDescriptor};
|
||||||
render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId},
|
|
||||||
shader::{Shader, ShaderSource},
|
|
||||||
};
|
|
||||||
use crate::{
|
|
||||||
asset::{AssetStorage, Handle},
|
|
||||||
render::{render_graph::RenderGraph, render_resource::resource_name},
|
|
||||||
};
|
|
||||||
use legion::prelude::*;
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
|
|
||||||
pub struct Renderable {
|
pub struct Renderable {
|
||||||
pub is_visible: bool,
|
pub is_visible: bool,
|
||||||
@ -40,206 +31,3 @@ impl Default for Renderable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: consider using (Typeid, fieldinfo.index) in place of string for hashes
|
|
||||||
pub struct CompiledShaderMap {
|
|
||||||
// TODO: need macro hash lookup
|
|
||||||
pub source_to_compiled: HashMap<Handle<Shader>, Vec<(HashSet<String>, Handle<Shader>)>>,
|
|
||||||
pub pipeline_to_macro_pipelines:
|
|
||||||
HashMap<Handle<PipelineDescriptor>, Vec<(HashSet<String>, Handle<PipelineDescriptor>)>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CompiledShaderMap {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
CompiledShaderMap {
|
|
||||||
source_to_compiled: HashMap::new(),
|
|
||||||
pipeline_to_macro_pipelines: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_shader_assignments(
|
|
||||||
&mut self,
|
|
||||||
render_graph: &mut RenderGraph,
|
|
||||||
shader_pipeline_assignments: &mut ShaderPipelineAssignments,
|
|
||||||
pipeline_storage: &mut AssetStorage<PipelineDescriptor>,
|
|
||||||
shader_storage: &mut AssetStorage<Shader>,
|
|
||||||
pipelines: &[Handle<PipelineDescriptor>],
|
|
||||||
render_resource_assignments: &RenderResourceAssignments,
|
|
||||||
) {
|
|
||||||
for pipeline_handle in pipelines.iter() {
|
|
||||||
if let None = self.pipeline_to_macro_pipelines.get(pipeline_handle) {
|
|
||||||
self.pipeline_to_macro_pipelines
|
|
||||||
.insert(*pipeline_handle, Vec::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
let final_handle = if let Some((_shader_defs, macroed_pipeline_handle)) = self
|
|
||||||
.pipeline_to_macro_pipelines
|
|
||||||
.get_mut(pipeline_handle)
|
|
||||||
.unwrap()
|
|
||||||
.iter()
|
|
||||||
.find(|(shader_defs, _macroed_pipeline_handle)| {
|
|
||||||
*shader_defs == render_resource_assignments.shader_defs
|
|
||||||
}) {
|
|
||||||
*macroed_pipeline_handle
|
|
||||||
} else {
|
|
||||||
let pipeline_descriptor = pipeline_storage.get(pipeline_handle).unwrap();
|
|
||||||
let macroed_pipeline_handle = {
|
|
||||||
let mut macroed_vertex_handle = try_compiling_shader_with_macros(
|
|
||||||
self,
|
|
||||||
shader_storage,
|
|
||||||
&render_resource_assignments,
|
|
||||||
&pipeline_descriptor.shader_stages.vertex,
|
|
||||||
);
|
|
||||||
let mut macroed_fragment_handle = pipeline_descriptor
|
|
||||||
.shader_stages
|
|
||||||
.fragment
|
|
||||||
.as_ref()
|
|
||||||
.map(|fragment| {
|
|
||||||
try_compiling_shader_with_macros(
|
|
||||||
self,
|
|
||||||
shader_storage,
|
|
||||||
&render_resource_assignments,
|
|
||||||
fragment,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
if macroed_vertex_handle.is_some() || macroed_fragment_handle.is_some() {
|
|
||||||
let mut macroed_pipeline = pipeline_descriptor.clone();
|
|
||||||
if let Some(vertex) = macroed_vertex_handle.take() {
|
|
||||||
macroed_pipeline.shader_stages.vertex = vertex;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(fragment) = macroed_fragment_handle.take() {
|
|
||||||
macroed_pipeline.shader_stages.fragment = fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
let macroed_pipeline_handle = pipeline_storage.add(macroed_pipeline);
|
|
||||||
// TODO: get correct pass name
|
|
||||||
render_graph
|
|
||||||
.add_pipeline(resource_name::pass::MAIN, macroed_pipeline_handle);
|
|
||||||
macroed_pipeline_handle
|
|
||||||
} else {
|
|
||||||
*pipeline_handle
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let macro_pipelines = self
|
|
||||||
.pipeline_to_macro_pipelines
|
|
||||||
.get_mut(pipeline_handle)
|
|
||||||
.unwrap();
|
|
||||||
macro_pipelines.push((
|
|
||||||
render_resource_assignments.shader_defs.clone(),
|
|
||||||
macroed_pipeline_handle,
|
|
||||||
));
|
|
||||||
macroed_pipeline_handle
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: this will break down if pipeline layout changes. fix this with "auto-layout"
|
|
||||||
if let None = shader_pipeline_assignments.assignments.get(&final_handle) {
|
|
||||||
shader_pipeline_assignments
|
|
||||||
.assignments
|
|
||||||
.insert(final_handle, Vec::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
let assignments = shader_pipeline_assignments
|
|
||||||
.assignments
|
|
||||||
.get_mut(&final_handle)
|
|
||||||
.unwrap();
|
|
||||||
assignments.push(render_resource_assignments.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ShaderPipelineAssignments {
|
|
||||||
pub assignments: HashMap<Handle<PipelineDescriptor>, Vec<RenderResourceAssignmentsId>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ShaderPipelineAssignments {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
ShaderPipelineAssignments {
|
|
||||||
assignments: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_compiling_shader_with_macros(
|
|
||||||
compiled_shader_map: &mut CompiledShaderMap,
|
|
||||||
shader_storage: &mut AssetStorage<Shader>,
|
|
||||||
assignments: &RenderResourceAssignments,
|
|
||||||
shader_handle: &Handle<Shader>,
|
|
||||||
) -> Option<Handle<Shader>> {
|
|
||||||
if let None = compiled_shader_map.source_to_compiled.get(shader_handle) {
|
|
||||||
compiled_shader_map
|
|
||||||
.source_to_compiled
|
|
||||||
.insert(*shader_handle, Vec::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
let compiled_shaders = compiled_shader_map
|
|
||||||
.source_to_compiled
|
|
||||||
.get_mut(shader_handle)
|
|
||||||
.unwrap();
|
|
||||||
let shader = shader_storage.get(shader_handle).unwrap();
|
|
||||||
|
|
||||||
// don't produce new shader if the input source is already spirv
|
|
||||||
if let ShaderSource::Spirv(_) = shader.source {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((_shader_defs, compiled_shader)) = compiled_shaders
|
|
||||||
.iter()
|
|
||||||
.find(|(shader_defs, _shader)| *shader_defs == assignments.shader_defs)
|
|
||||||
{
|
|
||||||
Some(compiled_shader.clone())
|
|
||||||
} else {
|
|
||||||
let shader_def_vec = assignments
|
|
||||||
.shader_defs
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<String>>();
|
|
||||||
let compiled_shader = shader.get_spirv_shader(Some(&shader_def_vec));
|
|
||||||
compiled_shaders.push((assignments.shader_defs.clone(), *shader_handle));
|
|
||||||
let compiled_shader_handle = shader_storage.add(compiled_shader);
|
|
||||||
Some(compiled_shader_handle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_shader_assignments(world: &mut World, resources: &mut Resources) {
|
|
||||||
// PERF: this seems like a lot of work for things that don't change that often.
|
|
||||||
// lots of string + hashset allocations. sees uniform_resource_provider for more context
|
|
||||||
{
|
|
||||||
let mut shader_pipeline_assignments =
|
|
||||||
resources.get_mut::<ShaderPipelineAssignments>().unwrap();
|
|
||||||
let mut compiled_shader_map = resources.get_mut::<CompiledShaderMap>().unwrap();
|
|
||||||
let mut shader_storage = resources.get_mut::<AssetStorage<Shader>>().unwrap();
|
|
||||||
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
|
||||||
let mut pipeline_descriptor_storage = resources
|
|
||||||
.get_mut::<AssetStorage<PipelineDescriptor>>()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// reset assignments so they are updated every frame
|
|
||||||
shader_pipeline_assignments.assignments = HashMap::new();
|
|
||||||
|
|
||||||
// TODO: only update when renderable is changed
|
|
||||||
for mut renderable in <Write<Renderable>>::query().iter_mut(world) {
|
|
||||||
// skip instanced entities. their batched RenderResourceAssignments will handle shader assignments
|
|
||||||
if renderable.is_instanced {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
compiled_shader_map.update_shader_assignments(
|
|
||||||
&mut render_graph,
|
|
||||||
&mut shader_pipeline_assignments,
|
|
||||||
&mut pipeline_descriptor_storage,
|
|
||||||
&mut shader_storage,
|
|
||||||
&renderable.pipelines,
|
|
||||||
&renderable.render_resource_assignments,
|
|
||||||
);
|
|
||||||
|
|
||||||
// reset shader_defs so they can be changed next frame
|
|
||||||
renderable
|
|
||||||
.render_resource_assignments
|
|
||||||
.shader_defs
|
|
||||||
.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -55,5 +55,8 @@ pub trait RenderPass {
|
|||||||
fn set_index_buffer(&mut self, resource: RenderResource, offset: u64);
|
fn set_index_buffer(&mut self, resource: RenderResource, offset: u64);
|
||||||
fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64);
|
fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64);
|
||||||
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
||||||
fn set_render_resources(&mut self, render_resource_assignments: &RenderResourceAssignments) -> Option<Range<u32>>;
|
fn set_render_resources(
|
||||||
|
&mut self,
|
||||||
|
render_resource_assignments: &RenderResourceAssignments,
|
||||||
|
) -> Option<Range<u32>>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use super::{WgpuRenderer, WgpuResources};
|
use super::{WgpuRenderer, WgpuResources};
|
||||||
use crate::render::{
|
use crate::render::{
|
||||||
pipeline::{BindType, PipelineDescriptor},
|
pipeline::PipelineDescriptor,
|
||||||
render_resource::{BufferInfo, RenderResource, RenderResourceAssignments, ResourceInfo},
|
render_resource::{RenderResource, RenderResourceAssignments},
|
||||||
renderer::{RenderPass, Renderer},
|
renderer::{RenderPass, Renderer},
|
||||||
};
|
};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
@ -53,11 +53,18 @@ 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
|
||||||
let empty = &[];
|
let empty = &[];
|
||||||
let dynamic_uniform_indices = if let Some(dynamic_uniform_indices) = dynamic_uniform_indices {
|
let dynamic_uniform_indices =
|
||||||
dynamic_uniform_indices.as_slice()
|
if let Some(dynamic_uniform_indices) = dynamic_uniform_indices {
|
||||||
} else {
|
dynamic_uniform_indices.as_slice()
|
||||||
empty
|
} else {
|
||||||
};
|
empty
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: remove this
|
||||||
|
// if dynamic_uniform_indices.len() == 0 && bind_group.index > 0 {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
self.render_pass.set_bind_group(
|
self.render_pass.set_bind_group(
|
||||||
bind_group.index,
|
bind_group.index,
|
||||||
&wgpu_bind_group,
|
&wgpu_bind_group,
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use crate::{
|
|||||||
PassDescriptor, RenderPassColorAttachmentDescriptor,
|
PassDescriptor, RenderPassColorAttachmentDescriptor,
|
||||||
RenderPassDepthStencilAttachmentDescriptor,
|
RenderPassDepthStencilAttachmentDescriptor,
|
||||||
},
|
},
|
||||||
pipeline::{BindType, PipelineDescriptor, PipelineLayout, PipelineLayoutType},
|
pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor},
|
||||||
render_graph::RenderGraph,
|
render_graph::RenderGraph,
|
||||||
render_resource::{
|
render_resource::{
|
||||||
resource_name, BufferInfo, RenderResource, RenderResourceAssignments, RenderResources,
|
resource_name, BufferInfo, RenderResource, RenderResourceAssignments, RenderResources,
|
||||||
@ -17,7 +17,6 @@ use crate::{
|
|||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
shader::Shader,
|
shader::Shader,
|
||||||
texture::{SamplerDescriptor, TextureDescriptor},
|
texture::{SamplerDescriptor, TextureDescriptor},
|
||||||
update_shader_assignments,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::{cell::RefCell, collections::HashMap, ops::Deref, rc::Rc};
|
use std::{cell::RefCell, collections::HashMap, ops::Deref, rc::Rc};
|
||||||
@ -65,7 +64,7 @@ impl WgpuRenderer {
|
|||||||
encoder: None,
|
encoder: None,
|
||||||
intialized: false,
|
intialized: false,
|
||||||
swap_chain_descriptor,
|
swap_chain_descriptor,
|
||||||
wgpu_resources: WgpuResources::new(),
|
wgpu_resources: WgpuResources::default(),
|
||||||
render_pipelines: HashMap::new(),
|
render_pipelines: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,102 +87,14 @@ impl WgpuRenderer {
|
|||||||
self.intialized = true;
|
self.intialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_vertex_buffer_descriptors(
|
|
||||||
render_graph: &RenderGraph,
|
|
||||||
vertex_spirv: &Shader,
|
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
|
||||||
) -> Vec<OwnedWgpuVertexBufferDescriptor> {
|
|
||||||
let mut reflected_vertex_layout = if pipeline_descriptor.reflect_vertex_buffer_descriptors {
|
|
||||||
Some(vertex_spirv.reflect_layout().unwrap())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let vertex_buffer_descriptors = if let Some(ref mut layout) = reflected_vertex_layout {
|
|
||||||
for vertex_buffer_descriptor in layout.vertex_buffer_descriptors.iter_mut() {
|
|
||||||
if let Some(graph_descriptor) =
|
|
||||||
render_graph.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name)
|
|
||||||
{
|
|
||||||
vertex_buffer_descriptor.sync_with_descriptor(graph_descriptor);
|
|
||||||
} else {
|
|
||||||
panic!(
|
|
||||||
"Encountered unsupported Vertex Buffer: {}",
|
|
||||||
vertex_buffer_descriptor.name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&layout.vertex_buffer_descriptors
|
|
||||||
} else {
|
|
||||||
&pipeline_descriptor.vertex_buffer_descriptors
|
|
||||||
};
|
|
||||||
|
|
||||||
vertex_buffer_descriptors
|
|
||||||
.iter()
|
|
||||||
.map(|v| v.into())
|
|
||||||
.collect::<Vec<OwnedWgpuVertexBufferDescriptor>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_render_pipeline(
|
pub fn create_render_pipeline(
|
||||||
wgpu_resources: &mut WgpuResources,
|
wgpu_resources: &mut WgpuResources,
|
||||||
pipeline_descriptor: &mut PipelineDescriptor,
|
pipeline_descriptor: &mut PipelineDescriptor,
|
||||||
|
shader_storage: &AssetStorage<Shader>,
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
render_graph: &RenderGraph,
|
|
||||||
vertex_shader: &Shader,
|
|
||||||
fragment_shader: Option<&Shader>,
|
|
||||||
) -> wgpu::RenderPipeline {
|
) -> wgpu::RenderPipeline {
|
||||||
let vertex_spirv = vertex_shader.get_spirv_shader(None);
|
let layout = pipeline_descriptor.get_layout().unwrap();
|
||||||
let fragment_spirv = fragment_shader.map(|f| f.get_spirv_shader(None));
|
for bind_group in layout.bind_groups.iter() {
|
||||||
|
|
||||||
let vertex_shader_module = Self::create_shader_module(device, &vertex_spirv, None);
|
|
||||||
let fragment_shader_module = match fragment_shader {
|
|
||||||
Some(fragment_spirv) => Some(Self::create_shader_module(device, fragment_spirv, None)),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let PipelineLayoutType::Reflected(None) = pipeline_descriptor.layout {
|
|
||||||
let mut layouts = vec![vertex_spirv.reflect_layout().unwrap()];
|
|
||||||
|
|
||||||
if let Some(ref fragment_spirv) = fragment_spirv {
|
|
||||||
layouts.push(fragment_spirv.reflect_layout().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut layout = PipelineLayout::from_shader_layouts(&mut layouts);
|
|
||||||
|
|
||||||
// set each uniform binding to dynamic if there is a matching dynamic uniform buffer info
|
|
||||||
for mut bind_group in layout.bind_groups.iter_mut() {
|
|
||||||
bind_group.bindings = bind_group
|
|
||||||
.bindings
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.map(|mut binding| {
|
|
||||||
if let BindType::Uniform {
|
|
||||||
ref mut dynamic, ..
|
|
||||||
} = binding.bind_type
|
|
||||||
{
|
|
||||||
if let Some(resource) = wgpu_resources
|
|
||||||
.render_resources
|
|
||||||
.get_named_resource(&binding.name)
|
|
||||||
{
|
|
||||||
if let Some(ResourceInfo::Buffer(buffer_info)) =
|
|
||||||
wgpu_resources.resource_info.get(&resource)
|
|
||||||
{
|
|
||||||
*dynamic = buffer_info.is_dynamic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline_descriptor.layout = PipelineLayoutType::Reflected(Some(layout));
|
|
||||||
}
|
|
||||||
|
|
||||||
let layout = pipeline_descriptor.get_layout_mut().unwrap();
|
|
||||||
|
|
||||||
// setup new bind group layouts
|
|
||||||
for bind_group in layout.bind_groups.iter_mut() {
|
|
||||||
if let None = wgpu_resources.bind_group_layouts.get(&bind_group.id) {
|
if let None = wgpu_resources.bind_group_layouts.get(&bind_group.id) {
|
||||||
let bind_group_layout_binding = bind_group
|
let bind_group_layout_binding = bind_group
|
||||||
.bindings
|
.bindings
|
||||||
@ -194,18 +105,18 @@ impl WgpuRenderer {
|
|||||||
ty: (&binding.bind_type).into(),
|
ty: (&binding.bind_type).into(),
|
||||||
})
|
})
|
||||||
.collect::<Vec<wgpu::BindGroupLayoutBinding>>();
|
.collect::<Vec<wgpu::BindGroupLayoutBinding>>();
|
||||||
let bind_group_layout =
|
let wgpu_bind_group_layout =
|
||||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
bindings: bind_group_layout_binding.as_slice(),
|
bindings: bind_group_layout_binding.as_slice(),
|
||||||
});
|
});
|
||||||
|
|
||||||
wgpu_resources
|
wgpu_resources
|
||||||
.bind_group_layouts
|
.bind_group_layouts
|
||||||
.insert(bind_group.id, bind_group_layout);
|
.insert(bind_group.id, wgpu_bind_group_layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect bind group layout references
|
// setup and collect bind group layouts
|
||||||
let bind_group_layouts = layout
|
let bind_group_layouts = layout
|
||||||
.bind_groups
|
.bind_groups
|
||||||
.iter()
|
.iter()
|
||||||
@ -221,8 +132,11 @@ impl WgpuRenderer {
|
|||||||
bind_group_layouts: bind_group_layouts.as_slice(),
|
bind_group_layouts: bind_group_layouts.as_slice(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let owned_vertex_buffer_descriptors =
|
let owned_vertex_buffer_descriptors = layout
|
||||||
Self::setup_vertex_buffer_descriptors(render_graph, &vertex_spirv, pipeline_descriptor);
|
.vertex_buffer_descriptors
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.into())
|
||||||
|
.collect::<Vec<OwnedWgpuVertexBufferDescriptor>>();
|
||||||
|
|
||||||
let color_states = pipeline_descriptor
|
let color_states = pipeline_descriptor
|
||||||
.color_states
|
.color_states
|
||||||
@ -230,13 +144,42 @@ impl WgpuRenderer {
|
|||||||
.map(|c| c.into())
|
.map(|c| c.into())
|
||||||
.collect::<Vec<wgpu::ColorStateDescriptor>>();
|
.collect::<Vec<wgpu::ColorStateDescriptor>>();
|
||||||
|
|
||||||
|
if let None = wgpu_resources
|
||||||
|
.shader_modules
|
||||||
|
.get(&pipeline_descriptor.shader_stages.vertex)
|
||||||
|
{
|
||||||
|
wgpu_resources.create_shader_module(
|
||||||
|
device,
|
||||||
|
pipeline_descriptor.shader_stages.vertex,
|
||||||
|
shader_storage,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(fragment_handle) = pipeline_descriptor.shader_stages.fragment {
|
||||||
|
if let None = wgpu_resources.shader_modules.get(&fragment_handle) {
|
||||||
|
wgpu_resources.create_shader_module(device, fragment_handle, shader_storage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let vertex_shader_module = wgpu_resources
|
||||||
|
.shader_modules
|
||||||
|
.get(&pipeline_descriptor.shader_stages.vertex)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let fragment_shader_module = match pipeline_descriptor.shader_stages.fragment {
|
||||||
|
Some(fragment_handle) => {
|
||||||
|
Some(wgpu_resources.shader_modules.get(&fragment_handle).unwrap())
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
let mut render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
|
let mut render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
|
||||||
layout: &pipeline_layout,
|
layout: &pipeline_layout,
|
||||||
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
||||||
module: &vertex_shader_module,
|
module: &vertex_shader_module,
|
||||||
entry_point: "main",
|
entry_point: "main",
|
||||||
},
|
},
|
||||||
fragment_stage: match fragment_shader {
|
fragment_stage: match pipeline_descriptor.shader_stages.fragment {
|
||||||
Some(_) => Some(wgpu::ProgrammableStageDescriptor {
|
Some(_) => Some(wgpu::ProgrammableStageDescriptor {
|
||||||
entry_point: "main",
|
entry_point: "main",
|
||||||
module: fragment_shader_module.as_ref().unwrap(),
|
module: fragment_shader_module.as_ref().unwrap(),
|
||||||
@ -269,6 +212,7 @@ impl WgpuRenderer {
|
|||||||
pub fn create_render_pass<'a>(
|
pub fn create_render_pass<'a>(
|
||||||
wgpu_resources: &'a WgpuResources,
|
wgpu_resources: &'a WgpuResources,
|
||||||
pass_descriptor: &PassDescriptor,
|
pass_descriptor: &PassDescriptor,
|
||||||
|
global_render_resource_assignments: &RenderResourceAssignments,
|
||||||
encoder: &'a mut wgpu::CommandEncoder,
|
encoder: &'a mut wgpu::CommandEncoder,
|
||||||
frame: &'a wgpu::SwapChainOutput,
|
frame: &'a wgpu::SwapChainOutput,
|
||||||
) -> wgpu::RenderPass<'a> {
|
) -> wgpu::RenderPass<'a> {
|
||||||
@ -276,25 +220,37 @@ impl WgpuRenderer {
|
|||||||
color_attachments: &pass_descriptor
|
color_attachments: &pass_descriptor
|
||||||
.color_attachments
|
.color_attachments
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| Self::create_wgpu_color_attachment_descriptor(wgpu_resources, c, frame))
|
.map(|c| {
|
||||||
|
Self::create_wgpu_color_attachment_descriptor(
|
||||||
|
wgpu_resources,
|
||||||
|
global_render_resource_assignments,
|
||||||
|
c,
|
||||||
|
frame,
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect::<Vec<wgpu::RenderPassColorAttachmentDescriptor>>(),
|
.collect::<Vec<wgpu::RenderPassColorAttachmentDescriptor>>(),
|
||||||
depth_stencil_attachment: pass_descriptor.depth_stencil_attachment.as_ref().map(|d| {
|
depth_stencil_attachment: pass_descriptor.depth_stencil_attachment.as_ref().map(|d| {
|
||||||
Self::create_wgpu_depth_stencil_attachment_descriptor(wgpu_resources, d, frame)
|
Self::create_wgpu_depth_stencil_attachment_descriptor(
|
||||||
|
wgpu_resources,
|
||||||
|
global_render_resource_assignments,
|
||||||
|
d,
|
||||||
|
frame,
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_wgpu_color_attachment_descriptor<'a>(
|
fn create_wgpu_color_attachment_descriptor<'a>(
|
||||||
wgpu_resources: &'a WgpuResources,
|
wgpu_resources: &'a WgpuResources,
|
||||||
|
global_render_resource_assignments: &RenderResourceAssignments,
|
||||||
color_attachment_descriptor: &RenderPassColorAttachmentDescriptor,
|
color_attachment_descriptor: &RenderPassColorAttachmentDescriptor,
|
||||||
frame: &'a wgpu::SwapChainOutput,
|
frame: &'a wgpu::SwapChainOutput,
|
||||||
) -> wgpu::RenderPassColorAttachmentDescriptor<'a> {
|
) -> wgpu::RenderPassColorAttachmentDescriptor<'a> {
|
||||||
let attachment = match color_attachment_descriptor.attachment.as_str() {
|
let attachment = match color_attachment_descriptor.attachment.as_str() {
|
||||||
resource_name::texture::SWAP_CHAIN => &frame.view,
|
resource_name::texture::SWAP_CHAIN => &frame.view,
|
||||||
_ => {
|
_ => {
|
||||||
match wgpu_resources
|
match global_render_resource_assignments
|
||||||
.render_resources
|
.get(&color_attachment_descriptor.attachment)
|
||||||
.get_named_resource(&color_attachment_descriptor.attachment)
|
|
||||||
{
|
{
|
||||||
Some(resource) => wgpu_resources.textures.get(&resource).unwrap(),
|
Some(resource) => wgpu_resources.textures.get(&resource).unwrap(),
|
||||||
None => panic!(
|
None => panic!(
|
||||||
@ -308,10 +264,7 @@ impl WgpuRenderer {
|
|||||||
let resolve_target = match color_attachment_descriptor.resolve_target {
|
let resolve_target = match color_attachment_descriptor.resolve_target {
|
||||||
Some(ref target) => match target.as_str() {
|
Some(ref target) => match target.as_str() {
|
||||||
resource_name::texture::SWAP_CHAIN => Some(&frame.view),
|
resource_name::texture::SWAP_CHAIN => Some(&frame.view),
|
||||||
_ => match wgpu_resources
|
_ => match global_render_resource_assignments.get(target.as_str()) {
|
||||||
.render_resources
|
|
||||||
.get_named_resource(target.as_str())
|
|
||||||
{
|
|
||||||
Some(resource) => Some(wgpu_resources.textures.get(&resource).unwrap()),
|
Some(resource) => Some(wgpu_resources.textures.get(&resource).unwrap()),
|
||||||
None => panic!(
|
None => panic!(
|
||||||
"Color attachment {} does not exist",
|
"Color attachment {} does not exist",
|
||||||
@ -333,15 +286,15 @@ impl WgpuRenderer {
|
|||||||
|
|
||||||
fn create_wgpu_depth_stencil_attachment_descriptor<'a>(
|
fn create_wgpu_depth_stencil_attachment_descriptor<'a>(
|
||||||
wgpu_resources: &'a WgpuResources,
|
wgpu_resources: &'a WgpuResources,
|
||||||
|
global_render_resource_assignments: &RenderResourceAssignments,
|
||||||
depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor,
|
depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor,
|
||||||
frame: &'a wgpu::SwapChainOutput,
|
frame: &'a wgpu::SwapChainOutput,
|
||||||
) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> {
|
) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> {
|
||||||
let attachment = match depth_stencil_attachment_descriptor.attachment.as_str() {
|
let attachment = match depth_stencil_attachment_descriptor.attachment.as_str() {
|
||||||
resource_name::texture::SWAP_CHAIN => &frame.view,
|
resource_name::texture::SWAP_CHAIN => &frame.view,
|
||||||
_ => {
|
_ => {
|
||||||
match wgpu_resources
|
match global_render_resource_assignments
|
||||||
.render_resources
|
.get(&depth_stencil_attachment_descriptor.attachment)
|
||||||
.get_named_resource(&depth_stencil_attachment_descriptor.attachment)
|
|
||||||
{
|
{
|
||||||
Some(ref resource) => wgpu_resources.textures.get(&resource).unwrap(),
|
Some(ref resource) => wgpu_resources.textures.get(&resource).unwrap(),
|
||||||
None => panic!(
|
None => panic!(
|
||||||
@ -363,14 +316,6 @@ impl WgpuRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_shader_module(
|
|
||||||
device: &wgpu::Device,
|
|
||||||
shader: &Shader,
|
|
||||||
macros: Option<&[String]>,
|
|
||||||
) -> wgpu::ShaderModule {
|
|
||||||
device.create_shader_module(&shader.get_spirv(macros))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn initialize_resource_providers(&mut self, world: &mut World, resources: &mut Resources) {
|
pub fn initialize_resource_providers(&mut self, world: &mut World, resources: &mut Resources) {
|
||||||
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
||||||
self.encoder = Some(
|
self.encoder = Some(
|
||||||
@ -400,11 +345,11 @@ impl WgpuRenderer {
|
|||||||
|
|
||||||
pub fn create_queued_textures(&mut self, resources: &mut Resources) {
|
pub fn create_queued_textures(&mut self, resources: &mut Resources) {
|
||||||
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
||||||
|
let mut render_resource_assignments =
|
||||||
|
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||||
for (name, texture_descriptor) in render_graph.queued_textures.drain(..) {
|
for (name, texture_descriptor) in render_graph.queued_textures.drain(..) {
|
||||||
let resource = self.create_texture(&texture_descriptor, None);
|
let resource = self.create_texture(&texture_descriptor, None);
|
||||||
self.wgpu_resources
|
render_resource_assignments.set(&name, resource);
|
||||||
.render_resources
|
|
||||||
.set_named_resource(&name, resource);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,33 +416,31 @@ impl Renderer for WgpuRenderer {
|
|||||||
let shader_storage = resources.get::<AssetStorage<Shader>>().unwrap();
|
let shader_storage = resources.get::<AssetStorage<Shader>>().unwrap();
|
||||||
let render_graph = resources.get::<RenderGraph>().unwrap();
|
let render_graph = resources.get::<RenderGraph>().unwrap();
|
||||||
let mut render_graph_mut = resources.get_mut::<RenderGraph>().unwrap();
|
let mut render_graph_mut = resources.get_mut::<RenderGraph>().unwrap();
|
||||||
|
let global_render_resource_assignments =
|
||||||
|
resources.get::<RenderResourceAssignments>().unwrap();
|
||||||
|
let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap();
|
||||||
|
|
||||||
for pipeline_descriptor_handle in render_graph.pipeline_descriptors.iter() {
|
for pipeline_descriptor_handle in render_graph.pipeline_descriptors.iter() {
|
||||||
let pipeline_descriptor = pipeline_storage
|
if let Some(compiled_pipelines_iter) =
|
||||||
.get_mut(pipeline_descriptor_handle)
|
pipeline_compiler.iter_compiled_pipelines(*pipeline_descriptor_handle)
|
||||||
.unwrap();
|
|
||||||
// create pipelines
|
|
||||||
if !self
|
|
||||||
.render_pipelines
|
|
||||||
.contains_key(pipeline_descriptor_handle)
|
|
||||||
{
|
{
|
||||||
let vertex_shader = shader_storage
|
for compiled_pipeline_handle in compiled_pipelines_iter {
|
||||||
.get(&pipeline_descriptor.shader_stages.vertex)
|
// create pipelines
|
||||||
.unwrap();
|
// TODO: merge this into "setup draw targets" loop
|
||||||
let fragment_shader = pipeline_descriptor
|
if !self.render_pipelines.contains_key(compiled_pipeline_handle) {
|
||||||
.shader_stages
|
let compiled_pipeline_descriptor =
|
||||||
.fragment
|
pipeline_storage.get_mut(compiled_pipeline_handle).unwrap();
|
||||||
.as_ref()
|
|
||||||
.map(|handle| &*shader_storage.get(&handle).unwrap());
|
let render_pipeline = WgpuRenderer::create_render_pipeline(
|
||||||
let render_pipeline = WgpuRenderer::create_render_pipeline(
|
&mut self.wgpu_resources,
|
||||||
&mut self.wgpu_resources,
|
compiled_pipeline_descriptor,
|
||||||
pipeline_descriptor,
|
&shader_storage,
|
||||||
&self.device.borrow(),
|
&self.device.borrow(),
|
||||||
&render_graph,
|
);
|
||||||
vertex_shader,
|
self.render_pipelines
|
||||||
fragment_shader,
|
.insert(*compiled_pipeline_handle, render_pipeline);
|
||||||
);
|
}
|
||||||
self.render_pipelines
|
}
|
||||||
.insert(*pipeline_descriptor_handle, render_pipeline);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,13 +448,25 @@ impl Renderer for WgpuRenderer {
|
|||||||
for (pass_name, _pass_descriptor) in render_graph.pass_descriptors.iter() {
|
for (pass_name, _pass_descriptor) in render_graph.pass_descriptors.iter() {
|
||||||
if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) {
|
if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) {
|
||||||
for pass_pipeline in pass_pipelines.iter() {
|
for pass_pipeline in pass_pipelines.iter() {
|
||||||
let pipeline_descriptor = pipeline_storage.get(pass_pipeline).unwrap();
|
if let Some(compiled_pipelines_iter) =
|
||||||
for draw_target_name in pipeline_descriptor.draw_targets.iter() {
|
pipeline_compiler.iter_compiled_pipelines(*pass_pipeline)
|
||||||
let draw_target = render_graph_mut
|
{
|
||||||
.draw_targets
|
for compiled_pipeline_handle in compiled_pipelines_iter {
|
||||||
.get_mut(draw_target_name)
|
let pipeline_descriptor =
|
||||||
.unwrap();
|
pipeline_storage.get(compiled_pipeline_handle).unwrap();
|
||||||
draw_target.setup(world, resources, self, *pass_pipeline);
|
for draw_target_name in pipeline_descriptor.draw_targets.iter() {
|
||||||
|
let draw_target = render_graph_mut
|
||||||
|
.draw_targets
|
||||||
|
.get_mut(draw_target_name)
|
||||||
|
.unwrap();
|
||||||
|
draw_target.setup(
|
||||||
|
world,
|
||||||
|
resources,
|
||||||
|
self,
|
||||||
|
*compiled_pipeline_handle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -522,25 +477,40 @@ impl Renderer for WgpuRenderer {
|
|||||||
let mut render_pass = Self::create_render_pass(
|
let mut render_pass = Self::create_render_pass(
|
||||||
&self.wgpu_resources,
|
&self.wgpu_resources,
|
||||||
pass_descriptor,
|
pass_descriptor,
|
||||||
|
&global_render_resource_assignments,
|
||||||
&mut encoder,
|
&mut encoder,
|
||||||
&frame,
|
&frame,
|
||||||
);
|
);
|
||||||
if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) {
|
if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) {
|
||||||
for pass_pipeline in pass_pipelines.iter() {
|
for pass_pipeline in pass_pipelines.iter() {
|
||||||
let pipeline_descriptor = pipeline_storage.get(pass_pipeline).unwrap();
|
if let Some(compiled_pipelines_iter) =
|
||||||
let render_pipeline = self.render_pipelines.get(pass_pipeline).unwrap();
|
pipeline_compiler.iter_compiled_pipelines(*pass_pipeline)
|
||||||
render_pass.set_pipeline(render_pipeline);
|
{
|
||||||
|
for compiled_pipeline_handle in compiled_pipelines_iter {
|
||||||
|
let pipeline_descriptor =
|
||||||
|
pipeline_storage.get(compiled_pipeline_handle).unwrap();
|
||||||
|
let render_pipeline =
|
||||||
|
self.render_pipelines.get(compiled_pipeline_handle).unwrap();
|
||||||
|
render_pass.set_pipeline(render_pipeline);
|
||||||
|
|
||||||
let mut wgpu_render_pass = WgpuRenderPass {
|
let mut wgpu_render_pass = WgpuRenderPass {
|
||||||
render_pass: &mut render_pass,
|
render_pass: &mut render_pass,
|
||||||
pipeline_descriptor,
|
pipeline_descriptor,
|
||||||
wgpu_resources: &self.wgpu_resources,
|
wgpu_resources: &self.wgpu_resources,
|
||||||
renderer: &self,
|
renderer: &self,
|
||||||
};
|
};
|
||||||
|
|
||||||
for draw_target_name in pipeline_descriptor.draw_targets.iter() {
|
for draw_target_name in pipeline_descriptor.draw_targets.iter() {
|
||||||
let draw_target = render_graph.draw_targets.get(draw_target_name).unwrap();
|
let draw_target =
|
||||||
draw_target.draw(world, resources, &mut wgpu_render_pass, *pass_pipeline);
|
render_graph.draw_targets.get(draw_target_name).unwrap();
|
||||||
|
draw_target.draw(
|
||||||
|
world,
|
||||||
|
resources,
|
||||||
|
&mut wgpu_render_pass,
|
||||||
|
*compiled_pipeline_handle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
use super::WgpuRenderer;
|
use super::WgpuRenderer;
|
||||||
use crate::render::{
|
use crate::{
|
||||||
pipeline::{BindGroupDescriptor, BindGroupDescriptorId, BindType},
|
asset::{AssetStorage, Handle},
|
||||||
render_resource::{
|
prelude::Shader,
|
||||||
BufferInfo, RenderResource, RenderResourceAssignments, RenderResourceSetId,
|
render::{
|
||||||
RenderResources, ResourceInfo,
|
pipeline::{BindGroupDescriptor, BindGroupDescriptorId, BindType},
|
||||||
|
render_resource::{
|
||||||
|
BufferInfo, RenderResource, RenderResourceAssignments, RenderResourceSetId,
|
||||||
|
RenderResources, ResourceInfo,
|
||||||
|
},
|
||||||
|
renderer::Renderer,
|
||||||
|
texture::{SamplerDescriptor, TextureDescriptor},
|
||||||
},
|
},
|
||||||
renderer::Renderer,
|
|
||||||
texture::{SamplerDescriptor, TextureDescriptor},
|
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@ -15,29 +19,19 @@ pub struct WgpuBindGroupInfo {
|
|||||||
pub bind_groups: HashMap<RenderResourceSetId, wgpu::BindGroup>,
|
pub bind_groups: HashMap<RenderResourceSetId, wgpu::BindGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct WgpuResources {
|
pub struct WgpuResources {
|
||||||
pub render_resources: RenderResources,
|
pub render_resources: RenderResources,
|
||||||
pub buffers: HashMap<RenderResource, wgpu::Buffer>,
|
pub buffers: HashMap<RenderResource, wgpu::Buffer>,
|
||||||
pub textures: HashMap<RenderResource, wgpu::TextureView>,
|
pub textures: HashMap<RenderResource, wgpu::TextureView>,
|
||||||
pub samplers: HashMap<RenderResource, wgpu::Sampler>,
|
pub samplers: HashMap<RenderResource, wgpu::Sampler>,
|
||||||
pub resource_info: HashMap<RenderResource, ResourceInfo>,
|
pub resource_info: HashMap<RenderResource, ResourceInfo>,
|
||||||
|
pub shader_modules: HashMap<Handle<Shader>, wgpu::ShaderModule>,
|
||||||
pub bind_groups: HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>,
|
pub bind_groups: HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>,
|
||||||
pub bind_group_layouts: HashMap<BindGroupDescriptorId, wgpu::BindGroupLayout>,
|
pub bind_group_layouts: HashMap<BindGroupDescriptorId, wgpu::BindGroupLayout>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WgpuResources {
|
impl WgpuResources {
|
||||||
pub fn new() -> Self {
|
|
||||||
WgpuResources {
|
|
||||||
buffers: HashMap::new(),
|
|
||||||
textures: HashMap::new(),
|
|
||||||
samplers: HashMap::new(),
|
|
||||||
resource_info: HashMap::new(),
|
|
||||||
bind_groups: HashMap::new(),
|
|
||||||
bind_group_layouts: HashMap::new(),
|
|
||||||
render_resources: RenderResources::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_resource_info(&mut self, resource: RenderResource, resource_info: ResourceInfo) {
|
pub fn add_resource_info(&mut self, resource: RenderResource, resource_info: ResourceInfo) {
|
||||||
self.resource_info.insert(resource, resource_info);
|
self.resource_info.insert(resource, resource_info);
|
||||||
}
|
}
|
||||||
@ -67,7 +61,7 @@ impl WgpuResources {
|
|||||||
.bindings
|
.bindings
|
||||||
.iter()
|
.iter()
|
||||||
.map(|binding| {
|
.map(|binding| {
|
||||||
if let Some((resource, index)) = render_resource_assignments.get(&binding.name) {
|
if let Some(resource) = render_resource_assignments.get(&binding.name) {
|
||||||
let resource_info = self.resource_info.get(&resource).unwrap();
|
let resource_info = self.resource_info.get(&resource).unwrap();
|
||||||
wgpu::Binding {
|
wgpu::Binding {
|
||||||
binding: binding.index,
|
binding: binding.index,
|
||||||
@ -121,9 +115,7 @@ impl WgpuResources {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let bind_group = device.create_bind_group(&wgpu_bind_group_descriptor);
|
let bind_group = device.create_bind_group(&wgpu_bind_group_descriptor);
|
||||||
// TODO: storing a large number entity bind groups might actually be really bad. make sure this is ok
|
let bind_group_info = self
|
||||||
|
|
||||||
let mut bind_group_info = self
|
|
||||||
.bind_groups
|
.bind_groups
|
||||||
.entry(bind_group_descriptor.id)
|
.entry(bind_group_descriptor.id)
|
||||||
.or_insert_with(|| WgpuBindGroupInfo::default());
|
.or_insert_with(|| WgpuBindGroupInfo::default());
|
||||||
@ -212,6 +204,18 @@ impl WgpuResources {
|
|||||||
encoder.copy_buffer_to_buffer(source, source_offset, destination, destination_offset, size);
|
encoder.copy_buffer_to_buffer(source, source_offset, destination, destination_offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_shader_module(
|
||||||
|
&mut self,
|
||||||
|
device: &wgpu::Device,
|
||||||
|
shader_handle: Handle<Shader>,
|
||||||
|
shader_storage: &AssetStorage<Shader>,
|
||||||
|
) {
|
||||||
|
self.shader_modules.entry(shader_handle).or_insert_with(|| {
|
||||||
|
let shader = shader_storage.get(&shader_handle).unwrap();
|
||||||
|
device.create_shader_module(&shader.get_spirv(None))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_sampler(
|
pub fn create_sampler(
|
||||||
&mut self,
|
&mut self,
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::render::{
|
use crate::render::{
|
||||||
pipeline::{
|
pipeline::{
|
||||||
BindGroupDescriptor, BindType, BindingDescriptor, InputStepMode, UniformProperty, UniformPropertyType,
|
BindGroupDescriptor, BindType, BindingDescriptor, InputStepMode, UniformProperty,
|
||||||
VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat,
|
UniformPropertyType, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat,
|
||||||
},
|
},
|
||||||
texture::TextureViewDimension,
|
texture::TextureViewDimension,
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user