extern crate core;
pub mod camera;
pub mod color;
pub mod extract_component;
mod extract_param;
pub mod extract_resource;
pub mod globals;
pub mod mesh;
pub mod primitives;
pub mod rangefinder;
pub mod render_asset;
pub mod render_graph;
pub mod render_phase;
pub mod render_resource;
pub mod renderer;
pub mod settings;
mod spatial_bundle;
pub mod texture;
pub mod view;
use bevy_core::FrameCount;
use bevy_hierarchy::ValidParentCheckPlugin;
pub use extract_param::Extract;
pub mod prelude {
#[doc(hidden)]
pub use crate::{
camera::{Camera, OrthographicProjection, PerspectiveProjection, Projection},
color::Color,
mesh::{shape, Mesh},
render_resource::Shader,
spatial_bundle::SpatialBundle,
texture::{Image, ImagePlugin},
view::{ComputedVisibility, Msaa, Visibility, VisibilityBundle},
};
}
use globals::GlobalsPlugin;
pub use once_cell;
use prelude::ComputedVisibility;
use crate::{
camera::CameraPlugin,
color::Color,
mesh::MeshPlugin,
primitives::{CubemapFrusta, Frustum},
render_graph::RenderGraph,
render_resource::{PipelineCache, Shader, ShaderLoader},
renderer::{render_system, RenderInstance},
view::{ViewPlugin, WindowRenderPlugin},
};
use bevy_app::{App, AppLabel, Plugin};
use bevy_asset::{AddAsset, AssetServer};
use bevy_ecs::prelude::*;
use bevy_utils::tracing::debug;
use std::{
any::TypeId,
ops::{Deref, DerefMut},
};
#[derive(Default)]
pub struct RenderPlugin;
#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)]
pub enum RenderStage {
Extract,
Prepare,
Queue,
PhaseSort,
Render,
Cleanup,
}
#[derive(Resource, Default)]
pub struct MainWorld(World);
#[derive(Resource, Default)]
pub struct RenderWorld(World);
impl Deref for MainWorld {
type Target = World;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for MainWorld {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub mod main_graph {
pub mod node {
pub const CAMERA_DRIVER: &str = "camera_driver";
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel)]
pub struct RenderApp;
impl Plugin for RenderPlugin {
fn build(&self, app: &mut App) {
let options = app
.world
.get_resource::<settings::WgpuSettings>()
.cloned()
.unwrap_or_default();
app.add_asset::<Shader>()
.add_debug_asset::<Shader>()
.init_asset_loader::<ShaderLoader>()
.init_debug_asset_loader::<ShaderLoader>()
.register_type::<Color>();
if let Some(backends) = options.backends {
let windows = app.world.resource_mut::<bevy_window::Windows>();
let instance = wgpu::Instance::new(backends);
let surface = windows
.get_primary()
.and_then(|window| window.raw_handle())
.map(|wrapper| unsafe {
let handle = wrapper.get_handle();
instance.create_surface(&handle)
});
let request_adapter_options = wgpu::RequestAdapterOptions {
power_preference: options.power_preference,
compatible_surface: surface.as_ref(),
..Default::default()
};
let (device, queue, adapter_info, render_adapter) = futures_lite::future::block_on(
renderer::initialize_renderer(&instance, &options, &request_adapter_options),
);
debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
debug!("Configured wgpu adapter Features: {:#?}", device.features());
app.insert_resource(device.clone())
.insert_resource(queue.clone())
.insert_resource(adapter_info.clone())
.insert_resource(render_adapter.clone())
.init_resource::<ScratchMainWorld>()
.register_type::<Frustum>()
.register_type::<CubemapFrusta>();
let pipeline_cache = PipelineCache::new(device.clone());
let asset_server = app.world.resource::<AssetServer>().clone();
let mut render_app = App::empty();
let mut extract_stage =
SystemStage::parallel().with_system(PipelineCache::extract_shaders);
render_app.init_resource::<MainWorld>();
render_app.world.remove_resource::<MainWorld>();
let main_world_in_render = render_app
.world
.components()
.get_resource_id(TypeId::of::<MainWorld>());
extract_stage.set_must_read_resource(main_world_in_render.unwrap());
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())
.add_stage(RenderStage::PhaseSort, SystemStage::parallel())
.add_stage(
RenderStage::Render,
SystemStage::parallel()
.with_system(PipelineCache::process_pipeline_queue_system)
.with_system(render_system.at_end()),
)
.add_stage(RenderStage::Cleanup, SystemStage::parallel())
.init_resource::<RenderGraph>()
.insert_resource(RenderInstance(instance))
.insert_resource(device)
.insert_resource(queue)
.insert_resource(render_adapter)
.insert_resource(adapter_info)
.insert_resource(pipeline_cache)
.insert_resource(asset_server);
let (sender, receiver) = bevy_time::create_time_channels();
app.insert_resource(receiver);
render_app.insert_resource(sender);
app.add_sub_app(RenderApp, render_app, move |app_world, render_app| {
#[cfg(feature = "trace")]
let _render_span = bevy_utils::tracing::info_span!("renderer subapp").entered();
{
#[cfg(feature = "trace")]
let _stage_span =
bevy_utils::tracing::info_span!("stage", name = "reserve_and_flush")
.entered();
let meta_len = app_world.entities().meta_len();
assert_eq!(
render_app.world.entities().len(),
0,
"An entity was spawned after the entity list was cleared last frame and before the extract stage began. This is not supported",
);
unsafe {
render_app
.world
.entities_mut()
.flush_and_reserve_invalid_assuming_no_entities(meta_len);
}
}
{
#[cfg(feature = "trace")]
let _stage_span =
bevy_utils::tracing::info_span!("stage", name = "extract").entered();
extract(app_world, render_app);
}
{
#[cfg(feature = "trace")]
let _stage_span =
bevy_utils::tracing::info_span!("stage", name = "prepare").entered();
let prepare = render_app
.schedule
.get_stage_mut::<SystemStage>(RenderStage::Prepare)
.unwrap();
prepare.run(&mut render_app.world);
}
{
#[cfg(feature = "trace")]
let _stage_span =
bevy_utils::tracing::info_span!("stage", name = "queue").entered();
let queue = render_app
.schedule
.get_stage_mut::<SystemStage>(RenderStage::Queue)
.unwrap();
queue.run(&mut render_app.world);
}
{
#[cfg(feature = "trace")]
let _stage_span =
bevy_utils::tracing::info_span!("stage", name = "sort").entered();
let phase_sort = render_app
.schedule
.get_stage_mut::<SystemStage>(RenderStage::PhaseSort)
.unwrap();
phase_sort.run(&mut render_app.world);
}
{
#[cfg(feature = "trace")]
let _stage_span =
bevy_utils::tracing::info_span!("stage", name = "render").entered();
let render = render_app
.schedule
.get_stage_mut::<SystemStage>(RenderStage::Render)
.unwrap();
render.run(&mut render_app.world);
}
{
#[cfg(feature = "trace")]
let _stage_span =
bevy_utils::tracing::info_span!("stage", name = "cleanup").entered();
let cleanup = render_app
.schedule
.get_stage_mut::<SystemStage>(RenderStage::Cleanup)
.unwrap();
cleanup.run(&mut render_app.world);
}
{
#[cfg(feature = "trace")]
let _stage_span =
bevy_utils::tracing::info_span!("stage", name = "clear_entities").entered();
render_app.world.clear_entities();
}
});
}
app.add_plugin(ValidParentCheckPlugin::<ComputedVisibility>::default())
.add_plugin(WindowRenderPlugin)
.add_plugin(CameraPlugin)
.add_plugin(ViewPlugin)
.add_plugin(MeshPlugin)
.add_plugin(GlobalsPlugin)
.add_plugin(FrameCountPlugin);
}
}
#[derive(Resource, Default)]
struct ScratchMainWorld(World);
fn extract(app_world: &mut World, render_app: &mut App) {
let extract = render_app
.schedule
.get_stage_mut::<SystemStage>(RenderStage::Extract)
.unwrap();
let scratch_world = app_world.remove_resource::<ScratchMainWorld>().unwrap();
let inserted_world = std::mem::replace(app_world, scratch_world.0);
let running_world = &mut render_app.world;
running_world.insert_resource(MainWorld(inserted_world));
extract.run(running_world);
let inserted_world = running_world.remove_resource::<MainWorld>().unwrap();
let scratch_world = std::mem::replace(app_world, inserted_world.0);
app_world.insert_resource(ScratchMainWorld(scratch_world));
extract.apply_buffers(running_world);
}
pub struct FrameCountPlugin;
impl Plugin for FrameCountPlugin {
fn build(&self, app: &mut bevy_app::App) {
app.add_system(update_frame_count);
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
render_app.add_system_to_stage(RenderStage::Extract, extract_frame_count);
}
}
}
fn update_frame_count(mut frame_count: ResMut<FrameCount>) {
frame_count.0 = frame_count.0.wrapping_add(1);
}
fn extract_frame_count(mut commands: Commands, frame_count: Extract<Res<FrameCount>>) {
commands.insert_resource(**frame_count);
}