RwLock WgpuResources works now!

This commit is contained in:
Carter Anderson 2020-04-15 11:42:56 -07:00
parent b53f198b99
commit 318b7dee1a
15 changed files with 325 additions and 268 deletions

8
.vscode/launch.json vendored
View file

@ -4,6 +4,7 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
@ -30,11 +31,11 @@
"cargo": {
"args": [
"build",
"--example=simple_new",
"--example=scene",
"--package=bevy"
],
"filter": {
"name": "simple_new",
"name": "scene",
"kind": "example"
}
},
@ -48,9 +49,8 @@
"cargo": {
"args": [
"run",
"--example=simple_new",
"--example=scene",
"--package=bevy",
"--release"
],
"filter": {
"name": "simple_new",

View file

@ -58,15 +58,15 @@ impl DrawTarget for AssignedMeshesDrawTarget {
{
let index_buffer_resource =
render_resources.get_mesh_indices_resource(mesh).unwrap();
match render_resources
.get_resource_info(index_buffer_resource)
.unwrap()
{
ResourceInfo::Buffer(buffer_info) => {
current_mesh_index_len = (buffer_info.size / 2) as u32
}
_ => panic!("expected a buffer type"),
}
render_resources.get_resource_info(
index_buffer_resource,
&mut |resource_info| match resource_info {
Some(ResourceInfo::Buffer(buffer_info)) => {
current_mesh_index_len = (buffer_info.size / 2) as u32
}
_ => panic!("expected a buffer type"),
},
);
render_pass.set_index_buffer(index_buffer_resource, 0);
render_pass.set_vertex_buffer(0, vertex_buffer_resource, 0);
}
@ -75,7 +75,10 @@ impl DrawTarget for AssignedMeshesDrawTarget {
}
// TODO: validate bind group properties against shader uniform properties at least once
render_pass.set_render_resources(pipeline_descriptor, &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);
}
}

View file

@ -37,15 +37,14 @@ impl DrawTarget for MeshesDrawTarget {
{
let index_buffer_resource =
render_resources.get_mesh_indices_resource(*mesh).unwrap();
match render_resources
.get_resource_info(index_buffer_resource)
.unwrap()
{
ResourceInfo::Buffer(buffer_info) => {
current_mesh_index_len = (buffer_info.size / 2) as u32
render_resources.get_resource_info(index_buffer_resource, &mut |resource_info| {
match resource_info {
Some(ResourceInfo::Buffer(buffer_info)) => {
current_mesh_index_len = (buffer_info.size / 2) as u32
}
_ => panic!("expected a buffer type"),
}
_ => panic!("expected a buffer type"),
}
});
render_pass.set_index_buffer(index_buffer_resource, 0);
render_pass.set_vertex_buffer(0, vertex_buffer_resource, 0);
}
@ -54,7 +53,8 @@ impl DrawTarget for MeshesDrawTarget {
}
// TODO: validate bind group properties against shader uniform properties at least once
render_pass.set_render_resources(pipeline_descriptor, &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);
}
}

View file

@ -40,18 +40,20 @@ impl DrawTarget for UiDrawTarget {
};
let index_count = {
let mut index_count = None;
let render_context = render_pass.get_render_context();
if let Some(ResourceInfo::Buffer(BufferInfo {
array_info: Some(array_info),
..
})) = render_context
render_context
.resources()
.get_resource_info(ui_instances_buffer)
{
Some(array_info.item_capacity)
} else {
None
}
.get_resource_info(ui_instances_buffer, &mut |resource_info| {
if let Some(ResourceInfo::Buffer(BufferInfo {
array_info: Some(array_info),
..
})) = resource_info
{
index_count = Some(array_info.item_capacity);
}
});
index_count
};
let global_render_resource_assignments =

View file

@ -60,18 +60,22 @@ impl PipelineCompiler {
for bind_group in layout.bind_groups.iter_mut() {
for binding in bind_group.bindings.iter_mut() {
if let Some(render_resource) = render_resource_assignments.get(&binding.name) {
if let Some(ResourceInfo::Buffer(BufferInfo { is_dynamic, .. })) =
render_context
.resources()
.get_resource_info(render_resource)
{
if let BindType::Uniform {
ref mut dynamic, ..
} = binding.bind_type
{
*dynamic = *is_dynamic
}
}
render_context.resources().get_resource_info(
render_resource,
&mut |resource_info| {
if let Some(ResourceInfo::Buffer(BufferInfo {
is_dynamic, ..
})) = resource_info
{
if let BindType::Uniform {
ref mut dynamic, ..
} = binding.bind_type
{
*dynamic = *is_dynamic
}
}
}
);
}
}
}

View file

@ -15,7 +15,7 @@ impl RenderResource {
// TODO: consider scoping breaking these mappings up by type: Texture, Sampler, etc
// the overlap could cause accidents.
#[derive(Default)]
#[derive(Default, Clone)]
pub struct AssetResources {
texture_to_resource: HashMap<Handle<Texture>, RenderResource>,
texture_to_sampler_resource: HashMap<Handle<Texture>, RenderResource>,

View file

@ -1,12 +1,12 @@
use crate::render_resource::BufferUsage;
#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct BufferArrayInfo {
pub item_size: usize,
pub item_capacity: usize,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct BufferInfo {
pub size: usize,
pub buffer_usage: BufferUsage,
@ -25,7 +25,7 @@ impl Default for BufferInfo {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum ResourceInfo {
Buffer(BufferInfo),
Texture,

View file

@ -281,23 +281,27 @@ where
self.uniform_buffer_status[i].as_mut().unwrap();
let (target_buffer, target_offset) = if self.use_dynamic_uniforms {
let buffer = uniform_buffer_status.buffer.unwrap();
if let Some(ResourceInfo::Buffer(BufferInfo {
array_info: Some(ref array_info),
is_dynamic: true,
..
})) = render_resources.get_resource_info(buffer)
{
let index = uniform_buffer_status
.get_or_assign_index(render_resource_assignments.id);
render_resource_assignments.set_indexed(
&field_info.uniform_name,
buffer,
(index * array_info.item_size) as u32,
);
(buffer, index * uniform_buffer_status.aligned_size)
} else {
panic!("Expected a dynamic uniform buffer");
}
let mut offset = 0;
render_resources.get_resource_info(buffer, &mut |resource_info| {
if let Some(ResourceInfo::Buffer(BufferInfo {
array_info: Some(ref array_info),
is_dynamic: true,
..
})) = resource_info
{
let index = uniform_buffer_status
.get_or_assign_index(render_resource_assignments.id);
render_resource_assignments.set_indexed(
&field_info.uniform_name,
buffer,
(index * array_info.item_size) as u32,
);
offset = index * uniform_buffer_status.aligned_size;
} else {
panic!("Expected a dynamic uniform buffer");
}
});
(buffer, offset)
} else {
let resource = match render_resource_assignments
.get(field_info.uniform_name)
@ -597,24 +601,31 @@ where
align: bool,
) {
let new_capacity = if let Some(buffer) = buffer_array_status.buffer {
if let Some(ResourceInfo::Buffer(BufferInfo {
array_info: Some(array_info),
..
})) = render_context.resources().get_resource_info(buffer)
{
if array_info.item_capacity < buffer_array_status.new_item_count {
// over capacity. lets resize
Some(
buffer_array_status.new_item_count + buffer_array_status.new_item_count / 2,
)
} else {
// under capacity. no change needed
None
}
} else {
// incorrect resource type. overwrite with new buffer
Some(buffer_array_status.new_item_count)
}
let mut new_capacity = None;
render_context
.resources()
.get_resource_info(buffer, &mut |resource_info| {
new_capacity = if let Some(ResourceInfo::Buffer(BufferInfo {
array_info: Some(array_info),
..
})) = resource_info
{
if array_info.item_capacity < buffer_array_status.new_item_count {
// over capacity. lets resize
Some(
buffer_array_status.new_item_count
+ buffer_array_status.new_item_count / 2,
)
} else {
// under capacity. no change needed
None
}
} else {
// incorrect resource type. overwrite with new buffer
Some(buffer_array_status.new_item_count)
};
});
new_capacity
} else {
// buffer does not exist. create it now.
Some(buffer_array_status.new_item_count)

View file

@ -9,7 +9,9 @@ use bevy_window::{Window, WindowId};
use std::any::Any;
pub struct GlobalRenderResourceContext {
pub context: Box<dyn RenderResourceContext + Send + Sync + 'static>,
pub context: Box<dyn Any + Send + Sync + 'static>,
// TODO: why doesn't this work?
// pub context: Box<dyn RenderResourceContext + Send + Sync + 'static>,
}
impl GlobalRenderResourceContext {
@ -53,7 +55,7 @@ pub trait RenderResourceContext: Any {
fn remove_buffer(&mut self, resource: RenderResource);
fn remove_texture(&mut self, resource: RenderResource);
fn remove_sampler(&mut self, resource: RenderResource);
fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo>;
fn get_resource_info(&self, resource: RenderResource, handle_info: &mut dyn FnMut(Option<&ResourceInfo>));
fn asset_resources(&self) -> &AssetResources;
fn asset_resources_mut(&mut self) -> &mut AssetResources;
fn get_texture_resource(&self, texture: Handle<Texture>) -> Option<RenderResource>;

View file

@ -30,37 +30,39 @@ pub fn render_resource_sets_system() -> Box<dyn Schedulable> {
_| {
// PERF: consider doing a par-iter over all renderable components so this can be parallelized
for handle in render_graph.pipeline_descriptors.iter() {
for compiled_pipeline_handle in
pipeline_compiler.iter_compiled_pipelines(*handle).unwrap()
if let Some(compiled_pipelines) =
pipeline_compiler.iter_compiled_pipelines(*handle)
{
if let Some(compiled_pipeline_assignments) = pipeline_assignments
.assignments
.get(compiled_pipeline_handle)
{
let compiled_pipeline =
pipelines.get(compiled_pipeline_handle).unwrap();
let pipeline_layout = compiled_pipeline.get_layout().unwrap();
for bind_group in pipeline_layout.bind_groups.iter() {
global_render_resource_assignments
.update_render_resource_set_id(bind_group);
}
for assignment_id in compiled_pipeline_assignments.iter() {
let entity = entity_render_resource_assignments
.get(*assignment_id)
.unwrap();
let mut renderable =
world.get_component_mut::<Renderable>(*entity).unwrap();
if !renderable.is_visible || renderable.is_instanced {
continue;
}
for compiled_pipeline_handle in compiled_pipelines {
if let Some(compiled_pipeline_assignments) = pipeline_assignments
.assignments
.get(compiled_pipeline_handle)
{
let compiled_pipeline =
pipelines.get(compiled_pipeline_handle).unwrap();
let pipeline_layout = compiled_pipeline.get_layout().unwrap();
for bind_group in pipeline_layout.bind_groups.iter() {
renderable
.render_resource_assignments
global_render_resource_assignments
.update_render_resource_set_id(bind_group);
// TODO: also setup bind groups here if possible
}
for assignment_id in compiled_pipeline_assignments.iter() {
let entity = entity_render_resource_assignments
.get(*assignment_id)
.unwrap();
let mut renderable =
world.get_component_mut::<Renderable>(*entity).unwrap();
if !renderable.is_visible || renderable.is_instanced {
continue;
}
for bind_group in pipeline_layout.bind_groups.iter() {
renderable
.render_resource_assignments
.update_render_resource_set_id(bind_group);
// TODO: also setup bind groups here if possible
}
}
}
}

View file

@ -1,7 +1,7 @@
use super::WgpuRenderResourceContext;
use crate::{
wgpu_type_converter::{OwnedWgpuVertexBufferDescriptor, WgpuInto},
WgpuRenderPass,
WgpuRenderPass, WgpuResourceRefs,
};
use bevy_asset::{AssetStorage, Handle};
use bevy_render::{
@ -127,10 +127,10 @@ impl RenderContext for WgpuRenderContext {
if let Some((render_resource_set_id, _indices)) =
render_resource_assignments.get_render_resource_set_id(bind_group_descriptor.id)
{
if let None = self
if !self
.render_resources
.wgpu_resources
.get_bind_group(bind_group_descriptor.id, *render_resource_set_id)
.has_bind_group(bind_group_descriptor.id, *render_resource_set_id)
{
log::trace!(
"start creating bind group for RenderResourceSet {:?}",
@ -155,48 +155,54 @@ impl RenderContext for WgpuRenderContext {
.iter()
.map(|binding| {
if let Some(resource) = render_resource_assignments.get(&binding.name) {
let resource_info =
self.resources().get_resource_info(resource).unwrap();
log::trace!(
"found binding {} ({}) resource: {:?} {:?}",
binding.index,
binding.name,
let mut wgpu_resource = None;
self.resources().get_resource_info(
resource,
resource_info
&mut |resource_info| {
log::trace!(
"found binding {} ({}) resource: {:?} {:?}",
binding.index,
binding.name,
resource,
resource_info
);
wgpu_resource = match &binding.bind_type {
BindType::SampledTexture { .. } => {
if let Some(ResourceInfo::Texture) = resource_info {
let texture = textures.get(&resource).unwrap();
Some(wgpu::BindingResource::TextureView(texture))
} else {
panic!("expected a Texture resource");
}
}
BindType::Sampler { .. } => {
if let Some(ResourceInfo::Sampler) = resource_info {
let sampler = samplers.get(&resource).unwrap();
Some(wgpu::BindingResource::Sampler(sampler))
} else {
panic!("expected a Sampler resource");
}
}
BindType::Uniform { .. } => {
if let Some(ResourceInfo::Buffer(buffer_info)) =
resource_info
{
let buffer = buffers.get(&resource).unwrap();
Some(wgpu::BindingResource::Buffer {
buffer,
range: 0..buffer_info.size as u64,
})
} else {
panic!("expected a Buffer resource");
}
}
_ => panic!("unsupported bind type"),
}
},
);
wgpu::Binding {
binding: binding.index,
resource: match &binding.bind_type {
BindType::SampledTexture { .. } => {
if let ResourceInfo::Texture = resource_info {
let texture = textures.get(&resource).unwrap();
wgpu::BindingResource::TextureView(texture)
} else {
panic!("expected a Texture resource");
}
}
BindType::Sampler { .. } => {
if let ResourceInfo::Sampler = resource_info {
let sampler = samplers.get(&resource).unwrap();
wgpu::BindingResource::Sampler(sampler)
} else {
panic!("expected a Sampler resource");
}
}
BindType::Uniform { .. } => {
if let ResourceInfo::Buffer(buffer_info) = resource_info
{
let buffer = buffers.get(&resource).unwrap();
wgpu::BindingResource::Buffer {
buffer,
range: 0..buffer_info.size as u64,
}
} else {
panic!("expected a Buffer resource");
}
}
_ => panic!("unsupported bind type"),
},
resource: wgpu_resource.expect("No resource binding found"),
}
} else {
panic!(
@ -256,13 +262,13 @@ impl RenderContext for WgpuRenderContext {
let layout = pipeline_descriptor.get_layout().unwrap();
for bind_group in layout.bind_groups.iter() {
if let None = self
if self
.render_resources
.wgpu_resources
.bind_group_layouts
.read()
.unwrap()
.get(&bind_group.id)
.get(&bind_group.id).is_none()
{
let bind_group_layout_binding = bind_group
.bindings
@ -412,18 +418,21 @@ impl RenderContext for WgpuRenderContext {
if !self.command_encoder.is_some() {
self.command_encoder.create(&self.device);
}
let resource_lock = self.render_resources.wgpu_resources.read();
let refs = resource_lock.refs();
let mut encoder = self.command_encoder.take().unwrap();
{
let render_pass = create_render_pass(
self,
pass_descriptor,
render_resource_assignments,
&refs,
&mut encoder,
);
let mut wgpu_render_pass = WgpuRenderPass {
render_context: self,
render_pass,
render_resources: refs,
bound_bind_groups: HashMap::default(),
};
@ -438,6 +447,7 @@ pub fn create_render_pass<'a, 'b>(
render_context: &'a WgpuRenderContext,
pass_descriptor: &PassDescriptor,
global_render_resource_assignments: &'b RenderResourceAssignments,
refs: &WgpuResourceRefs<'a>,
encoder: &'a mut wgpu::CommandEncoder,
) -> wgpu::RenderPass<'a> {
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
@ -448,6 +458,7 @@ pub fn create_render_pass<'a, 'b>(
create_wgpu_color_attachment_descriptor(
render_context,
global_render_resource_assignments,
refs,
c,
)
})
@ -456,6 +467,7 @@ pub fn create_render_pass<'a, 'b>(
create_wgpu_depth_stencil_attachment_descriptor(
render_context,
global_render_resource_assignments,
refs,
d,
)
}),
@ -465,16 +477,13 @@ pub fn create_render_pass<'a, 'b>(
fn get_texture_view<'a>(
render_context: &'a WgpuRenderContext,
global_render_resource_assignments: &RenderResourceAssignments,
refs: &WgpuResourceRefs<'a>,
name: &str,
) -> &'a wgpu::TextureView {
match name {
resource_name::texture::SWAP_CHAIN => {
if let Some(primary_swap_chain) = render_context
.render_resources
.wgpu_resources
if let Some(primary_swap_chain) = refs
.swap_chain_outputs
.read()
.unwrap()
.get(render_context.primary_window.as_ref().unwrap())
.map(|output| &output.view)
{
@ -484,14 +493,7 @@ fn get_texture_view<'a>(
}
}
_ => match global_render_resource_assignments.get(name) {
Some(resource) => render_context
.render_resources
.wgpu_resources
.textures
.read()
.unwrap()
.get(&resource)
.unwrap(),
Some(resource) => refs.textures.get(&resource).unwrap(),
None => {
// if let Some(swap_chain_output) = swap_chain_outputs.get(name) {
// &swap_chain_output.view
@ -506,11 +508,13 @@ fn get_texture_view<'a>(
fn create_wgpu_color_attachment_descriptor<'a>(
render_context: &'a WgpuRenderContext,
global_render_resource_assignments: &RenderResourceAssignments,
refs: &WgpuResourceRefs<'a>,
color_attachment_descriptor: &RenderPassColorAttachmentDescriptor,
) -> wgpu::RenderPassColorAttachmentDescriptor<'a> {
let attachment = get_texture_view(
render_context,
global_render_resource_assignments,
refs,
color_attachment_descriptor.attachment.as_str(),
);
@ -521,6 +525,7 @@ fn create_wgpu_color_attachment_descriptor<'a>(
get_texture_view(
render_context,
global_render_resource_assignments,
refs,
target.as_str(),
)
});
@ -537,11 +542,13 @@ fn create_wgpu_color_attachment_descriptor<'a>(
fn create_wgpu_depth_stencil_attachment_descriptor<'a>(
render_context: &'a WgpuRenderContext,
global_render_resource_assignments: &RenderResourceAssignments,
refs: &WgpuResourceRefs<'a>,
depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor,
) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> {
let attachment = get_texture_view(
render_context,
global_render_resource_assignments,
refs,
depth_stencil_attachment_descriptor.attachment.as_str(),
);

View file

@ -16,7 +16,7 @@ use bevy_window::{WindowId, Window};
#[derive(Clone)]
pub struct WgpuRenderResourceContext {
pub device: Arc<wgpu::Device>,
pub wgpu_resources: Arc<WgpuResources>,
pub wgpu_resources: WgpuResources,
}
@ -24,7 +24,7 @@ impl WgpuRenderResourceContext {
pub fn new(device: Arc<wgpu::Device>) -> Self {
WgpuRenderResourceContext {
device,
wgpu_resources: Arc::new(WgpuResources::default()),
wgpu_resources: WgpuResources::default(),
}
}
}
@ -95,8 +95,8 @@ impl RenderResourceContext for WgpuRenderResourceContext {
.get_mesh_indices_resource(mesh)
}
fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> {
self.wgpu_resources.get_resource_info(resource)
fn get_resource_info(&self, resource: RenderResource, handle_info: &mut dyn FnMut(Option<&ResourceInfo>)) {
self.wgpu_resources.get_resource_info(resource, handle_info);
}
fn asset_resources(&self) -> &AssetResources {

View file

@ -1,4 +1,4 @@
use crate::renderer_2::WgpuRenderContext;
use crate::{renderer_2::WgpuRenderContext, WgpuResourceRefs};
use bevy_asset::Handle;
use bevy_render::{
pass::RenderPass,
@ -13,6 +13,7 @@ use std::{collections::HashMap, ops::Range};
pub struct WgpuRenderPass<'a> {
pub render_pass: wgpu::RenderPass<'a>,
pub render_context: &'a WgpuRenderContext,
pub render_resources: WgpuResourceRefs<'a>,
pub bound_bind_groups: HashMap<u32, RenderResourceSetId>,
}
@ -22,27 +23,21 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
}
fn set_vertex_buffer(&mut self, start_slot: u32, resource: RenderResource, offset: u64) {
let buffers = self
.render_context
let buffer = self
.render_resources
.wgpu_resources
.buffers
.read()
.get(&resource)
.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 buffers = self
.render_context
let buffer = self
.render_resources
.wgpu_resources
.buffers
.read()
.get(&resource)
.unwrap();
let buffer = buffers.get(&resource).unwrap();
self.render_pass.set_index_buffer(&buffer, offset, 0);
}
@ -80,17 +75,15 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
index_buffer
);
self.set_index_buffer(index_buffer, 0);
match self
.render_context
.resources()
.get_resource_info(index_buffer)
.unwrap()
{
ResourceInfo::Buffer(buffer_info) => {
indices = Some(0..(buffer_info.size / 2) as u32)
}
_ => panic!("expected a buffer type"),
}
self.render_context.resources().get_resource_info(
index_buffer,
&mut |resource_info| match resource_info {
Some(ResourceInfo::Buffer(buffer_info)) => {
indices = Some(0..(buffer_info.size / 2) as u32)
}
_ => panic!("expected a buffer type"),
},
);
}
}
}
@ -99,50 +92,53 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
if let Some((render_resource_set_id, dynamic_uniform_indices)) =
render_resource_assignments.get_render_resource_set_id(bind_group.id)
{
if let Some(wgpu_bind_group) = self
.render_context
if let Some(bind_group_info) = self
.render_resources
.wgpu_resources
.get_bind_group(bind_group.id, *render_resource_set_id)
.bind_groups
.get(&bind_group.id)
{
const EMPTY: &'static [u32] = &[];
let dynamic_uniform_indices =
if let Some(dynamic_uniform_indices) = dynamic_uniform_indices {
dynamic_uniform_indices.as_slice()
} else {
EMPTY
};
// don't bind bind groups if they are already set
// TODO: these checks come at a performance cost. make sure its worth it!
if let Some(bound_render_resource_set) =
self.bound_bind_groups.get(&bind_group.index)
if let Some(wgpu_bind_group) =
bind_group_info.bind_groups.get(render_resource_set_id)
{
if *bound_render_resource_set == *render_resource_set_id
&& dynamic_uniform_indices.len() == 0
const EMPTY: &'static [u32] = &[];
let dynamic_uniform_indices =
if let Some(dynamic_uniform_indices) = dynamic_uniform_indices {
dynamic_uniform_indices.as_slice()
} else {
EMPTY
};
// don't bind bind groups if they are already set
// TODO: these checks come at a performance cost. make sure its worth it!
if let Some(bound_render_resource_set) =
self.bound_bind_groups.get(&bind_group.index)
{
continue;
if *bound_render_resource_set == *render_resource_set_id
&& dynamic_uniform_indices.len() == 0
{
continue;
}
}
}
if dynamic_uniform_indices.len() == 0 {
self.bound_bind_groups
.insert(bind_group.index, *render_resource_set_id);
} else {
self.bound_bind_groups.remove(&bind_group.index);
}
if dynamic_uniform_indices.len() == 0 {
self.bound_bind_groups
.insert(bind_group.index, *render_resource_set_id);
} else {
self.bound_bind_groups.remove(&bind_group.index);
}
log::trace!(
"set bind group {} {:?}: {:?}",
bind_group.index,
dynamic_uniform_indices,
render_resource_set_id
);
self.render_pass.set_bind_group(
bind_group.index,
&wgpu_bind_group,
dynamic_uniform_indices,
);
log::trace!(
"set bind group {} {:?}: {:?}",
bind_group.index,
dynamic_uniform_indices,
render_resource_set_id
);
self.render_pass.set_bind_group(
bind_group.index,
wgpu_bind_group,
dynamic_uniform_indices,
);
}
};
}
}
@ -150,14 +146,7 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
indices
}
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(
let pipeline = self.render_resources.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

@ -11,7 +11,7 @@ use bevy_render::{
};
use bevy_window::{WindowCreated, WindowResized, Windows};
use legion::prelude::*;
use std::{any::Any, collections::HashSet, ops::Deref, sync::Arc};
use std::{collections::HashSet, ops::Deref, sync::Arc};
pub struct WgpuRenderer {
pub device: Arc<wgpu::Device>,
@ -131,7 +131,6 @@ impl WgpuRenderer {
for resource_provider_chunk in render_graph.resource_providers.chunks_mut(chunk_size) {
// TODO: try to unify this Device usage
let device = self.device.clone();
let resource_device = device.clone();
// let sender = sender.clone();
// s.spawn(|_| {
// TODO: replace WgpuResources with Global+Local resources
@ -241,17 +240,11 @@ impl WgpuRenderer {
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
let render_resource_context = global_context
.context
.downcast_mut::<WgpuRenderResourceContext>()
.unwrap();
panic!("ahh");
// 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);
@ -266,11 +259,7 @@ impl WgpuRenderer {
self.intialized = true;
}
self.update_resource_providers(
world,
resources,
render_resource_context,
);
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);
@ -280,10 +269,8 @@ impl WgpuRenderer {
// 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
let render_resource_context = global_context
.context
.downcast_mut::<WgpuRenderResourceContext>()
.unwrap();
let mut render_context =

View file

@ -20,12 +20,56 @@ pub struct WgpuBindGroupInfo {
pub bind_groups: HashMap<RenderResourceSetId, wgpu::BindGroup>,
}
/// Grabs a read lock on all wgpu resources. When paired with WgpuResourceRefs, this allows
/// us to pass in wgpu resources to wgpu::RenderPass<'a> with the appropriate lifetime. This is accomplished by
/// grabbing a WgpuResourcesReadLock _before_ creating a wgpu::RenderPass, getting a WgpuResourcesRefs, and storing that
/// in the pass.
///
/// This is only a problem because RwLockReadGuard.read() erases the guard's lifetime and creates a new anonymous lifetime. If
/// you call RwLockReadGuard.read() during a pass, the reference will have an anonymous lifetime that lives for less than the
/// pass.
///
/// The biggest implication of this design (other than the additional boilerplate here) is that beginning a render pass
/// blocks writes to these resources. This means that if the pass attempts to write any resource, a deadlock will occur. It also means
/// that other threads attempting to write resources will need to wait for pass encoding to finish. Almost all writes should occur before
/// passes start, so this hopefully won't be a problem.
///
/// It is worth comparing the performance of this to transactional / copy-based approach. This design lock based design guarantees
/// consistency, doesn't perform redundant allocations, and only blocks when a write is occurring. A copy based approach would
/// never block, but would require more allocations / state-synchronization, which I expect will be more expensive.
///
/// Single threaded implementations don't need to worry about these lifetimes constraints at all. RenderPasses can use a RenderContext's
/// WgpuResources directly. RenderContext already has a lifetime greater than the RenderPass.
pub struct WgpuResourcesReadLock<'a> {
pub buffers: RwLockReadGuard<'a, HashMap<RenderResource, wgpu::Buffer>>,
pub textures: RwLockReadGuard<'a, HashMap<RenderResource, wgpu::TextureView>>,
pub swap_chain_outputs: RwLockReadGuard<'a, HashMap<WindowId, wgpu::SwapChainOutput>>,
pub render_pipelines: RwLockReadGuard<'a, HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>>,
pub bind_groups: RwLockReadGuard<'a, HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>>,
}
#[derive(Default)]
impl<'a> WgpuResourcesReadLock<'a> {
pub fn refs(&'a self) -> WgpuResourceRefs<'a> {
WgpuResourceRefs {
buffers: &self.buffers,
textures: &self.textures,
swap_chain_outputs: &self.swap_chain_outputs,
render_pipelines: &self.render_pipelines,
bind_groups: &self.bind_groups,
}
}
}
/// Stores read only references to WgpuResource collections. See WgpuResourcesReadLock docs for context on why this exists
pub struct WgpuResourceRefs<'a> {
pub buffers: &'a HashMap<RenderResource, wgpu::Buffer>,
pub textures: &'a HashMap<RenderResource, wgpu::TextureView>,
pub swap_chain_outputs: &'a HashMap<WindowId, wgpu::SwapChainOutput>,
pub render_pipelines: &'a HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
pub bind_groups: &'a HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>,
}
#[derive(Default, Clone)]
pub struct WgpuResources {
// TODO: remove this from WgpuResources. it doesn't need to be here
pub asset_resources: AssetResources,
@ -43,10 +87,13 @@ pub struct WgpuResources {
}
impl WgpuResources {
pub fn read(&self) -> WgpuResourcesReadLock {
pub fn read<'a>(&'a self) -> WgpuResourcesReadLock<'a> {
WgpuResourcesReadLock {
buffers: self.buffers.read().unwrap(),
textures: self.textures.read().unwrap(),
swap_chain_outputs: self.swap_chain_outputs.read().unwrap(),
render_pipelines: self.render_pipelines.read().unwrap(),
bind_groups: self.bind_groups.read().unwrap(),
}
}
@ -100,20 +147,20 @@ impl WgpuResources {
.insert(resource, resource_info);
}
pub fn get_bind_group(
pub fn has_bind_group(
&self,
bind_group_descriptor_id: BindGroupDescriptorId,
render_resource_set_id: RenderResourceSetId,
) -> Option<&wgpu::BindGroup> {
) -> bool {
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)
bind_group_info.bind_groups.get(&render_resource_set_id).is_some()
} else {
None
false
}
}
@ -174,8 +221,11 @@ impl WgpuResources {
self.assign_buffer(buffer, buffer_info)
}
pub fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo> {
self.resource_info.read().unwrap().get(&resource)
// TODO: taking a closure isn't fantastic. is there any way to make this better without exposing the lock in the interface?
pub fn get_resource_info(&self, resource: RenderResource, handle_info: &mut dyn FnMut(Option<&ResourceInfo>)) {
let resource_info = self.resource_info.read().unwrap();
let info = resource_info.get(&resource);
handle_info(info);
}
pub fn remove_buffer(&self, resource: RenderResource) {