mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
Add headless mode (#3439)
# Objective In this PR I added the ability to opt-out graphical backends. Closes #3155. ## Solution I turned backends into `Option` ~~and removed panicking sub app API to force users handle the error (was suggested by `@cart`)~~.
This commit is contained in:
parent
2ee38cb9e0
commit
458cb7a9e9
19 changed files with 283 additions and 230 deletions
|
@ -249,6 +249,10 @@ path = "examples/app/return_after_run.rs"
|
|||
name = "thread_pool_resources"
|
||||
path = "examples/app/thread_pool_resources.rs"
|
||||
|
||||
[[example]]
|
||||
name = "headless_defaults"
|
||||
path = "examples/app/headless_defaults.rs"
|
||||
|
||||
[[example]]
|
||||
name = "without_winit"
|
||||
path = "examples/app/without_winit.rs"
|
||||
|
|
|
@ -95,7 +95,11 @@ impl Plugin for CorePipelinePlugin {
|
|||
fn build(&self, app: &mut App) {
|
||||
app.init_resource::<ClearColor>();
|
||||
|
||||
let render_app = app.sub_app_mut(RenderApp);
|
||||
let render_app = match app.get_sub_app_mut(RenderApp) {
|
||||
Ok(render_app) => render_app,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
render_app
|
||||
.init_resource::<DrawFunctions<Transparent2d>>()
|
||||
.init_resource::<DrawFunctions<Opaque3d>>()
|
||||
|
|
|
@ -138,7 +138,11 @@ impl Plugin for PbrPlugin {
|
|||
},
|
||||
);
|
||||
|
||||
let render_app = app.sub_app_mut(RenderApp);
|
||||
let render_app = match app.get_sub_app_mut(RenderApp) {
|
||||
Ok(render_app) => render_app,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
render_app
|
||||
.add_system_to_stage(
|
||||
RenderStage::Extract,
|
||||
|
|
|
@ -53,11 +53,13 @@ impl Plugin for MeshRenderPlugin {
|
|||
|
||||
app.add_plugin(UniformComponentPlugin::<MeshUniform>::default());
|
||||
|
||||
app.sub_app_mut(RenderApp)
|
||||
.init_resource::<MeshPipeline>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_meshes)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_mesh_bind_group)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_mesh_view_bind_groups);
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.init_resource::<MeshPipeline>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_meshes)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_mesh_bind_group)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_mesh_view_bind_groups);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,13 +31,15 @@ impl Plugin for WireframePlugin {
|
|||
|
||||
app.init_resource::<WireframeConfig>();
|
||||
|
||||
app.sub_app_mut(RenderApp)
|
||||
.add_render_command::<Opaque3d, DrawWireframes>()
|
||||
.init_resource::<WireframePipeline>()
|
||||
.init_resource::<SpecializedPipelines<WireframePipeline>>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_wireframes)
|
||||
.add_system_to_stage(RenderStage::Extract, extract_wireframe_config)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_wireframes);
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.add_render_command::<Opaque3d, DrawWireframes>()
|
||||
.init_resource::<WireframePipeline>()
|
||||
.init_resource::<SpecializedPipelines<WireframePipeline>>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_wireframes)
|
||||
.add_system_to_stage(RenderStage::Extract, extract_wireframe_config)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_wireframes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,9 +53,11 @@ impl Plugin for CameraPlugin {
|
|||
CoreStage::PostUpdate,
|
||||
crate::camera::camera_system::<PerspectiveProjection>,
|
||||
);
|
||||
app.sub_app_mut(RenderApp)
|
||||
.init_resource::<ExtractedCameraNames>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_cameras);
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.init_resource::<ExtractedCameraNames>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_cameras);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -113,174 +113,178 @@ impl Plugin for RenderPlugin {
|
|||
.get_resource::<options::WgpuOptions>()
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
let instance = wgpu::Instance::new(options.backends);
|
||||
let surface = {
|
||||
let world = app.world.cell();
|
||||
let windows = world.get_resource_mut::<bevy_window::Windows>().unwrap();
|
||||
let raw_handle = windows.get_primary().map(|window| unsafe {
|
||||
let handle = window.raw_window_handle().get_handle();
|
||||
instance.create_surface(&handle)
|
||||
});
|
||||
raw_handle
|
||||
};
|
||||
let request_adapter_options = wgpu::RequestAdapterOptions {
|
||||
power_preference: options.power_preference,
|
||||
compatible_surface: surface.as_ref(),
|
||||
..Default::default()
|
||||
};
|
||||
let (device, queue) = futures_lite::future::block_on(renderer::initialize_renderer(
|
||||
&instance,
|
||||
&mut options,
|
||||
&request_adapter_options,
|
||||
));
|
||||
debug!("Configured wgpu adapter Limits: {:#?}", &options.limits);
|
||||
debug!("Configured wgpu adapter Features: {:#?}", &options.features);
|
||||
app.insert_resource(device.clone())
|
||||
.insert_resource(queue.clone())
|
||||
.insert_resource(options.clone())
|
||||
.add_asset::<Shader>()
|
||||
|
||||
app.add_asset::<Shader>()
|
||||
.init_asset_loader::<ShaderLoader>()
|
||||
.init_resource::<ScratchRenderWorld>()
|
||||
.register_type::<Color>()
|
||||
.register_type::<Frustum>()
|
||||
.register_type::<CubemapFrusta>();
|
||||
let render_pipeline_cache = RenderPipelineCache::new(device.clone());
|
||||
let asset_server = app.world.get_resource::<AssetServer>().unwrap().clone();
|
||||
.register_type::<Color>();
|
||||
|
||||
let mut render_app = App::empty();
|
||||
let mut extract_stage =
|
||||
SystemStage::parallel().with_system(RenderPipelineCache::extract_shaders);
|
||||
// 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())
|
||||
.add_stage(RenderStage::PhaseSort, SystemStage::parallel())
|
||||
.add_stage(
|
||||
RenderStage::Render,
|
||||
SystemStage::parallel()
|
||||
.with_system(RenderPipelineCache::process_pipeline_queue_system)
|
||||
.with_system(render_system.exclusive_system().at_end()),
|
||||
)
|
||||
.add_stage(RenderStage::Cleanup, SystemStage::parallel())
|
||||
.insert_resource(instance)
|
||||
.insert_resource(device)
|
||||
.insert_resource(queue)
|
||||
.insert_resource(options)
|
||||
.insert_resource(render_pipeline_cache)
|
||||
.insert_resource(asset_server)
|
||||
.init_resource::<RenderGraph>();
|
||||
if let Some(backends) = options.backends {
|
||||
let instance = wgpu::Instance::new(backends);
|
||||
let surface = {
|
||||
let world = app.world.cell();
|
||||
let windows = world.get_resource_mut::<bevy_window::Windows>().unwrap();
|
||||
let raw_handle = windows.get_primary().map(|window| unsafe {
|
||||
let handle = window.raw_window_handle().get_handle();
|
||||
instance.create_surface(&handle)
|
||||
});
|
||||
raw_handle
|
||||
};
|
||||
let request_adapter_options = wgpu::RequestAdapterOptions {
|
||||
power_preference: options.power_preference,
|
||||
compatible_surface: surface.as_ref(),
|
||||
..Default::default()
|
||||
};
|
||||
let (device, queue) = futures_lite::future::block_on(renderer::initialize_renderer(
|
||||
&instance,
|
||||
&mut options,
|
||||
&request_adapter_options,
|
||||
));
|
||||
debug!("Configured wgpu adapter Limits: {:#?}", &options.limits);
|
||||
debug!("Configured wgpu adapter Features: {:#?}", &options.features);
|
||||
app.insert_resource(device.clone())
|
||||
.insert_resource(queue.clone())
|
||||
.insert_resource(options.clone())
|
||||
.init_resource::<ScratchRenderWorld>()
|
||||
.register_type::<Frustum>()
|
||||
.register_type::<CubemapFrusta>();
|
||||
let render_pipeline_cache = RenderPipelineCache::new(device.clone());
|
||||
let asset_server = app.world.get_resource::<AssetServer>().unwrap().clone();
|
||||
|
||||
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");
|
||||
#[cfg(feature = "trace")]
|
||||
let _render_guard = render_span.enter();
|
||||
{
|
||||
let mut render_app = App::empty();
|
||||
let mut extract_stage =
|
||||
SystemStage::parallel().with_system(RenderPipelineCache::extract_shaders);
|
||||
// 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())
|
||||
.add_stage(RenderStage::PhaseSort, SystemStage::parallel())
|
||||
.add_stage(
|
||||
RenderStage::Render,
|
||||
SystemStage::parallel()
|
||||
.with_system(RenderPipelineCache::process_pipeline_queue_system)
|
||||
.with_system(render_system.exclusive_system().at_end()),
|
||||
)
|
||||
.add_stage(RenderStage::Cleanup, SystemStage::parallel())
|
||||
.insert_resource(instance)
|
||||
.insert_resource(device)
|
||||
.insert_resource(queue)
|
||||
.insert_resource(options)
|
||||
.insert_resource(render_pipeline_cache)
|
||||
.insert_resource(asset_server)
|
||||
.init_resource::<RenderGraph>();
|
||||
|
||||
app.add_sub_app(RenderApp, render_app, move |app_world, render_app| {
|
||||
#[cfg(feature = "trace")]
|
||||
let stage_span =
|
||||
bevy_utils::tracing::info_span!("stage", name = "reserve_and_flush");
|
||||
let render_span = bevy_utils::tracing::info_span!("renderer subapp");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
let _render_guard = render_span.enter();
|
||||
{
|
||||
#[cfg(feature = "trace")]
|
||||
let stage_span =
|
||||
bevy_utils::tracing::info_span!("stage", name = "reserve_and_flush");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
|
||||
// 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();
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
|
||||
{
|
||||
#[cfg(feature = "trace")]
|
||||
let stage_span = bevy_utils::tracing::info_span!("stage", name = "extract");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
{
|
||||
#[cfg(feature = "trace")]
|
||||
let stage_span = bevy_utils::tracing::info_span!("stage", name = "extract");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
|
||||
// extract
|
||||
extract(app_world, render_app);
|
||||
}
|
||||
// extract
|
||||
extract(app_world, render_app);
|
||||
}
|
||||
|
||||
{
|
||||
#[cfg(feature = "trace")]
|
||||
let stage_span = bevy_utils::tracing::info_span!("stage", name = "prepare");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
{
|
||||
#[cfg(feature = "trace")]
|
||||
let stage_span = bevy_utils::tracing::info_span!("stage", name = "prepare");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
|
||||
// prepare
|
||||
let prepare = render_app
|
||||
.schedule
|
||||
.get_stage_mut::<SystemStage>(&RenderStage::Prepare)
|
||||
.unwrap();
|
||||
prepare.run(&mut render_app.world);
|
||||
}
|
||||
// prepare
|
||||
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");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
{
|
||||
#[cfg(feature = "trace")]
|
||||
let stage_span = bevy_utils::tracing::info_span!("stage", name = "queue");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
|
||||
// queue
|
||||
let queue = render_app
|
||||
.schedule
|
||||
.get_stage_mut::<SystemStage>(&RenderStage::Queue)
|
||||
.unwrap();
|
||||
queue.run(&mut render_app.world);
|
||||
}
|
||||
// queue
|
||||
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");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
{
|
||||
#[cfg(feature = "trace")]
|
||||
let stage_span = bevy_utils::tracing::info_span!("stage", name = "sort");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
|
||||
// phase sort
|
||||
let phase_sort = render_app
|
||||
.schedule
|
||||
.get_stage_mut::<SystemStage>(&RenderStage::PhaseSort)
|
||||
.unwrap();
|
||||
phase_sort.run(&mut render_app.world);
|
||||
}
|
||||
// phase sort
|
||||
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");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
{
|
||||
#[cfg(feature = "trace")]
|
||||
let stage_span = bevy_utils::tracing::info_span!("stage", name = "render");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
|
||||
// render
|
||||
let render = render_app
|
||||
.schedule
|
||||
.get_stage_mut::<SystemStage>(&RenderStage::Render)
|
||||
.unwrap();
|
||||
render.run(&mut render_app.world);
|
||||
}
|
||||
// render
|
||||
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");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
{
|
||||
#[cfg(feature = "trace")]
|
||||
let stage_span = bevy_utils::tracing::info_span!("stage", name = "cleanup");
|
||||
#[cfg(feature = "trace")]
|
||||
let _stage_guard = stage_span.enter();
|
||||
|
||||
// cleanup
|
||||
let cleanup = render_app
|
||||
.schedule
|
||||
.get_stage_mut::<SystemStage>(&RenderStage::Cleanup)
|
||||
.unwrap();
|
||||
cleanup.run(&mut render_app.world);
|
||||
// cleanup
|
||||
let cleanup = render_app
|
||||
.schedule
|
||||
.get_stage_mut::<SystemStage>(&RenderStage::Cleanup)
|
||||
.unwrap();
|
||||
cleanup.run(&mut render_app.world);
|
||||
|
||||
render_app.world.clear_entities();
|
||||
}
|
||||
});
|
||||
render_app.world.clear_entities();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
app.add_plugin(WindowRenderPlugin)
|
||||
.add_plugin(CameraPlugin)
|
||||
|
|
|
@ -12,7 +12,7 @@ pub enum WgpuOptionsPriority {
|
|||
#[derive(Clone)]
|
||||
pub struct WgpuOptions {
|
||||
pub device_label: Option<Cow<'static, str>>,
|
||||
pub backends: Backends,
|
||||
pub backends: Option<Backends>,
|
||||
pub power_preference: PowerPreference,
|
||||
pub priority: WgpuOptionsPriority,
|
||||
pub features: WgpuFeatures,
|
||||
|
@ -27,7 +27,7 @@ impl Default for WgpuOptions {
|
|||
Backends::PRIMARY
|
||||
};
|
||||
|
||||
let backends = wgpu::util::backend_bits_from_env().unwrap_or(default_backends);
|
||||
let backends = Some(wgpu::util::backend_bits_from_env().unwrap_or(default_backends));
|
||||
|
||||
let priority = options_priority_from_env().unwrap_or(WgpuOptionsPriority::Functionality);
|
||||
|
||||
|
|
|
@ -54,14 +54,15 @@ impl<A: RenderAsset> Default for RenderAssetPlugin<A> {
|
|||
|
||||
impl<A: RenderAsset> Plugin for RenderAssetPlugin<A> {
|
||||
fn build(&self, app: &mut App) {
|
||||
let render_app = app.sub_app_mut(RenderApp);
|
||||
let prepare_asset_system = PrepareAssetSystem::<A>::system(&mut render_app.world);
|
||||
render_app
|
||||
.init_resource::<ExtractedAssets<A>>()
|
||||
.init_resource::<RenderAssets<A>>()
|
||||
.init_resource::<PrepareNextFrameAssets<A>>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_render_asset::<A>)
|
||||
.add_system_to_stage(RenderStage::Prepare, prepare_asset_system);
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
let prepare_asset_system = PrepareAssetSystem::<A>::system(&mut render_app.world);
|
||||
render_app
|
||||
.init_resource::<ExtractedAssets<A>>()
|
||||
.init_resource::<RenderAssets<A>>()
|
||||
.init_resource::<PrepareNextFrameAssets<A>>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_render_asset::<A>)
|
||||
.add_system_to_stage(RenderStage::Prepare, prepare_asset_system);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,12 +62,14 @@ impl<C> Default for UniformComponentPlugin<C> {
|
|||
|
||||
impl<C: Component + AsStd140 + Clone> Plugin for UniformComponentPlugin<C> {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.sub_app_mut(RenderApp)
|
||||
.insert_resource(ComponentUniforms::<C>::default())
|
||||
.add_system_to_stage(
|
||||
RenderStage::Prepare,
|
||||
prepare_uniform_components::<C>.system(),
|
||||
);
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.insert_resource(ComponentUniforms::<C>::default())
|
||||
.add_system_to_stage(
|
||||
RenderStage::Prepare,
|
||||
prepare_uniform_components::<C>.system(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,8 +146,9 @@ where
|
|||
{
|
||||
fn build(&self, app: &mut App) {
|
||||
let system = ExtractComponentSystem::<C>::system(&mut app.world);
|
||||
let render_app = app.sub_app_mut(RenderApp);
|
||||
render_app.add_system_to_stage(RenderStage::Extract, system);
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app.add_system_to_stage(RenderStage::Extract, system);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,9 +35,11 @@ impl Plugin for ImagePlugin {
|
|||
.unwrap()
|
||||
.set_untracked(DEFAULT_IMAGE_HANDLE, Image::default());
|
||||
|
||||
app.sub_app_mut(RenderApp)
|
||||
.init_resource::<TextureCache>()
|
||||
.add_system_to_stage(RenderStage::Cleanup, update_texture_cache_system);
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.init_resource::<TextureCache>()
|
||||
.add_system_to_stage(RenderStage::Cleanup, update_texture_cache_system);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,14 +26,16 @@ impl Plugin for ViewPlugin {
|
|||
fn build(&self, app: &mut App) {
|
||||
app.init_resource::<Msaa>().add_plugin(VisibilityPlugin);
|
||||
|
||||
app.sub_app_mut(RenderApp)
|
||||
.init_resource::<ViewUniforms>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_msaa)
|
||||
.add_system_to_stage(RenderStage::Prepare, prepare_view_uniforms)
|
||||
.add_system_to_stage(
|
||||
RenderStage::Prepare,
|
||||
prepare_view_targets.after(WindowSystem::Prepare),
|
||||
);
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.init_resource::<ViewUniforms>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_msaa)
|
||||
.add_system_to_stage(RenderStage::Prepare, prepare_view_uniforms)
|
||||
.add_system_to_stage(
|
||||
RenderStage::Prepare,
|
||||
prepare_view_targets.after(WindowSystem::Prepare),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,15 +24,17 @@ pub enum WindowSystem {
|
|||
|
||||
impl Plugin for WindowRenderPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.sub_app_mut(RenderApp)
|
||||
.init_resource::<ExtractedWindows>()
|
||||
.init_resource::<WindowSurfaces>()
|
||||
.init_resource::<NonSendMarker>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_windows)
|
||||
.add_system_to_stage(
|
||||
RenderStage::Prepare,
|
||||
prepare_windows.label(WindowSystem::Prepare),
|
||||
);
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.init_resource::<ExtractedWindows>()
|
||||
.init_resource::<WindowSurfaces>()
|
||||
.init_resource::<NonSendMarker>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_windows)
|
||||
.add_system_to_stage(
|
||||
RenderStage::Prepare,
|
||||
prepare_windows.label(WindowSystem::Prepare),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,20 +59,22 @@ impl Plugin for SpritePlugin {
|
|||
.register_type::<Sprite>()
|
||||
.add_plugin(Mesh2dRenderPlugin)
|
||||
.add_plugin(ColorMaterialPlugin);
|
||||
let render_app = app.sub_app_mut(RenderApp);
|
||||
render_app
|
||||
.init_resource::<ImageBindGroups>()
|
||||
.init_resource::<SpritePipeline>()
|
||||
.init_resource::<SpecializedPipelines<SpritePipeline>>()
|
||||
.init_resource::<SpriteMeta>()
|
||||
.init_resource::<ExtractedSprites>()
|
||||
.init_resource::<SpriteAssetEvents>()
|
||||
.add_render_command::<Transparent2d, DrawSprite>()
|
||||
.add_system_to_stage(
|
||||
RenderStage::Extract,
|
||||
render::extract_sprites.label(SpriteSystem::ExtractSprites),
|
||||
)
|
||||
.add_system_to_stage(RenderStage::Extract, render::extract_sprite_events)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_sprites);
|
||||
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.init_resource::<ImageBindGroups>()
|
||||
.init_resource::<SpritePipeline>()
|
||||
.init_resource::<SpecializedPipelines<SpritePipeline>>()
|
||||
.init_resource::<SpriteMeta>()
|
||||
.init_resource::<ExtractedSprites>()
|
||||
.init_resource::<SpriteAssetEvents>()
|
||||
.add_render_command::<Transparent2d, DrawSprite>()
|
||||
.add_system_to_stage(
|
||||
RenderStage::Extract,
|
||||
render::extract_sprites.label(SpriteSystem::ExtractSprites),
|
||||
)
|
||||
.add_system_to_stage(RenderStage::Extract, render::extract_sprite_events)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_sprites);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,12 +61,14 @@ impl Plugin for Mesh2dRenderPlugin {
|
|||
|
||||
app.add_plugin(UniformComponentPlugin::<Mesh2dUniform>::default());
|
||||
|
||||
app.sub_app_mut(RenderApp)
|
||||
.init_resource::<Mesh2dPipeline>()
|
||||
.init_resource::<SpecializedPipelines<Mesh2dPipeline>>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_mesh2d)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_mesh2d_bind_group)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_mesh2d_view_bind_groups);
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.init_resource::<Mesh2dPipeline>()
|
||||
.init_resource::<SpecializedPipelines<Mesh2dPipeline>>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_mesh2d)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_mesh2d_bind_group)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_mesh2d_view_bind_groups);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,10 +48,11 @@ impl Plugin for TextPlugin {
|
|||
.insert_resource(DefaultTextPipeline::default())
|
||||
.add_system_to_stage(CoreStage::PostUpdate, text2d_system);
|
||||
|
||||
let render_app = app.sub_app_mut(RenderApp);
|
||||
render_app.add_system_to_stage(
|
||||
RenderStage::Extract,
|
||||
extract_text2d_sprite.after(SpriteSystem::ExtractSprites),
|
||||
);
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app.add_system_to_stage(
|
||||
RenderStage::Extract,
|
||||
extract_text2d_sprite.after(SpriteSystem::ExtractSprites),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,11 @@ pub fn build_ui_render(app: &mut App) {
|
|||
let mut active_cameras = app.world.get_resource_mut::<ActiveCameras>().unwrap();
|
||||
active_cameras.add(CAMERA_UI);
|
||||
|
||||
let render_app = app.sub_app_mut(RenderApp);
|
||||
let render_app = match app.get_sub_app_mut(RenderApp) {
|
||||
Ok(render_app) => render_app,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
render_app
|
||||
.init_resource::<UiPipeline>()
|
||||
.init_resource::<SpecializedPipelines<UiPipeline>>()
|
||||
|
|
|
@ -121,6 +121,7 @@ Example | File | Description
|
|||
`empty` | [`app/empty.rs`](./app/empty.rs) | An empty application (does nothing)
|
||||
`empty_defaults` | [`app/empty_defaults.rs`](./app/empty_defaults.rs) | An empty application with default plugins
|
||||
`headless` | [`app/headless.rs`](./app/headless.rs) | An application that runs without default plugins
|
||||
`headless_defaults` | [`app/headless_defaults.rs`](./app/headless_defaults.rs) | An application that runs with default plugins, but without an actual renderer
|
||||
`logs` | [`app/logs.rs`](./app/logs.rs) | Illustrate how to use generate log output
|
||||
`plugin` | [`app/plugin.rs`](./app/plugin.rs) | Demonstrates the creation and registration of a custom plugin
|
||||
`plugin_group` | [`app/plugin_group.rs`](./app/plugin_group.rs) | Demonstrates the creation and registration of a custom plugin group
|
||||
|
|
11
examples/app/headless_defaults.rs
Normal file
11
examples/app/headless_defaults.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
use bevy::{prelude::*, render::options::WgpuOptions};
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.insert_resource(WgpuOptions {
|
||||
backends: None,
|
||||
..Default::default()
|
||||
})
|
||||
.add_plugins(DefaultPlugins)
|
||||
.run();
|
||||
}
|
Loading…
Reference in a new issue