RenderGraph2: Finish porting, refactor, cleanup

This commit is contained in:
Carter Anderson 2020-04-24 17:46:54 -07:00
parent 06b6ade902
commit 791c475354
79 changed files with 965 additions and 2473 deletions

View file

@ -6,13 +6,14 @@ edition = "2018"
[features]
default = ["headless", "wgpu", "winit"]
headless = ["asset", "core", "derive", "diagnostic", "gltf", "input", "render", "serialization", "transform", "ui", "window"]
headless = ["asset", "core", "derive", "diagnostic", "gltf", "input", "pbr", "render", "serialization", "transform", "ui", "window"]
asset = ["bevy_asset"]
core = ["bevy_core"]
derive = ["bevy_derive"]
diagnostic = ["bevy_diagnostic"]
gltf = ["bevy_gltf"]
input = ["bevy_input"]
pbr = ["bevy_pbr"]
render = ["bevy_render"]
serialization = ["bevy_serialization"]
transform = ["bevy_transform"]
@ -30,6 +31,7 @@ bevy_derive = { path = "bevy_derive", optional = true }
bevy_diagnostic = { path = "bevy_diagnostic", optional = true }
bevy_gltf = { path = "bevy_gltf", optional = true }
bevy_input = { path = "bevy_input", optional = true }
bevy_pbr = { path = "bevy_pbr", optional = true }
bevy_render = { path = "bevy_render", optional = true }
bevy_serialization = { path = "bevy_serialization", optional = true }
bevy_transform = { path = "bevy_transform", optional = true }
@ -51,6 +53,7 @@ members = [
"bevy_diagnostic",
"bevy_gltf",
"bevy_input",
"bevy_pbr",
"bevy_render",
"bevy_serialization",
"bevy_transform",

18
bevy_pbr/Cargo.toml Normal file
View file

@ -0,0 +1,18 @@
[package]
name = "bevy_pbr"
version = "0.1.0"
authors = ["Carter Anderson <mcanders1@gmail.com>"]
edition = "2018"
[dependencies]
bevy_app = { path = "../bevy_app", version = "0.1.0" }
bevy_asset = { path = "../bevy_asset", version = "0.1.0" }
bevy_core = { path = "../bevy_core", version = "0.1.0" }
bevy_derive = { path = "../bevy_derive", version = "0.1.0" }
bevy_render = { path = "../bevy_render", version = "0.1.0" }
bevy_transform = { path = "../bevy_transform" }
bevy_window = { path = "../bevy_window", version = "0.1.0" }
legion = { path = "../bevy_legion"}
zerocopy = "0.3"
glam = "0.8.6"

28
bevy_pbr/src/entity.rs Normal file
View file

@ -0,0 +1,28 @@
use crate::{light::Light, material::StandardMaterial};
use bevy_asset::Handle;
use bevy_render::{mesh::Mesh, Renderable};
use bevy_transform::prelude::{LocalToWorld, Rotation, Scale, Translation};
use bevy_derive::EntityArchetype;
#[derive(EntityArchetype, Default)]
#[module(meta = false)]
pub struct MeshEntity {
// #[tag]
pub mesh: Handle<Mesh>,
// #[tag]
pub material: Handle<StandardMaterial>,
pub renderable: Renderable,
pub local_to_world: LocalToWorld,
pub translation: Translation,
pub rotation: Rotation,
pub scale: Scale,
}
#[derive(EntityArchetype, Default)]
#[module(meta = false)]
pub struct LightEntity {
pub light: Light,
pub local_to_world: LocalToWorld,
pub translation: Translation,
pub rotation: Rotation,
}

View file

@ -0,0 +1,105 @@
use crate::{
material::StandardMaterial, nodes::LightsNode, passes::build_main_pass,
pipelines::build_forward_pipeline,
};
use bevy_app::GetEventReader;
use bevy_asset::AssetStorage;
use bevy_render::{
draw_target::AssignedMeshesDrawTarget,
pipeline::PipelineDescriptor,
render_graph::{
nodes::{
AssetUniformNode, CameraNode, PassNode, UniformNode, WindowSwapChainNode,
WindowTextureNode,
},
RenderGraph,
},
shader::Shader,
texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage},
};
use bevy_transform::prelude::LocalToWorld;
use bevy_window::{WindowCreated, WindowReference, WindowResized};
use legion::prelude::Resources;
pub trait ForwardPbrRenderGraphBuilder {
fn add_pbr_graph(&mut self, resources: &Resources) -> &mut Self;
}
impl ForwardPbrRenderGraphBuilder for RenderGraph {
fn add_pbr_graph(&mut self, resources: &Resources) -> &mut Self {
self.add_system_node_named("camera", CameraNode::default(), resources);
self.add_system_node_named(
"local_to_world",
UniformNode::<LocalToWorld>::new(true),
resources,
);
self.add_system_node_named(
"standard_material",
AssetUniformNode::<StandardMaterial>::new(true),
resources,
);
self.add_system_node_named("lights", LightsNode::new(10), resources);
self.add_node_named(
"swapchain",
WindowSwapChainNode::new(
WindowReference::Primary,
resources.get_event_reader::<WindowCreated>(),
resources.get_event_reader::<WindowResized>(),
),
);
self.add_node_named(
"main_pass_depth_texture",
WindowTextureNode::new(
WindowReference::Primary,
TextureDescriptor {
size: Extent3d {
depth: 1,
width: 1,
height: 1,
},
array_layer_count: 1,
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
format: TextureFormat::Depth32Float, // PERF: vulkan docs recommend using 24 bit depth for better performance
usage: TextureUsage::OUTPUT_ATTACHMENT,
},
resources.get_event_reader::<WindowCreated>(),
resources.get_event_reader::<WindowResized>(),
),
);
let mut shaders = resources.get_mut::<AssetStorage<Shader>>().unwrap();
let mut pipelines = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let mut main_pass = PassNode::new(build_main_pass());
main_pass.add_pipeline(
pipelines.add_default(build_forward_pipeline(&mut shaders)),
vec![Box::new(AssignedMeshesDrawTarget)],
);
self.add_node_named("main_pass", main_pass);
// TODO: replace these with "autowire" groups
self.add_node_edge("camera", "main_pass").unwrap();
self.add_node_edge("standard_material", "main_pass")
.unwrap();
self.add_node_edge("local_to_world", "main_pass").unwrap();
self.add_node_edge("lights", "main_pass").unwrap();
self.add_slot_edge(
"swapchain",
WindowSwapChainNode::OUT_TEXTURE,
"main_pass",
"color",
)
.unwrap();
self.add_slot_edge(
"main_pass_depth_texture",
WindowTextureNode::OUT_TEXTURE,
"main_pass",
"depth",
)
.unwrap();
self
}
}

36
bevy_pbr/src/lib.rs Normal file
View file

@ -0,0 +1,36 @@
pub mod entity;
pub mod light;
pub mod material;
pub mod nodes;
pub mod passes;
pub mod pipelines;
mod forward_pbr_render_graph;
pub use forward_pbr_render_graph::*;
use bevy_app::{AppBuilder, AppPlugin, stage};
use bevy_asset::AssetStorage;
use material::StandardMaterial;
use bevy_render::{render_graph::RenderGraph, shader};
#[derive(Default)]
pub struct PbrPlugin;
// NOTE: this isn't PBR yet. consider this name "aspirational" :)
impl AppPlugin for PbrPlugin {
fn build(&self, app: &mut AppBuilder) {
// asset_batchers.batch_types2::<Mesh, StandardMaterial>();
app.add_resource(AssetStorage::<StandardMaterial>::new())
.add_system_to_stage(
stage::POST_UPDATE,
shader::asset_handle_shader_def_system::<StandardMaterial>(),
)
.add_system_to_stage(
stage::POST_UPDATE,
shader::asset_handle_batcher_system::<StandardMaterial>(),
);
let resources = app.resources();
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.add_pbr_graph(resources);
}
}

View file

