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
					
				@ -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,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn clear_render_commands(&mut self) {
 | 
			
		||||
        self.render_commands.clear();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[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 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,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Draw {}
 | 
			
		||||
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
 | 
			
		||||
                .get_mut(pipeline_handle)
 | 
			
		||||
                .unwrap()
 | 
			
		||||
                .iter()
 | 
			
		||||
                .find(|(pipeline_specialization, _macroed_pipeline_handle)| {
 | 
			
		||||
                    *pipeline_specialization == render_resource_assignments.pipeline_specialization
 | 
			
		||||
                }) {
 | 
			
		||||
                *macroed_pipeline_handle
 | 
			
		||||
            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, _compiled_pipeline_handle)| {
 | 
			
		||||
                        *pipeline_specialization
 | 
			
		||||
                            == render_pipelines
 | 
			
		||||
                                .render_resource_assignments
 | 
			
		||||
                                .pipeline_specialization
 | 
			
		||||
                    }) {
 | 
			
		||||
                *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,49 +207,34 @@ 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 RenderPipelines is changed
 | 
			
		||||
    for mut render_pipelines in query.iter_mut(world) {
 | 
			
		||||
        pipeline_compiler.compile_pipelines(
 | 
			
		||||
            &vertex_buffer_descriptors,
 | 
			
		||||
            &mut pipelines,
 | 
			
		||||
            &mut shaders,
 | 
			
		||||
            &mut render_pipelines,
 | 
			
		||||
            render_resource_context,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // 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,
 | 
			
		||||
                &mut shader_pipeline_assignments,
 | 
			
		||||
                &mut pipeline_descriptor_storage,
 | 
			
		||||
                &mut shaders,
 | 
			
		||||
                &renderable.pipelines,
 | 
			
		||||
                &renderable.render_resource_assignments,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // reset shader_defs so they can be changed next frame
 | 
			
		||||
            renderable
 | 
			
		||||
                .render_resource_assignments
 | 
			
		||||
                .pipeline_specialization
 | 
			
		||||
                .shader_specialization
 | 
			
		||||
                .shader_defs
 | 
			
		||||
                .clear();
 | 
			
		||||
        }
 | 
			
		||||
        // reset shader_defs so they can be changed next frame
 | 
			
		||||
        render_pipelines
 | 
			
		||||
            .render_resource_assignments
 | 
			
		||||
            .pipeline_specialization
 | 
			
		||||
            .shader_specialization
 | 
			
		||||
            .shader_defs
 | 
			
		||||
            .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);
 | 
			
		||||
                for (entity, draw) in <Read<Draw>>::query().iter_entities(&world) {
 | 
			
		||||
                    if !draw.is_visible || entities_waiting_for_assets.contains(&entity) {
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                            // 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;
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
                                    // 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};
 | 
			
		||||
@ -217,12 +219,14 @@ where
 | 
			
		||||
                            None => {
 | 
			
		||||
                                // 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
 | 
			
		||||
                                    }
 | 
			
		||||
                                } 
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                let resource = render_resources.create_buffer(BufferInfo {
 | 
			
		||||
                                    size,
 | 
			
		||||
@ -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,60 +411,50 @@ 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.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,
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                    setup_uniform_texture_resources::<T>(
 | 
			
		||||
                        entity,
 | 
			
		||||
                        &uniforms,
 | 
			
		||||
                        render_resource_context,
 | 
			
		||||
                        entities_waiting_for_assets,
 | 
			
		||||
                        &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 staging_buffer,
 | 
			
		||||
                            );
 | 
			
		||||
                        }
 | 
			
		||||
                        uniform_buffer_arrays.setup_uniform_buffer_resources(
 | 
			
		||||
                            &uniforms,
 | 
			
		||||
                            dynamic_uniforms,
 | 
			
		||||
                            render_resource_context,
 | 
			
		||||
                            &mut render_pipelines.render_resource_assignments,
 | 
			
		||||
                            &mut staging_buffer,
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    let staging_buffer = render_resource_context.create_buffer_mapped(
 | 
			
		||||
@ -470,22 +464,20 @@ 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 staging_buffer,
 | 
			
		||||
                                    );
 | 
			
		||||
                                }
 | 
			
		||||
                                uniform_buffer_arrays.setup_uniform_buffer_resources(
 | 
			
		||||
                                    &uniforms,
 | 
			
		||||
                                    dynamic_uniforms,
 | 
			
		||||
                                    render_resource_context,
 | 
			
		||||
                                    &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,20 +555,18 @@ 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");
 | 
			
		||||
                        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);
 | 
			
		||||
                        } 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);
 | 
			
		||||
                            } else {
 | 
			
		||||
                                entities_waiting_for_assets.add(entity)
 | 
			
		||||
                            }
 | 
			
		||||
                            entities_waiting_for_assets.add(entity)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
@ -584,46 +574,40 @@ where
 | 
			
		||||
                        .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,
 | 
			
		||||
                                )
 | 
			
		||||
                            }
 | 
			
		||||
                        if let Some(uniforms) = assets.get(&handle) {
 | 
			
		||||
                            setup_uniform_texture_resources::<T>(
 | 
			
		||||
                                entity,
 | 
			
		||||
                                &uniforms,
 | 
			
		||||
                                render_resource_context,
 | 
			
		||||
                                entities_waiting_for_assets,
 | 
			
		||||
                                &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 staging_buffer,
 | 
			
		||||
                                    );
 | 
			
		||||
                                }
 | 
			
		||||
                            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 render_pipelines.render_resource_assignments,
 | 
			
		||||
                                    &mut staging_buffer,
 | 
			
		||||
                                );
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
@ -634,23 +618,21 @@ 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 staging_buffer,
 | 
			
		||||
                                            );
 | 
			
		||||
                                        }
 | 
			
		||||
                                    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 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)
 | 
			
		||||
        {
 | 
			
		||||
            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)
 | 
			
		||||
            } else {
 | 
			
		||||
                None
 | 
			
		||||
            }
 | 
			
		||||
    ) -> 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.render_resource_sets.insert(id, resource_set);
 | 
			
		||||
            self.bind_group_render_resource_sets
 | 
			
		||||
                .insert(bind_group_descriptor.id, id);
 | 
			
		||||
            RenderResourceSetStatus::Changed(id)
 | 
			
		||||
        } 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,
 | 
			
		||||
