mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 06:30:19 +00:00
Initial RenderGraph2. Port CameraResourceProvider
This commit is contained in:
parent
3c83e34cc1
commit
210a50e781
5 changed files with 284 additions and 147 deletions
|
@ -54,7 +54,8 @@ use bevy_app::{stage, AppBuilder, AppPlugin, GetEventReader};
|
|||
use bevy_asset::AssetStorage;
|
||||
use bevy_transform::prelude::LocalToWorld;
|
||||
use bevy_window::WindowResized;
|
||||
use render_resource::resource_providers::mesh_resource_provider_system;
|
||||
use render_resource::resource_providers::{CameraNode, mesh_resource_provider_system};
|
||||
use render_graph_2::RenderGraph2;
|
||||
|
||||
pub static RENDER_RESOURCE_STAGE: &str = "render_resource";
|
||||
pub static RENDER_STAGE: &str = "render";
|
||||
|
@ -77,9 +78,6 @@ impl RenderPlugin {
|
|||
.add_draw_target(AssignedBatchesDrawTarget::default())
|
||||
.add_draw_target(AssignedMeshesDrawTarget::default())
|
||||
.add_draw_target(UiDrawTarget::default())
|
||||
.add_resource_provider(CameraResourceProvider::new(
|
||||
app.resources().get_event_reader::<WindowResized>(),
|
||||
))
|
||||
.add_resource_provider(Camera2dResourceProvider::new(
|
||||
resources.get_event_reader::<WindowResized>(),
|
||||
))
|
||||
|
@ -93,21 +91,24 @@ impl RenderPlugin {
|
|||
|
||||
impl AppPlugin for RenderPlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
let mut render_graph = RenderGraph2::default();
|
||||
render_graph.add_system_node(CameraNode::default(), app.resources_mut());
|
||||
let mut asset_batchers = AssetBatchers::default();
|
||||
asset_batchers.batch_types2::<Mesh, StandardMaterial>();
|
||||
app.add_stage_after(stage::POST_UPDATE, RENDER_RESOURCE_STAGE)
|
||||
.add_stage_after(RENDER_RESOURCE_STAGE, RENDER_STAGE)
|
||||
// resources
|
||||
.add_resource(RenderGraph::default())
|
||||
.add_resource(render_graph)
|
||||
.add_resource(AssetStorage::<Mesh>::new())
|
||||
.add_resource(AssetStorage::<Texture>::new())
|
||||
.add_resource(AssetStorage::<Shader>::new())
|
||||
.add_resource(AssetStorage::<StandardMaterial>::new())
|
||||
.add_resource(AssetStorage::<PipelineDescriptor>::new())
|
||||
.add_resource(PipelineAssignments::new())
|
||||
.add_resource(VertexBufferDescriptors::default())
|
||||
.add_resource(PipelineCompiler::new())
|
||||
.add_resource(RenderResourceAssignments::default())
|
||||
.add_resource(VertexBufferDescriptors::default())
|
||||
.add_resource(EntityRenderResourceAssignments::default())
|
||||
.add_resource(asset_batchers)
|
||||
// core systems
|
||||
|
|
|
@ -1 +1,159 @@
|
|||
use crate::{
|
||||
render_resource::{RenderResource, ResourceInfo},
|
||||
renderer_2::RenderContext,
|
||||
};
|
||||
use legion::prelude::{Executor, Resources, Schedulable, World};
|
||||
use std::{
|
||||
collections::{HashMap, VecDeque},
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub enum Command {
|
||||
CopyBufferToBuffer {
|
||||
source_buffer: RenderResource,
|
||||
source_offset: u64,
|
||||
destination_buffer: RenderResource,
|
||||
destination_offset: u64,
|
||||
size: u64,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct CommandQueue {
|
||||
queue: Arc<Mutex<VecDeque<Command>>>,
|
||||
}
|
||||
|
||||
impl CommandQueue {
|
||||
fn push(&mut self, command: Command) {
|
||||
self.queue.lock().unwrap().push_front(command);
|
||||
}
|
||||
|
||||
pub fn copy_buffer_to_buffer(
|
||||
&mut self,
|
||||
source_buffer: RenderResource,
|
||||
source_offset: u64,
|
||||
destination_buffer: RenderResource,
|
||||
destination_offset: u64,
|
||||
size: u64,
|
||||
) {
|
||||
self.push(Command::CopyBufferToBuffer {
|
||||
source_buffer,
|
||||
source_offset,
|
||||
destination_buffer,
|
||||
destination_offset,
|
||||
size,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn execute(&mut self, render_context: &mut dyn RenderContext) {
|
||||
for command in self.queue.lock().unwrap().drain(..) {
|
||||
match command {
|
||||
Command::CopyBufferToBuffer {
|
||||
source_buffer,
|
||||
source_offset,
|
||||
destination_buffer,
|
||||
destination_offset,
|
||||
size,
|
||||
} => render_context.copy_buffer_to_buffer(
|
||||
source_buffer,
|
||||
source_offset,
|
||||
destination_buffer,
|
||||
destination_offset,
|
||||
size,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct NodeId(Uuid);
|
||||
|
||||
impl NodeId {
|
||||
fn new() -> Self {
|
||||
NodeId(Uuid::new_v4())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ResourceSlot {
|
||||
name: Option<String>,
|
||||
resource_type: ResourceInfo,
|
||||
}
|
||||
|
||||
pub struct ResourceSlotBinding {
|
||||
resource: RenderResource,
|
||||
}
|
||||
|
||||
pub struct NodeDescriptor {
|
||||
pub inputs: Vec<ResourceSlot>,
|
||||
pub outputs: Vec<ResourceSlot>,
|
||||
}
|
||||
|
||||
pub trait Node: Send + Sync + 'static {
|
||||
fn descriptor(&self) -> &NodeDescriptor;
|
||||
fn update(
|
||||
&mut self,
|
||||
world: &World,
|
||||
resources: &Resources,
|
||||
render_context: &mut dyn RenderContext,
|
||||
);
|
||||
}
|
||||
|
||||
pub trait SystemNode: Node {
|
||||
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RenderGraph2 {
|
||||
nodes: HashMap<NodeId, Box<dyn Node>>,
|
||||
new_systems: Vec<Box<dyn Schedulable>>,
|
||||
system_executor: Option<Executor>,
|
||||
}
|
||||
|
||||
impl RenderGraph2 {
|
||||
pub fn add_node<T>(&mut self, node: T) -> NodeId
|
||||
where
|
||||
T: Node + 'static,
|
||||
{
|
||||
let id = NodeId::new();
|
||||
self.nodes.insert(id, Box::new(node));
|
||||
id
|
||||
}
|
||||
|
||||
pub fn add_system_node<T>(&mut self, node: T, resources: &mut Resources) -> NodeId
|
||||
where
|
||||
T: SystemNode + 'static,
|
||||
{
|
||||
let id = NodeId::new();
|
||||
self.new_systems.push(node.get_system(resources));
|
||||
self.nodes.insert(id, Box::new(node));
|
||||
id
|
||||
}
|
||||
|
||||
pub fn get_schedule(&mut self) -> impl Iterator<Item = &mut Box<dyn Node>> {
|
||||
self.nodes.values_mut()
|
||||
}
|
||||
|
||||
pub fn take_executor(&mut self) -> Option<Executor> {
|
||||
// rebuild executor if there are new systems
|
||||
if self.new_systems.len() > 0 {
|
||||
let mut systems = self
|
||||
.system_executor
|
||||
.take()
|
||||
.map(|executor| executor.into_vec())
|
||||
.unwrap_or_else(|| Vec::new());
|
||||
for system in self.new_systems.drain(..) {
|
||||
systems.push(system);
|
||||
}
|
||||
|
||||
self.system_executor = Some(Executor::new(systems));
|
||||
}
|
||||
|
||||
self.system_executor.take()
|
||||
}
|
||||
|
||||
pub fn set_executor(&mut self, executor: Executor) {
|
||||
self.system_executor = Some(executor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,162 +1,107 @@
|
|||
use bevy_window::WindowResized;
|
||||
|
||||
use crate::{
|
||||
render_resource::{
|
||||
resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
|
||||
ResourceProvider,
|
||||
},
|
||||
render_graph_2::{CommandQueue, Node, NodeDescriptor, SystemNode},
|
||||
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResourceAssignments},
|
||||
renderer_2::{GlobalRenderResourceContext, RenderContext},
|
||||
ActiveCamera, Camera,
|
||||
};
|
||||
|
||||
use bevy_app::{EventReader, Events, GetEventReader};
|
||||
use bevy_app::{Events, GetEventReader};
|
||||
use bevy_transform::prelude::*;
|
||||
use legion::prelude::*;
|
||||
use once_cell::sync::Lazy;
|
||||
use zerocopy::AsBytes;
|
||||
|
||||
pub fn camera_resource_provider_system(resources: &mut Resources) -> Box<dyn Schedulable> {
|
||||
let mut camera_buffer = None;
|
||||
let mut tmp_buffer = None;
|
||||
let mut window_resized_event_reader = resources.get_event_reader::<WindowResized>();
|
||||
SystemBuilder::new("camera_resource_provider")
|
||||
.read_resource::<GlobalRenderResourceContext>()
|
||||
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
|
||||
.write_resource::<RenderResourceAssignments>()
|
||||
.read_resource::<Events<WindowResized>>()
|
||||
.with_query(<(Read<Camera>, Read<LocalToWorld>, Read<ActiveCamera>)>::query())
|
||||
.build(
|
||||
move |_,
|
||||
world,
|
||||
(
|
||||
render_resource_context,
|
||||
ref mut render_resource_assignments,
|
||||
window_resized_events,
|
||||
),
|
||||
query| {
|
||||
let render_resources = &render_resource_context.context;
|
||||
if camera_buffer.is_none() {
|
||||
let buffer = render_resources.create_buffer(BufferInfo {
|
||||
size: std::mem::size_of::<[[f32; 4]; 4]>(),
|
||||
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
|
||||
..Default::default()
|
||||
});
|
||||
render_resource_assignments.set(resource_name::uniform::CAMERA, buffer);
|
||||
camera_buffer = Some(buffer);
|
||||
}
|
||||
|
||||
let primary_window_resized_event = window_resized_events
|
||||
.find_latest(&mut window_resized_event_reader, |event| event.is_primary);
|
||||
if let Some(_) = primary_window_resized_event {
|
||||
let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>();
|
||||
for (camera, local_to_world, _) in query.iter(world) {
|
||||
let camera_matrix: [[f32; 4]; 4] =
|
||||
(camera.view_matrix * local_to_world.0).to_cols_array_2d();
|
||||
|
||||
if let Some(old_tmp_buffer) = tmp_buffer {
|
||||
render_resources.remove_buffer(old_tmp_buffer);
|
||||
}
|
||||
|
||||
tmp_buffer = Some(render_resources.create_buffer_mapped(
|
||||
BufferInfo {
|
||||
size: matrix_size,
|
||||
buffer_usage: BufferUsage::COPY_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
&mut |data, _renderer| {
|
||||
data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes());
|
||||
},
|
||||
));
|
||||
|
||||
// render_resources.copy_buffer_to_buffer(
|
||||
// tmp_buffer.unwrap(),
|
||||
// 0,
|
||||
// camera_buffer.unwrap(),
|
||||
// 0,
|
||||
// matrix_size as u64,
|
||||
// );
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
#[derive(Default)]
|
||||
pub struct CameraNode {
|
||||
command_queue: CommandQueue,
|
||||
}
|
||||
|
||||
pub struct CameraResourceProvider {
|
||||
pub camera_buffer: Option<RenderResource>,
|
||||
pub tmp_buffer: Option<RenderResource>,
|
||||
pub window_resized_event_reader: EventReader<WindowResized>,
|
||||
}
|
||||
|
||||
impl CameraResourceProvider {
|
||||
pub fn new(window_resized_event_reader: EventReader<WindowResized>) -> Self {
|
||||
CameraResourceProvider {
|
||||
camera_buffer: None,
|
||||
tmp_buffer: None,
|
||||
window_resized_event_reader,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceProvider for CameraResourceProvider {
|
||||
fn initialize(
|
||||
&mut self,
|
||||
render_context: &mut dyn RenderContext,
|
||||
_world: &mut World,
|
||||
resources: &Resources,
|
||||
) {
|
||||
let buffer = render_context.resources_mut().create_buffer(BufferInfo {
|
||||
size: std::mem::size_of::<[[f32; 4]; 4]>(),
|
||||
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
|
||||
..Default::default()
|
||||
impl Node for CameraNode {
|
||||
fn descriptor(&self) -> &NodeDescriptor {
|
||||
static DESCRIPTOR: Lazy<NodeDescriptor> = Lazy::new(|| NodeDescriptor {
|
||||
inputs: Vec::new(),
|
||||
outputs: Vec::new(),
|
||||
});
|
||||
|
||||
let mut render_resource_assignments =
|
||||
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||
render_resource_assignments.set(resource_name::uniform::CAMERA, buffer);
|
||||
self.camera_buffer = Some(buffer);
|
||||
&DESCRIPTOR
|
||||
}
|
||||
|
||||
fn update(
|
||||
&mut self,
|
||||
_world: &World,
|
||||
_resources: &Resources,
|
||||
render_context: &mut dyn RenderContext,
|
||||
world: &World,
|
||||
resources: &Resources,
|
||||
) {
|
||||
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
|
||||
let primary_window_resized_event = window_resized_events
|
||||
.find_latest(&mut self.window_resized_event_reader, |event| {
|
||||
event.is_primary
|
||||
});
|
||||
if let Some(_) = primary_window_resized_event {
|
||||
let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>();
|
||||
for (camera, local_to_world, _) in
|
||||
<(Read<Camera>, Read<LocalToWorld>, Read<ActiveCamera>)>::query().iter(world)
|
||||
{
|
||||
let camera_matrix: [[f32; 4]; 4] =
|
||||
(camera.view_matrix * local_to_world.0).to_cols_array_2d();
|
||||
|
||||
if let Some(old_tmp_buffer) = self.tmp_buffer {
|
||||
render_context.resources_mut().remove_buffer(old_tmp_buffer);
|
||||
}
|
||||
|
||||
self.tmp_buffer = Some(render_context.resources_mut().create_buffer_mapped(
|
||||
BufferInfo {
|
||||
size: matrix_size,
|
||||
buffer_usage: BufferUsage::COPY_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
&mut |data, _renderer| {
|
||||
data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes());
|
||||
},
|
||||
));
|
||||
|
||||
render_context.copy_buffer_to_buffer(
|
||||
self.tmp_buffer.unwrap(),
|
||||
0,
|
||||
self.camera_buffer.unwrap(),
|
||||
0,
|
||||
matrix_size as u64,
|
||||
);
|
||||
}
|
||||
}
|
||||
self.command_queue.execute(render_context);
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemNode for CameraNode {
|
||||
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable> {
|
||||
let mut camera_buffer = None;
|
||||
let mut tmp_buffer = None;
|
||||
let mut window_resized_event_reader = resources.get_event_reader::<WindowResized>();
|
||||
let mut command_queue = self.command_queue.clone();
|
||||
SystemBuilder::new("camera_resource_provider")
|
||||
.read_resource::<GlobalRenderResourceContext>()
|
||||
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
|
||||
.write_resource::<RenderResourceAssignments>()
|
||||
.read_resource::<Events<WindowResized>>()
|
||||
.with_query(<(Read<Camera>, Read<LocalToWorld>, Read<ActiveCamera>)>::query())
|
||||
.build(
|
||||
move |_,
|
||||
world,
|
||||
(
|
||||
render_resource_context,
|
||||
ref mut render_resource_assignments,
|
||||
window_resized_events,
|
||||
),
|
||||
query| {
|
||||
let render_resources = &render_resource_context.context;
|
||||
if camera_buffer.is_none() {
|
||||
let buffer = render_resources.create_buffer(BufferInfo {
|
||||
size: std::mem::size_of::<[[f32; 4]; 4]>(),
|
||||
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
|
||||
..Default::default()
|
||||
});
|
||||
render_resource_assignments.set(resource_name::uniform::CAMERA, buffer);
|
||||
camera_buffer = Some(buffer);
|
||||
}
|
||||
|
||||
let primary_window_resized_event = window_resized_events
|
||||
.find_latest(&mut window_resized_event_reader, |event| event.is_primary);
|
||||
if let Some(_) = primary_window_resized_event {
|
||||
let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>();
|
||||
for (camera, local_to_world, _) in query.iter(world) {
|
||||
let camera_matrix: [[f32; 4]; 4] =
|
||||
(camera.view_matrix * local_to_world.0).to_cols_array_2d();
|
||||
|
||||
if let Some(old_tmp_buffer) = tmp_buffer {
|
||||
render_resources.remove_buffer(old_tmp_buffer);
|
||||
}
|
||||
|
||||
tmp_buffer = Some(render_resources.create_buffer_mapped(
|
||||
BufferInfo {
|
||||
size: matrix_size,
|
||||
buffer_usage: BufferUsage::COPY_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
&mut |data, _renderer| {
|
||||
data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes());
|
||||
},
|
||||
));
|
||||
|
||||
command_queue.copy_buffer_to_buffer(
|
||||
tmp_buffer.unwrap(),
|
||||
0,
|
||||
camera_buffer.unwrap(),
|
||||
0,
|
||||
matrix_size as u64,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use bevy_asset::AssetStorage;
|
|||
use bevy_render::{
|
||||
pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor},
|
||||
render_graph::RenderGraph,
|
||||
render_graph_2::RenderGraph2,
|
||||
render_resource::RenderResourceAssignments,
|
||||
renderer_2::{GlobalRenderResourceContext, RenderContext, RenderResourceContext},
|
||||
};
|
||||
|
@ -225,7 +226,39 @@ impl WgpuRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn run_graph(&mut self, world: &mut World, resources: &mut Resources) {
|
||||
let mut executor = {
|
||||
let mut render_graph = resources.get_mut::<RenderGraph2>().unwrap();
|
||||
render_graph.take_executor()
|
||||
};
|
||||
|
||||
if let Some(executor) = executor.as_mut() {
|
||||
executor.execute(world, resources);
|
||||
}
|
||||
|
||||
let mut render_graph = resources.get_mut::<RenderGraph2>().unwrap();
|
||||
if let Some(executor) = executor.take() {
|
||||
render_graph.set_executor(executor);
|
||||
}
|
||||
let mut global_context = resources.get_mut::<GlobalRenderResourceContext>().unwrap();
|
||||
let render_resource_context = global_context
|
||||
.context
|
||||
.downcast_mut::<WgpuRenderResourceContext>()
|
||||
.unwrap();
|
||||
let mut render_context =
|
||||
WgpuRenderContext::new(self.device.clone(), render_resource_context.clone());
|
||||
for node in render_graph.get_schedule() {
|
||||
node.update(world, resources, &mut render_context);
|
||||
}
|
||||
|
||||
let command_buffer = render_context.finish();
|
||||
if let Some(command_buffer) = command_buffer {
|
||||
self.queue.submit(&[command_buffer]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, world: &mut World, resources: &mut Resources) {
|
||||
self.run_graph(world, resources);
|
||||
let mut encoder = {
|
||||
let mut global_context = resources.get_mut::<GlobalRenderResourceContext>().unwrap();
|
||||
let render_resource_context = global_context
|
||||
|
|
|
@ -19,7 +19,7 @@ pub struct WgpuBindGroupInfo {
|
|||
}
|
||||
|
||||
/// 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
|
||||
/// you 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.
|
||||
///
|
||||
|
@ -88,7 +88,7 @@ pub struct WgpuResources {
|
|||
}
|
||||
|
||||
impl WgpuResources {
|
||||
pub fn read<'a>(&'a self) -> WgpuResourcesReadLock<'a> {
|
||||
pub fn read(&self) -> WgpuResourcesReadLock {
|
||||
WgpuResourcesReadLock {
|
||||
buffers: self.buffers.read().unwrap(),
|
||||
textures: self.textures.read().unwrap(),
|
||||
|
|
Loading…
Reference in a new issue