remove DrawTargets in favor of PassNodes and in preparation for "immediate mode" drawing api
This commit is contained in:
parent
6531ccddab
commit
1426208e2f
@ -2,7 +2,6 @@ use crate::{material::StandardMaterial, nodes::LightsNode, pipelines::build_forw
|
|||||||
use bevy_asset::Assets;
|
use bevy_asset::Assets;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
base_render_graph,
|
base_render_graph,
|
||||||
draw_target::AssignedMeshesDrawTarget,
|
|
||||||
pipeline::PipelineDescriptor,
|
pipeline::PipelineDescriptor,
|
||||||
render_graph::{
|
render_graph::{
|
||||||
nodes::{AssetUniformNode, PassNode, UniformNode},
|
nodes::{AssetUniformNode, PassNode, UniformNode},
|
||||||
@ -41,10 +40,7 @@ impl ForwardPbrRenderGraphBuilder for RenderGraph {
|
|||||||
let main_pass: &mut PassNode = self
|
let main_pass: &mut PassNode = self
|
||||||
.get_node_mut(base_render_graph::node::MAIN_PASS)
|
.get_node_mut(base_render_graph::node::MAIN_PASS)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
main_pass.add_pipeline(
|
main_pass.add_pipeline(pipelines.add_default(build_forward_pipeline(&mut shaders)));
|
||||||
pipelines.add_default(build_forward_pipeline(&mut shaders)),
|
|
||||||
vec![Box::new(AssignedMeshesDrawTarget)],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: replace these with "autowire" groups
|
// TODO: replace these with "autowire" groups
|
||||||
|
|||||||
41
crates/bevy_render/src/draw.rs
Normal file
41
crates/bevy_render/src/draw.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use crate::{render_resource::RenderResourceId, pipeline::PipelineDescriptor};
|
||||||
|
use bevy_asset::Handle;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub enum DrawType {
|
||||||
|
Instanced {
|
||||||
|
indices: Range<u32>,
|
||||||
|
base_vertex: i32,
|
||||||
|
instances: Range<u32>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct VertexBufferBinding {
|
||||||
|
pub slot: u32,
|
||||||
|
pub vertex_buffer: RenderResourceId,
|
||||||
|
pub offset: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct IndexBufferBinding {
|
||||||
|
pub vertex_buffer: RenderResourceId,
|
||||||
|
pub offset: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct BindGroupBinding {
|
||||||
|
pub vertex_buffer: RenderResourceId,
|
||||||
|
pub offset: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct DrawCall {
|
||||||
|
pub pipeline: Handle<PipelineDescriptor>,
|
||||||
|
pub draw_type: DrawType,
|
||||||
|
pub vertex_buffers: Vec<VertexBufferBinding>,
|
||||||
|
pub index_buffer: Option<IndexBufferBinding>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Draw {}
|
||||||
@ -1,25 +0,0 @@
|
|||||||
use crate::{pass::RenderPass, pipeline::PipelineDescriptor, renderer::RenderContext};
|
|
||||||
use bevy_asset::Handle;
|
|
||||||
use legion::prelude::{Resources, World};
|
|
||||||
|
|
||||||
// A set of draw calls. ex: get + draw meshes, get + draw instanced meshes, draw ui meshes, etc
|
|
||||||
pub trait DrawTarget: Send + Sync + 'static {
|
|
||||||
fn draw(
|
|
||||||
&self,
|
|
||||||
world: &World,
|
|
||||||
resources: &Resources,
|
|
||||||
render_pass: &mut dyn RenderPass,
|
|
||||||
pipeline_handle: Handle<PipelineDescriptor>,
|
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
|
||||||
);
|
|
||||||
fn setup(
|
|
||||||
&mut self,
|
|
||||||
_world: &World,
|
|
||||||
_resources: &Resources,
|
|
||||||
_render_context: &mut dyn RenderContext,
|
|
||||||
_pipeline_handle: Handle<PipelineDescriptor>,
|
|
||||||
_pipeline_descriptor: &PipelineDescriptor,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
fn get_name(&self) -> String;
|
|
||||||
}
|
|
||||||
@ -1,106 +0,0 @@
|
|||||||
use bevy_asset::Handle;
|
|
||||||
use legion::prelude::*;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
draw_target::DrawTarget,
|
|
||||||
pass::RenderPass,
|
|
||||||
pipeline::{PipelineAssignments, PipelineDescriptor},
|
|
||||||
render_resource::{
|
|
||||||
EntitiesWaitingForAssets, EntityRenderResourceAssignments, RenderResourceAssignments,
|
|
||||||
},
|
|
||||||
renderer::RenderContext,
|
|
||||||
Renderable,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct AssignedMeshesDrawTarget;
|
|
||||||
|
|
||||||
impl AssignedMeshesDrawTarget {
|
|
||||||
pub const NAME: &'static str = "AssignedMeshes";
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DrawTarget for AssignedMeshesDrawTarget {
|
|
||||||
fn draw(
|
|
||||||
&self,
|
|
||||||
world: &World,
|
|
||||||
resources: &Resources,
|
|
||||||
render_pass: &mut dyn RenderPass,
|
|
||||||
pipeline_handle: Handle<PipelineDescriptor>,
|
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
|
||||||
) {
|
|
||||||
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 global_render_resource_assignments =
|
|
||||||
resources.get::<RenderResourceAssignments>().unwrap();
|
|
||||||
render_pass.set_render_resources(pipeline_descriptor, &global_render_resource_assignments);
|
|
||||||
|
|
||||||
let assigned_render_resource_assignments = shader_pipeline_assignments
|
|
||||||
.assignments
|
|
||||||
.get(&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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(indices) = render_pass.set_render_resources(
|
|
||||||
pipeline_descriptor,
|
|
||||||
&renderable.render_resource_assignments,
|
|
||||||
) {
|
|
||||||
render_pass.draw_indexed(indices, 0, 0..1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup(
|
|
||||||
&mut self,
|
|
||||||
world: &World,
|
|
||||||
resources: &Resources,
|
|
||||||
render_context: &mut dyn RenderContext,
|
|
||||||
pipeline_handle: Handle<PipelineDescriptor>,
|
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
|
||||||
) {
|
|
||||||
let pipeline_assignments = resources.get::<PipelineAssignments>().unwrap();
|
|
||||||
let entity_render_resource_assignments =
|
|
||||||
resources.get::<EntityRenderResourceAssignments>().unwrap();
|
|
||||||
let assigned_render_resource_assignments =
|
|
||||||
pipeline_assignments.assignments.get(&pipeline_handle);
|
|
||||||
let global_render_resource_assignments =
|
|
||||||
resources.get::<RenderResourceAssignments>().unwrap();
|
|
||||||
render_context
|
|
||||||
.resources()
|
|
||||||
.setup_bind_groups(pipeline_descriptor, &global_render_resource_assignments);
|
|
||||||
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_context.resources().setup_bind_groups(
|
|
||||||
pipeline_descriptor,
|
|
||||||
&renderable.render_resource_assignments,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_name(&self) -> String {
|
|
||||||
AssignedMeshesDrawTarget::NAME.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
draw_target::DrawTarget,
|
|
||||||
mesh::{self, Mesh},
|
|
||||||
pass::RenderPass,
|
|
||||||
pipeline::PipelineDescriptor,
|
|
||||||
render_resource::ResourceInfo,
|
|
||||||
Renderable,
|
|
||||||
};
|
|
||||||
use bevy_asset::Handle;
|
|
||||||
use legion::prelude::*;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct MeshesDrawTarget;
|
|
||||||
|
|
||||||
impl MeshesDrawTarget {
|
|
||||||
pub const NAME: &'static str = "Meshes";
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DrawTarget for MeshesDrawTarget {
|
|
||||||
fn draw(
|
|
||||||
&self,
|
|
||||||
world: &World,
|
|
||||||
_resources: &Resources,
|
|
||||||
render_pass: &mut dyn RenderPass,
|
|
||||||
_pipeline_handle: Handle<PipelineDescriptor>,
|
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
|
||||||
) {
|
|
||||||
let mut current_mesh_handle = None;
|
|
||||||
let mut current_mesh_index_len = 0;
|
|
||||||
let mesh_query = <(Read<Handle<Mesh>>, Read<Renderable>)>::query();
|
|
||||||
for (mesh_handle, renderable) in mesh_query.iter(world) {
|
|
||||||
if !renderable.is_visible || renderable.is_instanced {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let render_context = render_pass.get_render_context();
|
|
||||||
let render_resources = render_context.resources();
|
|
||||||
if current_mesh_handle != Some(*mesh_handle) {
|
|
||||||
if let Some(vertex_buffer_resource) = render_resources
|
|
||||||
.get_asset_resource(*mesh_handle, mesh::VERTEX_BUFFER_ASSET_INDEX)
|
|
||||||
{
|
|
||||||
let index_buffer_resource = render_resources
|
|
||||||
.get_asset_resource(*mesh_handle, mesh::INDEX_BUFFER_ASSET_INDEX)
|
|
||||||
.unwrap();
|
|
||||||
render_resources.get_resource_info(
|
|
||||||
index_buffer_resource,
|
|
||||||
&mut |resource_info| match resource_info {
|
|
||||||
Some(ResourceInfo::Buffer(Some(buffer_info))) => {
|
|
||||||
current_mesh_index_len = (buffer_info.size / 2) as u32
|
|
||||||
}
|
|
||||||
_ => panic!("expected a buffer type"),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
render_pass.set_index_buffer(index_buffer_resource, 0);
|
|
||||||
render_pass.set_vertex_buffer(0, vertex_buffer_resource, 0);
|
|
||||||
}
|
|
||||||
// TODO: Verify buffer format matches render pass
|
|
||||||
current_mesh_handle = Some(*mesh_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: validate bind group properties against shader uniform properties at least once
|
|
||||||
render_pass
|
|
||||||
.set_render_resources(pipeline_descriptor, &renderable.render_resource_assignments);
|
|
||||||
render_pass.draw_indexed(0..current_mesh_index_len, 0, 0..1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_name(&self) -> String {
|
|
||||||
MeshesDrawTarget::NAME.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
mod assigned_meshes_draw_target;
|
|
||||||
mod meshes_draw_target;
|
|
||||||
|
|
||||||
pub use assigned_meshes_draw_target::*;
|
|
||||||
pub use meshes_draw_target::*;
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
mod draw_target;
|
|
||||||
mod draw_targets;
|
|
||||||
|
|
||||||
pub use draw_target::*;
|
|
||||||
pub use draw_targets::*;
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
pub mod batch;
|
pub mod batch;
|
||||||
mod camera;
|
mod camera;
|
||||||
|
pub mod draw;
|
||||||
pub mod entity;
|
pub mod entity;
|
||||||
pub mod mesh;
|
pub mod mesh;
|
||||||
pub mod render_graph;
|
pub mod render_graph;
|
||||||
@ -16,7 +17,6 @@ pub use renderable::*;
|
|||||||
pub use vertex::Vertex;
|
pub use vertex::Vertex;
|
||||||
|
|
||||||
pub mod base_render_graph;
|
pub mod base_render_graph;
|
||||||
pub mod draw_target;
|
|
||||||
pub mod pass;
|
pub mod pass;
|
||||||
pub mod pipeline;
|
pub mod pipeline;
|
||||||
pub mod render_resource;
|
pub mod render_resource;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
pipeline::PipelineDescriptor,
|
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
||||||
render_resource::{RenderResourceId, RenderResourceAssignments},
|
render_resource::{RenderResourceId, RenderResourceSet},
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
};
|
};
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
@ -15,10 +15,9 @@ pub trait RenderPass {
|
|||||||
fn set_stencil_reference(&mut self, reference: u32);
|
fn set_stencil_reference(&mut self, reference: u32);
|
||||||
fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
|
fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
|
||||||
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>);
|
||||||
// TODO: try to somehow take into account the "set" pipeline instead of passing it in here
|
fn set_bind_group(
|
||||||
fn set_render_resources(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
bind_group_descriptor: &BindGroupDescriptor,
|
||||||
render_resource_assignments: &RenderResourceAssignments,
|
render_resource_set: &RenderResourceSet,
|
||||||
) -> Option<Range<u32>>;
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,22 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
draw_target::DrawTarget,
|
pass::{PassDescriptor, RenderPass, TextureAttachment},
|
||||||
pass::{PassDescriptor, TextureAttachment},
|
pipeline::{PipelineAssignments, PipelineCompiler, PipelineDescriptor},
|
||||||
pipeline::{PipelineCompiler, PipelineDescriptor},
|
|
||||||
render_graph::{Node, ResourceSlotInfo, ResourceSlots},
|
render_graph::{Node, ResourceSlotInfo, ResourceSlots},
|
||||||
render_resource::{ResourceInfo, RenderResourceAssignments},
|
render_resource::{
|
||||||
|
EntitiesWaitingForAssets, EntityRenderResourceAssignments, RenderResourceAssignments,
|
||||||
|
ResourceInfo,
|
||||||
|
},
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
shader::Shader,
|
shader::Shader,
|
||||||
|
Renderable,
|
||||||
};
|
};
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
pub struct PassNode {
|
pub struct PassNode {
|
||||||
descriptor: PassDescriptor,
|
descriptor: PassDescriptor,
|
||||||
pipelines: Vec<(Handle<PipelineDescriptor>, Vec<Box<dyn DrawTarget>>)>,
|
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>,
|
||||||
@ -54,12 +58,64 @@ impl PassNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_pipeline(
|
pub fn add_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>) {
|
||||||
&mut self,
|
self.pipelines.push(pipeline_handle);
|
||||||
pipeline_handle: Handle<PipelineDescriptor>,
|
}
|
||||||
draw_targets: Vec<Box<dyn DrawTarget>>,
|
|
||||||
) {
|
fn set_render_resources(
|
||||||
self.pipelines.push((pipeline_handle, draw_targets));
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +134,12 @@ impl Node for PassNode {
|
|||||||
) {
|
) {
|
||||||
let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap();
|
let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap();
|
||||||
let pipelines = resources.get::<Assets<PipelineDescriptor>>().unwrap();
|
let pipelines = resources.get::<Assets<PipelineDescriptor>>().unwrap();
|
||||||
|
let shader_pipeline_assignments = resources.get::<PipelineAssignments>().unwrap();
|
||||||
|
let entity_render_resource_assignments =
|
||||||
|
resources.get::<EntityRenderResourceAssignments>().unwrap();
|
||||||
|
let entities_waiting_for_assets = resources.get::<EntitiesWaitingForAssets>().unwrap();
|
||||||
|
let mut render_resource_assignments =
|
||||||
|
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||||
|
|
||||||
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] {
|
||||||
@ -94,50 +156,71 @@ impl Node for PassNode {
|
|||||||
.attachment = TextureAttachment::RenderResource(input.get(input_index).unwrap());
|
.attachment = TextureAttachment::RenderResource(input.get(input_index).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
let shaders = resources.get::<Assets<Shader>>().unwrap();
|
{
|
||||||
for (pipeline_handle, draw_targets) in self.pipelines.iter_mut() {
|
let render_resource_context = render_context.resources();
|
||||||
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: try merging the two pipeline loops below
|
||||||
{
|
let shaders = resources.get::<Assets<Shader>>().unwrap();
|
||||||
// TODO: this breaks down in a parallel setting. it needs to change. ideally in a way that
|
for pipeline_handle in self.pipelines.iter() {
|
||||||
// doesn't require modifying RenderResourceAssignments
|
if let Some(compiled_pipelines_iter) =
|
||||||
let mut render_resource_assignments =
|
pipeline_compiler.iter_compiled_pipelines(*pipeline_handle)
|
||||||
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
{
|
||||||
for bind_group in pipeline_layout.bind_groups.iter() {
|
for compiled_pipeline_handle in compiled_pipelines_iter {
|
||||||
render_resource_assignments.update_render_resource_set_id(bind_group);
|
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_context.resources().create_render_pipeline(
|
render_resource_context.create_render_pipeline(
|
||||||
*compiled_pipeline_handle,
|
|
||||||
&compiled_pipeline_descriptor,
|
|
||||||
&shaders,
|
|
||||||
);
|
|
||||||
for draw_target in draw_targets.iter_mut() {
|
|
||||||
draw_target.setup(
|
|
||||||
world,
|
|
||||||
resources,
|
|
||||||
render_context,
|
|
||||||
*compiled_pipeline_handle,
|
*compiled_pipeline_handle,
|
||||||
compiled_pipeline_descriptor,
|
&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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let render_resource_assignments = resources.get::<RenderResourceAssignments>().unwrap();
|
|
||||||
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, draw_targets) in self.pipelines.iter() {
|
for pipeline_handle in self.pipelines.iter() {
|
||||||
if let Some(compiled_pipelines_iter) =
|
if let Some(compiled_pipelines_iter) =
|
||||||
pipeline_compiler.iter_compiled_pipelines(*pipeline_handle)
|
pipeline_compiler.iter_compiled_pipelines(*pipeline_handle)
|
||||||
{
|
{
|
||||||
@ -145,14 +228,45 @@ impl Node for PassNode {
|
|||||||
let compiled_pipeline_descriptor =
|
let compiled_pipeline_descriptor =
|
||||||
pipelines.get(compiled_pipeline_handle).unwrap();
|
pipelines.get(compiled_pipeline_handle).unwrap();
|
||||||
render_pass.set_pipeline(*compiled_pipeline_handle);
|
render_pass.set_pipeline(*compiled_pipeline_handle);
|
||||||
for draw_target in draw_targets.iter() {
|
|
||||||
draw_target.draw(
|
// set global render resources
|
||||||
world,
|
Self::set_render_resources(
|
||||||
resources,
|
render_pass,
|
||||||
render_pass,
|
compiled_pipeline_descriptor,
|
||||||
*compiled_pipeline_handle,
|
&render_resource_assignments,
|
||||||
compiled_pipeline_descriptor,
|
);
|
||||||
);
|
|
||||||
|
// draw entities assigned to this pipeline
|
||||||
|
let assigned_render_resource_assignments = shader_pipeline_assignments
|
||||||
|
.assignments
|
||||||
|
.get(&compiled_pipeline_handle);
|
||||||
|
|
||||||
|
if let Some(assigned_render_resource_assignments) =
|
||||||
|
assigned_render_resource_assignments
|
||||||
|
{
|
||||||
|
for assignment_id in assigned_render_resource_assignments.iter() {
|
||||||
|
// TODO: hopefully legion has better random access apis that are more like queries?
|
||||||
|
let entity = entity_render_resource_assignments
|
||||||
|
.get(*assignment_id)
|
||||||
|
.unwrap();
|
||||||
|
let renderable =
|
||||||
|
world.get_component::<Renderable>(*entity).unwrap();
|
||||||
|
if !renderable.is_visible
|
||||||
|
|| renderable.is_instanced
|
||||||
|
|| entities_waiting_for_assets.contains(entity)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set local render resources
|
||||||
|
if let Some(indices) = Self::set_render_resources(
|
||||||
|
render_pass,
|
||||||
|
compiled_pipeline_descriptor,
|
||||||
|
&renderable.render_resource_assignments,
|
||||||
|
) {
|
||||||
|
render_pass.draw_indexed(indices, 0, 0..1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ use crate::{ColorMaterial, Quad, TextureAtlas, TextureAtlasSprite};
|
|||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
base_render_graph,
|
base_render_graph,
|
||||||
draw_target::AssignedMeshesDrawTarget,
|
|
||||||
pipeline::{state_descriptors::*, PipelineDescriptor},
|
pipeline::{state_descriptors::*, PipelineDescriptor},
|
||||||
render_graph::{
|
render_graph::{
|
||||||
nodes::{AssetUniformNode, PassNode, UniformNode},
|
nodes::{AssetUniformNode, PassNode, UniformNode},
|
||||||
@ -153,14 +152,8 @@ impl SpriteRenderGraphBuilder for RenderGraph {
|
|||||||
let main_pass: &mut PassNode = self
|
let main_pass: &mut PassNode = self
|
||||||
.get_node_mut(base_render_graph::node::MAIN_PASS)
|
.get_node_mut(base_render_graph::node::MAIN_PASS)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
main_pass.add_pipeline(
|
main_pass.add_pipeline(SPRITE_PIPELINE_HANDLE);
|
||||||
SPRITE_PIPELINE_HANDLE,
|
main_pass.add_pipeline(SPRITE_SHEET_PIPELINE_HANDLE);
|
||||||
vec![Box::new(AssignedMeshesDrawTarget)],
|
|
||||||
);
|
|
||||||
main_pass.add_pipeline(
|
|
||||||
SPRITE_SHEET_PIPELINE_HANDLE,
|
|
||||||
vec![Box::new(AssignedMeshesDrawTarget)],
|
|
||||||
);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
base_render_graph,
|
base_render_graph,
|
||||||
draw_target::AssignedMeshesDrawTarget,
|
|
||||||
pipeline::{state_descriptors::*, PipelineDescriptor},
|
pipeline::{state_descriptors::*, PipelineDescriptor},
|
||||||
render_graph::{
|
render_graph::{
|
||||||
nodes::{CameraNode, PassNode},
|
nodes::{CameraNode, PassNode},
|
||||||
@ -83,7 +82,7 @@ impl UiRenderGraphBuilder for RenderGraph {
|
|||||||
let main_pass: &mut PassNode = self
|
let main_pass: &mut PassNode = self
|
||||||
.get_node_mut(base_render_graph::node::MAIN_PASS)
|
.get_node_mut(base_render_graph::node::MAIN_PASS)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
main_pass.add_pipeline(UI_PIPELINE_HANDLE, vec![Box::new(AssignedMeshesDrawTarget)]);
|
main_pass.add_pipeline(UI_PIPELINE_HANDLE);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,12 +6,12 @@ use bevy_render::{
|
|||||||
PassDescriptor, RenderPass, RenderPassColorAttachmentDescriptor,
|
PassDescriptor, RenderPass, RenderPassColorAttachmentDescriptor,
|
||||||
RenderPassDepthStencilAttachmentDescriptor, TextureAttachment,
|
RenderPassDepthStencilAttachmentDescriptor, TextureAttachment,
|
||||||
},
|
},
|
||||||
render_resource::{RenderResourceId, RenderResourceAssignment, RenderResourceAssignments},
|
render_resource::{RenderResourceAssignment, RenderResourceAssignments, RenderResourceId},
|
||||||
renderer::{RenderContext, RenderResourceContext},
|
renderer::{RenderContext, RenderResourceContext},
|
||||||
texture::Extent3d,
|
texture::Extent3d,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct LazyCommandEncoder {
|
pub struct LazyCommandEncoder {
|
||||||
@ -138,10 +138,10 @@ impl RenderContext for WgpuRenderContext {
|
|||||||
&mut encoder,
|
&mut encoder,
|
||||||
);
|
);
|
||||||
let mut wgpu_render_pass = WgpuRenderPass {
|
let mut wgpu_render_pass = WgpuRenderPass {
|
||||||
render_context: self,
|
|
||||||
render_pass,
|
render_pass,
|
||||||
|
render_context: self,
|
||||||
render_resources: refs,
|
render_resources: refs,
|
||||||
bound_bind_groups: HashMap::default(),
|
pipeline_descriptor: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
run_pass(&mut wgpu_render_pass);
|
run_pass(&mut wgpu_render_pass);
|
||||||
|
|||||||
@ -2,19 +2,17 @@ use crate::{renderer::WgpuRenderContext, WgpuResourceRefs};
|
|||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
pass::RenderPass,
|
pass::RenderPass,
|
||||||
pipeline::PipelineDescriptor,
|
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
||||||
render_resource::{
|
render_resource::{RenderResourceId, RenderResourceSet},
|
||||||
RenderResourceId, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
|
|
||||||
},
|
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, ops::Range};
|
use std::ops::Range;
|
||||||
|
|
||||||
pub struct WgpuRenderPass<'a> {
|
pub struct WgpuRenderPass<'a> {
|
||||||
pub render_pass: wgpu::RenderPass<'a>,
|
pub render_pass: wgpu::RenderPass<'a>,
|
||||||
pub render_context: &'a WgpuRenderContext,
|
pub render_context: &'a WgpuRenderContext,
|
||||||
pub render_resources: WgpuResourceRefs<'a>,
|
pub render_resources: WgpuResourceRefs<'a>,
|
||||||
pub bound_bind_groups: HashMap<u32, RenderResourceSetId>,
|
pub pipeline_descriptor: Option<&'a PipelineDescriptor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RenderPass for WgpuRenderPass<'a> {
|
impl<'a> RenderPass for WgpuRenderPass<'a> {
|
||||||
@ -51,102 +49,42 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
|
|||||||
self.render_pass.draw(vertices, instances);
|
self.render_pass.draw(vertices, instances);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_render_resources(
|
fn set_bind_group(
|
||||||
&mut self,
|
&mut self,
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
bind_group_descriptor: &BindGroupDescriptor,
|
||||||
render_resource_assignments: &RenderResourceAssignments,
|
render_resource_set: &RenderResourceSet,
|
||||||
) -> Option<Range<u32>> {
|
) {
|
||||||
let pipeline_layout = pipeline_descriptor.get_layout().unwrap();
|
if let Some(bind_group_info) = self
|
||||||
// PERF: vertex buffer lookup comes at a cost when vertex buffers aren't in render_resource_assignments. iterating over render_resource_assignment vertex buffers
|
.render_resources
|
||||||
// would likely be faster
|
.bind_groups
|
||||||
let mut indices = None;
|
.get(&bind_group_descriptor.id)
|
||||||
for (i, vertex_buffer_descriptor) in
|
|
||||||
pipeline_layout.vertex_buffer_descriptors.iter().enumerate()
|
|
||||||
{
|
{
|
||||||
if let Some((vertex_buffer, index_buffer)) =
|
if let Some(wgpu_bind_group) = bind_group_info.bind_groups.get(&render_resource_set.id)
|
||||||
render_resource_assignments.get_vertex_buffer(&vertex_buffer_descriptor.name)
|
|
||||||
{
|
{
|
||||||
log::trace!(
|
const EMPTY: &'static [u32] = &[];
|
||||||
"set vertex buffer {}: {} ({:?})",
|
let dynamic_uniform_indices = if let Some(ref dynamic_uniform_indices) =
|
||||||
i,
|
render_resource_set.dynamic_uniform_indices
|
||||||
vertex_buffer_descriptor.name,
|
|
||||||
vertex_buffer
|
|
||||||
);
|
|
||||||
self.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
|
|
||||||
);
|
|
||||||
self.set_index_buffer(index_buffer, 0);
|
|
||||||
self.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(resource_set) =
|
|
||||||
render_resource_assignments.get_render_resource_set(bind_group.id)
|
|
||||||
{
|
|
||||||
if let Some(bind_group_info) = self.render_resources.bind_groups.get(&bind_group.id)
|
|
||||||
{
|
{
|
||||||
if let Some(wgpu_bind_group) = bind_group_info.bind_groups.get(&resource_set.id)
|
dynamic_uniform_indices.as_slice()
|
||||||
{
|
} else {
|
||||||
const EMPTY: &'static [u32] = &[];
|
EMPTY
|
||||||
let dynamic_uniform_indices = if let Some(ref dynamic_uniform_indices) =
|
|
||||||
resource_set.dynamic_uniform_indices
|
|
||||||
{
|
|
||||||
dynamic_uniform_indices.as_slice()
|
|
||||||
} else {
|
|
||||||
EMPTY
|
|
||||||
};
|
|
||||||
|
|
||||||
// don't bind bind groups if they are already set
|
|
||||||
// TODO: these checks come at a performance cost. make sure it's worth it!
|
|
||||||
if let Some(bound_render_resource_set) =
|
|
||||||
self.bound_bind_groups.get(&bind_group.index)
|
|
||||||
{
|
|
||||||
if *bound_render_resource_set == resource_set.id
|
|
||||||
&& dynamic_uniform_indices.len() == 0
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if dynamic_uniform_indices.len() == 0 {
|
|
||||||
self.bound_bind_groups
|
|
||||||
.insert(bind_group.index, resource_set.id);
|
|
||||||
} else {
|
|
||||||
self.bound_bind_groups.remove(&bind_group.index);
|
|
||||||
}
|
|
||||||
|
|
||||||
log::trace!(
|
|
||||||
"set bind group {} {:?}: {:?}",
|
|
||||||
bind_group.index,
|
|
||||||
dynamic_uniform_indices,
|
|
||||||
resource_set.id
|
|
||||||
);
|
|
||||||
self.render_pass.set_bind_group(
|
|
||||||
bind_group.index,
|
|
||||||
wgpu_bind_group,
|
|
||||||
dynamic_uniform_indices,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
log::trace!(
|
||||||
|
"set bind group {:?} {:?}: {:?}",
|
||||||
|
bind_group_descriptor.id,
|
||||||
|
dynamic_uniform_indices,
|
||||||
|
render_resource_set.id
|
||||||
|
);
|
||||||
|
self.render_pass.set_bind_group(
|
||||||
|
bind_group_descriptor.index,
|
||||||
|
wgpu_bind_group,
|
||||||
|
dynamic_uniform_indices,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
indices
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>) {
|
fn set_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>) {
|
||||||
let pipeline = self.render_resources.render_pipelines.get(&pipeline_handle).expect(
|
let pipeline = self.render_resources.render_pipelines.get(&pipeline_handle).expect(
|
||||||
"Attempted to use a pipeline that does not exist in this RenderPass's RenderContext",
|
"Attempted to use a pipeline that does not exist in this RenderPass's RenderContext",
|
||||||
|
|||||||
@ -55,10 +55,7 @@ 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();
|
let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap();
|
||||||
main_pass.add_pipeline(
|
main_pass.add_pipeline(pipeline_handle);
|
||||||
pipeline_handle,
|
|
||||||
vec![Box::new(draw_target::AssignedMeshesDrawTarget)],
|
|
||||||
);
|
|
||||||
pipeline_handle
|
pipeline_handle
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -65,10 +65,7 @@ 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();
|
let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap();
|
||||||
main_pass.add_pipeline(
|
main_pass.add_pipeline(pipeline_handle);
|
||||||
pipeline_handle,
|
|
||||||
vec![Box::new(draw_target::AssignedMeshesDrawTarget)],
|
|
||||||
);
|
|
||||||
pipeline_handle
|
pipeline_handle
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,6 @@ pub use crate::{
|
|||||||
pbr::{entity::*, light::Light, material::StandardMaterial},
|
pbr::{entity::*, light::Light, material::StandardMaterial},
|
||||||
property::{DynamicProperties, Properties, PropertiesVal, Property, PropertyVal},
|
property::{DynamicProperties, Properties, PropertiesVal, Property, PropertyVal},
|
||||||
render::{
|
render::{
|
||||||
draw_target,
|
|
||||||
entity::*,
|
entity::*,
|
||||||
mesh::{shape, Mesh},
|
mesh::{shape, Mesh},
|
||||||
pipeline::PipelineDescriptor,
|
pipeline::PipelineDescriptor,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user