partially working rwlock implementation (blocked on lifetime issues)

This commit is contained in:
Carter Anderson 2020-04-14 20:17:22 -07:00
parent 537d75bbce
commit b53f198b99
10 changed files with 425 additions and 822 deletions

View File

@ -239,7 +239,7 @@ impl PipelineAssignments {
// TODO: make this a system
pub fn update_shader_assignments(
world: &mut World,
resources: &mut Resources,
resources: &Resources,
render_context: &dyn RenderContext,
) {
// PERF: this seems like a lot of work for things that don't change that often.

View File

@ -17,25 +17,13 @@ impl RenderResource {
// the overlap could cause accidents.
#[derive(Default)]
pub struct AssetResources {
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>,
pub mesh_to_indices_resource: HashMap<Handle<Mesh>, RenderResource>,
texture_to_resource: HashMap<Handle<Texture>, RenderResource>,
texture_to_sampler_resource: HashMap<Handle<Texture>, RenderResource>,
mesh_to_vertices_resource: HashMap<Handle<Mesh>, RenderResource>,
mesh_to_indices_resource: HashMap<Handle<Mesh>, RenderResource>,
}
impl AssetResources {
pub fn consume(&mut self, render_resources: AssetResources) {
// TODO: this is brittle. consider a single change-stream-based approach instead?
self.texture_to_resource
.extend(render_resources.texture_to_resource);
self.texture_to_sampler_resource
.extend(render_resources.texture_to_sampler_resource);
self.mesh_to_vertices_resource
.extend(render_resources.mesh_to_vertices_resource);
self.mesh_to_indices_resource
.extend(render_resources.mesh_to_indices_resource);
}
pub fn set_texture_resource(&mut self, texture: Handle<Texture>, resource: RenderResource) {
self.texture_to_resource.insert(texture, resource);
}

View File

@ -6,13 +6,33 @@ use crate::{
};
use bevy_asset::{AssetStorage, Handle};
use bevy_window::{Window, WindowId};
use std::any::Any;
pub struct GlobalRenderResourceContext {
pub context: Box<dyn RenderResourceContext + Send + Sync + 'static>,
}
impl GlobalRenderResourceContext {
pub fn new<T>(context: T) -> GlobalRenderResourceContext
where
T: RenderResourceContext + Send + Sync + 'static,
{
GlobalRenderResourceContext {
context: Box::new(context),
}
}
// pub fn render_resources_mut(&mut self) -> &dyn RenderResourceContext {
// (&mut self.context).downcast_mut::<dyn RenderResourceContext>()
// }
// pub fn downcast_mut(&self) -> &dyn RenderResourceContext {
// self.context.downcast_ref::<RenderResourceContext>()
// }
}
// TODO: Rename to RenderResources after cleaning up AssetResources rename
pub trait RenderResourceContext {
pub trait RenderResourceContext: Any {
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);

View File

@ -1,9 +1,7 @@
mod systems;
mod wgpu_render_context;
mod wgpu_render_resource_context;
mod wgpu_transactional_render_resource_context;
pub use systems::*;
pub use wgpu_render_context::*;
pub use wgpu_render_resource_context::*;
pub use wgpu_transactional_render_resource_context::*;

View File

@ -1,4 +1,4 @@
use super::WgpuRenderResourceContextTrait;
use super::WgpuRenderResourceContext;
use crate::{
wgpu_type_converter::{OwnedWgpuVertexBufferDescriptor, WgpuInto},
WgpuRenderPass,
@ -21,7 +21,7 @@ use bevy_window::WindowId;
use std::{collections::HashMap, sync::Arc};
#[derive(Default)]
struct LazyCommandEncoder {
pub struct LazyCommandEncoder {
command_encoder: Option<wgpu::CommandEncoder>,
}
@ -55,22 +55,16 @@ impl LazyCommandEncoder {
}
}
pub struct WgpuRenderContext<T>
where
T: RenderResourceContext,
{
pub struct WgpuRenderContext {
pub device: Arc<wgpu::Device>,
// TODO: remove this
pub primary_window: Option<WindowId>,
command_encoder: LazyCommandEncoder,
pub render_resources: T,
pub command_encoder: LazyCommandEncoder,
pub render_resources: WgpuRenderResourceContext,
}
impl<T> WgpuRenderContext<T>
where
T: RenderResourceContext,
{
pub fn new(device: Arc<wgpu::Device>, resources: T) -> Self {
impl WgpuRenderContext {
pub fn new(device: Arc<wgpu::Device>, resources: WgpuRenderResourceContext) -> Self {
WgpuRenderContext {
device,
primary_window: None,
@ -81,34 +75,25 @@ where
/// Consume this context, finalize the current CommandEncoder (if it exists), and take the current WgpuResources.
/// This is intended to be called from a worker thread right before synchronizing with the main thread.
pub fn finish(mut self) -> (Option<wgpu::CommandBuffer>, T) {
(
self.command_encoder.take().map(|encoder| encoder.finish()),
self.render_resources,
)
}
/// Consume this context, finalize the current CommandEncoder (if it exists), and take the current WgpuResources.
/// This is intended to be called from a worker thread right before synchronizing with the main thread.
pub fn finish_encoder(&mut self) -> Option<wgpu::CommandBuffer> {
pub fn finish(&mut self) -> Option<wgpu::CommandBuffer> {
self.command_encoder.take().map(|encoder| encoder.finish())
}
}
impl<T> RenderContext for WgpuRenderContext<T>
where
T: RenderResourceContext + WgpuRenderResourceContextTrait,
{
impl RenderContext for WgpuRenderContext {
fn create_texture_with_data(
&mut self,
texture_descriptor: &TextureDescriptor,
bytes: &[u8],
) -> RenderResource {
self.render_resources.create_texture_with_data(
self.command_encoder.get_or_create(&self.device),
texture_descriptor,
bytes,
)
self.render_resources
.wgpu_resources
.create_texture_with_data(
&self.device,
self.command_encoder.get_or_create(&self.device),
texture_descriptor,
bytes,
)
}
fn copy_buffer_to_buffer(
&mut self,
@ -119,15 +104,11 @@ where
size: u64,
) {
let command_encoder = self.command_encoder.get_or_create(&self.device);
let source = self.render_resources.get_buffer(source_buffer).unwrap();
let destination = self
.render_resources
.get_buffer(destination_buffer)
.unwrap();
command_encoder.copy_buffer_to_buffer(
source,
self.render_resources.wgpu_resources.copy_buffer_to_buffer(
command_encoder,
source_buffer,
source_offset,
destination,
destination_buffer,
destination_offset,
size,
);
@ -148,6 +129,7 @@ where
{
if let None = self
.render_resources
.wgpu_resources
.get_bind_group(bind_group_descriptor.id, *render_resource_set_id)
{
log::trace!(
@ -155,6 +137,19 @@ where
render_resource_set_id
);
let wgpu_bind_group = {
let textures = self
.render_resources
.wgpu_resources
.textures
.read()
.unwrap();
let samplers = self
.render_resources
.wgpu_resources
.samplers
.read()
.unwrap();
let buffers = self.render_resources.wgpu_resources.buffers.read().unwrap();
let bindings = bind_group_descriptor
.bindings
.iter()
@ -174,10 +169,7 @@ where
resource: match &binding.bind_type {
BindType::SampledTexture { .. } => {
if let ResourceInfo::Texture = resource_info {
let texture = self
.render_resources
.get_texture(resource)
.unwrap();
let texture = textures.get(&resource).unwrap();
wgpu::BindingResource::TextureView(texture)
} else {
panic!("expected a Texture resource");
@ -185,10 +177,7 @@ where
}
BindType::Sampler { .. } => {
if let ResourceInfo::Sampler = resource_info {
let sampler = self
.render_resources
.get_sampler(resource)
.unwrap();
let sampler = samplers.get(&resource).unwrap();
wgpu::BindingResource::Sampler(sampler)
} else {
panic!("expected a Sampler resource");
@ -197,10 +186,7 @@ where
BindType::Uniform { .. } => {
if let ResourceInfo::Buffer(buffer_info) = resource_info
{
let buffer = self
.render_resources
.get_buffer(resource)
.unwrap();
let buffer = buffers.get(&resource).unwrap();
wgpu::BindingResource::Buffer {
buffer,
range: 0..buffer_info.size as u64,
@ -221,19 +207,26 @@ where
}
})
.collect::<Vec<wgpu::Binding>>();
let bind_group_layout = self
let bind_group_layouts = self
.render_resources
.get_bind_group_layout(bind_group_descriptor.id)
.wgpu_resources
.bind_group_layouts
.read()
.unwrap();
let bind_group_layout =
bind_group_layouts.get(&bind_group_descriptor.id).unwrap();
let wgpu_bind_group_descriptor = wgpu::BindGroupDescriptor {
label: None,
layout: bind_group_layout,
bindings: bindings.as_slice(),
};
self.render_resources
.create_bind_group(*render_resource_set_id, &wgpu_bind_group_descriptor)
self.render_resources.wgpu_resources.create_bind_group(
&self.device,
*render_resource_set_id,
&wgpu_bind_group_descriptor,
)
};
self.render_resources.set_bind_group(
self.render_resources.wgpu_resources.set_bind_group(
bind_group_descriptor.id,
*render_resource_set_id,
wgpu_bind_group,
@ -250,13 +243,27 @@ where
pipeline_descriptor: &mut PipelineDescriptor,
shader_storage: &AssetStorage<Shader>,
) {
if let Some(_) = self.render_resources.get_pipeline(pipeline_handle) {
if let Some(_) = self
.render_resources
.wgpu_resources
.render_pipelines
.read()
.unwrap()
.get(&pipeline_handle)
{
return;
}
let layout = pipeline_descriptor.get_layout().unwrap();
for bind_group in layout.bind_groups.iter() {
if let None = self.render_resources.get_bind_group_layout(bind_group.id) {
if let None = self
.render_resources
.wgpu_resources
.bind_group_layouts
.read()
.unwrap()
.get(&bind_group.id)
{
let bind_group_layout_binding = bind_group
.bindings
.iter()
@ -266,32 +273,37 @@ where
ty: (&binding.bind_type).wgpu_into(),
})
.collect::<Vec<wgpu::BindGroupLayoutEntry>>();
self.render_resources.create_bind_group_layout(
bind_group.id,
&wgpu::BindGroupLayoutDescriptor {
bindings: bind_group_layout_binding.as_slice(),
label: None,
},
);
self.render_resources
.wgpu_resources
.create_bind_group_layout(
&self.device,
bind_group.id,
&wgpu::BindGroupLayoutDescriptor {
bindings: bind_group_layout_binding.as_slice(),
label: None,
},
);
}
}
// setup and collect bind group layouts
let bind_group_layouts = layout
.bind_groups
.iter()
.map(|bind_group| {
self.render_resources
.get_bind_group_layout(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 pipeline_layout = {
let bind_group_layouts = self
.render_resources
.wgpu_resources
.bind_group_layouts
.read()
.unwrap();
// setup and collect bind group layouts
let bind_group_layouts = layout
.bind_groups
.iter()
.map(|bind_group| bind_group_layouts.get(&bind_group.id).unwrap())
.collect::<Vec<&wgpu::BindGroupLayout>>();
self.device
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: bind_group_layouts.as_slice(),
})
};
let owned_vertex_buffer_descriptors = layout
.vertex_buffer_descriptors
@ -305,32 +317,46 @@ where
.map(|c| c.wgpu_into())
.collect::<Vec<wgpu::ColorStateDescriptor>>();
if let None = self
if self
.render_resources
.get_shader_module(pipeline_descriptor.shader_stages.vertex)
.wgpu_resources
.shader_modules
.read()
.unwrap()
.get(&pipeline_descriptor.shader_stages.vertex)
.is_none()
{
self.render_resources
.create_shader_module(pipeline_descriptor.shader_stages.vertex, shader_storage);
}
if let Some(fragment_handle) = pipeline_descriptor.shader_stages.fragment {
if let None = self.render_resources.get_shader_module(fragment_handle) {
if self
.render_resources
.wgpu_resources
.shader_modules
.read()
.unwrap()
.get(&fragment_handle)
.is_none()
{
self.render_resources
.create_shader_module(fragment_handle, shader_storage);
}
};
let wgpu_pipeline = {
let vertex_shader_module = self
let shader_modules = self
.render_resources
.get_shader_module(pipeline_descriptor.shader_stages.vertex)
.wgpu_resources
.shader_modules
.read()
.unwrap();
let vertex_shader_module = shader_modules
.get(&pipeline_descriptor.shader_stages.vertex)
.unwrap();
let fragment_shader_module = match pipeline_descriptor.shader_stages.fragment {
Some(fragment_handle) => Some(
self.render_resources
.get_shader_module(fragment_handle)
.unwrap(),
),
Some(fragment_handle) => Some(shader_modules.get(&fragment_handle).unwrap()),
None => None,
};
@ -370,9 +396,11 @@ where
};
self.render_resources
.create_render_pipeline(&render_pipeline_descriptor)
.wgpu_resources
.create_render_pipeline(&self.device, &render_pipeline_descriptor)
};
self.render_resources
.wgpu_resources
.set_render_pipeline(pipeline_handle, wgpu_pipeline);
}
fn begin_pass(
@ -406,15 +434,12 @@ where
}
}
pub fn create_render_pass<'a, 'b, T>(
render_context: &'a WgpuRenderContext<T>,
pub fn create_render_pass<'a, 'b>(
render_context: &'a WgpuRenderContext,
pass_descriptor: &PassDescriptor,
global_render_resource_assignments: &'b RenderResourceAssignments,
encoder: &'a mut wgpu::CommandEncoder,
) -> wgpu::RenderPass<'a>
where
T: WgpuRenderResourceContextTrait + RenderResourceContext,
{
) -> wgpu::RenderPass<'a> {
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &pass_descriptor
.color_attachments
@ -437,19 +462,20 @@ where
})
}
fn get_texture_view<'a, T>(
render_context: &'a WgpuRenderContext<T>,
fn get_texture_view<'a>(
render_context: &'a WgpuRenderContext,
global_render_resource_assignments: &RenderResourceAssignments,
name: &str,
) -> &'a wgpu::TextureView
where
T: WgpuRenderResourceContextTrait + RenderResourceContext,
{
) -> &'a wgpu::TextureView {
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())
.wgpu_resources
.swap_chain_outputs
.read()
.unwrap()
.get(render_context.primary_window.as_ref().unwrap())
.map(|output| &output.view)
{
primary_swap_chain
@ -460,7 +486,11 @@ where
_ => match global_render_resource_assignments.get(name) {
Some(resource) => render_context
.render_resources
.get_texture(resource)
.wgpu_resources
.textures
.read()
.unwrap()
.get(&resource)
.unwrap(),
None => {
// if let Some(swap_chain_output) = swap_chain_outputs.get(name) {
@ -473,14 +503,11 @@ where
}
}
fn create_wgpu_color_attachment_descriptor<'a, T>(
render_context: &'a WgpuRenderContext<T>,
fn create_wgpu_color_attachment_descriptor<'a>(
render_context: &'a WgpuRenderContext,
global_render_resource_assignments: &RenderResourceAssignments,
color_attachment_descriptor: &RenderPassColorAttachmentDescriptor,
) -> wgpu::RenderPassColorAttachmentDescriptor<'a>
where
T: WgpuRenderResourceContextTrait + RenderResourceContext,
{
) -> wgpu::RenderPassColorAttachmentDescriptor<'a> {
let attachment = get_texture_view(
render_context,
global_render_resource_assignments,
@ -507,14 +534,11 @@ where
}
}
fn create_wgpu_depth_stencil_attachment_descriptor<'a, T>(
render_context: &'a WgpuRenderContext<T>,
fn create_wgpu_depth_stencil_attachment_descriptor<'a>(
render_context: &'a WgpuRenderContext,
global_render_resource_assignments: &RenderResourceAssignments,
depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor,
) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a>
where
T: WgpuRenderResourceContextTrait + RenderResourceContext,
{
) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> {
let attachment = get_texture_view(
render_context,
global_render_resource_assignments,

View File

@ -3,9 +3,8 @@ use crate::WgpuResources;
use bevy_asset::{AssetStorage, Handle};
use bevy_render::{
mesh::Mesh,
pipeline::{BindGroupDescriptorId, PipelineDescriptor},
render_resource::{
AssetResources, BufferInfo, RenderResource, RenderResourceSetId, ResourceInfo,
AssetResources, BufferInfo, RenderResource, ResourceInfo,
},
renderer_2::RenderResourceContext,
shader::Shader,
@ -14,158 +13,18 @@ use bevy_render::{
use std::sync::Arc;
use bevy_window::{WindowId, Window};
#[derive(Clone)]
pub struct WgpuRenderResourceContext {
pub device: Arc<wgpu::Device>,
pub wgpu_resources: WgpuResources,
pub wgpu_resources: Arc<WgpuResources>,
}
// TODO: make this name not terrible
pub trait WgpuRenderResourceContextTrait {
fn create_texture_with_data(
&mut self,
command_encoder: &mut wgpu::CommandEncoder,
texture_descriptor: &TextureDescriptor,
bytes: &[u8],
) -> RenderResource;
fn create_bind_group(
&self,
render_resource_set_id: RenderResourceSetId,
descriptor: &wgpu::BindGroupDescriptor,
) -> wgpu::BindGroup;
fn set_bind_group(
&mut self,
bind_group_descriptor_id: BindGroupDescriptorId,
render_resource_set_id: RenderResourceSetId,
bind_group: wgpu::BindGroup,
);
fn create_bind_group_layout(
&mut self,
bind_group_id: BindGroupDescriptorId,
descriptor: &wgpu::BindGroupLayoutDescriptor,
);
fn create_render_pipeline(
&self,
descriptor: &wgpu::RenderPipelineDescriptor,
) -> wgpu::RenderPipeline;
fn set_render_pipeline(
&mut self,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline: wgpu::RenderPipeline,
);
fn get_bind_group(
&self,
bind_group_id: BindGroupDescriptorId,
render_resource_set_id: RenderResourceSetId,
) -> Option<&wgpu::BindGroup>;
fn get_bind_group_layout(
&self,
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>;
fn get_shader_module(&self, shader: Handle<Shader>) -> Option<&wgpu::ShaderModule>;
}
impl WgpuRenderResourceContextTrait for WgpuRenderResourceContext {
fn get_buffer(&self, render_resource: RenderResource) -> Option<&wgpu::Buffer> {
self.wgpu_resources.buffers.get(&render_resource)
}
fn create_texture_with_data(
&mut self,
command_encoder: &mut wgpu::CommandEncoder,
texture_descriptor: &TextureDescriptor,
bytes: &[u8],
) -> RenderResource {
self.wgpu_resources.create_texture_with_data(
&self.device,
command_encoder,
texture_descriptor,
bytes,
)
}
fn create_bind_group(
&self,
render_resource_set_id: RenderResourceSetId,
descriptor: &wgpu::BindGroupDescriptor,
) -> wgpu::BindGroup {
self.wgpu_resources
.create_bind_group(&self.device, render_resource_set_id, descriptor)
}
fn create_bind_group_layout(
&mut self,
bind_group_id: BindGroupDescriptorId,
descriptor: &wgpu::BindGroupLayoutDescriptor,
) {
self.wgpu_resources
.create_bind_group_layout(&self.device, bind_group_id, descriptor);
}
fn create_render_pipeline(
&self,
descriptor: &wgpu::RenderPipelineDescriptor,
) -> wgpu::RenderPipeline {
self.wgpu_resources
.create_render_pipeline(&self.device, descriptor)
}
fn get_bind_group(
&self,
bind_group_descriptor_id: BindGroupDescriptorId,
render_resource_set_id: RenderResourceSetId,
) -> Option<&wgpu::BindGroup> {
self.wgpu_resources
.get_bind_group(bind_group_descriptor_id, render_resource_set_id)
}
fn get_bind_group_layout(
&self,
bind_group_id: BindGroupDescriptorId,
) -> Option<&wgpu::BindGroupLayout> {
self.wgpu_resources.bind_group_layouts.get(&bind_group_id)
}
fn get_texture(&self, render_resource: RenderResource) -> Option<&wgpu::TextureView> {
self.wgpu_resources.textures.get(&render_resource)
}
fn get_sampler(&self, render_resource: RenderResource) -> Option<&wgpu::Sampler> {
self.wgpu_resources.samplers.get(&render_resource)
}
fn get_pipeline(&self, pipeline: Handle<PipelineDescriptor>) -> Option<&wgpu::RenderPipeline> {
self.wgpu_resources.render_pipelines.get(&pipeline)
}
fn get_shader_module(&self, shader: Handle<Shader>) -> Option<&wgpu::ShaderModule> {
self.wgpu_resources.shader_modules.get(&shader)
}
fn set_bind_group(
&mut self,
bind_group_descriptor_id: BindGroupDescriptorId,
render_resource_set_id: RenderResourceSetId,
bind_group: wgpu::BindGroup,
) {
self.wgpu_resources.set_bind_group(
bind_group_descriptor_id,
render_resource_set_id,
bind_group,
);
}
fn set_render_pipeline(
&mut self,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline: wgpu::RenderPipeline,
) {
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 {
pub fn new(device: Arc<wgpu::Device>) -> Self {
WgpuRenderResourceContext {
device,
wgpu_resources: WgpuResources::default(),
wgpu_resources: Arc::new(WgpuResources::default()),
}
}
}
@ -251,7 +110,7 @@ impl RenderResourceContext for WgpuRenderResourceContext {
shader_handle: Handle<Shader>,
shader_storage: &AssetStorage<Shader>,
) {
if self.get_shader_module(shader_handle).is_some() {
if self.wgpu_resources.shader_modules.read().unwrap().get(&shader_handle).is_some() {
return;
}

View File

@ -1,307 +0,0 @@
use crate::WgpuResources;
use super::WgpuRenderResourceContextTrait;
use bevy_asset::Handle;
use bevy_render::{
mesh::Mesh,
pipeline::{BindGroupDescriptorId, PipelineDescriptor},
render_resource::{
AssetResources, BufferInfo, RenderResource, RenderResourceSetId, ResourceInfo,
},
renderer_2::RenderResourceContext,
shader::Shader,
texture::{SamplerDescriptor, Texture, TextureDescriptor},
};
use bevy_window::{WindowId, Window};
use std::sync::Arc;
pub struct WgpuTransactionalRenderResourceContext<'a> {
pub device: Arc<wgpu::Device>,
pub local_resources: WgpuResources,
pub parent_resources: &'a WgpuResources,
removed_resources: Vec<RenderResource>,
}
impl<'a> WgpuRenderResourceContextTrait for WgpuTransactionalRenderResourceContext<'a> {
fn get_buffer(&self, render_resource: RenderResource) -> Option<&wgpu::Buffer> {
let local = self.local_resources.buffers.get(&render_resource);
if local.is_some() {
return local;
}
self.parent_resources.buffers.get(&render_resource)
}
fn create_texture_with_data(
&mut self,
command_encoder: &mut wgpu::CommandEncoder,
texture_descriptor: &TextureDescriptor,
bytes: &[u8],
) -> RenderResource {
self.local_resources.create_texture_with_data(
&self.device,
command_encoder,
texture_descriptor,
bytes,
)
}
fn create_bind_group(
&self,
render_resource_set_id: RenderResourceSetId,
descriptor: &wgpu::BindGroupDescriptor,
) -> wgpu::BindGroup {
self.local_resources
.create_bind_group(&self.device, render_resource_set_id, descriptor)
}
fn create_bind_group_layout(
&mut self,
bind_group_id: BindGroupDescriptorId,
descriptor: &wgpu::BindGroupLayoutDescriptor,
) {
self.local_resources
.create_bind_group_layout(&self.device, bind_group_id, descriptor);
}
fn create_render_pipeline(
&self,
descriptor: &wgpu::RenderPipelineDescriptor,
) -> wgpu::RenderPipeline {
self.local_resources
.create_render_pipeline(&self.device, descriptor)
}
fn get_bind_group(
&self,
bind_group_descriptor_id: BindGroupDescriptorId,
render_resource_set_id: RenderResourceSetId,
) -> Option<&wgpu::BindGroup> {
let local = self
.local_resources
.get_bind_group(bind_group_descriptor_id, render_resource_set_id);
if local.is_some() {
return local;
}
self.parent_resources
.get_bind_group(bind_group_descriptor_id, render_resource_set_id)
}
fn get_bind_group_layout(
&self,
bind_group_id: BindGroupDescriptorId,
) -> Option<&wgpu::BindGroupLayout> {
let local = self.local_resources.bind_group_layouts.get(&bind_group_id);
if local.is_some() {
return local;
}
self.parent_resources.bind_group_layouts.get(&bind_group_id)
}
fn get_texture(&self, render_resource: RenderResource) -> Option<&wgpu::TextureView> {
let local = self.local_resources.textures.get(&render_resource);
if local.is_some() {
return local;
}
self.parent_resources.textures.get(&render_resource)
}
fn get_sampler(&self, render_resource: RenderResource) -> Option<&wgpu::Sampler> {
let local = self.local_resources.samplers.get(&render_resource);
if local.is_some() {
return local;
}
self.parent_resources.samplers.get(&render_resource)
}
fn get_pipeline(&self, pipeline: Handle<PipelineDescriptor>) -> Option<&wgpu::RenderPipeline> {
let local = self.local_resources.render_pipelines.get(&pipeline);
if local.is_some() {
return local;
}
self.parent_resources.render_pipelines.get(&pipeline)
}
fn get_shader_module(&self, shader: Handle<Shader>) -> Option<&wgpu::ShaderModule> {
let local = self.local_resources.shader_modules.get(&shader);
if local.is_some() {
return local;
}
self.parent_resources.shader_modules.get(&shader)
}
fn set_bind_group(
&mut self,
bind_group_descriptor_id: BindGroupDescriptorId,
render_resource_set_id: RenderResourceSetId,
bind_group: wgpu::BindGroup,
) {
self.local_resources.set_bind_group(
bind_group_descriptor_id,
render_resource_set_id,
bind_group,
);
}
fn set_render_pipeline(
&mut self,
pipeline_handle: Handle<PipelineDescriptor>,
pipeline: wgpu::RenderPipeline,
) {
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> {
pub fn new(device: Arc<wgpu::Device>, parent_resources: &'a WgpuResources) -> Self {
WgpuTransactionalRenderResourceContext {
device,
local_resources: WgpuResources::default(),
parent_resources,
removed_resources: Vec::new(),
}
}
}
impl<'a> RenderResourceContext for WgpuTransactionalRenderResourceContext<'a> {
fn create_sampler(&mut self, sampler_descriptor: &SamplerDescriptor) -> RenderResource {
self.local_resources
.create_sampler(&self.device, sampler_descriptor)
}
fn create_texture(&mut self, texture_descriptor: &TextureDescriptor) -> RenderResource {
self.local_resources
.create_texture(&self.device, texture_descriptor)
}
fn create_buffer(&mut self, buffer_info: BufferInfo) -> RenderResource {
self.local_resources
.create_buffer(&self.device, buffer_info)
}
// TODO: clean this up
fn create_buffer_mapped(
&mut self,
buffer_info: BufferInfo,
setup_data: &mut dyn FnMut(&mut [u8], &mut dyn RenderResourceContext),
) -> RenderResource {
let buffer = WgpuResources::begin_create_buffer_mapped_transactional_render_context(
&buffer_info,
self,
setup_data,
);
self.local_resources.assign_buffer(buffer, buffer_info)
}
fn create_buffer_with_data(&mut self, buffer_info: BufferInfo, data: &[u8]) -> RenderResource {
self.local_resources
.create_buffer_with_data(&self.device, buffer_info, data)
}
fn remove_buffer(&mut self, resource: RenderResource) {
self.local_resources.remove_buffer(resource);
self.removed_resources.push(resource);
}
fn remove_texture(&mut self, resource: RenderResource) {
self.local_resources.remove_texture(resource);
self.removed_resources.push(resource);
}
fn remove_sampler(&mut self, resource: RenderResource) {
self.local_resources.remove_sampler(resource);
self.removed_resources.push(resource);
}
fn get_texture_resource(&self, texture: Handle<Texture>) -> Option<RenderResource> {
let local = self
.local_resources
.asset_resources
.get_texture_resource(texture);
if local.is_some() {
return local;
}
self.parent_resources
.asset_resources
.get_texture_resource(texture)
}
fn get_texture_sampler_resource(&self, texture: Handle<Texture>) -> Option<RenderResource> {
let local = self
.local_resources
.asset_resources
.get_texture_sampler_resource(texture);
if local.is_some() {
return local;
}
self.parent_resources
.asset_resources
.get_texture_sampler_resource(texture)
}
fn get_mesh_vertices_resource(&self, mesh: Handle<Mesh>) -> Option<RenderResource> {
let local = self
.local_resources
.asset_resources
.get_mesh_vertices_resource(mesh);
if local.is_some() {
return local;
}
self.parent_resources
.asset_resources
.get_mesh_vertices_resource(mesh)
}
fn get_mesh_indices_resource(&self, mesh: Handle<Mesh>) -> Option<RenderResource> {
let local = self
.local_resources
.asset_resources
.get_mesh_indices_resource(mesh);
if local.is_some() {
return local;
}
self.parent_resources
.asset_resources
.get_mesh_indices_resource(mesh)
}
fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> {
let local = self.local_resources.get_resource_info(resource);
if local.is_some() {
return local;
}
self.parent_resources.get_resource_info(resource)
}
fn asset_resources(&self) -> &AssetResources {
&self.local_resources.asset_resources
}
fn asset_resources_mut(&mut self) -> &mut AssetResources {
&mut self.local_resources.asset_resources
}
fn create_shader_module(
&mut self,
shader_handle: Handle<Shader>,
shader_storage: &bevy_asset::AssetStorage<Shader>,
) {
if self.get_shader_module(shader_handle).is_some() {
return;
}
let shader = shader_storage.get(&shader_handle).unwrap();
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);
}
}

View File

@ -1,47 +1,48 @@
use crate::renderer_2::{WgpuRenderContext, WgpuRenderResourceContextTrait};
use crate::renderer_2::WgpuRenderContext;
use bevy_asset::Handle;
use bevy_render::{
pass::RenderPass,
pipeline::PipelineDescriptor,
render_resource::{
RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
},
renderer_2::{RenderContext, RenderResourceContext},
renderer_2::RenderContext,
};
use std::{collections::HashMap, ops::Range};
pub struct WgpuRenderPass<'a, T>
where
T: RenderResourceContext + WgpuRenderResourceContextTrait,
{
pub struct WgpuRenderPass<'a> {
pub render_pass: wgpu::RenderPass<'a>,
pub render_context: &'a WgpuRenderContext<T>,
pub render_context: &'a WgpuRenderContext,
pub bound_bind_groups: HashMap<u32, RenderResourceSetId>,
}
impl<'a, T> RenderPass for WgpuRenderPass<'a, T>
where
T: RenderResourceContext + WgpuRenderResourceContextTrait,
{
impl<'a> RenderPass for WgpuRenderPass<'a> {
fn get_render_context(&self) -> &dyn RenderContext {
self.render_context
}
fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64) {
let buffer = self
let buffers = self
.render_context
.render_resources
.get_buffer(resource)
.wgpu_resources
.buffers
.read()
.unwrap();
let buffer = buffers.get(&resource).unwrap();
self.render_pass
.set_vertex_buffer(start_slot, &buffer, offset, 0);
}
fn set_index_buffer(&mut self, resource: RenderResource, offset: u64) {
let buffer = self
let buffers = self
.render_context
.render_resources
.get_buffer(resource)
.wgpu_resources
.buffers
.read()
.unwrap();
let buffer = buffers.get(&resource).unwrap();
self.render_pass.set_index_buffer(&buffer, offset, 0);
}
@ -55,8 +56,7 @@ where
pipeline_descriptor: &PipelineDescriptor,
render_resource_assignments: &RenderResourceAssignments,
) -> Option<Range<u32>> {
let pipeline_layout = 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;
@ -102,6 +102,7 @@ where
if let Some(wgpu_bind_group) = self
.render_context
.render_resources
.wgpu_resources
.get_bind_group(bind_group.id, *render_resource_set_id)
{
const EMPTY: &'static [u32] = &[];
@ -148,8 +149,17 @@ 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");
fn set_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>) {
let render_pipelines = self
.render_context
.render_resources
.wgpu_resources
.render_pipelines
.read()
.unwrap();
let pipeline = render_pipelines.get(&pipeline_handle).expect(
"Attempted to use a pipeline that does not exist in this RenderPass's RenderContext",
);
self.render_pass.set_pipeline(pipeline);
}
}

View File

@ -1,7 +1,5 @@
use super::WgpuResources;
use crate::renderer_2::{
render_resource_sets_system, WgpuRenderContext, WgpuRenderResourceContext,
WgpuTransactionalRenderResourceContext,
};
use bevy_app::{EventReader, Events};
use bevy_asset::AssetStorage;
@ -9,14 +7,14 @@ use bevy_render::{
pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor},
render_graph::RenderGraph,
render_resource::RenderResourceAssignments,
renderer_2::{RenderContext, RenderResourceContext},
renderer_2::{GlobalRenderResourceContext, RenderContext, RenderResourceContext},
};
use bevy_window::{WindowCreated, WindowResized, Windows};
use legion::prelude::*;
use std::{collections::HashSet, ops::Deref, sync::Arc};
use std::{any::Any, collections::HashSet, ops::Deref, sync::Arc};
pub struct WgpuRenderer {
pub global_context: WgpuRenderContext<WgpuRenderResourceContext>,
pub device: Arc<wgpu::Device>,
pub queue: wgpu::Queue,
pub window_resized_event_reader: EventReader<WindowResized>,
pub window_created_event_reader: EventReader<WindowCreated>,
@ -48,10 +46,7 @@ impl WgpuRenderer {
.await;
let device = Arc::new(device);
WgpuRenderer {
global_context: WgpuRenderContext::new(
device.clone(),
WgpuRenderResourceContext::new(device),
),
device,
queue,
window_resized_event_reader,
window_created_event_reader,
@ -61,8 +56,8 @@ impl WgpuRenderer {
pub fn initialize_resource_providers(
world: &mut World,
resources: &mut Resources,
render_context: &mut WgpuRenderContext<WgpuRenderResourceContext>,
resources: &Resources,
render_context: &mut WgpuRenderContext,
) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
for resource_provider in render_graph.resource_providers.iter_mut() {
@ -74,8 +69,8 @@ impl WgpuRenderer {
world: &World,
resources: &Resources,
device: Arc<wgpu::Device>,
global_wgpu_resources: &WgpuResources,
) -> (Vec<wgpu::CommandBuffer>, Vec<WgpuResources>) {
render_resource_context: &WgpuRenderResourceContext,
) -> Vec<wgpu::CommandBuffer> {
let max_thread_count = 8;
let (sender, receiver) = crossbeam_channel::bounded(max_thread_count);
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
@ -86,21 +81,15 @@ impl WgpuRenderer {
crossbeam_utils::thread::scope(|s| {
for resource_provider_chunk in render_graph.resource_providers.chunks_mut(chunk_size) {
let device = device.clone();
let resource_device = device.clone();
let sender = sender.clone();
let global_wgpu_resources = &*global_wgpu_resources;
let world = &*world;
let resources = &*resources;
actual_thread_count += 1;
// println!("spawn {}", resource_provider_chunk.len());
let render_resource_context = render_resource_context.clone();
s.spawn(move |_| {
let mut render_context = WgpuRenderContext::new(
device,
WgpuTransactionalRenderResourceContext::new(
resource_device,
global_wgpu_resources,
),
);
let mut render_context =
WgpuRenderContext::new(device, render_resource_context);
for resource_provider in resource_provider_chunk.iter_mut() {
resource_provider.update(&mut render_context, world, resources);
}
@ -111,37 +100,28 @@ impl WgpuRenderer {
.unwrap();
let mut command_buffers = Vec::new();
let mut local_resources = Vec::new();
for _i in 0..actual_thread_count {
let (command_buffer, render_resources) = receiver.recv().unwrap();
let command_buffer = receiver.recv().unwrap();
if let Some(command_buffer) = command_buffer {
command_buffers.push(command_buffer);
}
local_resources.push(render_resources.local_resources);
// println!("got {}", i);
}
(command_buffers, local_resources)
command_buffers
}
pub fn update_resource_providers(
&mut self,
world: &mut World,
resources: &mut Resources,
queue: &mut wgpu::Queue,
device: Arc<wgpu::Device>,
global_wgpu_resources: &mut WgpuResources,
resources: &Resources,
render_resource_context: &WgpuRenderResourceContext,
) {
let (mut command_buffers, local_resources) = Self::parallel_resource_provider_update(
let mut command_buffers = Self::parallel_resource_provider_update(
world,
resources,
device.clone(),
global_wgpu_resources,
self.device.clone(),
render_resource_context,
);
for local_resource in local_resources {
global_wgpu_resources.consume(local_resource);
}
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
let mut results = Vec::new();
@ -150,15 +130,13 @@ impl WgpuRenderer {
// crossbeam_utils::thread::scope(|s| {
for resource_provider_chunk in render_graph.resource_providers.chunks_mut(chunk_size) {
// TODO: try to unify this Device usage
let device = device.clone();
let device = self.device.clone();
let resource_device = device.clone();
// let sender = sender.clone();
// s.spawn(|_| {
// TODO: replace WgpuResources with Global+Local resources
let mut render_context = WgpuRenderContext::new(
device,
WgpuTransactionalRenderResourceContext::new(resource_device, global_wgpu_resources),
);
let mut render_context =
WgpuRenderContext::new(device, render_resource_context.clone());
for resource_provider in resource_provider_chunk.iter_mut() {
resource_provider.finish_update(&mut render_context, world, resources);
}
@ -168,42 +146,37 @@ impl WgpuRenderer {
}
// });
let mut local_resources = Vec::new();
for (command_buffer, render_resources) in results {
for command_buffer 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);
}
local_resources.push(render_resources.local_resources);
// println!("got {}", i);
}
for local_resource in local_resources {
global_wgpu_resources.consume(local_resource);
}
queue.submit(&command_buffers);
self.queue.submit(&command_buffers);
}
pub fn create_queued_textures(&mut self, resources: &mut Resources) {
pub fn create_queued_textures(
&mut self,
resources: &Resources,
global_render_resources: &mut WgpuRenderResourceContext,
) {
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
.global_context
.resources_mut()
.create_texture(&texture_descriptor);
let resource = global_render_resources.create_texture(&texture_descriptor);
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>,
&mut self,
resources: &Resources,
global_render_resources: &mut WgpuRenderResourceContext,
) {
let windows = resources.get::<Windows>().unwrap();
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
@ -211,7 +184,7 @@ impl WgpuRenderer {
// 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)
.iter(&mut self.window_resized_event_reader)
.rev()
{
if handled_windows.contains(&window_resized_event.id) {
@ -223,21 +196,22 @@ impl WgpuRenderer {
.expect("Received window resized event for non-existent window");
// TODO: consider making this a WgpuRenderContext method
wgpu_resources.create_window_swap_chain(device, window);
global_render_resources.create_swap_chain(window);
handled_windows.insert(window_resized_event.id);
}
}
pub fn handle_window_created_events(
resources: &mut Resources,
device: &wgpu::Device,
wgpu_resources: &mut WgpuResources,
window_created_event_reader: &mut EventReader<WindowCreated>,
&mut self,
resources: &Resources,
global_render_resource_context: &mut WgpuRenderResourceContext,
) {
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) {
for window_created_event in
window_created_events.iter(&mut self.window_created_event_reader)
{
let window = windows
.get(window_created_event.id)
.expect("Received window created event for non-existent window");
@ -246,49 +220,81 @@ impl WgpuRenderer {
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);
global_render_resource_context
.wgpu_resources
.set_window_surface(window.id, surface);
global_render_resource_context.create_swap_chain(window);
}
}
}
pub fn create_global_render_resource_context(&self, resources: &mut Resources) {
resources.insert(GlobalRenderResourceContext::new(
WgpuRenderResourceContext::new(self.device.clone()),
))
}
pub fn update(&mut self, world: &mut World, resources: &mut Resources) {
Self::handle_window_created_events(
resources,
&self.global_context.device,
&mut self.global_context.render_resources.wgpu_resources,
&mut self.window_created_event_reader,
);
Self::handle_window_resized_events(
resources,
&self.global_context.device,
&mut self.global_context.render_resources.wgpu_resources,
&mut self.window_resized_event_reader,
);
if !self.intialized {
Self::initialize_resource_providers(world, resources, &mut self.global_context);
let buffer = self.global_context.finish_encoder();
if let Some(buffer) = buffer {
self.queue.submit(&[buffer]);
}
self.intialized = true;
self.create_global_render_resource_context(resources);
}
Self::update_resource_providers(
world,
resources,
&mut self.queue,
self.global_context.device.clone(),
&mut self.global_context.render_resources.wgpu_resources,
);
let mut encoder = {
let mut global_context = resources.get_mut::<GlobalRenderResourceContext>().unwrap();
let mut any_context = (&mut global_context.context) as &mut dyn Any;
// let mut any_context = (&mut global_context.context);
// println!("{}", std::any::type_name_of_val(any_context));
let mut render_resource_context = any_context
.downcast_mut::<WgpuRenderResourceContext>()
.unwrap();
panic!("ahh");
update_shader_assignments(world, resources, &self.global_context);
self.create_queued_textures(resources);
// let mut render_resource_context = any_context
// .downcast_mut::<WgpuRenderResourceContext>()
// .unwrap();
self.handle_window_created_events(resources, render_resource_context);
self.handle_window_resized_events(resources, render_resource_context);
let mut render_context =
WgpuRenderContext::new(self.device.clone(), render_resource_context.clone());
if !self.intialized {
Self::initialize_resource_providers(world, resources, &mut render_context);
let buffer = render_context.finish();
if let Some(buffer) = buffer {
self.queue.submit(&[buffer]);
}
self.intialized = true;
}
self.update_resource_providers(
world,
resources,
render_resource_context,
);
update_shader_assignments(world, resources, &render_context);
self.create_queued_textures(resources, &mut render_context.render_resources);
render_context.command_encoder.take()
};
// TODO: add to POST_UPDATE and remove redundant global_context
render_resource_sets_system().run(world, resources);
let mut global_context = resources.get_mut::<GlobalRenderResourceContext>().unwrap();
let mut any_context = (&mut global_context.context) as &mut dyn Any;
// let mut any_context = (&mut global_context.context);
// println!("{}", std::any::type_name_of_val(any_context));
let mut render_resource_context = any_context
.downcast_mut::<WgpuRenderResourceContext>()
.unwrap();
let mut render_context =
WgpuRenderContext::new(self.device.clone(), render_resource_context.clone());
if let Some(command_encoder) = encoder.take() {
render_context.command_encoder.set(command_encoder);
}
// setup draw targets
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.setup_pipeline_draw_targets(world, resources, &mut self.global_context);
render_graph.setup_pipeline_draw_targets(world, resources, &mut render_context);
// get next swap chain texture on primary window
let primary_window_id = resources
@ -297,10 +303,10 @@ impl WgpuRenderer {
.get_primary()
.map(|window| window.id);
if let Some(primary_window_id) = primary_window_id {
self.global_context
render_context
.render_resources
.next_swap_chain_texture(primary_window_id);
self.global_context.primary_window = Some(primary_window_id);
render_context.primary_window = Some(primary_window_id);
}
// begin render passes
@ -310,7 +316,7 @@ impl WgpuRenderer {
for (pass_name, pass_descriptor) in render_graph.pass_descriptors.iter() {
let global_render_resource_assignments =
resources.get::<RenderResourceAssignments>().unwrap();
self.global_context.begin_pass(
render_context.begin_pass(
pass_descriptor,
&global_render_resource_assignments,
&mut |render_pass| {
@ -346,14 +352,14 @@ impl WgpuRenderer {
);
}
let command_buffer = self.global_context.finish_encoder();
let command_buffer = render_context.finish();
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_context
.render_resources
.drop_swap_chain_texture(primary_window_id);
}

View File

@ -1,7 +1,4 @@
use crate::{
renderer_2::{WgpuRenderResourceContext, WgpuTransactionalRenderResourceContext},
wgpu_type_converter::WgpuInto,
};
use crate::{renderer_2::WgpuRenderResourceContext, wgpu_type_converter::WgpuInto};
use bevy_asset::Handle;
use bevy_render::{
pipeline::{BindGroupDescriptorId, PipelineDescriptor},
@ -13,85 +10,94 @@ use bevy_render::{
texture::{SamplerDescriptor, TextureDescriptor},
};
use bevy_window::{Window, WindowId};
use std::collections::HashMap;
use std::{
collections::HashMap,
sync::{Arc, RwLock, RwLockReadGuard},
};
#[derive(Default)]
pub struct WgpuBindGroupInfo {
pub bind_groups: HashMap<RenderResourceSetId, wgpu::BindGroup>,
}
pub struct WgpuResourcesReadLock<'a> {
pub buffers: RwLockReadGuard<'a, HashMap<RenderResource, wgpu::Buffer>>,
pub textures: RwLockReadGuard<'a, HashMap<RenderResource, wgpu::TextureView>>,
}
#[derive(Default)]
pub struct WgpuResources {
// TODO: remove this from WgpuResources. it doesn't need to be here
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>,
pub resource_info: HashMap<RenderResource, ResourceInfo>,
pub shader_modules: HashMap<Handle<Shader>, wgpu::ShaderModule>,
pub render_pipelines: HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
pub bind_groups: HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>,
pub bind_group_layouts: HashMap<BindGroupDescriptorId, wgpu::BindGroupLayout>,
pub window_surfaces: Arc<RwLock<HashMap<WindowId, wgpu::Surface>>>,
pub window_swap_chains: Arc<RwLock<HashMap<WindowId, wgpu::SwapChain>>>,
pub swap_chain_outputs: Arc<RwLock<HashMap<WindowId, wgpu::SwapChainOutput>>>,
pub buffers: Arc<RwLock<HashMap<RenderResource, wgpu::Buffer>>>,
pub textures: Arc<RwLock<HashMap<RenderResource, wgpu::TextureView>>>,
pub samplers: Arc<RwLock<HashMap<RenderResource, wgpu::Sampler>>>,
pub resource_info: Arc<RwLock<HashMap<RenderResource, ResourceInfo>>>,
pub shader_modules: Arc<RwLock<HashMap<Handle<Shader>, wgpu::ShaderModule>>>,
pub render_pipelines: Arc<RwLock<HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>>>,
pub bind_groups: Arc<RwLock<HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>>>,
pub bind_group_layouts: Arc<RwLock<HashMap<BindGroupDescriptorId, wgpu::BindGroupLayout>>>,
}
impl WgpuResources {
pub fn consume(&mut self, wgpu_resources: WgpuResources) {
// TODO: this is brittle. consider a single change-stream-based approach instead?
self.asset_resources.consume(wgpu_resources.asset_resources);
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);
pub fn read(&self) -> WgpuResourcesReadLock {
WgpuResourcesReadLock {
buffers: self.buffers.read().unwrap(),
textures: self.textures.read().unwrap(),
}
}
pub fn set_window_surface(&self, window_id: WindowId, surface: wgpu::Surface) {
self.window_surfaces
.write()
.unwrap()
.insert(window_id, surface);
}
pub fn set_window_surface(&mut self, window_id: WindowId, surface: wgpu::Surface) {
self.window_surfaces.insert(window_id, surface);
}
pub fn get_window_surface(&mut self, window_id: WindowId) -> Option<&wgpu::Surface> {
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();
pub fn next_swap_chain_texture(&self, window_id: WindowId) {
let mut swap_chain_outputs = self
.window_swap_chains
.write()
.unwrap();
let swap_chain_output = swap_chain_outputs
.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)
self.swap_chain_outputs
.write()
.unwrap()
.insert(window_id, next_texture);
}
pub fn remove_swap_chain_texture(&mut self, window_id: WindowId) {
self.swap_chain_outputs.remove(&window_id);
pub fn remove_swap_chain_texture(&self, window_id: WindowId) {
self.swap_chain_outputs.write().unwrap().remove(&window_id);
}
pub fn remove_all_swap_chain_textures(&mut self) {
self.swap_chain_outputs.clear();
pub fn remove_all_swap_chain_textures(&self) {
self.swap_chain_outputs.write().unwrap().clear();
}
pub fn create_window_swap_chain(&mut self, device: &wgpu::Device, window: &Window) {
pub fn create_window_swap_chain(&self, device: &wgpu::Device, window: &Window) {
let swap_chain_descriptor: wgpu::SwapChainDescriptor = window.wgpu_into();
let surface = self
.window_surfaces
let surfaces = self.window_surfaces.read().unwrap();
let surface = surfaces
.get(&window.id)
.expect("No surface found for window");
let swap_chain = device.create_swap_chain(surface, &swap_chain_descriptor);
self.window_swap_chains.insert(window.id, swap_chain);
self.window_swap_chains
.write()
.unwrap()
.insert(window.id, swap_chain);
}
pub fn add_resource_info(&mut self, resource: RenderResource, resource_info: ResourceInfo) {
self.resource_info.insert(resource, resource_info);
pub fn add_resource_info(&self, resource: RenderResource, resource_info: ResourceInfo) {
self.resource_info
.write()
.unwrap()
.insert(resource, resource_info);
}
pub fn get_bind_group(
@ -99,7 +105,12 @@ impl WgpuResources {
bind_group_descriptor_id: BindGroupDescriptorId,
render_resource_set_id: RenderResourceSetId,
) -> Option<&wgpu::BindGroup> {
if let Some(bind_group_info) = self.bind_groups.get(&bind_group_descriptor_id) {
if let Some(bind_group_info) = self
.bind_groups
.read()
.unwrap()
.get(&bind_group_descriptor_id)
{
bind_group_info.bind_groups.get(&render_resource_set_id)
} else {
None
@ -121,13 +132,16 @@ impl WgpuResources {
}
pub fn set_bind_group(
&mut self,
&self,
bind_group_descriptor_id: BindGroupDescriptorId,
render_resource_set_id: RenderResourceSetId,
bind_group: wgpu::BindGroup,
) {
let bind_group_info = self
let mut bind_groups = self
.bind_groups
.write()
.unwrap();
let bind_group_info = bind_groups
.entry(bind_group_descriptor_id)
.or_insert_with(|| WgpuBindGroupInfo::default());
bind_group_info
@ -135,11 +149,7 @@ impl WgpuResources {
.insert(render_resource_set_id, bind_group);
}
pub fn create_buffer(
&mut self,
device: &wgpu::Device,
buffer_info: BufferInfo,
) -> RenderResource {
pub fn create_buffer(&self, device: &wgpu::Device, buffer_info: BufferInfo) -> RenderResource {
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: None,
size: buffer_info.size as u64,
@ -149,12 +159,12 @@ impl WgpuResources {
let resource = RenderResource::new();
self.add_resource_info(resource, ResourceInfo::Buffer(buffer_info));
self.buffers.insert(resource, buffer);
self.buffers.write().unwrap().insert(resource, buffer);
resource
}
pub fn create_buffer_with_data(
&mut self,
&self,
device: &wgpu::Device,
mut buffer_info: BufferInfo,
data: &[u8],
@ -165,22 +175,18 @@ impl WgpuResources {
}
pub fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> {
self.resource_info.get(&resource)
self.resource_info.read().unwrap().get(&resource)
}
pub fn remove_buffer(&mut self, resource: RenderResource) {
self.buffers.remove(&resource);
self.resource_info.remove(&resource);
pub fn remove_buffer(&self, resource: RenderResource) {
self.buffers.write().unwrap().remove(&resource);
self.resource_info.write().unwrap().remove(&resource);
}
pub fn assign_buffer(
&mut self,
buffer: wgpu::Buffer,
buffer_info: BufferInfo,
) -> RenderResource {
pub fn assign_buffer(&self, buffer: wgpu::Buffer, buffer_info: BufferInfo) -> RenderResource {
let resource = RenderResource::new();
self.add_resource_info(resource, ResourceInfo::Buffer(buffer_info));
self.buffers.insert(resource, buffer);
self.buffers.write().unwrap().insert(resource, buffer);
resource
}
@ -200,23 +206,8 @@ impl WgpuResources {
mapped.finish()
}
pub fn begin_create_buffer_mapped_transactional_render_context(
buffer_info: &BufferInfo,
render_resources: &mut WgpuTransactionalRenderResourceContext,
setup_data: &mut dyn FnMut(&mut [u8], &mut dyn RenderResourceContext),
) -> wgpu::Buffer {
let device = render_resources.device.clone();
let mut mapped = device.create_buffer_mapped(&wgpu::BufferDescriptor {
size: buffer_info.size as u64,
usage: buffer_info.buffer_usage.wgpu_into(),
label: None,
});
setup_data(&mut mapped.data, render_resources);
mapped.finish()
}
pub fn copy_buffer_to_buffer(
&mut self,
&self,
encoder: &mut wgpu::CommandEncoder,
source_buffer: RenderResource,
source_offset: u64,
@ -224,36 +215,40 @@ impl WgpuResources {
destination_offset: u64,
size: u64,
) {
let source = self.buffers.get(&source_buffer).unwrap();
let destination = self.buffers.get(&destination_buffer).unwrap();
let buffers = self.buffers.read().unwrap();
let source = buffers.get(&source_buffer).unwrap();
let destination = buffers.get(&destination_buffer).unwrap();
encoder.copy_buffer_to_buffer(source, source_offset, destination, destination_offset, size);
}
pub fn create_shader_module(
&mut self,
&self,
device: &wgpu::Device,
shader_handle: Handle<Shader>,
shader: &Shader,
) {
let shader_module = device.create_shader_module(&shader.get_spirv(None));
self.shader_modules.insert(shader_handle, shader_module);
self.shader_modules
.write()
.unwrap()
.insert(shader_handle, shader_module);
}
pub fn create_sampler(
&mut self,
&self,
device: &wgpu::Device,
sampler_descriptor: &SamplerDescriptor,
) -> RenderResource {
let descriptor: wgpu::SamplerDescriptor = (*sampler_descriptor).wgpu_into();
let sampler = device.create_sampler(&descriptor);
let resource = RenderResource::new();
self.samplers.insert(resource, sampler);
self.samplers.write().unwrap().insert(resource, sampler);
self.add_resource_info(resource, ResourceInfo::Sampler);
resource
}
pub fn create_texture(
&mut self,
&self,
device: &wgpu::Device,
texture_descriptor: &TextureDescriptor,
) -> RenderResource {
@ -262,12 +257,15 @@ impl WgpuResources {
let texture_view = texture.create_default_view();
let resource = RenderResource::new();
self.add_resource_info(resource, ResourceInfo::Texture);
self.textures.insert(resource, texture_view);
self.textures
.write()
.unwrap()
.insert(resource, texture_view);
resource
}
pub fn create_texture_with_data(
&mut self,
&self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
texture_descriptor: &TextureDescriptor,
@ -295,18 +293,21 @@ impl WgpuResources {
let resource = RenderResource::new();
self.add_resource_info(resource, ResourceInfo::Texture);
self.textures.insert(resource, texture_view);
self.textures
.write()
.unwrap()
.insert(resource, texture_view);
resource
}
pub fn remove_texture(&mut self, resource: RenderResource) {
self.textures.remove(&resource);
self.resource_info.remove(&resource);
pub fn remove_texture(&self, resource: RenderResource) {
self.textures.write().unwrap().remove(&resource);
self.resource_info.write().unwrap().remove(&resource);
}
pub fn remove_sampler(&mut self, resource: RenderResource) {
self.samplers.remove(&resource);
self.resource_info.remove(&resource);
pub fn remove_sampler(&self, resource: RenderResource) {
self.samplers.write().unwrap().remove(&resource);
self.resource_info.write().unwrap().remove(&resource);
}
pub fn get_render_resources(&self) -> &AssetResources {
@ -318,13 +319,15 @@ impl WgpuResources {
}
pub fn create_bind_group_layout(
&mut self,
&self,
device: &wgpu::Device,
bind_group_id: BindGroupDescriptorId,
descriptor: &wgpu::BindGroupLayoutDescriptor,
) {
let wgpu_bind_group_layout = device.create_bind_group_layout(descriptor);
self.bind_group_layouts
.write()
.unwrap()
.insert(bind_group_id, wgpu_bind_group_layout);
}
@ -337,11 +340,13 @@ impl WgpuResources {
}
pub fn set_render_pipeline(
&mut self,
&self,
pipeline_handle: Handle<PipelineDescriptor>,
render_pipeline: wgpu::RenderPipeline,
) {
self.render_pipelines
.write()
.unwrap()
.insert(pipeline_handle, render_pipeline);
}
}