Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Renderer Optimization Round 1 #958

Merged
merged 14 commits into from
Dec 1, 2020
Merged
13 changes: 13 additions & 0 deletions crates/bevy_ecs/src/core/world_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,17 @@ impl<'a> WorldBuilder<'a> {
self.current_entity = Some(self.world.spawn(components));
self
}

#[inline]
pub fn current_entity(&self) -> Option<Entity> {
cart marked this conversation as resolved.
Show resolved Hide resolved
self.current_entity
}

pub fn for_current_entity(&mut self, f: impl FnOnce(Entity)) -> &mut Self {
let current_entity = self
.current_entity
.expect("The 'current entity' is not set. You should spawn an entity first.");
f(current_entity);
self
}
}
100 changes: 70 additions & 30 deletions crates/bevy_render/src/mesh/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use crate::{
use bevy_app::prelude::{EventReader, Events};
use bevy_asset::{AssetEvent, Assets, Handle};
use bevy_core::AsBytes;
use bevy_ecs::{Local, Query, Res};
use bevy_ecs::{Changed, Entity, Local, Mut, Query, QuerySet, Res, With};
use bevy_math::*;
use bevy_reflect::TypeUuid;
use std::borrow::Cow;

use crate::pipeline::{InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor};
use bevy_utils::HashMap;
use bevy_utils::{HashMap, HashSet};

pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
Expand Down Expand Up @@ -320,17 +320,27 @@ fn remove_current_mesh_resources(
remove_resource_save(render_resource_context, handle, INDEX_BUFFER_ASSET_INDEX);
}

#[derive(Default)]
pub struct MeshEntities {
entities: HashSet<Entity>,
waiting: HashSet<Entity>,
}

#[derive(Default)]
pub struct MeshResourceProviderState {
mesh_event_reader: EventReader<AssetEvent<Mesh>>,
mesh_entities: HashMap<Handle<Mesh>, MeshEntities>,
}

pub fn mesh_resource_provider_system(
mut state: Local<MeshResourceProviderState>,
render_resource_context: Res<Box<dyn RenderResourceContext>>,
meshes: Res<Assets<Mesh>>,
mesh_events: Res<Events<AssetEvent<Mesh>>>,
mut query: Query<(&Handle<Mesh>, &mut RenderPipelines)>,
mut queries: QuerySet<(
Query<&mut RenderPipelines, With<Handle<Mesh>>>,
Query<(Entity, &Handle<Mesh>, &mut RenderPipelines), Changed<Handle<Mesh>>>,
)>,
) {
let mut changed_meshes = bevy_utils::HashSet::<Handle<Mesh>>::default();
let render_resource_context = &**render_resource_context;
Expand Down Expand Up @@ -383,39 +393,69 @@ pub fn mesh_resource_provider_system(
)),
VERTEX_ATTRIBUTE_BUFFER_ID,
);

if let Some(mesh_entities) = state.mesh_entities.get_mut(changed_mesh_handle) {
for entity in mesh_entities.waiting.drain() {
if let Ok(render_pipelines) = queries.q0_mut().get_mut(entity) {
mesh_entities.entities.insert(entity);
update_entity_mesh(
render_resource_context,
mesh,
changed_mesh_handle,
render_pipelines,
);
}
}
}
}
}

// handover buffers to pipeline
for (handle, mut render_pipelines) in query.iter_mut() {
for (entity, handle, render_pipelines) in queries.q1_mut().iter_mut() {
let mesh_entities = state
.mesh_entities
.entry(handle.clone_weak())
.or_insert_with(MeshEntities::default);
if let Some(mesh) = meshes.get(handle) {
for render_pipeline in render_pipelines.pipelines.iter_mut() {
render_pipeline.specialization.primitive_topology = mesh.primitive_topology;
// TODO: don't allocate a new vertex buffer descriptor for every entity
render_pipeline.specialization.vertex_buffer_descriptor =
mesh.get_vertex_buffer_descriptor();
render_pipeline.specialization.index_format = mesh
.indices()
.map(|i| i.into())
.unwrap_or(IndexFormat::Uint32);
}
mesh_entities.entities.insert(entity);
mesh_entities.waiting.remove(&entity);
update_entity_mesh(render_resource_context, mesh, handle, render_pipelines);
} else {
mesh_entities.waiting.insert(entity);
}
}
}

