Refactor render passes
This commit is contained in:
parent
837e1dc139
commit
a99b5600bc
@ -10,6 +10,7 @@ pub trait DrawTarget {
|
||||
resources: &Resources,
|
||||
render_pass: &mut dyn RenderPass,
|
||||
pipeline_handle: Handle<PipelineDescriptor>,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
);
|
||||
fn setup(
|
||||
&mut self,
|
||||
|
@ -19,14 +19,15 @@ impl DrawTarget for AssignedBatchesDrawTarget {
|
||||
resources: &Resources,
|
||||
render_pass: &mut dyn RenderPass,
|
||||
pipeline_handle: Handle<PipelineDescriptor>,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
) {
|
||||
log::trace!("drawing batches for pipeline {:?}", pipeline_handle);
|
||||
let asset_batches = resources.get::<AssetBatchers>().unwrap();
|
||||
let global_render_resource_assignments =
|
||||
resources.get::<RenderResourceAssignments>().unwrap();
|
||||
render_pass.set_render_resources(&global_render_resource_assignments);
|
||||
render_pass.set_render_resources(pipeline_descriptor, &global_render_resource_assignments);
|
||||
for batch in asset_batches.get_batches() {
|
||||
let indices = render_pass.set_render_resources(&batch.render_resource_assignments);
|
||||
let indices = render_pass.set_render_resources(pipeline_descriptor, &batch.render_resource_assignments);
|
||||
log::trace!("drawing batch {:?}", batch.render_resource_assignments.id);
|
||||
log::trace!("{:#?}", batch);
|
||||
for batched_entity in batch.entities.iter() {
|
||||
@ -38,7 +39,7 @@ impl DrawTarget for AssignedBatchesDrawTarget {
|
||||
log::trace!("start drawing batched entity: {:?}", batched_entity);
|
||||
log::trace!("{:#?}", renderable.render_resource_assignments);
|
||||
let entity_indices =
|
||||
render_pass.set_render_resources(&renderable.render_resource_assignments);
|
||||
render_pass.set_render_resources(pipeline_descriptor, &renderable.render_resource_assignments);
|
||||
let mut draw_indices = &indices;
|
||||
if entity_indices.is_some() {
|
||||
if indices.is_some() {
|
||||
|
@ -23,6 +23,7 @@ impl DrawTarget for AssignedMeshesDrawTarget {
|
||||
resources: &Resources,
|
||||
render_pass: &mut dyn RenderPass,
|
||||
pipeline_handle: Handle<PipelineDescriptor>,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
) {
|
||||
let shader_pipeline_assignments = resources.get::<PipelineAssignments>().unwrap();
|
||||
let entity_render_resource_assignments =
|
||||
@ -31,7 +32,7 @@ impl DrawTarget for AssignedMeshesDrawTarget {
|
||||
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);
|
||||
render_pass.set_render_resources(pipeline_descriptor, &global_render_resource_assignments);
|
||||
|
||||
let assigned_render_resource_assignments = shader_pipeline_assignments
|
||||
.assignments
|
||||
@ -74,7 +75,7 @@ impl DrawTarget for AssignedMeshesDrawTarget {
|
||||
}
|
||||
|
||||
// TODO: validate bind group properties against shader uniform properties at least once
|
||||
render_pass.set_render_resources(&renderable.render_resource_assignments);
|
||||
render_pass.set_render_resources(pipeline_descriptor, &renderable.render_resource_assignments);
|
||||
render_pass.draw_indexed(0..current_mesh_index_len, 0, 0..1);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ impl DrawTarget for MeshesDrawTarget {
|
||||
_resources: &Resources,
|
||||
render_pass: &mut dyn RenderPass,
|
||||
_pipeline_handle: Handle<PipelineDescriptor>,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
) {
|
||||
let mut current_mesh_handle = None;
|
||||
let mut current_mesh_index_len = 0;
|
||||
@ -53,7 +54,7 @@ impl DrawTarget for MeshesDrawTarget {
|
||||
}
|
||||
|
||||
// TODO: validate bind group properties against shader uniform properties at least once
|
||||
render_pass.set_render_resources(&renderable.render_resource_assignments);
|
||||
render_pass.set_render_resources(pipeline_descriptor, &renderable.render_resource_assignments);
|
||||
render_pass.draw_indexed(0..current_mesh_index_len, 0, 0..1);
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ impl DrawTarget for UiDrawTarget {
|
||||
resources: &Resources,
|
||||
render_pass: &mut dyn RenderPass,
|
||||
_pipeline_handle: Handle<PipelineDescriptor>,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
) {
|
||||
let render_resource_assignments = resources.get::<RenderResourceAssignments>().unwrap();
|
||||
let ui_instances_buffer = {
|
||||
@ -55,7 +56,7 @@ impl DrawTarget for UiDrawTarget {
|
||||
|
||||
let global_render_resource_assignments =
|
||||
resources.get::<RenderResourceAssignments>().unwrap();
|
||||
render_pass.set_render_resources(&global_render_resource_assignments);
|
||||
render_pass.set_render_resources(pipeline_descriptor, &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);
|
||||
|
@ -4,15 +4,18 @@ use crate::{
|
||||
renderer_2::RenderContext,
|
||||
};
|
||||
use std::ops::Range;
|
||||
use bevy_asset::Handle;
|
||||
|
||||
pub trait RenderPass {
|
||||
fn get_render_context(&self) -> &dyn RenderContext;
|
||||
fn get_pipeline_descriptor(&self) -> &PipelineDescriptor;
|
||||
fn set_index_buffer(&mut self, resource: RenderResource, offset: u64);
|
||||
fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64);
|
||||
fn set_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>);
|
||||
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
||||
// TODO: try to somehow take into account the "set" pipeline instead of passing it in here
|
||||
fn set_render_resources(
|
||||
&mut self,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
) -> Option<Range<u32>>;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::RenderResourceContext;
|
||||
use crate::{
|
||||
pass::{PassDescriptor, RenderPass},
|
||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
||||
render_resource::{RenderResource, RenderResourceAssignments, RenderResourceSetId},
|
||||
shader::Shader,
|
||||
@ -8,18 +9,6 @@ use crate::{
|
||||
use bevy_asset::{AssetStorage, Handle};
|
||||
|
||||
pub trait RenderContext {
|
||||
// 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,
|
||||
// pipeline_descriptor: &PipelineDescriptor,
|
||||
// );
|
||||
|
||||
fn resources(&self) -> &dyn RenderResourceContext;
|
||||
fn resources_mut(&mut self) -> &mut dyn RenderResourceContext;
|
||||
|
||||
@ -36,14 +25,6 @@ pub trait RenderContext {
|
||||
destination_offset: u64,
|
||||
size: u64,
|
||||
);
|
||||
// fn copy_buffer_to_texture(
|
||||
// &mut self,
|
||||
// source_buffer: RenderResource,
|
||||
// source_offset: u64,
|
||||
// destination_buffer: RenderResource,
|
||||
// destination_offset: u64,
|
||||
// size: u64,
|
||||
// );
|
||||
fn create_bind_group(
|
||||
&mut self,
|
||||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
@ -65,4 +46,10 @@ pub trait RenderContext {
|
||||
self.create_bind_group(bind_group, render_resource_assignments);
|
||||
}
|
||||
}
|
||||
fn begin_pass(
|
||||
&mut self,
|
||||
pass_descriptor: &PassDescriptor,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
run_pass: &mut dyn Fn(&mut dyn RenderPass)
|
||||
);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ use crate::{
|
||||
texture::{SamplerDescriptor, Texture, TextureDescriptor},
|
||||
};
|
||||
use bevy_asset::{AssetStorage, Handle};
|
||||
use bevy_window::{Window, WindowId};
|
||||
|
||||
pub struct GlobalRenderResourceContext {
|
||||
pub context: Box<dyn RenderResourceContext + Send + Sync + 'static>,
|
||||
@ -12,6 +13,9 @@ pub struct GlobalRenderResourceContext {
|
||||
|
||||
// TODO: Rename to RenderResources after cleaning up AssetResources rename
|
||||
pub trait RenderResourceContext {
|
||||
fn create_swap_chain(&mut self, window: &Window);
|
||||
fn next_swap_chain_texture(&mut self, window_id: WindowId);
|
||||
fn drop_swap_chain_texture(&mut self, window_id: WindowId);
|
||||
fn create_sampler(&mut self, sampler_descriptor: &SamplerDescriptor) -> RenderResource;
|
||||
fn create_texture(&mut self, texture_descriptor: &TextureDescriptor) -> RenderResource;
|
||||
fn create_buffer(&mut self, buffer_info: BufferInfo) -> RenderResource;
|
||||
|
@ -1,16 +1,24 @@
|
||||
use super::WgpuRenderResourceContextTrait;
|
||||
use crate::wgpu_type_converter::{OwnedWgpuVertexBufferDescriptor, WgpuInto};
|
||||
use crate::{
|
||||
wgpu_type_converter::{OwnedWgpuVertexBufferDescriptor, WgpuInto},
|
||||
WgpuRenderPass,
|
||||
};
|
||||
use bevy_asset::{AssetStorage, Handle};
|
||||
use bevy_render::{
|
||||
pass::{
|
||||
PassDescriptor, RenderPass, RenderPassColorAttachmentDescriptor,
|
||||
RenderPassDepthStencilAttachmentDescriptor,
|
||||
},
|
||||
pipeline::{BindGroupDescriptor, BindType, PipelineDescriptor},
|
||||
render_resource::{
|
||||
RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
|
||||
resource_name, RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
|
||||
},
|
||||
renderer_2::{RenderContext, RenderResourceContext},
|
||||
shader::Shader,
|
||||
texture::TextureDescriptor,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use bevy_window::WindowId;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
#[derive(Default)]
|
||||
struct LazyCommandEncoder {
|
||||
@ -22,17 +30,29 @@ impl LazyCommandEncoder {
|
||||
match self.command_encoder {
|
||||
Some(ref mut command_encoder) => command_encoder,
|
||||
None => {
|
||||
let command_encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
self.command_encoder = Some(command_encoder);
|
||||
self.create(device);
|
||||
self.command_encoder.as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_some(&self) -> bool {
|
||||
self.command_encoder.is_some()
|
||||
}
|
||||
|
||||
pub fn create(&mut self, device: &wgpu::Device) {
|
||||
let command_encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
self.command_encoder = Some(command_encoder);
|
||||
}
|
||||
|
||||
pub fn take(&mut self) -> Option<wgpu::CommandEncoder> {
|
||||
self.command_encoder.take()
|
||||
}
|
||||
|
||||
pub fn set(&mut self, command_encoder: wgpu::CommandEncoder) {
|
||||
self.command_encoder = Some(command_encoder);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WgpuRenderContext<T>
|
||||
@ -40,6 +60,8 @@ where
|
||||
T: RenderResourceContext,
|
||||
{
|
||||
pub device: Arc<wgpu::Device>,
|
||||
// TODO: remove this
|
||||
pub primary_window: Option<WindowId>,
|
||||
command_encoder: LazyCommandEncoder,
|
||||
pub render_resources: T,
|
||||
}
|
||||
@ -51,6 +73,7 @@ where
|
||||
pub fn new(device: Arc<wgpu::Device>, resources: T) -> Self {
|
||||
WgpuRenderContext {
|
||||
device,
|
||||
primary_window: None,
|
||||
render_resources: resources,
|
||||
command_encoder: LazyCommandEncoder::default(),
|
||||
}
|
||||
@ -70,19 +93,6 @@ where
|
||||
pub fn finish_encoder(&mut self) -> Option<wgpu::CommandBuffer> {
|
||||
self.command_encoder.take().map(|encoder| encoder.finish())
|
||||
}
|
||||
|
||||
// fn get_buffer<'b>(
|
||||
// render_resource: RenderResource,
|
||||
// local_resources: &'b WgpuResources,
|
||||
// global_resources: &'b WgpuResources,
|
||||
// ) -> Option<&'b wgpu::Buffer> {
|
||||
// let buffer = local_resources.buffers.get(&render_resource);
|
||||
// if buffer.is_some() {
|
||||
// return buffer;
|
||||
// }
|
||||
|
||||
// global_resources.buffers.get(&render_resource)
|
||||
// }
|
||||
}
|
||||
|
||||
impl<T> RenderContext for WgpuRenderContext<T>
|
||||
@ -365,4 +375,167 @@ where
|
||||
self.render_resources
|
||||
.set_render_pipeline(pipeline_handle, wgpu_pipeline);
|
||||
}
|
||||
fn begin_pass(
|
||||
&mut self,
|
||||
pass_descriptor: &PassDescriptor,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
run_pass: &mut dyn Fn(&mut dyn RenderPass),
|
||||
) {
|
||||
if !self.command_encoder.is_some() {
|
||||
self.command_encoder.create(&self.device);
|
||||
}
|
||||
|
||||
let mut encoder = self.command_encoder.take().unwrap();
|
||||
{
|
||||
let render_pass = create_render_pass(
|
||||
self,
|
||||
pass_descriptor,
|
||||
render_resource_assignments,
|
||||
&mut encoder,
|
||||
);
|
||||
let mut wgpu_render_pass = WgpuRenderPass {
|
||||
render_context: self,
|
||||
render_pass,
|
||||
bound_bind_groups: HashMap::default(),
|
||||
};
|
||||
|
||||
run_pass(&mut wgpu_render_pass);
|
||||
}
|
||||
|
||||
self.command_encoder.set(encoder);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_render_pass<'a, 'b, T>(
|
||||
render_context: &'a WgpuRenderContext<T>,
|
||||
pass_descriptor: &PassDescriptor,
|
||||
global_render_resource_assignments: &'b RenderResourceAssignments,
|
||||
encoder: &'a mut wgpu::CommandEncoder,
|
||||
) -> wgpu::RenderPass<'a>
|
||||
where
|
||||
T: WgpuRenderResourceContextTrait + RenderResourceContext,
|
||||
{
|
||||
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &pass_descriptor
|
||||
.color_attachments
|
||||
.iter()
|
||||
.map(|c| {
|
||||
create_wgpu_color_attachment_descriptor(
|
||||
render_context,
|
||||
global_render_resource_assignments,
|
||||
c,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<wgpu::RenderPassColorAttachmentDescriptor>>(),
|
||||
depth_stencil_attachment: pass_descriptor.depth_stencil_attachment.as_ref().map(|d| {
|
||||
create_wgpu_depth_stencil_attachment_descriptor(
|
||||
render_context,
|
||||
global_render_resource_assignments,
|
||||
d,
|
||||
)
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_texture_view<'a, T>(
|
||||
render_context: &'a WgpuRenderContext<T>,
|
||||
global_render_resource_assignments: &RenderResourceAssignments,
|
||||
name: &str,
|
||||
) -> &'a wgpu::TextureView
|
||||
where
|
||||
T: WgpuRenderResourceContextTrait + RenderResourceContext,
|
||||
{
|
||||
match name {
|
||||
resource_name::texture::SWAP_CHAIN => {
|
||||
if let Some(primary_swap_chain) = render_context
|
||||
.render_resources
|
||||
.get_swap_chain_output(render_context.primary_window.as_ref().unwrap())
|
||||
.map(|output| &output.view)
|
||||
{
|
||||
primary_swap_chain
|
||||
} else {
|
||||
panic!("No primary swap chain found for color attachment");
|
||||
}
|
||||
}
|
||||
_ => match global_render_resource_assignments.get(name) {
|
||||
Some(resource) => render_context
|
||||
.render_resources
|
||||
.get_texture(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);
|
||||
// }
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn create_wgpu_color_attachment_descriptor<'a, T>(
|
||||
render_context: &'a WgpuRenderContext<T>,
|
||||
global_render_resource_assignments: &RenderResourceAssignments,
|
||||
color_attachment_descriptor: &RenderPassColorAttachmentDescriptor,
|
||||
) -> wgpu::RenderPassColorAttachmentDescriptor<'a>
|
||||
where
|
||||
T: WgpuRenderResourceContextTrait + RenderResourceContext,
|
||||
{
|
||||
let attachment = get_texture_view(
|
||||
render_context,
|
||||
global_render_resource_assignments,
|
||||
color_attachment_descriptor.attachment.as_str(),
|
||||
);
|
||||
|
||||
let resolve_target = color_attachment_descriptor
|
||||
.resolve_target
|
||||
.as_ref()
|
||||
.map(|target| {
|
||||
get_texture_view(
|
||||
render_context,
|
||||
global_render_resource_assignments,
|
||||
target.as_str(),
|
||||
)
|
||||
});
|
||||
|
||||
wgpu::RenderPassColorAttachmentDescriptor {
|
||||
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(),
|
||||
attachment,
|
||||
resolve_target,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_wgpu_depth_stencil_attachment_descriptor<'a, T>(
|
||||
render_context: &'a WgpuRenderContext<T>,
|
||||
global_render_resource_assignments: &RenderResourceAssignments,
|
||||
depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor,
|
||||
) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a>
|
||||
where
|
||||
T: WgpuRenderResourceContextTrait + RenderResourceContext,
|
||||
{
|
||||
let attachment = get_texture_view(
|
||||
render_context,
|
||||
global_render_resource_assignments,
|
||||
depth_stencil_attachment_descriptor.attachment.as_str(),
|
||||
);
|
||||
|
||||
wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment,
|
||||
clear_depth: depth_stencil_attachment_descriptor.clear_depth,
|
||||
clear_stencil: depth_stencil_attachment_descriptor.clear_stencil,
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ use bevy_render::{
|
||||
texture::{SamplerDescriptor, Texture, TextureDescriptor},
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use bevy_window::{WindowId, Window};
|
||||
|
||||
pub struct WgpuRenderResourceContext {
|
||||
pub device: Arc<wgpu::Device>,
|
||||
@ -62,6 +63,7 @@ pub trait WgpuRenderResourceContextTrait {
|
||||
bind_group_id: BindGroupDescriptorId,
|
||||
) -> Option<&wgpu::BindGroupLayout>;
|
||||
fn get_buffer(&self, render_resource: RenderResource) -> Option<&wgpu::Buffer>;
|
||||
fn get_swap_chain_output(&self, window_id: &WindowId) -> Option<&wgpu::SwapChainOutput>;
|
||||
fn get_texture(&self, render_resource: RenderResource) -> Option<&wgpu::TextureView>;
|
||||
fn get_sampler(&self, render_resource: RenderResource) -> Option<&wgpu::Sampler>;
|
||||
fn get_pipeline(&self, pipeline: Handle<PipelineDescriptor>) -> Option<&wgpu::RenderPipeline>;
|
||||
@ -154,6 +156,9 @@ impl WgpuRenderResourceContextTrait for WgpuRenderResourceContext {
|
||||
self.wgpu_resources
|
||||
.set_render_pipeline(pipeline_handle, pipeline);
|
||||
}
|
||||
fn get_swap_chain_output(&self, window_id: &WindowId) -> Option<&wgpu::SwapChainOutput> {
|
||||
self.wgpu_resources.swap_chain_outputs.get(window_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl WgpuRenderResourceContext {
|
||||
@ -254,4 +259,13 @@ impl RenderResourceContext for WgpuRenderResourceContext {
|
||||
self.wgpu_resources
|
||||
.create_shader_module(&self.device, shader_handle, shader);
|
||||
}
|
||||
fn create_swap_chain(&mut self, window: &Window) {
|
||||
self.wgpu_resources.create_window_swap_chain(&self.device, window)
|
||||
}
|
||||
fn next_swap_chain_texture(&mut self, window_id: bevy_window::WindowId) {
|
||||
self.wgpu_resources.next_swap_chain_texture(window_id);
|
||||
}
|
||||
fn drop_swap_chain_texture(&mut self, window_id: WindowId) {
|
||||
self.wgpu_resources.remove_swap_chain_texture(window_id);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ use bevy_render::{
|
||||
shader::Shader,
|
||||
texture::{SamplerDescriptor, Texture, TextureDescriptor},
|
||||
};
|
||||
use bevy_window::{WindowId, Window};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct WgpuTransactionalRenderResourceContext<'a> {
|
||||
@ -139,6 +140,16 @@ impl<'a> WgpuRenderResourceContextTrait for WgpuTransactionalRenderResourceConte
|
||||
self.local_resources
|
||||
.set_render_pipeline(pipeline_handle, pipeline);
|
||||
}
|
||||
fn get_swap_chain_output(
|
||||
&self,
|
||||
window_id: &bevy_window::WindowId,
|
||||
) -> Option<&wgpu::SwapChainOutput> {
|
||||
let local = self.local_resources.swap_chain_outputs.get(window_id);
|
||||
if local.is_some() {
|
||||
return local;
|
||||
}
|
||||
self.parent_resources.swap_chain_outputs.get(window_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> WgpuTransactionalRenderResourceContext<'a> {
|
||||
@ -283,4 +294,14 @@ impl<'a> RenderResourceContext for WgpuTransactionalRenderResourceContext<'a> {
|
||||
self.local_resources
|
||||
.create_shader_module(&self.device, shader_handle, shader);
|
||||
}
|
||||
fn create_swap_chain(&mut self, window: &Window) {
|
||||
self.local_resources
|
||||
.create_window_swap_chain(&self.device, window)
|
||||
}
|
||||
fn next_swap_chain_texture(&mut self, window_id: bevy_window::WindowId) {
|
||||
self.local_resources.next_swap_chain_texture(window_id);
|
||||
}
|
||||
fn drop_swap_chain_texture(&mut self, window_id: WindowId) {
|
||||
self.local_resources.remove_swap_chain_texture(window_id);
|
||||
}
|
||||
}
|
||||
|
@ -9,17 +9,16 @@ use bevy_render::{
|
||||
};
|
||||
use std::{collections::HashMap, ops::Range};
|
||||
|
||||
pub struct WgpuRenderPass<'a, 'b, 'c, T>
|
||||
pub struct WgpuRenderPass<'a, T>
|
||||
where
|
||||
T: RenderResourceContext + WgpuRenderResourceContextTrait,
|
||||
{
|
||||
pub render_pass: &'b mut wgpu::RenderPass<'a>,
|
||||
pub pipeline_descriptor: &'c PipelineDescriptor,
|
||||
pub render_pass: wgpu::RenderPass<'a>,
|
||||
pub render_context: &'a WgpuRenderContext<T>,
|
||||
pub bound_bind_groups: HashMap<u32, RenderResourceSetId>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c, T> RenderPass for WgpuRenderPass<'a, 'b, 'c, T>
|
||||
impl<'a, T> RenderPass for WgpuRenderPass<'a, T>
|
||||
where
|
||||
T: RenderResourceContext + WgpuRenderResourceContextTrait,
|
||||
{
|
||||
@ -27,10 +26,6 @@ where
|
||||
self.render_context
|
||||
}
|
||||
|
||||
fn get_pipeline_descriptor(&self) -> &PipelineDescriptor {
|
||||
self.pipeline_descriptor
|
||||
}
|
||||
|
||||
fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64) {
|
||||
let buffer = self
|
||||
.render_context
|
||||
@ -57,9 +52,11 @@ where
|
||||
|
||||
fn set_render_resources(
|
||||
&mut self,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
) -> Option<Range<u32>> {
|
||||
let pipeline_layout = self.pipeline_descriptor.get_layout().unwrap();
|
||||
let pipeline_layout = pipeline_descriptor.get_layout()
|
||||
.unwrap();
|
||||
// PERF: vertex buffer lookup comes at a cost when vertex buffers aren't in render_resource_assignments. iterating over render_resource_assignment vertex buffers
|
||||
// would likely be faster
|
||||
let mut indices = None;
|
||||
@ -151,4 +148,8 @@ where
|
||||
|
||||
indices
|
||||
}
|
||||
fn set_pipeline(&mut self, pipeline_handle: bevy_asset::Handle<PipelineDescriptor>) {
|
||||
let pipeline = self.render_context.render_resources.get_pipeline(pipeline_handle).expect("Attempted to use a pipeline that does not exist in this RenderPass's RenderContext");
|
||||
self.render_pass.set_pipeline(pipeline);
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,23 @@
|
||||
use super::{wgpu_type_converter::WgpuInto, WgpuRenderPass, WgpuResources};
|
||||
use super::WgpuResources;
|
||||
use crate::renderer_2::{
|
||||
render_resource_sets_system, WgpuRenderContext, WgpuRenderResourceContext,
|
||||
WgpuRenderResourceContextTrait, WgpuTransactionalRenderResourceContext,
|
||||
WgpuTransactionalRenderResourceContext,
|
||||
};
|
||||
use bevy_app::{EventReader, Events};
|
||||
use bevy_asset::AssetStorage;
|
||||
use bevy_render::{
|
||||
pass::{
|
||||
PassDescriptor, RenderPassColorAttachmentDescriptor,
|
||||
RenderPassDepthStencilAttachmentDescriptor,
|
||||
},
|
||||
pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor},
|
||||
render_graph::RenderGraph,
|
||||
render_resource::{resource_name, RenderResourceAssignments},
|
||||
renderer_2::RenderContext,
|
||||
render_resource::RenderResourceAssignments,
|
||||
renderer_2::{RenderContext, RenderResourceContext},
|
||||
};
|
||||
use bevy_window::{WindowCreated, WindowResized, Windows};
|
||||
use legion::prelude::*;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
ops::Deref,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{collections::HashSet, ops::Deref, sync::Arc};
|
||||
|
||||
pub struct WgpuRenderer {
|
||||
pub global_context: WgpuRenderContext<WgpuRenderResourceContext>,
|
||||
pub queue: wgpu::Queue,
|
||||
pub encoder: Option<wgpu::CommandEncoder>,
|
||||
pub window_resized_event_reader: EventReader<WindowResized>,
|
||||
pub window_created_event_reader: EventReader<WindowCreated>,
|
||||
pub intialized: bool,
|
||||
@ -62,149 +53,12 @@ impl WgpuRenderer {
|
||||
WgpuRenderResourceContext::new(device),
|
||||
),
|
||||
queue,
|
||||
encoder: None,
|
||||
window_resized_event_reader,
|
||||
window_created_event_reader,
|
||||
intialized: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_render_pass<'a, 'b>(
|
||||
wgpu_resources: &'a WgpuResources,
|
||||
pass_descriptor: &PassDescriptor,
|
||||
global_render_resource_assignments: &'b RenderResourceAssignments,
|
||||
encoder: &'a mut wgpu::CommandEncoder,
|
||||
primary_swap_chain: &Option<String>,
|
||||
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
|
||||
) -> 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,
|
||||
)
|
||||
})
|
||||
.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,
|
||||
)
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn create_wgpu_color_attachment_descriptor<'a>(
|
||||
wgpu_resources: &'a WgpuResources,
|
||||
global_render_resource_assignments: &RenderResourceAssignments,
|
||||
color_attachment_descriptor: &RenderPassColorAttachmentDescriptor,
|
||||
primary_swap_chain: &Option<String>,
|
||||
swap_chain_outputs: &'a HashMap<String, wgpu::SwapChainOutput>,
|
||||
) -> 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(),
|
||||
);
|
||||
|
||||
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(),
|
||||
)
|
||||
});
|
||||
|
||||
wgpu::RenderPassColorAttachmentDescriptor {
|
||||
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(),
|
||||
attachment,
|
||||
resolve_target,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_wgpu_depth_stencil_attachment_descriptor<'a>(
|
||||
wgpu_resources: &'a WgpuResources,
|
||||
global_render_resource_assignments: &RenderResourceAssignments,
|
||||
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(),
|
||||
);
|
||||
|
||||
wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment,
|
||||
clear_depth: depth_stencil_attachment_descriptor.clear_depth,
|
||||
clear_stencil: depth_stencil_attachment_descriptor.clear_stencil,
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize_resource_providers(
|
||||
world: &mut World,
|
||||
resources: &mut Resources,
|
||||
@ -398,35 +252,6 @@ impl WgpuRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
.global_context
|
||||
.render_resources
|
||||
.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)
|
||||
}
|
||||
|
||||
pub fn update(&mut self, world: &mut World, resources: &mut Resources) {
|
||||
Self::handle_window_created_events(
|
||||
resources,
|
||||
@ -457,78 +282,80 @@ impl WgpuRenderer {
|
||||
&mut self.global_context.render_resources.wgpu_resources,
|
||||
);
|
||||
|
||||
self.encoder = Some(
|
||||
self.global_context
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }),
|
||||
);
|
||||
update_shader_assignments(world, resources, &self.global_context);
|
||||
self.create_queued_textures(resources);
|
||||
let mut encoder = self.encoder.take().unwrap();
|
||||
|
||||
render_resource_sets_system().run(world, resources);
|
||||
// setup draw targets
|
||||
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
||||
render_graph.setup_pipeline_draw_targets(world, resources, &mut self.global_context);
|
||||
|
||||
let (primary_swap_chain, swap_chain_outputs) = self.get_swap_chain_outputs(resources);
|
||||
// get next swap chain texture on primary window
|
||||
let primary_window_id = resources
|
||||
.get::<Windows>()
|
||||
.unwrap()
|
||||
.get_primary()
|
||||
.map(|window| window.id);
|
||||
if let Some(primary_window_id) = primary_window_id {
|
||||
self.global_context
|
||||
.render_resources
|
||||
.next_swap_chain_texture(primary_window_id);
|
||||
self.global_context.primary_window = Some(primary_window_id);
|
||||
}
|
||||
|
||||
// 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 = {
|
||||
let global_render_resource_assignments =
|
||||
resources.get::<RenderResourceAssignments>().unwrap();
|
||||
Self::create_render_pass(
|
||||
&self.global_context.render_resources.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) =
|
||||
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
|
||||
.global_context
|
||||
.render_resources
|
||||
.get_pipeline(*compiled_pipeline_handle)
|
||||
.unwrap();
|
||||
render_pass.set_pipeline(render_pipeline);
|
||||
let global_render_resource_assignments =
|
||||
resources.get::<RenderResourceAssignments>().unwrap();
|
||||
self.global_context.begin_pass(
|
||||
pass_descriptor,
|
||||
&global_render_resource_assignments,
|
||||
&mut |render_pass| {
|
||||
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();
|
||||
render_pass.set_pipeline(*compiled_pipeline_handle);
|
||||
|
||||
let mut wgpu_render_pass = WgpuRenderPass {
|
||||
render_pass: &mut render_pass,
|
||||
pipeline_descriptor,
|
||||
render_context: &self.global_context,
|
||||
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,
|
||||
);
|
||||
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,
|
||||
render_pass,
|
||||
*compiled_pipeline_handle,
|
||||
pipeline_descriptor,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let command_buffer = encoder.finish();
|
||||
self.queue.submit(&[command_buffer]);
|
||||
let command_buffer = self.global_context.finish_encoder();
|
||||
if let Some(command_buffer) = command_buffer {
|
||||
self.queue.submit(&[command_buffer]);
|
||||
}
|
||||
|
||||
// clear primary swap chain texture
|
||||
if let Some(primary_window_id) = primary_window_id {
|
||||
self.global_context
|
||||
.render_resources
|
||||
.drop_swap_chain_texture(primary_window_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ pub struct WgpuResources {
|
||||
pub asset_resources: AssetResources,
|
||||
pub window_surfaces: HashMap<WindowId, wgpu::Surface>,
|
||||
pub window_swap_chains: HashMap<WindowId, wgpu::SwapChain>,
|
||||
pub swap_chain_outputs: HashMap<WindowId, wgpu::SwapChainOutput>,
|
||||
pub buffers: HashMap<RenderResource, wgpu::Buffer>,
|
||||
pub textures: HashMap<RenderResource, wgpu::TextureView>,
|
||||
pub samplers: HashMap<RenderResource, wgpu::Sampler>,
|
||||
@ -43,11 +44,14 @@ impl WgpuResources {
|
||||
self.window_surfaces.extend(wgpu_resources.window_surfaces);
|
||||
self.window_swap_chains
|
||||
.extend(wgpu_resources.window_swap_chains);
|
||||
self.swap_chain_outputs
|
||||
.extend(wgpu_resources.swap_chain_outputs);
|
||||
self.buffers.extend(wgpu_resources.buffers);
|
||||
self.textures.extend(wgpu_resources.textures);
|
||||
self.samplers.extend(wgpu_resources.samplers);
|
||||
self.resource_info.extend(wgpu_resources.resource_info);
|
||||
self.shader_modules.extend(wgpu_resources.shader_modules);
|
||||
self.render_pipelines.extend(wgpu_resources.render_pipelines);
|
||||
self.bind_groups.extend(wgpu_resources.bind_groups);
|
||||
self.bind_group_layouts
|
||||
.extend(wgpu_resources.bind_group_layouts);
|
||||
@ -61,6 +65,21 @@ impl WgpuResources {
|
||||
self.window_surfaces.get(&window_id)
|
||||
}
|
||||
|
||||
pub fn next_swap_chain_texture(&mut self, window_id: WindowId) -> Option<&wgpu::SwapChainOutput> {
|
||||
let swap_chain_output = self.window_swap_chains.get_mut(&window_id).unwrap();
|
||||
let next_texture = swap_chain_output.get_next_texture().unwrap();
|
||||
self.swap_chain_outputs.insert(window_id, next_texture);
|
||||
self.swap_chain_outputs.get(&window_id)
|
||||
}
|
||||
|
||||
pub fn remove_swap_chain_texture(&mut self, window_id: WindowId) {
|
||||
self.swap_chain_outputs.remove(&window_id);
|
||||
}
|
||||
|
||||
pub fn remove_all_swap_chain_textures(&mut self) {
|
||||
self.swap_chain_outputs.clear();
|
||||
}
|
||||
|
||||
pub fn create_window_swap_chain(&mut self, device: &wgpu::Device, window: &Window) {
|
||||
let swap_chain_descriptor: wgpu::SwapChainDescriptor = window.wgpu_into();
|
||||
let surface = self
|
||||
|
Loading…
Reference in New Issue
Block a user