refactor renderer to avoid resource access collisions. this fixes the legion errors in debug builds.

NOTE: these "random resource access" issues are a pretty compelling reason to remove Resources from the render api
This commit is contained in:
Carter Anderson 2020-04-05 13:22:27 -07:00
parent 6d53100ff3
commit 7bb889bada
14 changed files with 276 additions and 247 deletions

View file

@ -22,6 +22,7 @@ pub trait DrawTarget {
_resources: &Resources,
_renderer: &mut dyn Renderer,
_pipeline_handle: Handle<PipelineDescriptor>,
_pipeline_descriptor: &PipelineDescriptor,
) {
}
fn get_name(&self) -> String;

View file

@ -1,5 +1,5 @@
use crate::{
asset::{AssetStorage, Handle},
asset::Handle,
legion::prelude::*,
prelude::Renderable,
render::{
@ -68,17 +68,17 @@ impl DrawTarget for AssignedBatchesDrawTarget {
resources: &Resources,
renderer: &mut dyn Renderer,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &PipelineDescriptor,
) {
let mut asset_batches = resources.get_mut::<AssetBatchers>().unwrap();
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();
log::debug!(
"setting up batch bind groups for pipeline: {:?}",
pipeline_handle
"setting up batch bind groups for pipeline: {:?} {:?}",
pipeline_handle,
pipeline_descriptor.name,
);
log::trace!("setting up global bind groups");
renderer.setup_bind_groups(&mut global_render_resource_assignments, pipeline_descriptor);

View file

@ -1,5 +1,5 @@
use crate::{
asset::{AssetStorage, Handle},
asset::Handle,
legion::prelude::*,
render::{
draw_target::DrawTarget,
@ -83,6 +83,7 @@ impl DrawTarget for AssignedMeshesDrawTarget {
resources: &Resources,
renderer: &mut dyn Renderer,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &PipelineDescriptor,
) {
let shader_pipeline_assignments = resources.get::<ShaderPipelineAssignments>().unwrap();
let entity_render_resource_assignments =
@ -90,14 +91,11 @@ impl DrawTarget for AssignedMeshesDrawTarget {
let assigned_render_resource_assignments = shader_pipeline_assignments
.assignments
.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?
let entity = entity_render_resource_assignments
.get(*assignment_id)
.unwrap();

View file

@ -1,5 +1,5 @@
use crate::{
asset::{Asset, AssetStorage, Handle},
asset::{Asset, Handle},
legion::prelude::*,
math,
prelude::MeshType,
@ -72,7 +72,8 @@ impl DrawTarget for UiDrawTarget {
_world: &mut World,
resources: &Resources,
renderer: &mut dyn Renderer,
pipeline_handle: Handle<PipelineDescriptor>,
_pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &PipelineDescriptor,
) {
// don't create meshes if they have already been created
if let Some(_) = self.mesh_vertex_buffer {
@ -100,8 +101,6 @@ impl DrawTarget for UiDrawTarget {
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 {

View file

@ -1,9 +1,8 @@
use super::{BindType, PipelineDescriptor, PipelineLayout, PipelineLayoutType};
use super::{BindType, PipelineDescriptor, PipelineLayout, PipelineLayoutType, VertexBufferDescriptors};
use crate::{
asset::{AssetStorage, Handle},
prelude::{Renderable, Resources, Shader, World},
render::{
render_graph::RenderGraph,
render_resource::{
BufferInfo, RenderResourceAssignments, RenderResourceAssignmentsId, ResourceInfo,
},
@ -32,7 +31,7 @@ impl PipelineCompiler {
fn reflect_layout(
shader_storage: &AssetStorage<Shader>,
render_graph: &RenderGraph,
vertex_buffer_descriptors: &VertexBufferDescriptors,
pipeline_descriptor: &mut PipelineDescriptor,
renderer: &dyn Renderer,
render_resource_assignments: &RenderResourceAssignments,
@ -52,7 +51,7 @@ impl PipelineCompiler {
}
let mut layout = PipelineLayout::from_shader_layouts(&mut layouts);
layout.sync_vertex_buffer_descriptors_with_render_graph(render_graph);
layout.sync_vertex_buffer_descriptors(vertex_buffer_descriptors);
// set binding uniforms to dynamic if render resource assignments use dynamic
// TODO: this breaks down if different assignments have different "dynamic" status or if the dynamic status changes.
@ -113,7 +112,7 @@ impl PipelineCompiler {
fn compile_pipeline(
&mut self,
render_graph: &RenderGraph,
vertex_buffer_descriptors: &VertexBufferDescriptors,
shader_storage: &mut AssetStorage<Shader>,
renderer: &dyn Renderer,
pipeline_descriptor: &PipelineDescriptor,
@ -140,7 +139,7 @@ impl PipelineCompiler {
Self::reflect_layout(
shader_storage,
render_graph,
vertex_buffer_descriptors,
&mut compiled_pipeline_descriptor,
renderer,
render_resource_assignments,
@ -151,7 +150,7 @@ impl PipelineCompiler {
fn update_shader_assignments(
&mut self,
render_graph: &RenderGraph,
vertex_buffer_descriptors: &VertexBufferDescriptors,
shader_pipeline_assignments: &mut ShaderPipelineAssignments,
renderer: &dyn Renderer,
pipeline_storage: &mut AssetStorage<PipelineDescriptor>,
@ -177,7 +176,7 @@ impl PipelineCompiler {
} else {
let pipeline_descriptor = pipeline_storage.get(pipeline_handle).unwrap();
let compiled_pipeline = self.compile_pipeline(
render_graph,
vertex_buffer_descriptors,
shader_storage,
renderer,
pipeline_descriptor,
@ -248,7 +247,7 @@ pub fn update_shader_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 vertex_buffer_descriptors = resources.get::<VertexBufferDescriptors>().unwrap();
let mut pipeline_descriptor_storage = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
@ -264,7 +263,7 @@ pub fn update_shader_assignments(
}
pipeline_compiler.update_shader_assignments(
&mut render_graph,
&vertex_buffer_descriptors,
&mut shader_pipeline_assignments,
renderer,
&mut pipeline_descriptor_storage,

View file

@ -1,5 +1,5 @@
use super::{BindGroupDescriptor, VertexBufferDescriptor};
use crate::render::{render_graph::RenderGraph, shader::ShaderLayout};
use super::{BindGroupDescriptor, VertexBufferDescriptor, VertexBufferDescriptors};
use crate::render::shader::ShaderLayout;
use std::{collections::HashMap, hash::Hash};
#[derive(Clone, Debug, Default)]
@ -56,10 +56,13 @@ impl PipelineLayout {
}
}
pub fn sync_vertex_buffer_descriptors_with_render_graph(&mut self, render_graph: &RenderGraph) {
pub fn sync_vertex_buffer_descriptors(
&mut self,
vertex_buffer_descriptors: &VertexBufferDescriptors,
) {
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_descriptors.get(&vertex_buffer_descriptor.name)
{
vertex_buffer_descriptor.sync_with_descriptor(graph_descriptor);
} else {

View file

@ -1,4 +1,5 @@
use super::VertexFormat;
use std::collections::HashMap;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct VertexBufferDescriptor {
@ -41,3 +42,21 @@ pub struct VertexAttributeDescriptor {
pub format: VertexFormat,
pub shader_location: u32,
}
#[derive(Default)]
pub struct VertexBufferDescriptors {
pub descriptors: HashMap<String, VertexBufferDescriptor>,
}
impl VertexBufferDescriptors {
pub fn set(&mut self, vertex_buffer_descriptor: VertexBufferDescriptor) {
self.descriptors.insert(
vertex_buffer_descriptor.name.to_string(),
vertex_buffer_descriptor,
);
}
pub fn get(&self, name: &str) -> Option<&VertexBufferDescriptor> {
self.descriptors.get(name)
}
}

View file

@ -1,12 +1,13 @@
use super::RenderGraphBuilder;
use crate::{
asset::{AssetStorage, Handle},
prelude::Shader,
prelude::{Resources, Shader, World},
render::{
draw_target::DrawTarget,
pass::PassDescriptor,
pipeline::{PipelineDescriptor, VertexBufferDescriptor},
pipeline::{PipelineCompiler, PipelineDescriptor},
render_resource::ResourceProvider,
renderer::Renderer,
texture::TextureDescriptor,
},
};
@ -21,7 +22,6 @@ pub struct RenderGraph {
pub resource_providers: Vec<Box<dyn ResourceProvider + Send + Sync>>,
pub queued_textures: Vec<(String, TextureDescriptor)>,
pub draw_targets: HashMap<String, Box<dyn DrawTarget + Send + Sync>>,
pub vertex_buffer_descriptors: HashMap<String, VertexBufferDescriptor>,
}
impl RenderGraph {
@ -49,17 +49,52 @@ impl RenderGraph {
pass_pipelines.push(pipeline);
}
pub fn set_vertex_buffer_descriptor(
pub fn setup_pipeline_draw_targets(
&mut self,
vertex_buffer_descriptor: VertexBufferDescriptor,
world: &mut World,
resources: &Resources,
renderer: &mut dyn Renderer,
) {
self.vertex_buffer_descriptors.insert(
vertex_buffer_descriptor.name.to_string(),
vertex_buffer_descriptor,
);
}
let shader_storage = resources.get::<AssetStorage<Shader>>().unwrap();
let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap();
pub fn get_vertex_buffer_descriptor(&self, name: &str) -> Option<&VertexBufferDescriptor> {
self.vertex_buffer_descriptors.get(name)
for (pass_name, _pass_descriptor) in self.pass_descriptors.iter() {
if let Some(pass_pipelines) = self.pass_pipelines.get(pass_name) {
for pass_pipeline in pass_pipelines.iter() {
if let Some(compiled_pipelines_iter) =
pipeline_compiler.iter_compiled_pipelines(*pass_pipeline)
{
for compiled_pipeline_handle in compiled_pipelines_iter {
let mut pipeline_storage = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let compiled_pipeline_descriptor =
pipeline_storage.get_mut(compiled_pipeline_handle).unwrap();
// create wgpu pipeline if it doesn't exist
renderer.setup_render_pipeline(
*compiled_pipeline_handle,
compiled_pipeline_descriptor,
&shader_storage,
);
// setup pipeline draw targets
for draw_target_name in compiled_pipeline_descriptor.draw_targets.iter()
{
let draw_target =
self.draw_targets.get_mut(draw_target_name).unwrap();
draw_target.setup(
world,
resources,
renderer,
*compiled_pipeline_handle,
compiled_pipeline_descriptor,
);
}
}
}
}
}
}
}
}

View file

@ -3,7 +3,7 @@ use super::{
AssignedBatchesDrawTarget, AssignedMeshesDrawTarget, MeshesDrawTarget, UiDrawTarget,
},
pass::passes::ForwardPassBuilder,
pipeline::{pipelines::ForwardPipelineBuilder, PipelineCompiler, ShaderPipelineAssignments},
pipeline::{pipelines::ForwardPipelineBuilder, PipelineCompiler, ShaderPipelineAssignments, VertexBufferDescriptors},
render_graph::RenderGraph,
render_resource::{
build_entity_render_resource_assignments_system,
@ -62,6 +62,7 @@ impl AppPlugin for RenderPlugin {
.add_resource(AssetStorage::<StandardMaterial>::new())
.add_resource(AssetStorage::<PipelineDescriptor>::new())
.add_resource(ShaderPipelineAssignments::new())
.add_resource(VertexBufferDescriptors::default())
.add_resource(PipelineCompiler::new())
.add_resource(RenderResourceAssignments::default())
.add_resource(EntityRenderResourceAssignments::default())

View file

@ -3,7 +3,7 @@ use crate::{
prelude::Renderable,
render::{
mesh::Mesh,
render_graph::RenderGraph,
pipeline::VertexBufferDescriptors,
render_resource::{
AssetBatchers, BufferInfo, BufferUsage, RenderResourceAssignments, ResourceProvider,
},
@ -92,9 +92,8 @@ impl ResourceProvider for MeshResourceProvider {
_world: &mut World,
resources: &Resources,
) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph
.set_vertex_buffer_descriptor(Vertex::get_vertex_buffer_descriptor().cloned().unwrap());
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
vertex_buffer_descriptors.set(Vertex::get_vertex_buffer_descriptor().cloned().unwrap());
}
fn update(&mut self, _renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {

View file

@ -2,7 +2,7 @@ use crate::{
ecs,
prelude::Node,
render::{
render_graph::RenderGraph,
pipeline::VertexBufferDescriptors,
render_resource::{
resource_name, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource,
RenderResourceAssignments, ResourceProvider,
@ -113,9 +113,8 @@ impl ResourceProvider for UiResourceProvider {
_world: &mut World,
resources: &Resources,
) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph
.set_vertex_buffer_descriptor(Rect::get_vertex_buffer_descriptor().cloned().unwrap());
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
vertex_buffer_descriptors.set(Rect::get_vertex_buffer_descriptor().cloned().unwrap());
}
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {

View file

@ -1,7 +1,7 @@
use crate::{
asset::{AssetStorage, Handle},
render::{
render_graph::RenderGraph,
pipeline::VertexBufferDescriptors,
render_resource::{
AssetBatchers, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource,
RenderResourceAssignments, ResourceInfo, ResourceProvider,
@ -543,12 +543,14 @@ where
}
}
fn initialize_vertex_buffer_descriptor(&self, render_graph: &mut RenderGraph) {
fn initialize_vertex_buffer_descriptor(
&self,
vertex_buffer_descriptors: &mut VertexBufferDescriptors,
) {
let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor();
if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor {
if let None = render_graph.get_vertex_buffer_descriptor(&vertex_buffer_descriptor.name)
{
render_graph.set_vertex_buffer_descriptor(vertex_buffer_descriptor.clone());
if let None = vertex_buffer_descriptors.get(&vertex_buffer_descriptor.name) {
vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone());
}
}
}
@ -601,8 +603,8 @@ where
world: &mut World,
resources: &Resources,
) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
self.initialize_vertex_buffer_descriptor(&mut render_graph);
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
self.initialize_vertex_buffer_descriptor(&mut vertex_buffer_descriptors);
self.update(renderer, world, resources);
}

View file

@ -1,10 +1,12 @@
use crate::{
asset::{AssetStorage, Handle},
legion::prelude::*,
render::{
pipeline::PipelineDescriptor,
render_resource::{
BufferInfo, RenderResource, RenderResourceAssignments, RenderResources, ResourceInfo,
},
shader::Shader,
texture::{SamplerDescriptor, TextureDescriptor},
},
};
@ -40,6 +42,12 @@ pub trait Renderer {
);
fn get_render_resources(&self) -> &RenderResources;
fn get_render_resources_mut(&mut self) -> &mut RenderResources;
fn setup_render_pipeline(
&mut self,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &mut PipelineDescriptor,
shader_storage: &AssetStorage<Shader>,
);
fn setup_bind_groups(
&mut self,
render_resource_assignments: &mut RenderResourceAssignments,

View file

@ -82,143 +82,10 @@ impl WgpuRenderer {
self.intialized = true;
}
pub fn create_render_pipeline(
&mut self,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &mut PipelineDescriptor,
shader_storage: &AssetStorage<Shader>,
) {
let device = self.device.borrow();
let layout = pipeline_descriptor.get_layout().unwrap();
for bind_group in layout.bind_groups.iter() {
if let None = self.wgpu_resources.bind_group_layouts.get(&bind_group.id) {
let bind_group_layout_binding = bind_group
.bindings
.iter()
.map(|binding| wgpu::BindGroupLayoutEntry {
binding: binding.index,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: (&binding.bind_type).into(),
})
.collect::<Vec<wgpu::BindGroupLayoutEntry>>();
let wgpu_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: bind_group_layout_binding.as_slice(),
});
self.wgpu_resources
.bind_group_layouts
.insert(bind_group.id, wgpu_bind_group_layout);
}
}
// setup and collect bind group layouts
let bind_group_layouts = layout
.bind_groups
.iter()
.map(|bind_group| {
self.wgpu_resources
.bind_group_layouts
.get(&bind_group.id)
.unwrap()
})
.collect::<Vec<&wgpu::BindGroupLayout>>();
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: bind_group_layouts.as_slice(),
});
let owned_vertex_buffer_descriptors = layout
.vertex_buffer_descriptors
.iter()
.map(|v| v.into())
.collect::<Vec<OwnedWgpuVertexBufferDescriptor>>();
let color_states = pipeline_descriptor
.color_states
.iter()
.map(|c| c.into())
.collect::<Vec<wgpu::ColorStateDescriptor>>();
if let None = self
.wgpu_resources
.shader_modules
.get(&pipeline_descriptor.shader_stages.vertex)
{
self.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 = self.wgpu_resources.shader_modules.get(&fragment_handle) {
self.wgpu_resources
.create_shader_module(&device, fragment_handle, shader_storage);
}
};
let vertex_shader_module = self
.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(
self.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 pipeline_descriptor.shader_stages.fragment {
Some(_) => Some(wgpu::ProgrammableStageDescriptor {
entry_point: "main",
module: fragment_shader_module.as_ref().unwrap(),
}),
None => None,
},
rasterization_state: pipeline_descriptor
.rasterization_state
.as_ref()
.map(|r| r.into()),
primitive_topology: pipeline_descriptor.primitive_topology.into(),
color_states: &color_states,
depth_stencil_state: pipeline_descriptor
.depth_stencil_state
.as_ref()
.map(|d| d.into()),
vertex_state: wgpu::VertexStateDescriptor {
index_format: pipeline_descriptor.index_format.into(),
vertex_buffers: &owned_vertex_buffer_descriptors
.iter()
.map(|v| v.into())
.collect::<Vec<wgpu::VertexBufferDescriptor>>(),
},
sample_count: pipeline_descriptor.sample_count,
sample_mask: pipeline_descriptor.sample_mask,
alpha_to_coverage_enabled: pipeline_descriptor.alpha_to_coverage_enabled,
};
let render_pipeline = device.create_render_pipeline(&mut render_pipeline_descriptor);
self.render_pipelines
.insert(pipeline_handle, render_pipeline);
}
pub fn create_render_pass<'a>(
pub fn create_render_pass<'a, 'b>(
wgpu_resources: &'a WgpuResources,
pass_descriptor: &PassDescriptor,
global_render_resource_assignments: &RenderResourceAssignments,
global_render_resource_assignments: &'b RenderResourceAssignments,
encoder: &'a mut wgpu::CommandEncoder,
primary_swap_chain: &Option<String>,
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
@ -344,12 +211,13 @@ impl WgpuRenderer {
}
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(
self.device
.borrow()
.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }),
);
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
for resource_provider in render_graph.resource_providers.iter_mut() {
resource_provider.initialize(self, world, resources);
}
@ -491,68 +359,29 @@ impl Renderer for WgpuRenderer {
let mut encoder = self.encoder.take().unwrap();
let mut pipeline_storage = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
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();
// setup draw targets
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() {
if let Some(compiled_pipelines_iter) =
pipeline_compiler.iter_compiled_pipelines(*pass_pipeline)
{
for compiled_pipeline_handle in compiled_pipelines_iter {
let compiled_pipeline_descriptor =
pipeline_storage.get_mut(compiled_pipeline_handle).unwrap();
// create wgpu pipeline if it doesn't exist
if !self.render_pipelines.contains_key(compiled_pipeline_handle) {
self.create_render_pipeline(
*compiled_pipeline_handle,
compiled_pipeline_descriptor,
&shader_storage,
);
}
// setup pipeline draw targets
for draw_target_name in compiled_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,
);
}
}
}
}
}
}
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.setup_pipeline_draw_targets(world, resources, self);
let (primary_swap_chain, swap_chain_outputs) = self.get_swap_chain_outputs(resources);
// begin render passes
let pipeline_storage = resources.get::<AssetStorage<PipelineDescriptor>>().unwrap();
let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap();
for (pass_name, pass_descriptor) in render_graph.pass_descriptors.iter() {
let mut render_pass = Self::create_render_pass(
&self.wgpu_resources,
pass_descriptor,
&global_render_resource_assignments,
&mut encoder,
&primary_swap_chain,
&swap_chain_outputs,
);
let mut render_pass = {
let global_render_resource_assignments =
resources.get::<RenderResourceAssignments>().unwrap();
Self::create_render_pass(
&self.wgpu_resources,
pass_descriptor,
&global_render_resource_assignments,
&mut encoder,
&primary_swap_chain,
&swap_chain_outputs,
)
};
if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) {
for pass_pipeline in pass_pipelines.iter() {
if let Some(compiled_pipelines_iter) =
@ -705,4 +534,141 @@ impl Renderer for WgpuRenderer {
}
}
}
fn setup_render_pipeline(
&mut self,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline_descriptor: &mut PipelineDescriptor,
shader_storage: &AssetStorage<Shader>,
) {
if self.render_pipelines.contains_key(&pipeline_handle) {
return;
}
let device = self.device.borrow();
let layout = pipeline_descriptor.get_layout().unwrap();
for bind_group in layout.bind_groups.iter() {
if let None = self.wgpu_resources.bind_group_layouts.get(&bind_group.id) {
let bind_group_layout_binding = bind_group
.bindings
.iter()
.map(|binding| wgpu::BindGroupLayoutEntry {
binding: binding.index,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: (&binding.bind_type).into(),
})
.collect::<Vec<wgpu::BindGroupLayoutEntry>>();
let wgpu_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: bind_group_layout_binding.as_slice(),
});
self.wgpu_resources
.bind_group_layouts
.insert(bind_group.id, wgpu_bind_group_layout);
}
}
// setup and collect bind group layouts
let bind_group_layouts = layout
.bind_groups
.iter()
.map(|bind_group| {
self.wgpu_resources
.bind_group_layouts
.get(&bind_group.id)
.unwrap()
})
.collect::<Vec<&wgpu::BindGroupLayout>>();
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: bind_group_layouts.as_slice(),
});
let owned_vertex_buffer_descriptors = layout
.vertex_buffer_descriptors
.iter()
.map(|v| v.into())
.collect::<Vec<OwnedWgpuVertexBufferDescriptor>>();
let color_states = pipeline_descriptor
.color_states
.iter()
.map(|c| c.into())
.collect::<Vec<wgpu::ColorStateDescriptor>>();
if let None = self
.wgpu_resources
.shader_modules
.get(&pipeline_descriptor.shader_stages.vertex)
{
self.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 = self.wgpu_resources.shader_modules.get(&fragment_handle) {
self.wgpu_resources
.create_shader_module(&device, fragment_handle, shader_storage);
}
};
let vertex_shader_module = self
.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(
self.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 pipeline_descriptor.shader_stages.fragment {
Some(_) => Some(wgpu::ProgrammableStageDescriptor {
entry_point: "main",
module: fragment_shader_module.as_ref().unwrap(),
}),
None => None,
},
rasterization_state: pipeline_descriptor
.rasterization_state
.as_ref()
.map(|r| r.into()),
primitive_topology: pipeline_descriptor.primitive_topology.into(),
color_states: &color_states,
depth_stencil_state: pipeline_descriptor
.depth_stencil_state
.as_ref()
.map(|d| d.into()),
vertex_state: wgpu::VertexStateDescriptor {
index_format: pipeline_descriptor.index_format.into(),
vertex_buffers: &owned_vertex_buffer_descriptors
.iter()
.map(|v| v.into())
.collect::<Vec<wgpu::VertexBufferDescriptor>>(),
},
sample_count: pipeline_descriptor.sample_count,
sample_mask: pipeline_descriptor.sample_mask,
alpha_to_coverage_enabled: pipeline_descriptor.alpha_to_coverage_enabled,
};
let render_pipeline = device.create_render_pipeline(&mut render_pipeline_descriptor);
self.render_pipelines
.insert(pipeline_handle, render_pipeline);
}
}