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)
|
||||
* 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
|
||||
* Separate original/uncompiled/no_defs PipelineDescriptor from compiled PipelineDescriptor conceptually
|
||||
* Try to make Renderer a resource + system
|
||||
* Docs
|
||||
* Add doc comments to code
|
||||
* Add tutorials
|
||||
|
||||
@ -6,7 +6,11 @@ use winit::{
|
||||
|
||||
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 universe: Universe,
|
||||
@ -90,7 +94,12 @@ impl App {
|
||||
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 {
|
||||
println!("no renderer {} {}", size.width, size.height);
|
||||
}
|
||||
|
||||
@ -13,10 +13,11 @@ use crate::{
|
||||
};
|
||||
|
||||
use bevy_transform::{prelude::LocalToWorld, transform_system_bundle};
|
||||
use pipeline::PipelineDescriptor;
|
||||
use pipeline::{PipelineCompiler, PipelineDescriptor, ShaderPipelineAssignments};
|
||||
use render_graph::{RenderGraph, RenderGraphBuilder};
|
||||
use render_resource::{
|
||||
build_entity_render_resource_assignments_system, AssetBatchers, EntityRenderResourceAssignments,
|
||||
build_entity_render_resource_assignments_system, AssetBatchers,
|
||||
EntityRenderResourceAssignments, RenderResourceAssignments,
|
||||
};
|
||||
use shader::Shader;
|
||||
use std::collections::HashMap;
|
||||
@ -165,7 +166,8 @@ impl AppBuilder {
|
||||
resources.insert(AssetStorage::<StandardMaterial>::new());
|
||||
resources.insert(AssetStorage::<PipelineDescriptor>::new());
|
||||
resources.insert(ShaderPipelineAssignments::new());
|
||||
resources.insert(CompiledShaderMap::new());
|
||||
resources.insert(PipelineCompiler::new());
|
||||
resources.insert(RenderResourceAssignments::default());
|
||||
resources.insert(EntityRenderResourceAssignments::default());
|
||||
self.batch_types2::<Mesh, StandardMaterial>();
|
||||
self
|
||||
@ -212,11 +214,11 @@ impl AppBuilder {
|
||||
.add_resource_provider(LightResourceProvider::new(10))
|
||||
.add_resource_provider(UiResourceProvider::new())
|
||||
.add_resource_provider(MeshResourceProvider::new())
|
||||
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(true))
|
||||
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(true))
|
||||
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(false))
|
||||
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(false))
|
||||
.add_forward_pass()
|
||||
.add_forward_pipeline()
|
||||
.add_ui_pipeline();
|
||||
.add_forward_pipeline();
|
||||
// .add_ui_pipeline();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -4,10 +4,12 @@ use crate::{
|
||||
render::{
|
||||
draw_target::DrawTarget,
|
||||
mesh::Mesh,
|
||||
pipeline::PipelineDescriptor,
|
||||
render_resource::{resource_name, EntityRenderResourceAssignments, ResourceInfo},
|
||||
pipeline::{PipelineDescriptor, ShaderPipelineAssignments},
|
||||
render_resource::{
|
||||
resource_name, EntityRenderResourceAssignments, RenderResourceAssignments, ResourceInfo,
|
||||
},
|
||||
renderer::{RenderPass, Renderer},
|
||||
Renderable, ShaderPipelineAssignments,
|
||||
Renderable,
|
||||
},
|
||||
};
|
||||
|
||||
@ -27,6 +29,9 @@ impl DrawTarget for AssignedMeshesDrawTarget {
|
||||
resources.get::<EntityRenderResourceAssignments>().unwrap();
|
||||
let mut current_mesh_handle = None;
|
||||
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
|
||||
.assignments
|
||||
@ -87,6 +92,9 @@ impl DrawTarget for AssignedMeshesDrawTarget {
|
||||
.get(&pipeline_handle);
|
||||
let pipeline_storage = resources.get::<AssetStorage<PipelineDescriptor>>().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 {
|
||||
for assignment_id in assigned_render_resource_assignments.iter() {
|
||||
// TODO: hopefully legion has better random access apis that are more like queries?
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
asset::{Asset, Handle},
|
||||
asset::{Asset, AssetStorage, Handle},
|
||||
legion::prelude::*,
|
||||
math,
|
||||
prelude::MeshType,
|
||||
@ -7,7 +7,10 @@ use crate::{
|
||||
draw_target::DrawTarget,
|
||||
mesh::Mesh,
|
||||
pipeline::PipelineDescriptor,
|
||||
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResource, ResourceInfo},
|
||||
render_resource::{
|
||||
resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
|
||||
ResourceInfo,
|
||||
},
|
||||
renderer::{RenderPass, Renderer},
|
||||
},
|
||||
};
|
||||
@ -30,12 +33,9 @@ impl DrawTarget for UiDrawTarget {
|
||||
render_pass: &mut dyn RenderPass,
|
||||
_pipeline_handle: Handle<PipelineDescriptor>,
|
||||
) {
|
||||
let render_resource_assignments = resources.get::<RenderResourceAssignments>().unwrap();
|
||||
let ui_instances_buffer = {
|
||||
let renderer = render_pass.get_renderer();
|
||||
match renderer
|
||||
.get_render_resources()
|
||||
.get_named_resource(resource_name::buffer::UI_INSTANCES)
|
||||
{
|
||||
match render_resource_assignments.get(resource_name::buffer::UI_INSTANCES) {
|
||||
Some(buffer) => buffer,
|
||||
None => return,
|
||||
}
|
||||
@ -54,24 +54,25 @@ impl DrawTarget for UiDrawTarget {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: set global render resources
|
||||
// render_pass.set_render_resources(None);
|
||||
// render_pass.set_index_buffer(self.mesh_index_buffer.unwrap(), 0);
|
||||
// render_pass.set_vertex_buffer(0, self.mesh_vertex_buffer.unwrap(), 0);
|
||||
// render_pass.set_vertex_buffer(1, ui_instances_buffer, 0);
|
||||
// render_pass.draw_indexed(
|
||||
// 0..self.mesh_index_length as u32,
|
||||
// 0,
|
||||
// 0..(index_count.unwrap() as u32),
|
||||
// );
|
||||
let global_render_resource_assignments =
|
||||
resources.get::<RenderResourceAssignments>().unwrap();
|
||||
render_pass.set_render_resources(&global_render_resource_assignments);
|
||||
render_pass.set_index_buffer(self.mesh_index_buffer.unwrap(), 0);
|
||||
render_pass.set_vertex_buffer(0, self.mesh_vertex_buffer.unwrap(), 0);
|
||||
render_pass.set_vertex_buffer(1, ui_instances_buffer, 0);
|
||||
render_pass.draw_indexed(
|
||||
0..self.mesh_index_length as u32,
|
||||
0,
|
||||
0..(index_count.unwrap() as u32),
|
||||
);
|
||||
}
|
||||
|
||||
fn setup(
|
||||
&mut self,
|
||||
_world: &mut World,
|
||||
_resources: &Resources,
|
||||
resources: &Resources,
|
||||
renderer: &mut dyn Renderer,
|
||||
_pipeline_handle: Handle<PipelineDescriptor>,
|
||||
pipeline_handle: Handle<PipelineDescriptor>,
|
||||
) {
|
||||
// don't create meshes if they have already been created
|
||||
if let Some(_) = self.mesh_vertex_buffer {
|
||||
@ -99,6 +100,12 @@ impl DrawTarget for UiDrawTarget {
|
||||
quad.indices.as_bytes(),
|
||||
));
|
||||
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 {
|
||||
resource_name::draw_target::UI.to_string()
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
mod bind_group;
|
||||
mod binding;
|
||||
mod pipeline;
|
||||
mod pipeline_compiler;
|
||||
mod pipeline_layout;
|
||||
pub mod pipelines;
|
||||
pub mod state_descriptors;
|
||||
@ -10,6 +11,7 @@ mod vertex_format;
|
||||
pub use bind_group::*;
|
||||
pub use binding::*;
|
||||
pub use pipeline::*;
|
||||
pub use pipeline_compiler::*;
|
||||
pub use pipeline_layout::*;
|
||||
pub use vertex_buffer_descriptor::*;
|
||||
pub use vertex_format::*;
|
||||
|
||||
@ -33,7 +33,6 @@ pub struct PipelineDescriptor {
|
||||
pub draw_targets: Vec<String>,
|
||||
pub layout: PipelineLayoutType,
|
||||
pub shader_stages: ShaderStages,
|
||||
pub reflect_vertex_buffer_descriptors: bool,
|
||||
pub rasterization_state: Option<RasterizationStateDescriptor>,
|
||||
|
||||
/// The primitive topology used to interpret vertices.
|
||||
@ -48,9 +47,6 @@ pub struct PipelineDescriptor {
|
||||
/// The format of any index buffers used with this pipeline.
|
||||
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).
|
||||
pub sample_count: u32,
|
||||
|
||||
@ -74,7 +70,6 @@ impl PipelineDescriptor {
|
||||
depth_stencil_state: None,
|
||||
draw_targets: Vec::new(),
|
||||
shader_stages: ShaderStages::new(vertex_shader),
|
||||
vertex_buffer_descriptors: Vec::new(),
|
||||
rasterization_state: Some(RasterizationStateDescriptor {
|
||||
front_face: FrontFace::Ccw,
|
||||
cull_mode: CullMode::Back,
|
||||
@ -82,7 +77,6 @@ impl PipelineDescriptor {
|
||||
depth_bias_slope_scale: 0.0,
|
||||
depth_bias_clamp: 0.0,
|
||||
}),
|
||||
reflect_vertex_buffer_descriptors: true,
|
||||
primitive_topology: PrimitiveTopology::TriangleList,
|
||||
index_format: IndexFormat::Uint16,
|
||||
sample_count: 1,
|
||||
@ -170,12 +164,12 @@ impl<'a> PipelineBuilder<'a> {
|
||||
}
|
||||
|
||||
pub fn add_bind_group(&mut self, bind_group: BindGroupDescriptor) -> &mut Self {
|
||||
if let PipelineLayoutType::Reflected(_) = self.pipeline.as_ref().unwrap().layout {
|
||||
self.pipeline.as_mut().unwrap().layout =
|
||||
PipelineLayoutType::Manual(PipelineLayout::new());
|
||||
let pipeline = self.pipeline.as_mut().unwrap();
|
||||
if let PipelineLayoutType::Reflected(_) = pipeline.layout {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -187,10 +181,16 @@ impl<'a> PipelineBuilder<'a> {
|
||||
vertex_buffer_descriptor: VertexBufferDescriptor,
|
||||
) -> &mut Self {
|
||||
let pipeline = self.pipeline.as_mut().unwrap();
|
||||
pipeline.reflect_vertex_buffer_descriptors = false;
|
||||
pipeline
|
||||
if let PipelineLayoutType::Reflected(_) = pipeline.layout {
|
||||
pipeline.layout = PipelineLayoutType::Manual(PipelineLayout::default());
|
||||
}
|
||||
|
||||
if let PipelineLayoutType::Manual(ref mut layout) = pipeline.layout {
|
||||
layout
|
||||
.vertex_buffer_descriptors
|
||||
.push(vertex_buffer_descriptor);
|
||||
}
|
||||
|
||||
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 crate::render::shader::ShaderLayout;
|
||||
use super::{BindGroupDescriptor, VertexBufferDescriptor};
|
||||
use crate::render::{render_graph::RenderGraph, shader::ShaderLayout};
|
||||
use std::{collections::HashMap, hash::Hash};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct PipelineLayout {
|
||||
pub bind_groups: Vec<BindGroupDescriptor>,
|
||||
pub vertex_buffer_descriptors: Vec<VertexBufferDescriptor>,
|
||||
}
|
||||
|
||||
impl PipelineLayout {
|
||||
pub fn new() -> Self {
|
||||
PipelineLayout {
|
||||
bind_groups: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_shader_layouts(shader_layouts: &mut [ShaderLayout]) -> Self {
|
||||
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() {
|
||||
match bind_groups.get_mut(&shader_bind_group.index) {
|
||||
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
|
||||
.drain()
|
||||
.map(|(_, value)| value)
|
||||
.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
|
||||
// TODO: try removing this
|
||||
bind_groups_result.sort_by(|a, b| a.index.partial_cmp(&b.index).unwrap());
|
||||
|
||||
PipelineLayout {
|
||||
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];
|
||||
};
|
||||
|
||||
// TODO: this should be binding = 0 right?
|
||||
layout(set = 2, binding = 1) uniform StandardMaterial_albedo {
|
||||
vec4 Albedo;
|
||||
};
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
use crate::{
|
||||
asset::{HandleId, HandleUntyped},
|
||||
};
|
||||
use super::{AssetBatcher, Batch};
|
||||
use crate::asset::{HandleId, HandleUntyped};
|
||||
use legion::prelude::Entity;
|
||||
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
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::{asset::HandleUntyped, render::render_resource::RenderResourceAssignments};
|
||||
use legion::prelude::Entity;
|
||||
use std::collections::{HashSet, HashMap};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Default)]
|
||||
pub struct Batch {
|
||||
@ -18,7 +18,8 @@ impl Batch {
|
||||
|
||||
pub fn add_instanced_entity(&mut self, entity: 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ use crate::{
|
||||
render::{mesh::Mesh, texture::Texture},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use super::RenderResourceAssignments;
|
||||
|
||||
#[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)]
|
||||
pub struct RenderResource(pub u64);
|
||||
@ -12,7 +11,6 @@ pub struct RenderResource(pub u64);
|
||||
// the overlap could cause accidents.
|
||||
#[derive(Default)]
|
||||
pub struct RenderResources {
|
||||
pub global_assignments: RenderResourceAssignments,
|
||||
pub texture_to_resource: HashMap<Handle<Texture>, RenderResource>,
|
||||
pub texture_to_sampler_resource: HashMap<Handle<Texture>, RenderResource>,
|
||||
pub mesh_to_vertices_resource: HashMap<Handle<Mesh>, RenderResource>,
|
||||
@ -21,14 +19,6 @@ pub struct 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) {
|
||||
self.texture_to_resource.insert(texture, resource);
|
||||
}
|
||||
|
||||
@ -20,7 +20,11 @@ pub struct 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()
|
||||
}
|
||||
|
||||
@ -84,7 +88,7 @@ impl RenderResourceAssignments {
|
||||
} else {
|
||||
self.bind_group_resource_sets
|
||||
.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 indices = Vec::new();
|
||||
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);
|
||||
if let Some(index) = 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, 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_eq!(equal_set_id, set_id);
|
||||
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
use crate::render::{
|
||||
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResource, ResourceProvider},
|
||||
render_resource::{
|
||||
resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
|
||||
ResourceProvider,
|
||||
},
|
||||
renderer::Renderer,
|
||||
ActiveCamera2d, Camera,
|
||||
};
|
||||
@ -17,7 +20,7 @@ impl ResourceProvider for Camera2dResourceProvider {
|
||||
&mut self,
|
||||
renderer: &mut dyn Renderer,
|
||||
_world: &mut World,
|
||||
_resources: &Resources,
|
||||
resources: &Resources,
|
||||
) {
|
||||
let buffer = renderer.create_buffer(BufferInfo {
|
||||
size: std::mem::size_of::<[[f32; 4]; 4]>(),
|
||||
@ -25,9 +28,9 @@ impl ResourceProvider for Camera2dResourceProvider {
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
renderer
|
||||
.get_render_resources_mut()
|
||||
.set_named_resource(resource_name::uniform::CAMERA2D, buffer);
|
||||
let mut render_resource_assignments =
|
||||
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||
render_resource_assignments.set(resource_name::uniform::CAMERA2D, buffer);
|
||||
self.camera_buffer = Some(buffer);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
use crate::render::{
|
||||
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResource, ResourceProvider},
|
||||
render_resource::{
|
||||
resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
|
||||
ResourceProvider,
|
||||
},
|
||||
renderer::Renderer,
|
||||
ActiveCamera, Camera,
|
||||
};
|
||||
@ -18,7 +21,7 @@ impl ResourceProvider for CameraResourceProvider {
|
||||
&mut self,
|
||||
renderer: &mut dyn Renderer,
|
||||
_world: &mut World,
|
||||
_resources: &Resources,
|
||||
resources: &Resources,
|
||||
) {
|
||||
let buffer = renderer.create_buffer(BufferInfo {
|
||||
size: std::mem::size_of::<[[f32; 4]; 4]>(),
|
||||
@ -26,9 +29,9 @@ impl ResourceProvider for CameraResourceProvider {
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
renderer
|
||||
.get_render_resources_mut()
|
||||
.set_named_resource(resource_name::uniform::CAMERA, buffer);
|
||||
let mut render_resource_assignments =
|
||||
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||
render_resource_assignments.set(resource_name::uniform::CAMERA, buffer);
|
||||
self.camera_buffer = Some(buffer);
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
use crate::{
|
||||
core::Window,
|
||||
prelude::World,
|
||||
render::{render_resource::ResourceProvider, renderer::Renderer, texture::TextureDescriptor},
|
||||
render::{
|
||||
render_resource::{RenderResourceAssignments, ResourceProvider},
|
||||
renderer::Renderer,
|
||||
texture::TextureDescriptor,
|
||||
},
|
||||
};
|
||||
use legion::prelude::Resources;
|
||||
|
||||
@ -23,17 +27,14 @@ impl FrameTextureResourceProvider {
|
||||
self.descriptor.size.width = window.width;
|
||||
self.descriptor.size.height = window.height;
|
||||
|
||||
if let Some(old_resource) = renderer
|
||||
.get_render_resources()
|
||||
.get_named_resource(&self.name)
|
||||
{
|
||||
let mut render_resource_assignments =
|
||||
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||
if let Some(old_resource) = render_resource_assignments.get(&self.name) {
|
||||
renderer.remove_texture(old_resource);
|
||||
}
|
||||
|
||||
let texture_resource = renderer.create_texture(&self.descriptor, None);
|
||||
renderer
|
||||
.get_render_resources_mut()
|
||||
.set_named_resource(&self.name, texture_resource);
|
||||
render_resource_assignments.set(&self.name, texture_resource);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
use crate::render::{
|
||||
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResource, ResourceProvider},
|
||||
render_resource::{
|
||||
resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
|
||||
ResourceProvider,
|
||||
},
|
||||
renderer::Renderer,
|
||||
Light, LightRaw,
|
||||
};
|
||||
@ -38,7 +41,7 @@ impl ResourceProvider for LightResourceProvider {
|
||||
&mut self,
|
||||
renderer: &mut dyn Renderer,
|
||||
_world: &mut World,
|
||||
_resources: &Resources,
|
||||
resources: &Resources,
|
||||
) {
|
||||
let light_uniform_size =
|
||||
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,
|
||||
..Default::default()
|
||||
});
|
||||
renderer
|
||||
.get_render_resources_mut()
|
||||
.set_named_resource(resource_name::uniform::LIGHTS, buffer);
|
||||
let mut render_resource_assignments =
|
||||
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||
render_resource_assignments.set(resource_name::uniform::LIGHTS, buffer);
|
||||
self.light_buffer = Some(buffer);
|
||||
}
|
||||
|
||||
|
||||
@ -89,12 +89,12 @@ impl ResourceProvider for MeshResourceProvider {
|
||||
&mut self,
|
||||
_renderer: &mut dyn Renderer,
|
||||
_world: &mut World,
|
||||
resources: &Resources,
|
||||
_resources: &Resources,
|
||||
) {
|
||||
let mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
|
||||
for batch in asset_batchers.get_handle_batches::<Mesh>() {
|
||||
// batch.render_resource_assignments.
|
||||
}
|
||||
// TODO: assign vertex buffers
|
||||
// let mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
// let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
|
||||
// for batch in asset_batchers.get_handle_batches::<Mesh>() {
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ use crate::{
|
||||
render_graph::RenderGraph,
|
||||
render_resource::{
|
||||
resource_name, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource,
|
||||
ResourceProvider,
|
||||
RenderResourceAssignments, ResourceProvider,
|
||||
},
|
||||
renderer::Renderer,
|
||||
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 mut data = Vec::new();
|
||||
@ -99,9 +99,9 @@ impl UiResourceProvider {
|
||||
data.as_bytes(),
|
||||
);
|
||||
|
||||
renderer
|
||||
.get_render_resources_mut()
|
||||
.set_named_resource(resource_name::buffer::UI_INSTANCES, buffer);
|
||||
let mut render_resource_assignments =
|
||||
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||
render_resource_assignments.set(resource_name::buffer::UI_INSTANCES, 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());
|
||||
}
|
||||
|
||||
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, _resources: &Resources) {
|
||||
self.update(renderer, world);
|
||||
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {
|
||||
self.update(renderer, world, resources);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,8 +4,7 @@ use crate::{
|
||||
render_graph::RenderGraph,
|
||||
render_resource::{
|
||||
AssetBatchers, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource,
|
||||
RenderResourceAssignments, ResourceInfo,
|
||||
ResourceProvider,
|
||||
RenderResourceAssignments, ResourceInfo, ResourceProvider,
|
||||
},
|
||||
renderer::Renderer,
|
||||
shader::{AsUniforms, FieldBindType},
|
||||
@ -122,10 +121,7 @@ where
|
||||
self.increment_uniform_counts(&uniforms);
|
||||
}
|
||||
|
||||
Self::update_shader_defs(
|
||||
&uniforms,
|
||||
&mut renderable.render_resource_assignments,
|
||||
);
|
||||
Self::update_shader_defs(&uniforms, &mut renderable.render_resource_assignments);
|
||||
}
|
||||
|
||||
self.query = Some(query);
|
||||
@ -158,10 +154,7 @@ where
|
||||
let uniforms = assets
|
||||
.get(&handle)
|
||||
.expect("Handle points to a non-existent resource");
|
||||
Self::update_shader_defs(
|
||||
uniforms,
|
||||
&mut renderable.render_resource_assignments,
|
||||
);
|
||||
Self::update_shader_defs(uniforms, &mut renderable.render_resource_assignments);
|
||||
|
||||
self.increment_uniform_counts(&uniforms);
|
||||
}
|
||||
@ -264,9 +257,13 @@ where
|
||||
..
|
||||
})) = renderer.get_resource_info_mut(buffer)
|
||||
{
|
||||
let index = array_info
|
||||
.get_or_assign_index(render_resource_assignments.id);
|
||||
render_resource_assignments.set_indexed(&field_info.uniform_name, buffer, index as u32);
|
||||
let index =
|
||||
array_info.get_or_assign_index(render_resource_assignments.id);
|
||||
render_resource_assignments.set_indexed(
|
||||
&field_info.uniform_name,
|
||||
buffer,
|
||||
(index * array_info.item_size) as u32,
|
||||
);
|
||||
(buffer, index * uniform_buffer_status.aligned_size)
|
||||
} else {
|
||||
panic!("Expected a dynamic uniform buffer");
|
||||
@ -275,7 +272,7 @@ where
|
||||
let resource = match render_resource_assignments
|
||||
.get(field_info.uniform_name)
|
||||
{
|
||||
Some((render_resource, _index)) => render_resource,
|
||||
Some(render_resource) => render_resource,
|
||||
None => {
|
||||
let resource = renderer.create_buffer(BufferInfo {
|
||||
size,
|
||||
@ -470,12 +467,9 @@ where
|
||||
|
||||
fn setup_buffer_arrays(&mut self, renderer: &mut dyn Renderer) {
|
||||
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 {
|
||||
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 =
|
||||
|
||||
@ -1,14 +1,5 @@
|
||||
use super::{
|
||||
pipeline::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};
|
||||
use super::render_resource::RenderResourceAssignments;
|
||||
use crate::{asset::Handle, prelude::PipelineDescriptor};
|
||||
|
||||
pub struct Renderable {
|
||||
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_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 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 crate::render::{
|
||||
pipeline::{BindType, PipelineDescriptor},
|
||||
render_resource::{BufferInfo, RenderResource, RenderResourceAssignments, ResourceInfo},
|
||||
pipeline::PipelineDescriptor,
|
||||
render_resource::{RenderResource, RenderResourceAssignments},
|
||||
renderer::{RenderPass, Renderer},
|
||||
};
|
||||
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
|
||||
let empty = &[];
|
||||
let dynamic_uniform_indices = if let Some(dynamic_uniform_indices) = dynamic_uniform_indices {
|
||||
let dynamic_uniform_indices =
|
||||
if let Some(dynamic_uniform_indices) = dynamic_uniform_indices {
|
||||
dynamic_uniform_indices.as_slice()
|
||||
} else {
|
||||
empty
|
||||
};
|
||||
|
||||
// TODO: remove this
|
||||
// if dynamic_uniform_indices.len() == 0 && bind_group.index > 0 {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
self.render_pass.set_bind_group(
|
||||
bind_group.index,
|
||||
&wgpu_bind_group,
|
||||
|
||||
@ -8,7 +8,7 @@ use crate::{
|
||||
PassDescriptor, RenderPassColorAttachmentDescriptor,
|
||||
RenderPassDepthStencilAttachmentDescriptor,
|
||||
},
|
||||
pipeline::{BindType, PipelineDescriptor, PipelineLayout, PipelineLayoutType},
|
||||
pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor},
|
||||
render_graph::RenderGraph,
|
||||
render_resource::{
|
||||
resource_name, BufferInfo, RenderResource, RenderResourceAssignments, RenderResources,
|
||||
@ -17,7 +17,6 @@ use crate::{
|
||||
renderer::Renderer,
|
||||
shader::Shader,
|
||||
texture::{SamplerDescriptor, TextureDescriptor},
|
||||
update_shader_assignments,
|
||||
},
|
||||
};
|
||||
use std::{cell::RefCell, collections::HashMap, ops::Deref, rc::Rc};
|
||||
@ -65,7 +64,7 @@ impl WgpuRenderer {
|
||||
encoder: None,
|
||||
intialized: false,
|
||||
swap_chain_descriptor,
|
||||
wgpu_resources: WgpuResources::new(),
|
||||
wgpu_resources: WgpuResources::default(),
|
||||
render_pipelines: HashMap::new(),
|
||||
}
|
||||
}
|
||||
@ -88,102 +87,14 @@ impl WgpuRenderer {
|
||||
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(
|
||||
wgpu_resources: &mut WgpuResources,
|
||||
pipeline_descriptor: &mut PipelineDescriptor,
|
||||
shader_storage: &AssetStorage<Shader>,
|
||||
device: &wgpu::Device,
|
||||
render_graph: &RenderGraph,
|
||||
vertex_shader: &Shader,
|
||||
fragment_shader: Option<&Shader>,
|
||||
) -> wgpu::RenderPipeline {
|
||||
let vertex_spirv = vertex_shader.get_spirv_shader(None);
|
||||
let fragment_spirv = fragment_shader.map(|f| f.get_spirv_shader(None));
|
||||
|
||||
let vertex_shader_module = Self::create_shader_module(device, &vertex_spirv, None);
|
||||
let fragment_shader_module = match fragment_shader {
|
||||
Some(fragment_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() {
|
||||
let layout = pipeline_descriptor.get_layout().unwrap();
|
||||
for bind_group in layout.bind_groups.iter() {
|
||||
if let None = wgpu_resources.bind_group_layouts.get(&bind_group.id) {
|
||||
let bind_group_layout_binding = bind_group
|
||||
.bindings
|
||||
@ -194,18 +105,18 @@ impl WgpuRenderer {
|
||||
ty: (&binding.bind_type).into(),
|
||||
})
|
||||
.collect::<Vec<wgpu::BindGroupLayoutBinding>>();
|
||||
let bind_group_layout =
|
||||
let wgpu_bind_group_layout =
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
bindings: bind_group_layout_binding.as_slice(),
|
||||
});
|
||||
|
||||
wgpu_resources
|
||||
.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
|
||||
.bind_groups
|
||||
.iter()
|
||||
@ -221,8 +132,11 @@ impl WgpuRenderer {
|
||||
bind_group_layouts: bind_group_layouts.as_slice(),
|
||||
});
|
||||
|
||||
let owned_vertex_buffer_descriptors =
|
||||
Self::setup_vertex_buffer_descriptors(render_graph, &vertex_spirv, pipeline_descriptor);
|
||||
let owned_vertex_buffer_descriptors = layout
|
||||
.vertex_buffer_descriptors
|
||||
.iter()
|
||||
.map(|v| v.into())
|
||||
.collect::<Vec<OwnedWgpuVertexBufferDescriptor>>();
|
||||
|
||||
let color_states = pipeline_descriptor
|
||||
.color_states
|
||||
@ -230,13 +144,42 @@ impl WgpuRenderer {
|
||||
.map(|c| c.into())
|
||||
.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 {
|
||||
layout: &pipeline_layout,
|
||||
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
||||
module: &vertex_shader_module,
|
||||
entry_point: "main",
|
||||
},
|
||||
fragment_stage: match fragment_shader {
|
||||
fragment_stage: match pipeline_descriptor.shader_stages.fragment {
|
||||
Some(_) => Some(wgpu::ProgrammableStageDescriptor {
|
||||
entry_point: "main",
|
||||
module: fragment_shader_module.as_ref().unwrap(),
|
||||
@ -269,6 +212,7 @@ impl WgpuRenderer {
|
||||
pub fn create_render_pass<'a>(
|
||||
wgpu_resources: &'a WgpuResources,
|
||||
pass_descriptor: &PassDescriptor,
|
||||
global_render_resource_assignments: &RenderResourceAssignments,
|
||||
encoder: &'a mut wgpu::CommandEncoder,
|
||||
frame: &'a wgpu::SwapChainOutput,
|
||||
) -> wgpu::RenderPass<'a> {
|
||||
@ -276,25 +220,37 @@ impl WgpuRenderer {
|
||||
color_attachments: &pass_descriptor
|
||||
.color_attachments
|
||||
.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>>(),
|
||||
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>(
|
||||
wgpu_resources: &'a WgpuResources,
|
||||
global_render_resource_assignments: &RenderResourceAssignments,
|
||||
color_attachment_descriptor: &RenderPassColorAttachmentDescriptor,
|
||||
frame: &'a wgpu::SwapChainOutput,
|
||||
) -> wgpu::RenderPassColorAttachmentDescriptor<'a> {
|
||||
let attachment = match color_attachment_descriptor.attachment.as_str() {
|
||||
resource_name::texture::SWAP_CHAIN => &frame.view,
|
||||
_ => {
|
||||
match wgpu_resources
|
||||
.render_resources
|
||||
.get_named_resource(&color_attachment_descriptor.attachment)
|
||||
match global_render_resource_assignments
|
||||
.get(&color_attachment_descriptor.attachment)
|
||||
{
|
||||
Some(resource) => wgpu_resources.textures.get(&resource).unwrap(),
|
||||
None => panic!(
|
||||
@ -308,10 +264,7 @@ impl WgpuRenderer {
|
||||
let resolve_target = match color_attachment_descriptor.resolve_target {
|
||||
Some(ref target) => match target.as_str() {
|
||||
resource_name::texture::SWAP_CHAIN => Some(&frame.view),
|
||||
_ => match wgpu_resources
|
||||
.render_resources
|
||||
.get_named_resource(target.as_str())
|
||||
{
|
||||
_ => match global_render_resource_assignments.get(target.as_str()) {
|
||||
Some(resource) => Some(wgpu_resources.textures.get(&resource).unwrap()),
|
||||
None => panic!(
|
||||
"Color attachment {} does not exist",
|
||||
@ -333,15 +286,15 @@ impl WgpuRenderer {
|
||||
|
||||
fn create_wgpu_depth_stencil_attachment_descriptor<'a>(
|
||||
wgpu_resources: &'a WgpuResources,
|
||||
global_render_resource_assignments: &RenderResourceAssignments,
|
||||
depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor,
|
||||
frame: &'a wgpu::SwapChainOutput,
|
||||
) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> {
|
||||
let attachment = match depth_stencil_attachment_descriptor.attachment.as_str() {
|
||||
resource_name::texture::SWAP_CHAIN => &frame.view,
|
||||
_ => {
|
||||
match wgpu_resources
|
||||
.render_resources
|
||||
.get_named_resource(&depth_stencil_attachment_descriptor.attachment)
|
||||
match global_render_resource_assignments
|
||||
.get(&depth_stencil_attachment_descriptor.attachment)
|
||||
{
|
||||
Some(ref resource) => wgpu_resources.textures.get(&resource).unwrap(),
|
||||
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) {
|
||||
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
||||
self.encoder = Some(
|
||||
@ -400,11 +345,11 @@ impl WgpuRenderer {
|
||||
|
||||
pub fn create_queued_textures(&mut self, resources: &mut Resources) {
|
||||
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(..) {
|
||||
let resource = self.create_texture(&texture_descriptor, None);
|
||||
self.wgpu_resources
|
||||
.render_resources
|
||||
.set_named_resource(&name, resource);
|
||||
render_resource_assignments.set(&name, resource);
|
||||
}
|
||||
}
|
||||
|
||||
@ -471,33 +416,31 @@ impl Renderer for WgpuRenderer {
|
||||
let shader_storage = resources.get::<AssetStorage<Shader>>().unwrap();
|
||||
let render_graph = resources.get::<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() {
|
||||
let pipeline_descriptor = pipeline_storage
|
||||
.get_mut(pipeline_descriptor_handle)
|
||||
.unwrap();
|
||||
// create pipelines
|
||||
if !self
|
||||
.render_pipelines
|
||||
.contains_key(pipeline_descriptor_handle)
|
||||
if let Some(compiled_pipelines_iter) =
|
||||
pipeline_compiler.iter_compiled_pipelines(*pipeline_descriptor_handle)
|
||||
{
|
||||
let vertex_shader = shader_storage
|
||||
.get(&pipeline_descriptor.shader_stages.vertex)
|
||||
.unwrap();
|
||||
let fragment_shader = pipeline_descriptor
|
||||
.shader_stages
|
||||
.fragment
|
||||
.as_ref()
|
||||
.map(|handle| &*shader_storage.get(&handle).unwrap());
|
||||
for compiled_pipeline_handle in compiled_pipelines_iter {
|
||||
// create pipelines
|
||||
// TODO: merge this into "setup draw targets" loop
|
||||
if !self.render_pipelines.contains_key(compiled_pipeline_handle) {
|
||||
let compiled_pipeline_descriptor =
|
||||
pipeline_storage.get_mut(compiled_pipeline_handle).unwrap();
|
||||
|
||||
let render_pipeline = WgpuRenderer::create_render_pipeline(
|
||||
&mut self.wgpu_resources,
|
||||
pipeline_descriptor,
|
||||
compiled_pipeline_descriptor,
|
||||
&shader_storage,
|
||||
&self.device.borrow(),
|
||||
&render_graph,
|
||||
vertex_shader,
|
||||
fragment_shader,
|
||||
);
|
||||
self.render_pipelines
|
||||
.insert(*pipeline_descriptor_handle, render_pipeline);
|
||||
.insert(*compiled_pipeline_handle, render_pipeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -505,13 +448,25 @@ impl Renderer for WgpuRenderer {
|
||||
for (pass_name, _pass_descriptor) in render_graph.pass_descriptors.iter() {
|
||||
if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) {
|
||||
for pass_pipeline in pass_pipelines.iter() {
|
||||
let pipeline_descriptor = pipeline_storage.get(pass_pipeline).unwrap();
|
||||
if let Some(compiled_pipelines_iter) =
|
||||
pipeline_compiler.iter_compiled_pipelines(*pass_pipeline)
|
||||
{
|
||||
for compiled_pipeline_handle in compiled_pipelines_iter {
|
||||
let pipeline_descriptor =
|
||||
pipeline_storage.get(compiled_pipeline_handle).unwrap();
|
||||
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, *pass_pipeline);
|
||||
draw_target.setup(
|
||||
world,
|
||||
resources,
|
||||
self,
|
||||
*compiled_pipeline_handle,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -522,13 +477,20 @@ impl Renderer for WgpuRenderer {
|
||||
let mut render_pass = Self::create_render_pass(
|
||||
&self.wgpu_resources,
|
||||
pass_descriptor,
|
||||
&global_render_resource_assignments,
|
||||
&mut encoder,
|
||||
&frame,
|
||||
);
|
||||
if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) {
|
||||
for pass_pipeline in pass_pipelines.iter() {
|
||||
let pipeline_descriptor = pipeline_storage.get(pass_pipeline).unwrap();
|
||||
let render_pipeline = self.render_pipelines.get(pass_pipeline).unwrap();
|
||||
if let Some(compiled_pipelines_iter) =
|
||||
pipeline_compiler.iter_compiled_pipelines(*pass_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 {
|
||||
@ -539,8 +501,16 @@ impl Renderer for WgpuRenderer {
|
||||
};
|
||||
|
||||
for draw_target_name in pipeline_descriptor.draw_targets.iter() {
|
||||
let draw_target = render_graph.draw_targets.get(draw_target_name).unwrap();
|
||||
draw_target.draw(world, resources, &mut wgpu_render_pass, *pass_pipeline);
|
||||
let draw_target =
|
||||
render_graph.draw_targets.get(draw_target_name).unwrap();
|
||||
draw_target.draw(
|
||||
world,
|
||||
resources,
|
||||
&mut wgpu_render_pass,
|
||||
*compiled_pipeline_handle,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
use super::WgpuRenderer;
|
||||
use crate::render::{
|
||||
use crate::{
|
||||
asset::{AssetStorage, Handle},
|
||||
prelude::Shader,
|
||||
render::{
|
||||
pipeline::{BindGroupDescriptor, BindGroupDescriptorId, BindType},
|
||||
render_resource::{
|
||||
BufferInfo, RenderResource, RenderResourceAssignments, RenderResourceSetId,
|
||||
@ -7,6 +10,7 @@ use crate::render::{
|
||||
},
|
||||
renderer::Renderer,
|
||||
texture::{SamplerDescriptor, TextureDescriptor},
|
||||
},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@ -15,29 +19,19 @@ pub struct WgpuBindGroupInfo {
|
||||
pub bind_groups: HashMap<RenderResourceSetId, wgpu::BindGroup>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct WgpuResources {
|
||||
pub render_resources: RenderResources,
|
||||
pub buffers: HashMap<RenderResource, wgpu::Buffer>,
|
||||
pub textures: HashMap<RenderResource, wgpu::TextureView>,
|
||||
pub samplers: HashMap<RenderResource, wgpu::Sampler>,
|
||||
pub resource_info: HashMap<RenderResource, ResourceInfo>,
|
||||
pub shader_modules: HashMap<Handle<Shader>, wgpu::ShaderModule>,
|
||||
pub bind_groups: HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>,
|
||||
pub bind_group_layouts: HashMap<BindGroupDescriptorId, wgpu::BindGroupLayout>,
|
||||
}
|
||||
|
||||
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) {
|
||||
self.resource_info.insert(resource, resource_info);
|
||||
}
|
||||
@ -67,7 +61,7 @@ impl WgpuResources {
|
||||
.bindings
|
||||
.iter()
|
||||
.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();
|
||||
wgpu::Binding {
|
||||
binding: binding.index,
|
||||
@ -121,9 +115,7 @@ impl WgpuResources {
|
||||
};
|
||||
|
||||
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 mut bind_group_info = self
|
||||
let bind_group_info = self
|
||||
.bind_groups
|
||||
.entry(bind_group_descriptor.id)
|
||||
.or_insert_with(|| WgpuBindGroupInfo::default());
|
||||
@ -212,6 +204,18 @@ impl WgpuResources {
|
||||
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(
|
||||
&mut self,
|
||||
device: &wgpu::Device,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::render::{
|
||||
pipeline::{
|
||||
BindGroupDescriptor, BindType, BindingDescriptor, InputStepMode, UniformProperty, UniformPropertyType,
|
||||
VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat,
|
||||
BindGroupDescriptor, BindType, BindingDescriptor, InputStepMode, UniformProperty,
|
||||
UniformPropertyType, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat,
|
||||
},
|
||||
texture::TextureViewDimension,
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user