if let Some(RenderResourceId::Buffer(index_buffer_resource)) =
render_resource_context.get_asset_resource(handle, INDEX_BUFFER_ASSET_INDEX)
{
// set index buffer into binding
render_pipelines
.bindings
.set_index_buffer(index_buffer_resource);
}
fn update_entity_mesh(
render_resource_context: &dyn RenderResourceContext,
mesh: &Mesh,
handle: &Handle<Mesh>,
mut render_pipelines: Mut<RenderPipelines>,
) {
for render_pipeline in render_pipelines.pipelines.iter_mut() {
render_pipeline.specialization.primitive_topology = mesh.primitive_topology;
// TODO: don't allocate a new vertex buffer descriptor for every entity
render_pipeline.specialization.vertex_buffer_descriptor =
mesh.get_vertex_buffer_descriptor();
render_pipeline.specialization.index_format = mesh
.indices()
.map(|i| i.into())
.unwrap_or(IndexFormat::Uint32);
}

if let Some(RenderResourceId::Buffer(vertex_attribute_buffer_resource)) =
render_resource_context.get_asset_resource(handle, VERTEX_ATTRIBUTE_BUFFER_ID)
{
// set index buffer into binding
render_pipelines.bindings.vertex_attribute_buffer =
Some(vertex_attribute_buffer_resource);
}
}
if let Some(RenderResourceId::Buffer(index_buffer_resource)) =
render_resource_context.get_asset_resource(handle, INDEX_BUFFER_ASSET_INDEX)
{
// set index buffer into binding
render_pipelines
.bindings
.set_index_buffer(index_buffer_resource);
}

if let Some(RenderResourceId::Buffer(vertex_attribute_buffer_resource)) =
render_resource_context.get_asset_resource(handle, VERTEX_ATTRIBUTE_BUFFER_ID)
{
// set index buffer into binding
render_pipelines.bindings.vertex_attribute_buffer = Some(vertex_attribute_buffer_resource);
}
}
45 changes: 36 additions & 9 deletions crates/bevy_render/src/render_graph/nodes/pass_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,9 @@ where
for render_command in draw.render_commands.iter() {
match render_command {
RenderCommand::SetPipeline { pipeline } => {
// TODO: Filter pipelines
if draw_state.is_pipeline_set(pipeline.clone_weak()) {
continue;
}
render_pass.set_pipeline(pipeline);
let descriptor = pipelines.get(pipeline).unwrap();
draw_state.set_pipeline(pipeline, descriptor);
Expand Down Expand Up @@ -290,18 +292,27 @@ where
offset,
slot,
} => {
if draw_state.is_vertex_buffer_set(*slot, *buffer, *offset) {
continue;
}
render_pass.set_vertex_buffer(*slot, *buffer, *offset);
draw_state.set_vertex_buffer(*slot, *buffer);
draw_state.set_vertex_buffer(*slot, *buffer, *offset);
}
RenderCommand::SetIndexBuffer { buffer, offset } => {
if draw_state.is_index_buffer_set(*buffer, *offset) {
continue;
}
render_pass.set_index_buffer(*buffer, *offset);
draw_state.set_index_buffer(*buffer)
draw_state.set_index_buffer(*buffer, *offset)
}
RenderCommand::SetBindGroup {
index,
bind_group,
dynamic_uniform_indices,
} => {
if dynamic_uniform_indices.is_none() && draw_state.is_bind_group_set(*index, *bind_group) {
continue;
}
let pipeline = pipelines.get(draw_state.pipeline.as_ref().unwrap()).unwrap();
let layout = pipeline.get_layout().unwrap();
let bind_group_descriptor = layout.get_bind_group(*index).unwrap();
Expand Down Expand Up @@ -329,21 +340,33 @@ where
struct DrawState {
pipeline: Option<Handle<PipelineDescriptor>>,
bind_groups: Vec<Option<BindGroupId>>,
vertex_buffers: Vec<Option<BufferId>>,
index_buffer: Option<BufferId>,
vertex_buffers: Vec<Option<(BufferId, u64)>>,
index_buffer: Option<(BufferId, u64)>,
}

impl DrawState {
pub fn set_bind_group(&mut self, index: u32, bind_group: BindGroupId) {
self.bind_groups[index as usize] = Some(bind_group);
}

pub fn set_vertex_buffer(&mut self, index: u32, buffer: BufferId) {
self.vertex_buffers[index as usize] = Some(buffer);
pub fn is_bind_group_set(&self, index: u32, bind_group: BindGroupId) -> bool {
self.bind_groups[index as usize] == Some(bind_group)
}

pub fn set_vertex_buffer(&mut self, index: u32, buffer: BufferId, offset: u64) {
self.vertex_buffers[index as usize] = Some((buffer, offset));
}

pub fn set_index_buffer(&mut self, buffer: BufferId) {
self.index_buffer = Some(buffer);
pub fn is_vertex_buffer_set(&self, index: u32, buffer: BufferId, offset: u64) -> bool {
self.vertex_buffers[index as usize] == Some((buffer, offset))
}

pub fn set_index_buffer(&mut self, buffer: BufferId, offset: u64) {
self.index_buffer = Some((buffer, offset));
}

pub fn is_index_buffer_set(&self, buffer: BufferId, offset: u64) -> bool {
self.index_buffer == Some((buffer, offset))
}

pub fn can_draw(&self) -> bool {
Expand All @@ -355,6 +378,10 @@ impl DrawState {
self.can_draw() && self.index_buffer.is_some()
}

pub fn is_pipeline_set(&self, pipeline: Handle<PipelineDescriptor>) -> bool {
self.pipeline == Some(pipeline)
}

pub fn set_pipeline(
&mut self,
handle: &Handle<PipelineDescriptor>,
Expand Down
Loading