update mesh on gpu when it changes

This commit is contained in:
Carter Anderson 2020-05-16 00:21:04 -07:00
parent 5d0d3d28c7
commit fcc0a6303b
14 changed files with 173 additions and 95 deletions

View File

@ -143,7 +143,7 @@ impl AssetServer {
let loader = resources.get::<Box<dyn AssetLoader<T>>>().unwrap(); let loader = resources.get::<Box<dyn AssetLoader<T>>>().unwrap();
let asset = loader.load_from_file(&asset_path)?; let asset = loader.load_from_file(&asset_path)?;
let handle = Handle::from(handle_id); let handle = Handle::from(handle_id);
assets.add_with_handle(handle, asset); assets.set(handle, asset);
assets.set_path(handle, &asset_path.path); assets.set_path(handle, &asset_path.path);
Ok(handle) Ok(handle)
} else { } else {

View File

@ -9,6 +9,7 @@ use std::collections::HashMap;
pub enum AssetEvent<T> { pub enum AssetEvent<T> {
Created { handle: Handle<T> }, Created { handle: Handle<T> },
Modified { handle: Handle<T> },
} }
pub struct Assets<T> { pub struct Assets<T> {
@ -40,15 +41,26 @@ impl<T> Assets<T> {
handle handle
} }
pub fn add_with_handle(&mut self, handle: Handle<T>, asset: T) { pub fn set(&mut self, handle: Handle<T>, asset: T) {
let exists = self.assets.contains_key(&handle.id);
self.assets.insert(handle.id, asset); self.assets.insert(handle.id, asset);
self.events.send(AssetEvent::Created { handle });
if exists {
self.events.send(AssetEvent::Modified { handle });
} else {
self.events.send(AssetEvent::Created { handle });
}
} }
pub fn add_default(&mut self, asset: T) -> Handle<T> { pub fn add_default(&mut self, asset: T) -> Handle<T> {
let exists = self.assets.contains_key(&DEFAULT_HANDLE_ID);
self.assets.insert(DEFAULT_HANDLE_ID, asset); self.assets.insert(DEFAULT_HANDLE_ID, asset);
let handle = Handle::default(); let handle = Handle::default();
self.events.send(AssetEvent::Created { handle }); if exists {
self.events.send(AssetEvent::Modified { handle });
} else {
self.events.send(AssetEvent::Created { handle });
}
handle handle
} }
@ -111,7 +123,7 @@ impl AddAsset for AppBuilder {
{ {
self.init_resource::<Assets<T>>() self.init_resource::<Assets<T>>()
.add_system_to_stage( .add_system_to_stage(
stage::EVENT_UPDATE, stage::POST_UPDATE,
Assets::<T>::asset_event_system.system(), Assets::<T>::asset_event_system.system(),
) )
.add_event::<AssetEvent<T>>() .add_event::<AssetEvent<T>>()

View File

@ -53,7 +53,7 @@ pub fn update_asset_storage_system<T>(
match asset_channel.receiver.try_recv() { match asset_channel.receiver.try_recv() {
Ok(result) => { Ok(result) => {
let asset = result.result.unwrap(); let asset = result.result.unwrap();
assets.add_with_handle(result.handle, asset); assets.set(result.handle, asset);
assets.set_path(result.handle, &result.path.path); assets.set_path(result.handle, &result.path.path);
} }
Err(TryRecvError::Empty) => { Err(TryRecvError::Empty) => {

View File

@ -73,7 +73,6 @@ impl AppPlugin for RenderPlugin {
app.add_stage_after(stage::POST_UPDATE, RENDER_RESOURCE_STAGE) app.add_stage_after(stage::POST_UPDATE, RENDER_RESOURCE_STAGE)
.add_stage_after(RENDER_RESOURCE_STAGE, RENDER_STAGE) .add_stage_after(RENDER_RESOURCE_STAGE, RENDER_STAGE)
// resources
.add_asset::<Mesh>() .add_asset::<Mesh>()
.add_asset::<Texture>() .add_asset::<Texture>()
.add_asset::<Shader>() .add_asset::<Shader>()
@ -86,12 +85,9 @@ impl AppPlugin for RenderPlugin {
.init_resource::<VertexBufferDescriptors>() .init_resource::<VertexBufferDescriptors>()
.init_resource::<EntityRenderResourceAssignments>() .init_resource::<EntityRenderResourceAssignments>()
.init_resource::<EntitiesWaitingForAssets>() .init_resource::<EntitiesWaitingForAssets>()
// core systems
.add_system(entity_render_resource_assignments_system()) .add_system(entity_render_resource_assignments_system())
.init_system_to_stage(stage::POST_UPDATE, camera::camera_update_system) .init_system_to_stage(stage::POST_UPDATE, camera::camera_update_system)
.add_system_to_stage(stage::POST_UPDATE, mesh::mesh_specializer_system())
.add_system_to_stage(stage::PRE_UPDATE, EntitiesWaitingForAssets::clear_system.system()) .add_system_to_stage(stage::PRE_UPDATE, EntitiesWaitingForAssets::clear_system.system())
// render resource provider systems
.init_system_to_stage(RENDER_RESOURCE_STAGE, mesh_resource_provider_system); .init_system_to_stage(RENDER_RESOURCE_STAGE, mesh_resource_provider_system);
} }
} }

View File

@ -3,15 +3,16 @@ use crate::{
state_descriptors::{IndexFormat, PrimitiveTopology}, state_descriptors::{IndexFormat, PrimitiveTopology},
VertexBufferDescriptor, VertexBufferDescriptors, VertexFormat, VertexBufferDescriptor, VertexBufferDescriptors, VertexFormat,
}, },
render_resource::{BufferInfo, BufferUsage, RenderResourceAssignments, EntitiesWaitingForAssets}, render_resource::{BufferInfo, BufferUsage, EntitiesWaitingForAssets},
renderer::{RenderResourceContext, RenderResources}, renderer::{RenderResourceContext, RenderResources},
shader::AsUniforms, shader::AsUniforms,
Renderable, Vertex, Renderable, Vertex,
}; };
use bevy_asset::{Assets, Handle}; use bevy_app::Events;
use bevy_asset::{AssetEvent, Assets, Handle};
use glam::*; use glam::*;
use legion::prelude::*; use legion::prelude::*;
use std::borrow::Cow; use std::{borrow::Cow, collections::HashSet};
use thiserror::Error; use thiserror::Error;
use zerocopy::AsBytes; use zerocopy::AsBytes;
@ -170,41 +171,50 @@ pub mod shape {
use crate::pipeline::state_descriptors::PrimitiveTopology; use crate::pipeline::state_descriptors::PrimitiveTopology;
use glam::*; use glam::*;
pub struct Cube; pub struct Cube {
pub size: f32,
}
impl Default for Cube {
fn default() -> Self {
Cube { size: 1.0 }
}
}
impl From<Cube> for Mesh { impl From<Cube> for Mesh {
fn from(_: Cube) -> Self { fn from(cube: Cube) -> Self {
let size = cube.size;
let vertices = &[ let vertices = &[
// top (0., 0., 1.) // top (0., 0., size)
([-1., -1., 1.], [0., 0., 1.], [0., 0.]), ([-size, -size, size], [0., 0., size], [0., 0.]),
([1., -1., 1.], [0., 0., 1.], [1., 0.]), ([size, -size, size], [0., 0., size], [size, 0.]),
([1., 1., 1.], [0., 0., 1.], [1., 1.]), ([size, size, size], [0., 0., size], [size, size]),
([-1., 1., 1.], [0., 0., 1.], [0., 1.]), ([-size, size, size], [0., 0., size], [0., size]),
// bottom (0., 0., -1.) // bottom (0., 0., -size)
([-1., 1., -1.], [0., 0., -1.], [1., 0.]), ([-size, size, -size], [0., 0., -size], [size, 0.]),
([1., 1., -1.], [0., 0., -1.], [0., 0.]), ([size, size, -size], [0., 0., -size], [0., 0.]),
([1., -1., -1.], [0., 0., -1.], [0., 1.]), ([size, -size, -size], [0., 0., -size], [0., size]),
([-1., -1., -1.], [0., 0., -1.], [1., 1.]), ([-size, -size, -size], [0., 0., -size], [size, size]),
// right (1., 0., 0.) // right (size, 0., 0.)
([1., -1., -1.], [1., 0., 0.], [0., 0.]), ([size, -size, -size], [size, 0., 0.], [0., 0.]),
([1., 1., -1.], [1., 0., 0.], [1., 0.]), ([size, size, -size], [size, 0., 0.], [size, 0.]),
([1., 1., 1.], [1., 0., 0.], [1., 1.]), ([size, size, size], [size, 0., 0.], [size, size]),
([1., -1., 1.], [1., 0., 0.], [0., 1.]), ([size, -size, size], [size, 0., 0.], [0., size]),
// left (-1., 0., 0.) // left (-size, 0., 0.)
([-1., -1., 1.], [-1., 0., 0.], [1., 0.]), ([-size, -size, size], [-size, 0., 0.], [size, 0.]),
([-1., 1., 1.], [-1., 0., 0.], [0., 0.]), ([-size, size, size], [-size, 0., 0.], [0., 0.]),
([-1., 1., -1.], [-1., 0., 0.], [0., 1.]), ([-size, size, -size], [-size, 0., 0.], [0., size]),
([-1., -1., -1.], [-1., 0., 0.], [1., 1.]), ([-size, -size, -size], [-size, 0., 0.], [size, size]),
// front (0., 1., 0.) // front (0., size, 0.)
([1., 1., -1.], [0., 1., 0.], [1., 0.]), ([size, size, -size], [0., size, 0.], [size, 0.]),
([-1., 1., -1.], [0., 1., 0.], [0., 0.]), ([-size, size, -size], [0., size, 0.], [0., 0.]),
([-1., 1., 1.], [0., 1., 0.], [0., 1.]), ([-size, size, size], [0., size, 0.], [0., size]),
([1., 1., 1.], [0., 1., 0.], [1., 1.]), ([size, size, size], [0., size, 0.], [size, size]),
// back (0., -1., 0.) // back (0., -size, 0.)
([1., -1., 1.], [0., -1., 0.], [0., 0.]), ([size, -size, size], [0., -size, 0.], [0., 0.]),
([-1., -1., 1.], [0., -1., 0.], [1., 0.]), ([-size, -size, size], [0., -size, 0.], [size, 0.]),
([-1., -1., -1.], [0., -1., 0.], [1., 1.]), ([-size, -size, -size], [0., -size, 0.], [size, size]),
([1., -1., -1.], [0., -1., 0.], [0., 1.]), ([size, -size, -size], [0., -size, 0.], [0., size]),
]; ];
let mut positions = Vec::new(); let mut positions = Vec::new();
@ -310,45 +320,32 @@ pub mod shape {
} }
} }
pub fn mesh_specializer_system() -> Box<dyn Schedulable> {
SystemBuilder::new("mesh_specializer")
.read_resource::<Assets<Mesh>>()
.with_query(
<(Read<Handle<Mesh>>, Write<Renderable>)>::query()
.filter(changed::<Handle<Mesh>>() | changed::<Renderable>()),
)
.build(|_, world, meshes, query| {
for (mesh_handle, mut renderable) in query.iter_mut(world) {
if let Some(mesh) = meshes.get(&mesh_handle) {
renderable
.render_resource_assignments
.pipeline_specialization
.primitive_topology = mesh.primitive_topology;
}
}
})
}
fn setup_mesh_resource( fn setup_mesh_resource(
render_resources: &dyn RenderResourceContext, render_resources: &dyn RenderResourceContext,
render_resource_assignments: &mut RenderResourceAssignments, renderable: &mut Renderable,
vertex_buffer_descriptor: &VertexBufferDescriptor, vertex_buffer_descriptor: &VertexBufferDescriptor,
entities_waiting_for_assets: &EntitiesWaitingForAssets, entities_waiting_for_assets: &EntitiesWaitingForAssets,
entity: Entity, entity: Entity,
handle: Handle<Mesh>, handle: Handle<Mesh>,
meshes: &Assets<Mesh>, meshes: &Assets<Mesh>,
mesh_changed: bool,
) { ) {
log::trace!("setup mesh for {:?}", render_resource_assignments.id); log::trace!(
"setup mesh for {:?}",
renderable.render_resource_assignments.id
);
let index_format = IndexFormat::Uint16; let index_format = IndexFormat::Uint16;
let (vertex_buffer, index_buffer) = if let Some(vertex_buffer) = let (vertex_buffer, index_buffer) = if mesh_changed
render_resources.get_asset_resource(handle, VERTEX_BUFFER_ASSET_INDEX) || render_resources
.get_asset_resource(handle, VERTEX_BUFFER_ASSET_INDEX)
.is_none()
{ {
(
vertex_buffer,
render_resources.get_asset_resource(handle, INDEX_BUFFER_ASSET_INDEX),
)
} else {
if let Some(mesh_asset) = meshes.get(&handle) { if let Some(mesh_asset) = meshes.get(&handle) {
renderable
.render_resource_assignments
.pipeline_specialization
.primitive_topology = mesh_asset.primitive_topology;
let vertex_bytes = mesh_asset let vertex_bytes = mesh_asset
.get_vertex_buffer_bytes(&vertex_buffer_descriptor) .get_vertex_buffer_bytes(&vertex_buffer_descriptor)
.unwrap(); .unwrap();
@ -377,35 +374,108 @@ fn setup_mesh_resource(
entities_waiting_for_assets.add(entity); entities_waiting_for_assets.add(entity);
return; return;
} }
} else if let Some(vertex_buffer) =
render_resources.get_asset_resource(handle, VERTEX_BUFFER_ASSET_INDEX)
{
(
vertex_buffer,
render_resources.get_asset_resource(handle, INDEX_BUFFER_ASSET_INDEX),
)
} else {
panic!("This should never be reached. The current 'if let' limitations make this case required.")
}; };
render_resource_assignments.set_vertex_buffer("Vertex", vertex_buffer, index_buffer); renderable
.render_resource_assignments
.set_vertex_buffer("Vertex", vertex_buffer, index_buffer);
} }
pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Schedulable> { pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Schedulable> {
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap(); let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
let mesh_events = resources.get::<Events<AssetEvent<Mesh>>>().unwrap();
let mut mesh_event_reader = mesh_events.get_reader();
// TODO: allow pipelines to specialize on vertex_buffer_descriptor and index_format // TODO: allow pipelines to specialize on vertex_buffer_descriptor and index_format
let vertex_buffer_descriptor = Vertex::get_vertex_buffer_descriptor().unwrap(); let vertex_buffer_descriptor = Vertex::get_vertex_buffer_descriptor().unwrap();
vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone()); vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone());
SystemBuilder::new("mesh_resource_provider") SystemBuilder::new("mesh_resource_provider")
.read_resource::<RenderResources>() .read_resource::<RenderResources>()
.read_resource::<Assets<Mesh>>() .read_resource::<Assets<Mesh>>()
.read_resource::<EntitiesWaitingForAssets>() .read_resource::<Events<AssetEvent<Mesh>>>()
.with_query(<(Read<Handle<Mesh>>, Write<Renderable>)>::query()) .with_query(<(Read<Handle<Mesh>>, Write<Renderable>)>::query())
.build( .build(
move |_, world, (render_resource_context, meshes, entities_waiting_for_assets), query| { move |_,
world,
(render_resource_context, meshes, mesh_events),
query| {
let render_resources = &*render_resource_context.context; let render_resources = &*render_resource_context.context;
let changed_meshes = mesh_event_reader
.iter(&mesh_events)
.map(|e| match e {
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
Some(handle)
}
})
.filter(|h| h.is_some())
.map(|h| *h.unwrap())
.collect::<HashSet<Handle<Mesh>>>();
for changed_mesh_handle in changed_meshes.iter() {
if let Some(mesh) = meshes.get(changed_mesh_handle) {
let vertex_bytes = mesh
.get_vertex_buffer_bytes(&vertex_buffer_descriptor)
.unwrap();
// TODO: use a staging buffer here
let vertex_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::VERTEX,
..Default::default()
},
&vertex_bytes,
);
let index_bytes = mesh.get_index_buffer_bytes(IndexFormat::Uint16).unwrap();
let index_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::INDEX,
..Default::default()
},
&index_bytes,
);
render_resources.set_asset_resource(
*changed_mesh_handle,
vertex_buffer,
VERTEX_BUFFER_ASSET_INDEX,
);
render_resources.set_asset_resource(
*changed_mesh_handle,
index_buffer,
INDEX_BUFFER_ASSET_INDEX,
);
}
}
// 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 (entity, (handle, mut renderable)) in query.iter_entities_mut(world) { for (handle, mut renderable) in query.iter_mut(world) {
setup_mesh_resource( if let Some(mesh) = meshes.get(&handle) {
render_resources, renderable
&mut renderable.render_resource_assignments, .render_resource_assignments
&vertex_buffer_descriptor, .pipeline_specialization
entities_waiting_for_assets, .primitive_topology = mesh.primitive_topology;
entity, }
*handle,
&meshes, if let Some(vertex_buffer) =
); render_resources.get_asset_resource(*handle, VERTEX_BUFFER_ASSET_INDEX)
{
let index_buffer =
render_resources.get_asset_resource(*handle, INDEX_BUFFER_ASSET_INDEX);
renderable.render_resource_assignments.set_vertex_buffer(
"Vertex",
vertex_buffer,
index_buffer,
);
}
} }
}, },
) )

View File

@ -48,7 +48,7 @@ impl AppPlugin for UiPlugin {
render_graph.add_ui_graph(resources); render_graph.add_ui_graph(resources);
let mut meshes = resources.get_mut::<Assets<Mesh>>().unwrap(); let mut meshes = resources.get_mut::<Assets<Mesh>>().unwrap();
meshes.add_with_handle( meshes.set(
QUAD_HANDLE, QUAD_HANDLE,
Mesh::from(Quad { Mesh::from(Quad {
size: Vec2::new(1.0, 1.0), size: Vec2::new(1.0, 1.0),

View File

@ -78,7 +78,7 @@ impl UiRenderGraphBuilder for RenderGraph {
.unwrap(); .unwrap();
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.add_with_handle(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders)); pipelines.set(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders));
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();

View File

@ -21,7 +21,7 @@ fn setup(
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
) { ) {
let cube_handle = meshes.add(Mesh::from(shape::Cube)); let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
let cube_material_handle = materials.add(StandardMaterial { let cube_material_handle = materials.add(StandardMaterial {
albedo: Color::rgb(0.5, 0.4, 0.3), albedo: Color::rgb(0.5, 0.4, 0.3),
..Default::default() ..Default::default()

View File

@ -14,7 +14,7 @@ fn setup(
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
) { ) {
// create a cube and a plane mesh // create a cube and a plane mesh
let cube_handle = meshes.add(Mesh::from(shape::Cube)); let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
let plane_handle = meshes.add(Mesh::from(shape::Plane { size: 10.0 })); let plane_handle = meshes.add(Mesh::from(shape::Plane { size: 10.0 }));
// create materials for our cube and plane // create materials for our cube and plane

View File

@ -30,7 +30,7 @@ fn setup(
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
) { ) {
let cube_handle = meshes.add(Mesh::from(shape::Cube)); let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
let plane_handle = meshes.add(Mesh::from(shape::Plane { size: 10.0 })); let plane_handle = meshes.add(Mesh::from(shape::Plane { size: 10.0 }));
let cube_material_handle = materials.add(StandardMaterial { let cube_material_handle = materials.add(StandardMaterial {
albedo: Color::rgb(0.5, 0.4, 0.3), albedo: Color::rgb(0.5, 0.4, 0.3),

View File

@ -14,7 +14,7 @@ fn setup(
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
) { ) {
let cube_handle = meshes.add(Mesh::from(shape::Cube)); let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
let cube_material_handle = materials.add(StandardMaterial { let cube_material_handle = materials.add(StandardMaterial {
albedo: Color::rgb(0.5, 0.4, 0.3), albedo: Color::rgb(0.5, 0.4, 0.3),
..Default::default() ..Default::default()

View File

@ -65,7 +65,7 @@ fn setup(
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
) { ) {
let cube_handle = meshes.add(Mesh::from(shape::Cube)); let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
let cube_material_handle = materials.add(StandardMaterial { let cube_material_handle = materials.add(StandardMaterial {
albedo: Color::rgb(0.5, 0.4, 0.3), albedo: Color::rgb(0.5, 0.4, 0.3),
..Default::default() ..Default::default()

View File

@ -68,7 +68,7 @@ fn setup(
let material = materials.add(MyMaterial { let material = materials.add(MyMaterial {
color: Color::rgb(0.0, 0.8, 0.0), color: Color::rgb(0.0, 0.8, 0.0),
}); });
let cube_handle = meshes.add(Mesh::from(shape::Cube)); let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
command_buffer command_buffer
.build() .build()

View File

@ -84,7 +84,7 @@ fn setup(
always_red: true, always_red: true,
}); });
let cube_handle = meshes.add(Mesh::from(shape::Cube)); let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
command_buffer command_buffer
.build() .build()