render: "Immediate Mode" draw api

This replaces Renderable with Draw/RenderPipelines components and makes various aspects of the renderer much simpler and legible
This commit is contained in:
Carter Anderson 2020-06-09 23:16:48 -07:00
parent 3ccaebf9a5
commit 3d07fbdc81
34 changed files with 767 additions and 873 deletions

View file

@ -1,7 +1,7 @@
use crate::{light::Light, material::StandardMaterial}; use crate::{light::Light, material::StandardMaterial};
use bevy_asset::Handle; use bevy_asset::Handle;
use bevy_derive::EntityArchetype; use bevy_derive::EntityArchetype;
use bevy_render::{mesh::Mesh, Renderable}; use bevy_render::{mesh::Mesh, draw::{RenderPipelines, Draw}};
use bevy_transform::prelude::{Transform, Rotation, Scale, Translation}; use bevy_transform::prelude::{Transform, Rotation, Scale, Translation};
#[derive(EntityArchetype, Default)] #[derive(EntityArchetype, Default)]
@ -10,7 +10,8 @@ pub struct MeshEntity {
pub mesh: Handle<Mesh>, pub mesh: Handle<Mesh>,
// #[tag] // #[tag]
pub material: Handle<StandardMaterial>, pub material: Handle<StandardMaterial>,
pub renderable: Renderable, pub draw: Draw,
pub render_pipelines: RenderPipelines,
pub transform: Transform, pub transform: Transform,
pub translation: Translation, pub translation: Translation,
pub rotation: Rotation, pub rotation: Rotation,

View file

@ -4,7 +4,7 @@ use bevy_render::{
base_render_graph, base_render_graph,
pipeline::PipelineDescriptor, pipeline::PipelineDescriptor,
render_graph::{ render_graph::{
nodes::{AssetUniformNode, PassNode, UniformNode}, nodes::{AssetUniformNode, UniformNode},
RenderGraph, RenderGraph,
}, },
shader::Shader, shader::Shader,
@ -36,12 +36,7 @@ impl ForwardPbrRenderGraphBuilder for RenderGraph {
self.add_system_node(node::LIGHTS, LightsNode::new(10)); self.add_system_node(node::LIGHTS, LightsNode::new(10));
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap(); let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap(); let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
{ pipelines.add_default(build_forward_pipeline(&mut shaders));
let main_pass: &mut PassNode = self
.get_node_mut(base_render_graph::node::MAIN_PASS)
.unwrap();
main_pass.add_pipeline(pipelines.add_default(build_forward_pipeline(&mut shaders)));
}
// TODO: replace these with "autowire" groups // TODO: replace these with "autowire" groups
self.add_node_edge(node::STANDARD_MATERIAL, base_render_graph::node::MAIN_PASS) self.add_node_edge(node::STANDARD_MATERIAL, base_render_graph::node::MAIN_PASS)

View file

@ -4,7 +4,7 @@ use crate::{
RenderPassDepthStencilAttachmentDescriptor, StoreOp, TextureAttachment, RenderPassDepthStencilAttachmentDescriptor, StoreOp, TextureAttachment,
}, },
render_graph::{ render_graph::{
nodes::{CameraNode, PassNode, TextureCopyNode, WindowSwapChainNode, WindowTextureNode}, nodes::{CameraNode, MainPassNode, TextureCopyNode, WindowSwapChainNode, WindowTextureNode},
RenderGraph, RenderGraph,
}, },
texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage}, texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage},
@ -95,7 +95,7 @@ impl BaseRenderGraphBuilder for RenderGraph {
if config.add_main_pass { if config.add_main_pass {
self.add_node( self.add_node(
node::MAIN_PASS, node::MAIN_PASS,
PassNode::new(PassDescriptor { MainPassNode::new(PassDescriptor {
color_attachments: vec![RenderPassColorAttachmentDescriptor { color_attachments: vec![RenderPassColorAttachmentDescriptor {
attachment: TextureAttachment::Input("color".to_string()), attachment: TextureAttachment::Input("color".to_string()),
resolve_target: None, resolve_target: None,

View file

@ -1,41 +1,221 @@
use crate::{render_resource::RenderResourceId, pipeline::PipelineDescriptor}; use crate::{
use bevy_asset::Handle; pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineDescriptor},
use std::ops::Range; render_resource::{
RenderResourceAssignments, RenderResourceId, RenderResourceSet, RenderResourceSetId,
ResourceInfo,
},
renderer::{RenderResourceContext, RenderResources},
};
use bevy_asset::{Assets, Handle};
use bevy_property::Properties;
use legion::{
prelude::{Com, ComMut, Res},
storage::Component,
};
use std::{ops::Range, sync::Arc};
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub enum DrawType { pub enum RenderCommand {
Instanced { SetPipeline {
pipeline: Handle<PipelineDescriptor>,
},
SetVertexBuffer {
slot: u32,
buffer: RenderResourceId,
offset: u64,
},
SetIndexBuffer {
buffer: RenderResourceId,
offset: u64,
},
SetBindGroup {
index: u32,
bind_group_descriptor: BindGroupDescriptorId,
render_resource_set: RenderResourceSetId,
dynamic_uniform_indices: Option<Arc<Vec<u32>>>,
},
DrawIndexed {
indices: Range<u32>, indices: Range<u32>,
base_vertex: i32, base_vertex: i32,
instances: Range<u32>, instances: Range<u32>,
},
}
#[derive(Properties)]
pub struct Draw {
pub is_visible: bool,
#[property(ignore)]
pub render_commands: Vec<RenderCommand>,
}
impl Default for Draw {
fn default() -> Self {
Self {
is_visible: true,
render_commands: Default::default(),
}
} }
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Properties)]
pub struct VertexBufferBinding { pub struct RenderPipelines {
pub slot: u32, pub pipelines: Vec<Handle<PipelineDescriptor>>,
pub vertex_buffer: RenderResourceId, // TODO: make these pipeline specific
pub offset: u64, #[property(ignore)]
pub render_resource_assignments: RenderResourceAssignments,
#[property(ignore)]
pub compiled_pipelines: Vec<Handle<PipelineDescriptor>>,
} }
#[derive(Debug, Clone, Eq, PartialEq)] impl Default for RenderPipelines {
pub struct IndexBufferBinding { fn default() -> Self {
pub vertex_buffer: RenderResourceId, Self {
pub offset: u64, render_resource_assignments: Default::default(),
compiled_pipelines: Default::default(),
pipelines: vec![Handle::default()],
}
}
} }
#[derive(Debug, Clone, Eq, PartialEq)] impl Draw {
pub struct BindGroupBinding { pub fn get_context<'a>(
pub vertex_buffer: RenderResourceId, &'a mut self,
pub offset: u64, pipelines: &'a Assets<PipelineDescriptor>,
render_resource_context: &'a dyn RenderResourceContext,
render_resource_assignments: &'a RenderResourceAssignments,
) -> DrawContext {
DrawContext {
draw: self,
pipelines,
render_resource_context,
render_resource_assignments,
}
} }
#[derive(Debug, Clone, Eq, PartialEq)] pub fn clear_render_commands(&mut self) {
pub struct DrawCall { self.render_commands.clear();
pub pipeline: Handle<PipelineDescriptor>, }
pub draw_type: DrawType,
pub vertex_buffers: Vec<VertexBufferBinding>,
pub index_buffer: Option<IndexBufferBinding>,
} }
pub struct Draw {} pub struct DrawContext<'a> {
pub draw: &'a mut Draw,
pub pipelines: &'a Assets<PipelineDescriptor>,
pub render_resource_context: &'a dyn RenderResourceContext,
pub render_resource_assignments: &'a RenderResourceAssignments,
}
impl<'a> DrawContext<'a> {
pub fn set_pipeline(&mut self, pipeline: Handle<PipelineDescriptor>) {
self.render_command(RenderCommand::SetPipeline { pipeline });
}
pub fn set_vertex_buffer(&mut self, slot: u32, buffer: RenderResourceId, offset: u64) {
self.render_command(RenderCommand::SetVertexBuffer {
slot,
buffer,
offset,
});
}
pub fn set_index_buffer(&mut self, buffer: RenderResourceId, offset: u64) {
self.render_command(RenderCommand::SetIndexBuffer { buffer, offset });
}
pub fn set_bind_group(
&mut self,
bind_group_descriptor: &BindGroupDescriptor,
render_resource_set: &RenderResourceSet,
) {
self.render_command(RenderCommand::SetBindGroup {
index: bind_group_descriptor.index,
bind_group_descriptor: bind_group_descriptor.id,
render_resource_set: render_resource_set.id,
dynamic_uniform_indices: render_resource_set.dynamic_uniform_indices.clone(),
});
}
pub fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
self.render_command(RenderCommand::DrawIndexed {
base_vertex,
indices,
instances,
});
}
#[inline]
pub fn render_command(&mut self, render_command: RenderCommand) {
self.draw.render_commands.push(render_command);
}
pub fn draw<T: Drawable>(&mut self, drawable: &T) {
drawable.draw(self);
}
}
pub trait Drawable {
fn draw(&self, draw: &mut DrawContext);
}
impl Drawable for RenderPipelines {
fn draw(&self, draw: &mut DrawContext) {
for pipeline_handle in self.compiled_pipelines.iter() {
let pipeline = draw.pipelines.get(pipeline_handle).unwrap();
let layout = pipeline.get_layout().unwrap();
draw.set_pipeline(*pipeline_handle);
for bind_group in layout.bind_groups.iter() {
if let Some(local_render_resource_set) = self
.render_resource_assignments
.get_bind_group_render_resource_set(bind_group.id)
{
draw.set_bind_group(bind_group, local_render_resource_set);
} else if let Some(global_render_resource_set) = draw
.render_resource_assignments
.get_bind_group_render_resource_set(bind_group.id)
{
draw.set_bind_group(bind_group, global_render_resource_set);
}
}
let mut indices = 0..0;
for (slot, vertex_buffer_descriptor) in
layout.vertex_buffer_descriptors.iter().enumerate()
{
if let Some((vertex_buffer, index_buffer)) = self
.render_resource_assignments
.get_vertex_buffer(&vertex_buffer_descriptor.name)
{
draw.set_vertex_buffer(slot as u32, vertex_buffer, 0);
if let Some(index_buffer) = index_buffer {
draw.render_resource_context.get_resource_info(
index_buffer,
&mut |resource_info| match resource_info {
Some(ResourceInfo::Buffer(Some(buffer_info))) => {
indices = 0..(buffer_info.size / 2) as u32;
}
_ => panic!("expected a buffer type"),
},
);
draw.set_index_buffer(index_buffer, 0);
}
}
}
draw.draw_indexed(indices, 0, 0..1);
}
}
}
pub fn draw_system<T: Drawable + Component>(
pipelines: Res<Assets<PipelineDescriptor>>,
render_resource_assignments: Res<RenderResourceAssignments>,
render_resources: Res<RenderResources>,
mut draw: ComMut<Draw>,
drawable: Com<T>,
) {
let context = &*render_resources.context;
let mut draw_context = draw.get_context(&pipelines, context, &render_resource_assignments);
draw_context.draw(drawable.as_ref());
}
pub fn clear_draw_system(mut draw: ComMut<Draw>) {
draw.clear_render_commands();
}

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
base_render_graph, mesh::Mesh, Camera, OrthographicProjection, PerspectiveProjection, base_render_graph, mesh::Mesh, Camera, OrthographicProjection, PerspectiveProjection,
Renderable, WindowOrigin, RenderPipelines, WindowOrigin, draw::Draw,
}; };
use bevy_asset::Handle; use bevy_asset::Handle;
use bevy_derive::EntityArchetype; use bevy_derive::EntityArchetype;
@ -10,7 +10,8 @@ use bevy_transform::components::{Transform, Rotation, Scale, Translation};
pub struct MeshMaterialEntity<T: Default + Send + Sync + 'static> { pub struct MeshMaterialEntity<T: Default + Send + Sync + 'static> {
pub mesh: Handle<Mesh>, pub mesh: Handle<Mesh>,
pub material: Handle<T>, pub material: Handle<T>,
pub renderable: Renderable, pub draw: Draw,
pub render_pipelines: RenderPipelines,
pub transform: Transform, pub transform: Transform,
pub translation: Translation, pub translation: Translation,
pub rotation: Rotation, pub rotation: Rotation,

View file

@ -12,7 +12,6 @@ mod color;
pub use camera::*; pub use camera::*;
pub use color::*; pub use color::*;
pub use renderable::*;
pub use vertex::Vertex; pub use vertex::Vertex;
@ -20,20 +19,14 @@ pub mod base_render_graph;
pub mod pass; pub mod pass;
pub mod pipeline; pub mod pipeline;
pub mod render_resource; pub mod render_resource;
mod renderable;
pub mod texture; pub mod texture;
pub use once_cell; pub use once_cell;
use self::{ use self::{
mesh::Mesh, mesh::Mesh,
pipeline::{ pipeline::{PipelineCompiler, PipelineDescriptor, VertexBufferDescriptors},
PipelineAssignments, PipelineCompiler, PipelineDescriptor, VertexBufferDescriptors, render_resource::RenderResourceAssignments,
},
render_resource::{
entity_render_resource_assignments_system, EntityRenderResourceAssignments,
RenderResourceAssignments,
},
shader::Shader, shader::Shader,
texture::Texture, texture::Texture,
}; };
@ -42,6 +35,7 @@ use base_render_graph::{BaseRenderGraphBuilder, BaseRenderGraphConfig};
use bevy_app::{AppBuilder, AppPlugin}; use bevy_app::{AppBuilder, AppPlugin};
use bevy_asset::AddAsset; use bevy_asset::AddAsset;
use bevy_type_registry::RegisterType; use bevy_type_registry::RegisterType;
use draw::{clear_draw_system, Draw, RenderPipelines};
use legion::prelude::IntoSystem; use legion::prelude::IntoSystem;
use mesh::mesh_resource_provider_system; use mesh::mesh_resource_provider_system;
use render_graph::RenderGraph; use render_graph::RenderGraph;
@ -51,6 +45,7 @@ use texture::{PngTextureLoader, TextureResourceSystemState};
pub mod stage { pub mod stage {
pub static RENDER_RESOURCE: &str = "render_resource"; pub static RENDER_RESOURCE: &str = "render_resource";
pub static PRE_RENDER: &str = "pre_render";
pub static RENDER: &str = "render"; pub static RENDER: &str = "render";
} }
@ -70,30 +65,27 @@ impl Default for RenderPlugin {
impl AppPlugin for RenderPlugin { impl AppPlugin for RenderPlugin {
fn build(&self, app: &mut AppBuilder) { fn build(&self, app: &mut AppBuilder) {
app.add_stage_after(bevy_asset::stage::ASSET_EVENTS, stage::RENDER_RESOURCE) app.add_stage_after(bevy_asset::stage::ASSET_EVENTS, stage::RENDER_RESOURCE)
.add_stage_after(stage::RENDER_RESOURCE, stage::RENDER) .add_stage_after(stage::RENDER_RESOURCE, stage::PRE_RENDER)
.add_stage_after(stage::PRE_RENDER, stage::RENDER)
.add_asset::<Mesh>() .add_asset::<Mesh>()
.add_asset::<Texture>() .add_asset::<Texture>()
.add_asset::<Shader>() .add_asset::<Shader>()
.add_asset::<PipelineDescriptor>() .add_asset::<PipelineDescriptor>()
.add_asset_loader::<Texture, PngTextureLoader>() .add_asset_loader::<Texture, PngTextureLoader>()
.register_component::<Camera>() .register_component::<Camera>()
.register_component::<Draw>()
.register_component::<RenderPipelines>()
.register_component::<OrthographicProjection>() .register_component::<OrthographicProjection>()
.register_component::<PerspectiveProjection>() .register_component::<PerspectiveProjection>()
.register_component::<Renderable>()
.register_property_type::<Color>() .register_property_type::<Color>()
.register_property_type::<Range<f32>>() .register_property_type::<Range<f32>>()
.init_resource::<RenderGraph>() .init_resource::<RenderGraph>()
.init_resource::<PipelineAssignments>()
.init_resource::<PipelineCompiler>() .init_resource::<PipelineCompiler>()
.init_resource::<RenderResourceAssignments>() .init_resource::<RenderResourceAssignments>()
.init_resource::<VertexBufferDescriptors>() .init_resource::<VertexBufferDescriptors>()
.init_resource::<EntityRenderResourceAssignments>()
.init_resource::<EntitiesWaitingForAssets>() .init_resource::<EntitiesWaitingForAssets>()
.init_resource::<TextureResourceSystemState>() .init_resource::<TextureResourceSystemState>()
.add_system_to_stage( .add_system_to_stage(bevy_app::stage::PRE_UPDATE, clear_draw_system.system())
bevy_app::stage::POST_UPDATE,
entity_render_resource_assignments_system(),
)
.init_system_to_stage( .init_system_to_stage(
bevy_app::stage::POST_UPDATE, bevy_app::stage::POST_UPDATE,
camera::camera_system::<OrthographicProjection>, camera::camera_system::<OrthographicProjection>,

View file

@ -1,12 +1,11 @@
use crate::{ use crate::{
pipeline::{ pipeline::{
state_descriptors::{IndexFormat, PrimitiveTopology}, state_descriptors::{IndexFormat, PrimitiveTopology},
VertexBufferDescriptor, VertexBufferDescriptors, VertexFormat, AsVertexBufferDescriptor, VertexBufferDescriptor, VertexBufferDescriptors, VertexFormat,
AsVertexBufferDescriptor,
}, },
render_resource::{BufferInfo, BufferUsage}, render_resource::{BufferInfo, BufferUsage},
renderer::{RenderResourceContext, RenderResources}, renderer::{RenderResourceContext, RenderResources},
Renderable, Vertex, RenderPipelines, Vertex,
}; };
use bevy_app::{EventReader, Events}; use bevy_app::{EventReader, Events};
use bevy_asset::{AssetEvent, Assets, Handle}; use bevy_asset::{AssetEvent, Assets, Handle};
@ -345,7 +344,7 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
render_resources: Res<RenderResources>, render_resources: Res<RenderResources>,
meshes: Res<Assets<Mesh>>, meshes: Res<Assets<Mesh>>,
mesh_events: Res<Events<AssetEvent<Mesh>>>, mesh_events: Res<Events<AssetEvent<Mesh>>>,
query: &mut Query<(Read<Handle<Mesh>>, Write<Renderable>)>| { query: &mut Query<(Read<Handle<Mesh>>, Write<RenderPipelines>)>| {
let render_resources = &*render_resources.context; let render_resources = &*render_resources.context;
let mut changed_meshes = HashSet::new(); let mut changed_meshes = HashSet::new();
for event in mesh_event_reader.iter(&mesh_events) { for event in mesh_event_reader.iter(&mesh_events) {
@ -403,9 +402,9 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
} }
// TODO: remove this once batches are pipeline specific and deprecate assigned_meshes draw target // TODO: remove this once batches are pipeline specific and deprecate assigned_meshes draw target
for (handle, mut renderable) in query.iter_mut(world) { for (handle, mut render_pipelines) in query.iter_mut(world) {
if let Some(mesh) = meshes.get(&handle) { if let Some(mesh) = meshes.get(&handle) {
renderable render_pipelines
.render_resource_assignments .render_resource_assignments
.pipeline_specialization .pipeline_specialization
.primitive_topology = mesh.primitive_topology; .primitive_topology = mesh.primitive_topology;
@ -417,11 +416,9 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
let index_buffer = let index_buffer =
render_resources.get_asset_resource(*handle, INDEX_BUFFER_ASSET_INDEX); render_resources.get_asset_resource(*handle, INDEX_BUFFER_ASSET_INDEX);
renderable.render_resource_assignments.set_vertex_buffer( render_pipelines
"Vertex", .render_resource_assignments
vertex_buffer, .set_vertex_buffer("Vertex", vertex_buffer, index_buffer);
index_buffer,
);
} }
} }
}) })
@ -430,7 +427,7 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{Mesh, VertexAttribute, AsVertexBufferDescriptor}; use super::{AsVertexBufferDescriptor, Mesh, VertexAttribute};
use crate::{pipeline::state_descriptors::PrimitiveTopology, Vertex}; use crate::{pipeline::state_descriptors::PrimitiveTopology, Vertex};
use bevy_core::bytes::AsBytes; use bevy_core::bytes::AsBytes;

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
pipeline::{BindGroupDescriptor, PipelineDescriptor}, pipeline::{PipelineDescriptor, BindGroupDescriptorId},
render_resource::{RenderResourceId, RenderResourceSet}, render_resource::{RenderResourceId, RenderResourceSetId},
renderer::RenderContext, renderer::RenderContext,
}; };
use bevy_asset::Handle; use bevy_asset::Handle;
@ -17,7 +17,9 @@ pub trait RenderPass {
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>); fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
fn set_bind_group( fn set_bind_group(
&mut self, &mut self,
bind_group_descriptor: &BindGroupDescriptor, index: u32,
render_resource_set: &RenderResourceSet, bind_group_descriptor: BindGroupDescriptorId,
render_resource_set: RenderResourceSetId,
dynamic_uniform_indices: Option<&[u32]>,
); );
} }

View file

@ -13,23 +13,10 @@ use crate::{
}; };
use bevy_asset::Assets; use bevy_asset::Assets;
// TODO: consider removing this in favor of Option<Layout>
#[derive(Clone, Debug)]
pub enum PipelineLayoutType {
Manual(PipelineLayout),
Reflected(Option<PipelineLayout>),
}
#[derive(Clone, Debug)]
pub enum DescriptorType<T> {
Manual(T),
Reflected(Option<T>),
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PipelineDescriptor { pub struct PipelineDescriptor {
pub name: Option<String>, pub name: Option<String>,
pub layout: PipelineLayoutType, pub layout: Option<PipelineLayout>,
pub shader_stages: ShaderStages, pub shader_stages: ShaderStages,
pub rasterization_state: Option<RasterizationStateDescriptor>, pub rasterization_state: Option<RasterizationStateDescriptor>,
@ -63,7 +50,7 @@ impl PipelineDescriptor {
pub fn new(shader_stages: ShaderStages) -> Self { pub fn new(shader_stages: ShaderStages) -> Self {
PipelineDescriptor { PipelineDescriptor {
name: None, name: None,
layout: PipelineLayoutType::Reflected(None), layout: None,
color_states: Vec::new(), color_states: Vec::new(),
depth_stencil_state: None, depth_stencil_state: None,
shader_stages, shader_stages,
@ -80,7 +67,7 @@ impl PipelineDescriptor {
PipelineDescriptor { PipelineDescriptor {
name: None, name: None,
primitive_topology: PrimitiveTopology::TriangleList, primitive_topology: PrimitiveTopology::TriangleList,
layout: PipelineLayoutType::Reflected(None), layout: None,
index_format: IndexFormat::Uint16, index_format: IndexFormat::Uint16,
sample_count: 1, sample_count: 1,
sample_mask: !0, sample_mask: !0,
@ -120,17 +107,11 @@ impl PipelineDescriptor {
} }
pub fn get_layout(&self) -> Option<&PipelineLayout> { pub fn get_layout(&self) -> Option<&PipelineLayout> {
match self.layout { self.layout.as_ref()
PipelineLayoutType::Reflected(ref layout) => layout.as_ref(),
PipelineLayoutType::Manual(ref layout) => Some(layout),
}
} }
pub fn get_layout_mut(&mut self) -> Option<&mut PipelineLayout> { pub fn get_layout_mut(&mut self) -> Option<&mut PipelineLayout> {
match self.layout { self.layout.as_mut()
PipelineLayoutType::Reflected(ref mut layout) => layout.as_mut(),
PipelineLayoutType::Manual(ref mut layout) => Some(layout),
}
} }
/// Reflects the pipeline layout from its shaders. /// Reflects the pipeline layout from its shaders.
@ -190,6 +171,6 @@ impl PipelineDescriptor {
} }
} }
self.layout = PipelineLayoutType::Reflected(Some(layout)); self.layout = Some(layout);
} }
} }

View file

@ -1,8 +1,8 @@
use super::{state_descriptors::PrimitiveTopology, PipelineDescriptor, VertexBufferDescriptors}; use super::{state_descriptors::PrimitiveTopology, PipelineDescriptor, VertexBufferDescriptors};
use crate::{ use crate::{
render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId}, draw::RenderPipelines,
renderer::{RenderResourceContext, RenderResources},
shader::{Shader, ShaderSource}, shader::{Shader, ShaderSource},
Renderable,
}; };
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
@ -78,14 +78,15 @@ impl PipelineCompiler {
vertex_buffer_descriptors: &VertexBufferDescriptors, vertex_buffer_descriptors: &VertexBufferDescriptors,
shaders: &mut Assets<Shader>, shaders: &mut Assets<Shader>,
pipeline_descriptor: &PipelineDescriptor, pipeline_descriptor: &PipelineDescriptor,
render_resource_assignments: &RenderResourceAssignments, render_pipelines: &RenderPipelines,
) -> PipelineDescriptor { ) -> PipelineDescriptor {
let mut compiled_pipeline_descriptor = pipeline_descriptor.clone(); let mut compiled_pipeline_descriptor = pipeline_descriptor.clone();
compiled_pipeline_descriptor.shader_stages.vertex = self.compile_shader( compiled_pipeline_descriptor.shader_stages.vertex = self.compile_shader(
shaders, shaders,
&pipeline_descriptor.shader_stages.vertex, &pipeline_descriptor.shader_stages.vertex,
&render_resource_assignments &render_pipelines
.render_resource_assignments
.pipeline_specialization .pipeline_specialization
.shader_specialization, .shader_specialization,
); );
@ -97,7 +98,8 @@ impl PipelineCompiler {
self.compile_shader( self.compile_shader(
shaders, shaders,
fragment, fragment,
&render_resource_assignments &render_pipelines
.render_resource_assignments
.pipeline_specialization .pipeline_specialization
.shader_specialization, .shader_specialization,
) )
@ -107,72 +109,78 @@ impl PipelineCompiler {
shaders, shaders,
true, true,
Some(vertex_buffer_descriptors), Some(vertex_buffer_descriptors),
Some(render_resource_assignments), Some(&render_pipelines.render_resource_assignments),
); );
compiled_pipeline_descriptor.primitive_topology = render_resource_assignments compiled_pipeline_descriptor.primitive_topology = render_pipelines
.render_resource_assignments
.pipeline_specialization .pipeline_specialization
.primitive_topology; .primitive_topology;
compiled_pipeline_descriptor compiled_pipeline_descriptor
} }
fn update_shader_assignments( fn compile_pipelines(
&mut self, &mut self,
vertex_buffer_descriptors: &VertexBufferDescriptors, vertex_buffer_descriptors: &VertexBufferDescriptors,
shader_pipeline_assignments: &mut PipelineAssignments,
pipelines: &mut Assets<PipelineDescriptor>, pipelines: &mut Assets<PipelineDescriptor>,
shaders: &mut Assets<Shader>, shaders: &mut Assets<Shader>,
pipeline_handles: &[Handle<PipelineDescriptor>], render_pipelines: &mut RenderPipelines,
render_resource_assignments: &RenderResourceAssignments, render_resource_context: &dyn RenderResourceContext,
) { ) {
for pipeline_handle in pipeline_handles.iter() { for (i, pipeline_handle) in render_pipelines.pipelines.iter().enumerate() {
if let None = self.pipeline_source_to_compiled.get(pipeline_handle) { if let None = self.pipeline_source_to_compiled.get(pipeline_handle) {
self.pipeline_source_to_compiled self.pipeline_source_to_compiled
.insert(*pipeline_handle, Vec::new()); .insert(*pipeline_handle, Vec::new());
} }
let final_handle = if let Some((_shader_defs, macroed_pipeline_handle)) = self let compiled_pipeline_handle = if let Some((_shader_defs, compiled_pipeline_handle)) =
.pipeline_source_to_compiled self.pipeline_source_to_compiled
.get_mut(pipeline_handle) .get_mut(pipeline_handle)
.unwrap() .unwrap()
.iter() .iter()
.find(|(pipeline_specialization, _macroed_pipeline_handle)| { .find(|(pipeline_specialization, _compiled_pipeline_handle)| {
*pipeline_specialization == render_resource_assignments.pipeline_specialization *pipeline_specialization
== render_pipelines
.render_resource_assignments
.pipeline_specialization
}) { }) {
*macroed_pipeline_handle *compiled_pipeline_handle
} else { } else {
let pipeline_descriptor = pipelines.get(pipeline_handle).unwrap(); let pipeline_descriptor = pipelines.get(pipeline_handle).unwrap();
let compiled_pipeline = self.compile_pipeline( let compiled_pipeline_descriptor = self.compile_pipeline(
vertex_buffer_descriptors, vertex_buffer_descriptors,
shaders, shaders,
pipeline_descriptor, pipeline_descriptor,
render_resource_assignments, render_pipelines,
);
let compiled_pipeline_handle = pipelines.add(compiled_pipeline_descriptor);
render_resource_context.create_render_pipeline(
compiled_pipeline_handle,
pipelines.get(&compiled_pipeline_handle).unwrap(),
&shaders,
); );
let compiled_pipeline_handle = pipelines.add(compiled_pipeline);
let macro_pipelines = self let compiled_pipelines = self
.pipeline_source_to_compiled .pipeline_source_to_compiled
.get_mut(pipeline_handle) .get_mut(pipeline_handle)
.unwrap(); .unwrap();
macro_pipelines.push(( compiled_pipelines.push((
render_resource_assignments.pipeline_specialization.clone(), render_pipelines
.render_resource_assignments
.pipeline_specialization
.clone(),
compiled_pipeline_handle, compiled_pipeline_handle,
)); ));
compiled_pipeline_handle compiled_pipeline_handle
}; };
// TODO: this will break down if pipeline layout changes. fix this with "auto-layout" if i == render_pipelines.compiled_pipelines.len() {
if let None = shader_pipeline_assignments.assignments.get(&final_handle) { render_pipelines
shader_pipeline_assignments .compiled_pipelines
.assignments .push(compiled_pipeline_handle);
.insert(final_handle, Vec::new()); } else {
render_pipelines.compiled_pipelines[i] = compiled_pipeline_handle;
} }
let assignments = shader_pipeline_assignments
.assignments
.get_mut(&final_handle)
.unwrap();
assignments.push(render_resource_assignments.id);
} }
} }
@ -199,44 +207,30 @@ impl PipelineCompiler {
} }
} }
#[derive(Default)]
pub struct PipelineAssignments {
pub assignments: HashMap<Handle<PipelineDescriptor>, Vec<RenderResourceAssignmentsId>>,
}
// TODO: make this a system // TODO: make this a system
pub fn update_shader_assignments(world: &mut World, resources: &Resources) { pub fn compile_pipelines_system(
// PERF: this seems like a lot of work for things that don't change that often. world: &mut SubWorld,
// lots of string + hashset allocations. sees uniform_resource_provider for more context mut pipeline_compiler: ResMut<PipelineCompiler>,
{ mut shaders: ResMut<Assets<Shader>>,
let mut shader_pipeline_assignments = resources.get_mut::<PipelineAssignments>().unwrap(); mut pipelines: ResMut<Assets<PipelineDescriptor>>,
let mut pipeline_compiler = resources.get_mut::<PipelineCompiler>().unwrap(); vertex_buffer_descriptors: Res<VertexBufferDescriptors>,
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap(); render_resources: Res<RenderResources>,
let vertex_buffer_descriptors = resources.get::<VertexBufferDescriptors>().unwrap(); query: &mut Query<Write<RenderPipelines>>,
let mut pipeline_descriptor_storage = ) {
resources.get_mut::<Assets<PipelineDescriptor>>().unwrap(); let render_resource_context = &*render_resources.context;
// reset assignments so they are updated every frame // TODO: only update when RenderPipelines is changed
shader_pipeline_assignments.assignments = HashMap::new(); for mut render_pipelines in query.iter_mut(world) {
pipeline_compiler.compile_pipelines(
// TODO: only update when renderable is changed
for mut renderable in <Write<Renderable>>::query().iter_mut(world) {
// skip instanced entities. their batched RenderResourceAssignments will handle shader assignments
if renderable.is_instanced {
continue;
}
pipeline_compiler.update_shader_assignments(
&vertex_buffer_descriptors, &vertex_buffer_descriptors,
&mut shader_pipeline_assignments, &mut pipelines,
&mut pipeline_descriptor_storage,
&mut shaders, &mut shaders,
&renderable.pipelines, &mut render_pipelines,
&renderable.render_resource_assignments, render_resource_context,
); );
// reset shader_defs so they can be changed next frame // reset shader_defs so they can be changed next frame
renderable render_pipelines
.render_resource_assignments .render_resource_assignments
.pipeline_specialization .pipeline_specialization
.shader_specialization .shader_specialization
@ -244,4 +238,3 @@ pub fn update_shader_assignments(world: &mut World, resources: &Resources) {
.clear(); .clear();
} }
} }
}

View file

@ -1,28 +1,20 @@
use crate::{ use crate::{
pass::{PassDescriptor, RenderPass, TextureAttachment}, draw::{Draw, RenderCommand},
pipeline::{PipelineAssignments, PipelineCompiler, PipelineDescriptor}, pass::{PassDescriptor, TextureAttachment},
render_graph::{Node, ResourceSlotInfo, ResourceSlots}, render_graph::{Node, ResourceSlotInfo, ResourceSlots},
render_resource::{ render_resource::{EntitiesWaitingForAssets, RenderResourceAssignments, ResourceInfo},
EntitiesWaitingForAssets, EntityRenderResourceAssignments, RenderResourceAssignments,
ResourceInfo,
},
renderer::RenderContext, renderer::RenderContext,
shader::Shader,
Renderable,
}; };
use bevy_asset::{Assets, Handle};
use legion::prelude::*; use legion::prelude::*;
use std::ops::Range;
pub struct PassNode { pub struct MainPassNode {
descriptor: PassDescriptor, descriptor: PassDescriptor,
pipelines: Vec<Handle<PipelineDescriptor>>,
inputs: Vec<ResourceSlotInfo>, inputs: Vec<ResourceSlotInfo>,
color_attachment_input_indices: Vec<Option<usize>>, color_attachment_input_indices: Vec<Option<usize>>,
depth_stencil_attachment_input_index: Option<usize>, depth_stencil_attachment_input_index: Option<usize>,
} }
impl PassNode { impl MainPassNode {
pub fn new(descriptor: PassDescriptor) -> Self { pub fn new(descriptor: PassDescriptor) -> Self {
let mut inputs = Vec::new(); let mut inputs = Vec::new();
let mut color_attachment_input_indices = Vec::new(); let mut color_attachment_input_indices = Vec::new();
@ -49,77 +41,16 @@ impl PassNode {
} }
} }
PassNode { MainPassNode {
descriptor, descriptor,
pipelines: Vec::new(),
inputs, inputs,
color_attachment_input_indices, color_attachment_input_indices,
depth_stencil_attachment_input_index, depth_stencil_attachment_input_index,
} }
} }
pub fn add_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>) {
self.pipelines.push(pipeline_handle);
} }
fn set_render_resources( impl Node for MainPassNode {
render_pass: &mut dyn RenderPass,
pipeline_descriptor: &PipelineDescriptor,
render_resource_assignments: &RenderResourceAssignments,
) -> Option<Range<u32>> {
let pipeline_layout = pipeline_descriptor.get_layout().unwrap();
// PERF: vertex buffer lookup comes at a cost when vertex buffers aren't in render_resource_assignments. iterating over render_resource_assignment vertex buffers
// would likely be faster
let mut indices = None;
for (i, vertex_buffer_descriptor) in
pipeline_layout.vertex_buffer_descriptors.iter().enumerate()
{
if let Some((vertex_buffer, index_buffer)) =
render_resource_assignments.get_vertex_buffer(&vertex_buffer_descriptor.name)
{
log::trace!(
"set vertex buffer {}: {} ({:?})",
i,
vertex_buffer_descriptor.name,
vertex_buffer
);
render_pass.set_vertex_buffer(i as u32, vertex_buffer, 0);
if let Some(index_buffer) = index_buffer {
log::trace!(
"set index buffer: {} ({:?})",
vertex_buffer_descriptor.name,
index_buffer
);
render_pass.set_index_buffer(index_buffer, 0);
render_pass
.get_render_context()
.resources()
.get_resource_info(
index_buffer,
&mut |resource_info| match resource_info {
Some(ResourceInfo::Buffer(Some(buffer_info))) => {
indices = Some(0..(buffer_info.size / 2) as u32)
}
_ => panic!("expected a buffer type"),
},
);
}
}
}
for bind_group in pipeline_layout.bind_groups.iter() {
if let Some(render_resource_set) =
render_resource_assignments.get_render_resource_set(bind_group.id)
{
render_pass.set_bind_group(bind_group, &render_resource_set);
}
}
indices
}
}
impl Node for PassNode {
fn input(&self) -> &[ResourceSlotInfo] { fn input(&self) -> &[ResourceSlotInfo] {
&self.inputs &self.inputs
} }
@ -132,14 +63,8 @@ impl Node for PassNode {
input: &ResourceSlots, input: &ResourceSlots,
_output: &mut ResourceSlots, _output: &mut ResourceSlots,
) { ) {
let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap();
let pipelines = resources.get::<Assets<PipelineDescriptor>>().unwrap();
let shader_pipeline_assignments = resources.get::<PipelineAssignments>().unwrap();
let entity_render_resource_assignments =
resources.get::<EntityRenderResourceAssignments>().unwrap();
let entities_waiting_for_assets = resources.get::<EntitiesWaitingForAssets>().unwrap(); let entities_waiting_for_assets = resources.get::<EntitiesWaitingForAssets>().unwrap();
let mut render_resource_assignments = let render_resource_assignments = resources.get::<RenderResourceAssignments>().unwrap();
resources.get_mut::<RenderResourceAssignments>().unwrap();
for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() { for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() {
if let Some(input_index) = self.color_attachment_input_indices[i] { if let Some(input_index) = self.color_attachment_input_indices[i] {
@ -156,117 +81,56 @@ impl Node for PassNode {
.attachment = TextureAttachment::RenderResource(input.get(input_index).unwrap()); .attachment = TextureAttachment::RenderResource(input.get(input_index).unwrap());
} }
{
let render_resource_context = render_context.resources();
// TODO: try merging the two pipeline loops below
let shaders = resources.get::<Assets<Shader>>().unwrap();
for pipeline_handle in self.pipelines.iter() {
if let Some(compiled_pipelines_iter) =
pipeline_compiler.iter_compiled_pipelines(*pipeline_handle)
{
for compiled_pipeline_handle in compiled_pipelines_iter {
let compiled_pipeline_descriptor =
pipelines.get(compiled_pipeline_handle).unwrap();
let pipeline_layout = compiled_pipeline_descriptor.get_layout().unwrap();
{
// TODO: this breaks down in a parallel setting. it needs to change. ideally in a way that
// doesn't require modifying RenderResourceAssignments
for bind_group in pipeline_layout.bind_groups.iter() {
render_resource_assignments
.update_render_resource_set_id(bind_group);
}
}
render_resource_context.create_render_pipeline(
*compiled_pipeline_handle,
&compiled_pipeline_descriptor,
&shaders,
);
render_resource_context.setup_bind_groups(
compiled_pipeline_descriptor,
&render_resource_assignments,
);
let assigned_render_resource_assignments = shader_pipeline_assignments
.assignments
.get(&compiled_pipeline_handle);
if let Some(assigned_render_resource_assignments) =
assigned_render_resource_assignments
{
for assignment_id in assigned_render_resource_assignments.iter() {
let entity = entity_render_resource_assignments
.get(*assignment_id)
.unwrap();
let renderable =
world.get_component::<Renderable>(*entity).unwrap();
if !renderable.is_visible || renderable.is_instanced {
continue;
}
render_resource_context.setup_bind_groups(
compiled_pipeline_descriptor,
&renderable.render_resource_assignments,
);
}
}
}
}
}
}
render_context.begin_pass( render_context.begin_pass(
&self.descriptor, &self.descriptor,
&render_resource_assignments, &render_resource_assignments,
&mut |render_pass| { &mut |render_pass| {
for pipeline_handle in self.pipelines.iter() { for (entity, draw) in <Read<Draw>>::query().iter_entities(&world) {
if let Some(compiled_pipelines_iter) = if !draw.is_visible || entities_waiting_for_assets.contains(&entity) {
pipeline_compiler.iter_compiled_pipelines(*pipeline_handle)
{
for compiled_pipeline_handle in compiled_pipelines_iter {
let compiled_pipeline_descriptor =
pipelines.get(compiled_pipeline_handle).unwrap();
render_pass.set_pipeline(*compiled_pipeline_handle);
// set global render resources
Self::set_render_resources(
render_pass,
compiled_pipeline_descriptor,
&render_resource_assignments,
);
// draw entities assigned to this pipeline
let assigned_render_resource_assignments = shader_pipeline_assignments
.assignments
.get(&compiled_pipeline_handle);
if let Some(assigned_render_resource_assignments) =
assigned_render_resource_assignments
{
for assignment_id in assigned_render_resource_assignments.iter() {
// TODO: hopefully legion has better random access apis that are more like queries?
let entity = entity_render_resource_assignments
.get(*assignment_id)
.unwrap();
let renderable =
world.get_component::<Renderable>(*entity).unwrap();
if !renderable.is_visible
|| renderable.is_instanced
|| entities_waiting_for_assets.contains(entity)
{
continue; continue;
} }
// set local render resources for render_command in draw.render_commands.iter() {
if let Some(indices) = Self::set_render_resources( match render_command {
render_pass, RenderCommand::SetPipeline { pipeline } => {
compiled_pipeline_descriptor, // TODO: Filter pipelines
&renderable.render_resource_assignments, render_pass.set_pipeline(*pipeline);
) {
render_pass.draw_indexed(indices, 0, 0..1);
} }
RenderCommand::DrawIndexed {
base_vertex,
indices,
instances,
} => {
render_pass.draw_indexed(
indices.clone(),
*base_vertex,
instances.clone(),
);
} }
RenderCommand::SetVertexBuffer {
buffer,
offset,
slot,
} => {
render_pass.set_vertex_buffer(*slot, *buffer, *offset);
}
RenderCommand::SetIndexBuffer { buffer, offset } => {
render_pass.set_index_buffer(*buffer, *offset);
}
RenderCommand::SetBindGroup {
index,
bind_group_descriptor,
render_resource_set,
dynamic_uniform_indices,
} => {
render_pass.set_bind_group(
*index,
*bind_group_descriptor,
*render_resource_set,
dynamic_uniform_indices
.as_ref()
.map(|indices| indices.as_slice()),
);
} }
} }
} }

View file

@ -1,11 +1,13 @@
use crate::{ use crate::{
draw::{Draw, RenderPipelines},
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode}, render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
render_resource::{ render_resource::{
self, BufferInfo, BufferUsage, EntitiesWaitingForAssets, RenderResourceAssignment, self, BufferInfo, BufferUsage, EntitiesWaitingForAssets, RenderResourceAssignment,
RenderResourceAssignments, RenderResourceAssignmentsId, RenderResourceId, RenderResourceHints, RenderResourceAssignments, RenderResourceAssignmentsId, RenderResourceHints,
RenderResourceId,
}, },
renderer::{RenderContext, RenderResourceContext, RenderResources}, renderer::{RenderContext, RenderResourceContext, RenderResources},
texture, Renderable, texture,
}; };
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
@ -218,7 +220,9 @@ where
// TODO: RE-ADD support for BufferUsage::STORAGE type // TODO: RE-ADD support for BufferUsage::STORAGE type
let mut usage = BufferUsage::UNIFORM; let mut usage = BufferUsage::UNIFORM;
if let Some(render_resource_hints) = uniforms.get_render_resource_hints(i) { if let Some(render_resource_hints) =
uniforms.get_render_resource_hints(i)
{
if render_resource_hints.contains(RenderResourceHints::BUFFER) { if render_resource_hints.contains(RenderResourceHints::BUFFER) {
usage = BufferUsage::STORAGE usage = BufferUsage::STORAGE
} }
@ -396,8 +400,8 @@ where
.read_resource::<RenderResources>() .read_resource::<RenderResources>()
.read_resource::<EntitiesWaitingForAssets>() .read_resource::<EntitiesWaitingForAssets>()
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same // 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<T>, Read<Draw>, Read<RenderPipelines>)>::query())
.with_query(<(Read<T>, Write<Renderable>)>::query()) .with_query(<(Read<T>, Read<Draw>, Write<RenderPipelines>)>::query())
.build( .build(
move |_, move |_,
world, world,
@ -407,61 +411,51 @@ where
uniform_buffer_arrays.reset_new_item_counts(); uniform_buffer_arrays.reset_new_item_counts();
// update uniforms info // update uniforms info
for (uniforms, renderable) in read_uniform_query.iter(world) { for (uniforms, draw, _render_pipelines) in read_uniform_query.iter(world) {
if !renderable.is_visible { if !draw.is_visible {
return; return;
} }
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
uniform_buffer_arrays.increment_uniform_counts(&uniforms); uniform_buffer_arrays.increment_uniform_counts(&uniforms);
} }
}
uniform_buffer_arrays uniform_buffer_arrays
.setup_buffer_arrays(render_resource_context, dynamic_uniforms); .setup_buffer_arrays(render_resource_context, dynamic_uniforms);
let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets(); let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets();
for (entity, (uniforms, mut renderable)) in for (entity, (uniforms, draw, mut render_pipelines)) in
write_uniform_query.iter_entities_mut(world) write_uniform_query.iter_entities_mut(world)
{ {
if !renderable.is_visible { if !draw.is_visible {
return; return;
} }
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
setup_uniform_texture_resources::<T>( setup_uniform_texture_resources::<T>(
entity, entity,
&uniforms, &uniforms,
render_resource_context, render_resource_context,
entities_waiting_for_assets, entities_waiting_for_assets,
&mut renderable.render_resource_assignments, &mut render_pipelines.render_resource_assignments,
) )
} }
}
if staging_buffer_size == 0 { if staging_buffer_size == 0 {
let mut staging_buffer: [u8; 0] = []; let mut staging_buffer: [u8; 0] = [];
for (uniforms, mut renderable) in write_uniform_query.iter_mut(world) { for (uniforms, draw, mut render_pipelines) in
if !renderable.is_visible { write_uniform_query.iter_mut(world)
{
if !draw.is_visible {
return; return;
} }
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
uniform_buffer_arrays.setup_uniform_buffer_resources( uniform_buffer_arrays.setup_uniform_buffer_resources(
&uniforms, &uniforms,
dynamic_uniforms, dynamic_uniforms,
render_resource_context, render_resource_context,
&mut renderable.render_resource_assignments, &mut render_pipelines.render_resource_assignments,
&mut staging_buffer, &mut staging_buffer,
); );
} }
}
} else { } else {
let staging_buffer = render_resource_context.create_buffer_mapped( let staging_buffer = render_resource_context.create_buffer_mapped(
BufferInfo { BufferInfo {
@ -470,23 +464,21 @@ where
..Default::default() ..Default::default()
}, },
&mut |mut staging_buffer, _render_resources| { &mut |mut staging_buffer, _render_resources| {
for (uniforms, mut renderable) in write_uniform_query.iter_mut(world) { for (uniforms, draw, mut render_pipelines) in
if !renderable.is_visible { write_uniform_query.iter_mut(world)
{
if !draw.is_visible {
return; return;
} }
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
uniform_buffer_arrays.setup_uniform_buffer_resources( uniform_buffer_arrays.setup_uniform_buffer_resources(
&uniforms, &uniforms,
dynamic_uniforms, dynamic_uniforms,
render_resource_context, render_resource_context,
&mut renderable.render_resource_assignments, &mut render_pipelines.render_resource_assignments,
&mut staging_buffer, &mut staging_buffer,
); );
} }
}
}, },
); );
@ -552,8 +544,8 @@ where
.read_resource::<RenderResources>() .read_resource::<RenderResources>()
.read_resource::<EntitiesWaitingForAssets>() .read_resource::<EntitiesWaitingForAssets>()
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same // 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>>, Read<Draw>, Read<RenderPipelines>)>::query())
.with_query(<(Read<Handle<T>>, Write<Renderable>)>::query()) .with_query(<(Read<Handle<T>>, Read<Draw>, Write<RenderPipelines>)>::query())
.build( .build(
move |_, move |_,
world, world,
@ -563,14 +555,13 @@ where
uniform_buffer_arrays.reset_new_item_counts(); uniform_buffer_arrays.reset_new_item_counts();
// update uniform handles info // update uniform handles info
for (entity, (handle, renderable)) in read_handle_query.iter_entities(world) { for (entity, (handle, draw, _render_pipelines)) in
if !renderable.is_visible { read_handle_query.iter_entities(world)
{
if !draw.is_visible {
return; return;
} }
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
if let Some(uniforms) = assets.get(&handle) { if let Some(uniforms) = assets.get(&handle) {
// TODO: only increment count if we haven't seen this uniform handle before // TODO: only increment count if we haven't seen this uniform handle before
uniform_buffer_arrays.increment_uniform_counts(&uniforms); uniform_buffer_arrays.increment_uniform_counts(&uniforms);
@ -578,54 +569,47 @@ where
entities_waiting_for_assets.add(entity) entities_waiting_for_assets.add(entity)
} }
} }
}
uniform_buffer_arrays uniform_buffer_arrays
.setup_buffer_arrays(render_resource_context, dynamic_uniforms); .setup_buffer_arrays(render_resource_context, dynamic_uniforms);
let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets(); let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets();
for (entity, (handle, mut renderable)) in for (entity, (handle, draw, mut render_pipelines)) in
write_handle_query.iter_entities_mut(world) write_handle_query.iter_entities_mut(world)
{ {
if !renderable.is_visible { if !draw.is_visible {
return; return;
} }
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
if let Some(uniforms) = assets.get(&handle) { if let Some(uniforms) = assets.get(&handle) {
setup_uniform_texture_resources::<T>( setup_uniform_texture_resources::<T>(
entity, entity,
&uniforms, &uniforms,
render_resource_context, render_resource_context,
entities_waiting_for_assets, entities_waiting_for_assets,
&mut renderable.render_resource_assignments, &mut render_pipelines.render_resource_assignments,
) )
} }
} }
}
if staging_buffer_size == 0 { if staging_buffer_size == 0 {
let mut staging_buffer: [u8; 0] = []; let mut staging_buffer: [u8; 0] = [];
for (handle, mut renderable) in write_handle_query.iter_mut(world) { for (handle, draw, mut render_pipelines) in
if !renderable.is_visible { write_handle_query.iter_mut(world)
{
if !draw.is_visible {
return; return;
} }
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
if let Some(uniforms) = assets.get(&handle) { if let Some(uniforms) = assets.get(&handle) {
// TODO: only setup buffer if we haven't seen this handle before // TODO: only setup buffer if we haven't seen this handle before
uniform_buffer_arrays.setup_uniform_buffer_resources( uniform_buffer_arrays.setup_uniform_buffer_resources(
&uniforms, &uniforms,
dynamic_uniforms, dynamic_uniforms,
render_resource_context, render_resource_context,
&mut renderable.render_resource_assignments, &mut render_pipelines.render_resource_assignments,
&mut staging_buffer, &mut staging_buffer,
); );
} }
} }
}
} else { } else {
let staging_buffer = render_resource_context.create_buffer_mapped( let staging_buffer = render_resource_context.create_buffer_mapped(
BufferInfo { BufferInfo {
@ -634,25 +618,23 @@ where
..Default::default() ..Default::default()
}, },
&mut |mut staging_buffer, _render_resources| { &mut |mut staging_buffer, _render_resources| {
for (handle, mut renderable) in write_handle_query.iter_mut(world) { for (handle, draw, mut render_pipelines) in
if !renderable.is_visible { write_handle_query.iter_mut(world)
{
if !draw.is_visible {
return; return;
} }
if renderable.is_instanced {
panic!("instancing not currently supported");
} else {
if let Some(uniforms) = assets.get(&handle) { if let Some(uniforms) = assets.get(&handle) {
// TODO: only setup buffer if we haven't seen this handle before // TODO: only setup buffer if we haven't seen this handle before
uniform_buffer_arrays.setup_uniform_buffer_resources( uniform_buffer_arrays.setup_uniform_buffer_resources(
&uniforms, &uniforms,
dynamic_uniforms, dynamic_uniforms,
render_resource_context, render_resource_context,
&mut renderable.render_resource_assignments, &mut render_pipelines.render_resource_assignments,
&mut staging_buffer, &mut staging_buffer,
); );
} }
} }
}
}, },
); );

View file

@ -1,31 +0,0 @@
use super::RenderResourceAssignmentsId;
use crate::Renderable;
use legion::prelude::*;
use std::collections::HashMap;
#[derive(Default)]
pub struct EntityRenderResourceAssignments {
entity_assignments: HashMap<RenderResourceAssignmentsId, Entity>,
}
impl EntityRenderResourceAssignments {
pub fn set(&mut self, id: RenderResourceAssignmentsId, entity: Entity) {
self.entity_assignments.insert(id, entity);
}
pub fn get(&self, id: RenderResourceAssignmentsId) -> Option<&Entity> {
self.entity_assignments.get(&id)
}
}
// TODO: make sure this runs right before rendering
pub fn entity_render_resource_assignments_system() -> Box<dyn Schedulable> {
SystemBuilder::new("entity_render_resource_assignments")
.write_resource::<EntityRenderResourceAssignments>()
.with_query(<Write<Renderable>>::query().filter(changed::<Renderable>()))
.build(|_, world, entity_assignments, query| {
for (entity, renderable) in query.iter_entities_mut(world) {
entity_assignments.set(renderable.render_resource_assignments.id, entity);
}
})
}

View file

@ -1,13 +1,13 @@
mod buffer; mod buffer;
mod entities_waiting_for_assets; mod entities_waiting_for_assets;
mod entity_render_resource_assignments;
mod render_resource; mod render_resource;
mod render_resource_assignments; mod render_resource_assignments;
mod resource_info; mod resource_info;
mod systems;
pub use buffer::*; pub use buffer::*;
pub use entities_waiting_for_assets::*; pub use entities_waiting_for_assets::*;
pub use entity_render_resource_assignments::*;
pub use render_resource::*; pub use render_resource::*;
pub use render_resource_assignments::*; pub use render_resource_assignments::*;
pub use resource_info::*; pub use resource_info::*;
pub use systems::*;

View file

@ -4,6 +4,7 @@ use std::{
collections::{hash_map::DefaultHasher, HashMap, HashSet}, collections::{hash_map::DefaultHasher, HashMap, HashSet},
hash::{Hash, Hasher}, hash::{Hash, Hasher},
ops::Range, ops::Range,
sync::Arc,
}; };
use uuid::Uuid; use uuid::Uuid;
@ -28,10 +29,25 @@ impl RenderResourceAssignment {
} }
} }
#[derive(Eq, PartialEq, Debug)]
pub struct IndexedRenderResourceAssignment {
pub index: u32,
pub assignment: RenderResourceAssignment,
}
// TODO: consider renaming this to BindGroup for parity with renderer terminology
#[derive(Eq, PartialEq, Debug)] #[derive(Eq, PartialEq, Debug)]
pub struct RenderResourceSet { pub struct RenderResourceSet {
pub id: RenderResourceSetId, pub id: RenderResourceSetId,
pub dynamic_uniform_indices: Option<Vec<u32>>, pub indexed_assignments: Vec<IndexedRenderResourceAssignment>,
pub dynamic_uniform_indices: Option<Arc<Vec<u32>>>,
}
#[derive(Eq, PartialEq, Debug)]
pub enum RenderResourceSetStatus {
Changed(RenderResourceSetId),
Unchanged(RenderResourceSetId),
NoMatch,
} }
// PERF: if the assignments are scoped to a specific pipeline layout, then names could be replaced with indices here for a perf boost // PERF: if the assignments are scoped to a specific pipeline layout, then names could be replaced with indices here for a perf boost
@ -40,8 +56,9 @@ pub struct RenderResourceAssignments {
pub id: RenderResourceAssignmentsId, pub id: RenderResourceAssignmentsId,
render_resources: HashMap<String, RenderResourceAssignment>, render_resources: HashMap<String, RenderResourceAssignment>,
vertex_buffers: HashMap<String, (RenderResourceId, Option<RenderResourceId>)>, vertex_buffers: HashMap<String, (RenderResourceId, Option<RenderResourceId>)>,
bind_group_resource_sets: HashMap<BindGroupDescriptorId, RenderResourceSet>, render_resource_sets: HashMap<RenderResourceSetId, RenderResourceSet>,
dirty_bind_groups: HashSet<BindGroupDescriptorId>, bind_group_render_resource_sets: HashMap<BindGroupDescriptorId, RenderResourceSetId>,
dirty_render_resource_sets: HashSet<RenderResourceSetId>,
pub pipeline_specialization: PipelineSpecialization, pub pipeline_specialization: PipelineSpecialization,
} }
@ -58,9 +75,8 @@ impl RenderResourceAssignments {
fn try_set_dirty(&mut self, name: &str, assignment: &RenderResourceAssignment) { fn try_set_dirty(&mut self, name: &str, assignment: &RenderResourceAssignment) {
if let Some(current_assignment) = self.render_resources.get(name) { if let Some(current_assignment) = self.render_resources.get(name) {
if current_assignment != assignment { if current_assignment != assignment {
// TODO: this is pretty crude. can we do better? for id in self.render_resource_sets.keys() {
for bind_group_id in self.bind_group_resource_sets.keys() { self.dirty_render_resource_sets.insert(*id);
self.dirty_bind_groups.insert(*bind_group_id);
} }
} }
} }
@ -83,36 +99,54 @@ impl RenderResourceAssignments {
.insert(name.to_string(), (vertices_resource, indices_resource)); .insert(name.to_string(), (vertices_resource, indices_resource));
} }
pub fn update_render_resource_set_id( fn create_render_resource_set(
&mut self, &mut self,
bind_group_descriptor: &BindGroupDescriptor, bind_group_descriptor: &BindGroupDescriptor,
) -> Option<RenderResourceSetId> { ) -> RenderResourceSetStatus {
if !self
.bind_group_resource_sets
.contains_key(&bind_group_descriptor.id)
|| self.dirty_bind_groups.contains(&bind_group_descriptor.id)
{
let resource_set = self.generate_render_resource_set(bind_group_descriptor); let resource_set = self.generate_render_resource_set(bind_group_descriptor);
if let Some(resource_set) = resource_set { if let Some(resource_set) = resource_set {
let id = resource_set.id; let id = resource_set.id;
self.bind_group_resource_sets self.render_resource_sets.insert(id, resource_set);
.insert(bind_group_descriptor.id, resource_set); self.bind_group_render_resource_sets
Some(id) .insert(bind_group_descriptor.id, id);
RenderResourceSetStatus::Changed(id)
} else { } else {
None RenderResourceSetStatus::NoMatch
}
} else {
self.bind_group_resource_sets
.get(&bind_group_descriptor.id)
.map(|set| set.id)
} }
} }
pub fn get_render_resource_set( pub fn update_bind_group(
&mut self,
bind_group_descriptor: &BindGroupDescriptor,
) -> RenderResourceSetStatus {
if let Some(id) = self
.bind_group_render_resource_sets
.get(&bind_group_descriptor.id)
{
if self.dirty_render_resource_sets.contains(id) {
self.dirty_render_resource_sets.remove(id);
self.create_render_resource_set(bind_group_descriptor)
} else {
RenderResourceSetStatus::Unchanged(*id)
}
} else {
self.create_render_resource_set(bind_group_descriptor)
}
}
pub fn get_render_resource_set(&self, id: RenderResourceSetId) -> Option<&RenderResourceSet> {
self.render_resource_sets.get(&id)
}
pub fn get_bind_group_render_resource_set(
&self, &self,
bind_group_descriptor_id: BindGroupDescriptorId, id: BindGroupDescriptorId,
) -> Option<&RenderResourceSet> { ) -> Option<&RenderResourceSet> {
self.bind_group_resource_sets.get(&bind_group_descriptor_id) self.bind_group_render_resource_sets
.get(&id)
.and_then(|render_resource_set_id| {
self.get_render_resource_set(*render_resource_set_id)
})
} }
fn generate_render_resource_set( fn generate_render_resource_set(
@ -121,8 +155,13 @@ impl RenderResourceAssignments {
) -> Option<RenderResourceSet> { ) -> Option<RenderResourceSet> {
let mut hasher = DefaultHasher::new(); let mut hasher = DefaultHasher::new();
let mut indices = Vec::new(); let mut indices = Vec::new();
let mut indexed_assignments = Vec::new();
for binding_descriptor in bind_group_descriptor.bindings.iter() { for binding_descriptor in bind_group_descriptor.bindings.iter() {
if let Some(assignment) = self.get(&binding_descriptor.name) { if let Some(assignment) = self.get(&binding_descriptor.name) {
indexed_assignments.push(IndexedRenderResourceAssignment {
assignment: assignment.clone(),
index: binding_descriptor.index,
});
let resource = assignment.get_resource(); let resource = assignment.get_resource();
resource.hash(&mut hasher); resource.hash(&mut hasher);
if let RenderResourceAssignment::Buffer { if let RenderResourceAssignment::Buffer {
@ -139,10 +178,11 @@ impl RenderResourceAssignments {
Some(RenderResourceSet { Some(RenderResourceSet {
id: RenderResourceSetId(hasher.finish()), id: RenderResourceSetId(hasher.finish()),
indexed_assignments,
dynamic_uniform_indices: if indices.is_empty() { dynamic_uniform_indices: if indices.is_empty() {
None None
} else { } else {
Some(indices) Some(Arc::new(indices))
}, },
}) })
} }
@ -215,22 +255,34 @@ mod tests {
equal_assignments.set("a", resource1.clone()); equal_assignments.set("a", resource1.clone());
equal_assignments.set("b", resource2.clone()); equal_assignments.set("b", resource2.clone());
let set_id = assignments.update_render_resource_set_id(&bind_group_descriptor); let status = assignments.update_bind_group(&bind_group_descriptor);
assert_ne!(set_id, None); let id = if let RenderResourceSetStatus::Changed(id) = status {
id
} else {
panic!("expected a changed render resource set");
};
let different_set_id = let different_set_status = different_assignments.update_bind_group(&bind_group_descriptor);
different_assignments.update_render_resource_set_id(&bind_group_descriptor); if let RenderResourceSetStatus::Changed(different_set_id) = different_set_status {
assert_ne!(different_set_id, None); assert_ne!(
assert_ne!(different_set_id, set_id); id, different_set_id,
"different set shouldn't have the same id"
);
different_set_id
} else {
panic!("expected a changed render resource set");
};
let equal_set_id = equal_assignments.update_render_resource_set_id(&bind_group_descriptor); let equal_set_status = equal_assignments.update_bind_group(&bind_group_descriptor);
assert_ne!(equal_set_id, None); if let RenderResourceSetStatus::Changed(equal_set_id) = equal_set_status {
assert_eq!(equal_set_id, set_id); assert_eq!(id, equal_set_id, "equal set should have the same id");
} else {
panic!("expected a changed render resource set");
};
let mut unmatched_assignments = RenderResourceAssignments::default(); let mut unmatched_assignments = RenderResourceAssignments::default();
unmatched_assignments.set("a", resource1.clone()); unmatched_assignments.set("a", resource1.clone());
let unmatched_set_id = let unmatched_set_status = unmatched_assignments.update_bind_group(&bind_group_descriptor);
unmatched_assignments.update_render_resource_set_id(&bind_group_descriptor); assert_eq!(unmatched_set_status, RenderResourceSetStatus::NoMatch);
assert_eq!(unmatched_set_id, None);
} }
} }

View file

@ -0,0 +1,68 @@
use bevy_asset::Assets;
use crate::{
draw::RenderPipelines,
pipeline::{PipelineCompiler, PipelineDescriptor},
render_resource::{RenderResourceAssignments, RenderResourceSetStatus},
renderer::{RenderResourceContext, RenderResources},
};
use legion::prelude::*;
fn update_bind_groups(
pipeline: &PipelineDescriptor,
render_resource_assignments: &mut RenderResourceAssignments,
render_resource_context: &dyn RenderResourceContext,
) {
let layout = pipeline.get_layout().unwrap();
for bind_group in layout.bind_groups.iter() {
match render_resource_assignments.update_bind_group(bind_group) {
RenderResourceSetStatus::Changed(id) => {
let render_resource_set = render_resource_assignments
.get_render_resource_set(id)
.expect("RenderResourceSet was just changed, so it should exist");
render_resource_context.create_bind_group(bind_group.id, render_resource_set);
},
// TODO: Don't re-create bind groups if they havent changed. this will require cleanup of orphan bind groups and
// removal of global context.clear_bind_groups()
// PERF: see above
RenderResourceSetStatus::Unchanged(id) => {
let render_resource_set = render_resource_assignments
.get_render_resource_set(id)
.expect("RenderResourceSet was just changed, so it should exist");
render_resource_context.create_bind_group(bind_group.id, render_resource_set);
},
RenderResourceSetStatus::NoMatch => {
// ignore unchanged / unmatched render resource sets
}
}
}
}
pub fn render_resource_sets_system(
world: &mut SubWorld,
pipelines: Res<Assets<PipelineDescriptor>>,
pipeline_compiler: Res<PipelineCompiler>,
render_resources: Res<RenderResources>,
mut render_resource_assignments: ResMut<RenderResourceAssignments>,
query: &mut Query<Write<RenderPipelines>>,
) {
let render_resource_context = &*render_resources.context;
for compiled_pipeline_handle in pipeline_compiler.iter_all_compiled_pipelines() {
let pipeline = pipelines.get(compiled_pipeline_handle).unwrap();
update_bind_groups(
pipeline,
&mut render_resource_assignments,
render_resource_context,
)
}
for mut render_pipelines in query.iter_mut(world) {
let render_pipelines = render_pipelines.as_mut();
for pipeline in render_pipelines.compiled_pipelines.iter() {
let pipeline = pipelines.get(pipeline).unwrap();
update_bind_groups(
pipeline,
&mut render_pipelines.render_resource_assignments,
render_resource_context,
)
}
}
}

View file

@ -1,32 +0,0 @@
use crate::{pipeline::PipelineDescriptor, render_resource::RenderResourceAssignments};
use bevy_asset::Handle;
use bevy_property::Properties;
#[derive(Properties)]
pub struct Renderable {
pub is_visible: bool,
pub is_instanced: bool,
pub pipelines: Vec<Handle<PipelineDescriptor>>,
#[property(ignore)]
pub render_resource_assignments: RenderResourceAssignments,
}
impl Renderable {
pub fn instanced() -> Self {
Renderable {
is_instanced: true,
..Default::default()
}
}
}
impl Default for Renderable {
fn default() -> Self {
Renderable {
is_visible: true,
pipelines: vec![Handle::default()],
render_resource_assignments: RenderResourceAssignments::default(),
is_instanced: false,
}
}
}

View file

@ -1,9 +1,7 @@
use super::RenderResourceContext; use super::RenderResourceContext;
use crate::{ use crate::{
pipeline::{BindGroupDescriptor, PipelineDescriptor}, pipeline::{BindGroupDescriptorId, PipelineDescriptor},
render_resource::{ render_resource::{BufferInfo, RenderResourceId, RenderResourceSet, ResourceInfo},
BufferInfo, RenderResourceId, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
},
shader::Shader, shader::Shader,
texture::{SamplerDescriptor, TextureDescriptor}, texture::{SamplerDescriptor, TextureDescriptor},
}; };
@ -113,16 +111,9 @@ impl RenderResourceContext for HeadlessRenderResourceContext {
} }
fn create_bind_group( fn create_bind_group(
&self, &self,
bind_group_descriptor: &BindGroupDescriptor, _bind_group_descriptor_id: BindGroupDescriptorId,
render_resource_assignments: &RenderResourceAssignments, _render_resource_set: &RenderResourceSet,
) -> Option<RenderResourceSetId> { ) {
if let Some(resource_set) =
render_resource_assignments.get_render_resource_set(bind_group_descriptor.id)
{
Some(resource_set.id)
} else {
None
}
} }
fn create_shader_module_from_source(&self, _shader_handle: Handle<Shader>, _shader: &Shader) {} fn create_shader_module_from_source(&self, _shader_handle: Handle<Shader>, _shader: &Shader) {}
fn remove_asset_resource_untyped(&self, handle: HandleUntyped, index: usize) { fn remove_asset_resource_untyped(&self, handle: HandleUntyped, index: usize) {

View file

@ -1,8 +1,6 @@
use crate::{ use crate::{
pipeline::{BindGroupDescriptor, PipelineDescriptor}, pipeline::{BindGroupDescriptorId, PipelineDescriptor},
render_resource::{ render_resource::{BufferInfo, RenderResourceId, RenderResourceSet, ResourceInfo},
BufferInfo, RenderResourceId, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
},
shader::Shader, shader::Shader,
texture::{SamplerDescriptor, TextureDescriptor}, texture::{SamplerDescriptor, TextureDescriptor},
}; };
@ -70,29 +68,15 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
); );
fn create_bind_group( fn create_bind_group(
&self, &self,
bind_group_descriptor: &BindGroupDescriptor, bind_group_descriptor_id: BindGroupDescriptorId,
render_resource_assignments: &RenderResourceAssignments, render_resource_set: &RenderResourceSet,
) -> Option<RenderResourceSetId>; );
fn setup_bind_groups(
&self,
pipeline_descriptor: &PipelineDescriptor,
render_resource_assignments: &RenderResourceAssignments,
) {
let pipeline_layout = pipeline_descriptor.get_layout().unwrap();
for bind_group in pipeline_layout.bind_groups.iter() {
self.create_bind_group(bind_group, render_resource_assignments);
}
}
fn clear_bind_groups(&self); fn clear_bind_groups(&self);
} }
impl dyn RenderResourceContext { impl dyn RenderResourceContext {
pub fn set_asset_resource<T>( pub fn set_asset_resource<T>(&self, handle: Handle<T>, resource: RenderResourceId, index: usize)
&self, where
handle: Handle<T>,
resource: RenderResourceId,
index: usize,
) where
T: 'static, T: 'static,
{ {
self.set_asset_resource_untyped(handle.into(), resource, index); self.set_asset_resource_untyped(handle.into(), resource, index);

View file

@ -1,7 +1,6 @@
use crate::{texture::Texture, RenderPipelines};
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use crate::{Renderable, texture::Texture}; use legion::prelude::{Com, ComMut, Res};
use legion::prelude::{Res, Com, ComMut};
pub use bevy_derive::ShaderDefs; pub use bevy_derive::ShaderDefs;
@ -15,7 +14,6 @@ pub trait ShaderDefs {
fn iter_shader_defs(&self) -> ShaderDefIterator; fn iter_shader_defs(&self) -> ShaderDefIterator;
} }
pub struct ShaderDefIterator<'a> { pub struct ShaderDefIterator<'a> {
shader_defs: &'a dyn ShaderDefs, shader_defs: &'a dyn ShaderDefs,
index: usize, index: usize,
@ -36,9 +34,7 @@ impl<'a> Iterator for ShaderDefIterator<'a> {
if self.index == self.shader_defs.shader_defs_len() { if self.index == self.shader_defs.shader_defs_len() {
return None; return None;
} }
let shader_def = self let shader_def = self.shader_defs.get_shader_def(self.index);
.shader_defs
.get_shader_def(self.index);
self.index += 1; self.index += 1;
if shader_def.is_some() { if shader_def.is_some() {
return shader_def; return shader_def;
@ -59,12 +55,12 @@ impl ShaderDef for Option<Handle<Texture>> {
} }
} }
pub fn shader_def_system<T>(shader_defs: Com<T>, mut renderable: ComMut<Renderable>) pub fn shader_def_system<T>(shader_defs: Com<T>, mut render_pipelines: ComMut<RenderPipelines>)
where where
T: ShaderDefs + Send + Sync + 'static, T: ShaderDefs + Send + Sync + 'static,
{ {
for shader_def in shader_defs.iter_shader_defs() { for shader_def in shader_defs.iter_shader_defs() {
renderable render_pipelines
.render_resource_assignments .render_resource_assignments
.pipeline_specialization .pipeline_specialization
.shader_specialization .shader_specialization
@ -76,13 +72,13 @@ where
pub fn asset_shader_def_system<T>( pub fn asset_shader_def_system<T>(
assets: Res<Assets<T>>, assets: Res<Assets<T>>,
asset_handle: Com<Handle<T>>, asset_handle: Com<Handle<T>>,
mut renderable: ComMut<Renderable>, mut render_pipelines: ComMut<RenderPipelines>,
) where ) where
T: ShaderDefs + Send + Sync + 'static, T: ShaderDefs + Send + Sync + 'static,
{ {
let shader_defs = assets.get(&asset_handle).unwrap(); let shader_defs = assets.get(&asset_handle).unwrap();
for shader_def in shader_defs.iter_shader_defs() { for shader_def in shader_defs.iter_shader_defs() {
renderable render_pipelines
.render_resource_assignments .render_resource_assignments
.pipeline_specialization .pipeline_specialization
.shader_specialization .shader_specialization

View file

@ -4,7 +4,7 @@ use crate::{
}; };
use bevy_asset::Handle; use bevy_asset::Handle;
use bevy_app::EntityArchetype; use bevy_app::EntityArchetype;
use bevy_render::{mesh::Mesh, Renderable}; use bevy_render::{mesh::Mesh, draw::{Draw, RenderPipelines}};
#[derive(EntityArchetype)] #[derive(EntityArchetype)]
pub struct SpriteEntity { pub struct SpriteEntity {
@ -12,7 +12,8 @@ pub struct SpriteEntity {
pub quad: Quad, pub quad: Quad,
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
pub material: Handle<ColorMaterial>, pub material: Handle<ColorMaterial>,
pub renderable: Renderable, pub draw: Draw,
pub render_pipelines: RenderPipelines,
} }
impl Default for SpriteEntity { impl Default for SpriteEntity {
@ -22,7 +23,8 @@ impl Default for SpriteEntity {
quad: Default::default(), quad: Default::default(),
mesh: QUAD_HANDLE, mesh: QUAD_HANDLE,
material: Default::default(), material: Default::default(),
renderable: Renderable { draw: Default::default(),
render_pipelines: RenderPipelines {
pipelines: vec![SPRITE_PIPELINE_HANDLE], pipelines: vec![SPRITE_PIPELINE_HANDLE],
..Default::default() ..Default::default()
}, },
@ -34,7 +36,8 @@ impl Default for SpriteEntity {
pub struct SpriteSheetEntity { pub struct SpriteSheetEntity {
pub sprite: TextureAtlasSprite, pub sprite: TextureAtlasSprite,
pub texture_atlas: Handle<TextureAtlas>, pub texture_atlas: Handle<TextureAtlas>,
pub renderable: Renderable, pub draw: Draw,
pub render_pipelines: RenderPipelines,
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
// pub transform: Transform, // pub transform: Transform,
// pub translation: Translation, // pub translation: Translation,
@ -47,7 +50,8 @@ impl Default for SpriteSheetEntity {
Self { Self {
sprite: Default::default(), sprite: Default::default(),
texture_atlas: Default::default(), texture_atlas: Default::default(),
renderable: Renderable { draw: Default::default(),
render_pipelines: RenderPipelines {
pipelines: vec![SPRITE_SHEET_PIPELINE_HANDLE], pipelines: vec![SPRITE_SHEET_PIPELINE_HANDLE],
..Default::default() ..Default::default()
}, },

View file

@ -4,7 +4,7 @@ use bevy_render::{
base_render_graph, base_render_graph,
pipeline::{state_descriptors::*, PipelineDescriptor}, pipeline::{state_descriptors::*, PipelineDescriptor},
render_graph::{ render_graph::{
nodes::{AssetUniformNode, PassNode, UniformNode}, nodes::{AssetUniformNode, UniformNode},
RenderGraph, RenderGraph,
}, },
shader::{Shader, ShaderStage, ShaderStages}, shader::{Shader, ShaderStage, ShaderStages},
@ -149,11 +149,6 @@ impl SpriteRenderGraphBuilder for RenderGraph {
SPRITE_SHEET_PIPELINE_HANDLE, SPRITE_SHEET_PIPELINE_HANDLE,
build_sprite_sheet_pipeline(&mut shaders), build_sprite_sheet_pipeline(&mut shaders),
); );
let main_pass: &mut PassNode = self
.get_node_mut(base_render_graph::node::MAIN_PASS)
.unwrap();
main_pass.add_pipeline(SPRITE_PIPELINE_HANDLE);
main_pass.add_pipeline(SPRITE_SHEET_PIPELINE_HANDLE);
self self
} }
} }

View file

@ -2,7 +2,7 @@ use super::Node;
use crate::{render::UI_PIPELINE_HANDLE, widget::Label}; use crate::{render::UI_PIPELINE_HANDLE, widget::Label};
use bevy_asset::Handle; use bevy_asset::Handle;
use bevy_derive::EntityArchetype; use bevy_derive::EntityArchetype;
use bevy_render::{mesh::Mesh, Renderable}; use bevy_render::{draw::{Draw, RenderPipelines}, mesh::Mesh};
use bevy_sprite::{ColorMaterial, Quad, QUAD_HANDLE}; use bevy_sprite::{ColorMaterial, Quad, QUAD_HANDLE};
#[derive(EntityArchetype)] #[derive(EntityArchetype)]
@ -11,7 +11,8 @@ pub struct UiEntity {
pub quad: Quad, pub quad: Quad,
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
pub material: Handle<ColorMaterial>, pub material: Handle<ColorMaterial>,
pub renderable: Renderable, pub draw: Draw,
pub render_pipelines: RenderPipelines,
} }
impl Default for UiEntity { impl Default for UiEntity {
@ -21,7 +22,8 @@ impl Default for UiEntity {
quad: Default::default(), quad: Default::default(),
mesh: QUAD_HANDLE, mesh: QUAD_HANDLE,
material: Default::default(), material: Default::default(),
renderable: Renderable { draw: Default::default(),
render_pipelines: RenderPipelines {
pipelines: vec![UI_PIPELINE_HANDLE], pipelines: vec![UI_PIPELINE_HANDLE],
..Default::default() ..Default::default()
}, },
@ -35,7 +37,8 @@ pub struct LabelEntity {
pub quad: Quad, pub quad: Quad,
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
pub material: Handle<ColorMaterial>, pub material: Handle<ColorMaterial>,
pub renderable: Renderable, pub draw: Draw,
pub render_pipelines: RenderPipelines,
pub label: Label, pub label: Label,
} }
@ -47,7 +50,8 @@ impl Default for LabelEntity {
mesh: QUAD_HANDLE, mesh: QUAD_HANDLE,
// NOTE: labels each get their own material. // NOTE: labels each get their own material.
material: Handle::new(), // TODO: maybe abstract this out material: Handle::new(), // TODO: maybe abstract this out
renderable: Renderable { draw: Default::default(),
render_pipelines: RenderPipelines {
pipelines: vec![UI_PIPELINE_HANDLE], pipelines: vec![UI_PIPELINE_HANDLE],
..Default::default() ..Default::default()
}, },

View file

@ -2,10 +2,7 @@ use bevy_asset::{Assets, Handle};
use bevy_render::{ use bevy_render::{
base_render_graph, base_render_graph,
pipeline::{state_descriptors::*, PipelineDescriptor}, pipeline::{state_descriptors::*, PipelineDescriptor},
render_graph::{ render_graph::{nodes::CameraNode, RenderGraph},
nodes::{CameraNode, PassNode},
RenderGraph,
},
shader::{Shader, ShaderStage, ShaderStages}, shader::{Shader, ShaderStage, ShaderStages},
texture::TextureFormat, texture::TextureFormat,
}; };
@ -79,10 +76,6 @@ impl UiRenderGraphBuilder for RenderGraph {
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap(); let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap(); let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
pipelines.set(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders)); pipelines.set(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders));
let main_pass: &mut PassNode = self
.get_node_mut(base_render_graph::node::MAIN_PASS)
.unwrap();
main_pass.add_pipeline(UI_PIPELINE_HANDLE);
self self
} }
} }

View file

@ -9,9 +9,8 @@ pub use wgpu_render_pass::*;
pub use wgpu_renderer::*; pub use wgpu_renderer::*;
pub use wgpu_resources::*; pub use wgpu_resources::*;
use bevy_app::{AppBuilder, AppPlugin, Events}; use bevy_app::{AppBuilder, AppPlugin};
use bevy_render::renderer::RenderResources; use bevy_render::renderer::RenderResources;
use bevy_window::{WindowCreated, WindowResized};
use legion::prelude::*; use legion::prelude::*;
use renderer::WgpuRenderResourceContext; use renderer::WgpuRenderResourceContext;
@ -26,14 +25,7 @@ impl AppPlugin for WgpuPlugin {
} }
pub fn wgpu_render_system(resources: &mut Resources) -> impl FnMut(&mut World, &mut Resources) { pub fn wgpu_render_system(resources: &mut Resources) -> impl FnMut(&mut World, &mut Resources) {
let mut wgpu_renderer = { let mut wgpu_renderer = pollster::block_on(WgpuRenderer::new());
let window_resized_event = resources.get::<Events<WindowResized>>().unwrap();
let window_created_event = resources.get::<Events<WindowCreated>>().unwrap();
pollster::block_on(WgpuRenderer::new(
window_resized_event.get_reader(),
window_created_event.get_reader(),
))
};
resources.insert(RenderResources::new(WgpuRenderResourceContext::new( resources.insert(RenderResources::new(WgpuRenderResourceContext::new(
wgpu_renderer.device.clone(), wgpu_renderer.device.clone(),
))); )));

View file

@ -1,9 +1,7 @@
mod systems;
mod wgpu_render_context; mod wgpu_render_context;
mod wgpu_render_graph_executor; mod wgpu_render_graph_executor;
mod wgpu_render_resource_context; mod wgpu_render_resource_context;
pub use systems::*;
pub use wgpu_render_context::*; pub use wgpu_render_context::*;
pub use wgpu_render_graph_executor::*; pub use wgpu_render_graph_executor::*;
pub use wgpu_render_resource_context::*; pub use wgpu_render_resource_context::*;

View file

@ -1,92 +0,0 @@
use bevy_asset::Assets;
use bevy_render::{
pipeline::{PipelineAssignments, PipelineCompiler, PipelineDescriptor},
render_resource::EntityRenderResourceAssignments,
Renderable,
};
use legion::prelude::*;
// TODO: replace with system_fn once configurable "archetype access" is sorted out
// pub fn render_resource_sets_system(
// world: &mut SubWorld,
// pipelines: Res<Assets<PipelineDescriptor>>,
// pipeline_compiler: Res<PipelineCompiler>,
// pipeline_assignments: Res<PipelineAssignments>,
// entity_render_resource_assignments: Res<EntityRenderResourceAssignments>,
// query: &mut Query<Write<Renderable>>, // gives SubWorld write access to Renderable
// ) {
// // PERF: consider doing a par-iter over all renderable components so this can be parallelized
// for compiled_pipeline_handle in pipeline_compiler.iter_all_compiled_pipelines() {
// if let Some(compiled_pipeline_assignments) = pipeline_assignments
// .assignments
// .get(compiled_pipeline_handle)
// {
// let compiled_pipeline = pipelines.get(compiled_pipeline_handle).unwrap();
// let pipeline_layout = compiled_pipeline.get_layout().unwrap();
// for assignment_id in compiled_pipeline_assignments.iter() {
// let entity = entity_render_resource_assignments
// .get(*assignment_id)
// .unwrap();
// let mut renderable = world.get_component_mut::<Renderable>(*entity).unwrap();
// if !renderable.is_visible || renderable.is_instanced {
// continue;
// }
// for bind_group in pipeline_layout.bind_groups.iter() {
// renderable
// .render_resource_assignments
// .update_render_resource_set_id(bind_group);
// }
// }
// }
// }
// }
pub fn render_resource_sets_system() -> Box<dyn Schedulable> {
SystemBuilder::new("update_render_resource_sets")
.read_resource::<Assets<PipelineDescriptor>>()
.read_resource::<PipelineCompiler>()
.read_resource::<PipelineAssignments>()
.read_resource::<EntityRenderResourceAssignments>()
.write_component::<Renderable>()
.build(
|_,
world,
(
pipelines,
pipeline_compiler,
pipeline_assignments,
entity_render_resource_assignments,
),
_| {
// PERF: consider doing a par-iter over all renderable components so this can be parallelized
for compiled_pipeline_handle in pipeline_compiler.iter_all_compiled_pipelines() {
if let Some(compiled_pipeline_assignments) = pipeline_assignments
.assignments
.get(compiled_pipeline_handle)
{
let compiled_pipeline = pipelines.get(compiled_pipeline_handle).unwrap();
let pipeline_layout = compiled_pipeline.get_layout().unwrap();
for assignment_id in compiled_pipeline_assignments.iter() {
let entity = entity_render_resource_assignments
.get(*assignment_id)
.unwrap();
let mut renderable =
world.get_component_mut::<Renderable>(*entity).unwrap();
if !renderable.is_visible || renderable.is_instanced {
continue;
}
for bind_group in pipeline_layout.bind_groups.iter() {
renderable
.render_resource_assignments
.update_render_resource_set_id(bind_group);
}
}
}
}
},
)
}

View file

@ -5,10 +5,9 @@ use crate::{
use bevy_asset::{Assets, Handle, HandleUntyped}; use bevy_asset::{Assets, Handle, HandleUntyped};
use bevy_render::{ use bevy_render::{
pipeline::{BindGroupDescriptor, PipelineDescriptor}, pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineDescriptor},
render_resource::{ render_resource::{
BufferInfo, RenderResourceId, RenderResourceAssignment, RenderResourceAssignments, BufferInfo, RenderResourceAssignment, RenderResourceId, RenderResourceSet, ResourceInfo,
RenderResourceSetId, ResourceInfo,
}, },
renderer::RenderResourceContext, renderer::RenderResourceContext,
shader::Shader, shader::Shader,
@ -207,7 +206,11 @@ impl RenderResourceContext for WgpuRenderResourceContext {
resource resource
} }
fn create_buffer_with_data(&self, mut buffer_info: BufferInfo, data: &[u8]) -> RenderResourceId { fn create_buffer_with_data(
&self,
mut buffer_info: BufferInfo,
data: &[u8],
) -> RenderResourceId {
// TODO: consider moving this below "create" for efficiency // TODO: consider moving this below "create" for efficiency
let mut resource_info = self.resources.resource_info.write().unwrap(); let mut resource_info = self.resources.resource_info.write().unwrap();
let mut buffers = self.resources.buffers.write().unwrap(); let mut buffers = self.resources.buffers.write().unwrap();
@ -450,15 +453,12 @@ impl RenderResourceContext for WgpuRenderResourceContext {
fn create_bind_group( fn create_bind_group(
&self, &self,
bind_group_descriptor: &BindGroupDescriptor, bind_group_descriptor_id: BindGroupDescriptorId,
render_resource_assignments: &RenderResourceAssignments, render_resource_set: &RenderResourceSet,
) -> Option<RenderResourceSetId> { ) {
if let Some(render_resource_set) =
render_resource_assignments.get_render_resource_set(bind_group_descriptor.id)
{
if !self if !self
.resources .resources
.has_bind_group(bind_group_descriptor.id, render_resource_set.id) .has_bind_group(bind_group_descriptor_id, render_resource_set.id)
{ {
log::trace!( log::trace!(
"start creating bind group for RenderResourceSet {:?}", "start creating bind group for RenderResourceSet {:?}",
@ -470,18 +470,11 @@ impl RenderResourceContext for WgpuRenderResourceContext {
let bind_group_layouts = self.resources.bind_group_layouts.read().unwrap(); let bind_group_layouts = self.resources.bind_group_layouts.read().unwrap();
let mut bind_groups = self.resources.bind_groups.write().unwrap(); let mut bind_groups = self.resources.bind_groups.write().unwrap();
let bindings = bind_group_descriptor let bindings = render_resource_set
.bindings .indexed_assignments
.iter() .iter()
.map(|binding| { .map(|indexed_assignment| {
if let Some(assignment) = render_resource_assignments.get(&binding.name) { let wgpu_resource = match &indexed_assignment.assignment {
log::trace!(
"found binding {} ({}) assignment: {:?}",
binding.index,
binding.name,
assignment,
);
let wgpu_resource = match assignment {
RenderResourceAssignment::Texture(resource) => { RenderResourceAssignment::Texture(resource) => {
let texture = texture_views.get(&resource).unwrap(); let texture = texture_views.get(&resource).unwrap();
wgpu::BindingResource::TextureView(texture) wgpu::BindingResource::TextureView(texture)
@ -490,26 +483,21 @@ impl RenderResourceContext for WgpuRenderResourceContext {
let sampler = samplers.get(&resource).unwrap(); let sampler = samplers.get(&resource).unwrap();
wgpu::BindingResource::Sampler(sampler) wgpu::BindingResource::Sampler(sampler)
} }
RenderResourceAssignment::Buffer { resource, range , .. } => { RenderResourceAssignment::Buffer {
resource, range, ..
} => {
let buffer = buffers.get(&resource).unwrap(); let buffer = buffers.get(&resource).unwrap();
wgpu::BindingResource::Buffer(buffer.slice(range.clone())) wgpu::BindingResource::Buffer(buffer.slice(range.clone()))
} }
}; };
wgpu::Binding { wgpu::Binding {
binding: binding.index, binding: indexed_assignment.index,
resource: wgpu_resource, resource: wgpu_resource,
} }
} else {
panic!(
"No resource assigned to uniform \"{}\" for RenderResourceAssignments {:?}",
binding.name,
render_resource_assignments.id
);
}
}) })
.collect::<Vec<wgpu::Binding>>(); .collect::<Vec<wgpu::Binding>>();
let bind_group_layout = bind_group_layouts.get(&bind_group_descriptor.id).unwrap(); let bind_group_layout = bind_group_layouts.get(&bind_group_descriptor_id).unwrap();
let wgpu_bind_group_descriptor = wgpu::BindGroupDescriptor { let wgpu_bind_group_descriptor = wgpu::BindGroupDescriptor {
label: None, label: None,
layout: bind_group_layout, layout: bind_group_layout,
@ -518,7 +506,7 @@ impl RenderResourceContext for WgpuRenderResourceContext {
let wgpu_bind_group = self.device.create_bind_group(&wgpu_bind_group_descriptor); let wgpu_bind_group = self.device.create_bind_group(&wgpu_bind_group_descriptor);
let bind_group_info = bind_groups let bind_group_info = bind_groups
.entry(bind_group_descriptor.id) .entry(bind_group_descriptor_id)
.or_insert_with(|| WgpuBindGroupInfo::default()); .or_insert_with(|| WgpuBindGroupInfo::default());
bind_group_info bind_group_info
.bind_groups .bind_groups
@ -527,11 +515,8 @@ impl RenderResourceContext for WgpuRenderResourceContext {
"created bind group for RenderResourceSet {:?}", "created bind group for RenderResourceSet {:?}",
render_resource_set.id render_resource_set.id
); );
return Some(render_resource_set.id);
} }
} }
None
}
fn clear_bind_groups(&self) { fn clear_bind_groups(&self) {
self.resources.bind_groups.write().unwrap().clear(); self.resources.bind_groups.write().unwrap().clear();

View file

@ -2,8 +2,8 @@ use crate::{renderer::WgpuRenderContext, WgpuResourceRefs};
use bevy_asset::Handle; use bevy_asset::Handle;
use bevy_render::{ use bevy_render::{
pass::RenderPass, pass::RenderPass,
pipeline::{BindGroupDescriptor, PipelineDescriptor}, pipeline::{PipelineDescriptor, BindGroupDescriptorId},
render_resource::{RenderResourceId, RenderResourceSet}, render_resource::{RenderResourceId, RenderResourceSetId},
renderer::RenderContext, renderer::RenderContext,
}; };
use std::ops::Range; use std::ops::Range;
@ -51,33 +51,35 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
fn set_bind_group( fn set_bind_group(
&mut self, &mut self,
bind_group_descriptor: &BindGroupDescriptor, index: u32,
render_resource_set: &RenderResourceSet, bind_group_descriptor: BindGroupDescriptorId,
render_resource_set: RenderResourceSetId,
dynamic_uniform_indices: Option<&[u32]>,
) { ) {
if let Some(bind_group_info) = self if let Some(bind_group_info) = self
.render_resources .render_resources
.bind_groups .bind_groups
.get(&bind_group_descriptor.id) .get(&bind_group_descriptor)
{ {
if let Some(wgpu_bind_group) = bind_group_info.bind_groups.get(&render_resource_set.id) if let Some(wgpu_bind_group) = bind_group_info.bind_groups.get(&render_resource_set)
{ {
const EMPTY: &'static [u32] = &[]; const EMPTY: &'static [u32] = &[];
let dynamic_uniform_indices = if let Some(ref dynamic_uniform_indices) = let dynamic_uniform_indices = if let Some(dynamic_uniform_indices) =
render_resource_set.dynamic_uniform_indices dynamic_uniform_indices
{ {
dynamic_uniform_indices.as_slice() dynamic_uniform_indices
} else { } else {
EMPTY EMPTY
}; };
log::trace!( log::trace!(
"set bind group {:?} {:?}: {:?}", "set bind group {:?} {:?}: {:?}",
bind_group_descriptor.id, bind_group_descriptor,
dynamic_uniform_indices, dynamic_uniform_indices,
render_resource_set.id render_resource_set
); );
self.render_pass.set_bind_group( self.render_pass.set_bind_group(
bind_group_descriptor.index, index,
wgpu_bind_group, wgpu_bind_group,
dynamic_uniform_indices, dynamic_uniform_indices,
); );

View file

@ -1,10 +1,10 @@
use crate::renderer::{ use crate::renderer::{WgpuRenderGraphExecutor, WgpuRenderResourceContext};
render_resource_sets_system, WgpuRenderGraphExecutor, WgpuRenderResourceContext,
};
use bevy_app::{EventReader, Events}; use bevy_app::{EventReader, Events};
use bevy_render::{ use bevy_render::{
pipeline::update_shader_assignments, draw::{draw_system, RenderPipelines},
pipeline::compile_pipelines_system,
render_graph::{DependentNodeStager, RenderGraph, RenderGraphStager}, render_graph::{DependentNodeStager, RenderGraph, RenderGraphStager},
render_resource::render_resource_sets_system,
renderer::RenderResources, renderer::RenderResources,
}; };
use bevy_window::{WindowCreated, WindowResized, Windows}; use bevy_window::{WindowCreated, WindowResized, Windows};
@ -20,10 +20,7 @@ pub struct WgpuRenderer {
} }
impl WgpuRenderer { impl WgpuRenderer {
pub async fn new( pub async fn new() -> Self {
window_resized_event_reader: EventReader<WindowResized>,
window_created_event_reader: EventReader<WindowCreated>,
) -> Self {
let instance = wgpu::Instance::new(); let instance = wgpu::Instance::new();
let adapter = instance let adapter = instance
.request_adapter( .request_adapter(
@ -53,8 +50,8 @@ impl WgpuRenderer {
instance, instance,
device, device,
queue, queue,
window_resized_event_reader, window_resized_event_reader: Default::default(),
window_created_event_reader, window_created_event_reader: Default::default(),
intialized: false, intialized: false,
} }
} }
@ -85,6 +82,7 @@ impl WgpuRenderer {
} }
pub fn run_graph(&mut self, world: &mut World, resources: &mut Resources) { pub fn run_graph(&mut self, world: &mut World, resources: &mut Resources) {
// TODO: move this to a thread-local system
// run systems // run systems
let mut system_executor = { let mut system_executor = {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap(); let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
@ -95,8 +93,12 @@ impl WgpuRenderer {
executor.execute(world, resources); executor.execute(world, resources);
} }
update_shader_assignments(world, resources); // TODO: move these to a scheduler
render_resource_sets_system().run(world, resources); compile_pipelines_system.system().run(world, resources);
render_resource_sets_system.system().run(world, resources);
draw_system::<RenderPipelines>
.system()
.run(world, resources);
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap(); let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
if let Some(executor) = system_executor.take() { if let Some(executor) = system_executor.take() {

View file

@ -283,13 +283,12 @@ fn stateful_system(mut state: ComMut<State>, player: Com<Player>, score: ComMut<
// NOTE: this doesn't do anything relevant to our game, it is just here for illustrative purposes // NOTE: this doesn't do anything relevant to our game, it is just here for illustrative purposes
#[allow(dead_code)] #[allow(dead_code)]
fn complex_system(resources: &mut Resources) -> Box<dyn Schedulable> { fn complex_system(resources: &mut Resources) -> Box<dyn Schedulable> {
let mut counter = 0;
let game_state = resources.get::<GameState>().unwrap(); let game_state = resources.get::<GameState>().unwrap();
let initial_player_count = game_state.total_players; let initial_player_count = game_state.total_players;
SystemBuilder::new("complex_system") SystemBuilder::new("complex_system")
.read_resource::<GameState>() .read_resource::<GameState>()
.write_resource::<GameRules>() .write_resource::<GameRules>()
.read_component::<Renderable>() .read_component::<Draw>()
// this query is equivalent to the system we saw above: system(player: Com<Player>, mut score: ComMut<Score>) // this query is equivalent to the system we saw above: system(player: Com<Player>, mut score: ComMut<Score>)
.with_query(<(Read<Player>, Write<Score>)>::query()) .with_query(<(Read<Player>, Write<Score>)>::query())
// this query only returns entities with a Player component that has changed since the last update // this query only returns entities with a Player component that has changed since the last update
@ -303,7 +302,6 @@ fn complex_system(resources: &mut Resources) -> Box<dyn Schedulable> {
for (player, score) in player_score_query.iter_mut(world) { for (player, score) in player_score_query.iter_mut(world) {
println!("processed : {} {}", player.name, score.value); println!("processed : {} {}", player.name, score.value);
counter += 1;
} }
for player in player_changed_query.iter(world) { for player in player_changed_query.iter(world) {

View file

@ -54,8 +54,6 @@ fn setup(
})); }));
render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true)); render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true));
let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap();
main_pass.add_pipeline(pipeline_handle);
pipeline_handle pipeline_handle
}; };
@ -70,7 +68,7 @@ fn setup(
// cube // cube
.add_entity(MeshMaterialEntity::<MyMaterial> { .add_entity(MeshMaterialEntity::<MyMaterial> {
mesh: cube_handle, mesh: cube_handle,
renderable: Renderable { render_pipelines: RenderPipelines {
pipelines: vec![pipeline_handle], pipelines: vec![pipeline_handle],
..Default::default() ..Default::default()
}, },

View file

@ -64,8 +64,6 @@ fn setup(
fragment: Some(shaders.add(Shader::from_glsl(ShaderStage::Fragment, FRAGMENT_SHADER))), fragment: Some(shaders.add(Shader::from_glsl(ShaderStage::Fragment, FRAGMENT_SHADER))),
})); }));
render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true)); render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true));
let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap();
main_pass.add_pipeline(pipeline_handle);
pipeline_handle pipeline_handle
}; };
@ -87,7 +85,7 @@ fn setup(
// cube // cube
.add_entity(MeshMaterialEntity::<MyMaterial> { .add_entity(MeshMaterialEntity::<MyMaterial> {
mesh: cube_handle, mesh: cube_handle,
renderable: Renderable { render_pipelines: RenderPipelines {
pipelines: vec![pipeline_handle], pipelines: vec![pipeline_handle],
..Default::default() ..Default::default()
}, },
@ -98,7 +96,7 @@ fn setup(
// cube // cube
.add_entity(MeshMaterialEntity::<MyMaterial> { .add_entity(MeshMaterialEntity::<MyMaterial> {
mesh: cube_handle, mesh: cube_handle,
renderable: Renderable { render_pipelines: RenderPipelines {
pipelines: vec![pipeline_handle], pipelines: vec![pipeline_handle],
..Default::default() ..Default::default()
}, },

View file

@ -19,7 +19,7 @@ pub use crate::{
pipeline::PipelineDescriptor, pipeline::PipelineDescriptor,
render_graph::{ render_graph::{
nodes::{ nodes::{
AssetUniformNode, CameraNode, PassNode, UniformNode, WindowSwapChainNode, AssetUniformNode, CameraNode, MainPassNode, UniformNode, WindowSwapChainNode,
WindowTextureNode, WindowTextureNode,
}, },
RenderGraph, RenderGraph,
@ -27,7 +27,8 @@ pub use crate::{
render_resource::RenderResources, render_resource::RenderResources,
shader::{Shader, ShaderDefs, ShaderStage, ShaderStages}, shader::{Shader, ShaderDefs, ShaderStage, ShaderStages},
texture::Texture, texture::Texture,
Camera, Color, ColorSource, OrthographicProjection, PerspectiveProjection, Renderable, draw::{Draw, RenderPipelines},
Camera, Color, ColorSource, OrthographicProjection, PerspectiveProjection,
}, },
scene::{Scene, SceneSpawner}, scene::{Scene, SceneSpawner},
sprite::{ sprite::{