@ -1,8 +1,8 @@
use super::{Color, PerspectiveCamera};
use bevy_transform::components::Translation;
use glam::Mat4;
use std::ops::Range;
use zerocopy::{AsBytes, FromBytes};
use bevy_render::{PerspectiveCamera, Color};
pub struct Light {
pub color: Color,

View file

@ -1,12 +1,10 @@
use crate::{texture::Texture, Color};
use bevy_render::{texture::Texture, Color};
use bevy_asset::Handle;
use bevy_derive::Uniforms;
use bevy_asset;
use bevy_core;
#[derive(Uniforms)]
#[module(meta = false, bevy_render = "crate")]
#[module(meta = false)]
pub struct StandardMaterial {
#[uniform(instance)]
pub albedo: Color,

View file

@ -1,13 +1,13 @@
use crate::{
render_graph_2::{CommandQueue, Node, ResourceSlots, SystemNode},
use bevy_render::{
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResourceAssignments},
renderer_2::{GlobalRenderResourceContext, RenderContext},
Light, LightRaw,
renderer::{GlobalRenderResourceContext, RenderContext},
};
use bevy_transform::prelude::*;
use legion::prelude::*;
use zerocopy::AsBytes;
use crate::light::{LightRaw, Light};
#[derive(Default)]
pub struct LightsNode {
@ -44,7 +44,7 @@ pub struct LightCount {
}
impl SystemNode for LightsNode {
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable> {
fn get_system(&self, _resources: &Resources) -> Box<dyn Schedulable> {
let mut light_buffer = None;
let mut lights_are_dirty = true;
// TODO: merge these

View file

@ -0,0 +1,3 @@
mod lights_node;
pub use lights_node::*;

View file

@ -0,0 +1,28 @@
use bevy_render::pass::{
LoadOp, PassDescriptor, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor, StoreOp, TextureAttachment,
};
use bevy_render::Color;
pub fn build_main_pass() -> PassDescriptor {
PassDescriptor {
color_attachments: vec![RenderPassColorAttachmentDescriptor {
attachment: TextureAttachment::Input("color".to_string()),
resolve_target: None,
load_op: LoadOp::Clear,
store_op: StoreOp::Store,
clear_color: Color::rgb(0.1, 0.1, 0.1),
}],
depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor {
attachment: TextureAttachment::Input("depth".to_string()),
depth_load_op: LoadOp::Clear,
depth_store_op: StoreOp::Store,
stencil_load_op: LoadOp::Clear,
stencil_store_op: StoreOp::Store,
clear_depth: 1.0,
clear_stencil: 0,
}),
sample_count: 1,
}
}

View file

@ -0,0 +1,3 @@
mod main;
pub use main::*;

View file

@ -1,4 +1,4 @@
use crate::{
use bevy_render::{
pipeline::{
state_descriptors::{
BlendDescriptor, BlendFactor, BlendOperation, ColorStateDescriptor, ColorWrite,
@ -46,7 +46,7 @@ pub fn build_forward_pipeline(shaders: &mut AssetStorage<Shader>) -> PipelineDes
write_mask: ColorWrite::ALL,
}
],
..PipelineDescriptor::new_new(ShaderStages {
..PipelineDescriptor::new(ShaderStages {
vertex: shaders.add(Shader::from_glsl(
ShaderStage::Vertex,
include_str!("forward.vert"),

View file

@ -1,4 +1,4 @@
use crate::{pass::RenderPass, pipeline::PipelineDescriptor, renderer_2::RenderContext};
use crate::{pass::RenderPass, pipeline::PipelineDescriptor, renderer::RenderContext};
use bevy_asset::Handle;
use legion::prelude::{Resources, World};

View file

@ -3,7 +3,7 @@ use crate::{
pass::RenderPass,
pipeline::PipelineDescriptor,
render_resource::{resource_name, AssetBatchers, RenderResourceAssignments},
renderer_2::RenderContext,
renderer::RenderContext,
Renderable,
};
use bevy_asset::Handle;

View file

@ -9,7 +9,7 @@ use crate::{
render_resource::{
resource_name, EntityRenderResourceAssignments, RenderResourceAssignments, ResourceInfo,
},
renderer_2::RenderContext,
renderer::RenderContext,
Renderable,
};

View file

@ -7,7 +7,7 @@ use crate::{
resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
ResourceInfo,
},
renderer_2::RenderContext,
renderer::RenderContext,
};
use bevy_asset::Handle;
use legion::prelude::*;

View file

@ -1,4 +1,5 @@
mod draw_target;
pub mod draw_targets;
mod draw_targets;
pub use draw_target::*;
pub use draw_targets::*;

View file

@ -1,25 +1,11 @@
use crate::{
mesh::Mesh, shader::uniforms::StandardMaterial, ActiveCamera, ActiveCamera2d, Camera,
CameraType, Light, Renderable,
mesh::Mesh, ActiveCamera, ActiveCamera2d, Camera,
CameraType, Renderable,
};
use bevy_asset::Handle;
use bevy_derive::EntityArchetype;
use bevy_transform::components::{LocalToWorld, Rotation, Scale, Translation};
#[derive(EntityArchetype, Default)]
#[module(meta = false)]
pub struct MeshEntity {
// #[tag]
pub mesh: Handle<Mesh>,
// #[tag]
pub material: Handle<StandardMaterial>,
pub renderable: Renderable,
pub local_to_world: LocalToWorld,
pub translation: Translation,
pub rotation: Rotation,
pub scale: Scale,
}
#[derive(EntityArchetype, Default)]
#[module(meta = false)]
pub struct MeshMaterialEntity<T: Default + Send + Sync + 'static> {
@ -32,15 +18,6 @@ pub struct MeshMaterialEntity<T: Default + Send + Sync + 'static> {
pub scale: Scale,
}
#[derive(EntityArchetype, Default)]
#[module(meta = false)]
pub struct LightEntity {
pub light: Light,
pub local_to_world: LocalToWorld,
pub translation: Translation,
pub rotation: Rotation,
}
#[derive(EntityArchetype, Default)]
#[module(meta = false)]
pub struct CameraEntity {

View file

@ -3,17 +3,14 @@ mod camera;
pub mod entity;
pub mod mesh;
pub mod render_graph;
pub mod render_graph_2;
pub mod renderer_2;
pub mod renderer;
pub mod shader;
pub mod vertex;
mod color;
mod light;
pub use camera::*;
pub use color::*;
pub use light::*;
pub use renderable::*;
pub use vertex::Vertex;
@ -28,39 +25,22 @@ pub mod texture;
pub use once_cell;
use self::{
draw_target::draw_targets::AssignedMeshesDrawTarget,
mesh::Mesh,
pass::{
LoadOp, RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor,
StoreOp, TextureAttachment,
},
pipeline::{
PipelineAssignments, PipelineCompiler, PipelineDescriptor, VertexBufferDescriptors,
},
render_graph::RenderGraph,
render_resource::{
entity_render_resource_assignments_system, resource_providers::UniformResourceProvider,
AssetBatchers, EntityRenderResourceAssignments, RenderResourceAssignments,
entity_render_resource_assignments_system, AssetBatchers, EntityRenderResourceAssignments,
RenderResourceAssignments,
},
shader::{uniforms::StandardMaterial, Shader},
shader::Shader,
texture::Texture,
};
use bevy_app::{stage, AppBuilder, AppPlugin, GetEventReader};
use bevy_app::{stage, AppBuilder, AppPlugin};
use bevy_asset::AssetStorage;
use bevy_transform::prelude::LocalToWorld;
use bevy_window::{WindowCreated, WindowReference, WindowResized};
use pass::PassDescriptor;
use pipeline::pipelines::build_forward_pipeline;
use render_graph_2::{
nodes::{
Camera2dNode, CameraNode, LightsNode, PassNode, UniformNode, WindowSwapChainNode,
WindowTextureNode,
},
RenderGraph2,
};
use render_resource::resource_providers::mesh_resource_provider_system;
use texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage};
use mesh::mesh_resource_provider_system;
use render_graph::RenderGraph;
pub static RENDER_RESOURCE_STAGE: &str = "render_resource";
pub static RENDER_STAGE: &str = "render";
@ -69,24 +49,10 @@ pub static RENDER_STAGE: &str = "render";
pub struct RenderPlugin;
impl RenderPlugin {
pub fn setup_render_graph_defaults(app: &mut AppBuilder) {
let resources = app.resources();
let mut pipelines = app
.resources()
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let mut shaders = resources.get_mut::<AssetStorage<Shader>>().unwrap();
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph
.build(&mut pipelines, &mut shaders)
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(true));
}
}
impl AppPlugin for RenderPlugin {
fn build(&self, app: &mut AppBuilder) {
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
@ -94,125 +60,19 @@ impl AppPlugin for RenderPlugin {
.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(PipelineCompiler::new())
.add_resource(RenderResourceAssignments::default())
.add_resource(VertexBufferDescriptors::default())
.add_resource(EntityRenderResourceAssignments::default())
.add_resource(asset_batchers)
.add_resource(AssetBatchers::default())
// core systems
.add_system(entity_render_resource_assignments_system())
.add_system_to_stage_init(stage::POST_UPDATE, camera::camera_update_system)
.add_system_to_stage(stage::POST_UPDATE, mesh::mesh_specializer_system())
.add_system_to_stage(stage::POST_UPDATE, mesh::mesh_batcher_system())
.add_system_to_stage(
stage::POST_UPDATE,
shader::asset_handle_shader_def_system::<StandardMaterial>(),
)
.add_system_to_stage(
stage::POST_UPDATE,
shader::asset_handle_batcher_system::<StandardMaterial>(),
)
// render resource provider systems
.add_system_to_stage_init(RENDER_RESOURCE_STAGE, mesh_resource_provider_system);
RenderPlugin::setup_render_graph_defaults(app);
let mut render_graph = RenderGraph2::default();
// begin render graph 2
{
let resources = app.resources_mut();
render_graph.add_system_node_named("camera", CameraNode::default(), resources);
render_graph.add_system_node_named("camera2d", Camera2dNode::default(), resources);
render_graph.add_system_node_named(
"standard_material",
UniformNode::<StandardMaterial>::new(true),
resources,
);
render_graph.add_system_node_named("lights", LightsNode::new(10), resources);
render_graph.add_node_named(
"swapchain",
WindowSwapChainNode::new(
WindowReference::Primary,
resources.get_event_reader::<WindowCreated>(),
resources.get_event_reader::<WindowResized>(),
),
);
render_graph.add_node_named(
"main_pass_depth_texture",
WindowTextureNode::new(
WindowReference::Primary,
TextureDescriptor {
size: Extent3d {
depth: 1,
width: 1,
height: 1,
},
array_layer_count: 1,
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
format: TextureFormat::Depth32Float, // PERF: vulkan recommends using 24 bit depth for better performance
usage: TextureUsage::OUTPUT_ATTACHMENT,
},
resources.get_event_reader::<WindowCreated>(),
resources.get_event_reader::<WindowResized>(),
),
);
let mut shaders = resources.get_mut::<AssetStorage<Shader>>().unwrap();
let mut pipelines = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let mut main_pass = PassNode::new(PassDescriptor {
color_attachments: vec![RenderPassColorAttachmentDescriptor {
attachment: TextureAttachment::Input("color".to_string()),
resolve_target: None,
load_op: LoadOp::Clear,
store_op: StoreOp::Store,
clear_color: Color::rgb(0.1, 0.1, 0.1),
}],
depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor {
attachment: TextureAttachment::Input("depth".to_string()),
depth_load_op: LoadOp::Clear,
depth_store_op: StoreOp::Store,
stencil_load_op: LoadOp::Clear,
stencil_store_op: StoreOp::Store,
clear_depth: 1.0,
clear_stencil: 0,
}),
sample_count: 1,
});
main_pass.add_pipeline(
pipelines.add_default(build_forward_pipeline(&mut shaders)),
vec![Box::new(AssignedMeshesDrawTarget)],
);
render_graph.add_node_named("main_pass", main_pass);
// TODO: replace these with "autowire" groups
render_graph.add_node_edge("camera", "main_pass").unwrap();
render_graph.add_node_edge("camera2d", "main_pass").unwrap();
render_graph
.add_node_edge("standard_material", "main_pass")
.unwrap();
render_graph.add_node_edge("lights", "main_pass").unwrap();
render_graph
.add_slot_edge(
"swapchain",
WindowSwapChainNode::OUT_TEXTURE,
"main_pass",
"color",
)
.unwrap();
render_graph
.add_slot_edge(
"main_pass_depth_texture",
WindowTextureNode::OUT_TEXTURE,
"main_pass",
"depth",
)
.unwrap();
}
app.add_resource(render_graph);
// end render graph 2
}
}

View file

@ -1,10 +1,11 @@
use crate::{
pipeline::{
state_descriptors::{IndexFormat, PrimitiveTopology},
VertexBufferDescriptor, VertexFormat,
VertexBufferDescriptor, VertexFormat, VertexBufferDescriptors,
},
render_resource::AssetBatchers,
Renderable,
render_resource::{RenderResourceAssignments, AssetBatchers, BufferInfo, BufferUsage},
Renderable, renderer::{GlobalRenderResourceContext, RenderResourceContext}, Vertex,
shader::AsUniforms,
};
use bevy_asset::{AssetStorage, Handle};
use glam::*;
@ -335,6 +336,93 @@ pub fn mesh_specializer_system() -> Box<dyn Schedulable> {
})
}
fn setup_mesh_resource(
render_resources: &dyn RenderResourceContext,
render_resource_assignments: &mut RenderResourceAssignments,
vertex_buffer_descriptor: &VertexBufferDescriptor,
handle: Handle<Mesh>,
meshes: &AssetStorage<Mesh>,
) {
log::trace!("setup mesh for {:?}", render_resource_assignments.id);
let index_format = IndexFormat::Uint16;
let (vertex_buffer, index_buffer) = if let Some(vertex_buffer) =
render_resources.get_asset_resource(handle, VERTEX_BUFFER_ASSET_INDEX)
{
(
vertex_buffer,
render_resources.get_asset_resource(handle, INDEX_BUFFER_ASSET_INDEX),
)
} else {
let mesh_asset = meshes.get(&handle).unwrap();
let vertex_bytes = mesh_asset
.get_vertex_buffer_bytes(&vertex_buffer_descriptor)
.unwrap();
// TODO: use a staging buffer here
let vertex_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::VERTEX,
..Default::default()
},
&vertex_bytes,
);
let index_bytes = mesh_asset.get_index_buffer_bytes(index_format).unwrap();
let index_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::INDEX,
..Default::default()
},
&index_bytes,
);
render_resources.set_asset_resource(handle, vertex_buffer, VERTEX_BUFFER_ASSET_INDEX);
render_resources.set_asset_resource(handle, index_buffer, INDEX_BUFFER_ASSET_INDEX);
(vertex_buffer, Some(index_buffer))
};
render_resource_assignments.set_vertex_buffer("Vertex", vertex_buffer, index_buffer);
}
pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Schedulable> {
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
// TODO: allow pipelines to specialize on vertex_buffer_descriptor and index_format
let vertex_buffer_descriptor = Vertex::get_vertex_buffer_descriptor().unwrap();
vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone());
SystemBuilder::new("mesh_resource_provider")
.read_resource::<GlobalRenderResourceContext>()
.read_resource::<AssetStorage<Mesh>>()
.write_resource::<AssetBatchers>()
.with_query(<(Read<Handle<Mesh>>, Write<Renderable>)>::query())
.build(
move |_, world, (render_resource_context, meshes, asset_batchers), query| {
let render_resources = &*render_resource_context.context;
if let Some(batches) = asset_batchers.get_handle_batches_mut::<Mesh>() {
for batch in batches {
let handle = batch.get_handle::<Mesh>().unwrap();
setup_mesh_resource(
render_resources,
&mut batch.render_resource_assignments,
&vertex_buffer_descriptor,
handle,
&meshes,
);
}
}
// TODO: remove this once batches are pipeline specific and deprecate assigned_meshes draw target
for (handle, mut renderable) in query.iter_mut(world) {
setup_mesh_resource(
render_resources,
&mut renderable.render_resource_assignments,
&vertex_buffer_descriptor,
*handle,
&meshes,
);
}
},
)
}
#[cfg(test)]
mod tests {
use crate::{Vertex, pipeline::state_descriptors::PrimitiveTopology, shader::AsUniforms};

View file

@ -1,6 +1,5 @@
mod ops;
mod pass;
pub mod passes;
mod render_pass;
pub use ops::*;

View file

@ -1,57 +0,0 @@
use crate::{
pass::{
LoadOp, PassDescriptor, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor, StoreOp, TextureAttachment
},
render_graph::RenderGraphBuilder,
render_resource::{resource_name, resource_providers::FrameTextureResourceProvider},
texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage},
Color,
};
pub trait ForwardPassBuilder {
fn add_forward_pass(&mut self) -> &mut Self;
}
impl<'a, 'b, 'c> ForwardPassBuilder for RenderGraphBuilder<'a, 'b, 'c> {
fn add_forward_pass(&mut self) -> &mut Self {
self.add_resource_provider(FrameTextureResourceProvider::new(
resource_name::texture::DEPTH,
TextureDescriptor {
size: Extent3d {
depth: 1,
width: 1,
height: 1,
},
array_layer_count: 1,
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
format: TextureFormat::Depth32Float, // PERF: vulkan recommends using 24 bit depth for better performance
usage: TextureUsage::OUTPUT_ATTACHMENT,
},
))
.add_pass(
resource_name::pass::MAIN,
PassDescriptor {
color_attachments: vec![RenderPassColorAttachmentDescriptor {
attachment: TextureAttachment::Name(resource_name::texture::SWAP_CHAIN.to_string()),
resolve_target: None,
load_op: LoadOp::Clear,
store_op: StoreOp::Store,
clear_color: Color::rgb(0.1, 0.1, 0.1),
}],
depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor {
attachment: TextureAttachment::Name(resource_name::texture::DEPTH.to_string()),
depth_load_op: LoadOp::Clear,
depth_store_op: StoreOp::Store,
stencil_load_op: LoadOp::Clear,
stencil_store_op: StoreOp::Store,
clear_depth: 1.0,
clear_stencil: 0,
}),
sample_count: 1,
},
)
}
}

View file

@ -1,7 +1,7 @@
use crate::{
pipeline::PipelineDescriptor,
render_resource::{RenderResource, RenderResourceAssignments},
renderer_2::RenderContext,
renderer::RenderContext,
};
use bevy_asset::Handle;
use std::ops::Range;

View file

@ -3,7 +3,6 @@ mod binding;
mod pipeline;
mod pipeline_compiler;
mod pipeline_layout;
pub mod pipelines;
pub mod state_descriptors;
mod vertex_buffer_descriptor;
mod vertex_format;

View file

@ -1,18 +1,12 @@
use super::{
state_descriptors::{
BlendDescriptor, ColorStateDescriptor, ColorWrite, CompareFunction, CullMode,
DepthStencilStateDescriptor, FrontFace, IndexFormat, PrimitiveTopology,
RasterizationStateDescriptor, StencilStateFaceDescriptor,
BlendDescriptor, BlendFactor, BlendOperation, ColorStateDescriptor, ColorWrite,
CompareFunction, CullMode, DepthStencilStateDescriptor, FrontFace, IndexFormat,
PrimitiveTopology, RasterizationStateDescriptor, StencilStateFaceDescriptor,
},
BindGroupDescriptor, PipelineLayout, VertexBufferDescriptor,
PipelineLayout,
};
use crate::{
render_resource::resource_name,
shader::{Shader, ShaderStages},
texture::TextureFormat,
};
use bevy_asset::{AssetStorage, Handle};
use crate::{shader::ShaderStages, texture::TextureFormat};
// TODO: consider removing this in favor of Option<Layout>
#[derive(Clone, Debug)]
@ -30,7 +24,6 @@ pub enum DescriptorType<T> {
#[derive(Clone, Debug)]
pub struct PipelineDescriptor {
pub name: Option<String>,
pub draw_targets: Vec<String>,
pub layout: PipelineLayoutType,
pub shader_stages: ShaderStages,
pub rasterization_state: Option<RasterizationStateDescriptor>,
@ -62,13 +55,12 @@ pub struct PipelineDescriptor {
}
impl PipelineDescriptor {
pub fn new_new(shader_stages: ShaderStages) -> Self {
pub fn new(shader_stages: ShaderStages) -> Self {
PipelineDescriptor {
name: None,
layout: PipelineLayoutType::Reflected(None),
color_states: Vec::new(),
depth_stencil_state: None,
draw_targets: Vec::new(),
shader_stages,
rasterization_state: None,
primitive_topology: PrimitiveTopology::TriangleList,
@ -79,14 +71,15 @@ impl PipelineDescriptor {
}
}
fn new(name: Option<&str>, vertex_shader: Handle<Shader>) -> Self {
pub fn default_config(shader_stages: ShaderStages) -> Self {
PipelineDescriptor {
name: name.map(|name| name.to_string()),
name: None,
primitive_topology: PrimitiveTopology::TriangleList,
layout: PipelineLayoutType::Reflected(None),
color_states: Vec::new(),
depth_stencil_state: None,
draw_targets: Vec::new(),
shader_stages: ShaderStages::new(vertex_shader),
index_format: IndexFormat::Uint16,
sample_count: 1,
sample_mask: !0,
alpha_to_coverage_enabled: false,
rasterization_state: Some(RasterizationStateDescriptor {
front_face: FrontFace::Ccw,
cull_mode: CullMode::Back,
@ -94,11 +87,30 @@ impl PipelineDescriptor {
depth_bias_slope_scale: 0.0,
depth_bias_clamp: 0.0,
}),
primitive_topology: PrimitiveTopology::TriangleList,
index_format: IndexFormat::Uint16,
sample_count: 1,
sample_mask: !0,
alpha_to_coverage_enabled: false,
depth_stencil_state: Some(DepthStencilStateDescriptor {
format: TextureFormat::Depth32Float,
depth_write_enabled: true,
depth_compare: CompareFunction::Less,
stencil_front: StencilStateFaceDescriptor::IGNORE,
stencil_back: StencilStateFaceDescriptor::IGNORE,
stencil_read_mask: 0,
stencil_write_mask: 0,
}),
color_states: vec![ColorStateDescriptor {
format: TextureFormat::Bgra8UnormSrgb,
color_blend: BlendDescriptor {
src_factor: BlendFactor::SrcAlpha,
dst_factor: BlendFactor::OneMinusSrcAlpha,
operation: BlendOperation::Add,
},
alpha_blend: BlendDescriptor {
src_factor: BlendFactor::One,
dst_factor: BlendFactor::One,
operation: BlendOperation::Add,
},
write_mask: ColorWrite::ALL,
}],
shader_stages,
}
}
@ -116,159 +128,3 @@ impl PipelineDescriptor {
}
}
}
impl PipelineDescriptor {
pub fn build<'a>(
name: &'a str,
shader_storage: &'a mut AssetStorage<Shader>,
) -> PipelineBuilder<'a> {
PipelineBuilder::new(name, shader_storage)
}
}
pub struct PipelineBuilder<'a> {
pipeline: Option<PipelineDescriptor>,
shader_storage: &'a mut AssetStorage<Shader>,
name: &'a str,
}
impl<'a> PipelineBuilder<'a> {
pub fn new(name: &'a str, shader_storage: &'a mut AssetStorage<Shader>) -> Self {
PipelineBuilder {
pipeline: None,
shader_storage,
name,
}
}
pub fn finish(&mut self) -> PipelineDescriptor {
self.pipeline.take().unwrap()
}
pub fn with_vertex_shader(&mut self, vertex_shader: Shader) -> &mut Self {
let vertex_shader_handle = self.shader_storage.add(vertex_shader);
self.pipeline = Some(PipelineDescriptor::new(
Some(&self.name),
vertex_shader_handle,
));
self
}
pub fn with_fragment_shader(&mut self, fragment_shader: Shader) -> &mut Self {
let fragment_shader_handle = self.shader_storage.add(fragment_shader);
self.pipeline.as_mut().unwrap().shader_stages.fragment = Some(fragment_shader_handle);
self
}
pub fn add_color_state(&mut self, color_state_descriptor: ColorStateDescriptor) -> &mut Self {
self.pipeline
.as_mut()
.unwrap()
.color_states
.push(color_state_descriptor);
self
}
pub fn with_depth_stencil_state(
&mut self,
depth_stencil_state: DepthStencilStateDescriptor,
) -> &mut Self {
if let Some(_) = self.pipeline.as_ref().unwrap().depth_stencil_state {
panic!("Depth stencil state has already been set");
}
self.pipeline.as_mut().unwrap().depth_stencil_state = Some(depth_stencil_state);
self
}
pub fn add_bind_group(&mut self, bind_group: BindGroupDescriptor) -> &mut Self {
let pipeline = self.pipeline.as_mut().unwrap();
if let PipelineLayoutType::Reflected(_) = pipeline.layout {
pipeline.layout = PipelineLayoutType::Manual(PipelineLayout::default());
}
if let PipelineLayoutType::Manual(ref mut layout) = pipeline.layout {
layout.bind_groups.push(bind_group);
}
self
}
pub fn add_vertex_buffer_descriptor(
&mut self,
vertex_buffer_descriptor: VertexBufferDescriptor,
) -> &mut Self {
let pipeline = self.pipeline.as_mut().unwrap();
if let PipelineLayoutType::Reflected(_) = pipeline.layout {
pipeline.layout = PipelineLayoutType::Manual(PipelineLayout::default());
}
if let PipelineLayoutType::Manual(ref mut layout) = pipeline.layout {
layout
.vertex_buffer_descriptors
.push(vertex_buffer_descriptor);
}
self
}
pub fn with_index_format(&mut self, index_format: IndexFormat) -> &mut Self {
self.pipeline.as_mut().unwrap().index_format = index_format;
self
}
pub fn add_draw_target(&mut self, name: &str) -> &mut Self {
self.pipeline
.as_mut()
.unwrap()
.draw_targets
.push(name.to_string());
self
}
pub fn with_rasterization_state(
&mut self,
rasterization_state: RasterizationStateDescriptor,
) -> &mut Self {
self.pipeline.as_mut().unwrap().rasterization_state = Some(rasterization_state);
self
}
pub fn with_primitive_topology(&mut self, primitive_topology: PrimitiveTopology) -> &mut Self {
self.pipeline.as_mut().unwrap().primitive_topology = primitive_topology;
self
}
pub fn with_sample_count(&mut self, sample_count: u32) -> &mut Self {
self.pipeline.as_mut().unwrap().sample_count = sample_count;
self
}
pub fn with_alpha_to_coverage_enabled(&mut self, alpha_to_coverage_enabled: bool) -> &mut Self {
self.pipeline.as_mut().unwrap().alpha_to_coverage_enabled = alpha_to_coverage_enabled;
self
}
pub fn with_sample_mask(&mut self, sample_mask: u32) -> &mut Self {
self.pipeline.as_mut().unwrap().sample_mask = sample_mask;
self
}
pub fn with_default_config(&mut self) -> &mut Self {
self.with_depth_stencil_state(DepthStencilStateDescriptor {
format: TextureFormat::Depth32Float,
depth_write_enabled: true,
depth_compare: CompareFunction::Less,
stencil_front: StencilStateFaceDescriptor::IGNORE,
stencil_back: StencilStateFaceDescriptor::IGNORE,
stencil_read_mask: 0,
stencil_write_mask: 0,
})
.add_color_state(ColorStateDescriptor {
format: TextureFormat::Bgra8UnormSrgb,
color_blend: BlendDescriptor::REPLACE,
alpha_blend: BlendDescriptor::REPLACE,
write_mask: ColorWrite::ALL,
})
.add_draw_target(resource_name::draw_target::ASSIGNED_MESHES)
}
}

View file

@ -6,7 +6,7 @@ use crate::{
render_resource::{
BufferInfo, RenderResourceAssignments, RenderResourceAssignmentsId, ResourceInfo,
},
renderer_2::{RenderResourceContext, GlobalRenderResourceContext},
renderer::{RenderResourceContext, GlobalRenderResourceContext},
shader::{Shader, ShaderSource},
Renderable,
};

View file

@ -1,19 +0,0 @@
#version 450
layout(location = 0) in vec3 v_Position;
layout(location = 1) in vec3 v_Normal;
layout(location = 2) in vec2 v_Uv;
layout(location = 0) out vec4 o_Target;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 1) uniform StandardMaterial_albedo {
vec4 Albedo;
};
void main() {
o_Target = Albedo;
}

View file

@ -1,27 +0,0 @@
#version 450
layout(location = 0) in vec3 Vertex_Position;
layout(location = 1) in vec3 Vertex_Normal;
layout(location = 2) in vec2 Vertex_Uv;
layout(location = 0) out vec3 v_Position;
layout(location = 1) out vec3 v_Normal;
layout(location = 2) out vec2 v_Uv;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 0) uniform Object {
mat4 Model;
};
layout(set = 1, binding = 1) uniform StandardMaterial_albedo {
vec4 Albedo;
};
void main() {
v_Normal = mat3(Model) * Vertex_Normal;
v_Position = (Model * vec4(Vertex_Position, 1.0)).xyz;
gl_Position = ViewProj * v_Position;
}

View file

@ -1,54 +0,0 @@
use crate::{
pipeline::state_descriptors::{
BlendDescriptor, ColorStateDescriptor, ColorWrite, CompareFunction, CullMode,
DepthStencilStateDescriptor, FrontFace, RasterizationStateDescriptor,
StencilStateFaceDescriptor,
},
render_graph::RenderGraphBuilder,
render_resource::resource_name,
shader::{Shader, ShaderStage},
texture::TextureFormat,
};
pub trait ForwardFlatPipelineBuilder {
fn add_forward_flat_pipeline(&mut self) -> &mut Self;
}
impl<'a, 'b, 'c> ForwardFlatPipelineBuilder for RenderGraphBuilder<'a, 'b, 'c> {
fn add_forward_flat_pipeline(&mut self) -> &mut Self {
self.add_pipeline(resource_name::pipeline::FORWARD_FLAT, |builder| {
builder
.with_vertex_shader(Shader::from_glsl(
ShaderStage::Vertex,
include_str!("forward_flat.vert"),
))
.with_fragment_shader(Shader::from_glsl(
ShaderStage::Fragment,
include_str!("forward_flat.frag"),
))
.with_rasterization_state(RasterizationStateDescriptor {
front_face: FrontFace::Ccw,
cull_mode: CullMode::Back,
depth_bias: 0,
depth_bias_slope_scale: 0.0,
depth_bias_clamp: 0.0,
})
.with_depth_stencil_state(DepthStencilStateDescriptor {
format: TextureFormat::Depth32Float,
depth_write_enabled: true,
depth_compare: CompareFunction::Less,
stencil_front: StencilStateFaceDescriptor::IGNORE,
stencil_back: StencilStateFaceDescriptor::IGNORE,
stencil_read_mask: 0,
stencil_write_mask: 0,
})
.add_color_state(ColorStateDescriptor {
format: TextureFormat::Bgra8UnormSrgb,
color_blend: BlendDescriptor::REPLACE,
alpha_blend: BlendDescriptor::REPLACE,
write_mask: ColorWrite::ALL,
})
.add_draw_target(resource_name::draw_target::MESHES);
})
}
}

View file

@ -1,7 +0,0 @@
mod forward;
mod forward_flat;
mod ui;
pub use forward::*;
pub use forward_flat::*;
pub use ui::*;

View file

@ -1,61 +0,0 @@
use crate::{
pipeline::state_descriptors::{
BlendDescriptor, BlendFactor, BlendOperation, ColorStateDescriptor, ColorWrite,
CompareFunction, CullMode, DepthStencilStateDescriptor, FrontFace,
RasterizationStateDescriptor, StencilStateFaceDescriptor,
},
render_graph::RenderGraphBuilder,
render_resource::resource_name,
shader::{Shader, ShaderStage},
texture::TextureFormat,
};
pub trait UiPipelineBuilder {
fn add_ui_pipeline(&mut self) -> &mut Self;
}
impl<'a, 'b, 'c> UiPipelineBuilder for RenderGraphBuilder<'a, 'b, 'c> {
fn add_ui_pipeline(&mut self) -> &mut Self {
self.add_pipeline(resource_name::pipeline::UI, |builder| {
builder
.with_vertex_shader(Shader::from_glsl(
ShaderStage::Vertex,
include_str!("ui.vert"),
))
.with_fragment_shader(Shader::from_glsl(
ShaderStage::Fragment,
include_str!("ui.frag"),
))
.with_rasterization_state(RasterizationStateDescriptor {
front_face: FrontFace::Ccw,
cull_mode: CullMode::None,
depth_bias: 0,
depth_bias_slope_scale: 0.0,
depth_bias_clamp: 0.0,
})
.with_depth_stencil_state(DepthStencilStateDescriptor {
format: TextureFormat::Depth32Float,
depth_write_enabled: false,
depth_compare: CompareFunction::Always,
stencil_front: StencilStateFaceDescriptor::IGNORE,
stencil_back: StencilStateFaceDescriptor::IGNORE,
stencil_read_mask: 0,
stencil_write_mask: 0,
})
.add_color_state(ColorStateDescriptor {
format: TextureFormat::Bgra8UnormSrgb,
color_blend: BlendDescriptor {
src_factor: BlendFactor::SrcAlpha,
dst_factor: BlendFactor::OneMinusSrcAlpha,
operation: BlendOperation::Add,
},
alpha_blend: BlendDescriptor {
src_factor: BlendFactor::One,
dst_factor: BlendFactor::One,
operation: BlendOperation::Add,
},
write_mask: ColorWrite::ALL,
})
.add_draw_target(resource_name::draw_target::UI);
})
}
}

View file

@ -1,4 +1,4 @@
use crate::{render_resource::RenderResource, renderer_2::RenderContext, texture::Extent3d};
use crate::{render_resource::RenderResource, renderer::RenderContext, texture::Extent3d};
use std::sync::{Arc, Mutex};
pub enum Command {

View file

@ -3,14 +3,14 @@ use legion::prelude::{Executor, Resources, Schedulable};
use std::{borrow::Cow, collections::HashMap, fmt::Debug};
#[derive(Default)]
pub struct RenderGraph2 {
pub struct RenderGraph {
nodes: HashMap<NodeId, NodeState>,
node_names: HashMap<Cow<'static, str>, NodeId>,
new_node_systems: Vec<Box<dyn Schedulable>>,
node_system_executor: Option<Executor>,
}
impl RenderGraph2 {
impl RenderGraph {
pub fn add_node<T>(&mut self, node: T) -> NodeId
where
T: Node,
@ -41,7 +41,7 @@ impl RenderGraph2 {
self.add_node(node)
}
pub fn add_system_node_named<T>(&mut self, name: impl Into<Cow<'static, str>>, node: T, resources: &mut Resources) -> NodeId
pub fn add_system_node_named<T>(&mut self, name: impl Into<Cow<'static, str>>, node: T, resources: &Resources) -> NodeId
where
T: SystemNode + 'static,
{
@ -293,7 +293,7 @@ impl RenderGraph2 {
}
}
impl Debug for RenderGraph2 {
impl Debug for RenderGraph {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for node in self.iter_nodes() {
writeln!(f, "{:?}", node.id)?;
@ -307,11 +307,11 @@ impl Debug for RenderGraph2 {
#[cfg(test)]
mod tests {
use super::RenderGraph2;
use super::RenderGraph;
use crate::{
render_graph_2::{Edge, Node, NodeId, RenderGraphError, ResourceSlotInfo, ResourceSlots},
render_graph::{Edge, Node, NodeId, RenderGraphError, ResourceSlotInfo, ResourceSlots},
render_resource::ResourceInfo,
renderer_2::RenderContext,
renderer::RenderContext,
};
use legion::prelude::{Resources, World};
use std::{collections::HashSet, iter::FromIterator};
@ -362,7 +362,7 @@ mod tests {
#[test]
pub fn test_graph_edges() {
let mut graph = RenderGraph2::default();
let mut graph = RenderGraph::default();
let a_id = graph.add_node_named("A", TestNode::new(0, 1));
let b_id = graph.add_node_named("B", TestNode::new(0, 1));
let c_id = graph.add_node_named("C", TestNode::new(1, 1));
@ -372,7 +372,7 @@ mod tests {
graph.add_node_edge("B", "C").unwrap();
graph.add_slot_edge("C", 0, "D", 0).unwrap();
fn input_nodes(name: &'static str, graph: &RenderGraph2) -> HashSet<NodeId> {
fn input_nodes(name: &'static str, graph: &RenderGraph) -> HashSet<NodeId> {
graph
.iter_node_inputs(name)
.unwrap()
@ -380,7 +380,7 @@ mod tests {
.collect::<HashSet<NodeId>>()
}
fn output_nodes(name: &'static str, graph: &RenderGraph2) -> HashSet<NodeId> {
fn output_nodes(name: &'static str, graph: &RenderGraph) -> HashSet<NodeId> {
graph
.iter_node_outputs(name)
.unwrap()
@ -434,7 +434,7 @@ mod tests {
}
}
let mut graph = RenderGraph2::default();
let mut graph = RenderGraph::default();
graph.add_node_named("A", MyNode { value: 42 });
@ -451,7 +451,7 @@ mod tests {
#[test]
pub fn test_slot_already_occupied() {
let mut graph = RenderGraph2::default();
let mut graph = RenderGraph::default();
graph.add_node_named("A", TestNode::new(0, 1));
graph.add_node_named("B", TestNode::new(0, 1));
@ -471,7 +471,7 @@ mod tests {
#[test]
pub fn test_edge_already_exists() {
let mut graph = RenderGraph2::default();
let mut graph = RenderGraph::default();
graph.add_node_named("A", TestNode::new(0, 1));
graph.add_node_named("B", TestNode::new(1, 0));

View file

@ -1,5 +1,40 @@
mod render_graph;
mod render_graph_builder;
pub mod nodes;
mod command;
mod graph;
mod node;
mod edge;
mod node_slot;
mod schedule;
pub use command::*;
pub use graph::*;
pub use node::*;
pub use edge::*;
pub use node_slot::*;
pub use schedule::*;
pub use render_graph::*;
pub use render_graph_builder::*;
use thiserror::Error;
#[derive(Error, Debug, Eq, PartialEq)]
pub enum RenderGraphError {
#[error("Node does not exist")]
InvalidNode(NodeLabel),
#[error("Node slot does not exist")]
InvalidNodeSlot(SlotLabel),
#[error("Node does not match the given type")]
WrongNodeType,
#[error("Attempted to connect a node output slot to an incompatible input node slot")]
MismatchedNodeSlots {
output_node: NodeId,
output_slot: usize,
input_node: NodeId,
input_slot: usize,
},
#[error("Attempted to add an edge that already exists")]
EdgeAlreadyExists(Edge),
#[error("Node has an unconnected input slot.")]
UnconnectedNodeInputSlot { node: NodeId, input_slot: usize },
#[error("Node has an unconnected output slot.")]
UnconnectedNodeOutputSlot { node: NodeId, output_slot: usize },
#[error("Node input slot already occupied")]
NodeInputSlotAlreadyOccupied { node: NodeId, input_slot: usize, occupied_by_node: NodeId },
}

View file

@ -1,5 +1,5 @@
use super::{Edge, RenderGraphError, ResourceSlotInfo, ResourceSlots};
use crate::renderer_2::RenderContext;
use crate::renderer::RenderContext;
use downcast_rs::{impl_downcast, Downcast};
use legion::prelude::{Resources, Schedulable, World};
use std::{borrow::Cow, fmt::Debug};
@ -36,7 +36,7 @@ pub trait Node: Downcast + Send + Sync + 'static {
impl_downcast!(Node);
pub trait SystemNode: Node {
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable>;
fn get_system(&self, resources: &Resources) -> Box<dyn Schedulable>;
}
pub struct Edges {

View file

@ -4,12 +4,10 @@ mod window_texture_node;
mod window_swapchain_node;
mod pass_node;
mod uniform_node;
mod lights_node;
pub use camera_node::*;
pub use camera2d_node::*;
pub use window_texture_node::*;
pub use window_swapchain_node::*;
pub use pass_node::*;
pub use uniform_node::*;
pub use lights_node::*;
pub use uniform_node::*;

View file

@ -3,9 +3,9 @@ use bevy_window::WindowResized;
use crate::{
camera::{ActiveCamera2d, Camera},
render_graph_2::{CommandQueue, Node, SystemNode, ResourceSlots},
render_graph::{CommandQueue, Node, SystemNode, ResourceSlots},
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResourceAssignments},
renderer_2::{GlobalRenderResourceContext, RenderContext},
renderer::{GlobalRenderResourceContext, RenderContext},
};
use bevy_transform::components::LocalToWorld;
@ -31,7 +31,7 @@ impl Node for Camera2dNode {
}
impl SystemNode for Camera2dNode {
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable> {
fn get_system(&self, resources: &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>();

View file

@ -1,7 +1,7 @@
use crate::{
render_graph_2::{CommandQueue, Node, SystemNode, ResourceSlots},
render_graph::{CommandQueue, Node, SystemNode, ResourceSlots},
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResourceAssignments},
renderer_2::{GlobalRenderResourceContext, RenderContext},
renderer::{GlobalRenderResourceContext, RenderContext},
ActiveCamera, Camera,
};
@ -30,7 +30,7 @@ impl Node for CameraNode {
}
impl SystemNode for CameraNode {
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable> {
fn get_system(&self, resources: &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>();

View file

@ -2,9 +2,9 @@ use crate::{
draw_target::DrawTarget,
pass::{PassDescriptor, TextureAttachment},
pipeline::{PipelineCompiler, PipelineDescriptor},
render_graph_2::{Node, ResourceSlotInfo, ResourceSlots},
render_graph::{Node, ResourceSlotInfo, ResourceSlots},
render_resource::{RenderResourceAssignments, ResourceInfo},
renderer_2::RenderContext,
renderer::RenderContext,
shader::Shader,
};
use bevy_asset::{AssetStorage, Handle};

View file

@ -1,11 +1,11 @@
use crate::{
pipeline::VertexBufferDescriptors,
render_graph_2::{CommandQueue, Node, ResourceSlots, SystemNode},
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
render_resource::{
BufferArrayInfo, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
RenderResourceAssignmentsId, ResourceInfo,
},
renderer_2::{GlobalRenderResourceContext, RenderContext, RenderResourceContext},
renderer::{GlobalRenderResourceContext, RenderContext, RenderResourceContext},
shader::{AsUniforms, FieldBindType},
texture, Renderable,
};
@ -332,6 +332,55 @@ where
}
}
// TODO: use something like this to remove redundancy between AssetUniformNode and UniformNode
// fn update_uniforms<T>(
// render_resource_context: &dyn RenderResourceContext,
// staging_buffer_resource: &mut Option<RenderResource>,
// uniform_buffer_arrays: &mut UniformBufferArrays<T>,
// command_queue: &mut CommandQueue,
// dynamic_uniforms: bool,
// increment_uniform_counts: impl Fn(),
// update_textures: impl Fn(),
// update_uniform_buffers: impl Fn(&mut [u8]),
// ) where
// T: AsUniforms,
// {
// if let Some(staging_buffer_resource) = staging_buffer_resource {
// render_resource_context.remove_buffer(*staging_buffer_resource);
// }
// *staging_buffer_resource = None;
// uniform_buffer_arrays.reset_new_item_counts();
// increment_uniform_counts();
// uniform_buffer_arrays.setup_buffer_arrays(render_resource_context, dynamic_uniforms);
// let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets();
// update_textures();
// if staging_buffer_size == 0 {
// let mut staging_buffer: [u8; 0] = [];
// update_uniform_buffers(&mut staging_buffer);
// } else {
// let staging_buffer = render_resource_context.create_buffer_mapped(
// BufferInfo {
// buffer_usage: BufferUsage::COPY_SRC,
// size: staging_buffer_size,
// ..Default::default()
// },
// &mut |staging_buffer, _render_resources| {
// update_uniform_buffers(staging_buffer);
// },
// );
// uniform_buffer_arrays
// .copy_staging_buffer_to_final_buffers(command_queue, staging_buffer);
// *staging_buffer_resource = Some(staging_buffer);
// }
// }
#[derive(Default)]
pub struct UniformNode<T>
where
@ -353,90 +402,6 @@ where
_marker: PhantomData::default(),
}
}
fn initialize_vertex_buffer_descriptor(
vertex_buffer_descriptors: &mut VertexBufferDescriptors,
) {
let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor();
if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor {
if let None = vertex_buffer_descriptors.get(&vertex_buffer_descriptor.name) {
vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone());
}
}
}
fn setup_uniform_texture_resources(
uniforms: &T,
command_queue: &mut CommandQueue,
texture_storage: &AssetStorage<Texture>,
render_resource_context: &dyn RenderResourceContext,
render_resource_assignments: &mut RenderResourceAssignments,
) {
for field_info in T::get_field_infos().iter() {
let bind_type = uniforms.get_field_bind_type(&field_info.name);
match bind_type {
Some(FieldBindType::Texture) => {
let texture_handle = uniforms
.get_uniform_texture(&field_info.texture_name)
.unwrap();
let (texture_resource, sampler_resource) = match render_resource_context
.get_asset_resource(texture_handle, texture::TEXTURE_ASSET_INDEX)
{
Some(texture_resource) => (
texture_resource,
render_resource_context
.get_asset_resource(texture_handle, texture::SAMPLER_ASSET_INDEX)
.unwrap(),
),
None => {
let texture = texture_storage.get(&texture_handle).unwrap();
let texture_descriptor: TextureDescriptor = texture.into();
let texture_resource =
render_resource_context.create_texture(&texture_descriptor);
// TODO: queue texture copy
// .create_texture_with_data(&texture_descriptor, &texture.data);
let texture_buffer = render_resource_context.create_buffer_with_data(BufferInfo {
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
}, &texture.data);
command_queue.copy_buffer_to_texture(
texture_buffer,
0,
(4 * texture.width) as u32,
texture_resource,
[0, 0, 0],
0,
0,
texture_descriptor.size.clone(),
);
command_queue.free_buffer(texture_buffer);
let sampler_descriptor: SamplerDescriptor = texture.into();
let sampler_resource =
render_resource_context.create_sampler(&sampler_descriptor);
render_resource_context.set_asset_resource(
texture_handle,
texture_resource,
0,
);
render_resource_context.set_asset_resource(
texture_handle,
sampler_resource,
1,
);
(texture_resource, sampler_resource)
}
};
render_resource_assignments.set(field_info.texture_name, texture_resource);
render_resource_assignments.set(field_info.sampler_name, sampler_resource);
}
_ => {}
}
}
}
}
impl<T> Node for UniformNode<T>
@ -459,33 +424,25 @@ impl<T> SystemNode for UniformNode<T>
where
T: AsUniforms,
{
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable> {
fn get_system(&self, resources: &Resources) -> Box<dyn Schedulable> {
let mut command_queue = self.command_queue.clone();
let mut uniform_buffer_arrays = UniformBufferArrays::<T>::new();
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
let dynamic_uniforms = self.dynamic_uniforms;
let mut staging_buffer_resource = None;
UniformNode::<T>::initialize_vertex_buffer_descriptor(&mut vertex_buffer_descriptors);
initialize_vertex_buffer_descriptor::<T>(&mut vertex_buffer_descriptors);
// TODO: maybe run "update" here
SystemBuilder::new("uniform_resource_provider")
.read_resource::<AssetStorage<T>>()
.read_resource::<AssetStorage<Texture>>()
.read_resource::<GlobalRenderResourceContext>()
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
.with_query(<(Read<T>, Read<Renderable>)>::query())
.with_query(<(Read<Handle<T>>, Read<Renderable>)>::query())
.with_query(<(Read<T>, Write<Renderable>)>::query())
.with_query(<(Read<Handle<T>>, Write<Renderable>)>::query())
.build(
move |_,
world,
(assets, textures, global_render_resource_context),
(
read_resource_query,
read_handle_query,
write_resource_query,
write_handle_query,
)| {
(textures, global_render_resource_context),
(read_uniform_query, write_uniform_query)| {
let render_resource_context = &*global_render_resource_context.context;
if let Some(staging_buffer_resource) = staging_buffer_resource {
render_resource_context.remove_buffer(staging_buffer_resource);
@ -494,7 +451,7 @@ where
uniform_buffer_arrays.reset_new_item_counts();
// update uniforms info
for (uniforms, renderable) in read_resource_query.iter(world) {
for (uniforms, renderable) in read_uniform_query.iter(world) {
if !renderable.is_visible {
return;
}
@ -506,6 +463,160 @@ where
}
}
uniform_buffer_arrays
.setup_buffer_arrays(render_resource_context, dynamic_uniforms);
let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets();
for (uniforms, mut renderable) in write_uniform_query.iter_mut(world) {
if !renderable.is_visible {
return;
}
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
setup_uniform_texture_resources::<T>(
&uniforms,
&mut command_queue,
textures,
render_resource_context,
&mut renderable.render_resource_assignments,
)
}
}
if staging_buffer_size == 0 {
let mut staging_buffer: [u8; 0] = [];
for (uniforms, mut renderable) in write_uniform_query.iter_mut(world) {
if !renderable.is_visible {
return;
}
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
uniform_buffer_arrays.setup_uniform_buffer_resources(
&uniforms,
dynamic_uniforms,
render_resource_context,
&mut renderable.render_resource_assignments,
&mut staging_buffer,
);
}
}
} else {
let staging_buffer = render_resource_context.create_buffer_mapped(
BufferInfo {
buffer_usage: BufferUsage::COPY_SRC,
size: staging_buffer_size,
..Default::default()
},
&mut |mut staging_buffer, _render_resources| {
for (uniforms, mut renderable) in
write_uniform_query.iter_mut(world)
{
if !renderable.is_visible {
return;
}
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
uniform_buffer_arrays.setup_uniform_buffer_resources(
&uniforms,
dynamic_uniforms,
render_resource_context,
&mut renderable.render_resource_assignments,
&mut staging_buffer,
);
}
}
},
);
uniform_buffer_arrays.copy_staging_buffer_to_final_buffers(
&mut command_queue,
staging_buffer,
);
staging_buffer_resource = Some(staging_buffer);
}
},
)
}
}
#[derive(Default)]
pub struct AssetUniformNode<T>
where
T: AsUniforms,
{
command_queue: CommandQueue,
dynamic_uniforms: bool,
_marker: PhantomData<T>,
}
impl<T> AssetUniformNode<T>
where
T: AsUniforms,
{
pub fn new(dynamic_uniforms: bool) -> Self {
AssetUniformNode {
command_queue: CommandQueue::default(),
dynamic_uniforms,
_marker: PhantomData::default(),
}
}
}
impl<T> Node for AssetUniformNode<T>
where
T: AsUniforms,
{
fn update(
&mut self,
_world: &World,
_resources: &Resources,
render_context: &mut dyn RenderContext,
_input: &ResourceSlots,
_output: &mut ResourceSlots,
) {
self.command_queue.execute(render_context);
}
}
impl<T> SystemNode for AssetUniformNode<T>
where
T: AsUniforms,
{
fn get_system(&self, resources: &Resources) -> Box<dyn Schedulable> {
let mut command_queue = self.command_queue.clone();
let mut uniform_buffer_arrays = UniformBufferArrays::<T>::new();
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
let dynamic_uniforms = self.dynamic_uniforms;
let mut staging_buffer_resource = None;
initialize_vertex_buffer_descriptor::<T>(&mut vertex_buffer_descriptors);
// TODO: maybe run "update" here
SystemBuilder::new("uniform_resource_provider")
.read_resource::<AssetStorage<T>>()
.read_resource::<AssetStorage<Texture>>()
.read_resource::<GlobalRenderResourceContext>()
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
.with_query(<(Read<Handle<T>>, Read<Renderable>)>::query())
.with_query(<(Read<Handle<T>>, Write<Renderable>)>::query())
.build(
move |_,
world,
(assets, textures, global_render_resource_context),
(read_handle_query, write_handle_query)| {
let render_resource_context = &*global_render_resource_context.context;
if let Some(staging_buffer_resource) = staging_buffer_resource {
render_resource_context.remove_buffer(staging_buffer_resource);
}
staging_buffer_resource = None;
uniform_buffer_arrays.reset_new_item_counts();
// update uniform handles info
for (handle, renderable) in read_handle_query.iter(world) {
if !renderable.is_visible {
@ -527,24 +638,6 @@ where
.setup_buffer_arrays(render_resource_context, dynamic_uniforms);
let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets();
for (uniforms, mut renderable) in write_resource_query.iter_mut(world) {
if !renderable.is_visible {
return;
}
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
Self::setup_uniform_texture_resources(
&uniforms,
&mut command_queue,
textures,
render_resource_context,
&mut renderable.render_resource_assignments,
)
}
}
for (handle, mut renderable) in write_handle_query.iter_mut(world) {
if !renderable.is_visible {
return;
@ -556,7 +649,7 @@ where
let uniforms = assets
.get(&handle)
.expect("Handle points to a non-existent resource");
Self::setup_uniform_texture_resources(
setup_uniform_texture_resources::<T>(
&uniforms,
&mut command_queue,
textures,
@ -567,23 +660,6 @@ where
}
if staging_buffer_size == 0 {
let mut staging_buffer: [u8; 0] = [];
for (uniforms, mut renderable) in write_resource_query.iter_mut(world) {
if !renderable.is_visible {
return;
}
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
uniform_buffer_arrays.setup_uniform_buffer_resources(
&uniforms,
dynamic_uniforms,
render_resource_context,
&mut renderable.render_resource_assignments,
&mut staging_buffer,
);
}
}
for (handle, mut renderable) in write_handle_query.iter_mut(world) {
if !renderable.is_visible {
return;
@ -612,25 +688,6 @@ where
..Default::default()
},
&mut |mut staging_buffer, _render_resources| {
for (uniforms, mut renderable) in
write_resource_query.iter_mut(world)
{
if !renderable.is_visible {
return;
}
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
uniform_buffer_arrays.setup_uniform_buffer_resources(
&uniforms,
dynamic_uniforms,
render_resource_context,
&mut renderable.render_resource_assignments,
&mut staging_buffer,
);
}
}
for (handle, mut renderable) in write_handle_query.iter_mut(world) {
if !renderable.is_visible {
return;
@ -665,3 +722,93 @@ where
)
}
}
fn initialize_vertex_buffer_descriptor<T>(vertex_buffer_descriptors: &mut VertexBufferDescriptors)
where
T: AsUniforms,
{
let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor();
if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor {
if let None = vertex_buffer_descriptors.get(&vertex_buffer_descriptor.name) {
vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone());
}
}
}
fn setup_uniform_texture_resources<T>(
uniforms: &T,
command_queue: &mut CommandQueue,
texture_storage: &AssetStorage<Texture>,
render_resource_context: &dyn RenderResourceContext,
render_resource_assignments: &mut RenderResourceAssignments,
) where
T: AsUniforms,
{
for field_info in T::get_field_infos().iter() {
let bind_type = uniforms.get_field_bind_type(&field_info.name);
match bind_type {
Some(FieldBindType::Texture) => {
let texture_handle = uniforms
.get_uniform_texture(&field_info.texture_name)
.unwrap();
let (texture_resource, sampler_resource) = match render_resource_context
.get_asset_resource(texture_handle, texture::TEXTURE_ASSET_INDEX)
{
Some(texture_resource) => (
texture_resource,
render_resource_context
.get_asset_resource(texture_handle, texture::SAMPLER_ASSET_INDEX)
.unwrap(),
),
None => {
let texture = texture_storage.get(&texture_handle).unwrap();
let texture_descriptor: TextureDescriptor = texture.into();
let texture_resource =
render_resource_context.create_texture(&texture_descriptor);
// TODO: queue texture copy
// .create_texture_with_data(&texture_descriptor, &texture.data);
let texture_buffer = render_resource_context.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
},
&texture.data,
);
command_queue.copy_buffer_to_texture(
texture_buffer,
0,
(4 * texture.width) as u32,
texture_resource,
[0, 0, 0],
0,
0,
texture_descriptor.size.clone(),
);
command_queue.free_buffer(texture_buffer);
let sampler_descriptor: SamplerDescriptor = texture.into();
let sampler_resource =
render_resource_context.create_sampler(&sampler_descriptor);
render_resource_context.set_asset_resource(
texture_handle,
texture_resource,
0,
);
render_resource_context.set_asset_resource(
texture_handle,
sampler_resource,
1,
);
(texture_resource, sampler_resource)
}
};
render_resource_assignments.set(field_info.texture_name, texture_resource);
render_resource_assignments.set(field_info.sampler_name, sampler_resource);
}
_ => {}
}
}
}

View file

@ -1,7 +1,7 @@
use crate::{
render_graph_2::{Node, ResourceSlots, ResourceSlotInfo},
render_graph::{Node, ResourceSlots, ResourceSlotInfo},
render_resource::ResourceInfo,
renderer_2::RenderContext,
renderer::RenderContext,
};
use bevy_app::{EventReader, Events};
use bevy_window::{WindowCreated, WindowResized, Windows, WindowReference};

View file

@ -1,7 +1,7 @@
use crate::{
render_graph_2::{Node, ResourceSlotInfo, ResourceSlots},
render_graph::{Node, ResourceSlotInfo, ResourceSlots},
render_resource::ResourceInfo,
renderer_2::RenderContext,
renderer::RenderContext,
texture::TextureDescriptor,
};
use bevy_app::{EventReader, Events};

View file

@ -1,98 +0,0 @@
use super::RenderGraphBuilder;
use crate::{
draw_target::DrawTarget,
pass::PassDescriptor,
pipeline::{PipelineCompiler, PipelineDescriptor},
render_resource::ResourceProvider,
renderer_2::RenderContext,
shader::Shader,
texture::TextureDescriptor,
};
use bevy_asset::{AssetStorage, Handle};
use legion::prelude::*;
use std::collections::{HashMap, HashSet};
#[derive(Default)]
pub struct RenderGraph {
pub pipeline_descriptors: HashSet<Handle<PipelineDescriptor>>,
pub pass_descriptors: HashMap<String, PassDescriptor>,
pub pass_pipelines: HashMap<String, Vec<Handle<PipelineDescriptor>>>,
pub resource_providers: Vec<Box<dyn ResourceProvider + Send + Sync>>,
pub queued_textures: Vec<(String, TextureDescriptor)>,
pub draw_targets: HashMap<String, Box<dyn DrawTarget + Send + Sync>>,
}
impl RenderGraph {
pub fn build<'a, 'b, 'c>(
&'c mut self,
pipelines: &'a mut AssetStorage<PipelineDescriptor>,
shaders: &'b mut AssetStorage<Shader>,
) -> RenderGraphBuilder<'a, 'b, 'c> {
RenderGraphBuilder {
pipelines,
shaders,
current_pass: None,
render_graph: self,
}
}
pub fn add_pipeline(&mut self, pass: &str, pipeline: Handle<PipelineDescriptor>) {
self.pipeline_descriptors.insert(pipeline.clone());
if let None = self.pass_pipelines.get(pass) {
self.pass_pipelines.insert(pass.to_string(), Vec::new());
}
let pass_pipelines = self.pass_pipelines.get_mut(pass).unwrap();
pass_pipelines.push(pipeline);
}
pub fn setup_pipeline_draw_targets(
&mut self,
world: &mut World,
resources: &Resources,
render_context: &mut dyn RenderContext,
) {
let shader_storage = resources.get::<AssetStorage<Shader>>().unwrap();
let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap();
for (pass_name, _pass_descriptor) in self.pass_descriptors.iter() {
if let Some(pass_pipelines) = self.pass_pipelines.get(pass_name) {
for pass_pipeline in pass_pipelines.iter() {
if let Some(compiled_pipelines_iter) =
pipeline_compiler.iter_compiled_pipelines(*pass_pipeline)
{
for compiled_pipeline_handle in compiled_pipelines_iter {
let mut pipeline_storage = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let compiled_pipeline_descriptor =
pipeline_storage.get_mut(compiled_pipeline_handle).unwrap();
// create wgpu pipeline if it doesn't exist
render_context.create_render_pipeline(
*compiled_pipeline_handle,
compiled_pipeline_descriptor,
&shader_storage,
);
// setup pipeline draw targets
for draw_target_name in compiled_pipeline_descriptor.draw_targets.iter()
{
let draw_target =
self.draw_targets.get_mut(draw_target_name).unwrap();
draw_target.setup(
world,
resources,
render_context,
*compiled_pipeline_handle,
compiled_pipeline_descriptor,
);
}
}
}
}
}
}
}
}

View file

@ -1,125 +0,0 @@
use super::RenderGraph;
use crate::{
draw_target::DrawTarget,
pass::PassDescriptor,
pipeline::{PipelineBuilder, PipelineDescriptor},
render_resource::ResourceProvider,
shader::Shader,
texture::TextureDescriptor,
};
use bevy_asset::AssetStorage;
pub struct RenderGraphBuilder<'a, 'b, 'c> {
pub pipelines: &'a mut AssetStorage<PipelineDescriptor>,
pub shaders: &'b mut AssetStorage<Shader>,
pub render_graph: &'c mut RenderGraph,
pub current_pass: Option<String>,
}
impl<'a, 'b, 'c> RenderGraphBuilder<'a, 'b, 'c> {
pub fn add_pass(&mut self, name: &str, pass: PassDescriptor) -> &mut Self {
self.current_pass = Some(name.to_string());
self.render_graph
.pass_descriptors
.insert(name.to_string(), pass);
self
}
pub fn add_pipeline(&mut self, name: &str, build: impl Fn(&mut PipelineBuilder)) -> &mut Self {
if let Some(ref pass) = self.current_pass {
let mut builder = PipelineBuilder::new(name, &mut self.shaders);
build(&mut builder);
let pipeline = builder.finish();
let pipeline_descriptor_handle = self.pipelines.add(pipeline);
self.pipelines.set_name(name, pipeline_descriptor_handle);
self.render_graph
.add_pipeline(&pass, pipeline_descriptor_handle);
}
self
}
pub fn add_default_pipeline(
&mut self,
name: &str,
build: impl Fn(&mut PipelineBuilder),
) -> &mut Self {
if let Some(ref pass) = self.current_pass {
let mut builder = PipelineBuilder::new(name, &mut self.shaders);
build(&mut builder);
let pipeline = builder.finish();
let pipeline_descriptor_handle = self.pipelines.add_default(pipeline);
self.pipelines.set_name(name, pipeline_descriptor_handle);
self.render_graph
.add_pipeline(&pass, pipeline_descriptor_handle);
}
self
}
pub fn add_pipeline_to_pass(
&mut self,
pass: &str,
name: &str,
build: impl Fn(&mut PipelineBuilder),
) -> &mut Self {
{
let mut builder = PipelineBuilder::new(name, &mut self.shaders);
build(&mut builder);
let pipeline = builder.finish();
let pipeline_descriptor_handle = self.pipelines.add(pipeline);
self.pipelines.set_name(name, pipeline_descriptor_handle);
self.render_graph
.add_pipeline(pass, pipeline_descriptor_handle);
}
self
}
pub fn add_default_pipeline_to_pass(
&mut self,
pass: &str,
name: &str,
build: impl Fn(&mut PipelineBuilder),
) -> &mut Self {
{
let mut builder = PipelineBuilder::new(name, &mut self.shaders);
build(&mut builder);
let pipeline = builder.finish();
let pipeline_descriptor_handle = self.pipelines.add_default(pipeline);
self.pipelines.set_name(name, pipeline_descriptor_handle);
self.render_graph
.add_pipeline(pass, pipeline_descriptor_handle);
}
self
}
pub fn add_resource_provider<T>(&mut self, resource_provider: T) -> &mut Self
where
T: ResourceProvider + Send + Sync + 'static,
{
self.render_graph
.resource_providers
.push(Box::new(resource_provider));
self
}
pub fn add_texture(&mut self, name: &str, texture_descriptor: TextureDescriptor) -> &mut Self {
self.render_graph
.queued_textures
.push((name.to_string(), texture_descriptor));
self
}
pub fn add_draw_target<T>(&mut self, draw_target: T) -> &mut Self
where
T: DrawTarget + Send + Sync + 'static,
{
self.render_graph
.draw_targets
.insert(draw_target.get_name(), Box::new(draw_target));
self
}
}

View file

@ -1,4 +1,4 @@
use super::{NodeId, NodeState, RenderGraph2, RenderGraphError};
use super::{NodeId, NodeState, RenderGraph, RenderGraphError};
use std::collections::HashMap;
use thiserror::Error;
@ -65,7 +65,7 @@ impl Stages {
}
}
pub fn borrow<'a>(&self, render_graph: &'a mut RenderGraph2) -> Vec<StageBorrow<'a>> {
pub fn borrow<'a>(&self, render_graph: &'a mut RenderGraph) -> Vec<StageBorrow<'a>> {
// unfortunately borrowing render graph nodes in a specific order takes a little bit of gymnastics
let mut stage_borrows = Vec::with_capacity(self.stages.len());
@ -102,7 +102,7 @@ impl Stages {
/// Produces a collection of `Stages`, which are sets of OrderedJobs that must be run before moving on to the next stage
pub trait RenderGraphStager {
fn get_stages(&mut self, render_graph: &RenderGraph2) -> Result<Stages, RenderGraphError>;
fn get_stages(&mut self, render_graph: &RenderGraph) -> Result<Stages, RenderGraphError>;
}
// TODO: remove this
@ -111,7 +111,7 @@ pub trait RenderGraphStager {
pub struct LinearStager;
impl RenderGraphStager for LinearStager {
fn get_stages(&mut self, render_graph: &RenderGraph2) -> Result<Stages, RenderGraphError> {
fn get_stages(&mut self, render_graph: &RenderGraph) -> Result<Stages, RenderGraphError> {
let mut stage = Stage::default();
let mut job = OrderedJob::default();
for node in render_graph.iter_nodes() {
@ -155,7 +155,7 @@ impl DependentNodeStager {
}
impl RenderGraphStager for DependentNodeStager {
fn get_stages<'a>(&mut self, render_graph: &RenderGraph2) -> Result<Stages, RenderGraphError> {
fn get_stages<'a>(&mut self, render_graph: &RenderGraph) -> Result<Stages, RenderGraphError> {
// get all nodes without input. this intentionally includes nodes with no outputs
let output_only_nodes = render_graph
.iter_nodes()
@ -178,7 +178,7 @@ impl RenderGraphStager for DependentNodeStager {
}
fn stage_node(
graph: &RenderGraph2,
graph: &RenderGraph,
stages: &mut Vec<Stage>,
node_stages_and_jobs: &mut HashMap<NodeId, (usize, usize)>,
node: &NodeState,
@ -263,9 +263,9 @@ fn stage_node(
mod tests {
use super::{DependentNodeStager, OrderedJob, RenderGraphStager, Stage};
use crate::{
render_graph_2::{Node, NodeId, RenderGraph2, ResourceSlotInfo, ResourceSlots},
render_graph::{Node, NodeId, RenderGraph, ResourceSlotInfo, ResourceSlots},
render_resource::ResourceInfo,
renderer_2::RenderContext,
renderer::RenderContext,
};
use legion::prelude::{Resources, World};
@ -314,7 +314,7 @@ mod tests {
#[test]
fn test_render_graph_dependency_stager_loose() {
let mut graph = RenderGraph2::default();
let mut graph = RenderGraph::default();
// Setup graph to look like this:
//
@ -436,7 +436,7 @@ mod tests {
#[test]
fn test_render_graph_dependency_stager_tight() {
let mut graph = RenderGraph2::default();
let mut graph = RenderGraph::default();
// Setup graph to look like this:
//

View file

@ -1,40 +0,0 @@
pub mod nodes;
mod command;
mod graph;
mod node;
mod edge;
mod node_slot;
mod schedule;
pub use command::*;
pub use graph::*;
pub use node::*;
pub use edge::*;
pub use node_slot::*;
pub use schedule::*;
use thiserror::Error;
#[derive(Error, Debug, Eq, PartialEq)]
pub enum RenderGraphError {
#[error("Node does not exist")]
InvalidNode(NodeLabel),
#[error("Node slot does not exist")]
InvalidNodeSlot(SlotLabel),
#[error("Node does not match the given type")]
WrongNodeType,
#[error("Attempted to connect a node output slot to an incompatible input node slot")]
MismatchedNodeSlots {
output_node: NodeId,
output_slot: usize,
input_node: NodeId,
input_slot: usize,
},
#[error("Attempted to add an edge that already exists")]
EdgeAlreadyExists(Edge),
#[error("Node has an unconnected input slot.")]
UnconnectedNodeInputSlot { node: NodeId, input_slot: usize },
#[error("Node has an unconnected output slot.")]
UnconnectedNodeOutputSlot { node: NodeId, output_slot: usize },
#[error("Node input slot already occupied")]
NodeInputSlotAlreadyOccupied { node: NodeId, input_slot: usize, occupied_by_node: NodeId },
}

View file

@ -5,8 +5,6 @@ mod render_resource;
mod render_resource_assignments;
mod resource_info;
pub mod resource_name;
mod resource_provider;
pub mod resource_providers;
pub use batching::*;
pub use buffer::*;
@ -14,4 +12,3 @@ pub use entity_render_resource_assignments::*;
pub use render_resource::*;
pub use render_resource_assignments::*;
pub use resource_info::*;
pub use resource_provider::*;

View file

@ -1,38 +0,0 @@
use crate::renderer_2::RenderContext;
use legion::prelude::*;
pub trait ResourceProvider {
fn initialize(
&mut self,
_renderer: &mut dyn RenderContext,
_world: &mut World,
_resources: &Resources,
) {
}
fn update(
&mut self,
_render_context: &mut dyn RenderContext,
_world: &World,
_resources: &Resources,
) {
}
// TODO: remove this
fn finish_update(
&mut self,
_render_context: &mut dyn RenderContext,
_world: &mut World,
_resources: &Resources,
) {
}
/// Runs after resources have been created on the gpu. In general systems here write gpu-related resources back to entities in this step
fn post_update(
&mut self,
_render_context: &dyn RenderContext,
_world: &mut World,
_resources: &Resources,
) {
}
}

View file

@ -1,55 +0,0 @@
use crate::{
render_resource::{RenderResourceAssignments, ResourceProvider},
renderer_2::RenderContext,
texture::TextureDescriptor,
};
use bevy_window::Windows;
use legion::prelude::*;
pub struct FrameTextureResourceProvider {
pub name: String,
pub descriptor: TextureDescriptor,
pub width: u32,
pub height: u32,
}
impl FrameTextureResourceProvider {
pub fn new(name: &str, descriptor: TextureDescriptor) -> Self {
FrameTextureResourceProvider {
name: name.to_string(),
descriptor,
width: 0,
height: 0,
}
}
}
impl ResourceProvider for FrameTextureResourceProvider {
fn update(
&mut self,
render_context: &mut dyn RenderContext,
_world: &World,
resources: &Resources,
) {
let windows = resources.get::<Windows>().unwrap();
let window = windows.get_primary().unwrap();
if self.descriptor.size.width != window.width
|| self.descriptor.size.height != window.height
{
self.descriptor.size.width = window.width;
self.descriptor.size.height = window.height;
let mut render_resource_assignments =
resources.get_mut::<RenderResourceAssignments>().unwrap();
let render_resources = render_context.resources_mut();
if let Some(old_resource) = render_resource_assignments.get(&self.name) {
render_resources.remove_texture(old_resource);
}
let texture_resource = render_resources.create_texture(&self.descriptor);
render_resource_assignments.set(&self.name, texture_resource);
}
}
}

View file

@ -1,132 +0,0 @@
use crate::{
render_resource::{
resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments,
ResourceProvider,
},
renderer_2::RenderContext,
Light, LightRaw,
};
use bevy_transform::prelude::{LocalToWorld, Translation};
use legion::prelude::*;
use zerocopy::AsBytes;
pub struct LightResourceProvider {
pub lights_are_dirty: bool,
pub max_lights: usize,
pub light_buffer: Option<RenderResource>,
pub tmp_light_buffer: Option<RenderResource>,
pub tmp_count_buffer: Option<RenderResource>,
}
#[repr(C)]
#[derive(Clone, Copy, AsBytes)]
pub struct LightCount {
pub num_lights: [u32; 4],
}
impl LightResourceProvider {
pub fn new(max_lights: usize) -> Self {
LightResourceProvider {
lights_are_dirty: true,
max_lights,
light_buffer: None,
tmp_light_buffer: None,
tmp_count_buffer: None,
}
}
}
impl ResourceProvider for LightResourceProvider {
fn initialize(
&mut self,
render_context: &mut dyn RenderContext,
_world: &mut World,
resources: &Resources,
) {
let light_uniform_size =
std::mem::size_of::<LightCount>() + self.max_lights * std::mem::size_of::<LightRaw>();
let buffer = render_context.resources_mut().create_buffer(BufferInfo {
size: light_uniform_size,
buffer_usage: BufferUsage::UNIFORM | BufferUsage::COPY_SRC | BufferUsage::COPY_DST,
..Default::default()
});
let mut render_resource_assignments =
resources.get_mut::<RenderResourceAssignments>().unwrap();
render_resource_assignments.set(resource_name::uniform::LIGHTS, buffer);
self.light_buffer = Some(buffer);
}
fn update(
&mut self,
render_context: &mut dyn RenderContext,
world: &World,
_resources: &Resources,
) {
if self.lights_are_dirty {
let light_query = <(Read<Light>, Read<LocalToWorld>, Read<Translation>)>::query();
let light_count = light_query.iter(world).count();
if light_count == 0 {
return;
}
self.lights_are_dirty = false;
let size = std::mem::size_of::<LightRaw>();
let total_size = size * light_count;
let light_count_size = std::mem::size_of::<LightCount>();
let render_resources = render_context.resources_mut();
if let Some(old_tmp_light_buffer) = self.tmp_light_buffer {
render_resources.remove_buffer(old_tmp_light_buffer);
}
if let Some(old_tmp_count_buffer) = self.tmp_count_buffer {
render_resources.remove_buffer(old_tmp_count_buffer);
}
self.tmp_light_buffer = Some(render_resources.create_buffer_mapped(
BufferInfo {
size: total_size,
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
},
&mut |data, _renderer| {
for ((light, local_to_world, translation), slot) in
light_query.iter(world).zip(data.chunks_exact_mut(size))
{
slot.copy_from_slice(
LightRaw::from(&light, &local_to_world.0, &translation).as_bytes(),
);
}
},
));
self.tmp_count_buffer = Some(render_resources.create_buffer_mapped(
BufferInfo {
size: light_count_size,
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
},
&mut |data, _renderer| {
data.copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
},
));
render_context.copy_buffer_to_buffer(
self.tmp_count_buffer.unwrap(),
0,
self.light_buffer.unwrap(),
0,
light_count_size as u64,
);
render_context.copy_buffer_to_buffer(
self.tmp_light_buffer.unwrap(),
0,
self.light_buffer.unwrap(),
light_count_size as u64,
total_size as u64,
);
}
}
}

View file

@ -1,96 +0,0 @@
use crate::{
mesh::{self, Mesh},
pipeline::{state_descriptors::IndexFormat, VertexBufferDescriptor, VertexBufferDescriptors},
render_resource::{AssetBatchers, BufferInfo, BufferUsage, RenderResourceAssignments},
renderer_2::{GlobalRenderResourceContext, RenderResourceContext},
shader::AsUniforms,
Renderable, Vertex,
};
use bevy_asset::{AssetStorage, Handle};
use legion::prelude::*;
fn setup_mesh_resource(
render_resources: &dyn RenderResourceContext,
render_resource_assignments: &mut RenderResourceAssignments,
vertex_buffer_descriptor: &VertexBufferDescriptor,
handle: Handle<Mesh>,
meshes: &AssetStorage<Mesh>,
) {
log::trace!("setup mesh for {:?}", render_resource_assignments.id);
let index_format = IndexFormat::Uint16;
let (vertex_buffer, index_buffer) = if let Some(vertex_buffer) =
render_resources.get_asset_resource(handle, mesh::VERTEX_BUFFER_ASSET_INDEX)
{
(
vertex_buffer,
render_resources.get_asset_resource(handle, mesh::INDEX_BUFFER_ASSET_INDEX),
)
} else {
let mesh_asset = meshes.get(&handle).unwrap();
let vertex_bytes = mesh_asset
.get_vertex_buffer_bytes(&vertex_buffer_descriptor)
.unwrap();
// TODO: use a staging buffer here
let vertex_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::VERTEX,
..Default::default()
},
&vertex_bytes,
);
let index_bytes = mesh_asset.get_index_buffer_bytes(index_format).unwrap();
let index_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::INDEX,
..Default::default()
},
&index_bytes,
);
render_resources.set_asset_resource(handle, vertex_buffer, mesh::VERTEX_BUFFER_ASSET_INDEX);
render_resources.set_asset_resource(handle, index_buffer, mesh::INDEX_BUFFER_ASSET_INDEX);
(vertex_buffer, Some(index_buffer))
};
render_resource_assignments.set_vertex_buffer("Vertex", vertex_buffer, index_buffer);
}
pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Schedulable> {
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
// TODO: allow pipelines to specialize on vertex_buffer_descriptor and index_format
let vertex_buffer_descriptor = Vertex::get_vertex_buffer_descriptor().unwrap();
vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone());
SystemBuilder::new("mesh_resource_provider")
.read_resource::<GlobalRenderResourceContext>()
.read_resource::<AssetStorage<Mesh>>()
.write_resource::<AssetBatchers>()
.with_query(<(Read<Handle<Mesh>>, Write<Renderable>)>::query())
.build(
move |_, world, (render_resource_context, meshes, asset_batchers), query| {
let render_resources = &*render_resource_context.context;
if let Some(batches) = asset_batchers.get_handle_batches_mut::<Mesh>() {
for batch in batches {
let handle = batch.get_handle::<Mesh>().unwrap();
setup_mesh_resource(
render_resources,
&mut batch.render_resource_assignments,
&vertex_buffer_descriptor,
handle,
&meshes,
);
}
}
// TODO: remove this once batches are pipeline specific and deprecate assigned_meshes draw target
for (handle, mut renderable) in query.iter_mut(world) {
setup_mesh_resource(
render_resources,
&mut renderable.render_resource_assignments,
&vertex_buffer_descriptor,
*handle,
&meshes,
);
}
},
)
}

View file

@ -1,9 +0,0 @@
mod frame_texture_resource_provider;
mod light_resource_provider;
mod mesh_resource_provider;
mod uniform_resource_provider;
pub use frame_texture_resource_provider::*;
pub use light_resource_provider::*;
pub use mesh_resource_provider::*;
pub use uniform_resource_provider::*;

View file

@ -1,799 +0,0 @@
use crate::{
pipeline::VertexBufferDescriptors,
render_resource::{
AssetBatchers, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource,
RenderResourceAssignments, RenderResourceAssignmentsId, ResourceInfo, ResourceProvider,
},
renderer_2::{RenderContext, RenderResourceContext},
shader::{AsUniforms, FieldBindType},
texture::{self, SamplerDescriptor, Texture, TextureDescriptor},
Renderable,
};
use bevy_asset::{AssetStorage, Handle};
use legion::{filter::*, prelude::*};
use std::{collections::HashMap, marker::PhantomData};
pub const BIND_BUFFER_ALIGNMENT: usize = 256;
#[derive(Debug)]
struct BufferArrayStatus {
new_item_count: usize,
item_size: usize,
aligned_size: usize,
staging_buffer_offset: usize,
queued_buffer_writes: Vec<QueuedBufferWrite>,
buffer: Option<RenderResource>,
current_item_count: usize,
current_item_capacity: usize,
indices: HashMap<RenderResourceAssignmentsId, usize>,
current_index: usize,
}
impl BufferArrayStatus {
pub fn get_or_assign_index(&mut self, id: RenderResourceAssignmentsId) -> usize {
if let Some(offset) = self.indices.get(&id) {
*offset
} else {
if self.current_index == self.current_item_capacity {
panic!("no empty slots available in array");
}
let index = self.current_index;
self.indices.insert(id, index);
self.current_index += 1;
index
}
}
}
#[derive(Debug)]
struct QueuedBufferWrite {
buffer: RenderResource,
offset: usize,
}
// TODO: make these queries only update changed T components
type UniformQueryRead<T> = Query<
(Read<T>, Read<Renderable>),
EntityFilterTuple<
And<(ComponentFilter<T>, ComponentFilter<Renderable>)>,
And<(Passthrough, Passthrough)>,
And<(Passthrough, Passthrough)>,
>,
>;
type UniformQuery<T> = Query<
(Read<T>, Write<Renderable>),
EntityFilterTuple<
And<(ComponentFilter<T>, ComponentFilter<Renderable>)>,
And<(Passthrough, Passthrough)>,
And<(Passthrough, Passthrough)>,
>,
>;
type UniformHandleQueryRead<T> = Query<
(Read<Handle<T>>, Read<Renderable>),
EntityFilterTuple<
And<(ComponentFilter<Handle<T>>, ComponentFilter<Renderable>)>,
And<(Passthrough, Passthrough)>,
And<(Passthrough, Passthrough)>,
>,
>;
type UniformHandleQuery<T> = Query<
(Read<Handle<T>>, Write<Renderable>),
EntityFilterTuple<
And<(ComponentFilter<Handle<T>>, ComponentFilter<Renderable>)>,
And<(Passthrough, Passthrough)>,
And<(Passthrough, Passthrough)>,
>,
>;
// TODO: rename to RenderResourceProvider
pub struct UniformResourceProvider<T>
where
T: AsUniforms + Send + Sync + 'static,
{
_marker: PhantomData<T>,
use_dynamic_uniforms: bool,
is_instanceable: bool,
// PERF: somehow remove this HashSet
uniform_buffer_status: Vec<Option<(String, BufferArrayStatus)>>,
instance_buffer_status: Option<BufferArrayStatus>,
query: Option<UniformQueryRead<T>>,
query_finish: Option<UniformQuery<T>>,
handle_query: Option<UniformHandleQueryRead<T>>,
handle_query_finish: Option<UniformHandleQuery<T>>,
}
impl<T> UniformResourceProvider<T>
where
T: AsUniforms + Send + Sync + 'static,
{
pub fn new(use_dynamic_uniforms: bool) -> Self {
let mut dynamic_uniform_buffer_status = Vec::new();
let field_infos = T::get_field_infos();
dynamic_uniform_buffer_status.resize_with(field_infos.len(), || None);
let is_instanceable = field_infos.iter().find(|f| f.is_instanceable).is_some();
UniformResourceProvider {
uniform_buffer_status: dynamic_uniform_buffer_status,
use_dynamic_uniforms,
instance_buffer_status: None,
is_instanceable,
query: Some(<(Read<T>, Read<Renderable>)>::query()),
query_finish: Some(<(Read<T>, Write<Renderable>)>::query()),
handle_query: Some(<(Read<Handle<T>>, Read<Renderable>)>::query()),
handle_query_finish: Some(<(Read<Handle<T>>, Write<Renderable>)>::query()),
_marker: PhantomData,
}
}
fn reset_buffer_array_status_counts(&mut self) {
for buffer_status in self.uniform_buffer_status.iter_mut() {
if let Some((_name, buffer_status)) = buffer_status {
buffer_status.new_item_count = 0;
}
}
if let Some(ref mut buffer_status) = self.instance_buffer_status {
buffer_status.new_item_count = 0;
}
}
fn update_uniforms_info(&mut self, world: &World) {
let query = self.query.take().unwrap();
for (uniforms, renderable) in query.iter(world) {
if !renderable.is_visible {
return;
}
if renderable.is_instanced {
if self.is_instanceable {
self.increment_instance_count(|| Self::get_instance_size(&uniforms));
} else {
panic!(
"Cannot instance uniforms of type {}",
std::any::type_name::<T>()
);
}
} else {
self.increment_uniform_counts(&uniforms);
}
}
self.query = Some(query);
}
fn update_uniform_handles_info(&mut self, world: &World, resources: &Resources) {
let handle_query = self.handle_query.take().unwrap();
let assets = resources.get::<AssetStorage<T>>();
if let Some(assets) = assets {
for (handle, renderable) in handle_query.iter(world) {
if !renderable.is_visible {
return;
}
if renderable.is_instanced {
if self.is_instanceable {
self.increment_instance_count(|| {
let uniforms = assets.get(&handle).unwrap();
Self::get_instance_size(uniforms)
});
} else {
panic!(
"Cannot instance uniforms of type Handle<{}>",
std::any::type_name::<T>()
);
}
} else {
let uniforms = assets
.get(&handle)
.expect("Handle points to a non-existent resource");
// TODO: only increment count if we haven't seen this uniform handle before
self.increment_uniform_counts(&uniforms);
}
}
}
self.handle_query = Some(handle_query);
}
fn increment_instance_count(&mut self, f: impl Fn() -> usize) {
if let Some(ref mut buffer_array_status) = self.instance_buffer_status {
buffer_array_status.new_item_count += 1;
} else {
self.instance_buffer_status = Some(BufferArrayStatus {
new_item_count: 1,
queued_buffer_writes: Vec::new(),
aligned_size: 0,
item_size: f(),
staging_buffer_offset: 0,
buffer: None,
current_index: 0,
current_item_capacity: 0,
current_item_count: 0,
indices: HashMap::new(),
})
}
}
fn get_instance_size(uniforms: &T) -> usize {
let mut instance_buffer_size = 0;
for field_info in T::get_field_infos().iter() {
if field_info.is_instanceable {
if let Some(FieldBindType::Uniform { size }) =
uniforms.get_field_bind_type(field_info.name)
{
instance_buffer_size += size;
}
}
}
instance_buffer_size
}
fn increment_uniform_counts(&mut self, uniforms: &T) {
for (i, field_info) in T::get_field_infos().iter().enumerate() {
if let Some(FieldBindType::Uniform { size }) =
uniforms.get_field_bind_type(&field_info.name)
{
if let Some((ref _name, ref mut buffer_array_status)) =
self.uniform_buffer_status[i]
{
buffer_array_status.new_item_count += 1;
} else {
self.uniform_buffer_status[i] = Some((
field_info.uniform_name.to_string(),
BufferArrayStatus {
new_item_count: 1,
queued_buffer_writes: Vec::new(),
aligned_size: Self::get_aligned_dynamic_uniform_size(size),
item_size: size,
staging_buffer_offset: 0,
buffer: None,
current_index: 0,
current_item_count: 0,
current_item_capacity: 0,
indices: HashMap::new(),
},
))
}
}
}
}
fn get_aligned_dynamic_uniform_size(data_size: usize) -> usize {
BIND_BUFFER_ALIGNMENT * ((data_size as f32 / BIND_BUFFER_ALIGNMENT as f32).ceil() as usize)
}
fn setup_uniform_buffer_resources(
&mut self,
uniforms: &T,
render_resources: &dyn RenderResourceContext,
render_resource_assignments: &mut RenderResourceAssignments,
staging_buffer: &mut [u8],
) {
for (i, field_info) in T::get_field_infos().iter().enumerate() {
let bind_type = uniforms.get_field_bind_type(&field_info.name);
match bind_type {
Some(FieldBindType::Uniform { size }) => {
let (_name, uniform_buffer_status) =
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();
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)
{
Some(render_resource) => render_resource,
None => {
let resource = render_resources.create_buffer(BufferInfo {
size,
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
..Default::default()
});
render_resource_assignments.set(&field_info.uniform_name, resource);
resource
}
};
(resource, 0)
};
let staging_buffer_start = uniform_buffer_status.staging_buffer_offset
+ (uniform_buffer_status.queued_buffer_writes.len()
* uniform_buffer_status.item_size);
if let Some(uniform_bytes) =
uniforms.get_uniform_bytes_ref(&field_info.uniform_name)
{
if size != uniform_bytes.len() {
panic!("The number of bytes produced for {} do not match the expected count. Actual: {}. Expected: {}.", field_info.uniform_name, uniform_bytes.len(), size);
}
staging_buffer
[staging_buffer_start..(staging_buffer_start + uniform_bytes.len())]
.copy_from_slice(uniform_bytes);
} else if let Some(uniform_bytes) =
uniforms.get_uniform_bytes(field_info.uniform_name)
{
if size != uniform_bytes.len() {
panic!("The number of bytes produced for {} do not match the expected count. Actual: {}. Expected: {}.", field_info.uniform_name, uniform_bytes.len(), size);
}
staging_buffer
[staging_buffer_start..(staging_buffer_start + uniform_bytes.len())]
.copy_from_slice(&uniform_bytes);
} else {
panic!(
"failed to get data from uniform: {}",
field_info.uniform_name
);
};
uniform_buffer_status
.queued_buffer_writes
.push(QueuedBufferWrite {
buffer: target_buffer,
offset: target_offset,
});
}
_ => {}
}
}
}
fn setup_uniform_texture_resources(
&mut self,
uniforms: &T,
render_context: &mut dyn RenderContext,
resources: &Resources,
render_resource_assignments: &mut RenderResourceAssignments,
) {
for field_info in T::get_field_infos().iter() {
let bind_type = uniforms.get_field_bind_type(&field_info.name);
match bind_type {
Some(FieldBindType::Texture) => {
let texture_handle = uniforms
.get_uniform_texture(&field_info.texture_name)
.unwrap();
let (texture_resource, sampler_resource) = match render_context
.resources()
.get_asset_resource(texture_handle, texture::TEXTURE_ASSET_INDEX)
{
Some(texture_resource) => (
texture_resource,
render_context
.resources()
.get_asset_resource(texture_handle, texture::SAMPLER_ASSET_INDEX)
.unwrap(),
),
None => {
let storage = resources.get::<AssetStorage<Texture>>().unwrap();
let texture = storage.get(&texture_handle).unwrap();
let texture_descriptor: TextureDescriptor = texture.into();
let texture_resource = render_context
.create_texture_with_data(&texture_descriptor, &texture.data);
let render_resources = render_context.resources_mut();
let sampler_descriptor: SamplerDescriptor = texture.into();
let sampler_resource =
render_resources.create_sampler(&sampler_descriptor);
render_resources.set_asset_resource(
texture_handle,
texture_resource,
0,
);
render_resources.set_asset_resource(
texture_handle,
sampler_resource,
1,
);
(texture_resource, sampler_resource)
}
};
render_resource_assignments.set(field_info.texture_name, texture_resource);
render_resource_assignments.set(field_info.sampler_name, sampler_resource);
}
_ => {}
}
}
}
// TODO: the current WgpuRenderContext mapped-memory interface forced these to be separate, but thats inefficient / redundant
// try to merge setup_uniforms_buffer_resources and setup_uniforms_texture_resources if possible
fn setup_uniforms_buffer_resources(
&mut self,
world: &mut World,
render_resources: &dyn RenderResourceContext,
staging_buffer: &mut [u8],
) {
let query_finish = self.query_finish.take().unwrap();
for (uniforms, mut renderable) in query_finish.iter_mut(world) {
if !renderable.is_visible {
return;
}
if renderable.is_instanced {
panic!(
"Cannot instance uniforms of type {0}. Only Handle<{0}> can be instanced.",
std::any::type_name::<T>()
);
} else {
self.setup_uniform_buffer_resources(
&uniforms,
render_resources,
&mut renderable.render_resource_assignments,
staging_buffer,
);
}
}
self.query_finish = Some(query_finish);
}
fn setup_uniforms_texture_resources(
&mut self,
world: &mut World,
resources: &Resources,
render_context: &mut dyn RenderContext,
) {
let query_finish = self.query_finish.take().unwrap();
for (uniforms, mut renderable) in query_finish.iter_mut(world) {
if !renderable.is_visible {
return;
}
if renderable.is_instanced {
panic!(
"Cannot instance uniforms of type {0}. Only Handle<{0}> can be instanced.",
std::any::type_name::<T>()
);
} else {
self.setup_uniform_texture_resources(
&uniforms,
render_context,
resources,
&mut renderable.render_resource_assignments,
)
}
}
self.query_finish = Some(query_finish);
}
fn setup_handles_buffer_resources(
&mut self,
world: &mut World,
resources: &Resources,
render_resources: &dyn RenderResourceContext,
staging_buffer: &mut [u8],
) {
let assets = resources.get::<AssetStorage<T>>();
if let Some(assets) = assets {
let handle_query_finish = self.handle_query_finish.take().unwrap();
for (handle, mut renderable) in handle_query_finish.iter_mut(world) {
if !renderable.is_visible || renderable.is_instanced {
return;
}
let uniforms = assets
.get(&handle)
.expect("Handle points to a non-existent resource");
// TODO: only setup buffer if we haven't seen this handle before
self.setup_uniform_buffer_resources(
&uniforms,
render_resources,
&mut renderable.render_resource_assignments,
staging_buffer,
);
}
self.handle_query_finish = Some(handle_query_finish);
}
}
fn setup_handles_texture_resources(
&mut self,
world: &mut World,
resources: &Resources,
render_context: &mut dyn RenderContext,
) {
let assets = resources.get::<AssetStorage<T>>();
if let Some(assets) = assets {
let handle_query_finish = self.handle_query_finish.take().unwrap();
for (handle, mut renderable) in handle_query_finish.iter_mut(world) {
if !renderable.is_visible || renderable.is_instanced {
return;
}
let uniforms = assets
.get(&handle)
.expect("Handle points to a non-existent resource");
self.setup_uniform_texture_resources(
&uniforms,
render_context,
resources,
&mut renderable.render_resource_assignments,
)
}
self.handle_query_finish = Some(handle_query_finish);
}
}
#[allow(dead_code)]
fn setup_batched_resources(
&mut self,
_world: &mut World,
resources: &Resources,
render_context: &mut dyn RenderContext,
staging_buffer: &mut [u8],
) {
// update batch resources. this needs to run in "finish_update" because batches aren't finalized across
// all members of the batch until "UniformResourceProvider.update" has run for all members of the batch
if let Some(asset_storage) = resources.get::<AssetStorage<T>>() {
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
let handle_type = std::any::TypeId::of::<T>();
for batch in asset_batchers.get_handle_batches_mut::<T>().unwrap() {
let handle: Handle<T> = batch
.handles
.iter()
.find(|h| h.type_id == handle_type)
.map(|h| (*h).into())
.unwrap();
if let Some(uniforms) = asset_storage.get(&handle) {
self.setup_uniform_buffer_resources(
&uniforms,
render_context.resources_mut(),
&mut batch.render_resource_assignments,
staging_buffer,
);
self.setup_uniform_texture_resources(
&uniforms,
render_context,
resources,
&mut batch.render_resource_assignments,
);
}
}
}
}
fn setup_buffer_arrays(&mut self, render_context: &mut dyn RenderContext) {
for buffer_array_status in self.uniform_buffer_status.iter_mut() {
if let Some((_name, buffer_array_status)) = buffer_array_status {
if self.use_dynamic_uniforms {
Self::setup_buffer_array(buffer_array_status, render_context, true);
}
buffer_array_status.queued_buffer_writes =
Vec::with_capacity(buffer_array_status.new_item_count);
}
}
if let Some(ref mut buffer_array_status) = self.instance_buffer_status {
Self::setup_buffer_array(buffer_array_status, render_context, false);
}
}
fn setup_buffer_array(
buffer_array_status: &mut BufferArrayStatus,
render_context: &mut dyn RenderContext,
align: bool,
) {
let new_capacity = if let Some(buffer) = buffer_array_status.buffer {
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)
};
if let Some(new_capacity) = new_capacity {
let mut item_size = buffer_array_status.item_size;
if align {
item_size = Self::get_aligned_dynamic_uniform_size(item_size);
}
let total_size = item_size * new_capacity;
let buffer = render_context.resources_mut().create_buffer(BufferInfo {
array_info: Some(BufferArrayInfo {
item_capacity: new_capacity,
item_size,
..Default::default()
}),
size: total_size,
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
is_dynamic: true,
});
buffer_array_status.current_item_capacity = new_capacity;
log::trace!(
"creating buffer for uniform {}. size: {} item_capacity: {} item_size: {}",
std::any::type_name::<T>(),
total_size,
new_capacity,
item_size
);
buffer_array_status.buffer = Some(buffer);
}
}
fn initialize_vertex_buffer_descriptor(
&self,
vertex_buffer_descriptors: &mut VertexBufferDescriptors,
) {
let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor();
if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor {
if let None = vertex_buffer_descriptors.get(&vertex_buffer_descriptor.name) {
vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone());
}
}
}
fn update_staging_buffer_offsets(&mut self) -> usize {
let mut size = 0;
for dynamic_buffer_array_status in self.uniform_buffer_status.iter_mut() {
if let Some((_name, ref mut buffer_array_status)) = dynamic_buffer_array_status {
buffer_array_status.staging_buffer_offset = size;
size += buffer_array_status.item_size * buffer_array_status.new_item_count;
}
}
size
}
fn copy_staging_buffer_to_final_buffers(
&mut self,
render_context: &mut dyn RenderContext,
staging_buffer: RenderResource,
) {
for uniform_buffer_status in self.uniform_buffer_status.iter_mut() {
if let Some((_name, buffer_array_status)) = uniform_buffer_status {
let start = buffer_array_status.staging_buffer_offset;
for (i, queued_buffer_write) in buffer_array_status
.queued_buffer_writes
.drain(..)
.enumerate()
{
render_context.copy_buffer_to_buffer(
staging_buffer,
(start + (i * buffer_array_status.item_size)) as u64,
queued_buffer_write.buffer,
queued_buffer_write.offset as u64,
buffer_array_status.item_size as u64,
)
}
}
}
}
}
impl<T> ResourceProvider for UniformResourceProvider<T>
where
T: AsUniforms + Send + Sync + 'static,
{
fn initialize(
&mut self,
render_context: &mut dyn RenderContext,
world: &mut World,
resources: &Resources,
) {
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
self.initialize_vertex_buffer_descriptor(&mut vertex_buffer_descriptors);
self.update(render_context, world, resources);
}
fn update(
&mut self,
_render_context: &mut dyn RenderContext,
world: &World,
resources: &Resources,
) {
self.reset_buffer_array_status_counts();
self.update_uniforms_info(world);
self.update_uniform_handles_info(world, resources);
}
fn finish_update(
&mut self,
render_context: &mut dyn RenderContext,
world: &mut World,
resources: &Resources,
) {
// TODO: when setting batch shader_defs, add INSTANCING
self.setup_buffer_arrays(render_context);
let staging_buffer_size = self.update_staging_buffer_offsets();
self.setup_uniforms_texture_resources(world, resources, render_context);
self.setup_handles_texture_resources(world, resources, render_context);
// self.setup_batched_texture_resources(world, resources, renderer, staging_buffer);
if staging_buffer_size == 0 {
let mut staging_buffer: [u8; 0] = [];
self.setup_uniforms_buffer_resources(
world,
render_context.resources_mut(),
&mut staging_buffer,
);
self.setup_handles_buffer_resources(
world,
resources,
render_context.resources_mut(),
&mut staging_buffer,
);
// self.setup_batched_buffer_resources(world, resources, renderer, &mut staging_buffer);
} else {
let staging_buffer = render_context.resources_mut().create_buffer_mapped(
BufferInfo {
buffer_usage: BufferUsage::COPY_SRC,
size: staging_buffer_size,
..Default::default()
},
&mut |staging_buffer, render_resources| {
self.setup_uniforms_buffer_resources(world, render_resources, staging_buffer);
self.setup_handles_buffer_resources(
world,
resources,
render_resources,
staging_buffer,
);
// self.setup_batched_buffer_resources(world, resources, renderer, staging_buffer);
},
);
self.copy_staging_buffer_to_final_buffers(render_context, staging_buffer);
render_context.resources_mut().remove_buffer(staging_buffer);
}
}
}

View file

@ -1,5 +1,3 @@
mod local_to_world;
mod standard_material;
pub use local_to_world::*;
pub use standard_material::*;

61
bevy_ui/src/render/mod.rs Normal file
View file

@ -0,0 +1,61 @@
// use crate::{
// pipeline::state_descriptors::{
// BlendDescriptor, BlendFactor, BlendOperation, ColorStateDescriptor, ColorWrite,
// CompareFunction, CullMode, DepthStencilStateDescriptor, FrontFace,
// RasterizationStateDescriptor, StencilStateFaceDescriptor,
// },
// render_graph::RenderGraphBuilder,
// render_resource::resource_name,
// shader::{Shader, ShaderStage},
// texture::TextureFormat,
// };
// pub trait UiPipelineBuilder {
// fn add_ui_pipeline(&mut self) -> &mut Self;
// }
// impl<'a, 'b, 'c> UiPipelineBuilder for RenderGraphBuilder<'a, 'b, 'c> {
// fn add_ui_pipeline(&mut self) -> &mut Self {
// self.add_pipeline(resource_name::pipeline::UI, |builder| {
// builder
// .with_vertex_shader(Shader::from_glsl(
// ShaderStage::Vertex,
// include_str!("ui.vert"),
// ))
// .with_fragment_shader(Shader::from_glsl(
// ShaderStage::Fragment,
// include_str!("ui.frag"),
// ))
// .with_rasterization_state(RasterizationStateDescriptor {
// front_face: FrontFace::Ccw,
// cull_mode: CullMode::None,
// depth_bias: 0,
// depth_bias_slope_scale: 0.0,
// depth_bias_clamp: 0.0,
// })
// .with_depth_stencil_state(DepthStencilStateDescriptor {
// format: TextureFormat::Depth32Float,
// depth_write_enabled: false,
// depth_compare: CompareFunction::Always,
// stencil_front: StencilStateFaceDescriptor::IGNORE,
// stencil_back: StencilStateFaceDescriptor::IGNORE,
// stencil_read_mask: 0,
// stencil_write_mask: 0,
// })
// .add_color_state(ColorStateDescriptor {
// format: TextureFormat::Bgra8UnormSrgb,
// color_blend: BlendDescriptor {
// src_factor: BlendFactor::SrcAlpha,
// dst_factor: BlendFactor::OneMinusSrcAlpha,
// operation: BlendOperation::Add,
// },
// alpha_blend: BlendDescriptor {
// src_factor: BlendFactor::One,
// dst_factor: BlendFactor::One,
// operation: BlendOperation::Add,
// },
// write_mask: ColorWrite::ALL,
// })
// .add_draw_target(resource_name::draw_target::UI);
// })
// }
// }

View file

@ -1,4 +1,4 @@
pub mod renderer_2;
pub mod renderer;
mod wgpu_render_pass;
mod wgpu_renderer;
mod wgpu_resources;
@ -9,10 +9,10 @@ pub use wgpu_renderer::*;
pub use wgpu_resources::*;
use bevy_app::{AppBuilder, AppPlugin, Events};
use bevy_render::{renderer_2::GlobalRenderResourceContext, RENDER_STAGE};
use bevy_render::{renderer::GlobalRenderResourceContext, RENDER_STAGE};
use bevy_window::{WindowCreated, WindowResized};
use legion::prelude::*;
use renderer_2::WgpuRenderResourceContext;
use renderer::WgpuRenderResourceContext;
#[derive(Default)]
pub struct WgpuPlugin;

View file

@ -13,7 +13,7 @@ use bevy_render::{
render_resource::{
RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
},
renderer_2::{RenderContext, RenderResourceContext},
renderer::{RenderContext, RenderResourceContext},
shader::Shader,
texture::{Extent3d, TextureDescriptor},
};

View file

@ -1,7 +1,7 @@
use super::{WgpuRenderContext, WgpuRenderResourceContext};
use bevy_render::{
render_graph_2::{Edge, NodeId, ResourceSlots, StageBorrow},
renderer_2::GlobalRenderResourceContext,
render_graph::{Edge, NodeId, ResourceSlots, StageBorrow},
renderer::GlobalRenderResourceContext,
};
use legion::prelude::{Resources, World};
use std::{collections::HashMap, sync::Arc};

View file

@ -3,7 +3,7 @@ use crate::WgpuResources;
use bevy_asset::{AssetStorage, Handle, HandleUntyped};
use bevy_render::{
render_resource::{BufferInfo, RenderResource, ResourceInfo},
renderer_2::RenderResourceContext,
renderer::RenderResourceContext,
shader::Shader,
texture::{SamplerDescriptor, TextureDescriptor},
};

View file

@ -1,4 +1,4 @@
use crate::{renderer_2::WgpuRenderContext, WgpuResourceRefs};
use crate::{renderer::WgpuRenderContext, WgpuResourceRefs};
use bevy_asset::Handle;
use bevy_render::{
pass::RenderPass,
@ -6,7 +6,7 @@ use bevy_render::{
render_resource::{
RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
},
renderer_2::RenderContext,
renderer::RenderContext,
};
use std::{collections::HashMap, ops::Range};

View file

@ -1,14 +1,11 @@
use crate::renderer_2::{
render_resource_sets_system, WgpuRenderContext, WgpuRenderGraphExecutor,
WgpuRenderResourceContext,
use crate::renderer::{
render_resource_sets_system, WgpuRenderGraphExecutor, WgpuRenderResourceContext,
};
use bevy_app::{EventReader, Events};
use bevy_render::{
pipeline::update_shader_assignments,
render_graph::RenderGraph,
render_graph_2::{DependentNodeStager, RenderGraph2, RenderGraphStager},
render_resource::RenderResourceAssignments,
renderer_2::{GlobalRenderResourceContext, RenderResourceContext},
render_graph::{DependentNodeStager, RenderGraph, RenderGraphStager},
renderer::GlobalRenderResourceContext,
};
use bevy_window::{WindowCreated, WindowResized, Windows};
use legion::prelude::*;
@ -54,117 +51,12 @@ impl WgpuRenderer {
}
}
pub fn initialize_resource_providers(
world: &mut World,
resources: &Resources,
render_context: &mut WgpuRenderContext,
) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
for resource_provider in render_graph.resource_providers.iter_mut() {
resource_provider.initialize(render_context, world, resources);
}
}
fn parallel_resource_provider_update(
world: &World,
resources: &Resources,
device: Arc<wgpu::Device>,
render_resource_context: &WgpuRenderResourceContext,
) -> Vec<wgpu::CommandBuffer> {
let max_thread_count = 8;
let (sender, receiver) = crossbeam_channel::bounded(max_thread_count);
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
let chunk_size =
(render_graph.resource_providers.len() + max_thread_count - 1) / max_thread_count; // divide ints rounding remainder up
// println!("chunk {} {}", chunk_size, render_graph.resource_providers.len());
let mut actual_thread_count = 0;
crossbeam_utils::thread::scope(|s| {
for resource_provider_chunk in render_graph.resource_providers.chunks_mut(chunk_size) {
let device = device.clone();
let sender = sender.clone();
let world = &*world;
let resources = &*resources;
actual_thread_count += 1;
let render_resource_context = render_resource_context.clone();
s.spawn(move |_| {
let mut render_context =
WgpuRenderContext::new(device, render_resource_context);
for resource_provider in resource_provider_chunk.iter_mut() {
resource_provider.update(&mut render_context, world, resources);
}
sender.send(render_context.finish()).unwrap();
});
}
})
.unwrap();
let mut command_buffers = Vec::new();
for _i in 0..actual_thread_count {
let command_buffer = receiver.recv().unwrap();
if let Some(command_buffer) = command_buffer {
command_buffers.push(command_buffer);
}
}
command_buffers
}
pub fn update_resource_providers(
&mut self,
world: &mut World,
resources: &Resources,
render_resource_context: &WgpuRenderResourceContext,
) {
let mut command_buffers = Self::parallel_resource_provider_update(
world,
resources,
self.device.clone(),
render_resource_context,
);
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
let mut results = Vec::new();
let thread_count = 5;
let chunk_size = (render_graph.resource_providers.len() + thread_count - 1) / thread_count; // divide ints rounding remainder up
// crossbeam_utils::thread::scope(|s| {
for resource_provider_chunk in render_graph.resource_providers.chunks_mut(chunk_size) {
let device = self.device.clone();
let mut render_context =
WgpuRenderContext::new(device, render_resource_context.clone());
for resource_provider in resource_provider_chunk.iter_mut() {
resource_provider.finish_update(&mut render_context, world, resources);
}
results.push(render_context.finish());
}
for command_buffer in results {
if let Some(command_buffer) = command_buffer {
command_buffers.push(command_buffer);
}
}
self.queue.submit(&command_buffers);
}
pub fn create_queued_textures(
&mut self,
resources: &Resources,
global_render_resources: &mut WgpuRenderResourceContext,
) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
let mut render_resource_assignments =
resources.get_mut::<RenderResourceAssignments>().unwrap();
for (name, texture_descriptor) in render_graph.queued_textures.drain(..) {
let resource = global_render_resources.create_texture(&texture_descriptor);
render_resource_assignments.set(&name, resource);
}
}
pub fn handle_window_created_events(
&mut self,
resources: &Resources,
global_render_resource_context: &mut WgpuRenderResourceContext,
) {
pub fn handle_window_created_events(&mut self, resources: &Resources) {
let mut global_context = resources.get_mut::<GlobalRenderResourceContext>().unwrap();
let render_resource_context = global_context
.context
.downcast_mut::<WgpuRenderResourceContext>()
.unwrap();
let windows = resources.get::<Windows>().unwrap();
let window_created_events = resources.get::<Events<WindowCreated>>().unwrap();
for window_created_event in
@ -178,7 +70,7 @@ impl WgpuRenderer {
let winit_windows = resources.get::<bevy_winit::WinitWindows>().unwrap();
let winit_window = winit_windows.get_window(window.id).unwrap();
let surface = wgpu::Surface::create(winit_window.deref());
global_render_resource_context
render_resource_context
.wgpu_resources
.set_window_surface(window.id, surface);
}
@ -188,7 +80,7 @@ impl WgpuRenderer {
pub fn run_graph(&mut self, world: &mut World, resources: &mut Resources) {
// run systems
let mut system_executor = {
let mut render_graph = resources.get_mut::<RenderGraph2>().unwrap();
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.take_executor()
};
@ -199,7 +91,7 @@ impl WgpuRenderer {
update_shader_assignments(world, resources);
render_resource_sets_system().run(world, resources);
let mut render_graph = resources.get_mut::<RenderGraph2>().unwrap();
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
if let Some(executor) = system_executor.take() {
render_graph.set_executor(executor);
}
@ -208,7 +100,7 @@ impl WgpuRenderer {
let mut stager = DependentNodeStager::loose_grouping();
let stages = stager.get_stages(&render_graph).unwrap();
let mut borrowed = stages.borrow(&mut render_graph);
// execute stages
let graph_executor = WgpuRenderGraphExecutor {
max_thread_count: 2,
@ -223,31 +115,7 @@ impl WgpuRenderer {
}
pub fn update(&mut self, world: &mut World, resources: &mut Resources) {
{
let mut global_context = resources.get_mut::<GlobalRenderResourceContext>().unwrap();
let render_resource_context = global_context
.context
.downcast_mut::<WgpuRenderResourceContext>()
.unwrap();
self.handle_window_created_events(resources, render_resource_context);
let mut render_context =
WgpuRenderContext::new(self.device.clone(), render_resource_context.clone());
if !self.intialized {
Self::initialize_resource_providers(world, resources, &mut render_context);
let buffer = render_context.finish();
if let Some(buffer) = buffer {
self.queue.submit(&[buffer]);
}
self.intialized = true;
}
self.update_resource_providers(world, resources, render_resource_context);
self.create_queued_textures(resources, &mut render_context.render_resources);
};
self.handle_window_created_events(resources);
self.run_graph(world, resources);
let render_resource_context = resources.get::<GlobalRenderResourceContext>().unwrap();

View file

@ -1,9 +1,9 @@
use crate::{renderer_2::WgpuRenderResourceContext, wgpu_type_converter::WgpuInto};
use crate::{renderer::WgpuRenderResourceContext, wgpu_type_converter::WgpuInto};
use bevy_asset::{Handle, HandleUntyped};
use bevy_render::{
pipeline::{BindGroupDescriptorId, PipelineDescriptor},
render_resource::{BufferInfo, RenderResource, RenderResourceSetId, ResourceInfo},
renderer_2::RenderResourceContext,
renderer::RenderResourceContext,
shader::Shader,
texture::{Extent3d, SamplerDescriptor, TextureDescriptor},
};

View file

@ -12,54 +12,58 @@ struct MyMaterial {
pub color: Color,
}
fn add_shader_to_render_graph(resources: &mut Resources) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
let mut pipelines = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let mut shaders = resources.get_mut::<AssetStorage<Shader>>().unwrap();
render_graph
.build(&mut pipelines, &mut shaders)
.add_resource_provider(UniformResourceProvider::<MyMaterial>::new(true))
.add_pipeline_to_pass(resource_name::pass::MAIN, "MyMaterial", |builder| {
builder
.with_vertex_shader(Shader::from_glsl(
ShaderStage::Vertex,
r#"
#version 450
layout(location = 0) in vec3 Vertex_Position;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 0) uniform Object {
mat4 Model;
};
void main() {
gl_Position = ViewProj * Model * vec4(Vertex_Position, 1.0);
}
"#,
))
.with_fragment_shader(Shader::from_glsl(
ShaderStage::Fragment,
r#"
#version 450
layout(location = 0) out vec4 o_Target;
layout(set = 1, binding = 1) uniform MyMaterial_color {
vec4 color;
};
void main() {
o_Target = color;
}
"#,
))
.with_default_config();
});
}
fn setup(world: &mut World, resources: &mut Resources) {
// add our shader to the render graph
add_shader_to_render_graph(resources);
// create new shader pipeline and add to main pass in Render Graph
let pipeline_handle = {
let mut pipelines = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let mut shaders = resources.get_mut::<AssetStorage<Shader>>().unwrap();
let pipeline_handle = pipelines.add(PipelineDescriptor::default_config(ShaderStages {
vertex: shaders.add(Shader::from_glsl(
ShaderStage::Vertex,
r#"
#version 450
layout(location = 0) in vec3 Vertex_Position;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 0) uniform Object {
mat4 Model;
};
void main() {
gl_Position = ViewProj * Model * vec4(Vertex_Position, 1.0);
}
"#,
)),
fragment: Some(shaders.add(Shader::from_glsl(
ShaderStage::Fragment,
r#"
#version 450
layout(location = 0) out vec4 o_Target;
layout(set = 1, binding = 1) uniform MyMaterial_color {
vec4 color;
};
void main() {
o_Target = color;
}
"#,
))),
}));
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.add_system_node_named(
"my_material",
AssetUniformNode::<MyMaterial>::new(true),
resources,
);
let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap();
main_pass.add_pipeline(
pipeline_handle,
vec![Box::new(draw_target::AssignedMeshesDrawTarget)],
);
pipeline_handle
};
// create materials
let mut material_storage = AssetStorage::<MyMaterial>::new();
@ -68,12 +72,6 @@ fn setup(world: &mut World, resources: &mut Resources) {
});
resources.insert(material_storage);
// get a handle to our newly created shader pipeline
let mut pipeline_storage = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let pipeline_handle = pipeline_storage.get_named("MyMaterial").unwrap();
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let cube_handle = mesh_storage.add(Mesh::from(shape::Cube));

View file

@ -18,58 +18,62 @@ struct MyMaterial {
pub always_red: bool,
}
fn add_shader_to_render_graph(resources: &mut Resources) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
let mut pipelines = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let mut shaders = resources.get_mut::<AssetStorage<Shader>>().unwrap();
render_graph
.build(&mut pipelines, &mut shaders)
.add_resource_provider(UniformResourceProvider::<MyMaterial>::new(true))
.add_pipeline_to_pass(resource_name::pass::MAIN, "MyMaterial", |builder| {
builder
.with_vertex_shader(Shader::from_glsl(
ShaderStage::Vertex,
r#"
#version 450
layout(location = 0) in vec3 Vertex_Position;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 0) uniform Object {
mat4 Model;
};
void main() {
gl_Position = ViewProj * Model * vec4(Vertex_Position, 1.0);
}
"#,
))
.with_fragment_shader(Shader::from_glsl(
ShaderStage::Fragment,
r#"
#version 450
layout(location = 0) out vec4 o_Target;
layout(set = 1, binding = 1) uniform MyMaterial_color {
vec4 color;
};
void main() {
o_Target = color;
# ifdef MYMATERIAL_ALWAYS_RED
o_Target = vec4(0.8, 0.0, 0.0, 1.0);
# endif
}
"#,
))
.with_default_config();
});
}
fn setup(world: &mut World, resources: &mut Resources) {
// add our shader to the render graph
add_shader_to_render_graph(resources);
// create new shader pipeline and add to main pass in Render Graph
let pipeline_handle = {
let mut pipelines = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let mut shaders = resources.get_mut::<AssetStorage<Shader>>().unwrap();
let pipeline_handle = pipelines.add(PipelineDescriptor::default_config(ShaderStages {
vertex: shaders.add(Shader::from_glsl(
ShaderStage::Vertex,
r#"
#version 450
layout(location = 0) in vec3 Vertex_Position;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 0) uniform Object {
mat4 Model;
};
void main() {
gl_Position = ViewProj * Model * vec4(Vertex_Position, 1.0);
}
"#,
)),
fragment: Some(shaders.add(Shader::from_glsl(
ShaderStage::Fragment,
r#"
#version 450
layout(location = 0) out vec4 o_Target;
layout(set = 1, binding = 1) uniform MyMaterial_color {
vec4 color;
};
void main() {
o_Target = color;
# ifdef MYMATERIAL_ALWAYS_RED
o_Target = vec4(0.8, 0.0, 0.0, 1.0);
# endif
}
"#,
))),
}));
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.add_system_node_named(
"my_material",
AssetUniformNode::<MyMaterial>::new(true),
resources,
);
let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap();
main_pass.add_pipeline(
pipeline_handle,
vec![Box::new(draw_target::AssignedMeshesDrawTarget)],
);
pipeline_handle
};
// create materials
let mut material_storage = AssetStorage::<MyMaterial>::new();
@ -82,15 +86,8 @@ fn setup(world: &mut World, resources: &mut Resources) {
color: Color::rgb(0.0, 0.0, 0.0),
always_red: true,
});
resources.insert(material_storage);
// get a handle to our newly created shader pipeline
let mut pipeline_storage = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let pipeline_handle = pipeline_storage.get_named("MyMaterial").unwrap();
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let cube_handle = mesh_storage.add(Mesh::from(shape::Cube));

View file

@ -18,6 +18,9 @@ impl AddDefaultPlugins for AppBuilder {
#[cfg(feature = "render")]
self.add_plugin(bevy_render::RenderPlugin::default());
#[cfg(feature = "pbr")]
self.add_plugin(bevy_pbr::PbrPlugin::default());
#[cfg(feature = "ui")]
self.add_plugin(bevy_ui::UiPlugin::default());

View file

@ -53,6 +53,8 @@ pub use bevy_diagnostic as diagnostic;
pub use bevy_gltf as gltf;
#[cfg(feature = "input")]
pub use bevy_input as input;
#[cfg(feature = "pbr")]
pub use bevy_pbr as pbr;
#[cfg(feature = "render")]
pub use bevy_render as render;
#[cfg(feature = "serialization")]

View file

@ -9,16 +9,19 @@ pub use crate::core::{
pub use crate::derive::*;
#[cfg(feature = "diagnostic")]
pub use crate::diagnostic::DiagnosticsPlugin;
#[cfg(feature = "pbr")]
pub use crate::pbr::{material::StandardMaterial, light::Light, entity::*};
#[cfg(feature = "render")]
pub use crate::render::{
entity::*,
mesh::{Mesh, shape},
pipeline::PipelineDescriptor,
render_graph::RenderGraph,
render_resource::{resource_name, resource_providers::UniformResourceProvider, AssetBatchers},
shader::{uniforms::StandardMaterial, Shader, ShaderDefSuffixProvider, ShaderStage},
draw_target,
render_graph::{RenderGraph, nodes::{UniformNode, AssetUniformNode, PassNode, WindowSwapChainNode, WindowTextureNode, Camera2dNode, CameraNode}},
render_resource::{resource_name, AssetBatchers},
shader::{Shader, ShaderDefSuffixProvider, ShaderStage, ShaderStages},
texture::{Texture, TextureType},
ActiveCamera, ActiveCamera2d, Camera, CameraType, Color, ColorSource, Light, Renderable,
ActiveCamera, ActiveCamera2d, Camera, CameraType, Color, ColorSource, Renderable,
};
#[cfg(feature = "transform")]
pub use crate::transform::prelude::*;