@ -35,13 +33,11 @@ impl<'a> Iterator for ShaderDefIterator<'a> {
 | 
			
		||||
        loop {
 | 
			
		||||
            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; 
 | 
			
		||||
                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,17 +72,17 @@ 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
 | 
			
		||||
            .shader_defs
 | 
			
		||||
            .insert(shader_def.to_string());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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,87 +453,69 @@ 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)
 | 
			
		||||
        {
 | 
			
		||||
            if !self
 | 
			
		||||
                .resources
 | 
			
		||||
                .has_bind_group(bind_group_descriptor.id, render_resource_set.id)
 | 
			
		||||
            {
 | 
			
		||||
                log::trace!(
 | 
			
		||||
                    "start creating bind group for RenderResourceSet {:?}",
 | 
			
		||||
                    render_resource_set.id
 | 
			
		||||
                );
 | 
			
		||||
                let texture_views = self.resources.texture_views.read().unwrap();
 | 
			
		||||
                let samplers = self.resources.samplers.read().unwrap();
 | 
			
		||||
                let buffers = self.resources.buffers.read().unwrap();
 | 
			
		||||
                let bind_group_layouts = self.resources.bind_group_layouts.read().unwrap();
 | 
			
		||||
                let mut bind_groups = self.resources.bind_groups.write().unwrap();
 | 
			
		||||
            log::trace!(
 | 
			
		||||
                "start creating bind group for RenderResourceSet {:?}",
 | 
			
		||||
                render_resource_set.id
 | 
			
		||||
            );
 | 
			
		||||
            let texture_views = self.resources.texture_views.read().unwrap();
 | 
			
		||||
            let samplers = self.resources.samplers.read().unwrap();
 | 
			
		||||
            let buffers = self.resources.buffers.read().unwrap();
 | 
			
		||||
            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
 | 
			
		||||
                    .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 {
 | 
			
		||||
                                RenderResourceAssignment::Texture(resource) => {
 | 
			
		||||
                                    let texture = texture_views.get(&resource).unwrap();
 | 
			
		||||
                                    wgpu::BindingResource::TextureView(texture)
 | 
			
		||||
                                }
 | 
			
		||||
                                RenderResourceAssignment::Sampler(resource) => {
 | 
			
		||||
                                    let sampler = samplers.get(&resource).unwrap();
 | 
			
		||||
                                    wgpu::BindingResource::Sampler(sampler)
 | 
			
		||||
                                }
 | 
			
		||||
                                RenderResourceAssignment::Buffer { resource, range , .. } => {
 | 
			
		||||
                                    let buffer = buffers.get(&resource).unwrap();
 | 
			
		||||
                                    wgpu::BindingResource::Buffer(buffer.slice(range.clone()))
 | 
			
		||||
                                }
 | 
			
		||||
                            };
 | 
			
		||||
                            wgpu::Binding {
 | 
			
		||||
                                binding: binding.index,
 | 
			
		||||
                                resource: wgpu_resource,
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            panic!(
 | 
			
		||||
                                "No resource assigned to uniform \"{}\" for RenderResourceAssignments {:?}",
 | 
			
		||||
                                binding.name,
 | 
			
		||||
                                render_resource_assignments.id
 | 
			
		||||
                            );
 | 
			
		||||
            let bindings = render_resource_set
 | 
			
		||||
                .indexed_assignments
 | 
			
		||||
                .iter()
 | 
			
		||||
                .map(|indexed_assignment| {
 | 
			
		||||
                    let wgpu_resource = match &indexed_assignment.assignment {
 | 
			
		||||
                        RenderResourceAssignment::Texture(resource) => {
 | 
			
		||||
                            let texture = texture_views.get(&resource).unwrap();
 | 
			
		||||
                            wgpu::BindingResource::TextureView(texture)
 | 
			
		||||
                        }
 | 
			
		||||
                    })
 | 
			
		||||
                    .collect::<Vec<wgpu::Binding>>();
 | 
			
		||||
                        RenderResourceAssignment::Sampler(resource) => {
 | 
			
		||||
                            let sampler = samplers.get(&resource).unwrap();
 | 
			
		||||
                            wgpu::BindingResource::Sampler(sampler)
 | 
			
		||||
                        }
 | 
			
		||||
                        RenderResourceAssignment::Buffer {
 | 
			
		||||
                            resource, range, ..
 | 
			
		||||
                        } => {
 | 
			
		||||
                            let buffer = buffers.get(&resource).unwrap();
 | 
			
		||||
                            wgpu::BindingResource::Buffer(buffer.slice(range.clone()))
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                    wgpu::Binding {
 | 
			
		||||
                        binding: indexed_assignment.index,
 | 
			
		||||
                        resource: wgpu_resource,
 | 
			
		||||
                    }
 | 
			
		||||
                })
 | 
			
		||||
                .collect::<Vec<wgpu::Binding>>();
 | 
			
		||||
 | 
			
		||||
                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,
 | 
			
		||||
                    bindings: bindings.as_slice(),
 | 
			
		||||
                };
 | 
			
		||||
                let wgpu_bind_group = self.device.create_bind_group(&wgpu_bind_group_descriptor);
 | 
			
		||||
            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,
 | 
			
		||||
                bindings: bindings.as_slice(),
 | 
			
		||||
            };
 | 
			
		||||
            let wgpu_bind_group = self.device.create_bind_group(&wgpu_bind_group_descriptor);
 | 
			
		||||
 | 
			
		||||
                let bind_group_info = bind_groups
 | 
			
		||||
                    .entry(bind_group_descriptor.id)
 | 
			
		||||
                    .or_insert_with(|| WgpuBindGroupInfo::default());
 | 
			
		||||
                bind_group_info
 | 
			
		||||
                    .bind_groups
 | 
			
		||||
                    .insert(render_resource_set.id, wgpu_bind_group);
 | 
			
		||||
                log::trace!(
 | 
			
		||||
                    "created bind group for RenderResourceSet {:?}",
 | 
			
		||||
                    render_resource_set.id
 | 
			
		||||
                );
 | 
			
		||||
                return Some(render_resource_set.id);
 | 
			
		||||
            }
 | 
			
		||||
            let bind_group_info = bind_groups
 | 
			
		||||
                .entry(bind_group_descriptor_id)
 | 
			
		||||
                .or_insert_with(|| WgpuBindGroupInfo::default());
 | 
			
		||||
            bind_group_info
 | 
			
		||||
                .bind_groups
 | 
			
		||||
                .insert(render_resource_set.id, wgpu_bind_group);
 | 
			
		||||
            log::trace!(
 | 
			
		||||
                "created bind group for RenderResourceSet {:?}",
 | 
			
		||||
                render_resource_set.id
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn clear_bind_groups(&self) {
 | 
			
		||||
 | 
			
		||||
@ -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 New Issue
	
	Block a user