bevy/bevy_wgpu/src/wgpu_renderer.rs

751 lines
29 KiB
Rust
Raw Normal View History

2020-04-06 23:15:59 +00:00
use super::{
wgpu_type_converter::{OwnedWgpuVertexBufferDescriptor, WgpuInto},
WgpuRenderPass, WgpuResources,
};
use crate::renderer_2::WgpuRenderContext;
2020-04-06 03:19:02 +00:00
use bevy_app::{EventReader, Events};
use bevy_asset::{AssetStorage, Handle};
use bevy_render::{
pass::{
PassDescriptor, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor,
},
2020-04-06 03:19:02 +00:00
pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor},
render_graph::RenderGraph,
render_resource::{
2020-04-10 20:10:46 +00:00
resource_name, BufferInfo, RenderResource, RenderResourceAssignments, RenderResources,
ResourceInfo,
2020-04-06 03:19:02 +00:00
},
renderer::Renderer,
shader::Shader,
texture::{SamplerDescriptor, TextureDescriptor},
2020-01-20 08:57:54 +00:00
};
use bevy_window::{WindowCreated, WindowResized, Windows};
2020-04-06 03:19:02 +00:00
use legion::prelude::*;
use std::{
collections::{HashMap, HashSet},
ops::Deref,
2020-04-09 19:35:15 +00:00
sync::Arc,
};
2020-03-03 01:53:39 +00:00
pub struct WgpuRenderer {
2020-04-09 19:35:15 +00:00
pub device: Arc<wgpu::Device>,
2020-03-03 01:53:39 +00:00
pub queue: wgpu::Queue,
pub encoder: Option<wgpu::CommandEncoder>,
pub render_pipelines: HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
2020-03-03 01:53:39 +00:00
pub wgpu_resources: WgpuResources,
pub window_resized_event_reader: EventReader<WindowResized>,
pub window_created_event_reader: EventReader<WindowCreated>,
pub intialized: bool,
2020-03-03 01:53:39 +00:00
}
2020-01-20 08:57:54 +00:00
impl WgpuRenderer {
pub async fn new(
window_resized_event_reader: EventReader<WindowResized>,
window_created_event_reader: EventReader<WindowCreated>,
) -> Self {
2020-01-20 08:57:54 +00:00
let adapter = wgpu::Adapter::request(
&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::Default,
2020-04-08 02:36:57 +00:00
compatible_surface: None,
2020-01-20 08:57:54 +00:00
},
wgpu::BackendBit::PRIMARY,
)
2020-03-30 07:56:15 +00:00
.await
2020-01-20 08:57:54 +00:00
.unwrap();
let (device, queue) = adapter
.request_device(&wgpu::DeviceDescriptor {
extensions: wgpu::Extensions {
anisotropic_filtering: false,
},
limits: wgpu::Limits::default(),
})
.await;
2020-01-20 08:57:54 +00:00
WgpuRenderer {
2020-04-09 19:35:15 +00:00
device: Arc::new(device),
2020-01-20 08:57:54 +00:00
queue,
2020-02-04 08:06:17 +00:00
encoder: None,
window_resized_event_reader,
window_created_event_reader,
intialized: false,
wgpu_resources: WgpuResources::default(),
render_pipelines: HashMap::new(),
2020-01-20 08:57:54 +00:00
}
}
pub fn create_render_pass<'a, 'b>(
wgpu_resources: &'a WgpuResources,
2020-01-20 08:57:54 +00:00
pass_descriptor: &PassDescriptor,
global_render_resource_assignments: &'b RenderResourceAssignments,
2020-01-20 08:57:54 +00:00
encoder: &'a mut wgpu::CommandEncoder,
primary_swap_chain: &Option<String>,
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
2020-01-20 08:57:54 +00:00
) -> wgpu::RenderPass<'a> {
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &pass_descriptor
.color_attachments
.iter()
.map(|c| {
Self::create_wgpu_color_attachment_descriptor(
wgpu_resources,
global_render_resource_assignments,
c,
primary_swap_chain,
swap_chain_outputs,
)
})
2020-01-20 08:57:54 +00:00
.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,
global_render_resource_assignments,
d,
primary_swap_chain,
swap_chain_outputs,
)
}),
2020-01-20 08:57:54 +00:00
})
}
fn get_texture_view<'a>(
wgpu_resources: &'a WgpuResources,
global_render_resource_assignments: &RenderResourceAssignments,
primary_swap_chain: &Option<String>,
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
name: &str,
) -> &'a wgpu::TextureView {
match name {
resource_name::texture::SWAP_CHAIN => {
if let Some(primary_swap_chain) = primary_swap_chain {
swap_chain_outputs
.get(primary_swap_chain)
.map(|output| &output.view)
.unwrap()
} else {
panic!("No primary swap chain found for color attachment");
}
}
_ => match global_render_resource_assignments.get(name) {
Some(resource) => wgpu_resources.textures.get(&resource).unwrap(),
None => {
if let Some(swap_chain_output) = swap_chain_outputs.get(name) {
&swap_chain_output.view
} else {
panic!("Color attachment {} does not exist", name);
}
}
},
}
}
2020-01-20 08:57:54 +00:00
fn create_wgpu_color_attachment_descriptor<'a>(
2020-03-03 06:36:11 +00:00
wgpu_resources: &'a WgpuResources,
global_render_resource_assignments: &RenderResourceAssignments,
2020-01-20 08:57:54 +00:00
color_attachment_descriptor: &RenderPassColorAttachmentDescriptor,
primary_swap_chain: &Option<String>,
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
2020-01-20 08:57:54 +00:00
) -> wgpu::RenderPassColorAttachmentDescriptor<'a> {
let attachment = Self::get_texture_view(
wgpu_resources,
global_render_resource_assignments,
primary_swap_chain,
swap_chain_outputs,
color_attachment_descriptor.attachment.as_str(),
);
2020-01-20 08:57:54 +00:00
let resolve_target = color_attachment_descriptor
.resolve_target
.as_ref()
.map(|target| {
Self::get_texture_view(
wgpu_resources,
global_render_resource_assignments,
primary_swap_chain,
swap_chain_outputs,
target.as_str(),
)
});
2020-01-20 08:57:54 +00:00
wgpu::RenderPassColorAttachmentDescriptor {
2020-04-06 03:19:02 +00:00
store_op: color_attachment_descriptor.store_op.wgpu_into(),
load_op: color_attachment_descriptor.load_op.wgpu_into(),
clear_color: color_attachment_descriptor.clear_color.wgpu_into(),
2020-01-20 08:57:54 +00:00
attachment,
resolve_target,
}
}
fn create_wgpu_depth_stencil_attachment_descriptor<'a>(
2020-03-03 01:53:39 +00:00
wgpu_resources: &'a WgpuResources,
global_render_resource_assignments: &RenderResourceAssignments,
2020-01-20 08:57:54 +00:00
depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor,
primary_swap_chain: &Option<String>,
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> {
let attachment = Self::get_texture_view(
wgpu_resources,
global_render_resource_assignments,
primary_swap_chain,
swap_chain_outputs,
depth_stencil_attachment_descriptor.attachment.as_str(),
);
2020-01-20 08:57:54 +00:00
wgpu::RenderPassDepthStencilAttachmentDescriptor {
attachment,
clear_depth: depth_stencil_attachment_descriptor.clear_depth,
clear_stencil: depth_stencil_attachment_descriptor.clear_stencil,
2020-04-06 23:15:59 +00:00
depth_load_op: depth_stencil_attachment_descriptor
.depth_load_op
.wgpu_into(),
depth_store_op: depth_stencil_attachment_descriptor
.depth_store_op
.wgpu_into(),
stencil_load_op: depth_stencil_attachment_descriptor
.stencil_load_op
.wgpu_into(),
stencil_store_op: depth_stencil_attachment_descriptor
.stencil_store_op
.wgpu_into(),
2020-01-20 08:57:54 +00:00
}
}
2020-01-26 00:33:26 +00:00
pub fn initialize_resource_providers(
world: &mut World,
resources: &mut Resources,
render_context: &mut WgpuRenderContext,
) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
2020-02-18 00:33:46 +00:00
for resource_provider in render_graph.resource_providers.iter_mut() {
resource_provider.initialize(render_context, world, resources);
2020-02-18 00:33:46 +00:00
}
}
pub fn update_resource_providers(
world: &mut World,
resources: &mut Resources,
2020-04-10 20:10:46 +00:00
queue: &mut wgpu::Queue,
device: Arc<wgpu::Device>,
global_wgpu_resources: &mut WgpuResources,
) {
2020-04-10 20:10:46 +00:00
let thread_count = 5;
// let (sender, receiver) = crossbeam_channel::bounded(thread_count);
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
2020-04-10 20:10:46 +00:00
let chunk_size = (render_graph.resource_providers.len() + thread_count - 1) / thread_count; // divide ints rounding remainder up
let mut results = Vec::new();
// crossbeam_utils::thread::scope(|s| {
for resource_provider_chunk in render_graph.resource_providers.chunks_mut(chunk_size) {
let device = device.clone();
// let sender = sender.clone();
// s.spawn(|_| {
let mut render_context = WgpuRenderContext::new(device, global_wgpu_resources);
for resource_provider in resource_provider_chunk.iter_mut() {
resource_provider.update(&mut render_context, world, resources);
}
results.push(render_context.finish());
// sender.send(render_context.finish()).unwrap();
// });
}
// });
let mut command_buffers = Vec::new();
for (command_buffer, wgpu_resources) in results {
// for i in 0..thread_count {
// let (command_buffer, wgpu_resources) = receiver.recv().unwrap();
if let Some(command_buffer) = command_buffer {
command_buffers.push(command_buffer);
}
global_wgpu_resources.consume(wgpu_resources);
// println!("got {}", i);
}
2020-01-20 08:57:54 +00:00
2020-04-10 20:10:46 +00:00
let mut results = Vec::new();
// crossbeam_utils::thread::scope(|s| {
for resource_provider_chunk in render_graph.resource_providers.chunks_mut(chunk_size) {
let device = device.clone();
// let sender = sender.clone();
// s.spawn(|_| {
let mut render_context = WgpuRenderContext::new(device, global_wgpu_resources);
for resource_provider in resource_provider_chunk.iter_mut() {
resource_provider.finish_update(&mut render_context, world, resources);
}
results.push(render_context.finish());
// sender.send(render_context.finish()).unwrap();
// });
}
// });
for (command_buffer, wgpu_resources) in results {
// for i in 0..thread_count {
// let (command_buffer, wgpu_resources) = receiver.recv().unwrap();
if let Some(command_buffer) = command_buffer {
command_buffers.push(command_buffer);
}
global_wgpu_resources.consume(wgpu_resources);
// println!("got {}", i);
}
2020-04-10 20:10:46 +00:00
queue.submit(&command_buffers);
}
2020-02-18 00:33:46 +00:00
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);
render_resource_assignments.set(&name, resource);
}
}
pub fn handle_window_resized_events(
resources: &mut Resources,
device: &wgpu::Device,
wgpu_resources: &mut WgpuResources,
window_resized_event_reader: &mut EventReader<WindowResized>,
) {
let windows = resources.get::<Windows>().unwrap();
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
let mut handled_windows = HashSet::new();
// iterate in reverse order so we can handle the latest window resize event first for each window.
// we skip earlier events for the same window because it results in redundant work
for window_resized_event in window_resized_events
.iter(window_resized_event_reader)
.rev()
2020-03-30 18:52:33 +00:00
{
if handled_windows.contains(&window_resized_event.id) {
continue;
}
let window = windows
.get(window_resized_event.id)
.expect("Received window resized event for non-existent window");
// TODO: consider making this a WgpuRenderContext method
2020-04-10 20:10:46 +00:00
wgpu_resources.create_window_swap_chain(device, window);
handled_windows.insert(window_resized_event.id);
2020-03-30 18:52:33 +00:00
}
2020-01-20 08:57:54 +00:00
}
pub fn handle_window_created_events(
resources: &mut Resources,
device: &wgpu::Device,
wgpu_resources: &mut WgpuResources,
window_created_event_reader: &mut EventReader<WindowCreated>,
) {
let windows = resources.get::<Windows>().unwrap();
let window_created_events = resources.get::<Events<WindowCreated>>().unwrap();
for window_created_event in window_created_events.iter(window_created_event_reader) {
let window = windows
.get(window_created_event.id)
.expect("Received window created event for non-existent window");
2020-04-06 03:19:02 +00:00
#[cfg(feature = "bevy_winit")]
{
2020-04-06 03:19:02 +00:00
let winit_windows = resources.get::<bevy_winit::WinitWindows>().unwrap();
let primary_winit_window = winit_windows.get_window(window.id).unwrap();
let surface = wgpu::Surface::create(primary_winit_window.deref());
wgpu_resources.set_window_surface(window.id, surface);
wgpu_resources.create_window_swap_chain(device, window);
}
}
2020-01-20 08:57:54 +00:00
}
fn get_swap_chain_outputs(
&mut self,
resources: &Resources,
) -> (Option<String>, HashMap<String, wgpu::SwapChainOutput>) {
let primary_window_id = resources
.get::<Windows>()
.unwrap()
.get_primary()
.map(|window| window.id);
let primary_swap_chain =
primary_window_id.map(|primary_window_id| primary_window_id.to_string());
let swap_chain_outputs = self
.wgpu_resources
.window_swap_chains
.iter_mut()
// TODO: include non-primary swap chains
.filter(|(window_id, _swap_chain)| **window_id == primary_window_id.unwrap())
.map(|(window_id, swap_chain)| {
let swap_chain_texture = swap_chain
.get_next_texture()
.expect("Timeout when acquiring next swap chain texture");
(window_id.to_string(), swap_chain_texture)
})
.collect::<HashMap<String, wgpu::SwapChainOutput>>();
(primary_swap_chain, swap_chain_outputs)
}
}
impl Renderer for WgpuRenderer {
fn update(&mut self, world: &mut World, resources: &mut Resources) {
Self::handle_window_created_events(
resources,
&self.device,
&mut self.wgpu_resources,
&mut self.window_created_event_reader,
);
Self::handle_window_resized_events(
resources,
&self.device,
&mut self.wgpu_resources,
&mut self.window_resized_event_reader,
);
if !self.intialized {
2020-04-10 20:10:46 +00:00
let mut render_context = WgpuRenderContext::new(self.device.clone(), &self.wgpu_resources);
Self::initialize_resource_providers(world, resources, &mut render_context);
2020-04-10 20:10:46 +00:00
let (buffer, wgpu_resources) = render_context.finish();
self.wgpu_resources.consume(wgpu_resources);
if let Some(buffer) = buffer {
self.queue.submit(&[buffer]);
}
self.intialized = true;
}
2020-04-10 20:10:46 +00:00
Self::update_resource_providers(
world,
resources,
&mut self.queue,
self.device.clone(),
&mut self.wgpu_resources,
);
self.encoder = Some(
self.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }),
);
2020-03-28 05:41:45 +00:00
update_shader_assignments(world, resources, self);
self.create_queued_textures(resources);
2020-02-04 08:06:17 +00:00
let mut encoder = self.encoder.take().unwrap();
// setup draw targets
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();
2020-01-20 08:57:54 +00:00
for (pass_name, pass_descriptor) in render_graph.pass_descriptors.iter() {
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,
)
};
2020-01-20 08:57:54 +00:00
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 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 {
render_pass: &mut render_pass,
pipeline_descriptor,
wgpu_resources: &self.wgpu_resources,
renderer: &self,
bound_bind_groups: HashMap::default(),
};
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,
*compiled_pipeline_handle,
);
}
}
2020-01-20 08:57:54 +00:00
}
}
}
}
let command_buffer = encoder.finish();
self.queue.submit(&[command_buffer]);
}
2020-01-24 07:39:56 +00:00
fn create_buffer_with_data(&mut self, buffer_info: BufferInfo, data: &[u8]) -> RenderResource {
self.wgpu_resources
2020-04-09 19:35:15 +00:00
.create_buffer_with_data(&self.device, buffer_info, data)
2020-02-08 06:42:30 +00:00
}
fn create_buffer(&mut self, buffer_info: BufferInfo) -> RenderResource {
self.wgpu_resources.create_buffer(&self.device, buffer_info)
2020-02-08 06:42:30 +00:00
}
2020-02-24 05:13:03 +00:00
fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> {
2020-03-03 06:36:11 +00:00
self.wgpu_resources.resource_info.get(&resource)
2020-01-23 08:31:56 +00:00
}
fn get_resource_info_mut(&mut self, resource: RenderResource) -> Option<&mut ResourceInfo> {
self.wgpu_resources.resource_info.get_mut(&resource)
}
2020-02-24 05:13:03 +00:00
fn remove_buffer(&mut self, resource: RenderResource) {
2020-03-03 06:36:11 +00:00
self.wgpu_resources.remove_buffer(resource);
2020-01-24 07:39:56 +00:00
}
fn create_buffer_mapped(
&mut self,
buffer_info: BufferInfo,
setup_data: &mut dyn FnMut(&mut [u8], &mut dyn Renderer),
2020-02-24 05:13:03 +00:00
) -> RenderResource {
let buffer = WgpuResources::begin_create_buffer_mapped(&buffer_info, self, setup_data);
self.wgpu_resources.assign_buffer(buffer, buffer_info)
}
fn copy_buffer_to_buffer(
&mut self,
2020-02-24 05:13:03 +00:00
source_buffer: RenderResource,
source_offset: u64,
2020-02-24 05:13:03 +00:00
destination_buffer: RenderResource,
destination_offset: u64,
size: u64,
) {
self.wgpu_resources.copy_buffer_to_buffer(
self.encoder.as_mut().unwrap(),
source_buffer,
source_offset,
destination_buffer,
destination_offset,
size,
);
}
2020-03-03 06:36:11 +00:00
2020-02-24 07:41:48 +00:00
fn create_sampler(&mut self, sampler_descriptor: &SamplerDescriptor) -> RenderResource {
self.wgpu_resources
2020-04-09 19:35:15 +00:00
.create_sampler(&self.device, sampler_descriptor)
2020-02-24 05:13:03 +00:00
}
2020-02-24 07:41:48 +00:00
fn create_texture(
2020-02-24 05:13:03 +00:00
&mut self,
texture_descriptor: &TextureDescriptor,
bytes: Option<&[u8]>,
) -> RenderResource {
if let Some(bytes) = bytes {
self.wgpu_resources.create_texture_with_data(
&self.device,
self.encoder.as_mut().unwrap(),
texture_descriptor,
bytes,
)
} else {
self.wgpu_resources
.create_texture(&self.device, texture_descriptor)
}
2020-02-24 05:13:03 +00:00
}
fn remove_texture(&mut self, resource: RenderResource) {
2020-03-03 06:36:11 +00:00
self.wgpu_resources.remove_texture(resource);
2020-02-06 01:50:56 +00:00
}
2020-02-24 07:41:48 +00:00
fn remove_sampler(&mut self, resource: RenderResource) {
2020-03-03 06:36:11 +00:00
self.wgpu_resources.remove_sampler(resource);
2020-02-24 07:41:48 +00:00
}
2020-03-01 18:22:58 +00:00
fn get_render_resources(&self) -> &RenderResources {
2020-03-03 06:36:11 +00:00
&self.wgpu_resources.render_resources
2020-02-24 07:41:48 +00:00
}
2020-03-01 18:22:58 +00:00
fn get_render_resources_mut(&mut self) -> &mut RenderResources {
2020-03-03 06:36:11 +00:00
&mut self.wgpu_resources.render_resources
2020-03-01 18:22:58 +00:00
}
fn setup_bind_groups(
&mut self,
render_resource_assignments: &mut RenderResourceAssignments,
pipeline_descriptor: &PipelineDescriptor,
) {
let pipeline_layout = pipeline_descriptor.get_layout().unwrap();
for bind_group in pipeline_layout.bind_groups.iter() {
if let Some(render_resource_set_id) =
render_resource_assignments.get_or_update_render_resource_set_id(bind_group)
{
if let None = self
.wgpu_resources
.get_bind_group(bind_group.id, render_resource_set_id)
{
self.wgpu_resources.create_bind_group(
2020-04-09 19:35:15 +00:00
&self.device,
bind_group,
render_resource_assignments,
);
} else {
log::trace!(
"reusing RenderResourceSet {:?} for bind group {}",
render_resource_set_id,
bind_group.index
);
}
}
}
2020-02-24 07:41:48 +00:00
}
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 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,
2020-04-06 03:19:02 +00:00
ty: (&binding.bind_type).wgpu_into(),
})
.collect::<Vec<wgpu::BindGroupLayoutEntry>>();
let wgpu_bind_group_layout =
self.device
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: bind_group_layout_binding.as_slice(),
label: None,
});
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 = self
.device
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: bind_group_layouts.as_slice(),
});
let owned_vertex_buffer_descriptors = layout
.vertex_buffer_descriptors
.iter()
2020-04-06 03:19:02 +00:00
.map(|v| v.wgpu_into())
.collect::<Vec<OwnedWgpuVertexBufferDescriptor>>();
let color_states = pipeline_descriptor
.color_states
.iter()
2020-04-06 03:19:02 +00:00
.map(|c| c.wgpu_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(
2020-04-09 19:35:15 +00:00
&self.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(
&self.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()
2020-04-06 03:19:02 +00:00
.map(|r| r.wgpu_into()),
primitive_topology: pipeline_descriptor.primitive_topology.wgpu_into(),
color_states: &color_states,
depth_stencil_state: pipeline_descriptor
.depth_stencil_state
.as_ref()
2020-04-06 03:19:02 +00:00
.map(|d| d.wgpu_into()),
vertex_state: wgpu::VertexStateDescriptor {
2020-04-06 03:19:02 +00:00
index_format: pipeline_descriptor.index_format.wgpu_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 = self
.device
.create_render_pipeline(&mut render_pipeline_descriptor);
self.render_pipelines
.insert(pipeline_handle, render_pipeline);
}
2020-03-11 04:57:57 +00:00
}