mirror of
https://github.com/bevyengine/bevy
synced 2025-02-16 22:18:33 +00:00
render: "Immediate Mode" draw api
This replaces Renderable with Draw/RenderPipelines components and makes various aspects of the renderer much simpler and legible
This commit is contained in:
parent
3ccaebf9a5
commit
3d07fbdc81
34 changed files with 767 additions and 873 deletions
|
@ -1,7 +1,7 @@
|
||||||
use crate::{light::Light, material::StandardMaterial};
|
use crate::{light::Light, material::StandardMaterial};
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
use bevy_derive::EntityArchetype;
|
use bevy_derive::EntityArchetype;
|
||||||
use bevy_render::{mesh::Mesh, Renderable};
|
use bevy_render::{mesh::Mesh, draw::{RenderPipelines, Draw}};
|
||||||
use bevy_transform::prelude::{Transform, Rotation, Scale, Translation};
|
use bevy_transform::prelude::{Transform, Rotation, Scale, Translation};
|
||||||
|
|
||||||
#[derive(EntityArchetype, Default)]
|
#[derive(EntityArchetype, Default)]
|
||||||
|
@ -10,7 +10,8 @@ pub struct MeshEntity {
|
||||||
pub mesh: Handle<Mesh>,
|
pub mesh: Handle<Mesh>,
|
||||||
// #[tag]
|
// #[tag]
|
||||||
pub material: Handle<StandardMaterial>,
|
pub material: Handle<StandardMaterial>,
|
||||||
pub renderable: Renderable,
|
pub draw: Draw,
|
||||||
|
pub render_pipelines: RenderPipelines,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub translation: Translation,
|
pub translation: Translation,
|
||||||
pub rotation: Rotation,
|
pub rotation: Rotation,
|
||||||
|
|
|
@ -4,7 +4,7 @@ use bevy_render::{
|
||||||
base_render_graph,
|
base_render_graph,
|
||||||
pipeline::PipelineDescriptor,
|
pipeline::PipelineDescriptor,
|
||||||
render_graph::{
|
render_graph::{
|
||||||
nodes::{AssetUniformNode, PassNode, UniformNode},
|
nodes::{AssetUniformNode, UniformNode},
|
||||||
RenderGraph,
|
RenderGraph,
|
||||||
},
|
},
|
||||||
shader::Shader,
|
shader::Shader,
|
||||||
|
@ -36,12 +36,7 @@ impl ForwardPbrRenderGraphBuilder for RenderGraph {
|
||||||
self.add_system_node(node::LIGHTS, LightsNode::new(10));
|
self.add_system_node(node::LIGHTS, LightsNode::new(10));
|
||||||
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
|
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
|
||||||
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
|
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
|
||||||
{
|
pipelines.add_default(build_forward_pipeline(&mut shaders));
|
||||||
let main_pass: &mut PassNode = self
|
|
||||||
.get_node_mut(base_render_graph::node::MAIN_PASS)
|
|
||||||
.unwrap();
|
|
||||||
main_pass.add_pipeline(pipelines.add_default(build_forward_pipeline(&mut shaders)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: replace these with "autowire" groups
|
// TODO: replace these with "autowire" groups
|
||||||
self.add_node_edge(node::STANDARD_MATERIAL, base_render_graph::node::MAIN_PASS)
|
self.add_node_edge(node::STANDARD_MATERIAL, base_render_graph::node::MAIN_PASS)
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
RenderPassDepthStencilAttachmentDescriptor, StoreOp, TextureAttachment,
|
RenderPassDepthStencilAttachmentDescriptor, StoreOp, TextureAttachment,
|
||||||
},
|
},
|
||||||
render_graph::{
|
render_graph::{
|
||||||
nodes::{CameraNode, PassNode, TextureCopyNode, WindowSwapChainNode, WindowTextureNode},
|
nodes::{CameraNode, MainPassNode, TextureCopyNode, WindowSwapChainNode, WindowTextureNode},
|
||||||
RenderGraph,
|
RenderGraph,
|
||||||
},
|
},
|
||||||
texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage},
|
texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage},
|
||||||
|
@ -95,7 +95,7 @@ impl BaseRenderGraphBuilder for RenderGraph {
|
||||||
if config.add_main_pass {
|
if config.add_main_pass {
|
||||||
self.add_node(
|
self.add_node(
|
||||||
node::MAIN_PASS,
|
node::MAIN_PASS,
|
||||||
PassNode::new(PassDescriptor {
|
MainPassNode::new(PassDescriptor {
|
||||||
color_attachments: vec![RenderPassColorAttachmentDescriptor {
|
color_attachments: vec![RenderPassColorAttachmentDescriptor {
|
||||||
attachment: TextureAttachment::Input("color".to_string()),
|
attachment: TextureAttachment::Input("color".to_string()),
|
||||||
resolve_target: None,
|
resolve_target: None,
|
||||||
|
|
|
@ -1,41 +1,221 @@
|
||||||
use crate::{render_resource::RenderResourceId, pipeline::PipelineDescriptor};
|
use crate::{
|
||||||
use bevy_asset::Handle;
|
pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineDescriptor},
|
||||||
use std::ops::Range;
|
render_resource::{
|
||||||
|
RenderResourceAssignments, RenderResourceId, RenderResourceSet, RenderResourceSetId,
|
||||||
|
ResourceInfo,
|
||||||
|
},
|
||||||
|
renderer::{RenderResourceContext, RenderResources},
|
||||||
|
};
|
||||||
|
use bevy_asset::{Assets, Handle};
|
||||||
|
use bevy_property::Properties;
|
||||||
|
use legion::{
|
||||||
|
prelude::{Com, ComMut, Res},
|
||||||
|
storage::Component,
|
||||||
|
};
|
||||||
|
use std::{ops::Range, sync::Arc};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub enum DrawType {
|
pub enum RenderCommand {
|
||||||
Instanced {
|
SetPipeline {
|
||||||
|
pipeline: Handle<PipelineDescriptor>,
|
||||||
|
},
|
||||||
|
SetVertexBuffer {
|
||||||
|
slot: u32,
|
||||||
|
buffer: RenderResourceId,
|
||||||
|
offset: u64,
|
||||||
|
},
|
||||||
|
SetIndexBuffer {
|
||||||
|
buffer: RenderResourceId,
|
||||||
|
offset: u64,
|
||||||
|
},
|
||||||
|
SetBindGroup {
|
||||||
|
index: u32,
|
||||||
|
bind_group_descriptor: BindGroupDescriptorId,
|
||||||
|
render_resource_set: RenderResourceSetId,
|
||||||
|
dynamic_uniform_indices: Option<Arc<Vec<u32>>>,
|
||||||
|
},
|
||||||
|
DrawIndexed {
|
||||||
indices: Range<u32>,
|
indices: Range<u32>,
|
||||||
base_vertex: i32,
|
base_vertex: i32,
|
||||||
instances: Range<u32>,
|
instances: Range<u32>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Properties)]
|
||||||
|
pub struct Draw {
|
||||||
|
pub is_visible: bool,
|
||||||
|
#[property(ignore)]
|
||||||
|
pub render_commands: Vec<RenderCommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Draw {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
is_visible: true,
|
||||||
|
render_commands: Default::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Properties)]
|
||||||
pub struct VertexBufferBinding {
|
pub struct RenderPipelines {
|
||||||
pub slot: u32,
|
pub pipelines: Vec<Handle<PipelineDescriptor>>,
|
||||||
pub vertex_buffer: RenderResourceId,
|
// TODO: make these pipeline specific
|
||||||
pub offset: u64,
|
#[property(ignore)]
|
||||||
|
pub render_resource_assignments: RenderResourceAssignments,
|
||||||
|
#[property(ignore)]
|
||||||
|
pub compiled_pipelines: Vec<Handle<PipelineDescriptor>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
impl Default for RenderPipelines {
|
||||||
pub struct IndexBufferBinding {
|
fn default() -> Self {
|
||||||
pub vertex_buffer: RenderResourceId,
|
Self {
|
||||||
pub offset: u64,
|
render_resource_assignments: Default::default(),
|
||||||
|
compiled_pipelines: Default::default(),
|
||||||
|
pipelines: vec![Handle::default()],
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
impl Draw {
|
||||||
pub struct BindGroupBinding {
|
pub fn get_context<'a>(
|
||||||
pub vertex_buffer: RenderResourceId,
|
&'a mut self,
|
||||||
pub offset: u64,
|
pipelines: &'a Assets<PipelineDescriptor>,
|
||||||
|
render_resource_context: &'a dyn RenderResourceContext,
|
||||||
|
render_resource_assignments: &'a RenderResourceAssignments,
|
||||||
|
) -> DrawContext {
|
||||||
|
DrawContext {
|
||||||
|
draw: self,
|
||||||
|
pipelines,
|
||||||
|
render_resource_context,
|
||||||
|
render_resource_assignments,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
pub fn clear_render_commands(&mut self) {
|
||||||
pub struct DrawCall {
|
self.render_commands.clear();
|
||||||
pub pipeline: Handle<PipelineDescriptor>,
|
}
|
||||||
pub draw_type: DrawType,
|
|
||||||
pub vertex_buffers: Vec<VertexBufferBinding>,
|
|
||||||
pub index_buffer: Option<IndexBufferBinding>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Draw {}
|
pub struct DrawContext<'a> {
|
||||||
|
pub draw: &'a mut Draw,
|
||||||
|
pub pipelines: &'a Assets<PipelineDescriptor>,
|
||||||
|
pub render_resource_context: &'a dyn RenderResourceContext,
|
||||||
|
pub render_resource_assignments: &'a RenderResourceAssignments,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DrawContext<'a> {
|
||||||
|
pub fn set_pipeline(&mut self, pipeline: Handle<PipelineDescriptor>) {
|
||||||
|
self.render_command(RenderCommand::SetPipeline { pipeline });
|
||||||
|
}
|
||||||
|
pub fn set_vertex_buffer(&mut self, slot: u32, buffer: RenderResourceId, offset: u64) {
|
||||||
|
self.render_command(RenderCommand::SetVertexBuffer {
|
||||||
|
slot,
|
||||||
|
buffer,
|
||||||
|
offset,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_index_buffer(&mut self, buffer: RenderResourceId, offset: u64) {
|
||||||
|
self.render_command(RenderCommand::SetIndexBuffer { buffer, offset });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_bind_group(
|
||||||
|
&mut self,
|
||||||
|
bind_group_descriptor: &BindGroupDescriptor,
|
||||||
|
render_resource_set: &RenderResourceSet,
|
||||||
|
) {
|
||||||
|
self.render_command(RenderCommand::SetBindGroup {
|
||||||
|
index: bind_group_descriptor.index,
|
||||||
|
bind_group_descriptor: bind_group_descriptor.id,
|
||||||
|
render_resource_set: render_resource_set.id,
|
||||||
|
dynamic_uniform_indices: render_resource_set.dynamic_uniform_indices.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
|
||||||
|
self.render_command(RenderCommand::DrawIndexed {
|
||||||
|
base_vertex,
|
||||||
|
indices,
|
||||||
|
instances,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn render_command(&mut self, render_command: RenderCommand) {
|
||||||
|
self.draw.render_commands.push(render_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw<T: Drawable>(&mut self, drawable: &T) {
|
||||||
|
drawable.draw(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Drawable {
|
||||||
|
fn draw(&self, draw: &mut DrawContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drawable for RenderPipelines {
|
||||||
|
fn draw(&self, draw: &mut DrawContext) {
|
||||||
|
for pipeline_handle in self.compiled_pipelines.iter() {
|
||||||
|
let pipeline = draw.pipelines.get(pipeline_handle).unwrap();
|
||||||
|
let layout = pipeline.get_layout().unwrap();
|
||||||
|
draw.set_pipeline(*pipeline_handle);
|
||||||
|
for bind_group in layout.bind_groups.iter() {
|
||||||
|
if let Some(local_render_resource_set) = self
|
||||||
|
.render_resource_assignments
|
||||||
|
.get_bind_group_render_resource_set(bind_group.id)
|
||||||
|
{
|
||||||
|
draw.set_bind_group(bind_group, local_render_resource_set);
|
||||||
|
} else if let Some(global_render_resource_set) = draw
|
||||||
|
.render_resource_assignments
|
||||||
|
.get_bind_group_render_resource_set(bind_group.id)
|
||||||
|
{
|
||||||
|
draw.set_bind_group(bind_group, global_render_resource_set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut indices = 0..0;
|
||||||
|
for (slot, vertex_buffer_descriptor) in
|
||||||
|
layout.vertex_buffer_descriptors.iter().enumerate()
|
||||||
|
{
|
||||||
|
if let Some((vertex_buffer, index_buffer)) = self
|
||||||
|
.render_resource_assignments
|
||||||
|
.get_vertex_buffer(&vertex_buffer_descriptor.name)
|
||||||
|
{
|
||||||
|
draw.set_vertex_buffer(slot as u32, vertex_buffer, 0);
|
||||||
|
if let Some(index_buffer) = index_buffer {
|
||||||
|
draw.render_resource_context.get_resource_info(
|
||||||
|
index_buffer,
|
||||||
|
&mut |resource_info| match resource_info {
|
||||||
|
Some(ResourceInfo::Buffer(Some(buffer_info))) => {
|
||||||
|
indices = 0..(buffer_info.size / 2) as u32;
|
||||||
|
}
|
||||||
|
_ => panic!("expected a buffer type"),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
draw.set_index_buffer(index_buffer, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw.draw_indexed(indices, 0, 0..1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_system<T: Drawable + Component>(
|
||||||
|
pipelines: Res<Assets<PipelineDescriptor>>,
|
||||||
|
render_resource_assignments: Res<RenderResourceAssignments>,
|
||||||
|
render_resources: Res<RenderResources>,
|
||||||
|
mut draw: ComMut<Draw>,
|
||||||
|
drawable: Com<T>,
|
||||||
|
) {
|
||||||
|
let context = &*render_resources.context;
|
||||||
|
let mut draw_context = draw.get_context(&pipelines, context, &render_resource_assignments);
|
||||||
|
draw_context.draw(drawable.as_ref());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_draw_system(mut draw: ComMut<Draw>) {
|
||||||
|
draw.clear_render_commands();
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
base_render_graph, mesh::Mesh, Camera, OrthographicProjection, PerspectiveProjection,
|
base_render_graph, mesh::Mesh, Camera, OrthographicProjection, PerspectiveProjection,
|
||||||
Renderable, WindowOrigin,
|
RenderPipelines, WindowOrigin, draw::Draw,
|
||||||
};
|
};
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
use bevy_derive::EntityArchetype;
|
use bevy_derive::EntityArchetype;
|
||||||
|
@ -10,7 +10,8 @@ use bevy_transform::components::{Transform, Rotation, Scale, Translation};
|
||||||
pub struct MeshMaterialEntity<T: Default + Send + Sync + 'static> {
|
pub struct MeshMaterialEntity<T: Default + Send + Sync + 'static> {
|
||||||
pub mesh: Handle<Mesh>,
|
pub mesh: Handle<Mesh>,
|
||||||
pub material: Handle<T>,
|
pub material: Handle<T>,
|
||||||
pub renderable: Renderable,
|
pub draw: Draw,
|
||||||
|
pub render_pipelines: RenderPipelines,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub translation: Translation,
|
pub translation: Translation,
|
||||||
pub rotation: Rotation,
|
pub rotation: Rotation,
|
||||||
|
|
|
@ -12,7 +12,6 @@ mod color;
|
||||||
|
|
||||||
pub use camera::*;
|
pub use camera::*;
|
||||||
pub use color::*;
|
pub use color::*;
|
||||||
pub use renderable::*;
|
|
||||||
|
|
||||||
pub use vertex::Vertex;
|
pub use vertex::Vertex;
|
||||||
|
|
||||||
|
@ -20,20 +19,14 @@ pub mod base_render_graph;
|
||||||
pub mod pass;
|
pub mod pass;
|
||||||
pub mod pipeline;
|
pub mod pipeline;
|
||||||
pub mod render_resource;
|
pub mod render_resource;
|
||||||
mod renderable;
|
|
||||||
pub mod texture;
|
pub mod texture;
|
||||||
|
|
||||||
pub use once_cell;
|
pub use once_cell;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
mesh::Mesh,
|
mesh::Mesh,
|
||||||
pipeline::{
|
pipeline::{PipelineCompiler, PipelineDescriptor, VertexBufferDescriptors},
|
||||||
PipelineAssignments, PipelineCompiler, PipelineDescriptor, VertexBufferDescriptors,
|
render_resource::RenderResourceAssignments,
|
||||||
},
|
|
||||||
render_resource::{
|
|
||||||
entity_render_resource_assignments_system, EntityRenderResourceAssignments,
|
|
||||||
RenderResourceAssignments,
|
|
||||||
},
|
|
||||||
shader::Shader,
|
shader::Shader,
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
};
|
};
|
||||||
|
@ -42,6 +35,7 @@ use base_render_graph::{BaseRenderGraphBuilder, BaseRenderGraphConfig};
|
||||||
use bevy_app::{AppBuilder, AppPlugin};
|
use bevy_app::{AppBuilder, AppPlugin};
|
||||||
use bevy_asset::AddAsset;
|
use bevy_asset::AddAsset;
|
||||||
use bevy_type_registry::RegisterType;
|
use bevy_type_registry::RegisterType;
|
||||||
|
use draw::{clear_draw_system, Draw, RenderPipelines};
|
||||||
use legion::prelude::IntoSystem;
|
use legion::prelude::IntoSystem;
|
||||||
use mesh::mesh_resource_provider_system;
|
use mesh::mesh_resource_provider_system;
|
||||||
use render_graph::RenderGraph;
|
use render_graph::RenderGraph;
|
||||||
|
@ -51,6 +45,7 @@ use texture::{PngTextureLoader, TextureResourceSystemState};
|
||||||
|
|
||||||
pub mod stage {
|
pub mod stage {
|
||||||
pub static RENDER_RESOURCE: &str = "render_resource";
|
pub static RENDER_RESOURCE: &str = "render_resource";
|
||||||
|
pub static PRE_RENDER: &str = "pre_render";
|
||||||
pub static RENDER: &str = "render";
|
pub static RENDER: &str = "render";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,30 +65,27 @@ impl Default for RenderPlugin {
|
||||||
impl AppPlugin for RenderPlugin {
|
impl AppPlugin for RenderPlugin {
|
||||||
fn build(&self, app: &mut AppBuilder) {
|
fn build(&self, app: &mut AppBuilder) {
|
||||||
app.add_stage_after(bevy_asset::stage::ASSET_EVENTS, stage::RENDER_RESOURCE)
|
app.add_stage_after(bevy_asset::stage::ASSET_EVENTS, stage::RENDER_RESOURCE)
|
||||||
.add_stage_after(stage::RENDER_RESOURCE, stage::RENDER)
|
.add_stage_after(stage::RENDER_RESOURCE, stage::PRE_RENDER)
|
||||||
|
.add_stage_after(stage::PRE_RENDER, stage::RENDER)
|
||||||
.add_asset::<Mesh>()
|
.add_asset::<Mesh>()
|
||||||
.add_asset::<Texture>()
|
.add_asset::<Texture>()
|
||||||
.add_asset::<Shader>()
|
.add_asset::<Shader>()
|
||||||
.add_asset::<PipelineDescriptor>()
|
.add_asset::<PipelineDescriptor>()
|
||||||
.add_asset_loader::<Texture, PngTextureLoader>()
|
.add_asset_loader::<Texture, PngTextureLoader>()
|
||||||
.register_component::<Camera>()
|
.register_component::<Camera>()
|
||||||
|
.register_component::<Draw>()
|
||||||
|
.register_component::<RenderPipelines>()
|
||||||
.register_component::<OrthographicProjection>()
|
.register_component::<OrthographicProjection>()
|
||||||
.register_component::<PerspectiveProjection>()
|
.register_component::<PerspectiveProjection>()
|
||||||
.register_component::<Renderable>()
|
|
||||||
.register_property_type::<Color>()
|
.register_property_type::<Color>()
|
||||||
.register_property_type::<Range<f32>>()
|
.register_property_type::<Range<f32>>()
|
||||||
.init_resource::<RenderGraph>()
|
.init_resource::<RenderGraph>()
|
||||||
.init_resource::<PipelineAssignments>()
|
|
||||||
.init_resource::<PipelineCompiler>()
|
.init_resource::<PipelineCompiler>()
|
||||||
.init_resource::<RenderResourceAssignments>()
|
.init_resource::<RenderResourceAssignments>()
|
||||||
.init_resource::<VertexBufferDescriptors>()
|
.init_resource::<VertexBufferDescriptors>()
|
||||||
.init_resource::<EntityRenderResourceAssignments>()
|
|
||||||
.init_resource::<EntitiesWaitingForAssets>()
|
.init_resource::<EntitiesWaitingForAssets>()
|
||||||
.init_resource::<TextureResourceSystemState>()
|
.init_resource::<TextureResourceSystemState>()
|
||||||
.add_system_to_stage(
|
.add_system_to_stage(bevy_app::stage::PRE_UPDATE, clear_draw_system.system())
|
||||||
bevy_app::stage::POST_UPDATE,
|
|
||||||
entity_render_resource_assignments_system(),
|
|
||||||
)
|
|
||||||
.init_system_to_stage(
|
.init_system_to_stage(
|
||||||
bevy_app::stage::POST_UPDATE,
|
bevy_app::stage::POST_UPDATE,
|
||||||
camera::camera_system::<OrthographicProjection>,
|
camera::camera_system::<OrthographicProjection>,
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
pipeline::{
|
pipeline::{
|
||||||
state_descriptors::{IndexFormat, PrimitiveTopology},
|
state_descriptors::{IndexFormat, PrimitiveTopology},
|
||||||
VertexBufferDescriptor, VertexBufferDescriptors, VertexFormat,
|
AsVertexBufferDescriptor, VertexBufferDescriptor, VertexBufferDescriptors, VertexFormat,
|
||||||
AsVertexBufferDescriptor,
|
|
||||||
},
|
},
|
||||||
render_resource::{BufferInfo, BufferUsage},
|
render_resource::{BufferInfo, BufferUsage},
|
||||||
renderer::{RenderResourceContext, RenderResources},
|
renderer::{RenderResourceContext, RenderResources},
|
||||||
Renderable, Vertex,
|
RenderPipelines, Vertex,
|
||||||
};
|
};
|
||||||
use bevy_app::{EventReader, Events};
|
use bevy_app::{EventReader, Events};
|
||||||
use bevy_asset::{AssetEvent, Assets, Handle};
|
use bevy_asset::{AssetEvent, Assets, Handle};
|
||||||
|
@ -345,7 +344,7 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
|
||||||
render_resources: Res<RenderResources>,
|
render_resources: Res<RenderResources>,
|
||||||
meshes: Res<Assets<Mesh>>,
|
meshes: Res<Assets<Mesh>>,
|
||||||
mesh_events: Res<Events<AssetEvent<Mesh>>>,
|
mesh_events: Res<Events<AssetEvent<Mesh>>>,
|
||||||
query: &mut Query<(Read<Handle<Mesh>>, Write<Renderable>)>| {
|
query: &mut Query<(Read<Handle<Mesh>>, Write<RenderPipelines>)>| {
|
||||||
let render_resources = &*render_resources.context;
|
let render_resources = &*render_resources.context;
|
||||||
let mut changed_meshes = HashSet::new();
|
let mut changed_meshes = HashSet::new();
|
||||||
for event in mesh_event_reader.iter(&mesh_events) {
|
for event in mesh_event_reader.iter(&mesh_events) {
|
||||||
|
@ -403,9 +402,9 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this once batches are pipeline specific and deprecate assigned_meshes draw target
|
// TODO: remove this once batches are pipeline specific and deprecate assigned_meshes draw target
|
||||||
for (handle, mut renderable) in query.iter_mut(world) {
|
for (handle, mut render_pipelines) in query.iter_mut(world) {
|
||||||
if let Some(mesh) = meshes.get(&handle) {
|
if let Some(mesh) = meshes.get(&handle) {
|
||||||
renderable
|
render_pipelines
|
||||||
.render_resource_assignments
|
.render_resource_assignments
|
||||||
.pipeline_specialization
|
.pipeline_specialization
|
||||||
.primitive_topology = mesh.primitive_topology;
|
.primitive_topology = mesh.primitive_topology;
|
||||||
|
@ -417,11 +416,9 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
|
||||||
let index_buffer =
|
let index_buffer =
|
||||||
render_resources.get_asset_resource(*handle, INDEX_BUFFER_ASSET_INDEX);
|
render_resources.get_asset_resource(*handle, INDEX_BUFFER_ASSET_INDEX);
|
||||||
|
|
||||||
renderable.render_resource_assignments.set_vertex_buffer(
|
render_pipelines
|
||||||
"Vertex",
|
.render_resource_assignments
|
||||||
vertex_buffer,
|
.set_vertex_buffer("Vertex", vertex_buffer, index_buffer);
|
||||||
index_buffer,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -430,7 +427,7 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Mesh, VertexAttribute, AsVertexBufferDescriptor};
|
use super::{AsVertexBufferDescriptor, Mesh, VertexAttribute};
|
||||||
use crate::{pipeline::state_descriptors::PrimitiveTopology, Vertex};
|
use crate::{pipeline::state_descriptors::PrimitiveTopology, Vertex};
|
||||||
use bevy_core::bytes::AsBytes;
|
use bevy_core::bytes::AsBytes;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
pipeline::{PipelineDescriptor, BindGroupDescriptorId},
|
||||||
render_resource::{RenderResourceId, RenderResourceSet},
|
render_resource::{RenderResourceId, RenderResourceSetId},
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
};
|
};
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
|
@ -17,7 +17,9 @@ pub trait RenderPass {
|
||||||
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
||||||
fn set_bind_group(
|
fn set_bind_group(
|
||||||
&mut self,
|
&mut self,
|
||||||
bind_group_descriptor: &BindGroupDescriptor,
|
index: u32,
|
||||||
render_resource_set: &RenderResourceSet,
|
bind_group_descriptor: BindGroupDescriptorId,
|
||||||
|
render_resource_set: RenderResourceSetId,
|
||||||
|
dynamic_uniform_indices: Option<&[u32]>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,23 +13,10 @@ use crate::{
|
||||||
};
|
};
|
||||||
use bevy_asset::Assets;
|
use bevy_asset::Assets;
|
||||||
|
|
||||||
// TODO: consider removing this in favor of Option<Layout>
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum PipelineLayoutType {
|
|
||||||
Manual(PipelineLayout),
|
|
||||||
Reflected(Option<PipelineLayout>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum DescriptorType<T> {
|
|
||||||
Manual(T),
|
|
||||||
Reflected(Option<T>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PipelineDescriptor {
|
pub struct PipelineDescriptor {
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub layout: PipelineLayoutType,
|
pub layout: Option<PipelineLayout>,
|
||||||
pub shader_stages: ShaderStages,
|
pub shader_stages: ShaderStages,
|
||||||
pub rasterization_state: Option<RasterizationStateDescriptor>,
|
pub rasterization_state: Option<RasterizationStateDescriptor>,
|
||||||
|
|
||||||
|
@ -63,7 +50,7 @@ impl PipelineDescriptor {
|
||||||
pub fn new(shader_stages: ShaderStages) -> Self {
|
pub fn new(shader_stages: ShaderStages) -> Self {
|
||||||
PipelineDescriptor {
|
PipelineDescriptor {
|
||||||
name: None,
|
name: None,
|
||||||
layout: PipelineLayoutType::Reflected(None),
|
layout: None,
|
||||||
color_states: Vec::new(),
|
color_states: Vec::new(),
|
||||||
depth_stencil_state: None,
|
depth_stencil_state: None,
|
||||||
shader_stages,
|
shader_stages,
|
||||||
|
@ -80,7 +67,7 @@ impl PipelineDescriptor {
|
||||||
PipelineDescriptor {
|
PipelineDescriptor {
|
||||||
name: None,
|
name: None,
|
||||||
primitive_topology: PrimitiveTopology::TriangleList,
|
primitive_topology: PrimitiveTopology::TriangleList,
|
||||||
layout: PipelineLayoutType::Reflected(None),
|
layout: None,
|
||||||
index_format: IndexFormat::Uint16,
|
index_format: IndexFormat::Uint16,
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
sample_mask: !0,
|
sample_mask: !0,
|
||||||
|
@ -120,17 +107,11 @@ impl PipelineDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_layout(&self) -> Option<&PipelineLayout> {
|
pub fn get_layout(&self) -> Option<&PipelineLayout> {
|
||||||
match self.layout {
|
self.layout.as_ref()
|
||||||
PipelineLayoutType::Reflected(ref layout) => layout.as_ref(),
|
|
||||||
PipelineLayoutType::Manual(ref layout) => Some(layout),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_layout_mut(&mut self) -> Option<&mut PipelineLayout> {
|
pub fn get_layout_mut(&mut self) -> Option<&mut PipelineLayout> {
|
||||||
match self.layout {
|
self.layout.as_mut()
|
||||||
PipelineLayoutType::Reflected(ref mut layout) => layout.as_mut(),
|
|
||||||
PipelineLayoutType::Manual(ref mut layout) => Some(layout),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reflects the pipeline layout from its shaders.
|
/// Reflects the pipeline layout from its shaders.
|
||||||
|
@ -190,6 +171,6 @@ impl PipelineDescriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.layout = PipelineLayoutType::Reflected(Some(layout));
|
self.layout = Some(layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use super::{state_descriptors::PrimitiveTopology, PipelineDescriptor, VertexBufferDescriptors};
|
use super::{state_descriptors::PrimitiveTopology, PipelineDescriptor, VertexBufferDescriptors};
|
||||||
use crate::{
|
use crate::{
|
||||||
render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId},
|
draw::RenderPipelines,
|
||||||
|
renderer::{RenderResourceContext, RenderResources},
|
||||||
shader::{Shader, ShaderSource},
|
shader::{Shader, ShaderSource},
|
||||||
Renderable,
|
|
||||||
};
|
};
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
@ -78,14 +78,15 @@ impl PipelineCompiler {
|
||||||
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
||||||
shaders: &mut Assets<Shader>,
|
shaders: &mut Assets<Shader>,
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
pipeline_descriptor: &PipelineDescriptor,
|
||||||
render_resource_assignments: &RenderResourceAssignments,
|
render_pipelines: &RenderPipelines,
|
||||||
) -> PipelineDescriptor {
|
) -> PipelineDescriptor {
|
||||||
let mut compiled_pipeline_descriptor = pipeline_descriptor.clone();
|
let mut compiled_pipeline_descriptor = pipeline_descriptor.clone();
|
||||||
|
|
||||||
compiled_pipeline_descriptor.shader_stages.vertex = self.compile_shader(
|
compiled_pipeline_descriptor.shader_stages.vertex = self.compile_shader(
|
||||||
shaders,
|
shaders,
|
||||||
&pipeline_descriptor.shader_stages.vertex,
|
&pipeline_descriptor.shader_stages.vertex,
|
||||||
&render_resource_assignments
|
&render_pipelines
|
||||||
|
.render_resource_assignments
|
||||||
.pipeline_specialization
|
.pipeline_specialization
|
||||||
.shader_specialization,
|
.shader_specialization,
|
||||||
);
|
);
|
||||||
|
@ -97,7 +98,8 @@ impl PipelineCompiler {
|
||||||
self.compile_shader(
|
self.compile_shader(
|
||||||
shaders,
|
shaders,
|
||||||
fragment,
|
fragment,
|
||||||
&render_resource_assignments
|
&render_pipelines
|
||||||
|
.render_resource_assignments
|
||||||
.pipeline_specialization
|
.pipeline_specialization
|
||||||
.shader_specialization,
|
.shader_specialization,
|
||||||
)
|
)
|
||||||
|
@ -107,72 +109,78 @@ impl PipelineCompiler {
|
||||||
shaders,
|
shaders,
|
||||||
true,
|
true,
|
||||||
Some(vertex_buffer_descriptors),
|
Some(vertex_buffer_descriptors),
|
||||||
Some(render_resource_assignments),
|
Some(&render_pipelines.render_resource_assignments),
|
||||||
);
|
);
|
||||||
|
|
||||||
compiled_pipeline_descriptor.primitive_topology = render_resource_assignments
|
compiled_pipeline_descriptor.primitive_topology = render_pipelines
|
||||||
|
.render_resource_assignments
|
||||||
.pipeline_specialization
|
.pipeline_specialization
|
||||||
.primitive_topology;
|
.primitive_topology;
|
||||||
compiled_pipeline_descriptor
|
compiled_pipeline_descriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_shader_assignments(
|
fn compile_pipelines(
|
||||||
&mut self,
|
&mut self,
|
||||||
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
||||||
shader_pipeline_assignments: &mut PipelineAssignments,
|
|
||||||
pipelines: &mut Assets<PipelineDescriptor>,
|
pipelines: &mut Assets<PipelineDescriptor>,
|
||||||
shaders: &mut Assets<Shader>,
|
shaders: &mut Assets<Shader>,
|
||||||
pipeline_handles: &[Handle<PipelineDescriptor>],
|
render_pipelines: &mut RenderPipelines,
|
||||||
render_resource_assignments: &RenderResourceAssignments,
|
render_resource_context: &dyn RenderResourceContext,
|
||||||
) {
|
) {
|
||||||
for pipeline_handle in pipeline_handles.iter() {
|
for (i, pipeline_handle) in render_pipelines.pipelines.iter().enumerate() {
|
||||||
if let None = self.pipeline_source_to_compiled.get(pipeline_handle) {
|
if let None = self.pipeline_source_to_compiled.get(pipeline_handle) {
|
||||||
self.pipeline_source_to_compiled
|
self.pipeline_source_to_compiled
|
||||||
.insert(*pipeline_handle, Vec::new());
|
.insert(*pipeline_handle, Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
let final_handle = if let Some((_shader_defs, macroed_pipeline_handle)) = self
|
let compiled_pipeline_handle = if let Some((_shader_defs, compiled_pipeline_handle)) =
|
||||||
.pipeline_source_to_compiled
|
self.pipeline_source_to_compiled
|
||||||
.get_mut(pipeline_handle)
|
.get_mut(pipeline_handle)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(pipeline_specialization, _macroed_pipeline_handle)| {
|
.find(|(pipeline_specialization, _compiled_pipeline_handle)| {
|
||||||
*pipeline_specialization == render_resource_assignments.pipeline_specialization
|
*pipeline_specialization
|
||||||
|
== render_pipelines
|
||||||
|
.render_resource_assignments
|
||||||
|
.pipeline_specialization
|
||||||
}) {
|
}) {
|
||||||
*macroed_pipeline_handle
|
*compiled_pipeline_handle
|
||||||
} else {
|
} else {
|
||||||
let pipeline_descriptor = pipelines.get(pipeline_handle).unwrap();
|
let pipeline_descriptor = pipelines.get(pipeline_handle).unwrap();
|
||||||
let compiled_pipeline = self.compile_pipeline(
|
let compiled_pipeline_descriptor = self.compile_pipeline(
|
||||||
vertex_buffer_descriptors,
|
vertex_buffer_descriptors,
|
||||||
shaders,
|
shaders,
|
||||||
pipeline_descriptor,
|
pipeline_descriptor,
|
||||||
render_resource_assignments,
|
render_pipelines,
|
||||||
|
);
|
||||||
|
let compiled_pipeline_handle = pipelines.add(compiled_pipeline_descriptor);
|
||||||
|
render_resource_context.create_render_pipeline(
|
||||||
|
compiled_pipeline_handle,
|
||||||
|
pipelines.get(&compiled_pipeline_handle).unwrap(),
|
||||||
|
&shaders,
|
||||||
);
|
);
|
||||||
let compiled_pipeline_handle = pipelines.add(compiled_pipeline);
|
|
||||||
|
|
||||||
let macro_pipelines = self
|
let compiled_pipelines = self
|
||||||
.pipeline_source_to_compiled
|
.pipeline_source_to_compiled
|
||||||
.get_mut(pipeline_handle)
|
.get_mut(pipeline_handle)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
macro_pipelines.push((
|
compiled_pipelines.push((
|
||||||
render_resource_assignments.pipeline_specialization.clone(),
|
render_pipelines
|
||||||
|
.render_resource_assignments
|
||||||
|
.pipeline_specialization
|
||||||
|
.clone(),
|
||||||
compiled_pipeline_handle,
|
compiled_pipeline_handle,
|
||||||
));
|
));
|
||||||
compiled_pipeline_handle
|
compiled_pipeline_handle
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: this will break down if pipeline layout changes. fix this with "auto-layout"
|
if i == render_pipelines.compiled_pipelines.len() {
|
||||||
if let None = shader_pipeline_assignments.assignments.get(&final_handle) {
|
render_pipelines
|
||||||
shader_pipeline_assignments
|
.compiled_pipelines
|
||||||
.assignments
|
.push(compiled_pipeline_handle);
|
||||||
.insert(final_handle, Vec::new());
|
} else {
|
||||||
|
render_pipelines.compiled_pipelines[i] = compiled_pipeline_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
let assignments = shader_pipeline_assignments
|
|
||||||
.assignments
|
|
||||||
.get_mut(&final_handle)
|
|
||||||
.unwrap();
|
|
||||||
assignments.push(render_resource_assignments.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,44 +207,30 @@ impl PipelineCompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct PipelineAssignments {
|
|
||||||
pub assignments: HashMap<Handle<PipelineDescriptor>, Vec<RenderResourceAssignmentsId>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: make this a system
|
// TODO: make this a system
|
||||||
pub fn update_shader_assignments(world: &mut World, resources: &Resources) {
|
pub fn compile_pipelines_system(
|
||||||
// PERF: this seems like a lot of work for things that don't change that often.
|
world: &mut SubWorld,
|
||||||
// lots of string + hashset allocations. sees uniform_resource_provider for more context
|
mut pipeline_compiler: ResMut<PipelineCompiler>,
|
||||||
{
|
mut shaders: ResMut<Assets<Shader>>,
|
||||||
let mut shader_pipeline_assignments = resources.get_mut::<PipelineAssignments>().unwrap();
|
mut pipelines: ResMut<Assets<PipelineDescriptor>>,
|
||||||
let mut pipeline_compiler = resources.get_mut::<PipelineCompiler>().unwrap();
|
vertex_buffer_descriptors: Res<VertexBufferDescriptors>,
|
||||||
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
|
render_resources: Res<RenderResources>,
|
||||||
let vertex_buffer_descriptors = resources.get::<VertexBufferDescriptors>().unwrap();
|
query: &mut Query<Write<RenderPipelines>>,
|
||||||
let mut pipeline_descriptor_storage =
|
) {
|
||||||
resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
|
let render_resource_context = &*render_resources.context;
|
||||||
|
|
||||||
// reset assignments so they are updated every frame
|
// TODO: only update when RenderPipelines is changed
|
||||||
shader_pipeline_assignments.assignments = HashMap::new();
|
for mut render_pipelines in query.iter_mut(world) {
|
||||||
|
pipeline_compiler.compile_pipelines(
|
||||||
// TODO: only update when renderable is changed
|
|
||||||
for mut renderable in <Write<Renderable>>::query().iter_mut(world) {
|
|
||||||
// skip instanced entities. their batched RenderResourceAssignments will handle shader assignments
|
|
||||||
if renderable.is_instanced {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline_compiler.update_shader_assignments(
|
|
||||||
&vertex_buffer_descriptors,
|
&vertex_buffer_descriptors,
|
||||||
&mut shader_pipeline_assignments,
|
&mut pipelines,
|
||||||
&mut pipeline_descriptor_storage,
|
|
||||||
&mut shaders,
|
&mut shaders,
|
||||||
&renderable.pipelines,
|
&mut render_pipelines,
|
||||||
&renderable.render_resource_assignments,
|
render_resource_context,
|
||||||
);
|
);
|
||||||
|
|
||||||
// reset shader_defs so they can be changed next frame
|
// reset shader_defs so they can be changed next frame
|
||||||
renderable
|
render_pipelines
|
||||||
.render_resource_assignments
|
.render_resource_assignments
|
||||||
.pipeline_specialization
|
.pipeline_specialization
|
||||||
.shader_specialization
|
.shader_specialization
|
||||||
|
@ -244,4 +238,3 @@ pub fn update_shader_assignments(world: &mut World, resources: &Resources) {
|
||||||
.clear();
|
.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,28 +1,20 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
pass::{PassDescriptor, RenderPass, TextureAttachment},
|
draw::{Draw, RenderCommand},
|
||||||
pipeline::{PipelineAssignments, PipelineCompiler, PipelineDescriptor},
|
pass::{PassDescriptor, TextureAttachment},
|
||||||
render_graph::{Node, ResourceSlotInfo, ResourceSlots},
|
render_graph::{Node, ResourceSlotInfo, ResourceSlots},
|
||||||
render_resource::{
|
render_resource::{EntitiesWaitingForAssets, RenderResourceAssignments, ResourceInfo},
|
||||||
EntitiesWaitingForAssets, EntityRenderResourceAssignments, RenderResourceAssignments,
|
|
||||||
ResourceInfo,
|
|
||||||
},
|
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
shader::Shader,
|
|
||||||
Renderable,
|
|
||||||
};
|
};
|
||||||
use bevy_asset::{Assets, Handle};
|
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
use std::ops::Range;
|
|
||||||
|
|
||||||
pub struct PassNode {
|
pub struct MainPassNode {
|
||||||
descriptor: PassDescriptor,
|
descriptor: PassDescriptor,
|
||||||
pipelines: Vec<Handle<PipelineDescriptor>>,
|
|
||||||
inputs: Vec<ResourceSlotInfo>,
|
inputs: Vec<ResourceSlotInfo>,
|
||||||
color_attachment_input_indices: Vec<Option<usize>>,
|
color_attachment_input_indices: Vec<Option<usize>>,
|
||||||
depth_stencil_attachment_input_index: Option<usize>,
|
depth_stencil_attachment_input_index: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PassNode {
|
impl MainPassNode {
|
||||||
pub fn new(descriptor: PassDescriptor) -> Self {
|
pub fn new(descriptor: PassDescriptor) -> Self {
|
||||||
let mut inputs = Vec::new();
|
let mut inputs = Vec::new();
|
||||||
let mut color_attachment_input_indices = Vec::new();
|
let mut color_attachment_input_indices = Vec::new();
|
||||||
|
@ -49,77 +41,16 @@ impl PassNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PassNode {
|
MainPassNode {
|
||||||
descriptor,
|
descriptor,
|
||||||
pipelines: Vec::new(),
|
|
||||||
inputs,
|
inputs,
|
||||||
color_attachment_input_indices,
|
color_attachment_input_indices,
|
||||||
depth_stencil_attachment_input_index,
|
depth_stencil_attachment_input_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>) {
|
|
||||||
self.pipelines.push(pipeline_handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_render_resources(
|
impl Node for MainPassNode {
|
||||||
render_pass: &mut dyn RenderPass,
|
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
|
||||||
render_resource_assignments: &RenderResourceAssignments,
|
|
||||||
) -> Option<Range<u32>> {
|
|
||||||
let pipeline_layout = pipeline_descriptor.get_layout().unwrap();
|
|
||||||
// PERF: vertex buffer lookup comes at a cost when vertex buffers aren't in render_resource_assignments. iterating over render_resource_assignment vertex buffers
|
|
||||||
// would likely be faster
|
|
||||||
let mut indices = None;
|
|
||||||
for (i, vertex_buffer_descriptor) in
|
|
||||||
pipeline_layout.vertex_buffer_descriptors.iter().enumerate()
|
|
||||||
{
|
|
||||||
if let Some((vertex_buffer, index_buffer)) =
|
|
||||||
render_resource_assignments.get_vertex_buffer(&vertex_buffer_descriptor.name)
|
|
||||||
{
|
|
||||||
log::trace!(
|
|
||||||
"set vertex buffer {}: {} ({:?})",
|
|
||||||
i,
|
|
||||||
vertex_buffer_descriptor.name,
|
|
||||||
vertex_buffer
|
|
||||||
);
|
|
||||||
render_pass.set_vertex_buffer(i as u32, vertex_buffer, 0);
|
|
||||||
if let Some(index_buffer) = index_buffer {
|
|
||||||
log::trace!(
|
|
||||||
"set index buffer: {} ({:?})",
|
|
||||||
vertex_buffer_descriptor.name,
|
|
||||||
index_buffer
|
|
||||||
);
|
|
||||||
render_pass.set_index_buffer(index_buffer, 0);
|
|
||||||
render_pass
|
|
||||||
.get_render_context()
|
|
||||||
.resources()
|
|
||||||
.get_resource_info(
|
|
||||||
index_buffer,
|
|
||||||
&mut |resource_info| match resource_info {
|
|
||||||
Some(ResourceInfo::Buffer(Some(buffer_info))) => {
|
|
||||||
indices = Some(0..(buffer_info.size / 2) as u32)
|
|
||||||
}
|
|
||||||
_ => panic!("expected a buffer type"),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for bind_group in pipeline_layout.bind_groups.iter() {
|
|
||||||
if let Some(render_resource_set) =
|
|
||||||
render_resource_assignments.get_render_resource_set(bind_group.id)
|
|
||||||
{
|
|
||||||
render_pass.set_bind_group(bind_group, &render_resource_set);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
indices
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node for PassNode {
|
|
||||||
fn input(&self) -> &[ResourceSlotInfo] {
|
fn input(&self) -> &[ResourceSlotInfo] {
|
||||||
&self.inputs
|
&self.inputs
|
||||||
}
|
}
|
||||||
|
@ -132,14 +63,8 @@ impl Node for PassNode {
|
||||||
input: &ResourceSlots,
|
input: &ResourceSlots,
|
||||||
_output: &mut ResourceSlots,
|
_output: &mut ResourceSlots,
|
||||||
) {
|
) {
|
||||||
let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap();
|
|
||||||
let pipelines = resources.get::<Assets<PipelineDescriptor>>().unwrap();
|
|
||||||
let shader_pipeline_assignments = resources.get::<PipelineAssignments>().unwrap();
|
|
||||||
let entity_render_resource_assignments =
|
|
||||||
resources.get::<EntityRenderResourceAssignments>().unwrap();
|
|
||||||
let entities_waiting_for_assets = resources.get::<EntitiesWaitingForAssets>().unwrap();
|
let entities_waiting_for_assets = resources.get::<EntitiesWaitingForAssets>().unwrap();
|
||||||
let mut render_resource_assignments =
|
let render_resource_assignments = resources.get::<RenderResourceAssignments>().unwrap();
|
||||||
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
|
||||||
|
|
||||||
for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() {
|
for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() {
|
||||||
if let Some(input_index) = self.color_attachment_input_indices[i] {
|
if let Some(input_index) = self.color_attachment_input_indices[i] {
|
||||||
|
@ -156,117 +81,56 @@ impl Node for PassNode {
|
||||||
.attachment = TextureAttachment::RenderResource(input.get(input_index).unwrap());
|
.attachment = TextureAttachment::RenderResource(input.get(input_index).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
let render_resource_context = render_context.resources();
|
|
||||||
|
|
||||||
// TODO: try merging the two pipeline loops below
|
|
||||||
let shaders = resources.get::<Assets<Shader>>().unwrap();
|
|
||||||
for pipeline_handle in self.pipelines.iter() {
|
|
||||||
if let Some(compiled_pipelines_iter) =
|
|
||||||
pipeline_compiler.iter_compiled_pipelines(*pipeline_handle)
|
|
||||||
{
|
|
||||||
for compiled_pipeline_handle in compiled_pipelines_iter {
|
|
||||||
let compiled_pipeline_descriptor =
|
|
||||||
pipelines.get(compiled_pipeline_handle).unwrap();
|
|
||||||
|
|
||||||
let pipeline_layout = compiled_pipeline_descriptor.get_layout().unwrap();
|
|
||||||
{
|
|
||||||
// TODO: this breaks down in a parallel setting. it needs to change. ideally in a way that
|
|
||||||
// doesn't require modifying RenderResourceAssignments
|
|
||||||
for bind_group in pipeline_layout.bind_groups.iter() {
|
|
||||||
render_resource_assignments
|
|
||||||
.update_render_resource_set_id(bind_group);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render_resource_context.create_render_pipeline(
|
|
||||||
*compiled_pipeline_handle,
|
|
||||||
&compiled_pipeline_descriptor,
|
|
||||||
&shaders,
|
|
||||||
);
|
|
||||||
|
|
||||||
render_resource_context.setup_bind_groups(
|
|
||||||
compiled_pipeline_descriptor,
|
|
||||||
&render_resource_assignments,
|
|
||||||
);
|
|
||||||
let assigned_render_resource_assignments = shader_pipeline_assignments
|
|
||||||
.assignments
|
|
||||||
.get(&compiled_pipeline_handle);
|
|
||||||
if let Some(assigned_render_resource_assignments) =
|
|
||||||
assigned_render_resource_assignments
|
|
||||||
{
|
|
||||||
for assignment_id in assigned_render_resource_assignments.iter() {
|
|
||||||
let entity = entity_render_resource_assignments
|
|
||||||
.get(*assignment_id)
|
|
||||||
.unwrap();
|
|
||||||
let renderable =
|
|
||||||
world.get_component::<Renderable>(*entity).unwrap();
|
|
||||||
if !renderable.is_visible || renderable.is_instanced {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
render_resource_context.setup_bind_groups(
|
|
||||||
compiled_pipeline_descriptor,
|
|
||||||
&renderable.render_resource_assignments,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render_context.begin_pass(
|
render_context.begin_pass(
|
||||||
&self.descriptor,
|
&self.descriptor,
|
||||||
&render_resource_assignments,
|
&render_resource_assignments,
|
||||||
&mut |render_pass| {
|
&mut |render_pass| {
|
||||||
for pipeline_handle in self.pipelines.iter() {
|
for (entity, draw) in <Read<Draw>>::query().iter_entities(&world) {
|
||||||
if let Some(compiled_pipelines_iter) =
|
if !draw.is_visible || entities_waiting_for_assets.contains(&entity) {
|
||||||
pipeline_compiler.iter_compiled_pipelines(*pipeline_handle)
|
|
||||||
{
|
|
||||||
for compiled_pipeline_handle in compiled_pipelines_iter {
|
|
||||||
let compiled_pipeline_descriptor =
|
|
||||||
pipelines.get(compiled_pipeline_handle).unwrap();
|
|
||||||
render_pass.set_pipeline(*compiled_pipeline_handle);
|
|
||||||
|
|
||||||
// set global render resources
|
|
||||||
Self::set_render_resources(
|
|
||||||
render_pass,
|
|
||||||
compiled_pipeline_descriptor,
|
|
||||||
&render_resource_assignments,
|
|
||||||
);
|
|
||||||
|
|
||||||
// draw entities assigned to this pipeline
|
|
||||||
let assigned_render_resource_assignments = shader_pipeline_assignments
|
|
||||||
.assignments
|
|
||||||
.get(&compiled_pipeline_handle);
|
|
||||||
|
|
||||||
if let Some(assigned_render_resource_assignments) =
|
|
||||||
assigned_render_resource_assignments
|
|
||||||
{
|
|
||||||
for assignment_id in assigned_render_resource_assignments.iter() {
|
|
||||||
// TODO: hopefully legion has better random access apis that are more like queries?
|
|
||||||
let entity = entity_render_resource_assignments
|
|
||||||
.get(*assignment_id)
|
|
||||||
.unwrap();
|
|
||||||
let renderable =
|
|
||||||
world.get_component::<Renderable>(*entity).unwrap();
|
|
||||||
if !renderable.is_visible
|
|
||||||
|| renderable.is_instanced
|
|
||||||
|| entities_waiting_for_assets.contains(entity)
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set local render resources
|
for render_command in draw.render_commands.iter() {
|
||||||
if let Some(indices) = Self::set_render_resources(
|
match render_command {
|
||||||
render_pass,
|
RenderCommand::SetPipeline { pipeline } => {
|
||||||
compiled_pipeline_descriptor,
|
// TODO: Filter pipelines
|
||||||
&renderable.render_resource_assignments,
|
render_pass.set_pipeline(*pipeline);
|
||||||
) {
|
|
||||||
render_pass.draw_indexed(indices, 0, 0..1);
|
|
||||||
}
|
}
|
||||||
|
RenderCommand::DrawIndexed {
|
||||||
|
base_vertex,
|
||||||
|
indices,
|
||||||
|
instances,
|
||||||
|
} => {
|
||||||
|
render_pass.draw_indexed(
|
||||||
|
indices.clone(),
|
||||||
|
*base_vertex,
|
||||||
|
instances.clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
RenderCommand::SetVertexBuffer {
|
||||||
|
buffer,
|
||||||
|
offset,
|
||||||
|
slot,
|
||||||
|
} => {
|
||||||
|
render_pass.set_vertex_buffer(*slot, *buffer, *offset);
|
||||||
|
}
|
||||||
|
RenderCommand::SetIndexBuffer { buffer, offset } => {
|
||||||
|
render_pass.set_index_buffer(*buffer, *offset);
|
||||||
|
}
|
||||||
|
RenderCommand::SetBindGroup {
|
||||||
|
index,
|
||||||
|
bind_group_descriptor,
|
||||||
|
render_resource_set,
|
||||||
|
dynamic_uniform_indices,
|
||||||
|
} => {
|
||||||
|
render_pass.set_bind_group(
|
||||||
|
*index,
|
||||||
|
*bind_group_descriptor,
|
||||||
|
*render_resource_set,
|
||||||
|
dynamic_uniform_indices
|
||||||
|
.as_ref()
|
||||||
|
.map(|indices| indices.as_slice()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
draw::{Draw, RenderPipelines},
|
||||||
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
|
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
|
||||||
render_resource::{
|
render_resource::{
|
||||||
self, BufferInfo, BufferUsage, EntitiesWaitingForAssets, RenderResourceAssignment,
|
self, BufferInfo, BufferUsage, EntitiesWaitingForAssets, RenderResourceAssignment,
|
||||||
RenderResourceAssignments, RenderResourceAssignmentsId, RenderResourceId, RenderResourceHints,
|
RenderResourceAssignments, RenderResourceAssignmentsId, RenderResourceHints,
|
||||||
|
RenderResourceId,
|
||||||
},
|
},
|
||||||
renderer::{RenderContext, RenderResourceContext, RenderResources},
|
renderer::{RenderContext, RenderResourceContext, RenderResources},
|
||||||
texture, Renderable,
|
texture,
|
||||||
};
|
};
|
||||||
|
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
|
@ -218,7 +220,9 @@ where
|
||||||
// TODO: RE-ADD support for BufferUsage::STORAGE type
|
// TODO: RE-ADD support for BufferUsage::STORAGE type
|
||||||
let mut usage = BufferUsage::UNIFORM;
|
let mut usage = BufferUsage::UNIFORM;
|
||||||
|
|
||||||
if let Some(render_resource_hints) = uniforms.get_render_resource_hints(i) {
|
if let Some(render_resource_hints) =
|
||||||
|
uniforms.get_render_resource_hints(i)
|
||||||
|
{
|
||||||
if render_resource_hints.contains(RenderResourceHints::BUFFER) {
|
if render_resource_hints.contains(RenderResourceHints::BUFFER) {
|
||||||
usage = BufferUsage::STORAGE
|
usage = BufferUsage::STORAGE
|
||||||
}
|
}
|
||||||
|
@ -396,8 +400,8 @@ where
|
||||||
.read_resource::<RenderResources>()
|
.read_resource::<RenderResources>()
|
||||||
.read_resource::<EntitiesWaitingForAssets>()
|
.read_resource::<EntitiesWaitingForAssets>()
|
||||||
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
|
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
|
||||||
.with_query(<(Read<T>, Read<Renderable>)>::query())
|
.with_query(<(Read<T>, Read<Draw>, Read<RenderPipelines>)>::query())
|
||||||
.with_query(<(Read<T>, Write<Renderable>)>::query())
|
.with_query(<(Read<T>, Read<Draw>, Write<RenderPipelines>)>::query())
|
||||||
.build(
|
.build(
|
||||||
move |_,
|
move |_,
|
||||||
world,
|
world,
|
||||||
|
@ -407,61 +411,51 @@ where
|
||||||
|
|
||||||
uniform_buffer_arrays.reset_new_item_counts();
|
uniform_buffer_arrays.reset_new_item_counts();
|
||||||
// update uniforms info
|
// update uniforms info
|
||||||
for (uniforms, renderable) in read_uniform_query.iter(world) {
|
for (uniforms, draw, _render_pipelines) in read_uniform_query.iter(world) {
|
||||||
if !renderable.is_visible {
|
if !draw.is_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if renderable.is_instanced {
|
|
||||||
panic!("instancing not currently supported");
|
|
||||||
} else {
|
|
||||||
uniform_buffer_arrays.increment_uniform_counts(&uniforms);
|
uniform_buffer_arrays.increment_uniform_counts(&uniforms);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
uniform_buffer_arrays
|
uniform_buffer_arrays
|
||||||
.setup_buffer_arrays(render_resource_context, dynamic_uniforms);
|
.setup_buffer_arrays(render_resource_context, dynamic_uniforms);
|
||||||
let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets();
|
let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets();
|
||||||
|
|
||||||
for (entity, (uniforms, mut renderable)) in
|
for (entity, (uniforms, draw, mut render_pipelines)) in
|
||||||
write_uniform_query.iter_entities_mut(world)
|
write_uniform_query.iter_entities_mut(world)
|
||||||
{
|
{
|
||||||
if !renderable.is_visible {
|
if !draw.is_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if renderable.is_instanced {
|
|
||||||
panic!("instancing not currently supported");
|
|
||||||
} else {
|
|
||||||
setup_uniform_texture_resources::<T>(
|
setup_uniform_texture_resources::<T>(
|
||||||
entity,
|
entity,
|
||||||
&uniforms,
|
&uniforms,
|
||||||
render_resource_context,
|
render_resource_context,
|
||||||
entities_waiting_for_assets,
|
entities_waiting_for_assets,
|
||||||
&mut renderable.render_resource_assignments,
|
&mut render_pipelines.render_resource_assignments,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if staging_buffer_size == 0 {
|
if staging_buffer_size == 0 {
|
||||||
let mut staging_buffer: [u8; 0] = [];
|
let mut staging_buffer: [u8; 0] = [];
|
||||||
for (uniforms, mut renderable) in write_uniform_query.iter_mut(world) {
|
for (uniforms, draw, mut render_pipelines) in
|
||||||
if !renderable.is_visible {
|
write_uniform_query.iter_mut(world)
|
||||||
|
{
|
||||||
|
if !draw.is_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if renderable.is_instanced {
|
|
||||||
panic!("instancing not currently supported");
|
|
||||||
} else {
|
|
||||||
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
||||||
&uniforms,
|
&uniforms,
|
||||||
dynamic_uniforms,
|
dynamic_uniforms,
|
||||||
render_resource_context,
|
render_resource_context,
|
||||||
&mut renderable.render_resource_assignments,
|
&mut render_pipelines.render_resource_assignments,
|
||||||
&mut staging_buffer,
|
&mut staging_buffer,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let staging_buffer = render_resource_context.create_buffer_mapped(
|
let staging_buffer = render_resource_context.create_buffer_mapped(
|
||||||
BufferInfo {
|
BufferInfo {
|
||||||
|
@ -470,23 +464,21 @@ where
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
&mut |mut staging_buffer, _render_resources| {
|
&mut |mut staging_buffer, _render_resources| {
|
||||||
for (uniforms, mut renderable) in write_uniform_query.iter_mut(world) {
|
for (uniforms, draw, mut render_pipelines) in
|
||||||
if !renderable.is_visible {
|
write_uniform_query.iter_mut(world)
|
||||||
|
{
|
||||||
|
if !draw.is_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if renderable.is_instanced {
|
|
||||||
panic!("instancing not currently supported");
|
|
||||||
} else {
|
|
||||||
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
||||||
&uniforms,
|
&uniforms,
|
||||||
dynamic_uniforms,
|
dynamic_uniforms,
|
||||||
render_resource_context,
|
render_resource_context,
|
||||||
&mut renderable.render_resource_assignments,
|
&mut render_pipelines.render_resource_assignments,
|
||||||
&mut staging_buffer,
|
&mut staging_buffer,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -552,8 +544,8 @@ where
|
||||||
.read_resource::<RenderResources>()
|
.read_resource::<RenderResources>()
|
||||||
.read_resource::<EntitiesWaitingForAssets>()
|
.read_resource::<EntitiesWaitingForAssets>()
|
||||||
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
|
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
|
||||||
.with_query(<(Read<Handle<T>>, Read<Renderable>)>::query())
|
.with_query(<(Read<Handle<T>>, Read<Draw>, Read<RenderPipelines>)>::query())
|
||||||
.with_query(<(Read<Handle<T>>, Write<Renderable>)>::query())
|
.with_query(<(Read<Handle<T>>, Read<Draw>, Write<RenderPipelines>)>::query())
|
||||||
.build(
|
.build(
|
||||||
move |_,
|
move |_,
|
||||||
world,
|
world,
|
||||||
|
@ -563,14 +555,13 @@ where
|
||||||
uniform_buffer_arrays.reset_new_item_counts();
|
uniform_buffer_arrays.reset_new_item_counts();
|
||||||
|
|
||||||
// update uniform handles info
|
// update uniform handles info
|
||||||
for (entity, (handle, renderable)) in read_handle_query.iter_entities(world) {
|
for (entity, (handle, draw, _render_pipelines)) in
|
||||||
if !renderable.is_visible {
|
read_handle_query.iter_entities(world)
|
||||||
|
{
|
||||||
|
if !draw.is_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if renderable.is_instanced {
|
|
||||||
panic!("instancing not currently supported");
|
|
||||||
} else {
|
|
||||||
if let Some(uniforms) = assets.get(&handle) {
|
if let Some(uniforms) = assets.get(&handle) {
|
||||||
// TODO: only increment count if we haven't seen this uniform handle before
|
// TODO: only increment count if we haven't seen this uniform handle before
|
||||||
uniform_buffer_arrays.increment_uniform_counts(&uniforms);
|
uniform_buffer_arrays.increment_uniform_counts(&uniforms);
|
||||||
|
@ -578,54 +569,47 @@ where
|
||||||
entities_waiting_for_assets.add(entity)
|
entities_waiting_for_assets.add(entity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
uniform_buffer_arrays
|
uniform_buffer_arrays
|
||||||
.setup_buffer_arrays(render_resource_context, dynamic_uniforms);
|
.setup_buffer_arrays(render_resource_context, dynamic_uniforms);
|
||||||
let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets();
|
let staging_buffer_size = uniform_buffer_arrays.update_staging_buffer_offsets();
|
||||||
|
|
||||||
for (entity, (handle, mut renderable)) in
|
for (entity, (handle, draw, mut render_pipelines)) in
|
||||||
write_handle_query.iter_entities_mut(world)
|
write_handle_query.iter_entities_mut(world)
|
||||||
{
|
{
|
||||||
if !renderable.is_visible {
|
if !draw.is_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if renderable.is_instanced {
|
|
||||||
panic!("instancing not currently supported");
|
|
||||||
} else {
|
|
||||||
if let Some(uniforms) = assets.get(&handle) {
|
if let Some(uniforms) = assets.get(&handle) {
|
||||||
setup_uniform_texture_resources::<T>(
|
setup_uniform_texture_resources::<T>(
|
||||||
entity,
|
entity,
|
||||||
&uniforms,
|
&uniforms,
|
||||||
render_resource_context,
|
render_resource_context,
|
||||||
entities_waiting_for_assets,
|
entities_waiting_for_assets,
|
||||||
&mut renderable.render_resource_assignments,
|
&mut render_pipelines.render_resource_assignments,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if staging_buffer_size == 0 {
|
if staging_buffer_size == 0 {
|
||||||
let mut staging_buffer: [u8; 0] = [];
|
let mut staging_buffer: [u8; 0] = [];
|
||||||
for (handle, mut renderable) in write_handle_query.iter_mut(world) {
|
for (handle, draw, mut render_pipelines) in
|
||||||
if !renderable.is_visible {
|
write_handle_query.iter_mut(world)
|
||||||
|
{
|
||||||
|
if !draw.is_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if renderable.is_instanced {
|
|
||||||
panic!("instancing not currently supported");
|
|
||||||
} else {
|
|
||||||
if let Some(uniforms) = assets.get(&handle) {
|
if let Some(uniforms) = assets.get(&handle) {
|
||||||
// TODO: only setup buffer if we haven't seen this handle before
|
// TODO: only setup buffer if we haven't seen this handle before
|
||||||
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
||||||
&uniforms,
|
&uniforms,
|
||||||
dynamic_uniforms,
|
dynamic_uniforms,
|
||||||
render_resource_context,
|
render_resource_context,
|
||||||
&mut renderable.render_resource_assignments,
|
&mut render_pipelines.render_resource_assignments,
|
||||||
&mut staging_buffer,
|
&mut staging_buffer,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let staging_buffer = render_resource_context.create_buffer_mapped(
|
let staging_buffer = render_resource_context.create_buffer_mapped(
|
||||||
BufferInfo {
|
BufferInfo {
|
||||||
|
@ -634,25 +618,23 @@ where
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
&mut |mut staging_buffer, _render_resources| {
|
&mut |mut staging_buffer, _render_resources| {
|
||||||
for (handle, mut renderable) in write_handle_query.iter_mut(world) {
|
for (handle, draw, mut render_pipelines) in
|
||||||
if !renderable.is_visible {
|
write_handle_query.iter_mut(world)
|
||||||
|
{
|
||||||
|
if !draw.is_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if renderable.is_instanced {
|
|
||||||
panic!("instancing not currently supported");
|
|
||||||
} else {
|
|
||||||
if let Some(uniforms) = assets.get(&handle) {
|
if let Some(uniforms) = assets.get(&handle) {
|
||||||
// TODO: only setup buffer if we haven't seen this handle before
|
// TODO: only setup buffer if we haven't seen this handle before
|
||||||
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
uniform_buffer_arrays.setup_uniform_buffer_resources(
|
||||||
&uniforms,
|
&uniforms,
|
||||||
dynamic_uniforms,
|
dynamic_uniforms,
|
||||||
render_resource_context,
|
render_resource_context,
|
||||||
&mut renderable.render_resource_assignments,
|
&mut render_pipelines.render_resource_assignments,
|
||||||
&mut staging_buffer,
|
&mut staging_buffer,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -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 buffer;
|
||||||
mod entities_waiting_for_assets;
|
mod entities_waiting_for_assets;
|
||||||
mod entity_render_resource_assignments;
|
|
||||||
mod render_resource;
|
mod render_resource;
|
||||||
mod render_resource_assignments;
|
mod render_resource_assignments;
|
||||||
mod resource_info;
|
mod resource_info;
|
||||||
|
mod systems;
|
||||||
|
|
||||||
pub use buffer::*;
|
pub use buffer::*;
|
||||||
pub use entities_waiting_for_assets::*;
|
pub use entities_waiting_for_assets::*;
|
||||||
pub use entity_render_resource_assignments::*;
|
|
||||||
pub use render_resource::*;
|
pub use render_resource::*;
|
||||||
pub use render_resource_assignments::*;
|
pub use render_resource_assignments::*;
|
||||||
pub use resource_info::*;
|
pub use resource_info::*;
|
||||||
|
pub use systems::*;
|
|
@ -4,6 +4,7 @@ use std::{
|
||||||
collections::{hash_map::DefaultHasher, HashMap, HashSet},
|
collections::{hash_map::DefaultHasher, HashMap, HashSet},
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
ops::Range,
|
ops::Range,
|
||||||
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -28,10 +29,25 @@ impl RenderResourceAssignment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Debug)]
|
||||||
|
pub struct IndexedRenderResourceAssignment {
|
||||||
|
pub index: u32,
|
||||||
|
pub assignment: RenderResourceAssignment,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: consider renaming this to BindGroup for parity with renderer terminology
|
||||||
#[derive(Eq, PartialEq, Debug)]
|
#[derive(Eq, PartialEq, Debug)]
|
||||||
pub struct RenderResourceSet {
|
pub struct RenderResourceSet {
|
||||||
pub id: RenderResourceSetId,
|
pub id: RenderResourceSetId,
|
||||||
pub dynamic_uniform_indices: Option<Vec<u32>>,
|
pub indexed_assignments: Vec<IndexedRenderResourceAssignment>,
|
||||||
|
pub dynamic_uniform_indices: Option<Arc<Vec<u32>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Debug)]
|
||||||
|
pub enum RenderResourceSetStatus {
|
||||||
|
Changed(RenderResourceSetId),
|
||||||
|
Unchanged(RenderResourceSetId),
|
||||||
|
NoMatch,
|
||||||
}
|
}
|
||||||
|
|
||||||
// PERF: if the assignments are scoped to a specific pipeline layout, then names could be replaced with indices here for a perf boost
|
// PERF: if the assignments are scoped to a specific pipeline layout, then names could be replaced with indices here for a perf boost
|
||||||
|
@ -40,8 +56,9 @@ pub struct RenderResourceAssignments {
|
||||||
pub id: RenderResourceAssignmentsId,
|
pub id: RenderResourceAssignmentsId,
|
||||||
render_resources: HashMap<String, RenderResourceAssignment>,
|
render_resources: HashMap<String, RenderResourceAssignment>,
|
||||||
vertex_buffers: HashMap<String, (RenderResourceId, Option<RenderResourceId>)>,
|
vertex_buffers: HashMap<String, (RenderResourceId, Option<RenderResourceId>)>,
|
||||||
bind_group_resource_sets: HashMap<BindGroupDescriptorId, RenderResourceSet>,
|
render_resource_sets: HashMap<RenderResourceSetId, RenderResourceSet>,
|
||||||
dirty_bind_groups: HashSet<BindGroupDescriptorId>,
|
bind_group_render_resource_sets: HashMap<BindGroupDescriptorId, RenderResourceSetId>,
|
||||||
|
dirty_render_resource_sets: HashSet<RenderResourceSetId>,
|
||||||
pub pipeline_specialization: PipelineSpecialization,
|
pub pipeline_specialization: PipelineSpecialization,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,9 +75,8 @@ impl RenderResourceAssignments {
|
||||||
fn try_set_dirty(&mut self, name: &str, assignment: &RenderResourceAssignment) {
|
fn try_set_dirty(&mut self, name: &str, assignment: &RenderResourceAssignment) {
|
||||||
if let Some(current_assignment) = self.render_resources.get(name) {
|
if let Some(current_assignment) = self.render_resources.get(name) {
|
||||||
if current_assignment != assignment {
|
if current_assignment != assignment {
|
||||||
// TODO: this is pretty crude. can we do better?
|
for id in self.render_resource_sets.keys() {
|
||||||
for bind_group_id in self.bind_group_resource_sets.keys() {
|
self.dirty_render_resource_sets.insert(*id);
|
||||||
self.dirty_bind_groups.insert(*bind_group_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,36 +99,54 @@ impl RenderResourceAssignments {
|
||||||
.insert(name.to_string(), (vertices_resource, indices_resource));
|
.insert(name.to_string(), (vertices_resource, indices_resource));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_render_resource_set_id(
|
fn create_render_resource_set(
|
||||||
&mut self,
|
&mut self,
|
||||||
bind_group_descriptor: &BindGroupDescriptor,
|
bind_group_descriptor: &BindGroupDescriptor,
|
||||||
) -> Option<RenderResourceSetId> {
|
) -> RenderResourceSetStatus {
|
||||||
if !self
|
|
||||||
.bind_group_resource_sets
|
|
||||||
.contains_key(&bind_group_descriptor.id)
|
|
||||||
|| self.dirty_bind_groups.contains(&bind_group_descriptor.id)
|
|
||||||
{
|
|
||||||
let resource_set = self.generate_render_resource_set(bind_group_descriptor);
|
let resource_set = self.generate_render_resource_set(bind_group_descriptor);
|
||||||
if let Some(resource_set) = resource_set {
|
if let Some(resource_set) = resource_set {
|
||||||
let id = resource_set.id;
|
let id = resource_set.id;
|
||||||
self.bind_group_resource_sets
|
self.render_resource_sets.insert(id, resource_set);
|
||||||
.insert(bind_group_descriptor.id, resource_set);
|
self.bind_group_render_resource_sets
|
||||||
Some(id)
|
.insert(bind_group_descriptor.id, id);
|
||||||
|
RenderResourceSetStatus::Changed(id)
|
||||||
} else {
|
} else {
|
||||||
None
|
RenderResourceSetStatus::NoMatch
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.bind_group_resource_sets
|
|
||||||
.get(&bind_group_descriptor.id)
|
|
||||||
.map(|set| set.id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_render_resource_set(
|
pub fn update_bind_group(
|
||||||
|
&mut self,
|
||||||
|
bind_group_descriptor: &BindGroupDescriptor,
|
||||||
|
) -> RenderResourceSetStatus {
|
||||||
|
if let Some(id) = self
|
||||||
|
.bind_group_render_resource_sets
|
||||||
|
.get(&bind_group_descriptor.id)
|
||||||
|
{
|
||||||
|
if self.dirty_render_resource_sets.contains(id) {
|
||||||
|
self.dirty_render_resource_sets.remove(id);
|
||||||
|
self.create_render_resource_set(bind_group_descriptor)
|
||||||
|
} else {
|
||||||
|
RenderResourceSetStatus::Unchanged(*id)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.create_render_resource_set(bind_group_descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_render_resource_set(&self, id: RenderResourceSetId) -> Option<&RenderResourceSet> {
|
||||||
|
self.render_resource_sets.get(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_bind_group_render_resource_set(
|
||||||
&self,
|
&self,
|
||||||
bind_group_descriptor_id: BindGroupDescriptorId,
|
id: BindGroupDescriptorId,
|
||||||
) -> Option<&RenderResourceSet> {
|
) -> Option<&RenderResourceSet> {
|
||||||
self.bind_group_resource_sets.get(&bind_group_descriptor_id)
|
self.bind_group_render_resource_sets
|
||||||
|
.get(&id)
|
||||||
|
.and_then(|render_resource_set_id| {
|
||||||
|
self.get_render_resource_set(*render_resource_set_id)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_render_resource_set(
|
fn generate_render_resource_set(
|
||||||
|
@ -121,8 +155,13 @@ impl RenderResourceAssignments {
|
||||||
) -> Option<RenderResourceSet> {
|
) -> Option<RenderResourceSet> {
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
let mut indices = Vec::new();
|
let mut indices = Vec::new();
|
||||||
|
let mut indexed_assignments = Vec::new();
|
||||||
for binding_descriptor in bind_group_descriptor.bindings.iter() {
|
for binding_descriptor in bind_group_descriptor.bindings.iter() {
|
||||||
if let Some(assignment) = self.get(&binding_descriptor.name) {
|
if let Some(assignment) = self.get(&binding_descriptor.name) {
|
||||||
|
indexed_assignments.push(IndexedRenderResourceAssignment {
|
||||||
|
assignment: assignment.clone(),
|
||||||
|
index: binding_descriptor.index,
|
||||||
|
});
|
||||||
let resource = assignment.get_resource();
|
let resource = assignment.get_resource();
|
||||||
resource.hash(&mut hasher);
|
resource.hash(&mut hasher);
|
||||||
if let RenderResourceAssignment::Buffer {
|
if let RenderResourceAssignment::Buffer {
|
||||||
|
@ -139,10 +178,11 @@ impl RenderResourceAssignments {
|
||||||
|
|
||||||
Some(RenderResourceSet {
|
Some(RenderResourceSet {
|
||||||
id: RenderResourceSetId(hasher.finish()),
|
id: RenderResourceSetId(hasher.finish()),
|
||||||
|
indexed_assignments,
|
||||||
dynamic_uniform_indices: if indices.is_empty() {
|
dynamic_uniform_indices: if indices.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(indices)
|
Some(Arc::new(indices))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -215,22 +255,34 @@ mod tests {
|
||||||
equal_assignments.set("a", resource1.clone());
|
equal_assignments.set("a", resource1.clone());
|
||||||
equal_assignments.set("b", resource2.clone());
|
equal_assignments.set("b", resource2.clone());
|
||||||
|
|
||||||
let set_id = assignments.update_render_resource_set_id(&bind_group_descriptor);
|
let status = assignments.update_bind_group(&bind_group_descriptor);
|
||||||
assert_ne!(set_id, None);
|
let id = if let RenderResourceSetStatus::Changed(id) = status {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
panic!("expected a changed render resource set");
|
||||||
|
};
|
||||||
|
|
||||||
let different_set_id =
|
let different_set_status = different_assignments.update_bind_group(&bind_group_descriptor);
|
||||||
different_assignments.update_render_resource_set_id(&bind_group_descriptor);
|
if let RenderResourceSetStatus::Changed(different_set_id) = different_set_status {
|
||||||
assert_ne!(different_set_id, None);
|
assert_ne!(
|
||||||
assert_ne!(different_set_id, set_id);
|
id, different_set_id,
|
||||||
|
"different set shouldn't have the same id"
|
||||||
|
);
|
||||||
|
different_set_id
|
||||||
|
} else {
|
||||||
|
panic!("expected a changed render resource set");
|
||||||
|
};
|
||||||
|
|
||||||
let equal_set_id = equal_assignments.update_render_resource_set_id(&bind_group_descriptor);
|
let equal_set_status = equal_assignments.update_bind_group(&bind_group_descriptor);
|
||||||
assert_ne!(equal_set_id, None);
|
if let RenderResourceSetStatus::Changed(equal_set_id) = equal_set_status {
|
||||||
assert_eq!(equal_set_id, set_id);
|
assert_eq!(id, equal_set_id, "equal set should have the same id");
|
||||||
|
} else {
|
||||||
|
panic!("expected a changed render resource set");
|
||||||
|
};
|
||||||
|
|
||||||
let mut unmatched_assignments = RenderResourceAssignments::default();
|
let mut unmatched_assignments = RenderResourceAssignments::default();
|
||||||
unmatched_assignments.set("a", resource1.clone());
|
unmatched_assignments.set("a", resource1.clone());
|
||||||
let unmatched_set_id =
|
let unmatched_set_status = unmatched_assignments.update_bind_group(&bind_group_descriptor);
|
||||||
unmatched_assignments.update_render_resource_set_id(&bind_group_descriptor);
|
assert_eq!(unmatched_set_status, RenderResourceSetStatus::NoMatch);
|
||||||
assert_eq!(unmatched_set_id, None);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
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 super::RenderResourceContext;
|
||||||
use crate::{
|
use crate::{
|
||||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
pipeline::{BindGroupDescriptorId, PipelineDescriptor},
|
||||||
render_resource::{
|
render_resource::{BufferInfo, RenderResourceId, RenderResourceSet, ResourceInfo},
|
||||||
BufferInfo, RenderResourceId, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
|
|
||||||
},
|
|
||||||
shader::Shader,
|
shader::Shader,
|
||||||
texture::{SamplerDescriptor, TextureDescriptor},
|
texture::{SamplerDescriptor, TextureDescriptor},
|
||||||
};
|
};
|
||||||
|
@ -113,16 +111,9 @@ impl RenderResourceContext for HeadlessRenderResourceContext {
|
||||||
}
|
}
|
||||||
fn create_bind_group(
|
fn create_bind_group(
|
||||||
&self,
|
&self,
|
||||||
bind_group_descriptor: &BindGroupDescriptor,
|
_bind_group_descriptor_id: BindGroupDescriptorId,
|
||||||
render_resource_assignments: &RenderResourceAssignments,
|
_render_resource_set: &RenderResourceSet,
|
||||||
) -> Option<RenderResourceSetId> {
|
) {
|
||||||
if let Some(resource_set) =
|
|
||||||
render_resource_assignments.get_render_resource_set(bind_group_descriptor.id)
|
|
||||||
{
|
|
||||||
Some(resource_set.id)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fn create_shader_module_from_source(&self, _shader_handle: Handle<Shader>, _shader: &Shader) {}
|
fn create_shader_module_from_source(&self, _shader_handle: Handle<Shader>, _shader: &Shader) {}
|
||||||
fn remove_asset_resource_untyped(&self, handle: HandleUntyped, index: usize) {
|
fn remove_asset_resource_untyped(&self, handle: HandleUntyped, index: usize) {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
pipeline::{BindGroupDescriptorId, PipelineDescriptor},
|
||||||
render_resource::{
|
render_resource::{BufferInfo, RenderResourceId, RenderResourceSet, ResourceInfo},
|
||||||
BufferInfo, RenderResourceId, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
|
|
||||||
},
|
|
||||||
shader::Shader,
|
shader::Shader,
|
||||||
texture::{SamplerDescriptor, TextureDescriptor},
|
texture::{SamplerDescriptor, TextureDescriptor},
|
||||||
};
|
};
|
||||||
|
@ -70,29 +68,15 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
|
||||||
);
|
);
|
||||||
fn create_bind_group(
|
fn create_bind_group(
|
||||||
&self,
|
&self,
|
||||||
bind_group_descriptor: &BindGroupDescriptor,
|
bind_group_descriptor_id: BindGroupDescriptorId,
|
||||||
render_resource_assignments: &RenderResourceAssignments,
|
render_resource_set: &RenderResourceSet,
|
||||||
) -> Option<RenderResourceSetId>;
|
);
|
||||||
fn setup_bind_groups(
|
|
||||||
&self,
|
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
|
||||||
render_resource_assignments: &RenderResourceAssignments,
|
|
||||||
) {
|
|
||||||
let pipeline_layout = pipeline_descriptor.get_layout().unwrap();
|
|
||||||
for bind_group in pipeline_layout.bind_groups.iter() {
|
|
||||||
self.create_bind_group(bind_group, render_resource_assignments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn clear_bind_groups(&self);
|
fn clear_bind_groups(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl dyn RenderResourceContext {
|
impl dyn RenderResourceContext {
|
||||||
pub fn set_asset_resource<T>(
|
pub fn set_asset_resource<T>(&self, handle: Handle<T>, resource: RenderResourceId, index: usize)
|
||||||
&self,
|
where
|
||||||
handle: Handle<T>,
|
|
||||||
resource: RenderResourceId,
|
|
||||||
index: usize,
|
|
||||||
) where
|
|
||||||
T: 'static,
|
T: 'static,
|
||||||
{
|
{
|
||||||
self.set_asset_resource_untyped(handle.into(), resource, index);
|
self.set_asset_resource_untyped(handle.into(), resource, index);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
use crate::{texture::Texture, RenderPipelines};
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use crate::{Renderable, texture::Texture};
|
use legion::prelude::{Com, ComMut, Res};
|
||||||
use legion::prelude::{Res, Com, ComMut};
|
|
||||||
|
|
||||||
pub use bevy_derive::ShaderDefs;
|
pub use bevy_derive::ShaderDefs;
|
||||||
|
|
||||||
|
@ -15,7 +14,6 @@ pub trait ShaderDefs {
|
||||||
fn iter_shader_defs(&self) -> ShaderDefIterator;
|
fn iter_shader_defs(&self) -> ShaderDefIterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct ShaderDefIterator<'a> {
|
pub struct ShaderDefIterator<'a> {
|
||||||
shader_defs: &'a dyn ShaderDefs,
|
shader_defs: &'a dyn ShaderDefs,
|
||||||
index: usize,
|
index: usize,
|
||||||
|
@ -36,9 +34,7 @@ impl<'a> Iterator for ShaderDefIterator<'a> {
|
||||||
if self.index == self.shader_defs.shader_defs_len() {
|
if self.index == self.shader_defs.shader_defs_len() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let shader_def = self
|
let shader_def = self.shader_defs.get_shader_def(self.index);
|
||||||
.shader_defs
|
|
||||||
.get_shader_def(self.index);
|
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
if shader_def.is_some() {
|
if shader_def.is_some() {
|
||||||
return shader_def;
|
return shader_def;
|
||||||
|
@ -59,12 +55,12 @@ impl ShaderDef for Option<Handle<Texture>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shader_def_system<T>(shader_defs: Com<T>, mut renderable: ComMut<Renderable>)
|
pub fn shader_def_system<T>(shader_defs: Com<T>, mut render_pipelines: ComMut<RenderPipelines>)
|
||||||
where
|
where
|
||||||
T: ShaderDefs + Send + Sync + 'static,
|
T: ShaderDefs + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
for shader_def in shader_defs.iter_shader_defs() {
|
for shader_def in shader_defs.iter_shader_defs() {
|
||||||
renderable
|
render_pipelines
|
||||||
.render_resource_assignments
|
.render_resource_assignments
|
||||||
.pipeline_specialization
|
.pipeline_specialization
|
||||||
.shader_specialization
|
.shader_specialization
|
||||||
|
@ -76,13 +72,13 @@ where
|
||||||
pub fn asset_shader_def_system<T>(
|
pub fn asset_shader_def_system<T>(
|
||||||
assets: Res<Assets<T>>,
|
assets: Res<Assets<T>>,
|
||||||
asset_handle: Com<Handle<T>>,
|
asset_handle: Com<Handle<T>>,
|
||||||
mut renderable: ComMut<Renderable>,
|
mut render_pipelines: ComMut<RenderPipelines>,
|
||||||
) where
|
) where
|
||||||
T: ShaderDefs + Send + Sync + 'static,
|
T: ShaderDefs + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let shader_defs = assets.get(&asset_handle).unwrap();
|
let shader_defs = assets.get(&asset_handle).unwrap();
|
||||||
for shader_def in shader_defs.iter_shader_defs() {
|
for shader_def in shader_defs.iter_shader_defs() {
|
||||||
renderable
|
render_pipelines
|
||||||
.render_resource_assignments
|
.render_resource_assignments
|
||||||
.pipeline_specialization
|
.pipeline_specialization
|
||||||
.shader_specialization
|
.shader_specialization
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
use bevy_app::EntityArchetype;
|
use bevy_app::EntityArchetype;
|
||||||
use bevy_render::{mesh::Mesh, Renderable};
|
use bevy_render::{mesh::Mesh, draw::{Draw, RenderPipelines}};
|
||||||
|
|
||||||
#[derive(EntityArchetype)]
|
#[derive(EntityArchetype)]
|
||||||
pub struct SpriteEntity {
|
pub struct SpriteEntity {
|
||||||
|
@ -12,7 +12,8 @@ pub struct SpriteEntity {
|
||||||
pub quad: Quad,
|
pub quad: Quad,
|
||||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||||
pub material: Handle<ColorMaterial>,
|
pub material: Handle<ColorMaterial>,
|
||||||
pub renderable: Renderable,
|
pub draw: Draw,
|
||||||
|
pub render_pipelines: RenderPipelines,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SpriteEntity {
|
impl Default for SpriteEntity {
|
||||||
|
@ -22,7 +23,8 @@ impl Default for SpriteEntity {
|
||||||
quad: Default::default(),
|
quad: Default::default(),
|
||||||
mesh: QUAD_HANDLE,
|
mesh: QUAD_HANDLE,
|
||||||
material: Default::default(),
|
material: Default::default(),
|
||||||
renderable: Renderable {
|
draw: Default::default(),
|
||||||
|
render_pipelines: RenderPipelines {
|
||||||
pipelines: vec![SPRITE_PIPELINE_HANDLE],
|
pipelines: vec![SPRITE_PIPELINE_HANDLE],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -34,7 +36,8 @@ impl Default for SpriteEntity {
|
||||||
pub struct SpriteSheetEntity {
|
pub struct SpriteSheetEntity {
|
||||||
pub sprite: TextureAtlasSprite,
|
pub sprite: TextureAtlasSprite,
|
||||||
pub texture_atlas: Handle<TextureAtlas>,
|
pub texture_atlas: Handle<TextureAtlas>,
|
||||||
pub renderable: Renderable,
|
pub draw: Draw,
|
||||||
|
pub render_pipelines: RenderPipelines,
|
||||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||||
// pub transform: Transform,
|
// pub transform: Transform,
|
||||||
// pub translation: Translation,
|
// pub translation: Translation,
|
||||||
|
@ -47,7 +50,8 @@ impl Default for SpriteSheetEntity {
|
||||||
Self {
|
Self {
|
||||||
sprite: Default::default(),
|
sprite: Default::default(),
|
||||||
texture_atlas: Default::default(),
|
texture_atlas: Default::default(),
|
||||||
renderable: Renderable {
|
draw: Default::default(),
|
||||||
|
render_pipelines: RenderPipelines {
|
||||||
pipelines: vec![SPRITE_SHEET_PIPELINE_HANDLE],
|
pipelines: vec![SPRITE_SHEET_PIPELINE_HANDLE],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,7 +4,7 @@ use bevy_render::{
|
||||||
base_render_graph,
|
base_render_graph,
|
||||||
pipeline::{state_descriptors::*, PipelineDescriptor},
|
pipeline::{state_descriptors::*, PipelineDescriptor},
|
||||||
render_graph::{
|
render_graph::{
|
||||||
nodes::{AssetUniformNode, PassNode, UniformNode},
|
nodes::{AssetUniformNode, UniformNode},
|
||||||
RenderGraph,
|
RenderGraph,
|
||||||
},
|
},
|
||||||
shader::{Shader, ShaderStage, ShaderStages},
|
shader::{Shader, ShaderStage, ShaderStages},
|
||||||
|
@ -149,11 +149,6 @@ impl SpriteRenderGraphBuilder for RenderGraph {
|
||||||
SPRITE_SHEET_PIPELINE_HANDLE,
|
SPRITE_SHEET_PIPELINE_HANDLE,
|
||||||
build_sprite_sheet_pipeline(&mut shaders),
|
build_sprite_sheet_pipeline(&mut shaders),
|
||||||
);
|
);
|
||||||
let main_pass: &mut PassNode = self
|
|
||||||
.get_node_mut(base_render_graph::node::MAIN_PASS)
|
|
||||||
.unwrap();
|
|
||||||
main_pass.add_pipeline(SPRITE_PIPELINE_HANDLE);
|
|
||||||
main_pass.add_pipeline(SPRITE_SHEET_PIPELINE_HANDLE);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use super::Node;
|
||||||
use crate::{render::UI_PIPELINE_HANDLE, widget::Label};
|
use crate::{render::UI_PIPELINE_HANDLE, widget::Label};
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
use bevy_derive::EntityArchetype;
|
use bevy_derive::EntityArchetype;
|
||||||
use bevy_render::{mesh::Mesh, Renderable};
|
use bevy_render::{draw::{Draw, RenderPipelines}, mesh::Mesh};
|
||||||
use bevy_sprite::{ColorMaterial, Quad, QUAD_HANDLE};
|
use bevy_sprite::{ColorMaterial, Quad, QUAD_HANDLE};
|
||||||
|
|
||||||
#[derive(EntityArchetype)]
|
#[derive(EntityArchetype)]
|
||||||
|
@ -11,7 +11,8 @@ pub struct UiEntity {
|
||||||
pub quad: Quad,
|
pub quad: Quad,
|
||||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||||
pub material: Handle<ColorMaterial>,
|
pub material: Handle<ColorMaterial>,
|
||||||
pub renderable: Renderable,
|
pub draw: Draw,
|
||||||
|
pub render_pipelines: RenderPipelines,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for UiEntity {
|
impl Default for UiEntity {
|
||||||
|
@ -21,7 +22,8 @@ impl Default for UiEntity {
|
||||||
quad: Default::default(),
|
quad: Default::default(),
|
||||||
mesh: QUAD_HANDLE,
|
mesh: QUAD_HANDLE,
|
||||||
material: Default::default(),
|
material: Default::default(),
|
||||||
renderable: Renderable {
|
draw: Default::default(),
|
||||||
|
render_pipelines: RenderPipelines {
|
||||||
pipelines: vec![UI_PIPELINE_HANDLE],
|
pipelines: vec![UI_PIPELINE_HANDLE],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -35,7 +37,8 @@ pub struct LabelEntity {
|
||||||
pub quad: Quad,
|
pub quad: Quad,
|
||||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||||
pub material: Handle<ColorMaterial>,
|
pub material: Handle<ColorMaterial>,
|
||||||
pub renderable: Renderable,
|
pub draw: Draw,
|
||||||
|
pub render_pipelines: RenderPipelines,
|
||||||
pub label: Label,
|
pub label: Label,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +50,8 @@ impl Default for LabelEntity {
|
||||||
mesh: QUAD_HANDLE,
|
mesh: QUAD_HANDLE,
|
||||||
// NOTE: labels each get their own material.
|
// NOTE: labels each get their own material.
|
||||||
material: Handle::new(), // TODO: maybe abstract this out
|
material: Handle::new(), // TODO: maybe abstract this out
|
||||||
renderable: Renderable {
|
draw: Default::default(),
|
||||||
|
render_pipelines: RenderPipelines {
|
||||||
pipelines: vec![UI_PIPELINE_HANDLE],
|
pipelines: vec![UI_PIPELINE_HANDLE],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,10 +2,7 @@ use bevy_asset::{Assets, Handle};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
base_render_graph,
|
base_render_graph,
|
||||||
pipeline::{state_descriptors::*, PipelineDescriptor},
|
pipeline::{state_descriptors::*, PipelineDescriptor},
|
||||||
render_graph::{
|
render_graph::{nodes::CameraNode, RenderGraph},
|
||||||
nodes::{CameraNode, PassNode},
|
|
||||||
RenderGraph,
|
|
||||||
},
|
|
||||||
shader::{Shader, ShaderStage, ShaderStages},
|
shader::{Shader, ShaderStage, ShaderStages},
|
||||||
texture::TextureFormat,
|
texture::TextureFormat,
|
||||||
};
|
};
|
||||||
|
@ -79,10 +76,6 @@ impl UiRenderGraphBuilder for RenderGraph {
|
||||||
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
|
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
|
||||||
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
|
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
|
||||||
pipelines.set(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders));
|
pipelines.set(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders));
|
||||||
let main_pass: &mut PassNode = self
|
|
||||||
.get_node_mut(base_render_graph::node::MAIN_PASS)
|
|
||||||
.unwrap();
|
|
||||||
main_pass.add_pipeline(UI_PIPELINE_HANDLE);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,8 @@ pub use wgpu_render_pass::*;
|
||||||
pub use wgpu_renderer::*;
|
pub use wgpu_renderer::*;
|
||||||
pub use wgpu_resources::*;
|
pub use wgpu_resources::*;
|
||||||
|
|
||||||
use bevy_app::{AppBuilder, AppPlugin, Events};
|
use bevy_app::{AppBuilder, AppPlugin};
|
||||||
use bevy_render::renderer::RenderResources;
|
use bevy_render::renderer::RenderResources;
|
||||||
use bevy_window::{WindowCreated, WindowResized};
|
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
use renderer::WgpuRenderResourceContext;
|
use renderer::WgpuRenderResourceContext;
|
||||||
|
|
||||||
|
@ -26,14 +25,7 @@ impl AppPlugin for WgpuPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wgpu_render_system(resources: &mut Resources) -> impl FnMut(&mut World, &mut Resources) {
|
pub fn wgpu_render_system(resources: &mut Resources) -> impl FnMut(&mut World, &mut Resources) {
|
||||||
let mut wgpu_renderer = {
|
let mut wgpu_renderer = pollster::block_on(WgpuRenderer::new());
|
||||||
let window_resized_event = resources.get::<Events<WindowResized>>().unwrap();
|
|
||||||
let window_created_event = resources.get::<Events<WindowCreated>>().unwrap();
|
|
||||||
pollster::block_on(WgpuRenderer::new(
|
|
||||||
window_resized_event.get_reader(),
|
|
||||||
window_created_event.get_reader(),
|
|
||||||
))
|
|
||||||
};
|
|
||||||
resources.insert(RenderResources::new(WgpuRenderResourceContext::new(
|
resources.insert(RenderResources::new(WgpuRenderResourceContext::new(
|
||||||
wgpu_renderer.device.clone(),
|
wgpu_renderer.device.clone(),
|
||||||
)));
|
)));
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
mod systems;
|
|
||||||
mod wgpu_render_context;
|
mod wgpu_render_context;
|
||||||
mod wgpu_render_graph_executor;
|
mod wgpu_render_graph_executor;
|
||||||
mod wgpu_render_resource_context;
|
mod wgpu_render_resource_context;
|
||||||
|
|
||||||
pub use systems::*;
|
|
||||||
pub use wgpu_render_context::*;
|
pub use wgpu_render_context::*;
|
||||||
pub use wgpu_render_graph_executor::*;
|
pub use wgpu_render_graph_executor::*;
|
||||||
pub use wgpu_render_resource_context::*;
|
pub use wgpu_render_resource_context::*;
|
||||||
|
|
|
@ -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_asset::{Assets, Handle, HandleUntyped};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineDescriptor},
|
||||||
render_resource::{
|
render_resource::{
|
||||||
BufferInfo, RenderResourceId, RenderResourceAssignment, RenderResourceAssignments,
|
BufferInfo, RenderResourceAssignment, RenderResourceId, RenderResourceSet, ResourceInfo,
|
||||||
RenderResourceSetId, ResourceInfo,
|
|
||||||
},
|
},
|
||||||
renderer::RenderResourceContext,
|
renderer::RenderResourceContext,
|
||||||
shader::Shader,
|
shader::Shader,
|
||||||
|
@ -207,7 +206,11 @@ impl RenderResourceContext for WgpuRenderResourceContext {
|
||||||
resource
|
resource
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_buffer_with_data(&self, mut buffer_info: BufferInfo, data: &[u8]) -> RenderResourceId {
|
fn create_buffer_with_data(
|
||||||
|
&self,
|
||||||
|
mut buffer_info: BufferInfo,
|
||||||
|
data: &[u8],
|
||||||
|
) -> RenderResourceId {
|
||||||
// TODO: consider moving this below "create" for efficiency
|
// TODO: consider moving this below "create" for efficiency
|
||||||
let mut resource_info = self.resources.resource_info.write().unwrap();
|
let mut resource_info = self.resources.resource_info.write().unwrap();
|
||||||
let mut buffers = self.resources.buffers.write().unwrap();
|
let mut buffers = self.resources.buffers.write().unwrap();
|
||||||
|
@ -450,15 +453,12 @@ impl RenderResourceContext for WgpuRenderResourceContext {
|
||||||
|
|
||||||
fn create_bind_group(
|
fn create_bind_group(
|
||||||
&self,
|
&self,
|
||||||
bind_group_descriptor: &BindGroupDescriptor,
|
bind_group_descriptor_id: BindGroupDescriptorId,
|
||||||
render_resource_assignments: &RenderResourceAssignments,
|
render_resource_set: &RenderResourceSet,
|
||||||
) -> Option<RenderResourceSetId> {
|
) {
|
||||||
if let Some(render_resource_set) =
|
|
||||||
render_resource_assignments.get_render_resource_set(bind_group_descriptor.id)
|
|
||||||
{
|
|
||||||
if !self
|
if !self
|
||||||
.resources
|
.resources
|
||||||
.has_bind_group(bind_group_descriptor.id, render_resource_set.id)
|
.has_bind_group(bind_group_descriptor_id, render_resource_set.id)
|
||||||
{
|
{
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"start creating bind group for RenderResourceSet {:?}",
|
"start creating bind group for RenderResourceSet {:?}",
|
||||||
|
@ -470,18 +470,11 @@ impl RenderResourceContext for WgpuRenderResourceContext {
|
||||||
let bind_group_layouts = self.resources.bind_group_layouts.read().unwrap();
|
let bind_group_layouts = self.resources.bind_group_layouts.read().unwrap();
|
||||||
let mut bind_groups = self.resources.bind_groups.write().unwrap();
|
let mut bind_groups = self.resources.bind_groups.write().unwrap();
|
||||||
|
|
||||||
let bindings = bind_group_descriptor
|
let bindings = render_resource_set
|
||||||
.bindings
|
.indexed_assignments
|
||||||
.iter()
|
.iter()
|
||||||
.map(|binding| {
|
.map(|indexed_assignment| {
|
||||||
if let Some(assignment) = render_resource_assignments.get(&binding.name) {
|
let wgpu_resource = match &indexed_assignment.assignment {
|
||||||
log::trace!(
|
|
||||||
"found binding {} ({}) assignment: {:?}",
|
|
||||||
binding.index,
|
|
||||||
binding.name,
|
|
||||||
assignment,
|
|
||||||
);
|
|
||||||
let wgpu_resource = match assignment {
|
|
||||||
RenderResourceAssignment::Texture(resource) => {
|
RenderResourceAssignment::Texture(resource) => {
|
||||||
let texture = texture_views.get(&resource).unwrap();
|
let texture = texture_views.get(&resource).unwrap();
|
||||||
wgpu::BindingResource::TextureView(texture)
|
wgpu::BindingResource::TextureView(texture)
|
||||||
|
@ -490,26 +483,21 @@ impl RenderResourceContext for WgpuRenderResourceContext {
|
||||||
let sampler = samplers.get(&resource).unwrap();
|
let sampler = samplers.get(&resource).unwrap();
|
||||||
wgpu::BindingResource::Sampler(sampler)
|
wgpu::BindingResource::Sampler(sampler)
|
||||||
}
|
}
|
||||||
RenderResourceAssignment::Buffer { resource, range , .. } => {
|
RenderResourceAssignment::Buffer {
|
||||||
|
resource, range, ..
|
||||||
|
} => {
|
||||||
let buffer = buffers.get(&resource).unwrap();
|
let buffer = buffers.get(&resource).unwrap();
|
||||||
wgpu::BindingResource::Buffer(buffer.slice(range.clone()))
|
wgpu::BindingResource::Buffer(buffer.slice(range.clone()))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
wgpu::Binding {
|
wgpu::Binding {
|
||||||
binding: binding.index,
|
binding: indexed_assignment.index,
|
||||||
resource: wgpu_resource,
|
resource: wgpu_resource,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
panic!(
|
|
||||||
"No resource assigned to uniform \"{}\" for RenderResourceAssignments {:?}",
|
|
||||||
binding.name,
|
|
||||||
render_resource_assignments.id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<wgpu::Binding>>();
|
.collect::<Vec<wgpu::Binding>>();
|
||||||
|
|
||||||
let bind_group_layout = bind_group_layouts.get(&bind_group_descriptor.id).unwrap();
|
let bind_group_layout = bind_group_layouts.get(&bind_group_descriptor_id).unwrap();
|
||||||
let wgpu_bind_group_descriptor = wgpu::BindGroupDescriptor {
|
let wgpu_bind_group_descriptor = wgpu::BindGroupDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
layout: bind_group_layout,
|
layout: bind_group_layout,
|
||||||
|
@ -518,7 +506,7 @@ impl RenderResourceContext for WgpuRenderResourceContext {
|
||||||
let wgpu_bind_group = self.device.create_bind_group(&wgpu_bind_group_descriptor);
|
let wgpu_bind_group = self.device.create_bind_group(&wgpu_bind_group_descriptor);
|
||||||
|
|
||||||
let bind_group_info = bind_groups
|
let bind_group_info = bind_groups
|
||||||
.entry(bind_group_descriptor.id)
|
.entry(bind_group_descriptor_id)
|
||||||
.or_insert_with(|| WgpuBindGroupInfo::default());
|
.or_insert_with(|| WgpuBindGroupInfo::default());
|
||||||
bind_group_info
|
bind_group_info
|
||||||
.bind_groups
|
.bind_groups
|
||||||
|
@ -527,11 +515,8 @@ impl RenderResourceContext for WgpuRenderResourceContext {
|
||||||
"created bind group for RenderResourceSet {:?}",
|
"created bind group for RenderResourceSet {:?}",
|
||||||
render_resource_set.id
|
render_resource_set.id
|
||||||
);
|
);
|
||||||
return Some(render_resource_set.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_bind_groups(&self) {
|
fn clear_bind_groups(&self) {
|
||||||
self.resources.bind_groups.write().unwrap().clear();
|
self.resources.bind_groups.write().unwrap().clear();
|
||||||
|
|
|
@ -2,8 +2,8 @@ use crate::{renderer::WgpuRenderContext, WgpuResourceRefs};
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
pass::RenderPass,
|
pass::RenderPass,
|
||||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
pipeline::{PipelineDescriptor, BindGroupDescriptorId},
|
||||||
render_resource::{RenderResourceId, RenderResourceSet},
|
render_resource::{RenderResourceId, RenderResourceSetId},
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
};
|
};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
@ -51,33 +51,35 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
|
||||||
|
|
||||||
fn set_bind_group(
|
fn set_bind_group(
|
||||||
&mut self,
|
&mut self,
|
||||||
bind_group_descriptor: &BindGroupDescriptor,
|
index: u32,
|
||||||
render_resource_set: &RenderResourceSet,
|
bind_group_descriptor: BindGroupDescriptorId,
|
||||||
|
render_resource_set: RenderResourceSetId,
|
||||||
|
dynamic_uniform_indices: Option<&[u32]>,
|
||||||
) {
|
) {
|
||||||
if let Some(bind_group_info) = self
|
if let Some(bind_group_info) = self
|
||||||
.render_resources
|
.render_resources
|
||||||
.bind_groups
|
.bind_groups
|
||||||
.get(&bind_group_descriptor.id)
|
.get(&bind_group_descriptor)
|
||||||
{
|
{
|
||||||
if let Some(wgpu_bind_group) = bind_group_info.bind_groups.get(&render_resource_set.id)
|
if let Some(wgpu_bind_group) = bind_group_info.bind_groups.get(&render_resource_set)
|
||||||
{
|
{
|
||||||
const EMPTY: &'static [u32] = &[];
|
const EMPTY: &'static [u32] = &[];
|
||||||
let dynamic_uniform_indices = if let Some(ref dynamic_uniform_indices) =
|
let dynamic_uniform_indices = if let Some(dynamic_uniform_indices) =
|
||||||
render_resource_set.dynamic_uniform_indices
|
dynamic_uniform_indices
|
||||||
{
|
{
|
||||||
dynamic_uniform_indices.as_slice()
|
dynamic_uniform_indices
|
||||||
} else {
|
} else {
|
||||||
EMPTY
|
EMPTY
|
||||||
};
|
};
|
||||||
|
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"set bind group {:?} {:?}: {:?}",
|
"set bind group {:?} {:?}: {:?}",
|
||||||
bind_group_descriptor.id,
|
bind_group_descriptor,
|
||||||
dynamic_uniform_indices,
|
dynamic_uniform_indices,
|
||||||
render_resource_set.id
|
render_resource_set
|
||||||
);
|
);
|
||||||
self.render_pass.set_bind_group(
|
self.render_pass.set_bind_group(
|
||||||
bind_group_descriptor.index,
|
index,
|
||||||
wgpu_bind_group,
|
wgpu_bind_group,
|
||||||
dynamic_uniform_indices,
|
dynamic_uniform_indices,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::renderer::{
|
use crate::renderer::{WgpuRenderGraphExecutor, WgpuRenderResourceContext};
|
||||||
render_resource_sets_system, WgpuRenderGraphExecutor, WgpuRenderResourceContext,
|
|
||||||
};
|
|
||||||
use bevy_app::{EventReader, Events};
|
use bevy_app::{EventReader, Events};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
pipeline::update_shader_assignments,
|
draw::{draw_system, RenderPipelines},
|
||||||
|
pipeline::compile_pipelines_system,
|
||||||
render_graph::{DependentNodeStager, RenderGraph, RenderGraphStager},
|
render_graph::{DependentNodeStager, RenderGraph, RenderGraphStager},
|
||||||
|
render_resource::render_resource_sets_system,
|
||||||
renderer::RenderResources,
|
renderer::RenderResources,
|
||||||
};
|
};
|
||||||
use bevy_window::{WindowCreated, WindowResized, Windows};
|
use bevy_window::{WindowCreated, WindowResized, Windows};
|
||||||
|
@ -20,10 +20,7 @@ pub struct WgpuRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WgpuRenderer {
|
impl WgpuRenderer {
|
||||||
pub async fn new(
|
pub async fn new() -> Self {
|
||||||
window_resized_event_reader: EventReader<WindowResized>,
|
|
||||||
window_created_event_reader: EventReader<WindowCreated>,
|
|
||||||
) -> Self {
|
|
||||||
let instance = wgpu::Instance::new();
|
let instance = wgpu::Instance::new();
|
||||||
let adapter = instance
|
let adapter = instance
|
||||||
.request_adapter(
|
.request_adapter(
|
||||||
|
@ -53,8 +50,8 @@ impl WgpuRenderer {
|
||||||
instance,
|
instance,
|
||||||
device,
|
device,
|
||||||
queue,
|
queue,
|
||||||
window_resized_event_reader,
|
window_resized_event_reader: Default::default(),
|
||||||
window_created_event_reader,
|
window_created_event_reader: Default::default(),
|
||||||
intialized: false,
|
intialized: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,6 +82,7 @@ impl WgpuRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_graph(&mut self, world: &mut World, resources: &mut Resources) {
|
pub fn run_graph(&mut self, world: &mut World, resources: &mut Resources) {
|
||||||
|
// TODO: move this to a thread-local system
|
||||||
// run systems
|
// run systems
|
||||||
let mut system_executor = {
|
let mut system_executor = {
|
||||||
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
||||||
|
@ -95,8 +93,12 @@ impl WgpuRenderer {
|
||||||
executor.execute(world, resources);
|
executor.execute(world, resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
update_shader_assignments(world, resources);
|
// TODO: move these to a scheduler
|
||||||
render_resource_sets_system().run(world, resources);
|
compile_pipelines_system.system().run(world, resources);
|
||||||
|
render_resource_sets_system.system().run(world, resources);
|
||||||
|
draw_system::<RenderPipelines>
|
||||||
|
.system()
|
||||||
|
.run(world, resources);
|
||||||
|
|
||||||
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
||||||
if let Some(executor) = system_executor.take() {
|
if let Some(executor) = system_executor.take() {
|
||||||
|
|
|
@ -283,13 +283,12 @@ fn stateful_system(mut state: ComMut<State>, player: Com<Player>, score: ComMut<
|
||||||
// NOTE: this doesn't do anything relevant to our game, it is just here for illustrative purposes
|
// NOTE: this doesn't do anything relevant to our game, it is just here for illustrative purposes
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn complex_system(resources: &mut Resources) -> Box<dyn Schedulable> {
|
fn complex_system(resources: &mut Resources) -> Box<dyn Schedulable> {
|
||||||
let mut counter = 0;
|
|
||||||
let game_state = resources.get::<GameState>().unwrap();
|
let game_state = resources.get::<GameState>().unwrap();
|
||||||
let initial_player_count = game_state.total_players;
|
let initial_player_count = game_state.total_players;
|
||||||
SystemBuilder::new("complex_system")
|
SystemBuilder::new("complex_system")
|
||||||
.read_resource::<GameState>()
|
.read_resource::<GameState>()
|
||||||
.write_resource::<GameRules>()
|
.write_resource::<GameRules>()
|
||||||
.read_component::<Renderable>()
|
.read_component::<Draw>()
|
||||||
// this query is equivalent to the system we saw above: system(player: Com<Player>, mut score: ComMut<Score>)
|
// this query is equivalent to the system we saw above: system(player: Com<Player>, mut score: ComMut<Score>)
|
||||||
.with_query(<(Read<Player>, Write<Score>)>::query())
|
.with_query(<(Read<Player>, Write<Score>)>::query())
|
||||||
// this query only returns entities with a Player component that has changed since the last update
|
// this query only returns entities with a Player component that has changed since the last update
|
||||||
|
@ -303,7 +302,6 @@ fn complex_system(resources: &mut Resources) -> Box<dyn Schedulable> {
|
||||||
|
|
||||||
for (player, score) in player_score_query.iter_mut(world) {
|
for (player, score) in player_score_query.iter_mut(world) {
|
||||||
println!("processed : {} {}", player.name, score.value);
|
println!("processed : {} {}", player.name, score.value);
|
||||||
counter += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for player in player_changed_query.iter(world) {
|
for player in player_changed_query.iter(world) {
|
||||||
|
|
|
@ -54,8 +54,6 @@ fn setup(
|
||||||
}));
|
}));
|
||||||
|
|
||||||
render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true));
|
render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true));
|
||||||
let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap();
|
|
||||||
main_pass.add_pipeline(pipeline_handle);
|
|
||||||
pipeline_handle
|
pipeline_handle
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,7 +68,7 @@ fn setup(
|
||||||
// cube
|
// cube
|
||||||
.add_entity(MeshMaterialEntity::<MyMaterial> {
|
.add_entity(MeshMaterialEntity::<MyMaterial> {
|
||||||
mesh: cube_handle,
|
mesh: cube_handle,
|
||||||
renderable: Renderable {
|
render_pipelines: RenderPipelines {
|
||||||
pipelines: vec![pipeline_handle],
|
pipelines: vec![pipeline_handle],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
@ -64,8 +64,6 @@ fn setup(
|
||||||
fragment: Some(shaders.add(Shader::from_glsl(ShaderStage::Fragment, FRAGMENT_SHADER))),
|
fragment: Some(shaders.add(Shader::from_glsl(ShaderStage::Fragment, FRAGMENT_SHADER))),
|
||||||
}));
|
}));
|
||||||
render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true));
|
render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true));
|
||||||
let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap();
|
|
||||||
main_pass.add_pipeline(pipeline_handle);
|
|
||||||
pipeline_handle
|
pipeline_handle
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,7 +85,7 @@ fn setup(
|
||||||
// cube
|
// cube
|
||||||
.add_entity(MeshMaterialEntity::<MyMaterial> {
|
.add_entity(MeshMaterialEntity::<MyMaterial> {
|
||||||
mesh: cube_handle,
|
mesh: cube_handle,
|
||||||
renderable: Renderable {
|
render_pipelines: RenderPipelines {
|
||||||
pipelines: vec![pipeline_handle],
|
pipelines: vec![pipeline_handle],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -98,7 +96,7 @@ fn setup(
|
||||||
// cube
|
// cube
|
||||||
.add_entity(MeshMaterialEntity::<MyMaterial> {
|
.add_entity(MeshMaterialEntity::<MyMaterial> {
|
||||||
mesh: cube_handle,
|
mesh: cube_handle,
|
||||||
renderable: Renderable {
|
render_pipelines: RenderPipelines {
|
||||||
pipelines: vec![pipeline_handle],
|
pipelines: vec![pipeline_handle],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub use crate::{
|
||||||
pipeline::PipelineDescriptor,
|
pipeline::PipelineDescriptor,
|
||||||
render_graph::{
|
render_graph::{
|
||||||
nodes::{
|
nodes::{
|
||||||
AssetUniformNode, CameraNode, PassNode, UniformNode, WindowSwapChainNode,
|
AssetUniformNode, CameraNode, MainPassNode, UniformNode, WindowSwapChainNode,
|
||||||
WindowTextureNode,
|
WindowTextureNode,
|
||||||
},
|
},
|
||||||
RenderGraph,
|
RenderGraph,
|
||||||
|
@ -27,7 +27,8 @@ pub use crate::{
|
||||||
render_resource::RenderResources,
|
render_resource::RenderResources,
|
||||||
shader::{Shader, ShaderDefs, ShaderStage, ShaderStages},
|
shader::{Shader, ShaderDefs, ShaderStage, ShaderStages},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
Camera, Color, ColorSource, OrthographicProjection, PerspectiveProjection, Renderable,
|
draw::{Draw, RenderPipelines},
|
||||||
|
Camera, Color, ColorSource, OrthographicProjection, PerspectiveProjection,
|
||||||
},
|
},
|
||||||
scene::{Scene, SceneSpawner},
|
scene::{Scene, SceneSpawner},
|
||||||
sprite::{
|
sprite::{
|
||||||
|
|
Loading…
Add table
Reference in a new issue