mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 14:40:19 +00:00
render graph 2: schedulers + window nodes
This commit is contained in:
parent
210a50e781
commit
5fec31b63c
12 changed files with 473 additions and 175 deletions
|
@ -41,7 +41,7 @@ use self::{
|
||||||
render_resource::{
|
render_resource::{
|
||||||
entity_render_resource_assignments_system,
|
entity_render_resource_assignments_system,
|
||||||
resource_providers::{
|
resource_providers::{
|
||||||
Camera2dResourceProvider, CameraResourceProvider, LightResourceProvider,
|
LightResourceProvider,
|
||||||
UniformResourceProvider,
|
UniformResourceProvider,
|
||||||
},
|
},
|
||||||
AssetBatchers, EntityRenderResourceAssignments, RenderResourceAssignments,
|
AssetBatchers, EntityRenderResourceAssignments, RenderResourceAssignments,
|
||||||
|
@ -50,12 +50,11 @@ use self::{
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
};
|
};
|
||||||
|
|
||||||
use bevy_app::{stage, AppBuilder, AppPlugin, GetEventReader};
|
use bevy_app::{stage, AppBuilder, AppPlugin};
|
||||||
use bevy_asset::AssetStorage;
|
use bevy_asset::AssetStorage;
|
||||||
use bevy_transform::prelude::LocalToWorld;
|
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::{nodes::{Camera2dNode, CameraNode}, RenderGraph2};
|
||||||
use render_graph_2::RenderGraph2;
|
|
||||||
|
|
||||||
pub static RENDER_RESOURCE_STAGE: &str = "render_resource";
|
pub static RENDER_RESOURCE_STAGE: &str = "render_resource";
|
||||||
pub static RENDER_STAGE: &str = "render";
|
pub static RENDER_STAGE: &str = "render";
|
||||||
|
@ -78,9 +77,6 @@ impl RenderPlugin {
|
||||||
.add_draw_target(AssignedBatchesDrawTarget::default())
|
.add_draw_target(AssignedBatchesDrawTarget::default())
|
||||||
.add_draw_target(AssignedMeshesDrawTarget::default())
|
.add_draw_target(AssignedMeshesDrawTarget::default())
|
||||||
.add_draw_target(UiDrawTarget::default())
|
.add_draw_target(UiDrawTarget::default())
|
||||||
.add_resource_provider(Camera2dResourceProvider::new(
|
|
||||||
resources.get_event_reader::<WindowResized>(),
|
|
||||||
))
|
|
||||||
.add_resource_provider(LightResourceProvider::new(10))
|
.add_resource_provider(LightResourceProvider::new(10))
|
||||||
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(true))
|
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(true))
|
||||||
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(true))
|
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(true))
|
||||||
|
@ -93,6 +89,7 @@ impl AppPlugin for RenderPlugin {
|
||||||
fn build(&self, app: &mut AppBuilder) {
|
fn build(&self, app: &mut AppBuilder) {
|
||||||
let mut render_graph = RenderGraph2::default();
|
let mut render_graph = RenderGraph2::default();
|
||||||
render_graph.add_system_node(CameraNode::default(), app.resources_mut());
|
render_graph.add_system_node(CameraNode::default(), app.resources_mut());
|
||||||
|
render_graph.add_system_node(Camera2dNode::default(), app.resources_mut());
|
||||||
let mut asset_batchers = AssetBatchers::default();
|
let mut asset_batchers = AssetBatchers::default();
|
||||||
asset_batchers.batch_types2::<Mesh, StandardMaterial>();
|
asset_batchers.batch_types2::<Mesh, StandardMaterial>();
|
||||||
app.add_stage_after(stage::POST_UPDATE, RENDER_RESOURCE_STAGE)
|
app.add_stage_after(stage::POST_UPDATE, RENDER_RESOURCE_STAGE)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
pub mod nodes;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
render_resource::{RenderResource, ResourceInfo},
|
render_resource::{RenderResource, ResourceInfo},
|
||||||
renderer_2::RenderContext,
|
renderer_2::RenderContext,
|
||||||
|
@ -76,37 +78,124 @@ impl NodeId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ResourceBinding {
|
||||||
|
pub resource: Option<RenderResource>,
|
||||||
|
pub slot: ResourceSlot,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ResourceBindings {
|
||||||
|
bindings: Vec<ResourceBinding>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResourceBindings {
|
||||||
|
pub fn set(&mut self, index: usize, resource: RenderResource) {
|
||||||
|
self.bindings[index].resource = Some(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_named(&mut self, name: &str, resource: RenderResource) {
|
||||||
|
let binding = self
|
||||||
|
.bindings
|
||||||
|
.iter_mut()
|
||||||
|
.find(|b| b.slot.name == name)
|
||||||
|
.expect("Name not found");
|
||||||
|
binding.resource = Some(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, index: usize) -> Option<RenderResource> {
|
||||||
|
self.bindings
|
||||||
|
.get(index)
|
||||||
|
.and_then(|binding| binding.resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_named(&self, name: &str) -> Option<RenderResource> {
|
||||||
|
self.bindings
|
||||||
|
.iter()
|
||||||
|
.find(|b| b.slot.name == name)
|
||||||
|
.and_then(|binding| binding.resource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ResourceSlot> for ResourceBinding {
|
||||||
|
fn from(slot: &ResourceSlot) -> Self {
|
||||||
|
ResourceBinding {
|
||||||
|
resource: None,
|
||||||
|
slot: slot.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&[ResourceSlot]> for ResourceBindings {
|
||||||
|
fn from(slots: &[ResourceSlot]) -> Self {
|
||||||
|
ResourceBindings {
|
||||||
|
bindings: slots
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.into())
|
||||||
|
.collect::<Vec<ResourceBinding>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ResourceSlot {
|
pub struct ResourceSlot {
|
||||||
name: Option<String>,
|
name: &'static str,
|
||||||
resource_type: ResourceInfo,
|
resource_type: ResourceInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ResourceSlotBinding {
|
impl ResourceSlot {
|
||||||
resource: RenderResource,
|
pub const fn new(name: &'static str, resource_type: ResourceInfo) -> Self {
|
||||||
|
ResourceSlot {
|
||||||
|
name,
|
||||||
|
resource_type,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NodeDescriptor {
|
|
||||||
pub inputs: Vec<ResourceSlot>,
|
|
||||||
pub outputs: Vec<ResourceSlot>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Node: Send + Sync + 'static {
|
pub trait Node: Send + Sync + 'static {
|
||||||
fn descriptor(&self) -> &NodeDescriptor;
|
fn input(&self) -> &[ResourceSlot] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output(&self) -> &[ResourceSlot] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
world: &World,
|
world: &World,
|
||||||
resources: &Resources,
|
resources: &Resources,
|
||||||
render_context: &mut dyn RenderContext,
|
render_context: &mut dyn RenderContext,
|
||||||
|
input: &ResourceBindings,
|
||||||
|
output: &mut ResourceBindings,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct NodeState {
|
||||||
|
pub node: Box<dyn Node>,
|
||||||
|
pub input: ResourceBindings,
|
||||||
|
pub output: ResourceBindings,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeState {
|
||||||
|
pub fn new<T>(node: T) -> Self
|
||||||
|
where
|
||||||
|
T: Node,
|
||||||
|
{
|
||||||
|
NodeState {
|
||||||
|
input: ResourceBindings::from(node.input()),
|
||||||
|
output: ResourceBindings::from(node.output()),
|
||||||
|
node: Box::new(node),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait SystemNode: Node {
|
pub trait SystemNode: Node {
|
||||||
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable>;
|
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct RenderGraph2 {
|
pub struct RenderGraph2 {
|
||||||
nodes: HashMap<NodeId, Box<dyn Node>>,
|
nodes: HashMap<NodeId, NodeState>,
|
||||||
new_systems: Vec<Box<dyn Schedulable>>,
|
new_systems: Vec<Box<dyn Schedulable>>,
|
||||||
system_executor: Option<Executor>,
|
system_executor: Option<Executor>,
|
||||||
}
|
}
|
||||||
|
@ -117,7 +206,7 @@ impl RenderGraph2 {
|
||||||
T: Node + 'static,
|
T: Node + 'static,
|
||||||
{
|
{
|
||||||
let id = NodeId::new();
|
let id = NodeId::new();
|
||||||
self.nodes.insert(id, Box::new(node));
|
self.nodes.insert(id, NodeState::new(node));
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,14 +216,10 @@ impl RenderGraph2 {
|
||||||
{
|
{
|
||||||
let id = NodeId::new();
|
let id = NodeId::new();
|
||||||
self.new_systems.push(node.get_system(resources));
|
self.new_systems.push(node.get_system(resources));
|
||||||
self.nodes.insert(id, Box::new(node));
|
self.nodes.insert(id, NodeState::new(node));
|
||||||
id
|
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> {
|
pub fn take_executor(&mut self) -> Option<Executor> {
|
||||||
// rebuild executor if there are new systems
|
// rebuild executor if there are new systems
|
||||||
if self.new_systems.len() > 0 {
|
if self.new_systems.len() > 0 {
|
||||||
|
@ -157,3 +242,54 @@ impl RenderGraph2 {
|
||||||
self.system_executor = Some(executor);
|
self.system_executor = Some(executor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Stage<'a> {
|
||||||
|
ordered_jobs: Vec<OrderedJob<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Stage<'a> {
|
||||||
|
pub fn add(&mut self, job: OrderedJob<'a>) {
|
||||||
|
self.ordered_jobs.push(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_mut(&mut self) -> impl Iterator<Item=&mut OrderedJob<'a>> {
|
||||||
|
self.ordered_jobs.iter_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct OrderedJob<'a> {
|
||||||
|
node_states: Vec<&'a mut NodeState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> OrderedJob<'a> {
|
||||||
|
pub fn add(&mut self, node_state: &'a mut NodeState) {
|
||||||
|
self.node_states.push(node_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_mut(&mut self) -> impl Iterator<Item=&mut &'a mut NodeState> {
|
||||||
|
self.node_states.iter_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RenderGraphScheduler {
|
||||||
|
fn get_stages<'a>(&mut self, render_graph: &'a mut RenderGraph2) -> Vec<Stage<'a>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct LinearScheduler;
|
||||||
|
|
||||||
|
impl RenderGraphScheduler for LinearScheduler {
|
||||||
|
fn get_stages<'a>(&mut self, render_graph: &'a mut RenderGraph2) -> Vec<Stage<'a>> {
|
||||||
|
let mut stage = Stage::default();
|
||||||
|
let mut job = OrderedJob::default();
|
||||||
|
for node_state in render_graph.nodes.values_mut() {
|
||||||
|
job.add(node_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
stage.ordered_jobs.push(job);
|
||||||
|
|
||||||
|
vec![stage]
|
||||||
|
}
|
||||||
|
}
|
100
bevy_render/src/render_graph_2/nodes/camera2d_node.rs
Normal file
100
bevy_render/src/render_graph_2/nodes/camera2d_node.rs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
use bevy_app::{Events, GetEventReader};
|
||||||
|
use bevy_window::WindowResized;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
camera::{ActiveCamera2d, Camera},
|
||||||
|
render_graph_2::{CommandQueue, Node, SystemNode, ResourceBindings},
|
||||||
|
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResourceAssignments},
|
||||||
|
renderer_2::{GlobalRenderResourceContext, RenderContext},
|
||||||
|
};
|
||||||
|
|
||||||
|
use bevy_transform::components::LocalToWorld;
|
||||||
|
use legion::prelude::*;
|
||||||
|
use zerocopy::AsBytes;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Camera2dNode {
|
||||||
|
command_queue: CommandQueue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for Camera2dNode {
|
||||||
|
fn update(
|
||||||
|
&mut self,
|
||||||
|
_world: &World,
|
||||||
|
_resources: &Resources,
|
||||||
|
render_context: &mut dyn RenderContext,
|
||||||
|
_input: &ResourceBindings,
|
||||||
|
_output: &mut ResourceBindings,
|
||||||
|
) {
|
||||||
|
self.command_queue.execute(render_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SystemNode for Camera2dNode {
|
||||||
|
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<ActiveCamera2d>)>::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::CAMERA2D, 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,5 @@
|
||||||
use bevy_window::WindowResized;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
render_graph_2::{CommandQueue, Node, NodeDescriptor, SystemNode},
|
render_graph_2::{CommandQueue, Node, SystemNode, ResourceBindings},
|
||||||
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResourceAssignments},
|
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResourceAssignments},
|
||||||
renderer_2::{GlobalRenderResourceContext, RenderContext},
|
renderer_2::{GlobalRenderResourceContext, RenderContext},
|
||||||
ActiveCamera, Camera,
|
ActiveCamera, Camera,
|
||||||
|
@ -10,8 +8,8 @@ use crate::{
|
||||||
use bevy_app::{Events, GetEventReader};
|
use bevy_app::{Events, GetEventReader};
|
||||||
use bevy_transform::prelude::*;
|
use bevy_transform::prelude::*;
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
|
use bevy_window::WindowResized;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct CameraNode {
|
pub struct CameraNode {
|
||||||
|
@ -19,19 +17,13 @@ pub struct CameraNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for CameraNode {
|
impl Node for CameraNode {
|
||||||
fn descriptor(&self) -> &NodeDescriptor {
|
|
||||||
static DESCRIPTOR: Lazy<NodeDescriptor> = Lazy::new(|| NodeDescriptor {
|
|
||||||
inputs: Vec::new(),
|
|
||||||
outputs: Vec::new(),
|
|
||||||
});
|
|
||||||
&DESCRIPTOR
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
_world: &World,
|
_world: &World,
|
||||||
_resources: &Resources,
|
_resources: &Resources,
|
||||||
render_context: &mut dyn RenderContext,
|
render_context: &mut dyn RenderContext,
|
||||||
|
_input: &ResourceBindings,
|
||||||
|
_output: &mut ResourceBindings,
|
||||||
) {
|
) {
|
||||||
self.command_queue.execute(render_context);
|
self.command_queue.execute(render_context);
|
||||||
}
|
}
|
9
bevy_render/src/render_graph_2/nodes/mod.rs
Normal file
9
bevy_render/src/render_graph_2/nodes/mod.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
mod camera_node;
|
||||||
|
mod camera2d_node;
|
||||||
|
mod window_texture_node;
|
||||||
|
mod window_swapchain_node;
|
||||||
|
|
||||||
|
pub use camera_node::*;
|
||||||
|
pub use camera2d_node::*;
|
||||||
|
pub use window_texture_node::*;
|
||||||
|
pub use window_swapchain_node::*;
|
|
@ -0,0 +1,70 @@
|
||||||
|
use crate::{
|
||||||
|
render_graph_2::{Node, ResourceBindings, ResourceSlot},
|
||||||
|
render_resource::{RenderResource, ResourceInfo},
|
||||||
|
renderer_2::RenderContext,
|
||||||
|
texture::TextureDescriptor,
|
||||||
|
};
|
||||||
|
use bevy_app::{EventReader, Events};
|
||||||
|
use bevy_window::{WindowCreated, WindowId, WindowResized, Windows};
|
||||||
|
use legion::prelude::*;
|
||||||
|
|
||||||
|
pub struct WindowSwapChainNode {
|
||||||
|
window_id: WindowId,
|
||||||
|
use_primary_window: bool,
|
||||||
|
window_resized_event_reader: EventReader<WindowResized>,
|
||||||
|
window_created_event_reader: EventReader<WindowCreated>,
|
||||||
|
swap_chain_resource: Option<RenderResource>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for WindowSwapChainNode {
|
||||||
|
fn output(&self) -> &[ResourceSlot] {
|
||||||
|
static OUTPUT: &[ResourceSlot] = &[ResourceSlot::new(
|
||||||
|
"swapchain_texture",
|
||||||
|
ResourceInfo::Texture,
|
||||||
|
)];
|
||||||
|
OUTPUT
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(
|
||||||
|
&mut self,
|
||||||
|
_world: &World,
|
||||||
|
resources: &Resources,
|
||||||
|
render_context: &mut dyn RenderContext,
|
||||||
|
_input: &ResourceBindings,
|
||||||
|
output: &mut ResourceBindings,
|
||||||
|
) {
|
||||||
|
const WINDOW_TEXTURE: usize = 0;
|
||||||
|
let window_created_events = resources.get::<Events<WindowCreated>>().unwrap();
|
||||||
|
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
|
||||||
|
let windows = resources.get::<Windows>().unwrap();
|
||||||
|
|
||||||
|
let render_resources = render_context.resources_mut();
|
||||||
|
let window = if self.use_primary_window {
|
||||||
|
windows.get_primary().expect("No primary window exists")
|
||||||
|
} else {
|
||||||
|
windows
|
||||||
|
.get(self.window_id)
|
||||||
|
.expect("Received window resized event for non-existent window")
|
||||||
|
};
|
||||||
|
|
||||||
|
// create window swapchain
|
||||||
|
if let Some(_) = window_created_events
|
||||||
|
.find_latest(&mut self.window_created_event_reader, |e| {
|
||||||
|
e.id == window.id
|
||||||
|
})
|
||||||
|
{
|
||||||
|
render_resources.create_swap_chain(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
// resize window swapchain
|
||||||
|
if let Some(_) = window_resized_events
|
||||||
|
.find_latest(&mut self.window_resized_event_reader, |e| {
|
||||||
|
e.id == window.id
|
||||||
|
})
|
||||||
|
{
|
||||||
|
render_resources.create_swap_chain(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.set(WINDOW_TEXTURE, self.swap_chain_resource.unwrap());
|
||||||
|
}
|
||||||
|
}
|
45
bevy_render/src/render_graph_2/nodes/window_texture_node.rs
Normal file
45
bevy_render/src/render_graph_2/nodes/window_texture_node.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use crate::{
|
||||||
|
render_graph_2::{Node, ResourceBindings, ResourceSlot},
|
||||||
|
render_resource::ResourceInfo,
|
||||||
|
renderer_2::RenderContext,
|
||||||
|
texture::TextureDescriptor,
|
||||||
|
};
|
||||||
|
use bevy_app::{EventReader, Events};
|
||||||
|
use bevy_window::WindowResized;
|
||||||
|
use legion::prelude::*;
|
||||||
|
|
||||||
|
pub struct WindowTextureNode {
|
||||||
|
pub descriptor: TextureDescriptor,
|
||||||
|
window_resized_event_reader: EventReader<WindowResized>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for WindowTextureNode {
|
||||||
|
fn output(&self) -> &[ResourceSlot] {
|
||||||
|
static OUTPUT: &[ResourceSlot] =
|
||||||
|
&[ResourceSlot::new("window_texture", ResourceInfo::Texture)];
|
||||||
|
OUTPUT
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(
|
||||||
|
&mut self,
|
||||||
|
_world: &World,
|
||||||
|
resources: &Resources,
|
||||||
|
render_context: &mut dyn RenderContext,
|
||||||
|
_input: &ResourceBindings,
|
||||||
|
output: &mut ResourceBindings,
|
||||||
|
) {
|
||||||
|
const WINDOW_TEXTURE: usize = 0;
|
||||||
|
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
|
||||||
|
if let Some(event) = window_resized_events.latest(&mut self.window_resized_event_reader) {
|
||||||
|
let render_resources = render_context.resources_mut();
|
||||||
|
if let Some(old_texture) = output.get(WINDOW_TEXTURE) {
|
||||||
|
render_resources.remove_texture(old_texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.descriptor.size.width = event.width;
|
||||||
|
self.descriptor.size.height = event.height;
|
||||||
|
let texture_resource = render_resources.create_texture(&self.descriptor);
|
||||||
|
output.set(WINDOW_TEXTURE, texture_resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,91 +0,0 @@
|
||||||
use bevy_app::{EventReader, Events};
|
|
||||||
use bevy_window::WindowResized;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
camera::{ActiveCamera2d, Camera},
|
|
||||||
render_resource::{
|
|
||||||
resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
|
|
||||||
ResourceProvider,
|
|
||||||
},
|
|
||||||
renderer_2::RenderContext,
|
|
||||||
};
|
|
||||||
|
|
||||||
use legion::prelude::*;
|
|
||||||
use zerocopy::AsBytes;
|
|
||||||
|
|
||||||
pub struct Camera2dResourceProvider {
|
|
||||||
pub camera_buffer: Option<RenderResource>,
|
|
||||||
pub tmp_buffer: Option<RenderResource>,
|
|
||||||
pub window_resized_event_reader: EventReader<WindowResized>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Camera2dResourceProvider {
|
|
||||||
pub fn new(window_resized_event_reader: EventReader<WindowResized>) -> Self {
|
|
||||||
Camera2dResourceProvider {
|
|
||||||
camera_buffer: None,
|
|
||||||
tmp_buffer: None,
|
|
||||||
window_resized_event_reader,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResourceProvider for Camera2dResourceProvider {
|
|
||||||
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()
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut render_resource_assignments =
|
|
||||||
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
|
||||||
render_resource_assignments.set(resource_name::uniform::CAMERA2D, buffer);
|
|
||||||
self.camera_buffer = Some(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(
|
|
||||||
&mut self,
|
|
||||||
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, _) in <(Read<Camera>, Read<ActiveCamera2d>)>::query().iter(world) {
|
|
||||||
let camera_matrix: [[f32; 4]; 4] = camera.view_matrix.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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +1,50 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
render_resource::{RenderResourceAssignments, ResourceProvider},
|
render_graph_2::{Node, ResourceBindings, ResourceSlot},
|
||||||
|
render_resource::{RenderResourceAssignments, ResourceInfo, ResourceProvider},
|
||||||
renderer_2::RenderContext,
|
renderer_2::RenderContext,
|
||||||
texture::TextureDescriptor,
|
texture::TextureDescriptor,
|
||||||
};
|
};
|
||||||
use bevy_window::Windows;
|
use bevy_app::{EventReader, Events};
|
||||||
|
use bevy_window::{WindowResized, Windows};
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
|
|
||||||
|
pub struct WindowTextureNode {
|
||||||
|
pub name: String,
|
||||||
|
pub descriptor: TextureDescriptor,
|
||||||
|
pub window_resized_event_reader: EventReader<WindowResized>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for WindowTextureNode {
|
||||||
|
fn output(&self) -> &[ResourceSlot] {
|
||||||
|
static OUTPUT: &[ResourceSlot] =
|
||||||
|
&[ResourceSlot::new("window_texture", ResourceInfo::Texture)];
|
||||||
|
OUTPUT
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(
|
||||||
|
&mut self,
|
||||||
|
_world: &World,
|
||||||
|
resources: &Resources,
|
||||||
|
render_context: &mut dyn RenderContext,
|
||||||
|
_input: &ResourceBindings,
|
||||||
|
output: &mut ResourceBindings,
|
||||||
|
) {
|
||||||
|
const WINDOW_TEXTURE: usize = 0;
|
||||||
|
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
|
||||||
|
if let Some(event) = window_resized_events.latest(&mut self.window_resized_event_reader) {
|
||||||
|
let render_resources = render_context.resources_mut();
|
||||||
|
if let Some(old_texture) = output.get(WINDOW_TEXTURE) {
|
||||||
|
render_resources.remove_texture(old_texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.descriptor.size.width = event.width;
|
||||||
|
self.descriptor.size.height = event.height;
|
||||||
|
let texture_resource = render_resources.create_texture(&self.descriptor);
|
||||||
|
output.set(WINDOW_TEXTURE, texture_resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FrameTextureResourceProvider {
|
pub struct FrameTextureResourceProvider {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub descriptor: TextureDescriptor,
|
pub descriptor: TextureDescriptor,
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
mod camera2d_resource_provider;
|
|
||||||
mod camera_resource_provider;
|
|
||||||
mod frame_texture_resource_provider;
|
mod frame_texture_resource_provider;
|
||||||
mod light_resource_provider;
|
mod light_resource_provider;
|
||||||
mod mesh_resource_provider;
|
mod mesh_resource_provider;
|
||||||
mod uniform_resource_provider;
|
mod uniform_resource_provider;
|
||||||
|
|
||||||
pub use camera2d_resource_provider::*;
|
|
||||||
pub use camera_resource_provider::*;
|
|
||||||
pub use frame_texture_resource_provider::*;
|
pub use frame_texture_resource_provider::*;
|
||||||
pub use light_resource_provider::*;
|
pub use light_resource_provider::*;
|
||||||
pub use mesh_resource_provider::*;
|
pub use mesh_resource_provider::*;
|
||||||
|
|
|
@ -1,46 +1,46 @@
|
||||||
#![feature(test)]
|
// #![feature(test)]
|
||||||
|
|
||||||
extern crate test;
|
// extern crate test;
|
||||||
|
|
||||||
use legion::prelude::*;
|
// use legion::prelude::*;
|
||||||
use legion_transform::{local_to_world_system, prelude::*};
|
// use bevy_transform::{local_to_world_system, prelude::*};
|
||||||
use test::Bencher;
|
// use test::Bencher;
|
||||||
|
|
||||||
#[bench]
|
// #[bench]
|
||||||
fn local_to_world_update_without_change(b: &mut Bencher) {
|
// fn local_to_world_update_without_change(b: &mut Bencher) {
|
||||||
let _ = env_logger::builder().is_test(true).try_init();
|
// let _ = env_logger::builder().is_test(true).try_init();
|
||||||
|
|
||||||
let mut world = Universe::new().create_world();
|
// let mut world = Universe::new().create_world();
|
||||||
let system = local_to_world_system::build(&mut world);
|
// let system = local_to_world_system::build(&mut world);
|
||||||
|
|
||||||
let ltw = LocalToWorld::identity();
|
// let ltw = LocalToWorld::identity();
|
||||||
let t = Translation::new(1.0, 2.0, 3.0);
|
// let t = Translation::new(1.0, 2.0, 3.0);
|
||||||
let r = Rotation::from_euler_angles(1.0, 2.0, 3.0);
|
// let r = Rotation::from_euler_angles(1.0, 2.0, 3.0);
|
||||||
let s = Scale(2.0);
|
// let s = Scale(2.0);
|
||||||
let nus = NonUniformScale::new(1.0, 2.0, 3.0);
|
// let nus = NonUniformScale::new(1.0, 2.0, 3.0);
|
||||||
|
|
||||||
// Add N of every combination of transform types.
|
// // Add N of every combination of transform types.
|
||||||
let n = 1000;
|
// let n = 1000;
|
||||||
let _translation = *world.insert((), vec![(ltw, t); n]).first().unwrap();
|
// let _translation = *world.insert((), vec![(ltw, t); n]).first().unwrap();
|
||||||
let _rotation = *world.insert((), vec![(ltw, r); n]).first().unwrap();
|
// let _rotation = *world.insert((), vec![(ltw, r); n]).first().unwrap();
|
||||||
let _scale = *world.insert((), vec![(ltw, s); n]).first().unwrap();
|
// let _scale = *world.insert((), vec![(ltw, s); n]).first().unwrap();
|
||||||
let _non_uniform_scale = *world.insert((), vec![(ltw, nus); n]).first().unwrap();
|
// let _non_uniform_scale = *world.insert((), vec![(ltw, nus); n]).first().unwrap();
|
||||||
let _translation_and_rotation = *world.insert((), vec![(ltw, t, r); n]).first().unwrap();
|
// let _translation_and_rotation = *world.insert((), vec![(ltw, t, r); n]).first().unwrap();
|
||||||
let _translation_and_scale = *world.insert((), vec![(ltw, t, s); n]).first().unwrap();
|
// let _translation_and_scale = *world.insert((), vec![(ltw, t, s); n]).first().unwrap();
|
||||||
let _translation_and_nus = *world.insert((), vec![(ltw, t, nus); n]).first().unwrap();
|
// let _translation_and_nus = *world.insert((), vec![(ltw, t, nus); n]).first().unwrap();
|
||||||
let _rotation_scale = *world.insert((), vec![(ltw, r, s); n]).first().unwrap();
|
// let _rotation_scale = *world.insert((), vec![(ltw, r, s); n]).first().unwrap();
|
||||||
let _rotation_nus = *world.insert((), vec![(ltw, r, nus); n]).first().unwrap();
|
// let _rotation_nus = *world.insert((), vec![(ltw, r, nus); n]).first().unwrap();
|
||||||
let _translation_rotation_scale = *world.insert((), vec![(ltw, t, r, s); n]).first().unwrap();
|
// let _translation_rotation_scale = *world.insert((), vec![(ltw, t, r, s); n]).first().unwrap();
|
||||||
let _translation_rotation_nus = *world.insert((), vec![(ltw, t, r, nus); n]).first().unwrap();
|
// let _translation_rotation_nus = *world.insert((), vec![(ltw, t, r, nus); n]).first().unwrap();
|
||||||
|
|
||||||
// Run the system once outside the test (which should compute everything and it shouldn't be
|
// // Run the system once outside the test (which should compute everything and it shouldn't be
|
||||||
// touched again).
|
// // touched again).
|
||||||
system.run(&mut world);
|
// system.run(&mut world);
|
||||||
system.command_buffer_mut().write(&mut world);
|
// system.command_buffer_mut().write(&mut world);
|
||||||
|
|
||||||
// Then time the already-computed updates.
|
// // Then time the already-computed updates.
|
||||||
b.iter(|| {
|
// b.iter(|| {
|
||||||
system.run(&mut world);
|
// system.run(&mut world);
|
||||||
system.command_buffer_mut().write(&mut world);
|
// system.command_buffer_mut().write(&mut world);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
|
@ -6,7 +6,7 @@ use bevy_asset::AssetStorage;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor},
|
pipeline::{update_shader_assignments, PipelineCompiler, PipelineDescriptor},
|
||||||
render_graph::RenderGraph,
|
render_graph::RenderGraph,
|
||||||
render_graph_2::RenderGraph2,
|
render_graph_2::{LinearScheduler, RenderGraph2, RenderGraphScheduler},
|
||||||
render_resource::RenderResourceAssignments,
|
render_resource::RenderResourceAssignments,
|
||||||
renderer_2::{GlobalRenderResourceContext, RenderContext, RenderResourceContext},
|
renderer_2::{GlobalRenderResourceContext, RenderContext, RenderResourceContext},
|
||||||
};
|
};
|
||||||
|
@ -245,10 +245,15 @@ impl WgpuRenderer {
|
||||||
.context
|
.context
|
||||||
.downcast_mut::<WgpuRenderResourceContext>()
|
.downcast_mut::<WgpuRenderResourceContext>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let mut linear_scheduler = LinearScheduler::default();
|
||||||
let mut render_context =
|
let mut render_context =
|
||||||
WgpuRenderContext::new(self.device.clone(), render_resource_context.clone());
|
WgpuRenderContext::new(self.device.clone(), render_resource_context.clone());
|
||||||
for node in render_graph.get_schedule() {
|
for mut stage in linear_scheduler.get_stages(&mut render_graph) {
|
||||||
node.update(world, resources, &mut render_context);
|
for job in stage.iter_mut() {
|
||||||
|
for node_state in job.iter_mut() {
|
||||||
|
node_state.node.update(world, resources, &mut render_context, &node_state.input, &mut node_state.output);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let command_buffer = render_context.finish();
|
let command_buffer = render_context.finish();
|
||||||
|
|
Loading…
Reference in a new issue