mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 12:43:34 +00:00
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:
parent
3ccaebf9a5
commit
3d07fbdc81
34 changed files with 767 additions and 873 deletions
|
@ -1,7 +1,7 @@
|
|||
use crate::{light::Light, material::StandardMaterial};
|
||||
use bevy_asset::Handle;
|
||||
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};
|
||||
|
||||
#[derive(EntityArchetype, Default)]
|
||||
|
@ -10,7 +10,8 @@ pub struct MeshEntity {
|
|||
pub mesh: Handle<Mesh>,
|
||||
// #[tag]
|
||||
pub material: Handle<StandardMaterial>,
|
||||
pub renderable: Renderable,
|
||||
pub draw: Draw,
|
||||
pub render_pipelines: RenderPipelines,
|
||||
pub transform: Transform,
|
||||
pub translation: Translation,
|
||||
pub rotation: Rotation,
|
||||
|
|
|
@ -4,7 +4,7 @@ use bevy_render::{
|
|||
base_render_graph,
|
||||
pipeline::PipelineDescriptor,
|
||||
render_graph::{
|
||||
nodes::{AssetUniformNode, PassNode, UniformNode},
|
||||
nodes::{AssetUniformNode, UniformNode},
|
||||
RenderGraph,
|
||||
},
|
||||
shader::Shader,
|
||||
|
@ -36,12 +36,7 @@ impl ForwardPbrRenderGraphBuilder for RenderGraph {
|
|||
self.add_system_node(node::LIGHTS, LightsNode::new(10));
|
||||
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
|
||||
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
|
||||
{
|
||||
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)));
|
||||
}
|
||||
pipelines.add_default(build_forward_pipeline(&mut shaders));
|
||||
|
||||
// TODO: replace these with "autowire" groups
|
||||
self.add_node_edge(node::STANDARD_MATERIAL, base_render_graph::node::MAIN_PASS)
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
RenderPassDepthStencilAttachmentDescriptor, StoreOp, TextureAttachment,
|
||||
},
|
||||
render_graph::{
|
||||
nodes::{CameraNode, PassNode, TextureCopyNode, WindowSwapChainNode, WindowTextureNode},
|
||||
nodes::{CameraNode, MainPassNode, TextureCopyNode, WindowSwapChainNode, WindowTextureNode},
|
||||
RenderGraph,
|
||||
},
|
||||
texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage},
|
||||
|
@ -95,7 +95,7 @@ impl BaseRenderGraphBuilder for RenderGraph {
|
|||
if config.add_main_pass {
|
||||
self.add_node(
|
||||
node::MAIN_PASS,
|
||||
PassNode::new(PassDescriptor {
|
||||
MainPassNode::new(PassDescriptor {
|
||||
color_attachments: vec![RenderPassColorAttachmentDescriptor {
|
||||
attachment: TextureAttachment::Input("color".to_string()),
|
||||
resolve_target: None,
|
||||
|
|
|
@ -1,41 +1,221 @@
|
|||
use crate::{render_resource::RenderResourceId, pipeline::PipelineDescriptor};
|
||||
use bevy_asset::Handle;
|
||||
use std::ops::Range;
|
||||
use crate::{
|
||||
pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineDescriptor},
|
||||
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)]
|
||||
pub enum DrawType {
|
||||
Instanced {
|
||||
pub enum RenderCommand {
|
||||
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>,
|
||||
base_vertex: i32,
|
||||
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)]
|
||||
pub struct VertexBufferBinding {
|
||||
pub slot: u32,
|
||||
pub vertex_buffer: RenderResourceId,
|
||||
pub offset: u64,
|
||||
#[derive(Properties)]
|
||||
pub struct RenderPipelines {
|
||||
pub pipelines: Vec<Handle<PipelineDescriptor>>,
|
||||
// TODO: make these pipeline specific
|
||||
#[property(ignore)]
|
||||
pub render_resource_assignments: RenderResourceAssignments,
|
||||
#[property(ignore)]
|
||||
pub compiled_pipelines: Vec<Handle<PipelineDescriptor>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct IndexBufferBinding {
|
||||
pub vertex_buffer: RenderResourceId,
|
||||
pub offset: u64,
|
||||
impl Default for RenderPipelines {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
render_resource_assignments: Default::default(),
|
||||
compiled_pipelines: Default::default(),
|
||||
pipelines: vec![Handle::default()],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct BindGroupBinding {
|
||||
pub vertex_buffer: RenderResourceId,
|
||||
pub offset: u64,
|
||||
impl Draw {
|
||||
pub fn get_context<'a>(
|
||||
&'a mut self,
|
||||
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 struct DrawCall {
|
||||
pub pipeline: Handle<PipelineDescriptor>,
|
||||
pub draw_type: DrawType,
|
||||
pub vertex_buffers: Vec<VertexBufferBinding>,
|
||||
pub index_buffer: Option<IndexBufferBinding>,
|
||||
pub fn clear_render_commands(&mut self) {
|
||||
self.render_commands.clear();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
base_render_graph, mesh::Mesh, Camera, OrthographicProjection, PerspectiveProjection,
|
||||
Renderable, WindowOrigin,
|
||||
RenderPipelines, WindowOrigin, draw::Draw,
|
||||
};
|
||||
use bevy_asset::Handle;
|
||||
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 mesh: Handle<Mesh>,
|
||||
pub material: Handle<T>,
|
||||
pub renderable: Renderable,
|
||||
pub draw: Draw,
|
||||
pub render_pipelines: RenderPipelines,
|
||||
pub transform: Transform,
|
||||
pub translation: Translation,
|
||||
pub rotation: Rotation,
|
||||
|
|
|
@ -12,7 +12,6 @@ mod color;
|
|||
|
||||
pub use camera::*;
|
||||
pub use color::*;
|
||||
pub use renderable::*;
|
||||
|
||||
pub use vertex::Vertex;
|
||||
|
||||
|
@ -20,20 +19,14 @@ pub mod base_render_graph;
|
|||
pub mod pass;
|
||||
pub mod pipeline;
|
||||
pub mod render_resource;
|
||||
mod renderable;
|
||||
pub mod texture;
|
||||
|
||||
pub use once_cell;
|
||||
|
||||
use self::{
|
||||
mesh::Mesh,
|
||||
pipeline::{
|
||||
PipelineAssignments, PipelineCompiler, PipelineDescriptor, VertexBufferDescriptors,
|
||||
},
|
||||
render_resource::{
|
||||
entity_render_resource_assignments_system, EntityRenderResourceAssignments,
|
||||
RenderResourceAssignments,
|
||||
},
|
||||
pipeline::{PipelineCompiler, PipelineDescriptor, VertexBufferDescriptors},
|
||||
render_resource::RenderResourceAssignments,
|
||||
shader::Shader,
|
||||
texture::Texture,
|
||||
};
|
||||
|
@ -42,6 +35,7 @@ use base_render_graph::{BaseRenderGraphBuilder, BaseRenderGraphConfig};
|
|||
use bevy_app::{AppBuilder, AppPlugin};
|
||||
use bevy_asset::AddAsset;
|
||||
use bevy_type_registry::RegisterType;
|
||||
use draw::{clear_draw_system, Draw, RenderPipelines};
|
||||
use legion::prelude::IntoSystem;
|
||||
use mesh::mesh_resource_provider_system;
|
||||
use render_graph::RenderGraph;
|
||||
|
@ -51,6 +45,7 @@ use texture::{PngTextureLoader, TextureResourceSystemState};
|
|||
|
||||
pub mod stage {
|
||||
pub static RENDER_RESOURCE: &str = "render_resource";
|
||||
pub static PRE_RENDER: &str = "pre_render";
|
||||
pub static RENDER: &str = "render";
|
||||
}
|
||||
|
||||
|
@ -70,30 +65,27 @@ impl Default for RenderPlugin {
|
|||
impl AppPlugin for RenderPlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
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::<Texture>()
|
||||
.add_asset::<Shader>()
|
||||
.add_asset::<PipelineDescriptor>()
|
||||
.add_asset_loader::<Texture, PngTextureLoader>()
|
||||
.register_component::<Camera>()
|
||||
.register_component::<Draw>()
|
||||
.register_component::<RenderPipelines>()
|
||||
.register_component::<OrthographicProjection>()
|
||||
.register_component::<PerspectiveProjection>()
|
||||
.register_component::<Renderable>()
|
||||
.register_property_type::<Color>()
|
||||
.register_property_type::<Range<f32>>()
|
||||
.init_resource::<RenderGraph>()
|
||||
.init_resource::<PipelineAssignments>()
|
||||
.init_resource::<PipelineCompiler>()
|
||||
.init_resource::<RenderResourceAssignments>()
|
||||
.init_resource::<VertexBufferDescriptors>()
|
||||
.init_resource::<EntityRenderResourceAssignments>()
|
||||
.init_resource::<EntitiesWaitingForAssets>()
|
||||
.init_resource::<TextureResourceSystemState>()
|
||||
.add_system_to_stage(
|
||||
bevy_app::stage::POST_UPDATE,
|
||||
entity_render_resource_assignments_system(),
|
||||
)
|
||||
.add_system_to_stage(bevy_app::stage::PRE_UPDATE, clear_draw_system.system())
|
||||
.init_system_to_stage(
|
||||
bevy_app::stage::POST_UPDATE,
|
||||
camera::camera_system::<OrthographicProjection>,
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use crate::{
|
||||
pipeline::{
|
||||
state_descriptors::{IndexFormat, PrimitiveTopology},
|
||||
VertexBufferDescriptor, VertexBufferDescriptors, VertexFormat,
|
||||
AsVertexBufferDescriptor,
|
||||
AsVertexBufferDescriptor, VertexBufferDescriptor, VertexBufferDescriptors, VertexFormat,
|
||||
},
|
||||
render_resource::{BufferInfo, BufferUsage},
|
||||
renderer::{RenderResourceContext, RenderResources},
|
||||
Renderable, Vertex,
|
||||
RenderPipelines, Vertex,
|
||||
};
|
||||
use bevy_app::{EventReader, Events};
|
||||
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>,
|
||||
meshes: Res<Assets<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 mut changed_meshes = HashSet::new();
|
||||
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
|
||||
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) {
|
||||
renderable
|
||||
render_pipelines
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.primitive_topology = mesh.primitive_topology;
|
||||
|
@ -417,11 +416,9 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
|
|||
let index_buffer =
|
||||
render_resources.get_asset_resource(*handle, INDEX_BUFFER_ASSET_INDEX);
|
||||
|
||||
renderable.render_resource_assignments.set_vertex_buffer(
|
||||
"Vertex",
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
);
|
||||
render_pipelines
|
||||
.render_resource_assignments
|
||||
.set_vertex_buffer("Vertex", vertex_buffer, index_buffer);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -430,7 +427,7 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Mesh, VertexAttribute, AsVertexBufferDescriptor};
|
||||
use super::{AsVertexBufferDescriptor, Mesh, VertexAttribute};
|
||||
use crate::{pipeline::state_descriptors::PrimitiveTopology, Vertex};
|
||||
use bevy_core::bytes::AsBytes;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
||||
render_resource::{RenderResourceId, RenderResourceSet},
|
||||
pipeline::{PipelineDescriptor, BindGroupDescriptorId},
|
||||
render_resource::{RenderResourceId, RenderResourceSetId},
|
||||
renderer::RenderContext,
|
||||
};
|
||||
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 set_bind_group(
|
||||
&mut self,
|
||||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
render_resource_set: &RenderResourceSet,
|
||||
index: u32,
|
||||
bind_group_descriptor: BindGroupDescriptorId,
|
||||
render_resource_set: RenderResourceSetId,
|
||||
dynamic_uniform_indices: Option<&[u32]>,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,23 +13,10 @@ use crate::{
|
|||
};
|
||||
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)]
|
||||
pub struct PipelineDescriptor {
|
||||
pub name: Option<String>,
|
||||
pub layout: PipelineLayoutType,
|
||||
pub layout: Option<PipelineLayout>,
|
||||
pub shader_stages: ShaderStages,
|
||||
pub rasterization_state: Option<RasterizationStateDescriptor>,
|
||||
|
||||
|
@ -63,7 +50,7 @@ impl PipelineDescriptor {
|
|||
pub fn new(shader_stages: ShaderStages) -> Self {
|
||||
PipelineDescriptor {
|
||||
name: None,
|
||||
layout: PipelineLayoutType::Reflected(None),
|
||||
layout: None,
|
||||
color_states: Vec::new(),
|
||||
depth_stencil_state: None,
|
||||
shader_stages,
|
||||
|
@ -80,7 +67,7 @@ impl PipelineDescriptor {
|
|||
PipelineDescriptor {
|
||||
name: None,
|
||||
primitive_topology: PrimitiveTopology::TriangleList,
|
||||
layout: PipelineLayoutType::Reflected(None),
|
||||
layout: None,
|
||||
index_format: IndexFormat::Uint16,
|
||||
sample_count: 1,
|
||||
sample_mask: !0,
|
||||
|
@ -120,17 +107,11 @@ impl PipelineDescriptor {
|
|||
}
|
||||
|
||||
pub fn get_layout(&self) -> Option<&PipelineLayout> {
|
||||
match self.layout {
|
||||
PipelineLayoutType::Reflected(ref layout) => layout.as_ref(),
|
||||
PipelineLayoutType::Manual(ref layout) => Some(layout),
|
||||
}
|
||||
self.layout.as_ref()
|
||||
}
|
||||
|
||||
pub fn get_layout_mut(&mut self) -> Option<&mut PipelineLayout> {
|
||||
match self.layout {
|
||||
PipelineLayoutType::Reflected(ref mut layout) => layout.as_mut(),
|
||||
PipelineLayoutType::Manual(ref mut layout) => Some(layout),
|
||||
}
|
||||
self.layout.as_mut()
|
||||
}
|
||||
|
||||
/// Reflects the pipeline layout from its shaders.
|
||||
|
@ -190,6 +171,6 @@ impl PipelineDescriptor {
|
|||
}
|
||||
}
|
||||
|
||||
self.layout = PipelineLayoutType::Reflected(Some(layout));
|
||||
self.layout = Some(layout);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use super::{state_descriptors::PrimitiveTopology, PipelineDescriptor, VertexBufferDescriptors};
|
||||
use crate::{
|
||||
render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId},
|
||||
draw::RenderPipelines,
|
||||
renderer::{RenderResourceContext, RenderResources},
|
||||
shader::{Shader, ShaderSource},
|
||||
Renderable,
|
||||
};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
@ -78,14 +78,15 @@ impl PipelineCompiler {
|
|||
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
||||
shaders: &mut Assets<Shader>,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
render_pipelines: &RenderPipelines,
|
||||
) -> PipelineDescriptor {
|
||||
let mut compiled_pipeline_descriptor = pipeline_descriptor.clone();
|
||||
|
||||
compiled_pipeline_descriptor.shader_stages.vertex = self.compile_shader(
|
||||
shaders,
|
||||
&pipeline_descriptor.shader_stages.vertex,
|
||||
&render_resource_assignments
|
||||
&render_pipelines
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.shader_specialization,
|
||||
);
|
||||
|
@ -97,7 +98,8 @@ impl PipelineCompiler {
|
|||
self.compile_shader(
|
||||
shaders,
|
||||
fragment,
|
||||
&render_resource_assignments
|
||||
&render_pipelines
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.shader_specialization,
|
||||
)
|
||||
|
@ -107,72 +109,78 @@ impl PipelineCompiler {
|
|||
shaders,
|
||||
true,
|
||||
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
|
||||
.primitive_topology;
|
||||
compiled_pipeline_descriptor
|
||||
}
|
||||
|
||||
fn update_shader_assignments(
|
||||
fn compile_pipelines(
|
||||
&mut self,
|
||||
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
||||
shader_pipeline_assignments: &mut PipelineAssignments,
|
||||
pipelines: &mut Assets<PipelineDescriptor>,
|
||||
shaders: &mut Assets<Shader>,
|
||||
pipeline_handles: &[Handle<PipelineDescriptor>],
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
render_pipelines: &mut RenderPipelines,
|
||||
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) {
|
||||
self.pipeline_source_to_compiled
|
||||
.insert(*pipeline_handle, Vec::new());
|
||||
}
|
||||
|
||||
let final_handle = if let Some((_shader_defs, macroed_pipeline_handle)) = self
|
||||
.pipeline_source_to_compiled
|
||||
let compiled_pipeline_handle = if let Some((_shader_defs, compiled_pipeline_handle)) =
|
||||
self.pipeline_source_to_compiled
|
||||
.get_mut(pipeline_handle)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|(pipeline_specialization, _macroed_pipeline_handle)| {
|
||||
*pipeline_specialization == render_resource_assignments.pipeline_specialization
|
||||
.find(|(pipeline_specialization, _compiled_pipeline_handle)| {
|
||||
*pipeline_specialization
|
||||
== render_pipelines
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
}) {
|
||||
*macroed_pipeline_handle
|
||||
*compiled_pipeline_handle
|
||||
} else {
|
||||
let pipeline_descriptor = pipelines.get(pipeline_handle).unwrap();
|
||||
let compiled_pipeline = self.compile_pipeline(
|
||||
let compiled_pipeline_descriptor = self.compile_pipeline(
|
||||
vertex_buffer_descriptors,
|
||||
shaders,
|
||||
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
|
||||
.get_mut(pipeline_handle)
|
||||
.unwrap();
|
||||
macro_pipelines.push((
|
||||
render_resource_assignments.pipeline_specialization.clone(),
|
||||
compiled_pipelines.push((
|
||||
render_pipelines
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.clone(),
|
||||
compiled_pipeline_handle,
|
||||
));
|
||||
compiled_pipeline_handle
|
||||
};
|
||||
|
||||
// TODO: this will break down if pipeline layout changes. fix this with "auto-layout"
|
||||
if let None = shader_pipeline_assignments.assignments.get(&final_handle) {
|
||||
shader_pipeline_assignments
|
||||
.assignments
|
||||
.insert(final_handle, Vec::new());
|
||||
if i == render_pipelines.compiled_pipelines.len() {
|
||||
render_pipelines
|
||||
.compiled_pipelines
|
||||
.push(compiled_pipeline_handle);
|
||||
} 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
|
||||
pub fn update_shader_assignments(world: &mut World, resources: &Resources) {
|
||||
// PERF: this seems like a lot of work for things that don't change that often.
|
||||
// lots of string + hashset allocations. sees uniform_resource_provider for more context
|
||||
{
|
||||
let mut shader_pipeline_assignments = resources.get_mut::<PipelineAssignments>().unwrap();
|
||||
let mut pipeline_compiler = resources.get_mut::<PipelineCompiler>().unwrap();
|
||||
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
|
||||
let vertex_buffer_descriptors = resources.get::<VertexBufferDescriptors>().unwrap();
|
||||
let mut pipeline_descriptor_storage =
|
||||
resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
|
||||
pub fn compile_pipelines_system(
|
||||
world: &mut SubWorld,
|
||||
mut pipeline_compiler: ResMut<PipelineCompiler>,
|
||||
mut shaders: ResMut<Assets<Shader>>,
|
||||
mut pipelines: ResMut<Assets<PipelineDescriptor>>,
|
||||
vertex_buffer_descriptors: Res<VertexBufferDescriptors>,
|
||||
render_resources: Res<RenderResources>,
|
||||
query: &mut Query<Write<RenderPipelines>>,
|
||||
) {
|
||||
let render_resource_context = &*render_resources.context;
|
||||
|
||||
// reset assignments so they are updated every frame
|
||||
shader_pipeline_assignments.assignments = HashMap::new();
|
||||
|
||||
// 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(
|
||||
// TODO: only update when RenderPipelines is changed
|
||||
for mut render_pipelines in query.iter_mut(world) {
|
||||
pipeline_compiler.compile_pipelines(
|
||||
&vertex_buffer_descriptors,
|
||||
&mut shader_pipeline_assignments,
|
||||
&mut pipeline_descriptor_storage,
|
||||
&mut pipelines,
|
||||
&mut shaders,
|
||||
&renderable.pipelines,
|
||||
&renderable.render_resource_assignments,
|
||||
&mut render_pipelines,
|
||||
render_resource_context,
|
||||
);
|
||||
|
||||
// reset shader_defs so they can be changed next frame
|
||||
renderable
|
||||
render_pipelines
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.shader_specialization
|
||||
|
@ -244,4 +238,3 @@ pub fn update_shader_assignments(world: &mut World, resources: &Resources) {
|
|||
.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,20 @@
|
|||
use crate::{
|
||||
pass::{PassDescriptor, RenderPass, TextureAttachment},
|
||||
pipeline::{PipelineAssignments, PipelineCompiler, PipelineDescriptor},
|
||||
draw::{Draw, RenderCommand},
|
||||
pass::{PassDescriptor, TextureAttachment},
|
||||
render_graph::{Node, ResourceSlotInfo, ResourceSlots},
|
||||
render_resource::{
|
||||
EntitiesWaitingForAssets, EntityRenderResourceAssignments, RenderResourceAssignments,
|
||||
ResourceInfo,
|
||||
},
|
||||
render_resource::{EntitiesWaitingForAssets, RenderResourceAssignments, ResourceInfo},
|
||||
renderer::RenderContext,
|
||||
shader::Shader,
|
||||
Renderable,
|
||||
};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use legion::prelude::*;
|
||||
use std::ops::Range;
|
||||
|
||||
pub struct PassNode {
|
||||
pub struct MainPassNode {
|
||||
descriptor: PassDescriptor,
|
||||
pipelines: Vec<Handle<PipelineDescriptor>>,
|
||||
inputs: Vec<ResourceSlotInfo>,
|
||||
color_attachment_input_indices: Vec<Option<usize>>,
|
||||
depth_stencil_attachment_input_index: Option<usize>,
|
||||
}
|
||||
|
||||
impl PassNode {
|
||||
impl MainPassNode {
|
||||
pub fn new(descriptor: PassDescriptor) -> Self {
|
||||
let mut inputs = Vec::new();
|
||||
let mut color_attachment_input_indices = Vec::new();
|
||||
|
@ -49,77 +41,16 @@ impl PassNode {
|
|||
}
|
||||
}
|
||||
|
||||
PassNode {
|
||||
MainPassNode {
|
||||
descriptor,
|
||||
pipelines: Vec::new(),
|
||||
inputs,
|
||||
color_attachment_input_indices,
|
||||
depth_stencil_attachment_input_index,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>) {
|
||||
self.pipelines.push(pipeline_handle);
|
||||
}
|
||||
|
||||
fn set_render_resources(
|
||||
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 {
|
||||
impl Node for MainPassNode {
|
||||
fn input(&self) -> &[ResourceSlotInfo] {
|
||||
&self.inputs
|
||||
}
|
||||
|
@ -132,14 +63,8 @@ impl Node for PassNode {
|
|||
input: &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 mut render_resource_assignments =
|
||||
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||
let render_resource_assignments = resources.get::<RenderResourceAssignments>().unwrap();
|
||||
|
||||
for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() {
|
||||
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());
|
||||
}
|
||||
|
||||
{
|
||||
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(
|
||||
&self.descriptor,
|
||||
&render_resource_assignments,
|
||||
&mut |render_pass| {
|
||||
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();
|
||||
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)
|
||||
{
|
||||
for (entity, draw) in <Read<Draw>>::query().iter_entities(&world) {
|
||||
if !draw.is_visible || entities_waiting_for_assets.contains(&entity) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// set local render resources
|
||||
if let Some(indices) = Self::set_render_resources(
|
||||
render_pass,
|
||||
compiled_pipeline_descriptor,
|
||||
&renderable.render_resource_assignments,
|
||||
) {
|
||||
render_pass.draw_indexed(indices, 0, 0..1);
|
||||
for render_command in draw.render_commands.iter() {
|
||||
match render_command {
|
||||
RenderCommand::SetPipeline { pipeline } => {
|
||||
// TODO: Filter pipelines
|
||||
render_pass.set_pipeline(*pipeline);
|
||||
}
|
||||
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()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
use crate::{
|
||||
draw::{Draw, RenderPipelines},
|
||||
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
|
||||
render_resource::{
|
||||
self, BufferInfo, BufferUsage, EntitiesWaitingForAssets, RenderResourceAssignment,
|
||||
RenderResourceAssignments, RenderResourceAssignmentsId, RenderResourceId, RenderResourceHints,
|
||||
RenderResourceAssignments, RenderResourceAssignmentsId, RenderResourceHints,
|
||||
RenderResourceId,
|
||||
},
|
||||
renderer::{RenderContext, RenderResourceContext, RenderResources},
|
||||
texture, Renderable,
|
||||
texture,
|
||||
};
|
||||
|
||||
use bevy_asset::{Assets, Handle};
|
||||
|
@ -218,7 +220,9 @@ where
|
|||
// TODO: RE-ADD support for BufferUsage::STORAGE type
|
||||
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) {
|
||||
usage = BufferUsage::STORAGE
|
||||
}
|
||||
|
@ -396,8 +400,8 @@ where
|
|||
.read_resource::<RenderResources>()
|
||||
.read_resource::<EntitiesWaitingForAssets>()
|
||||
// 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>, Write<Renderable>)>::query())
|
||||
.with_query(<(Read<T>, Read<Draw>, Read<RenderPipelines>)>::query())
|
||||
.with_query(<(Read<T>, Read<Draw>, Write<RenderPipelines>)>::query())
|
||||
.build(
|
||||
move |_,
|
||||
world,
|
||||
|
@ -407,61 +411,51 @@ where
|
|||
|
||||
uniform_buffer_arrays.reset_new_item_counts();
|
||||
// update uniforms info
|
||||
for (uniforms, renderable) in read_uniform_query.iter(world) {
|
||||
if !renderable.is_visible {
|
||||
for (uniforms, draw, _render_pipelines) in read_uniform_query.iter(world) {
|
||||
if !draw.is_visible {
|
||||
return;
|
||||
}
|
||||
|
||||
if renderable.is_instanced {
|
||||
panic!("instancing not currently supported");
|
||||
} else {
|
||||
uniform_buffer_arrays.increment_uniform_counts(&uniforms);
|
||||
}
|
||||
}
|
||||
|
||||
uniform_buffer_arrays
|
||||
.setup_buffer_arrays(render_resource_context, dynamic_uniforms);
|
||||
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)
|
||||
{
|
||||
if !renderable.is_visible {
|
||||
if !draw.is_visible {
|
||||
return;
|
||||
}
|
||||
|
||||
if renderable.is_instanced {
|
||||
panic!("instancing not currently supported");
|
||||
} else {
|
||||
setup_uniform_texture_resources::<T>(
|
||||
entity,
|
||||
&uniforms,
|
||||
render_resource_context,
|
||||
entities_waiting_for_assets,
|
||||
&mut renderable.render_resource_assignments,
|
||||
&mut render_pipelines.render_resource_assignments,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if staging_buffer_size == 0 {
|
||||
let mut staging_buffer: [u8; 0] = [];
|
||||
for (uniforms, mut renderable) in write_uniform_query.iter_mut(world) {
|
||||
if !renderable.is_visible {
|
||||
for (uniforms, draw, mut render_pipelines) in
|
||||
write_uniform_query.iter_mut(world)
|
||||
{
|
||||
if !draw.is_visible {
|
||||
return;
|
||||
}
|
||||
|
||||
if renderable.is_instanced {
|
||||
panic!("instancing not currently supported");
|
||||
} else {
|
||||
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
||||
&uniforms,
|
||||
dynamic_uniforms,
|
||||
render_resource_context,
|
||||
&mut renderable.render_resource_assignments,
|
||||
&mut render_pipelines.render_resource_assignments,
|
||||
&mut staging_buffer,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let staging_buffer = render_resource_context.create_buffer_mapped(
|
||||
BufferInfo {
|
||||
|
@ -470,23 +464,21 @@ where
|
|||
..Default::default()
|
||||
},
|
||||
&mut |mut staging_buffer, _render_resources| {
|
||||
for (uniforms, mut renderable) in write_uniform_query.iter_mut(world) {
|
||||
if !renderable.is_visible {
|
||||
for (uniforms, draw, mut render_pipelines) in
|
||||
write_uniform_query.iter_mut(world)
|
||||
{
|
||||
if !draw.is_visible {
|
||||
return;
|
||||
}
|
||||
|
||||
if renderable.is_instanced {
|
||||
panic!("instancing not currently supported");
|
||||
} else {
|
||||
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
||||
&uniforms,
|
||||
dynamic_uniforms,
|
||||
render_resource_context,
|
||||
&mut renderable.render_resource_assignments,
|
||||
&mut render_pipelines.render_resource_assignments,
|
||||
&mut staging_buffer,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -552,8 +544,8 @@ where
|
|||
.read_resource::<RenderResources>()
|
||||
.read_resource::<EntitiesWaitingForAssets>()
|
||||
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
|
||||
.with_query(<(Read<Handle<T>>, Read<Renderable>)>::query())
|
||||
.with_query(<(Read<Handle<T>>, Write<Renderable>)>::query())
|
||||
.with_query(<(Read<Handle<T>>, Read<Draw>, Read<RenderPipelines>)>::query())
|
||||
.with_query(<(Read<Handle<T>>, Read<Draw>, Write<RenderPipelines>)>::query())
|
||||
.build(
|
||||
move |_,
|
||||
world,
|
||||
|
@ -563,14 +555,13 @@ where
|
|||
uniform_buffer_arrays.reset_new_item_counts();
|
||||
|
||||
// update uniform handles info
|
||||
for (entity, (handle, renderable)) in read_handle_query.iter_entities(world) {
|
||||
if !renderable.is_visible {
|
||||
for (entity, (handle, draw, _render_pipelines)) in
|
||||
read_handle_query.iter_entities(world)
|
||||
{
|
||||
if !draw.is_visible {
|
||||
return;
|
||||
}
|
||||
|
||||
if renderable.is_instanced {
|
||||
panic!("instancing not currently supported");
|
||||
} else {
|
||||
if let Some(uniforms) = assets.get(&handle) {
|
||||
// TODO: only increment count if we haven't seen this uniform handle before
|
||||
uniform_buffer_arrays.increment_uniform_counts(&uniforms);
|
||||
|
@ -578,54 +569,47 @@ where
|
|||
entities_waiting_for_assets.add(entity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uniform_buffer_arrays
|
||||
.setup_buffer_arrays(render_resource_context, dynamic_uniforms);
|
||||
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)
|
||||
{
|
||||
if !renderable.is_visible {
|
||||
if !draw.is_visible {
|
||||
return;
|
||||
}
|
||||
|
||||
if renderable.is_instanced {
|
||||
panic!("instancing not currently supported");
|
||||
} else {
|
||||
if let Some(uniforms) = assets.get(&handle) {
|
||||
setup_uniform_texture_resources::<T>(
|
||||
entity,
|
||||
&uniforms,
|
||||
render_resource_context,
|
||||
entities_waiting_for_assets,
|
||||
&mut renderable.render_resource_assignments,
|
||||
&mut render_pipelines.render_resource_assignments,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if staging_buffer_size == 0 {
|
||||
let mut staging_buffer: [u8; 0] = [];
|
||||
for (handle, mut renderable) in write_handle_query.iter_mut(world) {
|
||||
if !renderable.is_visible {
|
||||
for (handle, draw, mut render_pipelines) in
|
||||
write_handle_query.iter_mut(world)
|
||||
{
|
||||
if !draw.is_visible {
|
||||
return;
|
||||
}
|
||||
if renderable.is_instanced {
|
||||
panic!("instancing not currently supported");
|
||||
} else {
|
||||
if let Some(uniforms) = assets.get(&handle) {
|
||||
// TODO: only setup buffer if we haven't seen this handle before
|
||||
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
||||
&uniforms,
|
||||
dynamic_uniforms,
|
||||
render_resource_context,
|
||||
&mut renderable.render_resource_assignments,
|
||||
&mut render_pipelines.render_resource_assignments,
|
||||
&mut staging_buffer,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let staging_buffer = render_resource_context.create_buffer_mapped(
|
||||
BufferInfo {
|
||||
|
@ -634,25 +618,23 @@ where
|
|||
..Default::default()
|
||||
},
|
||||
&mut |mut staging_buffer, _render_resources| {
|
||||
for (handle, mut renderable) in write_handle_query.iter_mut(world) {
|
||||
if !renderable.is_visible {
|
||||
for (handle, draw, mut render_pipelines) in
|
||||
write_handle_query.iter_mut(world)
|
||||
{
|
||||
if !draw.is_visible {
|
||||
return;
|
||||
}
|
||||
if renderable.is_instanced {
|
||||
panic!("instancing not currently supported");
|
||||
} else {
|
||||
if let Some(uniforms) = assets.get(&handle) {
|
||||
// TODO: only setup buffer if we haven't seen this handle before
|
||||
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
||||
&uniforms,
|
||||
dynamic_uniforms,
|
||||
render_resource_context,
|
||||
&mut renderable.render_resource_assignments,
|
||||
&mut render_pipelines.render_resource_assignments,
|
||||
&mut staging_buffer,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
mod buffer;
|
||||
mod entities_waiting_for_assets;
|
||||
mod entity_render_resource_assignments;
|
||||
mod render_resource;
|
||||
mod render_resource_assignments;
|
||||
mod resource_info;
|
||||
mod systems;
|
||||
|
||||
pub use buffer::*;
|
||||
pub use entities_waiting_for_assets::*;
|
||||
pub use entity_render_resource_assignments::*;
|
||||
pub use render_resource::*;
|
||||
pub use render_resource_assignments::*;
|
||||
pub use resource_info::*;
|
||||
pub use systems::*;
|
|
@ -4,6 +4,7 @@ use std::{
|
|||
collections::{hash_map::DefaultHasher, HashMap, HashSet},
|
||||
hash::{Hash, Hasher},
|
||||
ops::Range,
|
||||
sync::Arc,
|
||||
};
|
||||
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)]
|
||||
pub struct RenderResourceSet {
|
||||
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
|
||||
|
@ -40,8 +56,9 @@ pub struct RenderResourceAssignments {
|
|||
pub id: RenderResourceAssignmentsId,
|
||||
render_resources: HashMap<String, RenderResourceAssignment>,
|
||||
vertex_buffers: HashMap<String, (RenderResourceId, Option<RenderResourceId>)>,
|
||||
bind_group_resource_sets: HashMap<BindGroupDescriptorId, RenderResourceSet>,
|
||||
dirty_bind_groups: HashSet<BindGroupDescriptorId>,
|
||||
render_resource_sets: HashMap<RenderResourceSetId, RenderResourceSet>,
|
||||
bind_group_render_resource_sets: HashMap<BindGroupDescriptorId, RenderResourceSetId>,
|
||||
dirty_render_resource_sets: HashSet<RenderResourceSetId>,
|
||||
pub pipeline_specialization: PipelineSpecialization,
|
||||
}
|
||||
|
||||
|
@ -58,9 +75,8 @@ impl RenderResourceAssignments {
|
|||
fn try_set_dirty(&mut self, name: &str, assignment: &RenderResourceAssignment) {
|
||||
if let Some(current_assignment) = self.render_resources.get(name) {
|
||||
if current_assignment != assignment {
|
||||
// TODO: this is pretty crude. can we do better?
|
||||
for bind_group_id in self.bind_group_resource_sets.keys() {
|
||||
self.dirty_bind_groups.insert(*bind_group_id);
|
||||
for id in self.render_resource_sets.keys() {
|
||||
self.dirty_render_resource_sets.insert(*id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,36 +99,54 @@ impl RenderResourceAssignments {
|
|||
.insert(name.to_string(), (vertices_resource, indices_resource));
|
||||
}
|
||||
|
||||
pub fn update_render_resource_set_id(
|
||||
fn create_render_resource_set(
|
||||
&mut self,
|
||||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
) -> Option<RenderResourceSetId> {
|
||||
if !self
|
||||
.bind_group_resource_sets
|
||||
.contains_key(&bind_group_descriptor.id)
|
||||
|| self.dirty_bind_groups.contains(&bind_group_descriptor.id)
|
||||
{
|
||||
) -> RenderResourceSetStatus {
|
||||
let resource_set = self.generate_render_resource_set(bind_group_descriptor);
|
||||
if let Some(resource_set) = resource_set {
|
||||
let id = resource_set.id;
|
||||
self.bind_group_resource_sets
|
||||
.insert(bind_group_descriptor.id, resource_set);
|
||||
Some(id)
|
||||
self.render_resource_sets.insert(id, resource_set);
|
||||
self.bind_group_render_resource_sets
|
||||
.insert(bind_group_descriptor.id, id);
|
||||
RenderResourceSetStatus::Changed(id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
self.bind_group_resource_sets
|
||||
.get(&bind_group_descriptor.id)
|
||||
.map(|set| set.id)
|
||||
RenderResourceSetStatus::NoMatch
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
bind_group_descriptor_id: BindGroupDescriptorId,
|
||||
id: BindGroupDescriptorId,
|
||||
) -> 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(
|
||||
|
@ -121,8 +155,13 @@ impl RenderResourceAssignments {
|
|||
) -> Option<RenderResourceSet> {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
let mut indices = Vec::new();
|
||||
let mut indexed_assignments = Vec::new();
|
||||
for binding_descriptor in bind_group_descriptor.bindings.iter() {
|
||||
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();
|
||||
resource.hash(&mut hasher);
|
||||
if let RenderResourceAssignment::Buffer {
|
||||
|
@ -139,10 +178,11 @@ impl RenderResourceAssignments {
|
|||
|
||||
Some(RenderResourceSet {
|
||||
id: RenderResourceSetId(hasher.finish()),
|
||||
indexed_assignments,
|
||||
dynamic_uniform_indices: if indices.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(indices)
|
||||
Some(Arc::new(indices))
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -215,22 +255,34 @@ mod tests {
|
|||
equal_assignments.set("a", resource1.clone());
|
||||
equal_assignments.set("b", resource2.clone());
|
||||
|
||||
let set_id = assignments.update_render_resource_set_id(&bind_group_descriptor);
|
||||
assert_ne!(set_id, None);
|
||||
let status = assignments.update_bind_group(&bind_group_descriptor);
|
||||
let id = if let RenderResourceSetStatus::Changed(id) = status {
|
||||
id
|
||||
} else {
|
||||
panic!("expected a changed render resource set");
|
||||
};
|
||||
|
||||
let different_set_id =
|
||||
different_assignments.update_render_resource_set_id(&bind_group_descriptor);
|
||||
assert_ne!(different_set_id, None);
|
||||
assert_ne!(different_set_id, set_id);
|
||||
let different_set_status = different_assignments.update_bind_group(&bind_group_descriptor);
|
||||
if let RenderResourceSetStatus::Changed(different_set_id) = different_set_status {
|
||||
assert_ne!(
|
||||
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);
|
||||
assert_ne!(equal_set_id, None);
|
||||
assert_eq!(equal_set_id, set_id);
|
||||
let equal_set_status = equal_assignments.update_bind_group(&bind_group_descriptor);
|
||||
if let RenderResourceSetStatus::Changed(equal_set_id) = equal_set_status {
|
||||
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();
|
||||
unmatched_assignments.set("a", resource1.clone());
|
||||
let unmatched_set_id =
|
||||
unmatched_assignments.update_render_resource_set_id(&bind_group_descriptor);
|
||||
assert_eq!(unmatched_set_id, None);
|
||||
let unmatched_set_status = unmatched_assignments.update_bind_group(&bind_group_descriptor);
|
||||
assert_eq!(unmatched_set_status, RenderResourceSetStatus::NoMatch);
|
||||
}
|
||||
}
|
||||
|
|
68
crates/bevy_render/src/render_resource/systems.rs
Normal file
68
crates/bevy_render/src/render_resource/systems.rs
Normal 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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
use super::RenderResourceContext;
|
||||
use crate::{
|
||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
||||
render_resource::{
|
||||
BufferInfo, RenderResourceId, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
|
||||
},
|
||||
pipeline::{BindGroupDescriptorId, PipelineDescriptor},
|
||||
render_resource::{BufferInfo, RenderResourceId, RenderResourceSet, ResourceInfo},
|
||||
shader::Shader,
|
||||
texture::{SamplerDescriptor, TextureDescriptor},
|
||||
};
|
||||
|
@ -113,16 +111,9 @@ impl RenderResourceContext for HeadlessRenderResourceContext {
|
|||
}
|
||||
fn create_bind_group(
|
||||
&self,
|
||||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
) -> Option<RenderResourceSetId> {
|
||||
if let Some(resource_set) =
|
||||
render_resource_assignments.get_render_resource_set(bind_group_descriptor.id)
|
||||
{
|
||||
Some(resource_set.id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
_bind_group_descriptor_id: BindGroupDescriptorId,
|
||||
_render_resource_set: &RenderResourceSet,
|
||||
) {
|
||||
}
|
||||
fn create_shader_module_from_source(&self, _shader_handle: Handle<Shader>, _shader: &Shader) {}
|
||||
fn remove_asset_resource_untyped(&self, handle: HandleUntyped, index: usize) {
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use crate::{
|
||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
||||
render_resource::{
|
||||
BufferInfo, RenderResourceId, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
|
||||
},
|
||||
pipeline::{BindGroupDescriptorId, PipelineDescriptor},
|
||||
render_resource::{BufferInfo, RenderResourceId, RenderResourceSet, ResourceInfo},
|
||||
shader::Shader,
|
||||
texture::{SamplerDescriptor, TextureDescriptor},
|
||||
};
|
||||
|
@ -70,29 +68,15 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
|
|||
);
|
||||
fn create_bind_group(
|
||||
&self,
|
||||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
) -> 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);
|
||||
}
|
||||
}
|
||||
bind_group_descriptor_id: BindGroupDescriptorId,
|
||||
render_resource_set: &RenderResourceSet,
|
||||
);
|
||||
fn clear_bind_groups(&self);
|
||||
}
|
||||
|
||||
impl dyn RenderResourceContext {
|
||||
pub fn set_asset_resource<T>(
|
||||
&self,
|
||||
handle: Handle<T>,
|
||||
resource: RenderResourceId,
|
||||
index: usize,
|
||||
) where
|
||||
pub fn set_asset_resource<T>(&self, handle: Handle<T>, resource: RenderResourceId, index: usize)
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
self.set_asset_resource_untyped(handle.into(), resource, index);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
use crate::{texture::Texture, RenderPipelines};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use crate::{Renderable, texture::Texture};
|
||||
use legion::prelude::{Res, Com, ComMut};
|
||||
use legion::prelude::{Com, ComMut, Res};
|
||||
|
||||
pub use bevy_derive::ShaderDefs;
|
||||
|
||||
|
@ -15,7 +14,6 @@ pub trait ShaderDefs {
|
|||
fn iter_shader_defs(&self) -> ShaderDefIterator;
|
||||
}
|
||||
|
||||
|
||||
pub struct ShaderDefIterator<'a> {
|
||||
shader_defs: &'a dyn ShaderDefs,
|
||||
index: usize,
|
||||
|
@ -36,9 +34,7 @@ impl<'a> Iterator for ShaderDefIterator<'a> {
|
|||
if self.index == self.shader_defs.shader_defs_len() {
|
||||
return None;
|
||||
}
|
||||
let shader_def = self
|
||||
.shader_defs
|
||||
.get_shader_def(self.index);
|
||||
let shader_def = self.shader_defs.get_shader_def(self.index);
|
||||
self.index += 1;
|
||||
if shader_def.is_some() {
|
||||
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
|
||||
T: ShaderDefs + Send + Sync + 'static,
|
||||
{
|
||||
for shader_def in shader_defs.iter_shader_defs() {
|
||||
renderable
|
||||
render_pipelines
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.shader_specialization
|
||||
|
@ -76,13 +72,13 @@ where
|
|||
pub fn asset_shader_def_system<T>(
|
||||
assets: Res<Assets<T>>,
|
||||
asset_handle: Com<Handle<T>>,
|
||||
mut renderable: ComMut<Renderable>,
|
||||
mut render_pipelines: ComMut<RenderPipelines>,
|
||||
) where
|
||||
T: ShaderDefs + Send + Sync + 'static,
|
||||
{
|
||||
let shader_defs = assets.get(&asset_handle).unwrap();
|
||||
for shader_def in shader_defs.iter_shader_defs() {
|
||||
renderable
|
||||
render_pipelines
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.shader_specialization
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
};
|
||||
use bevy_asset::Handle;
|
||||
use bevy_app::EntityArchetype;
|
||||
use bevy_render::{mesh::Mesh, Renderable};
|
||||
use bevy_render::{mesh::Mesh, draw::{Draw, RenderPipelines}};
|
||||
|
||||
#[derive(EntityArchetype)]
|
||||
pub struct SpriteEntity {
|
||||
|
@ -12,7 +12,8 @@ pub struct SpriteEntity {
|
|||
pub quad: Quad,
|
||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||
pub material: Handle<ColorMaterial>,
|
||||
pub renderable: Renderable,
|
||||
pub draw: Draw,
|
||||
pub render_pipelines: RenderPipelines,
|
||||
}
|
||||
|
||||
impl Default for SpriteEntity {
|
||||
|
@ -22,7 +23,8 @@ impl Default for SpriteEntity {
|
|||
quad: Default::default(),
|
||||
mesh: QUAD_HANDLE,
|
||||
material: Default::default(),
|
||||
renderable: Renderable {
|
||||
draw: Default::default(),
|
||||
render_pipelines: RenderPipelines {
|
||||
pipelines: vec![SPRITE_PIPELINE_HANDLE],
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -34,7 +36,8 @@ impl Default for SpriteEntity {
|
|||
pub struct SpriteSheetEntity {
|
||||
pub sprite: TextureAtlasSprite,
|
||||
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 transform: Transform,
|
||||
// pub translation: Translation,
|
||||
|
@ -47,7 +50,8 @@ impl Default for SpriteSheetEntity {
|
|||
Self {
|
||||
sprite: Default::default(),
|
||||
texture_atlas: Default::default(),
|
||||
renderable: Renderable {
|
||||
draw: Default::default(),
|
||||
render_pipelines: RenderPipelines {
|
||||
pipelines: vec![SPRITE_SHEET_PIPELINE_HANDLE],
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
@ -4,7 +4,7 @@ use bevy_render::{
|
|||
base_render_graph,
|
||||
pipeline::{state_descriptors::*, PipelineDescriptor},
|
||||
render_graph::{
|
||||
nodes::{AssetUniformNode, PassNode, UniformNode},
|
||||
nodes::{AssetUniformNode, UniformNode},
|
||||
RenderGraph,
|
||||
},
|
||||
shader::{Shader, ShaderStage, ShaderStages},
|
||||
|
@ -149,11 +149,6 @@ impl SpriteRenderGraphBuilder for RenderGraph {
|
|||
SPRITE_SHEET_PIPELINE_HANDLE,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use super::Node;
|
|||
use crate::{render::UI_PIPELINE_HANDLE, widget::Label};
|
||||
use bevy_asset::Handle;
|
||||
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};
|
||||
|
||||
#[derive(EntityArchetype)]
|
||||
|
@ -11,7 +11,8 @@ pub struct UiEntity {
|
|||
pub quad: Quad,
|
||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||
pub material: Handle<ColorMaterial>,
|
||||
pub renderable: Renderable,
|
||||
pub draw: Draw,
|
||||
pub render_pipelines: RenderPipelines,
|
||||
}
|
||||
|
||||
impl Default for UiEntity {
|
||||
|
@ -21,7 +22,8 @@ impl Default for UiEntity {
|
|||
quad: Default::default(),
|
||||
mesh: QUAD_HANDLE,
|
||||
material: Default::default(),
|
||||
renderable: Renderable {
|
||||
draw: Default::default(),
|
||||
render_pipelines: RenderPipelines {
|
||||
pipelines: vec![UI_PIPELINE_HANDLE],
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -35,7 +37,8 @@ pub struct LabelEntity {
|
|||
pub quad: Quad,
|
||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||
pub material: Handle<ColorMaterial>,
|
||||
pub renderable: Renderable,
|
||||
pub draw: Draw,
|
||||
pub render_pipelines: RenderPipelines,
|
||||
pub label: Label,
|
||||
}
|
||||
|
||||
|
@ -47,7 +50,8 @@ impl Default for LabelEntity {
|
|||
mesh: QUAD_HANDLE,
|
||||
// NOTE: labels each get their own material.
|
||||
material: Handle::new(), // TODO: maybe abstract this out
|
||||
renderable: Renderable {
|
||||
draw: Default::default(),
|
||||
render_pipelines: RenderPipelines {
|
||||
pipelines: vec![UI_PIPELINE_HANDLE],
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
@ -2,10 +2,7 @@ use bevy_asset::{Assets, Handle};
|
|||
use bevy_render::{
|
||||
base_render_graph,
|
||||
pipeline::{state_descriptors::*, PipelineDescriptor},
|
||||
render_graph::{
|
||||
nodes::{CameraNode, PassNode},
|
||||
RenderGraph,
|
||||
},
|
||||
render_graph::{nodes::CameraNode, RenderGraph},
|
||||
shader::{Shader, ShaderStage, ShaderStages},
|
||||
texture::TextureFormat,
|
||||
};
|
||||
|
@ -79,10 +76,6 @@ impl UiRenderGraphBuilder for RenderGraph {
|
|||
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
|
||||
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,8 @@ pub use wgpu_render_pass::*;
|
|||
pub use wgpu_renderer::*;
|
||||
pub use wgpu_resources::*;
|
||||
|
||||
use bevy_app::{AppBuilder, AppPlugin, Events};
|
||||
use bevy_app::{AppBuilder, AppPlugin};
|
||||
use bevy_render::renderer::RenderResources;
|
||||
use bevy_window::{WindowCreated, WindowResized};
|
||||
use legion::prelude::*;
|
||||
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) {
|
||||
let mut wgpu_renderer = {
|
||||
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(),
|
||||
))
|
||||
};
|
||||
let mut wgpu_renderer = pollster::block_on(WgpuRenderer::new());
|
||||
resources.insert(RenderResources::new(WgpuRenderResourceContext::new(
|
||||
wgpu_renderer.device.clone(),
|
||||
)));
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
mod systems;
|
||||
mod wgpu_render_context;
|
||||
mod wgpu_render_graph_executor;
|
||||
mod wgpu_render_resource_context;
|
||||
|
||||
pub use systems::*;
|
||||
pub use wgpu_render_context::*;
|
||||
pub use wgpu_render_graph_executor::*;
|
||||
pub use wgpu_render_resource_context::*;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
|
@ -5,10 +5,9 @@ use crate::{
|
|||
|
||||
use bevy_asset::{Assets, Handle, HandleUntyped};
|
||||
use bevy_render::{
|
||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
||||
pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineDescriptor},
|
||||
render_resource::{
|
||||
BufferInfo, RenderResourceId, RenderResourceAssignment, RenderResourceAssignments,
|
||||
RenderResourceSetId, ResourceInfo,
|
||||
BufferInfo, RenderResourceAssignment, RenderResourceId, RenderResourceSet, ResourceInfo,
|
||||
},
|
||||
renderer::RenderResourceContext,
|
||||
shader::Shader,
|
||||
|
@ -207,7 +206,11 @@ impl RenderResourceContext for WgpuRenderResourceContext {
|
|||
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
|
||||
let mut resource_info = self.resources.resource_info.write().unwrap();
|
||||
let mut buffers = self.resources.buffers.write().unwrap();
|
||||
|
@ -450,15 +453,12 @@ impl RenderResourceContext for WgpuRenderResourceContext {
|
|||
|
||||
fn create_bind_group(
|
||||
&self,
|
||||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
) -> Option<RenderResourceSetId> {
|
||||
if let Some(render_resource_set) =
|
||||
render_resource_assignments.get_render_resource_set(bind_group_descriptor.id)
|
||||
{
|
||||
bind_group_descriptor_id: BindGroupDescriptorId,
|
||||
render_resource_set: &RenderResourceSet,
|
||||
) {
|
||||
if !self
|
||||
.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!(
|
||||
"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 mut bind_groups = self.resources.bind_groups.write().unwrap();
|
||||
|
||||
let bindings = bind_group_descriptor
|
||||
.bindings
|
||||
let bindings = render_resource_set
|
||||
.indexed_assignments
|
||||
.iter()
|
||||
.map(|binding| {
|
||||
if let Some(assignment) = render_resource_assignments.get(&binding.name) {
|
||||
log::trace!(
|
||||
"found binding {} ({}) assignment: {:?}",
|
||||
binding.index,
|
||||
binding.name,
|
||||
assignment,
|
||||
);
|
||||
let wgpu_resource = match assignment {
|
||||
.map(|indexed_assignment| {
|
||||
let wgpu_resource = match &indexed_assignment.assignment {
|
||||
RenderResourceAssignment::Texture(resource) => {
|
||||
let texture = texture_views.get(&resource).unwrap();
|
||||
wgpu::BindingResource::TextureView(texture)
|
||||
|
@ -490,26 +483,21 @@ impl RenderResourceContext for WgpuRenderResourceContext {
|
|||
let sampler = samplers.get(&resource).unwrap();
|
||||
wgpu::BindingResource::Sampler(sampler)
|
||||
}
|
||||
RenderResourceAssignment::Buffer { resource, range , .. } => {
|
||||
RenderResourceAssignment::Buffer {
|
||||
resource, range, ..
|
||||
} => {
|
||||
let buffer = buffers.get(&resource).unwrap();
|
||||
wgpu::BindingResource::Buffer(buffer.slice(range.clone()))
|
||||
}
|
||||
};
|
||||
wgpu::Binding {
|
||||
binding: binding.index,
|
||||
binding: indexed_assignment.index,
|
||||
resource: wgpu_resource,
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"No resource assigned to uniform \"{}\" for RenderResourceAssignments {:?}",
|
||||
binding.name,
|
||||
render_resource_assignments.id
|
||||
);
|
||||
}
|
||||
})
|
||||
.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 {
|
||||
label: None,
|
||||
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 bind_group_info = bind_groups
|
||||
.entry(bind_group_descriptor.id)
|
||||
.entry(bind_group_descriptor_id)
|
||||
.or_insert_with(|| WgpuBindGroupInfo::default());
|
||||
bind_group_info
|
||||
.bind_groups
|
||||
|
@ -527,11 +515,8 @@ impl RenderResourceContext for WgpuRenderResourceContext {
|
|||
"created bind group for RenderResourceSet {:?}",
|
||||
render_resource_set.id
|
||||
);
|
||||
return Some(render_resource_set.id);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn clear_bind_groups(&self) {
|
||||
self.resources.bind_groups.write().unwrap().clear();
|
||||
|
|
|
@ -2,8 +2,8 @@ use crate::{renderer::WgpuRenderContext, WgpuResourceRefs};
|
|||
use bevy_asset::Handle;
|
||||
use bevy_render::{
|
||||
pass::RenderPass,
|
||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
||||
render_resource::{RenderResourceId, RenderResourceSet},
|
||||
pipeline::{PipelineDescriptor, BindGroupDescriptorId},
|
||||
render_resource::{RenderResourceId, RenderResourceSetId},
|
||||
renderer::RenderContext,
|
||||
};
|
||||
use std::ops::Range;
|
||||
|
@ -51,33 +51,35 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
|
|||
|
||||
fn set_bind_group(
|
||||
&mut self,
|
||||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
render_resource_set: &RenderResourceSet,
|
||||
index: u32,
|
||||
bind_group_descriptor: BindGroupDescriptorId,
|
||||
render_resource_set: RenderResourceSetId,
|
||||
dynamic_uniform_indices: Option<&[u32]>,
|
||||
) {
|
||||
if let Some(bind_group_info) = self
|
||||
.render_resources
|
||||
.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] = &[];
|
||||
let dynamic_uniform_indices = if let Some(ref dynamic_uniform_indices) =
|
||||
render_resource_set.dynamic_uniform_indices
|
||||
let dynamic_uniform_indices = if let Some(dynamic_uniform_indices) =
|
||||
dynamic_uniform_indices
|
||||
{
|
||||
dynamic_uniform_indices.as_slice()
|
||||
dynamic_uniform_indices
|
||||
} else {
|
||||
EMPTY
|
||||
};
|
||||
|
||||
log::trace!(
|
||||
"set bind group {:?} {:?}: {:?}",
|
||||
bind_group_descriptor.id,
|
||||
bind_group_descriptor,
|
||||
dynamic_uniform_indices,
|
||||
render_resource_set.id
|
||||
render_resource_set
|
||||
);
|
||||
self.render_pass.set_bind_group(
|
||||
bind_group_descriptor.index,
|
||||
index,
|
||||
wgpu_bind_group,
|
||||
dynamic_uniform_indices,
|
||||
);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::renderer::{
|
||||
render_resource_sets_system, WgpuRenderGraphExecutor, WgpuRenderResourceContext,
|
||||
};
|
||||
use crate::renderer::{WgpuRenderGraphExecutor, WgpuRenderResourceContext};
|
||||
use bevy_app::{EventReader, Events};
|
||||
use bevy_render::{
|
||||
pipeline::update_shader_assignments,
|
||||
draw::{draw_system, RenderPipelines},
|
||||
pipeline::compile_pipelines_system,
|
||||
render_graph::{DependentNodeStager, RenderGraph, RenderGraphStager},
|
||||
render_resource::render_resource_sets_system,
|
||||
renderer::RenderResources,
|
||||
};
|
||||
use bevy_window::{WindowCreated, WindowResized, Windows};
|
||||
|
@ -20,10 +20,7 @@ pub struct WgpuRenderer {
|
|||
}
|
||||
|
||||
impl WgpuRenderer {
|
||||
pub async fn new(
|
||||
window_resized_event_reader: EventReader<WindowResized>,
|
||||
window_created_event_reader: EventReader<WindowCreated>,
|
||||
) -> Self {
|
||||
pub async fn new() -> Self {
|
||||
let instance = wgpu::Instance::new();
|
||||
let adapter = instance
|
||||
.request_adapter(
|
||||
|
@ -53,8 +50,8 @@ impl WgpuRenderer {
|
|||
instance,
|
||||
device,
|
||||
queue,
|
||||
window_resized_event_reader,
|
||||
window_created_event_reader,
|
||||
window_resized_event_reader: Default::default(),
|
||||
window_created_event_reader: Default::default(),
|
||||
intialized: false,
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +82,7 @@ impl WgpuRenderer {
|
|||
}
|
||||
|
||||
pub fn run_graph(&mut self, world: &mut World, resources: &mut Resources) {
|
||||
// TODO: move this to a thread-local system
|
||||
// run systems
|
||||
let mut system_executor = {
|
||||
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
||||
|
@ -95,8 +93,12 @@ impl WgpuRenderer {
|
|||
executor.execute(world, resources);
|
||||
}
|
||||
|
||||
update_shader_assignments(world, resources);
|
||||
render_resource_sets_system().run(world, resources);
|
||||
// TODO: move these to a scheduler
|
||||
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();
|
||||
if let Some(executor) = system_executor.take() {
|
||||
|
|
|
@ -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
|
||||
#[allow(dead_code)]
|
||||
fn complex_system(resources: &mut Resources) -> Box<dyn Schedulable> {
|
||||
let mut counter = 0;
|
||||
let game_state = resources.get::<GameState>().unwrap();
|
||||
let initial_player_count = game_state.total_players;
|
||||
SystemBuilder::new("complex_system")
|
||||
.read_resource::<GameState>()
|
||||
.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>)
|
||||
.with_query(<(Read<Player>, Write<Score>)>::query())
|
||||
// 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) {
|
||||
println!("processed : {} {}", player.name, score.value);
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
for player in player_changed_query.iter(world) {
|
||||
|
|
|
@ -54,8 +54,6 @@ fn setup(
|
|||
}));
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -70,7 +68,7 @@ fn setup(
|
|||
// cube
|
||||
.add_entity(MeshMaterialEntity::<MyMaterial> {
|
||||
mesh: cube_handle,
|
||||
renderable: Renderable {
|
||||
render_pipelines: RenderPipelines {
|
||||
pipelines: vec![pipeline_handle],
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
@ -64,8 +64,6 @@ fn setup(
|
|||
fragment: Some(shaders.add(Shader::from_glsl(ShaderStage::Fragment, FRAGMENT_SHADER))),
|
||||
}));
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -87,7 +85,7 @@ fn setup(
|
|||
// cube
|
||||
.add_entity(MeshMaterialEntity::<MyMaterial> {
|
||||
mesh: cube_handle,
|
||||
renderable: Renderable {
|
||||
render_pipelines: RenderPipelines {
|
||||
pipelines: vec![pipeline_handle],
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -98,7 +96,7 @@ fn setup(
|
|||
// cube
|
||||
.add_entity(MeshMaterialEntity::<MyMaterial> {
|
||||
mesh: cube_handle,
|
||||
renderable: Renderable {
|
||||
render_pipelines: RenderPipelines {
|
||||
pipelines: vec![pipeline_handle],
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
@ -19,7 +19,7 @@ pub use crate::{
|
|||
pipeline::PipelineDescriptor,
|
||||
render_graph::{
|
||||
nodes::{
|
||||
AssetUniformNode, CameraNode, PassNode, UniformNode, WindowSwapChainNode,
|
||||
AssetUniformNode, CameraNode, MainPassNode, UniformNode, WindowSwapChainNode,
|
||||
WindowTextureNode,
|
||||
},
|
||||
RenderGraph,
|
||||
|
@ -27,7 +27,8 @@ pub use crate::{
|
|||
render_resource::RenderResources,
|
||||
shader::{Shader, ShaderDefs, ShaderStage, ShaderStages},
|
||||
texture::Texture,
|
||||
Camera, Color, ColorSource, OrthographicProjection, PerspectiveProjection, Renderable,
|
||||
draw::{Draw, RenderPipelines},
|
||||
Camera, Color, ColorSource, OrthographicProjection, PerspectiveProjection,
|
||||
},
|
||||
scene::{Scene, SceneSpawner},
|
||||
sprite::{
|
||||
|
|
Loading…
Reference in a new issue