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_render::{
|
||||
base_render_graph,
|
||||
draw_target::AssignedMeshesDrawTarget,
|
||||
pipeline::PipelineDescriptor,
|
||||
render_graph::{
|
||||
nodes::{AssetUniformNode, PassNode, UniformNode},
|
||||
@ -41,10 +40,7 @@ impl ForwardPbrRenderGraphBuilder for RenderGraph {
|
||||
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)),
|
||||
vec![Box::new(AssignedMeshesDrawTarget)],
|
||||
);
|
||||
main_pass.add_pipeline(pipelines.add_default(build_forward_pipeline(&mut shaders)));
|
||||
}
|
||||
|
||||
// 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;
|
||||
mod camera;
|
||||
pub mod draw;
|
||||
pub mod entity;
|
||||
pub mod mesh;
|
||||
pub mod render_graph;
|
||||
@ -16,7 +17,6 @@ pub use renderable::*;
|
||||
pub use vertex::Vertex;
|
||||
|
||||
pub mod base_render_graph;
|
||||
pub mod draw_target;
|
||||
pub mod pass;
|
||||
pub mod pipeline;
|
||||
pub mod render_resource;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
pipeline::PipelineDescriptor,
|
||||
render_resource::{RenderResourceId, RenderResourceAssignments},
|
||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
||||
render_resource::{RenderResourceId, RenderResourceSet},
|
||||
renderer::RenderContext,
|
||||
};
|
||||
use bevy_asset::Handle;
|
||||
@ -15,10 +15,9 @@ pub trait RenderPass {
|
||||
fn set_stencil_reference(&mut self, reference: 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>);
|
||||
// TODO: try to somehow take into account the "set" pipeline instead of passing it in here
|
||||
fn set_render_resources(
|
||||
fn set_bind_group(
|
||||
&mut self,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
) -> Option<Range<u32>>;
|
||||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
render_resource_set: &RenderResourceSet,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,18 +1,22 @@
|
||||
use crate::{
|
||||
draw_target::DrawTarget,
|
||||
pass::{PassDescriptor, TextureAttachment},
|
||||
pipeline::{PipelineCompiler, PipelineDescriptor},
|
||||
pass::{PassDescriptor, RenderPass, TextureAttachment},
|
||||
pipeline::{PipelineAssignments, PipelineCompiler, PipelineDescriptor},
|
||||
render_graph::{Node, ResourceSlotInfo, ResourceSlots},
|
||||
render_resource::{ResourceInfo, RenderResourceAssignments},
|
||||
render_resource::{
|
||||
EntitiesWaitingForAssets, EntityRenderResourceAssignments, RenderResourceAssignments,
|
||||
ResourceInfo,
|
||||
},
|
||||
renderer::RenderContext,
|
||||
shader::Shader,
|
||||
Renderable,
|
||||
};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use legion::prelude::*;
|
||||
use std::ops::Range;
|
||||
|
||||
pub struct PassNode {
|
||||
descriptor: PassDescriptor,
|
||||
pipelines: Vec<(Handle<PipelineDescriptor>, Vec<Box<dyn DrawTarget>>)>,
|
||||
pipelines: Vec<Handle<PipelineDescriptor>>,
|
||||
inputs: Vec<ResourceSlotInfo>,
|
||||
color_attachment_input_indices: Vec<Option<usize>>,
|
||||
depth_stencil_attachment_input_index: Option<usize>,
|
||||
@ -54,12 +58,64 @@ impl PassNode {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_pipeline(
|
||||
&mut self,
|
||||
pipeline_handle: Handle<PipelineDescriptor>,
|
||||
draw_targets: Vec<Box<dyn DrawTarget>>,
|
||||
) {
|
||||
self.pipelines.push((pipeline_handle, draw_targets));
|
||||
pub fn add_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>) {
|
||||
self.pipelines.push(pipeline_handle);
|
||||
}
|
||||
|
||||
fn set_render_resources(
|
||||
render_pass: &mut dyn RenderPass,
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
render_resource_assignments: &RenderResourceAssignments,
|
||||
) -> Option<Range<u32>> {
|
||||
let pipeline_layout = pipeline_descriptor.get_layout().unwrap();
|
||||
// PERF: vertex buffer lookup comes at a cost when vertex buffers aren't in render_resource_assignments. iterating over render_resource_assignment vertex buffers
|
||||
// would likely be faster
|
||||
let mut indices = None;
|
||||
for (i, vertex_buffer_descriptor) in
|
||||
pipeline_layout.vertex_buffer_descriptors.iter().enumerate()
|
||||
{
|
||||
if let Some((vertex_buffer, index_buffer)) =
|
||||
render_resource_assignments.get_vertex_buffer(&vertex_buffer_descriptor.name)
|
||||
{
|
||||
log::trace!(
|
||||
"set vertex buffer {}: {} ({:?})",
|
||||
i,
|
||||
vertex_buffer_descriptor.name,
|
||||
vertex_buffer
|
||||
);
|
||||
render_pass.set_vertex_buffer(i as u32, vertex_buffer, 0);
|
||||
if let Some(index_buffer) = index_buffer {
|
||||
log::trace!(
|
||||
"set index buffer: {} ({:?})",
|
||||
vertex_buffer_descriptor.name,
|
||||
index_buffer
|
||||
);
|
||||
render_pass.set_index_buffer(index_buffer, 0);
|
||||
render_pass
|
||||
.get_render_context()
|
||||
.resources()
|
||||
.get_resource_info(
|
||||
index_buffer,
|
||||
&mut |resource_info| match resource_info {
|
||||
Some(ResourceInfo::Buffer(Some(buffer_info))) => {
|
||||
indices = Some(0..(buffer_info.size / 2) as u32)
|
||||
}
|
||||
_ => panic!("expected a buffer type"),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for bind_group in pipeline_layout.bind_groups.iter() {
|
||||
if let Some(render_resource_set) =
|
||||
render_resource_assignments.get_render_resource_set(bind_group.id)
|
||||
{
|
||||
render_pass.set_bind_group(bind_group, &render_resource_set);
|
||||
}
|
||||
}
|
||||
|
||||
indices
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,6 +134,12 @@ impl Node for PassNode {
|
||||
) {
|
||||
let pipeline_compiler = resources.get::<PipelineCompiler>().unwrap();
|
||||
let pipelines = resources.get::<Assets<PipelineDescriptor>>().unwrap();
|
||||
let shader_pipeline_assignments = resources.get::<PipelineAssignments>().unwrap();
|
||||
let entity_render_resource_assignments =
|
||||
resources.get::<EntityRenderResourceAssignments>().unwrap();
|
||||
let entities_waiting_for_assets = resources.get::<EntitiesWaitingForAssets>().unwrap();
|
||||
let mut render_resource_assignments =
|
||||
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||
|
||||
for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() {
|
||||
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());
|
||||
}
|
||||
|
||||
let shaders = resources.get::<Assets<Shader>>().unwrap();
|
||||
for (pipeline_handle, draw_targets) in self.pipelines.iter_mut() {
|
||||
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 render_resource_context = render_context.resources();
|
||||
|
||||
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
|
||||
let mut render_resource_assignments =
|
||||
resources.get_mut::<RenderResourceAssignments>().unwrap();
|
||||
for bind_group in pipeline_layout.bind_groups.iter() {
|
||||
render_resource_assignments.update_render_resource_set_id(bind_group);
|
||||
// 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_context.resources().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,
|
||||
render_resource_context.create_render_pipeline(
|
||||
*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(
|
||||
&self.descriptor,
|
||||
&render_resource_assignments,
|
||||
&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) =
|
||||
pipeline_compiler.iter_compiled_pipelines(*pipeline_handle)
|
||||
{
|
||||
@ -145,14 +228,45 @@ impl Node for PassNode {
|
||||
let compiled_pipeline_descriptor =
|
||||
pipelines.get(compiled_pipeline_handle).unwrap();
|
||||
render_pass.set_pipeline(*compiled_pipeline_handle);
|
||||
for draw_target in draw_targets.iter() {
|
||||
draw_target.draw(
|
||||
world,
|
||||
resources,
|
||||
render_pass,
|
||||
*compiled_pipeline_handle,
|
||||
compiled_pipeline_descriptor,
|
||||
);
|
||||
|
||||
// set global render resources
|
||||
Self::set_render_resources(
|
||||
render_pass,
|
||||
compiled_pipeline_descriptor,
|
||||
&render_resource_assignments,
|
||||
);
|
||||
|
||||
// draw entities assigned to this pipeline
|
||||
let assigned_render_resource_assignments = shader_pipeline_assignments
|
||||
.assignments
|
||||
.get(&compiled_pipeline_handle);
|
||||
|
||||
if let Some(assigned_render_resource_assignments) =
|
||||
assigned_render_resource_assignments
|
||||
{
|
||||
for assignment_id in assigned_render_resource_assignments.iter() {
|
||||
// TODO: hopefully legion has better random access apis that are more like queries?
|
||||
let entity = entity_render_resource_assignments
|
||||
.get(*assignment_id)
|
||||
.unwrap();
|
||||
let renderable =
|
||||
world.get_component::<Renderable>(*entity).unwrap();
|
||||
if !renderable.is_visible
|
||||
|| renderable.is_instanced
|
||||
|| entities_waiting_for_assets.contains(entity)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// set local render resources
|
||||
if let Some(indices) = Self::set_render_resources(
|
||||
render_pass,
|
||||
compiled_pipeline_descriptor,
|
||||
&renderable.render_resource_assignments,
|
||||
) {
|
||||
render_pass.draw_indexed(indices, 0, 0..1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ use crate::{ColorMaterial, Quad, TextureAtlas, TextureAtlasSprite};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_render::{
|
||||
base_render_graph,
|
||||
draw_target::AssignedMeshesDrawTarget,
|
||||
pipeline::{state_descriptors::*, PipelineDescriptor},
|
||||
render_graph::{
|
||||
nodes::{AssetUniformNode, PassNode, UniformNode},
|
||||
@ -153,14 +152,8 @@ impl SpriteRenderGraphBuilder for RenderGraph {
|
||||
let main_pass: &mut PassNode = self
|
||||
.get_node_mut(base_render_graph::node::MAIN_PASS)
|
||||
.unwrap();
|
||||
main_pass.add_pipeline(
|
||||
SPRITE_PIPELINE_HANDLE,
|
||||
vec![Box::new(AssignedMeshesDrawTarget)],
|
||||
);
|
||||
main_pass.add_pipeline(
|
||||
SPRITE_SHEET_PIPELINE_HANDLE,
|
||||
vec![Box::new(AssignedMeshesDrawTarget)],
|
||||
);
|
||||
main_pass.add_pipeline(SPRITE_PIPELINE_HANDLE);
|
||||
main_pass.add_pipeline(SPRITE_SHEET_PIPELINE_HANDLE);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_render::{
|
||||
base_render_graph,
|
||||
draw_target::AssignedMeshesDrawTarget,
|
||||
pipeline::{state_descriptors::*, PipelineDescriptor},
|
||||
render_graph::{
|
||||
nodes::{CameraNode, PassNode},
|
||||
@ -83,7 +82,7 @@ impl UiRenderGraphBuilder for RenderGraph {
|
||||
let main_pass: &mut PassNode = self
|
||||
.get_node_mut(base_render_graph::node::MAIN_PASS)
|
||||
.unwrap();
|
||||
main_pass.add_pipeline(UI_PIPELINE_HANDLE, vec![Box::new(AssignedMeshesDrawTarget)]);
|
||||
main_pass.add_pipeline(UI_PIPELINE_HANDLE);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,12 +6,12 @@ use bevy_render::{
|
||||
PassDescriptor, RenderPass, RenderPassColorAttachmentDescriptor,
|
||||
RenderPassDepthStencilAttachmentDescriptor, TextureAttachment,
|
||||
},
|
||||
render_resource::{RenderResourceId, RenderResourceAssignment, RenderResourceAssignments},
|
||||
render_resource::{RenderResourceAssignment, RenderResourceAssignments, RenderResourceId},
|
||||
renderer::{RenderContext, RenderResourceContext},
|
||||
texture::Extent3d,
|
||||
};
|
||||
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LazyCommandEncoder {
|
||||
@ -138,10 +138,10 @@ impl RenderContext for WgpuRenderContext {
|
||||
&mut encoder,
|
||||
);
|
||||
let mut wgpu_render_pass = WgpuRenderPass {
|
||||
render_context: self,
|
||||
render_pass,
|
||||
render_context: self,
|
||||
render_resources: refs,
|
||||
bound_bind_groups: HashMap::default(),
|
||||
pipeline_descriptor: None,
|
||||
};
|
||||
|
||||
run_pass(&mut wgpu_render_pass);
|
||||
|
||||
@ -2,19 +2,17 @@ use crate::{renderer::WgpuRenderContext, WgpuResourceRefs};
|
||||
use bevy_asset::Handle;
|
||||
use bevy_render::{
|
||||
pass::RenderPass,
|
||||
pipeline::PipelineDescriptor,
|
||||
render_resource::{
|
||||
RenderResourceId, RenderResourceAssignments, RenderResourceSetId, ResourceInfo,
|
||||
},
|
||||
pipeline::{BindGroupDescriptor, PipelineDescriptor},
|
||||
render_resource::{RenderResourceId, RenderResourceSet},
|
||||
renderer::RenderContext,
|
||||
};
|
||||
use std::{collections::HashMap, ops::Range};
|
||||
use std::ops::Range;
|
||||
|
||||
pub struct WgpuRenderPass<'a> {
|
||||
pub render_pass: wgpu::RenderPass<'a>,
|
||||
pub render_context: &'a WgpuRenderContext,
|
||||
pub render_resources: WgpuResourceRefs<'a>,
|
||||
pub bound_bind_groups: HashMap<u32, RenderResourceSetId>,
|
||||
pub pipeline_descriptor: Option<&'a PipelineDescriptor>,
|
||||
}
|
||||
|
||||
impl<'a> RenderPass for WgpuRenderPass<'a> {
|
||||
@ -51,102 +49,42 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
|
||||
self.render_pass.draw(vertices, instances);
|
||||
}
|
||||
|
||||
fn set_render_resources(
|
||||
fn set_bind_group(
|
||||
&mut self,
|
||||
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()
|
||||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
render_resource_set: &RenderResourceSet,
|
||||
) {
|
||||
if let Some(bind_group_info) = self
|
||||
.render_resources
|
||||
.bind_groups
|
||||
.get(&bind_group_descriptor.id)
|
||||
{
|
||||
if let Some((vertex_buffer, index_buffer)) =
|
||||
render_resource_assignments.get_vertex_buffer(&vertex_buffer_descriptor.name)
|
||||
if let Some(wgpu_bind_group) = bind_group_info.bind_groups.get(&render_resource_set.id)
|
||||
{
|
||||
log::trace!(
|
||||
"set vertex buffer {}: {} ({:?})",
|
||||
i,
|
||||
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)
|
||||
const EMPTY: &'static [u32] = &[];
|
||||
let dynamic_uniform_indices = if let Some(ref dynamic_uniform_indices) =
|
||||
render_resource_set.dynamic_uniform_indices
|
||||
{
|
||||
if let Some(wgpu_bind_group) = bind_group_info.bind_groups.get(&resource_set.id)
|
||||
{
|
||||
const EMPTY: &'static [u32] = &[];
|
||||
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,
|
||||
);
|
||||
}
|
||||
dynamic_uniform_indices.as_slice()
|
||||
} else {
|
||||
EMPTY
|
||||
};
|
||||
|
||||
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>) {
|
||||
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",
|
||||
|
||||
@ -55,10 +55,7 @@ fn setup(
|
||||
|
||||
render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true));
|
||||
let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap();
|
||||
main_pass.add_pipeline(
|
||||
pipeline_handle,
|
||||
vec![Box::new(draw_target::AssignedMeshesDrawTarget)],
|
||||
);
|
||||
main_pass.add_pipeline(pipeline_handle);
|
||||
pipeline_handle
|
||||
};
|
||||
|
||||
|
||||
@ -65,10 +65,7 @@ fn setup(
|
||||
}));
|
||||
render_graph.add_system_node("my_material", AssetUniformNode::<MyMaterial>::new(true));
|
||||
let main_pass: &mut PassNode = render_graph.get_node_mut("main_pass").unwrap();
|
||||
main_pass.add_pipeline(
|
||||
pipeline_handle,
|
||||
vec![Box::new(draw_target::AssignedMeshesDrawTarget)],
|
||||
);
|
||||
main_pass.add_pipeline(pipeline_handle);
|
||||
pipeline_handle
|
||||
};
|
||||
|
||||
|
||||
@ -14,7 +14,6 @@ pub use crate::{
|
||||
pbr::{entity::*, light::Light, material::StandardMaterial},
|
||||
property::{DynamicProperties, Properties, PropertiesVal, Property, PropertyVal},
|
||||
render::{
|
||||
draw_target,
|
||||
entity::*,
|
||||
mesh::{shape, Mesh},
|
||||
pipeline::PipelineDescriptor,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user