mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 06:30:19 +00:00
RwLock WgpuResources works now!
This commit is contained in:
parent
b53f198b99
commit
318b7dee1a
15 changed files with 325 additions and 268 deletions
8
.vscode/launch.json
vendored
8
.vscode/launch.json
vendored
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue