1#![allow(missing_docs, reason = "Not all docs are written yet, see #3492.")]
3#![allow(unsafe_code)]
4#![allow(internal_features)]
6#![cfg_attr(any(docsrs, docsrs_dep), feature(doc_auto_cfg, rustdoc_internals))]
7#![doc(
8 html_logo_url = "https://bevyengine.org/assets/icon.png",
9 html_favicon_url = "https://bevyengine.org/assets/icon.png"
10)]
11
12#[cfg(target_pointer_width = "16")]
13compile_error!("bevy_render cannot compile for a 16-bit platform.");
14
15extern crate alloc;
16extern crate core;
17
18pub mod alpha;
19pub mod batching;
20pub mod camera;
21pub mod diagnostic;
22pub mod extract_component;
23pub mod extract_instances;
24mod extract_param;
25pub mod extract_resource;
26pub mod globals;
27pub mod gpu_component_array_buffer;
28pub mod gpu_readback;
29pub mod mesh;
30#[cfg(not(target_arch = "wasm32"))]
31pub mod pipelined_rendering;
32pub mod primitives;
33pub mod render_asset;
34pub mod render_graph;
35pub mod render_phase;
36pub mod render_resource;
37pub mod renderer;
38pub mod settings;
39mod spatial_bundle;
40pub mod storage;
41pub mod sync_component;
42pub mod sync_world;
43pub mod texture;
44pub mod view;
45
46#[expect(deprecated)]
50pub mod prelude {
51 #[doc(hidden)]
52 pub use crate::{
53 alpha::AlphaMode,
54 camera::{
55 Camera, ClearColor, ClearColorConfig, OrthographicProjection, PerspectiveProjection,
56 Projection,
57 },
58 mesh::{
59 morph::MorphWeights, primitives::MeshBuilder, primitives::Meshable, Mesh, Mesh2d,
60 Mesh3d,
61 },
62 render_resource::Shader,
63 spatial_bundle::SpatialBundle,
64 texture::ImagePlugin,
65 view::{InheritedVisibility, Msaa, ViewVisibility, Visibility, VisibilityBundle},
66 ExtractSchedule,
67 };
68}
69use batching::gpu_preprocessing::BatchingPlugin;
70use bevy_ecs::schedule::ScheduleBuildSettings;
71use bevy_utils::prelude::default;
72pub use extract_param::Extract;
73
74use bevy_hierarchy::ValidParentCheckPlugin;
75use bevy_window::{PrimaryWindow, RawHandleWrapperHolder};
76use extract_resource::ExtractResourcePlugin;
77use globals::GlobalsPlugin;
78use render_asset::RenderAssetBytesPerFrame;
79use renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue};
80use sync_world::{
81 despawn_temporary_render_entities, entity_sync_system, SyncToRenderWorld, SyncWorldPlugin,
82};
83
84use crate::gpu_readback::GpuReadbackPlugin;
85use crate::{
86 camera::CameraPlugin,
87 mesh::{MeshPlugin, MorphPlugin, RenderMesh},
88 render_asset::prepare_assets,
89 render_resource::{PipelineCache, Shader, ShaderLoader},
90 renderer::{render_system, RenderInstance, WgpuWrapper},
91 settings::RenderCreation,
92 storage::StoragePlugin,
93 view::{ViewPlugin, WindowRenderPlugin},
94};
95use alloc::sync::Arc;
96use bevy_app::{App, AppLabel, Plugin, SubApp};
97use bevy_asset::{load_internal_asset, AssetApp, AssetServer, Handle};
98use bevy_ecs::{prelude::*, schedule::ScheduleLabel, system::SystemState};
99use bevy_utils::tracing::debug;
100use core::ops::{Deref, DerefMut};
101use std::sync::Mutex;
102
103#[derive(Default)]
112pub struct RenderPlugin {
113 pub render_creation: RenderCreation,
114 pub synchronous_pipeline_compilation: bool,
117}
118
119#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
123pub enum RenderSet {
124 ExtractCommands,
126 PrepareAssets,
128 ManageViews,
130 Queue,
133 QueueMeshes,
135 PhaseSort,
140 Prepare,
143 PrepareResources,
145 PrepareResourcesFlush,
147 PrepareBindGroups,
149 Render,
152 Cleanup,
154 PostCleanup,
158}
159
160#[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone)]
162pub struct Render;
163
164impl Render {
165 pub fn base_schedule() -> Schedule {
169 use RenderSet::*;
170
171 let mut schedule = Schedule::new(Self);
172
173 schedule.configure_sets(
174 (
175 ExtractCommands,
176 ManageViews,
177 Queue,
178 PhaseSort,
179 Prepare,
180 Render,
181 Cleanup,
182 PostCleanup,
183 )
184 .chain(),
185 );
186
187 schedule.configure_sets((ExtractCommands, PrepareAssets, Prepare).chain());
188 schedule.configure_sets(
189 QueueMeshes
190 .in_set(Queue)
191 .after(prepare_assets::<RenderMesh>),
192 );
193 schedule.configure_sets(
194 (PrepareResources, PrepareResourcesFlush, PrepareBindGroups)
195 .chain()
196 .in_set(Prepare),
197 );
198
199 schedule
200 }
201}
202
203#[derive(ScheduleLabel, PartialEq, Eq, Debug, Clone, Hash)]
211pub struct ExtractSchedule;
212
213#[derive(Resource, Default)]
219pub struct MainWorld(World);
220
221impl Deref for MainWorld {
222 type Target = World;
223
224 fn deref(&self) -> &Self::Target {
225 &self.0
226 }
227}
228
229impl DerefMut for MainWorld {
230 fn deref_mut(&mut self) -> &mut Self::Target {
231 &mut self.0
232 }
233}
234
235pub mod graph {
236 use crate::render_graph::RenderLabel;
237
238 #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
239 pub struct CameraDriverLabel;
240}
241
242#[derive(Resource)]
243struct FutureRendererResources(
244 Arc<
245 Mutex<
246 Option<(
247 RenderDevice,
248 RenderQueue,
249 RenderAdapterInfo,
250 RenderAdapter,
251 RenderInstance,
252 )>,
253 >,
254 >,
255);
256
257#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel)]
259pub struct RenderApp;
260
261pub const INSTANCE_INDEX_SHADER_HANDLE: Handle<Shader> =
262 Handle::weak_from_u128(10313207077636615845);
263pub const MATHS_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(10665356303104593376);
264pub const COLOR_OPERATIONS_SHADER_HANDLE: Handle<Shader> =
265 Handle::weak_from_u128(1844674407370955161);
266
267impl Plugin for RenderPlugin {
268 fn build(&self, app: &mut App) {
270 app.init_asset::<Shader>()
271 .init_asset_loader::<ShaderLoader>();
272
273 match &self.render_creation {
274 RenderCreation::Manual(device, queue, adapter_info, adapter, instance) => {
275 let future_renderer_resources_wrapper = Arc::new(Mutex::new(Some((
276 device.clone(),
277 queue.clone(),
278 adapter_info.clone(),
279 adapter.clone(),
280 instance.clone(),
281 ))));
282 app.insert_resource(FutureRendererResources(
283 future_renderer_resources_wrapper.clone(),
284 ));
285 unsafe { initialize_render_app(app) };
287 }
288 RenderCreation::Automatic(render_creation) => {
289 if let Some(backends) = render_creation.backends {
290 let future_renderer_resources_wrapper = Arc::new(Mutex::new(None));
291 app.insert_resource(FutureRendererResources(
292 future_renderer_resources_wrapper.clone(),
293 ));
294
295 let mut system_state: SystemState<
296 Query<&RawHandleWrapperHolder, With<PrimaryWindow>>,
297 > = SystemState::new(app.world_mut());
298 let primary_window = system_state.get(app.world()).get_single().ok().cloned();
299 let settings = render_creation.clone();
300 let async_renderer = async move {
301 let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
302 backends,
303 dx12_shader_compiler: settings.dx12_shader_compiler.clone(),
304 flags: settings.instance_flags,
305 gles_minor_version: settings.gles3_minor_version,
306 });
307
308 let surface = primary_window.and_then(|wrapper| unsafe {
310 let maybe_handle = wrapper.0.lock().expect(
311 "Couldn't get the window handle in time for renderer initialization",
312 );
313 if let Some(wrapper) = maybe_handle.as_ref() {
314 let handle = wrapper.get_handle();
315 Some(
316 instance
317 .create_surface(handle)
318 .expect("Failed to create wgpu surface"),
319 )
320 } else {
321 None
322 }
323 });
324
325 let request_adapter_options = wgpu::RequestAdapterOptions {
326 power_preference: settings.power_preference,
327 compatible_surface: surface.as_ref(),
328 ..Default::default()
329 };
330
331 let (device, queue, adapter_info, render_adapter) =
332 renderer::initialize_renderer(
333 &instance,
334 &settings,
335 &request_adapter_options,
336 )
337 .await;
338 debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
339 debug!("Configured wgpu adapter Features: {:#?}", device.features());
340 let mut future_renderer_resources_inner =
341 future_renderer_resources_wrapper.lock().unwrap();
342 *future_renderer_resources_inner = Some((
343 device,
344 queue,
345 adapter_info,
346 render_adapter,
347 RenderInstance(Arc::new(WgpuWrapper::new(instance))),
348 ));
349 };
350 #[cfg(target_arch = "wasm32")]
352 bevy_tasks::IoTaskPool::get()
353 .spawn_local(async_renderer)
354 .detach();
355 #[cfg(not(target_arch = "wasm32"))]
357 futures_lite::future::block_on(async_renderer);
358
359 unsafe { initialize_render_app(app) };
361 }
362 }
363 };
364
365 app.add_plugins((
366 ValidParentCheckPlugin::<view::InheritedVisibility>::default(),
367 WindowRenderPlugin,
368 CameraPlugin,
369 ViewPlugin,
370 MeshPlugin,
371 GlobalsPlugin,
372 MorphPlugin,
373 BatchingPlugin,
374 SyncWorldPlugin,
375 StoragePlugin,
376 GpuReadbackPlugin::default(),
377 ));
378
379 app.init_resource::<RenderAssetBytesPerFrame>()
380 .add_plugins(ExtractResourcePlugin::<RenderAssetBytesPerFrame>::default());
381
382 app.register_type::<alpha::AlphaMode>()
383 .register_type::<bevy_color::Color>()
385 .register_type::<primitives::Aabb>()
386 .register_type::<primitives::CascadesFrusta>()
387 .register_type::<primitives::CubemapFrusta>()
388 .register_type::<primitives::Frustum>()
389 .register_type::<SyncToRenderWorld>();
390 }
391
392 fn ready(&self, app: &App) -> bool {
393 app.world()
394 .get_resource::<FutureRendererResources>()
395 .and_then(|frr| frr.0.try_lock().map(|locked| locked.is_some()).ok())
396 .unwrap_or(true)
397 }
398
399 fn finish(&self, app: &mut App) {
400 load_internal_asset!(app, MATHS_SHADER_HANDLE, "maths.wgsl", Shader::from_wgsl);
401 load_internal_asset!(
402 app,
403 COLOR_OPERATIONS_SHADER_HANDLE,
404 "color_operations.wgsl",
405 Shader::from_wgsl
406 );
407 if let Some(future_renderer_resources) =
408 app.world_mut().remove_resource::<FutureRendererResources>()
409 {
410 let (device, queue, adapter_info, render_adapter, instance) =
411 future_renderer_resources.0.lock().unwrap().take().unwrap();
412
413 app.insert_resource(device.clone())
414 .insert_resource(queue.clone())
415 .insert_resource(adapter_info.clone())
416 .insert_resource(render_adapter.clone());
417
418 let render_app = app.sub_app_mut(RenderApp);
419
420 render_app
421 .insert_resource(instance)
422 .insert_resource(PipelineCache::new(
423 device.clone(),
424 render_adapter.clone(),
425 self.synchronous_pipeline_compilation,
426 ))
427 .insert_resource(device)
428 .insert_resource(queue)
429 .insert_resource(render_adapter)
430 .insert_resource(adapter_info)
431 .add_systems(
432 Render,
433 (|mut bpf: ResMut<RenderAssetBytesPerFrame>| {
434 bpf.reset();
435 })
436 .in_set(RenderSet::Cleanup),
437 );
438 }
439 }
440}
441
442#[derive(Resource, Default)]
445struct ScratchMainWorld(World);
446
447fn extract(main_world: &mut World, render_world: &mut World) {
450 let scratch_world = main_world.remove_resource::<ScratchMainWorld>().unwrap();
452 let inserted_world = core::mem::replace(main_world, scratch_world.0);
453 render_world.insert_resource(MainWorld(inserted_world));
454 render_world.run_schedule(ExtractSchedule);
455
456 let inserted_world = render_world.remove_resource::<MainWorld>().unwrap();
458 let scratch_world = core::mem::replace(main_world, inserted_world.0);
459 main_world.insert_resource(ScratchMainWorld(scratch_world));
460}
461
462unsafe fn initialize_render_app(app: &mut App) {
465 app.init_resource::<ScratchMainWorld>();
466
467 let mut render_app = SubApp::new();
468 render_app.update_schedule = Some(Render.intern());
469
470 let mut extract_schedule = Schedule::new(ExtractSchedule);
471 extract_schedule.set_build_settings(ScheduleBuildSettings {
474 auto_insert_apply_deferred: false,
475 ..default()
476 });
477 extract_schedule.set_apply_final_deferred(false);
478
479 render_app
480 .add_schedule(extract_schedule)
481 .add_schedule(Render::base_schedule())
482 .init_resource::<render_graph::RenderGraph>()
483 .insert_resource(app.world().resource::<AssetServer>().clone())
484 .add_systems(ExtractSchedule, PipelineCache::extract_shaders)
485 .add_systems(
486 Render,
487 (
488 apply_extract_commands.in_set(RenderSet::ExtractCommands),
491 (
492 PipelineCache::process_pipeline_queue_system.before(render_system),
493 render_system,
494 )
495 .in_set(RenderSet::Render),
496 despawn_temporary_render_entities.in_set(RenderSet::PostCleanup),
497 ),
498 );
499
500 render_app.set_extract(|main_world, render_world| {
501 {
502 #[cfg(feature = "trace")]
503 let _stage_span = bevy_utils::tracing::info_span!("entity_sync").entered();
504 entity_sync_system(main_world, render_world);
505 }
506
507 extract(main_world, render_world);
509 });
510
511 let (sender, receiver) = bevy_time::create_time_channels();
512 render_app.insert_resource(sender);
513 app.insert_resource(receiver);
514 app.insert_sub_app(RenderApp, render_app);
515}
516
517fn apply_extract_commands(render_world: &mut World) {
521 render_world.resource_scope(|render_world, mut schedules: Mut<Schedules>| {
522 schedules
523 .get_mut(ExtractSchedule)
524 .unwrap()
525 .apply_deferred(render_world);
526 });
527}