2021-04-11 20:13:07 +00:00
|
|
|
pub mod camera;
|
|
|
|
pub mod color;
|
|
|
|
pub mod mesh;
|
2021-06-25 03:04:28 +00:00
|
|
|
pub mod render_asset;
|
2021-04-11 20:13:07 +00:00
|
|
|
pub mod render_graph;
|
2021-06-02 02:59:17 +00:00
|
|
|
pub mod render_phase;
|
2021-04-11 20:13:07 +00:00
|
|
|
pub mod render_resource;
|
|
|
|
pub mod renderer;
|
|
|
|
pub mod shader;
|
|
|
|
pub mod texture;
|
2021-06-02 02:59:17 +00:00
|
|
|
pub mod view;
|
2021-04-11 20:13:07 +00:00
|
|
|
|
2021-07-28 17:52:24 +00:00
|
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
|
2021-04-11 20:13:07 +00:00
|
|
|
pub use once_cell;
|
2021-06-21 23:28:52 +00:00
|
|
|
use wgpu::BackendBit;
|
2021-04-11 20:13:07 +00:00
|
|
|
|
|
|
|
use crate::{
|
2021-06-02 02:59:17 +00:00
|
|
|
camera::CameraPlugin,
|
|
|
|
mesh::MeshPlugin,
|
|
|
|
render_graph::RenderGraph,
|
|
|
|
render_phase::DrawFunctions,
|
2021-06-21 23:28:52 +00:00
|
|
|
renderer::render_system,
|
|
|
|
texture::ImagePlugin,
|
2021-06-02 02:59:17 +00:00
|
|
|
view::{ViewPlugin, WindowRenderPlugin},
|
2021-04-11 20:13:07 +00:00
|
|
|
};
|
2021-08-24 00:31:21 +00:00
|
|
|
use bevy_app::{App, Plugin, SubAppLabel};
|
2021-04-11 20:13:07 +00:00
|
|
|
use bevy_ecs::prelude::*;
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct RenderPlugin;
|
|
|
|
|
|
|
|
/// The names of the default App stages
|
|
|
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)]
|
|
|
|
pub enum RenderStage {
|
|
|
|
/// Extract data from "app world" and insert it into "render world". This step should be kept
|
|
|
|
/// as short as possible to increase the "pipelining potential" for running the next frame
|
|
|
|
/// while rendering the current frame.
|
|
|
|
Extract,
|
|
|
|
|
|
|
|
/// Prepare render resources from extracted data.
|
|
|
|
Prepare,
|
|
|
|
|
|
|
|
/// Create Bind Groups that depend on Prepare data and queue up draw calls to run during the Render stage.
|
|
|
|
Queue,
|
|
|
|
|
2021-06-02 02:59:17 +00:00
|
|
|
// TODO: This could probably be moved in favor of a system ordering abstraction in Render or Queue
|
2021-06-18 18:21:18 +00:00
|
|
|
/// Sort RenderPhases here
|
2021-06-02 02:59:17 +00:00
|
|
|
PhaseSort,
|
|
|
|
|
2021-04-11 20:13:07 +00:00
|
|
|
/// Actual rendering happens here. In most cases, only the render backend should insert resources here
|
|
|
|
Render,
|
2021-06-02 02:59:17 +00:00
|
|
|
|
|
|
|
/// Cleanup render resources here.
|
|
|
|
Cleanup,
|
2021-04-11 20:13:07 +00:00
|
|
|
}
|
|
|
|
|
2021-07-28 17:52:24 +00:00
|
|
|
/// The Render App World. This is only available as a resource during the Extract step.
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct RenderWorld(World);
|
|
|
|
|
|
|
|
impl Deref for RenderWorld {
|
|
|
|
type Target = World;
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DerefMut for RenderWorld {
|
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
&mut self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-24 00:31:21 +00:00
|
|
|
/// Label for the rendering sub-app
|
|
|
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, SubAppLabel)]
|
|
|
|
pub struct RenderSubApp;
|
|
|
|
|
2021-07-28 17:52:24 +00:00
|
|
|
/// A "scratch" world used to avoid allocating new worlds every frame when
|
|
|
|
// swapping out the Render World.
|
|
|
|
#[derive(Default)]
|
|
|
|
struct ScratchRenderWorld(World);
|
|
|
|
|
2021-04-11 20:13:07 +00:00
|
|
|
impl Plugin for RenderPlugin {
|
|
|
|
fn build(&self, app: &mut App) {
|
2021-06-21 23:28:52 +00:00
|
|
|
let (instance, device, queue) =
|
|
|
|
futures_lite::future::block_on(renderer::initialize_renderer(
|
|
|
|
BackendBit::PRIMARY,
|
|
|
|
&wgpu::RequestAdapterOptions {
|
|
|
|
power_preference: wgpu::PowerPreference::HighPerformance,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
&wgpu::DeviceDescriptor::default(),
|
|
|
|
));
|
|
|
|
app.insert_resource(device.clone())
|
2021-07-28 17:52:24 +00:00
|
|
|
.insert_resource(queue.clone())
|
|
|
|
.init_resource::<ScratchRenderWorld>();
|
2021-06-21 23:28:52 +00:00
|
|
|
|
2021-04-11 20:13:07 +00:00
|
|
|
let mut render_app = App::empty();
|
|
|
|
let mut extract_stage = SystemStage::parallel();
|
|
|
|
// don't apply buffers when the stage finishes running
|
|
|
|
// extract stage runs on the app world, but the buffers are applied to the render world
|
|
|
|
extract_stage.set_apply_buffers(false);
|
|
|
|
render_app
|
|
|
|
.add_stage(RenderStage::Extract, extract_stage)
|
|
|
|
.add_stage(RenderStage::Prepare, SystemStage::parallel())
|
|
|
|
.add_stage(RenderStage::Queue, SystemStage::parallel())
|
2021-06-02 02:59:17 +00:00
|
|
|
.add_stage(RenderStage::PhaseSort, SystemStage::parallel())
|
2021-06-21 23:28:52 +00:00
|
|
|
.add_stage(
|
|
|
|
RenderStage::Render,
|
|
|
|
SystemStage::parallel().with_system(render_system.exclusive_system()),
|
|
|
|
)
|
2021-06-02 02:59:17 +00:00
|
|
|
.add_stage(RenderStage::Cleanup, SystemStage::parallel())
|
2021-06-21 23:28:52 +00:00
|
|
|
.insert_resource(instance)
|
|
|
|
.insert_resource(device)
|
|
|
|
.insert_resource(queue)
|
2021-06-02 02:59:17 +00:00
|
|
|
.init_resource::<RenderGraph>()
|
|
|
|
.init_resource::<DrawFunctions>();
|
|
|
|
|
2021-08-24 00:31:21 +00:00
|
|
|
app.add_sub_app(RenderSubApp, render_app, move |app_world, render_app| {
|
2021-06-02 02:59:17 +00:00
|
|
|
// reserve all existing app entities for use in render_app
|
|
|
|
// they can only be spawned using `get_or_spawn()`
|
|
|
|
let meta_len = app_world.entities().meta.len();
|
|
|
|
render_app
|
|
|
|
.world
|
|
|
|
.entities()
|
|
|
|
.reserve_entities(meta_len as u32);
|
2021-07-28 17:52:24 +00:00
|
|
|
|
2021-06-02 02:59:17 +00:00
|
|
|
// flushing as "invalid" ensures that app world entities aren't added as "empty archetype" entities by default
|
|
|
|
// these entities cannot be accessed without spawning directly onto them
|
|
|
|
// this _only_ works as expected because clear_entities() is called at the end of every frame.
|
|
|
|
render_app.world.entities_mut().flush_as_invalid();
|
|
|
|
|
2021-04-11 20:13:07 +00:00
|
|
|
// extract
|
|
|
|
extract(app_world, render_app);
|
|
|
|
|
|
|
|
// prepare
|
|
|
|
let prepare = render_app
|
|
|
|
.schedule
|
|
|
|
.get_stage_mut::<SystemStage>(&RenderStage::Prepare)
|
|
|
|
.unwrap();
|
|
|
|
prepare.run(&mut render_app.world);
|
|
|
|
|
|
|
|
// queue
|
|
|
|
let queue = render_app
|
|
|
|
.schedule
|
|
|
|
.get_stage_mut::<SystemStage>(&RenderStage::Queue)
|
|
|
|
.unwrap();
|
|
|
|
queue.run(&mut render_app.world);
|
|
|
|
|
2021-06-02 02:59:17 +00:00
|
|
|
// phase sort
|
|
|
|
let phase_sort = render_app
|
|
|
|
.schedule
|
|
|
|
.get_stage_mut::<SystemStage>(&RenderStage::PhaseSort)
|
|
|
|
.unwrap();
|
|
|
|
phase_sort.run(&mut render_app.world);
|
|
|
|
|
2021-04-11 20:13:07 +00:00
|
|
|
// render
|
|
|
|
let render = render_app
|
|
|
|
.schedule
|
|
|
|
.get_stage_mut::<SystemStage>(&RenderStage::Render)
|
|
|
|
.unwrap();
|
|
|
|
render.run(&mut render_app.world);
|
|
|
|
|
2021-06-02 02:59:17 +00:00
|
|
|
// cleanup
|
|
|
|
let cleanup = render_app
|
|
|
|
.schedule
|
|
|
|
.get_stage_mut::<SystemStage>(&RenderStage::Cleanup)
|
|
|
|
.unwrap();
|
|
|
|
cleanup.run(&mut render_app.world);
|
|
|
|
|
2021-04-11 20:13:07 +00:00
|
|
|
render_app.world.clear_entities();
|
|
|
|
});
|
|
|
|
|
2021-06-21 23:28:52 +00:00
|
|
|
app.add_plugin(WindowRenderPlugin)
|
2021-06-02 02:59:17 +00:00
|
|
|
.add_plugin(CameraPlugin)
|
|
|
|
.add_plugin(ViewPlugin)
|
|
|
|
.add_plugin(MeshPlugin)
|
2021-06-21 23:28:52 +00:00
|
|
|
.add_plugin(ImagePlugin);
|
2021-04-11 20:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn extract(app_world: &mut World, render_app: &mut App) {
|
|
|
|
let extract = render_app
|
|
|
|
.schedule
|
|
|
|
.get_stage_mut::<SystemStage>(&RenderStage::Extract)
|
|
|
|
.unwrap();
|
2021-07-28 17:52:24 +00:00
|
|
|
|
|
|
|
// temporarily add the render world to the app world as a resource
|
|
|
|
let scratch_world = app_world.remove_resource::<ScratchRenderWorld>().unwrap();
|
|
|
|
let render_world = std::mem::replace(&mut render_app.world, scratch_world.0);
|
|
|
|
app_world.insert_resource(RenderWorld(render_world));
|
|
|
|
|
2021-04-11 20:13:07 +00:00
|
|
|
extract.run(app_world);
|
2021-07-28 17:52:24 +00:00
|
|
|
|
|
|
|
// add the render world back to the render app
|
|
|
|
let render_world = app_world.remove_resource::<RenderWorld>().unwrap();
|
|
|
|
let scratch_world = std::mem::replace(&mut render_app.world, render_world.0);
|
|
|
|
app_world.insert_resource(ScratchRenderWorld(scratch_world));
|
|
|
|
|
2021-04-11 20:13:07 +00:00
|
|
|
extract.apply_buffers(&mut render_app.world);
|
|
|
|
}
|