1//! # Useful Environment Variables
2//!
3//! Both `bevy_render` and `wgpu` have a number of environment variable options for changing the runtime behavior
4//! of both crates. Many of these may be useful in development or release environments.
5//!
6//! - `WGPU_DEBUG=1` enables debug labels, which can be useful in release builds.
7//! - `WGPU_VALIDATION=0` disables validation layers. This can help with particularly spammy errors.
8//! - `WGPU_FORCE_FALLBACK_ADAPTER=1` attempts to force software rendering. This typically matches what is used in CI.
9//! - `WGPU_ADAPTER_NAME` allows selecting a specific adapter by name.
10//! - `WGPU_SETTINGS_PRIO=webgl2` uses webgl2 limits.
11//! - `WGPU_SETTINGS_PRIO=webgpu` uses webgpu limits.
12//! - `VERBOSE_SHADER_ERROR=1` prints more detailed information about WGSL compilation errors, such as shader defs and shader entrypoint.
1314#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")]
15#![expect(unsafe_code, reason = "Unsafe code is used to improve performance.")]
16#![cfg_attr(
17 any(docsrs, docsrs_dep),
18 expect(
19 internal_features,
20 reason = "rustdoc_internals is needed for fake_variadic"
21)
22)]
23#![cfg_attr(any(docsrs, docsrs_dep), feature(rustdoc_internals))]
24#![cfg_attr(docsrs, feature(doc_cfg))]
25#![doc(
26 html_logo_url = "https://bevy.org/assets/icon.png",
27 html_favicon_url = "https://bevy.org/assets/icon.png"
28)]
2930#[cfg(target_pointer_width = "16")]
31compile_error!("bevy_render cannot compile for a 16-bit platform.");
3233extern crate alloc;
34extern crate core;
3536// Required to make proc macros work in bevy itself.
37extern crate self as bevy_render;
3839pub mod batching;
40pub mod camera;
41pub mod diagnostic;
42pub mod erased_render_asset;
43pub mod error_handler;
44pub mod extract_component;
45pub mod extract_instances;
46mod extract_param;
47pub mod extract_plugin;
48pub mod extract_resource;
49pub mod globals;
50pub mod gpu_component_array_buffer;
51pub mod gpu_readback;
52pub mod mesh;
53pub mod occlusion_culling;
54#[cfg(not(target_arch = "wasm32"))]
55pub mod pipelined_rendering;
56pub mod render_asset;
57pub mod render_phase;
58pub mod render_resource;
59pub mod renderer;
60pub mod settings;
61pub mod slab_allocator;
62pub mod storage;
63pub mod sync_component;
64pub mod sync_world;
65#[cfg(test)]
66pub(crate) mod test_utils;
67pub mod texture;
68pub mod uniform;
69pub mod view;
7071/// The render prelude.
72///
73/// This includes the most common types in this crate, re-exported for your convenience.
74pub mod prelude {
75#[doc(hidden)]
76pub use crate::{
77camera::NormalizedRenderTargetExtas _, renderer::RenderGraph, texture::ManualTextureViews,
78view::Msaa, ExtractSchedule,
79 };
80}
8182pub use extract_param::Extract;
83pub use extract_plugin::{ExtractSchedule, MainWorld};
8485use crate::{
86camera::CameraPlugin,
87 error_handler::{RenderErrorHandler, RenderState},
88extract_plugin::ExtractPlugin,
89gpu_readback::GpuReadbackPlugin,
90 mesh::{MeshRenderAssetPlugin, RenderMesh},
91render_asset::prepare_assets,
92 render_resource::{PipelineCache, SparseBufferPlugin},
93 renderer::{render_system, RenderAdapterInfo, RenderGraph},
94 settings::{RenderCreation, WgpuLimits},
95storage::StoragePlugin,
96texture::TexturePlugin,
97 view::{ViewPlugin, WindowRenderPlugin},
98};
99use alloc::sync::Arc;
100use batching::gpu_preprocessing::BatchingPlugin;
101use bevy_app::{App, AppLabel, First, Plugin, SubApp};
102use bevy_asset::{AssetApp, AssetServer};
103use bevy_derive::Deref;
104use bevy_ecs::{
105prelude::*,
106 schedule::{InternedScheduleLabel, ScheduleLabel},
107};
108use bevy_platform::time::Instant;
109use bevy_shader::{load_shader_library, Shader, ShaderLoader};
110use bevy_time::TimeSender;
111use bevy_window::{PrimaryWindow, RawHandleWrapperHolder};
112use bitflags::bitflags;
113use globals::GlobalsPlugin;
114use occlusion_culling::OcclusionCullingPlugin;
115use render_asset::{
116extract_render_asset_bytes_per_frame, reset_render_asset_bytes_per_frame,
117RenderAssetBytesPerFrame, RenderAssetBytesPerFrameLimiter,
118};
119use settings::RenderResources;
120use std::sync::{Mutex, OnceLock};
121122/// Contains the default Bevy rendering backend based on wgpu.
123///
124/// Rendering is done in a [`SubApp`], which exchanges data with the main app
125/// between main schedule iterations.
126///
127/// Rendering can be executed between iterations of the main schedule,
128/// or it can be executed in parallel with main schedule when
129/// [`PipelinedRenderingPlugin`](pipelined_rendering::PipelinedRenderingPlugin) is enabled.
130#[derive(#[automatically_derived]
impl ::core::default::Default for RenderPlugin {
#[inline]
fn default() -> RenderPlugin {
RenderPlugin {
render_creation: ::core::default::Default::default(),
synchronous_pipeline_compilation: ::core::default::Default::default(),
debug_flags: ::core::default::Default::default(),
}
}
}Default)]
131pub struct RenderPlugin {
132pub render_creation: RenderCreation,
133/// If `true`, disables asynchronous pipeline compilation.
134 /// This has no effect on macOS, Wasm, iOS, or without the `multi_threaded` feature.
135pub synchronous_pipeline_compilation: bool,
136/// Debugging flags that can optionally be set when constructing the renderer.
137pub debug_flags: RenderDebugFlags,
138}
139140bitflags! {
141/// Debugging flags that can optionally be set when constructing the renderer.
142#[derive(#[automatically_derived]
impl ::core::clone::Clone for RenderDebugFlags {
#[inline]
fn clone(&self) -> RenderDebugFlags {
let _:
::core::clone::AssertParamIsClone<<RenderDebugFlags as
::bitflags::__private::PublicFlags>::Internal>;
*self
}
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
const _: () =
{
#[repr(transparent)]
pub struct InternalBitFlags(u8);
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for InternalBitFlags { }
#[automatically_derived]
impl ::core::clone::Clone for InternalBitFlags {
#[inline]
fn clone(&self) -> InternalBitFlags {
let _: ::core::clone::AssertParamIsClone<u8>;
*self
}
}
#[automatically_derived]
impl ::core::marker::Copy for InternalBitFlags { }
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
#[automatically_derived]
impl ::core::cmp::PartialEq for InternalBitFlags {
#[inline]
fn eq(&self, other: &InternalBitFlags) -> bool {
self.0 == other.0
}
}
#[automatically_derived]
impl ::core::cmp::Eq for InternalBitFlags {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u8>;
}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for InternalBitFlags {
#[inline]
fn partial_cmp(&self, other: &InternalBitFlags)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self,
other))
}
}
#[automatically_derived]
impl ::core::cmp::Ord for InternalBitFlags {
#[inline]
fn cmp(&self, other: &InternalBitFlags) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&self.0, &other.0)
}
}
#[automatically_derived]
impl ::core::hash::Hash for InternalBitFlags {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}
impl RenderDebugFlags {
#[doc =
r" If true, this sets the `COPY_SRC` flag on indirect draw parameters"]
#[doc = r" so that they can be read back to CPU."]
#[doc = r""]
#[doc =
r" This is a debugging feature that may reduce performance. It"]
#[doc = r" primarily exists for the `occlusion_culling` example."]
pub const ALLOW_COPIES_FROM_INDIRECT_PARAMETERS: Self =
Self::from_bits_retain(1);
}
impl ::bitflags::Flags for RenderDebugFlags {
const FLAGS: &'static [::bitflags::Flag<RenderDebugFlags>] =
{
mod __bitflags_flag_names {
use super::*;
pub(super) const ALLOW_COPIES_FROM_INDIRECT_PARAMETERS:
&'static str =
"ALLOW_COPIES_FROM_INDIRECT_PARAMETERS";
}
&[{
::bitflags::Flag::new(__bitflags_flag_names::ALLOW_COPIES_FROM_INDIRECT_PARAMETERS,
RenderDebugFlags::ALLOW_COPIES_FROM_INDIRECT_PARAMETERS)
}]
};
type Bits = u8;
fn bits(&self) -> u8 { RenderDebugFlags::bits(self) }
fn from_bits_retain(bits: u8) -> RenderDebugFlags {
RenderDebugFlags::from_bits_retain(bits)
}
fn all_named() -> RenderDebugFlags {
const ALL_NAMED: u8 =
{
let mut truncated = <u8 as ::bitflags::Bits>::EMPTY;
let mut i = 0;
{
{
let flag =
&<RenderDebugFlags as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
let _ = i;
truncated
};
RenderDebugFlags::from_bits_retain(ALL_NAMED)
}
}
impl ::bitflags::__private::PublicFlags for RenderDebugFlags {
type Primitive = u8;
type Internal = InternalBitFlags;
}
impl ::bitflags::__private::core::default::Default for
InternalBitFlags {
#[inline]
fn default() -> Self { InternalBitFlags::empty() }
}
impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
fn fmt(&self,
f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
-> ::bitflags::__private::core::fmt::Result {
if self.is_empty() {
f.write_fmt(format_args!("{0:#x}",
<u8 as ::bitflags::Bits>::EMPTY))
} else {
::bitflags::__private::core::fmt::Display::fmt(self, f)
}
}
}
impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
fn fmt(&self,
f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
-> ::bitflags::__private::core::fmt::Result {
::bitflags::parser::to_writer(&RenderDebugFlags(*self), f)
}
}
impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
type Err = ::bitflags::parser::ParseError;
fn from_str(s: &str)
->
::bitflags::__private::core::result::Result<Self,
Self::Err> {
::bitflags::parser::from_str::<RenderDebugFlags>(s).map(|flags|
flags.0)
}
}
impl ::bitflags::__private::core::convert::AsRef<u8> for
InternalBitFlags {
fn as_ref(&self) -> &u8 { &self.0 }
}
impl ::bitflags::__private::core::convert::From<u8> for
InternalBitFlags {
fn from(bits: u8) -> Self { Self::from_bits_retain(bits) }
}
impl InternalBitFlags {
/// Get a flags value with all bits unset.
#[inline]
pub const fn empty() -> Self {
Self(<u8 as ::bitflags::Bits>::EMPTY)
}
/// Get a flags value with all known bits set.
#[inline]
pub const fn all() -> Self {
const ALL: InternalBitFlags =
{
let mut truncated = <u8 as ::bitflags::Bits>::EMPTY;
let mut _i = 0;
{
{
truncated |=
<RenderDebugFlags as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
InternalBitFlags(truncated)
};
ALL
}
/// Get the underlying bits value.
///
/// The returned value is exactly the bits set in this flags value.
#[inline]
pub const fn bits(&self) -> u8 { self.0 }
/// Convert from a bits value.
///
/// This method will return `None` if any unknown bits are set.
#[inline]
pub const fn from_bits(bits: u8)
-> ::bitflags::__private::core::option::Option<Self> {
let truncated = Self::from_bits_truncate(bits).0;
if truncated == bits {
::bitflags::__private::core::option::Option::Some(Self(bits))
} else { ::bitflags::__private::core::option::Option::None }
}
/// Convert from a bits value, unsetting any unknown bits.
#[inline]
pub const fn from_bits_truncate(bits: u8) -> Self {
Self(bits & Self::all().0)
}
/// Convert from a bits value exactly.
#[inline]
pub const fn from_bits_retain(bits: u8) -> Self { Self(bits) }
/// Get a flags value with the bits of a flag with the given name set.
///
/// This method will return `None` if `name` is empty or doesn't
/// correspond to any named flag.
#[inline]
pub fn from_name(name: &str)
-> ::bitflags::__private::core::option::Option<Self> {
mod __bitflags_flag_names {
use super::*;
pub(super) const ALLOW_COPIES_FROM_INDIRECT_PARAMETERS:
&'static str =
"ALLOW_COPIES_FROM_INDIRECT_PARAMETERS";
}
{
{
if name ==
__bitflags_flag_names::ALLOW_COPIES_FROM_INDIRECT_PARAMETERS
{
return ::bitflags::__private::core::option::Option::Some(Self(RenderDebugFlags::ALLOW_COPIES_FROM_INDIRECT_PARAMETERS.bits()));
}
};
};
let _ = name;
::bitflags::__private::core::option::Option::None
}
/// Whether all bits in `self` are unset.
#[inline]
pub const fn is_empty(&self) -> bool {
self.0 == <u8 as ::bitflags::Bits>::EMPTY
}
/// Whether all known bits in this flags value are set.
#[inline]
pub const fn is_all(&self) -> bool {
Self::all().0 | self.0 == self.0
}
/// Whether any set bits in `other` are also set in `self`.
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0 & other.0 != <u8 as ::bitflags::Bits>::EMPTY
}
/// Whether all set bits in `other` are also set in `self`.
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0 & other.0 == other.0
}
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
pub fn insert(&mut self, other: Self) {
*self = Self(self.0).union(other);
}
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `remove` won't truncate `other`, but the `!` operator will.
#[inline]
pub fn remove(&mut self, other: Self) {
*self = Self(self.0).difference(other);
}
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
pub fn toggle(&mut self, other: Self) {
*self = Self(self.0).symmetric_difference(other);
}
/// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
if value { self.insert(other); } else { self.remove(other); }
}
/// The bitwise and (`&`) of the bits in `self` and `other`.
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0 & other.0)
}
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0 & !other.0)
}
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0 ^ other.0)
}
/// The bitwise negation (`!`) of the bits in `self`, truncating the result.
#[inline]
#[must_use]
pub const fn complement(self) -> Self {
Self::from_bits_truncate(!self.0)
}
}
impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
type Output = Self;
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
fn bitor(self, other: InternalBitFlags) -> Self {
self.union(other)
}
}
impl ::bitflags::__private::core::ops::BitOrAssign for
InternalBitFlags {
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
type Output = Self;
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for
InternalBitFlags {
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
type Output = Self;
/// The bitwise and (`&`) of the bits in `self` and `other`.
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for
InternalBitFlags {
/// The bitwise and (`&`) of the bits in `self` and `other`.
#[inline]
fn bitand_assign(&mut self, other: Self) {
*self =
Self::from_bits_retain(self.bits()).intersection(other);
}
}
impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
type Output = Self;
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
{
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
type Output = Self;
/// The bitwise negation (`!`) of the bits in `self`, truncating the result.
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
InternalBitFlags {
/// The bitwise or (`|`) of the bits in each flags value.
fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(&mut self, iterator: T) {
for item in iterator { self.insert(item) }
}
}
impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
for InternalBitFlags {
/// The bitwise or (`|`) of the bits in each flags value.
fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(iterator: T) -> Self {
use ::bitflags::__private::core::iter::Extend;
let mut result = Self::empty();
result.extend(iterator);
result
}
}
impl InternalBitFlags {
/// Yield a set of contained flags values.
///
/// Each yielded flags value will correspond to a defined named flag. Any unknown bits
/// will be yielded together as a final flags value.
#[inline]
pub const fn iter(&self)
-> ::bitflags::iter::Iter<RenderDebugFlags> {
::bitflags::iter::Iter::__private_const_new(<RenderDebugFlags
as ::bitflags::Flags>::FLAGS,
RenderDebugFlags::from_bits_retain(self.bits()),
RenderDebugFlags::from_bits_retain(self.bits()))
}
/// Yield a set of contained named flags values.
///
/// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
/// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
#[inline]
pub const fn iter_names(&self)
-> ::bitflags::iter::IterNames<RenderDebugFlags> {
::bitflags::iter::IterNames::__private_const_new(<RenderDebugFlags
as ::bitflags::Flags>::FLAGS,
RenderDebugFlags::from_bits_retain(self.bits()),
RenderDebugFlags::from_bits_retain(self.bits()))
}
}
impl ::bitflags::__private::core::iter::IntoIterator for
InternalBitFlags {
type Item = RenderDebugFlags;
type IntoIter = ::bitflags::iter::Iter<RenderDebugFlags>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
impl InternalBitFlags {
/// Returns a mutable reference to the raw value of the flags currently stored.
#[inline]
pub fn bits_mut(&mut self) -> &mut u8 { &mut self.0 }
}
impl ::bitflags::__private::serde::Serialize for InternalBitFlags {
fn serialize<S: ::bitflags::__private::serde::Serializer>(&self,
serializer: S)
->
::bitflags::__private::core::result::Result<S::Ok,
S::Error> {
::bitflags::serde::serialize(&RenderDebugFlags::from_bits_retain(self.bits()),
serializer)
}
}
impl<'de> ::bitflags::__private::serde::Deserialize<'de> for
InternalBitFlags {
fn deserialize<D: ::bitflags::__private::serde::Deserializer<'de>>(deserializer:
D)
->
::bitflags::__private::core::result::Result<Self,
D::Error> {
let flags: RenderDebugFlags =
::bitflags::serde::deserialize(deserializer)?;
::bitflags::__private::core::result::Result::Ok(flags.0)
}
}
impl RenderDebugFlags {
/// Get a flags value with all bits unset.
#[inline]
pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
/// Get a flags value with all known bits set.
#[inline]
pub const fn all() -> Self { Self(InternalBitFlags::all()) }
/// Get the underlying bits value.
///
/// The returned value is exactly the bits set in this flags value.
#[inline]
pub const fn bits(&self) -> u8 { self.0.bits() }
/// Convert from a bits value.
///
/// This method will return `None` if any unknown bits are set.
#[inline]
pub const fn from_bits(bits: u8)
-> ::bitflags::__private::core::option::Option<Self> {
match InternalBitFlags::from_bits(bits) {
::bitflags::__private::core::option::Option::Some(bits) =>
::bitflags::__private::core::option::Option::Some(Self(bits)),
::bitflags::__private::core::option::Option::None =>
::bitflags::__private::core::option::Option::None,
}
}
/// Convert from a bits value, unsetting any unknown bits.
#[inline]
pub const fn from_bits_truncate(bits: u8) -> Self {
Self(InternalBitFlags::from_bits_truncate(bits))
}
/// Convert from a bits value exactly.
#[inline]
pub const fn from_bits_retain(bits: u8) -> Self {
Self(InternalBitFlags::from_bits_retain(bits))
}
/// Get a flags value with the bits of a flag with the given name set.
///
/// This method will return `None` if `name` is empty or doesn't
/// correspond to any named flag.
#[inline]
pub fn from_name(name: &str)
-> ::bitflags::__private::core::option::Option<Self> {
match InternalBitFlags::from_name(name) {
::bitflags::__private::core::option::Option::Some(bits) =>
::bitflags::__private::core::option::Option::Some(Self(bits)),
::bitflags::__private::core::option::Option::None =>
::bitflags::__private::core::option::Option::None,
}
}
/// Whether all bits in `self` are unset.
#[inline]
pub const fn is_empty(&self) -> bool { self.0.is_empty() }
/// Whether all known bits in this flags value are set.
#[inline]
pub const fn is_all(&self) -> bool { self.0.is_all() }
/// Whether any set bits in `other` are also set in `self`.
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0.intersects(other.0)
}
/// Whether all set bits in `other` are also set in `self`.
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0.contains(other.0)
}
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `remove` won't truncate `other`, but the `!` operator will.
#[inline]
pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
/// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
self.0.set(other.0, value)
}
/// The bitwise and (`&`) of the bits in `self` and `other`.
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0.intersection(other.0))
}
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0.union(other.0))
}
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0.difference(other.0))
}
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0.symmetric_difference(other.0))
}
/// The bitwise negation (`!`) of the bits in `self`, truncating the result.
#[inline]
#[must_use]
pub const fn complement(self) -> Self {
Self(self.0.complement())
}
}
impl ::bitflags::__private::core::fmt::Binary for RenderDebugFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::Octal for RenderDebugFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::LowerHex for RenderDebugFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::UpperHex for RenderDebugFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::ops::BitOr for RenderDebugFlags {
type Output = Self;
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
fn bitor(self, other: RenderDebugFlags) -> Self {
self.union(other)
}
}
impl ::bitflags::__private::core::ops::BitOrAssign for
RenderDebugFlags {
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for RenderDebugFlags {
type Output = Self;
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for
RenderDebugFlags {
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for RenderDebugFlags {
type Output = Self;
/// The bitwise and (`&`) of the bits in `self` and `other`.
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for
RenderDebugFlags {
/// The bitwise and (`&`) of the bits in `self` and `other`.
#[inline]
fn bitand_assign(&mut self, other: Self) {
*self =
Self::from_bits_retain(self.bits()).intersection(other);
}
}
impl ::bitflags::__private::core::ops::Sub for RenderDebugFlags {
type Output = Self;
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for RenderDebugFlags
{
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for RenderDebugFlags {
type Output = Self;
/// The bitwise negation (`!`) of the bits in `self`, truncating the result.
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<RenderDebugFlags> for
RenderDebugFlags {
/// The bitwise or (`|`) of the bits in each flags value.
fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(&mut self, iterator: T) {
for item in iterator { self.insert(item) }
}
}
impl ::bitflags::__private::core::iter::FromIterator<RenderDebugFlags>
for RenderDebugFlags {
/// The bitwise or (`|`) of the bits in each flags value.
fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(iterator: T) -> Self {
use ::bitflags::__private::core::iter::Extend;
let mut result = Self::empty();
result.extend(iterator);
result
}
}
impl RenderDebugFlags {
/// Yield a set of contained flags values.
///
/// Each yielded flags value will correspond to a defined named flag. Any unknown bits
/// will be yielded together as a final flags value.
#[inline]
pub const fn iter(&self)
-> ::bitflags::iter::Iter<RenderDebugFlags> {
::bitflags::iter::Iter::__private_const_new(<RenderDebugFlags
as ::bitflags::Flags>::FLAGS,
RenderDebugFlags::from_bits_retain(self.bits()),
RenderDebugFlags::from_bits_retain(self.bits()))
}
/// Yield a set of contained named flags values.
///
/// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
/// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
#[inline]
pub const fn iter_names(&self)
-> ::bitflags::iter::IterNames<RenderDebugFlags> {
::bitflags::iter::IterNames::__private_const_new(<RenderDebugFlags
as ::bitflags::Flags>::FLAGS,
RenderDebugFlags::from_bits_retain(self.bits()),
RenderDebugFlags::from_bits_retain(self.bits()))
}
}
impl ::bitflags::__private::core::iter::IntoIterator for
RenderDebugFlags {
type Item = RenderDebugFlags;
type IntoIter = ::bitflags::iter::Iter<RenderDebugFlags>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
};Clone, #[automatically_derived]
impl ::core::marker::Copy for RenderDebugFlags { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for RenderDebugFlags {
#[inline]
fn eq(&self, other: &RenderDebugFlags) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::default::Default for RenderDebugFlags {
#[inline]
fn default() -> RenderDebugFlags {
RenderDebugFlags(::core::default::Default::default())
}
}Default, #[automatically_derived]
impl ::core::fmt::Debug for RenderDebugFlags {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"RenderDebugFlags", &&self.0)
}
}Debug)]
143pub struct RenderDebugFlags: u8 {
144/// If true, this sets the `COPY_SRC` flag on indirect draw parameters
145 /// so that they can be read back to CPU.
146 ///
147 /// This is a debugging feature that may reduce performance. It
148 /// primarily exists for the `occlusion_culling` example.
149const ALLOW_COPIES_FROM_INDIRECT_PARAMETERS = 1;
150 }
151}
152153/// The systems sets of the default [`App`] rendering schedule.
154///
155/// These can be useful for ordering, but you almost never want to add your systems to these sets.
156#[derive(#[automatically_derived]
impl ::core::fmt::Debug for RenderSystems {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
static __NAMES: &str =
"ExtractCommandsPrepareAssetsPrepareMeshesCreateViewsSpecializePrepareViewsQueueQueueMeshesQueueSweepPhaseSortPreparePrepareResourcesPrepareResourcesBatchPhasesPrepareResourcesWritePhaseBuffersPrepareResourcesCollectPhaseBuffersPrepareResourcesFlushPrepareBindGroupsRenderCleanupPostCleanup";
static __OFFSET: [usize; 21] =
[0usize, 15usize, 28usize, 41usize, 52usize, 62usize, 74usize,
79usize, 90usize, 100usize, 109usize, 116usize, 132usize,
159usize, 192usize, 227usize, 248usize, 265usize, 271usize,
278usize, 289usize];
let __d = ::core::intrinsics::discriminant_value(self) as usize;
::core::fmt::Formatter::debug_c_like_enum_write_str(f, __NAMES,
&__OFFSET, __d)
}
}Debug, #[automatically_derived]
impl ::core::hash::Hash for RenderSystems {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
let __self_discr = ::core::intrinsics::discriminant_value(self);
::core::hash::Hash::hash(&__self_discr, state)
}
}Hash, #[automatically_derived]
impl ::core::cmp::PartialEq for RenderSystems {
#[inline]
fn eq(&self, other: &RenderSystems) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for RenderSystems {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::clone::Clone for RenderSystems {
#[inline]
fn clone(&self) -> RenderSystems {
match self {
RenderSystems::ExtractCommands => RenderSystems::ExtractCommands,
RenderSystems::PrepareAssets => RenderSystems::PrepareAssets,
RenderSystems::PrepareMeshes => RenderSystems::PrepareMeshes,
RenderSystems::CreateViews => RenderSystems::CreateViews,
RenderSystems::Specialize => RenderSystems::Specialize,
RenderSystems::PrepareViews => RenderSystems::PrepareViews,
RenderSystems::Queue => RenderSystems::Queue,
RenderSystems::QueueMeshes => RenderSystems::QueueMeshes,
RenderSystems::QueueSweep => RenderSystems::QueueSweep,
RenderSystems::PhaseSort => RenderSystems::PhaseSort,
RenderSystems::Prepare => RenderSystems::Prepare,
RenderSystems::PrepareResources =>
RenderSystems::PrepareResources,
RenderSystems::PrepareResourcesBatchPhases =>
RenderSystems::PrepareResourcesBatchPhases,
RenderSystems::PrepareResourcesWritePhaseBuffers =>
RenderSystems::PrepareResourcesWritePhaseBuffers,
RenderSystems::PrepareResourcesCollectPhaseBuffers =>
RenderSystems::PrepareResourcesCollectPhaseBuffers,
RenderSystems::PrepareResourcesFlush =>
RenderSystems::PrepareResourcesFlush,
RenderSystems::PrepareBindGroups =>
RenderSystems::PrepareBindGroups,
RenderSystems::Render => RenderSystems::Render,
RenderSystems::Cleanup => RenderSystems::Cleanup,
RenderSystems::PostCleanup => RenderSystems::PostCleanup,
}
}
}Clone, const _: () =
{
extern crate alloc;
impl bevy_ecs::schedule::SystemSet for RenderSystems where
Self: 'static + ::core::marker::Send + ::core::marker::Sync +
::core::clone::Clone + ::core::cmp::Eq + ::core::fmt::Debug +
::core::hash::Hash {
fn dyn_clone(&self)
-> alloc::boxed::Box<dyn bevy_ecs::schedule::SystemSet> {
alloc::boxed::Box::new(::core::clone::Clone::clone(self))
}
}
};SystemSet)]
157pub enum RenderSystems {
158/// This is used for applying the commands from the [`ExtractSchedule`]
159ExtractCommands,
160/// Prepare assets that have been created/modified/removed this frame.
161PrepareAssets,
162/// Prepares extracted meshes.
163PrepareMeshes,
164/// Create any additional views such as those used for shadow mapping.
165CreateViews,
166/// Specialize material meshes and shadow views.
167Specialize,
168/// Prepare any additional views such as those used for shadow mapping.
169PrepareViews,
170/// Queue drawable entities as phase items in render phases ready for
171 /// sorting (if necessary)
172Queue,
173/// A sub-set within [`Queue`](RenderSystems::Queue) where mesh entity queue systems are executed. Ensures `prepare_assets::<RenderMesh>` is completed.
174QueueMeshes,
175/// A sub-set within [`Queue`](RenderSystems::Queue) where meshes that have
176 /// become invisible or changed phases are removed from the bins.
177QueueSweep,
178// TODO: This could probably be moved in favor of a system ordering
179 // abstraction in `Render` or `Queue`
180/// Sort the [`SortedRenderPhase`](render_phase::SortedRenderPhase)s and
181 /// [`BinKey`](render_phase::BinnedPhaseItem::BinKey)s here.
182PhaseSort,
183/// Prepare render resources from extracted data for the GPU based on their sorted order.
184 /// Create [`BindGroups`](render_resource::BindGroup) that depend on those data.
185Prepare,
186/// A sub-set within [`Prepare`](RenderSystems::Prepare) for initializing buffers, textures and uniforms for use in bind groups.
187PrepareResources,
188/// A sub-set within [`Prepare`](RenderSystems::Prepare) that creates batches for render phases.
189PrepareResourcesBatchPhases,
190/// A sub-set within [`Prepare`](RenderSystems::Prepare) that writes batches
191 /// for render phases to the GPU.
192PrepareResourcesWritePhaseBuffers,
193/// A sub-set within [`Prepare`](RenderSystems::Prepare) to collect phase buffers after
194 /// [`PrepareResourcesBatchPhases`](RenderSystems::PrepareResourcesBatchPhases) has run.
195PrepareResourcesCollectPhaseBuffers,
196/// Flush buffers after [`PrepareResources`](RenderSystems::PrepareResources), but before [`PrepareBindGroups`](RenderSystems::PrepareBindGroups).
197PrepareResourcesFlush,
198/// A sub-set within [`Prepare`](RenderSystems::Prepare) for constructing bind groups, or other data that relies on render resources prepared in [`PrepareResources`](RenderSystems::PrepareResources).
199PrepareBindGroups,
200/// Actual rendering happens here.
201 /// In most cases, only the render backend should insert resources here.
202Render,
203/// Cleanup render resources here.
204Cleanup,
205/// Final cleanup occurs: any entities with
206 /// [`TemporaryRenderEntity`](sync_world::TemporaryRenderEntity) will be despawned.
207 ///
208 /// Runs after [`Cleanup`](RenderSystems::Cleanup).
209PostCleanup,
210}
211212/// The startup schedule of the [`RenderApp`].
213/// This can potentially run multiple times, and not on a fresh render world.
214/// Every time a new [`RenderDevice`](renderer::RenderDevice) is acquired,
215/// this schedule runs to initialize any gpu resources needed for rendering on it.
216#[derive(const _: () =
{
extern crate alloc;
impl bevy_ecs::schedule::ScheduleLabel for RenderStartup where
Self: 'static + ::core::marker::Send + ::core::marker::Sync +
::core::clone::Clone + ::core::cmp::Eq + ::core::fmt::Debug +
::core::hash::Hash {
fn dyn_clone(&self)
-> alloc::boxed::Box<dyn bevy_ecs::schedule::ScheduleLabel> {
alloc::boxed::Box::new(::core::clone::Clone::clone(self))
}
}
};ScheduleLabel, #[automatically_derived]
impl ::core::fmt::Debug for RenderStartup {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "RenderStartup")
}
}Debug, #[automatically_derived]
impl ::core::hash::Hash for RenderStartup {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {}
}Hash, #[automatically_derived]
impl ::core::cmp::PartialEq for RenderStartup {
#[inline]
fn eq(&self, other: &RenderStartup) -> bool { true }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for RenderStartup {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::clone::Clone for RenderStartup {
#[inline]
fn clone(&self) -> RenderStartup { RenderStartup }
}Clone, #[automatically_derived]
impl ::core::default::Default for RenderStartup {
#[inline]
fn default() -> RenderStartup { RenderStartup {} }
}Default)]
217pub struct RenderStartup;
218219/// Constructs a `T` resource with `from_world` and inserts it.
220pub fn init_gpu_resource<R: Resource + FromWorld>(world: &mut World) {
221let res = R::from_world(world);
222world.insert_resource(res);
223}
224225/// Convenience methods for render-recovery-aware resource initialization.
226pub trait GpuResourceAppExt {
227/// Causes the provided GPU resource to be re-initialized during [`RenderStartup`].
228 ///
229 /// This is useful when recovering from lost render devices.
230 ///
231 /// Shorthand for:
232 /// ```ignore
233 /// app.add_systems(RenderStartup, init_gpu_resource::<R>.ambiguous_with_all());
234 /// ```
235fn init_gpu_resource<R: Resource + FromWorld>(&mut self) -> &mut Self;
236}
237238impl GpuResourceAppExtfor SubApp {
239fn init_gpu_resource<R: Resource + FromWorld>(&mut self) -> &mut Self {
240self.add_systems(RenderStartup, init_gpu_resource::<R>.ambiguous_with_all())
241 }
242}
243244/// The render recovery schedule. This schedule runs the [`RenderScheduleOrder`] schedules if
245/// we are in [`RenderState::Ready`], and is otherwise hidden from users.
246#[derive(const _: () =
{
extern crate alloc;
impl bevy_ecs::schedule::ScheduleLabel for RenderRecovery where
Self: 'static + ::core::marker::Send + ::core::marker::Sync +
::core::clone::Clone + ::core::cmp::Eq + ::core::fmt::Debug +
::core::hash::Hash {
fn dyn_clone(&self)
-> alloc::boxed::Box<dyn bevy_ecs::schedule::ScheduleLabel> {
alloc::boxed::Box::new(::core::clone::Clone::clone(self))
}
}
};ScheduleLabel, #[automatically_derived]
impl ::core::fmt::Debug for RenderRecovery {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "RenderRecovery")
}
}Debug, #[automatically_derived]
impl ::core::hash::Hash for RenderRecovery {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {}
}Hash, #[automatically_derived]
impl ::core::cmp::PartialEq for RenderRecovery {
#[inline]
fn eq(&self, other: &RenderRecovery) -> bool { true }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for RenderRecovery {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::clone::Clone for RenderRecovery {
#[inline]
fn clone(&self) -> RenderRecovery { RenderRecovery }
}Clone)]
247struct RenderRecovery;
248249/// Defines the schedules to be run for the rendering, including their order.
250///
251/// This is the same approach as [`MainScheduleOrder`](`bevy_app::MainScheduleOrder`).
252#[derive(impl bevy_ecs::resource::Resource for RenderScheduleOrder where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]
impl ::core::fmt::Debug for RenderScheduleOrder {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"RenderScheduleOrder", "labels", &&self.labels)
}
}Debug)]
253pub struct RenderScheduleOrder {
254/// The labels to run for the rendering schedule (in the order they will be run).
255pub labels: Vec<InternedScheduleLabel>,
256}
257258impl Defaultfor RenderScheduleOrder {
259fn default() -> Self {
260Self {
261 labels: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[First.intern(), Render.intern()]))vec![First.intern(), Render.intern()],
262 }
263 }
264}
265266impl RenderScheduleOrder {
267/// Adds the given `schedule` after the `after` schedule
268pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) {
269let index = self270 .labels
271 .iter()
272 .position(|current| (**current).eq(&after))
273 .unwrap_or_else(|| {
::core::panicking::panic_fmt(format_args!("Expected {0:?} to exist",
after));
}panic!("Expected {after:?} to exist"));
274self.labels.insert(index + 1, schedule.intern());
275 }
276277/// Adds the given `schedule` before the `before` schedule
278pub fn insert_before(&mut self, before: impl ScheduleLabel, schedule: impl ScheduleLabel) {
279let index = self280 .labels
281 .iter()
282 .position(|current| (**current).eq(&before))
283 .unwrap_or_else(|| {
::core::panicking::panic_fmt(format_args!("Expected {0:?} to exist",
before));
}panic!("Expected {before:?} to exist"));
284self.labels.insert(index, schedule.intern());
285 }
286}
287288/// The main render schedule.
289#[derive(const _: () =
{
extern crate alloc;
impl bevy_ecs::schedule::ScheduleLabel for Render where
Self: 'static + ::core::marker::Send + ::core::marker::Sync +
::core::clone::Clone + ::core::cmp::Eq + ::core::fmt::Debug +
::core::hash::Hash {
fn dyn_clone(&self)
-> alloc::boxed::Box<dyn bevy_ecs::schedule::ScheduleLabel> {
alloc::boxed::Box::new(::core::clone::Clone::clone(self))
}
}
};ScheduleLabel, #[automatically_derived]
impl ::core::fmt::Debug for Render {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "Render")
}
}Debug, #[automatically_derived]
impl ::core::hash::Hash for Render {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {}
}Hash, #[automatically_derived]
impl ::core::cmp::PartialEq for Render {
#[inline]
fn eq(&self, other: &Render) -> bool { true }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Render {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::clone::Clone for Render {
#[inline]
fn clone(&self) -> Render { Render }
}Clone, #[automatically_derived]
impl ::core::default::Default for Render {
#[inline]
fn default() -> Render { Render {} }
}Default)]
290pub struct Render;
291292impl Render {
293/// Sets up the base structure of the rendering [`Schedule`].
294 ///
295 /// The sets defined in this enum are configured to run in order.
296pub fn base_schedule() -> Schedule {
297use RenderSystems::*;
298299let mut schedule = Schedule::new(Self);
300301schedule.configure_sets(
302 (
303ExtractCommands,
304PrepareMeshes,
305CreateViews,
306Specialize,
307PrepareViews,
308Queue,
309PhaseSort,
310Prepare,
311Render,
312Cleanup,
313PostCleanup,
314 )
315 .chain(),
316 );
317schedule.ignore_ambiguity(Specialize, Specialize);
318319schedule.configure_sets((ExtractCommands, PrepareAssets, PrepareMeshes, Prepare).chain());
320schedule.configure_sets(
321 (QueueMeshes, QueueSweep)
322 .chain()
323 .in_set(Queue)
324 .after(prepare_assets::<RenderMesh>),
325 );
326schedule.configure_sets(
327 (
328PrepareResources,
329PrepareResourcesBatchPhases,
330PrepareResourcesWritePhaseBuffers,
331PrepareResourcesCollectPhaseBuffers,
332PrepareResourcesFlush,
333PrepareBindGroups,
334 )
335 .chain()
336 .in_set(Prepare),
337 );
338339schedule340 }
341}
342343#[derive(impl bevy_ecs::resource::Resource for FutureRenderResources where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]
impl ::core::default::Default for FutureRenderResources {
#[inline]
fn default() -> FutureRenderResources {
FutureRenderResources(::core::default::Default::default())
}
}Default, #[automatically_derived]
impl ::core::clone::Clone for FutureRenderResources {
#[inline]
fn clone(&self) -> FutureRenderResources {
FutureRenderResources(::core::clone::Clone::clone(&self.0))
}
}Clone, impl ::core::ops::Deref for FutureRenderResources {
type Target = Arc<Mutex<Option<RenderResources>>>;
fn deref(&self) -> &Self::Target { &self.0 }
}Deref)]
344pub(crate) struct FutureRenderResources(Arc<Mutex<Option<RenderResources>>>);
345346/// A label for the rendering sub-app.
347#[derive(#[automatically_derived]
impl ::core::fmt::Debug for RenderApp {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "RenderApp")
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for RenderApp {
#[inline]
fn clone(&self) -> RenderApp { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for RenderApp { }Copy, #[automatically_derived]
impl ::core::hash::Hash for RenderApp {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {}
}Hash, #[automatically_derived]
impl ::core::cmp::PartialEq for RenderApp {
#[inline]
fn eq(&self, other: &RenderApp) -> bool { true }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for RenderApp {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, const _: () =
{
extern crate alloc;
impl bevy_app::AppLabel for RenderApp where Self: 'static +
::core::marker::Send + ::core::marker::Sync +
::core::clone::Clone + ::core::cmp::Eq + ::core::fmt::Debug +
::core::hash::Hash {
fn dyn_clone(&self) -> alloc::boxed::Box<dyn bevy_app::AppLabel> {
alloc::boxed::Box::new(::core::clone::Clone::clone(self))
}
}
};AppLabel)]
348pub struct RenderApp;
349350impl Pluginfor RenderPlugin {
351/// Initializes the renderer, sets up the [`RenderSystems`] and creates the rendering sub-app.
352fn build(&self, app: &mut App) {
353app.init_asset::<Shader>()
354 .init_asset_loader::<ShaderLoader>();
355{
{
let mut embedded =
app.world_mut().resource_mut::<::bevy_asset::io::embedded::EmbeddedAssetRegistry>();
let path =
{
let crate_name = "bevy_render".split(':').next().unwrap();
::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
"src".as_ref(), "src/lib.rs".as_ref(),
"maths.wgsl".as_ref())
};
let watched_path =
::bevy_asset::io::embedded::watched_path("src/lib.rs",
"maths.wgsl");
embedded.insert_asset(watched_path, &path,
b"#define_import_path bevy_render::maths\n\nconst PI: f32 = 3.141592653589793; // \xcf\x80\nconst PI_2: f32 = 6.283185307179586; // 2\xcf\x80\nconst HALF_PI: f32 = 1.57079632679; // \xcf\x80/2\nconst FRAC_PI_3: f32 = 1.0471975512; // \xcf\x80/3\nconst E: f32 = 2.718281828459045; // exp(1)\n\nfn affine2_to_square(affine: mat3x2<f32>) -> mat3x3<f32> {\n return mat3x3<f32>(\n vec3<f32>(affine[0].xy, 0.0),\n vec3<f32>(affine[1].xy, 0.0),\n vec3<f32>(affine[2].xy, 1.0),\n );\n}\n\nfn affine3_to_square(affine: mat3x4<f32>) -> mat4x4<f32> {\n return transpose(mat4x4<f32>(\n affine[0],\n affine[1],\n affine[2],\n vec4<f32>(0.0, 0.0, 0.0, 1.0),\n ));\n}\n\nfn mat2x4_f32_to_mat3x3_unpack(\n a: mat2x4<f32>,\n b: f32,\n) -> mat3x3<f32> {\n return mat3x3<f32>(\n a[0].xyz,\n vec3<f32>(a[0].w, a[1].xy),\n vec3<f32>(a[1].zw, b),\n );\n}\n\n// Extracts the square portion of an affine matrix: i.e. discards the\n// translation.\nfn affine3_to_mat3x3(affine: mat4x3<f32>) -> mat3x3<f32> {\n return mat3x3<f32>(affine[0].xyz, affine[1].xyz, affine[2].xyz);\n}\n\n// Returns the inverse of a 3x3 matrix.\nfn inverse_mat3x3(matrix: mat3x3<f32>) -> mat3x3<f32> {\n let tmp0 = cross(matrix[1], matrix[2]);\n let tmp1 = cross(matrix[2], matrix[0]);\n let tmp2 = cross(matrix[0], matrix[1]);\n let inv_det = 1.0 / dot(matrix[2], tmp2);\n return transpose(mat3x3<f32>(tmp0 * inv_det, tmp1 * inv_det, tmp2 * inv_det));\n}\n\n// Returns the inverse of an affine matrix.\n//\n// https://en.wikipedia.org/wiki/Affine_transformation#Groups\nfn inverse_affine3(affine: mat4x3<f32>) -> mat4x3<f32> {\n let matrix3 = affine3_to_mat3x3(affine);\n let inv_matrix3 = inverse_mat3x3(matrix3);\n return mat4x3<f32>(inv_matrix3[0], inv_matrix3[1], inv_matrix3[2], -(inv_matrix3 * affine[3]));\n}\n\n// Extracts the upper 3x3 portion of a 4x4 matrix.\nfn mat4x4_to_mat3x3(m: mat4x4<f32>) -> mat3x3<f32> {\n return mat3x3<f32>(m[0].xyz, m[1].xyz, m[2].xyz);\n}\n\n// Copy the sign bit from B onto A.\n// copysign allows proper handling of negative zero to match the rust implementation of orthonormalize\nfn copysign(a: f32, b: f32) -> f32 {\n return bitcast<f32>((bitcast<u32>(a) & 0x7FFFFFFF) | (bitcast<u32>(b) & 0x80000000));\n}\n\n// Constructs a right-handed orthonormal basis from a given unit Z vector.\n//\n// NOTE: requires unit-length (normalized) input to function properly.\n//\n// https://jcgt.org/published/0006/01/01/paper.pdf\n// this method of constructing a basis from a vec3 is also used by `glam::Vec3::any_orthonormal_pair`\n// the construction of the orthonormal basis up and right vectors here needs to precisely match the rust\n// implementation in bevy_light/spot_light.rs:spot_light_world_from_view\nfn orthonormalize(z_basis: vec3<f32>) -> mat3x3<f32> {\n let sign = copysign(1.0, z_basis.z);\n let a = -1.0 / (sign + z_basis.z);\n let b = z_basis.x * z_basis.y * a;\n let x_basis = vec3(1.0 + sign * z_basis.x * z_basis.x * a, sign * b, -sign * z_basis.x);\n let y_basis = vec3(b, sign + z_basis.y * z_basis.y * a, -z_basis.y);\n return mat3x3(x_basis, y_basis, z_basis);\n}\n\n// Returns true if any part of a sphere is on the positive side of a plane.\n//\n// `sphere_center.w` should be 1.0.\n//\n// This is used for frustum culling.\nfn sphere_intersects_plane_half_space(\n plane: vec4<f32>,\n sphere_center: vec4<f32>,\n sphere_radius: f32\n) -> bool {\n return dot(plane, sphere_center) + sphere_radius > 0.0;\n}\n\n// Returns the distances along the ray to its intersections with a sphere\n// centered at the origin.\n//\n// r: distance from the sphere center to the ray origin\n// mu: cosine of the zenith angle\n// sphere_radius: radius of the sphere\n//\n// Returns vec2(t0, t1). If there is no intersection, returns vec2(-1.0).\nfn ray_sphere_intersect(r: f32, mu: f32, sphere_radius: f32) -> vec2<f32> {\n let discriminant = r * r * (mu * mu - 1.0) + sphere_radius * sphere_radius;\n \n // No intersection\n if discriminant < 0.0 {\n return vec2(-1.0);\n }\n \n let q = -r * mu;\n let sqrt_discriminant = sqrt(discriminant);\n \n // Return both intersection distances\n return vec2(\n q - sqrt_discriminant,\n q + sqrt_discriminant\n );\n}\n\n// pow() but safe for NaNs/negatives\nfn powsafe(color: vec3<f32>, power: f32) -> vec3<f32> {\n return pow(abs(color), vec3(power)) * sign(color);\n}\n\n// https://en.wikipedia.org/wiki/Vector_projection#Vector_projection_2\nfn project_onto(lhs: vec3<f32>, rhs: vec3<f32>) -> vec3<f32> {\n let other_len_sq_rcp = 1.0 / dot(rhs, rhs);\n return rhs * dot(lhs, rhs) * other_len_sq_rcp;\n}\n\n// Below are fast approximations of common irrational and trig functions. These\n// are likely most useful when raymarching, for example, where complete numeric\n// accuracy can be sacrificed for greater sample count.\n\n// Slightly less accurate than fast_acos_4, but much simpler.\nfn fast_acos(in_x: f32) -> f32 {\n let x = abs(in_x);\n var res = -0.156583 * x + HALF_PI;\n res *= sqrt(1.0 - x);\n return select(PI - res, res, in_x >= 0.0);\n}\n\n// 4th order polynomial approximation\n// 4 VGRP, 16 ALU Full Rate\n// 7 * 10^-5 radians precision\n// Reference : Handbook of Mathematical Functions (chapter : Elementary Transcendental Functions), M. Abramowitz and I.A. Stegun, Ed.\nfn fast_acos_4(x: f32) -> f32 {\n let x1 = abs(x);\n let x2 = x1 * x1;\n let x3 = x2 * x1;\n var s: f32;\n\n s = -0.2121144 * x1 + 1.5707288;\n s = 0.0742610 * x2 + s;\n s = -0.0187293 * x3 + s;\n s = sqrt(1.0 - x1) * s;\n\n\t// acos function mirroring\n return select(PI - s, s, x >= 0.0);\n}\n\nfn fast_atan2(y: f32, x: f32) -> f32 {\n var t0 = max(abs(x), abs(y));\n var t1 = min(abs(x), abs(y));\n var t3 = t1 / t0;\n var t4 = t3 * t3;\n\n t0 = 0.0872929;\n t0 = t0 * t4 - 0.301895;\n t0 = t0 * t4 + 1.0;\n t3 = t0 * t3;\n\n t3 = select(t3, (0.5 * PI) - t3, abs(y) > abs(x));\n t3 = select(t3, PI - t3, x < 0);\n t3 = select(-t3, t3, y > 0);\n\n return t3;\n}\n");
}
};
let handle:
::bevy_shader::_macro::bevy_asset::prelude::Handle<::bevy_shader::prelude::Shader> =
{
let (path, asset_server) =
{
let path =
{
{
let crate_name = "bevy_render".split(':').next().unwrap();
::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
"src".as_ref(), "src/lib.rs".as_ref(),
"maths.wgsl".as_ref())
}
};
let path =
::bevy_asset::AssetPath::from_path_buf(path).with_source("embedded");
let asset_server =
::bevy_asset::io::embedded::GetAssetServer::get_asset_server(app);
(path, asset_server)
};
asset_server.load(path)
};
core::mem::forget(handle);load_shader_library!(app, "maths.wgsl");
356{
{
let mut embedded =
app.world_mut().resource_mut::<::bevy_asset::io::embedded::EmbeddedAssetRegistry>();
let path =
{
let crate_name = "bevy_render".split(':').next().unwrap();
::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
"src".as_ref(), "src/lib.rs".as_ref(),
"color_operations.wgsl".as_ref())
};
let watched_path =
::bevy_asset::io::embedded::watched_path("src/lib.rs",
"color_operations.wgsl");
embedded.insert_asset(watched_path, &path,
b"#define_import_path bevy_render::color_operations\n\n#import bevy_render::maths::{PI_2,PI,FRAC_PI_3}\n\nconst HUE_GUARD: f32 = 0.0001;\n\n// https://en.wikipedia.org/wiki/SRGB\nfn gamma(value: f32) -> f32 {\n if value <= 0.0 {\n return value;\n }\n if value <= 0.04045 {\n return value / 12.92; // linear falloff in dark values\n } else {\n return pow((value + 0.055) / 1.055, 2.4); // gamma curve in other area\n }\n}\n\n// https://en.wikipedia.org/wiki/SRGB\nfn inverse_gamma(value: f32) -> f32 {\n if value <= 0.0 {\n return value;\n }\n\n if value <= 0.0031308 {\n return value * 12.92; // linear falloff in dark values\n } else {\n return 1.055 * pow(value, 1.0 / 2.4) - 0.055; // gamma curve in other area\n }\n}\n\nfn srgb_to_linear_rgb(color: vec3<f32>) -> vec3<f32> {\n return vec3(\n gamma(color.x),\n gamma(color.y),\n gamma(color.z)\n );\n}\n\nfn linear_rgb_to_srgb(color: vec3<f32>) -> vec3<f32> {\n return vec3(\n inverse_gamma(color.x),\n inverse_gamma(color.y),\n inverse_gamma(color.z)\n );\n}\n\nfn linear_to_srgb(color: vec3<f32>) -> vec3<f32> {\n return linear_rgb_to_srgb(color);\n}\n\nfn srgb_to_linear(color: vec3<f32>) -> vec3<f32> {\n return srgb_to_linear_rgb(color);\n}\n\n// https://bottosson.github.io/posts/oklab/\nfn oklab_to_linear_rgb(c: vec3<f32>) -> vec3<f32> {\n let l_ = c.x + 0.39633778 * c.y + 0.21580376 * c.z;\n let m_ = c.x - 0.105561346 * c.y - 0.06385417 * c.z;\n let s_ = c.x - 0.08948418 * c.y - 1.2914855 * c.z;\n let l = l_ * l_ * l_;\n let m = m_ * m_ * m_;\n let s = s_ * s_ * s_;\n return vec3(\n 4.0767417 * l - 3.3077116 * m + 0.23096994 * s,\n -1.268438 * l + 2.6097574 * m - 0.34131938 * s,\n -0.0041960863 * l - 0.7034186 * m + 1.7076147 * s,\n );\n}\n\n// https://bottosson.github.io/posts/oklab/ - inverse of oklab_to_linear_rgb\nfn linear_rgb_to_oklab(c: vec3<f32>) -> vec3<f32> {\n let l_ = pow(c.x * 0.4122214708 + c.y * 0.5363325363 + c.z * 0.0514459929, 1.0 / 3.0);\n let m_ = pow(c.x * 0.2119034982 + c.y * 0.6806995451 + c.z * 0.1073969566, 1.0 / 3.0);\n let s_ = pow(c.x * 0.0883024619 + c.y * 0.2817188376 + c.z * 0.6299787005, 1.0 / 3.0);\n return vec3(\n 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_,\n 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_,\n 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_,\n );\n}\n\nfn hsl_to_linear_rgb(hsl: vec3<f32>) -> vec3<f32> {\n let h = hsl.x;\n let s = hsl.y;\n let l = hsl.z;\n let c = (1.0 - abs(2.0 * l - 1.0)) * s;\n let hp = h * 6.0;\n let x = c * (1.0 - abs(hp % 2.0 - 1.0));\n var r: f32 = 0.0;\n var g: f32 = 0.0;\n var b: f32 = 0.0;\n if 0.0 <= hp && hp < 1.0 {\n r = c; g = x; b = 0.0;\n } else if 1.0 <= hp && hp < 2.0 {\n r = x; g = c; b = 0.0;\n } else if 2.0 <= hp && hp < 3.0 {\n r = 0.0; g = c; b = x;\n } else if 3.0 <= hp && hp < 4.0 {\n r = 0.0; g = x; b = c;\n } else if 4.0 <= hp && hp < 5.0 {\n r = x; g = 0.0; b = c;\n } else if 5.0 <= hp && hp < 6.0 {\n r = c; g = 0.0; b = x;\n }\n let m = l - 0.5 * c;\n return srgb_to_linear_rgb(vec3(r + m, g + m, b + m));\n}\n\nfn hsv_to_linear_rgb(hsva: vec3<f32>) -> vec3<f32> {\n let h = hsva.x * 6.0;\n let s = hsva.y;\n let v = hsva.z;\n let c = v * s;\n let x = c * (1.0 - abs(h % 2.0 - 1.0));\n let m = v - c;\n var r: f32 = 0.0;\n var g: f32 = 0.0;\n var b: f32 = 0.0;\n if 0.0 <= h && h < 1.0 {\n r = c; g = x; b = 0.0;\n } else if 1.0 <= h && h < 2.0 {\n r = x; g = c; b = 0.0;\n } else if 2.0 <= h && h < 3.0 {\n r = 0.0; g = c; b = x;\n } else if 3.0 <= h && h < 4.0 {\n r = 0.0; g = x; b = c;\n } else if 4.0 <= h && h < 5.0 {\n r = x; g = 0.0; b = c;\n } else if 5.0 <= h && h < 6.0 {\n r = c; g = 0.0; b = x;\n }\n return srgb_to_linear_rgb(vec3(r + m, g + m, b + m));\n}\n\nfn oklch_to_linear_rgb(c: vec3<f32>) -> vec3<f32> {\n let hue = c.z * PI_2;\n return oklab_to_linear_rgb(vec3(c.x, c.y * cos(hue), c.y * sin(hue)));\n}\n\nfn mix_oklch(a: vec3<f32>, b: vec3<f32>, t: f32) -> vec3<f32> {\n // If the chroma is close to zero for one of the endpoints, don\'t interpolate \n // the hue and instead use the hue of the other endpoint. This allows gradients that smoothly \n // transition from black or white to a target color without passing through unrelated hues.\n var h = a.z;\n var g = b.z;\n if a.y < HUE_GUARD {\n h = g;\n } else if b.y < HUE_GUARD {\n g = h;\n }\n\n let hue_diff = g - h;\n if abs(hue_diff) > 0.5 {\n if hue_diff > 0.0 {\n h += (hue_diff - 1.) * t;\n } else {\n h += (hue_diff + 1.) * t;\n }\n } else {\n h += hue_diff * t;\n }\n return vec3(\n mix(a.x, b.x, t),\n mix(a.y, b.y, t),\n fract(h),\n );\n}\n\nfn mix_oklch_long(a: vec3<f32>, b: vec3<f32>, t: f32) -> vec3<f32> {\n var h = a.z;\n var g = b.z;\n if a.y < HUE_GUARD {\n h = g;\n } else if b.y < HUE_GUARD {\n g = h;\n }\n\n let hue_diff = g - h;\n if abs(hue_diff) < 0.5 {\n if hue_diff >= 0.0 {\n h += (hue_diff - 1.) * t;\n } else {\n h += (hue_diff + 1.) * t;\n }\n } else {\n h += hue_diff * t;\n }\n return vec3(\n mix(a.x, b.x, t),\n mix(a.y, b.y, t),\n fract(h),\n );\n}\n\nfn mix_hsl(a: vec3<f32>, b: vec3<f32>, t: f32) -> vec3<f32> {\n // If the saturation is close to zero for one of the endpoints, don\'t interpolate \n // the hue and instead use the hue of the other endpoint. This allows gradients that smoothly \n // transition from black or white to a target color without passing through unrelated hues.\n var h = a.x; \n var g = b.x;\n if a.y < HUE_GUARD {\n h = g;\n } else if b.y < HUE_GUARD {\n g = h;\n }\n\n return vec3(\n fract(h + (fract(g - h + 0.5) - 0.5) * t),\n mix(a.y, b.y, t),\n mix(a.z, b.z, t),\n );\n}\n\nfn mix_hsl_long(a: vec3<f32>, b: vec3<f32>, t: f32) -> vec3<f32> {\n var h = a.x;\n var g = b.x;\n if a.y < HUE_GUARD {\n h = g;\n } else if b.y < HUE_GUARD {\n g = h;\n }\n\n let d = fract(g - h + 0.5) - 0.5;\n return vec3(\n fract(h + (d + select(1., -1., 0. < d)) * t),\n mix(a.y, b.y, t),\n mix(a.z, b.z, t),\n );\n}\n\nfn mix_hsv(a: vec3<f32>, b: vec3<f32>, t: f32) -> vec3<f32> {\n // If the saturation is close to zero for one of the endpoints, don\'t interpolate \n // the hue and instead use the hue of the other endpoint. This allows gradients that smoothly \n // transition from black or white to a target color without passing through unrelated hues.\n var h = a.x;\n var g = b.x;\n if a.y < HUE_GUARD {\n h = g;\n } else if b.y < HUE_GUARD {\n g = h;\n }\n\n let hue_diff = g - h;\n if abs(hue_diff) > 0.5 {\n if hue_diff > 0.0 {\n h += (hue_diff - 1.0) * t;\n } else {\n h += (hue_diff + 1.0) * t;\n }\n } else {\n h += hue_diff * t;\n }\n return vec3(\n fract(h),\n mix(a.y, b.y, t),\n mix(a.z, b.z, t),\n );\n}\n\nfn mix_hsv_long(a: vec3<f32>, b: vec3<f32>, t: f32) -> vec3<f32> {\n var h = a.x;\n var g = b.x;\n if a.y < HUE_GUARD {\n h = g;\n } else if b.y < HUE_GUARD {\n g = h;\n }\n\n let hue_diff = g - h;\n if abs(hue_diff) < 0.5 {\n if hue_diff >= 0.0 {\n h += (hue_diff - 1.0) * t;\n } else {\n h += (hue_diff + 1.0) * t;\n }\n } else {\n h += hue_diff * t;\n }\n return vec3(\n fract(h),\n mix(a.y, b.y, t),\n mix(a.z, b.z, t),\n );\n}\n\n// Converts HSV to RGB.\n//\n// Input: H \xe2\x88\x88 [0, 2\xcf\x80), S \xe2\x88\x88 [0, 1], V \xe2\x88\x88 [0, 1].\n// Output: R \xe2\x88\x88 [0, 1], G \xe2\x88\x88 [0, 1], B \xe2\x88\x88 [0, 1].\n//\n// <https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB_alternative>\nfn hsv_to_rgb(hsv: vec3<f32>) -> vec3<f32> {\n let n = vec3(5.0, 3.0, 1.0);\n let k = (n + hsv.x / FRAC_PI_3) % 6.0;\n return hsv.z - hsv.z * hsv.y * max(vec3(0.0), min(k, min(4.0 - k, vec3(1.0))));\n}\n\n// Converts RGB to HSV.\n//\n// Input: R \xe2\x88\x88 [0, 1], G \xe2\x88\x88 [0, 1], B \xe2\x88\x88 [0, 1].\n// Output: H \xe2\x88\x88 [0, 2\xcf\x80), S \xe2\x88\x88 [0, 1], V \xe2\x88\x88 [0, 1].\n//\n// <https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB>\nfn rgb_to_hsv(rgb: vec3<f32>) -> vec3<f32> {\n let x_max = max(rgb.r, max(rgb.g, rgb.b)); // i.e. V\n let x_min = min(rgb.r, min(rgb.g, rgb.b));\n let c = x_max - x_min; // chroma\n\n var swizzle = vec3<f32>(0.0);\n if (x_max == rgb.r) {\n swizzle = vec3(rgb.gb, 0.0);\n } else if (x_max == rgb.g) {\n swizzle = vec3(rgb.br, 2.0);\n } else {\n swizzle = vec3(rgb.rg, 4.0);\n }\n\n let h = FRAC_PI_3 * (((swizzle.x - swizzle.y) / c + swizzle.z) % 6.0);\n\n // Avoid division by zero.\n var s = 0.0;\n if (x_max > 0.0) {\n s = c / x_max;\n }\n\n return vec3(h, s, x_max);\n}\n\n");
}
};
let handle:
::bevy_shader::_macro::bevy_asset::prelude::Handle<::bevy_shader::prelude::Shader> =
{
let (path, asset_server) =
{
let path =
{
{
let crate_name = "bevy_render".split(':').next().unwrap();
::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
"src".as_ref(), "src/lib.rs".as_ref(),
"color_operations.wgsl".as_ref())
}
};
let path =
::bevy_asset::AssetPath::from_path_buf(path).with_source("embedded");
let asset_server =
::bevy_asset::io::embedded::GetAssetServer::get_asset_server(app);
(path, asset_server)
};
asset_server.load(path)
};
core::mem::forget(handle);load_shader_library!(app, "color_operations.wgsl");
357{
{
let mut embedded =
app.world_mut().resource_mut::<::bevy_asset::io::embedded::EmbeddedAssetRegistry>();
let path =
{
let crate_name = "bevy_render".split(':').next().unwrap();
::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
"src".as_ref(), "src/lib.rs".as_ref(),
"bindless.wgsl".as_ref())
};
let watched_path =
::bevy_asset::io::embedded::watched_path("src/lib.rs",
"bindless.wgsl");
embedded.insert_asset(watched_path, &path,
b"// Defines the common arrays used to access bindless resources.\n//\n// This need to be kept up to date with the `BINDING_NUMBERS` table in\n// `bindless.rs`.\n//\n// You access these by indexing into the bindless index table, and from there\n// indexing into the appropriate binding array. For example, to access the base\n// color texture of a `StandardMaterial` in bindless mode, write\n// `bindless_textures_2d[materials[slot].base_color_texture]`, where\n// `materials` is the bindless index table and `slot` is the index into that\n// table (which can be found in the `Mesh`).\n\n#define_import_path bevy_render::bindless\n\n#ifdef BINDLESS\n\n// Binding 0 is the bindless index table.\n// Filtering samplers.\n@group(#{MATERIAL_BIND_GROUP}) @binding(1) var bindless_samplers_filtering: binding_array<sampler>;\n// Non-filtering samplers (nearest neighbor).\n@group(#{MATERIAL_BIND_GROUP}) @binding(2) var bindless_samplers_non_filtering: binding_array<sampler>;\n// Comparison samplers (typically for shadow mapping).\n@group(#{MATERIAL_BIND_GROUP}) @binding(3) var bindless_samplers_comparison: binding_array<sampler>;\n// 1D textures.\n@group(#{MATERIAL_BIND_GROUP}) @binding(4) var bindless_textures_1d: binding_array<texture_1d<f32>>;\n// 2D textures.\n@group(#{MATERIAL_BIND_GROUP}) @binding(5) var bindless_textures_2d: binding_array<texture_2d<f32>>;\n// 2D array textures.\n@group(#{MATERIAL_BIND_GROUP}) @binding(6) var bindless_textures_2d_array: binding_array<texture_2d_array<f32>>;\n// 3D textures.\n@group(#{MATERIAL_BIND_GROUP}) @binding(7) var bindless_textures_3d: binding_array<texture_3d<f32>>;\n// Cubemap textures.\n@group(#{MATERIAL_BIND_GROUP}) @binding(8) var bindless_textures_cube: binding_array<texture_cube<f32>>;\n// Cubemap array textures.\n@group(#{MATERIAL_BIND_GROUP}) @binding(9) var bindless_textures_cube_array: binding_array<texture_cube_array<f32>>;\n\n#endif // BINDLESS\n");
}
};
let handle:
::bevy_shader::_macro::bevy_asset::prelude::Handle<::bevy_shader::prelude::Shader> =
{
let (path, asset_server) =
{
let path =
{
{
let crate_name = "bevy_render".split(':').next().unwrap();
::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
"src".as_ref(), "src/lib.rs".as_ref(),
"bindless.wgsl".as_ref())
}
};
let path =
::bevy_asset::AssetPath::from_path_buf(path).with_source("embedded");
let asset_server =
::bevy_asset::io::embedded::GetAssetServer::get_asset_server(app);
(path, asset_server)
};
asset_server.load(path)
};
core::mem::forget(handle);load_shader_library!(app, "bindless.wgsl");
358359if insert_future_resources(&self.render_creation, app.world_mut()) {
360// We only create the render world and set up extraction if we
361 // have a rendering backend available.
362app.add_plugins(ExtractPlugin {
363 pre_extract: error_handler::update_state,
364 });
365 };
366367app.add_plugins((
368WindowRenderPlugin,
369CameraPlugin,
370ViewPlugin,
371MeshRenderAssetPlugin,
372GlobalsPlugin,
373TexturePlugin,
374BatchingPlugin {
375 debug_flags: self.debug_flags,
376 },
377StoragePlugin,
378GpuReadbackPlugin::default(),
379OcclusionCullingPlugin,
380SparseBufferPlugin,
381#[cfg(feature = "tracing-tracy")]
382diagnostic::RenderDiagnosticsPlugin,
383 ));
384385let (sender, receiver) = bevy_time::create_time_channels();
386app.insert_resource(receiver);
387388let asset_server = app.world().resource::<AssetServer>().clone();
389app.init_resource::<RenderAssetBytesPerFrame>()
390 .init_resource::<RenderErrorHandler>();
391if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
392render_app.init_resource::<RenderScheduleOrder>();
393render_app.init_resource::<RenderAssetBytesPerFrameLimiter>();
394render_app.init_gpu_resource::<renderer::PendingCommandBuffers>();
395render_app.insert_resource(sender);
396render_app.insert_resource(asset_server);
397render_app.insert_resource(RenderState::Initializing);
398render_app.add_systems(
399ExtractSchedule,
400 (
401extract_render_asset_bytes_per_frame,
402PipelineCache::extract_shaders,
403 ),
404 );
405406#[cfg(not(feature = "reflect_auto_register"))]
407render_app.init_resource::<AppTypeRegistry>();
408409#[cfg(feature = "reflect_auto_register")]
410render_app.insert_resource(AppTypeRegistry::new_with_derived_types());
411412#[cfg(feature = "reflect_functions")]
413render_app.init_resource::<AppFunctionRegistry>();
414415render_app.add_schedule(RenderGraph::base_schedule());
416417render_app.init_schedule(RenderStartup);
418render_app419 .get_schedule_mut(RenderStartup)
420 .unwrap()
421 .set_executor(bevy_ecs::schedule::SingleThreadedExecutor::new());
422render_app.update_schedule = Some(RenderRecovery.intern());
423render_app.add_systems(
424RenderRecovery,
425 (run_render_schedule.run_if(renderer_is_ready), send_time).chain(),
426 );
427render_app.add_systems(
428Render,
429 (
430 (PipelineCache::process_pipeline_queue_system, render_system)
431 .chain()
432 .in_set(RenderSystems::Render),
433reset_render_asset_bytes_per_frame.in_set(RenderSystems::Cleanup),
434 ),
435 );
436 }
437 }
438439fn ready(&self, app: &App) -> bool {
440// This is a little tricky. `FutureRenderResources` is added in `build`, which runs synchronously before `ready`.
441 // It is only added if there is a wgpu backend and thus the renderer can be created.
442 // Hence, if we try and get the resource and it is not present, that means we are ready, because we dont need it.
443 // On the other hand, if the resource is present, then we try and lock on it. The lock can fail, in which case
444 // we currently can assume that means the `FutureRenderResources` is in the act of being populated, because
445 // that is the only other place the lock may be held. If it is being populated, we can assume we're ready. This
446 // happens via the `and_then` falling through to the same `unwrap_or(true)` case as when there's no resource.
447 // If the lock succeeds, we can straightforwardly check if it is populated. If it is not, then we're not ready.
448app.world()
449 .get_resource::<FutureRenderResources>()
450 .and_then(|frr| frr.try_lock().map(|locked| locked.is_some()).ok())
451 .unwrap_or(true)
452 }
453454fn finish(&self, app: &mut App) {
455if let Some(future_render_resources) =
456app.world_mut().remove_resource::<FutureRenderResources>()
457 {
458let bevy_app::SubApps { main, sub_apps } = app.sub_apps_mut();
459let render = sub_apps.get_mut(&RenderApp.intern()).unwrap();
460let render_resources = future_render_resources.0.lock().unwrap().take().unwrap();
461462render_resources.unpack_into(
463main.world_mut(),
464render.world_mut(),
465self.synchronous_pipeline_compilation,
466 );
467 }
468 }
469}
470471fn renderer_is_ready(state: Res<RenderState>) -> bool {
472#[allow(non_exhaustive_omitted_patterns)] match *state {
RenderState::Ready => true,
_ => false,
}matches!(*state, RenderState::Ready)473}
474475fn run_render_schedule(world: &mut World) {
476world.resource_scope(|world, order: Mut<RenderScheduleOrder>| {
477for &label in &order.labels {
478let _ = world.try_run_schedule(label);
479 }
480 });
481}
482483fn send_time(time_sender: Res<TimeSender>) {
484// update the time and send it to the app world regardless of whether we render
485if let Err(error) = time_sender.0.try_send(Instant::now()) {
486match error {
487 bevy_time::TrySendError::Full(_) => {
488{
::core::panicking::panic_fmt(format_args!("The TimeSender channel should always be empty during render. You might need to add the bevy::core::time_system to your app."));
};panic!(
489"The TimeSender channel should always be empty during render. \
490 You might need to add the bevy::core::time_system to your app."
491);
492 }
493 bevy_time::TrySendError::Disconnected(_) => {
494// ignore disconnected errors, the main world probably just got dropped during shutdown
495}
496 }
497 }
498}
499500/// Inserts a [`FutureRenderResources`] created from this [`RenderCreation`].
501///
502/// Returns true if creation was successful, false otherwise.
503fn insert_future_resources(render_creation: &RenderCreation, main_world: &mut World) -> bool {
504let primary_window = main_world505 .query_filtered::<&RawHandleWrapperHolder, With<PrimaryWindow>>()
506 .single(main_world)
507 .ok()
508 .cloned();
509510#[cfg(feature = "raw_vulkan_init")]
511let raw_vulkan_init_settings = main_world512 .get_resource::<renderer::raw_vulkan_init::RawVulkanInitSettings>()
513 .cloned()
514 .unwrap_or_default();
515516let future_resources = FutureRenderResources::default();
517let success = render_creation.create_render(
518future_resources.clone(),
519primary_window,
520#[cfg(feature = "raw_vulkan_init")]
521raw_vulkan_init_settings,
522 );
523if success {
524// Note that `future_resources` is not necessarily populated here yet.
525main_world.insert_resource(future_resources);
526 }
527success528}
529530/// If the [`RenderAdapterInfo`] is a Qualcomm Adreno, returns its model number.
531///
532/// This lets us work around hardware bugs.
533pub fn get_adreno_model(adapter_info: &RenderAdapterInfo) -> Option<u32> {
534if !falsecfg!(target_os = "android") {
535return None;
536 }
537538let adreno_model = adapter_info.name.strip_prefix("Adreno (TM) ")?;
539540// Take suffixes into account (like Adreno 642L).
541Some(
542adreno_model543 .chars()
544 .map_while(|c| c.to_digit(10))
545 .fold(0, |acc, digit| acc * 10 + digit),
546 )
547}
548549/// Get the Mali driver version if the adapter is a Mali GPU.
550pub fn get_mali_driver_version(adapter_info: &RenderAdapterInfo) -> Option<u32> {
551if !falsecfg!(target_os = "android") {
552return None;
553 }
554555if !adapter_info.name.contains("Mali") {
556return None;
557 }
558let driver_info = &adapter_info.driver_info;
559if let Some(start_pos) = driver_info.find("v1.r")
560 && let Some(end_pos) = driver_info[start_pos..].find('p')
561 {
562let start_idx = start_pos + 4; // Skip "v1.r"
563let end_idx = start_pos + end_pos;
564565return driver_info[start_idx..end_idx].parse::<u32>().ok();
566 }
567568None569}
570571pub fn get_pixel10_driver_version(adapter_info: &RenderAdapterInfo) -> Option<u32> {
572if !falsecfg!(target_os = "android") {
573return None;
574 }
575576if adapter_info.name != "PowerVR D-Series DXT-48-1536 MC1" {
577return None;
578 }
579580let (_, driver_version) = adapter_info.driver_info.split_once('@')?;
581driver_version.parse::<u32>().ok()
582}
583584/// Returns true if storage buffers are unsupported on this platform or false
585/// if they are supported.
586pub fn storage_buffers_are_unsupported(limits: &WgpuLimits) -> bool {
587static STORAGE_BUFFERS_UNSUPPORTED: OnceLock<bool> = OnceLock::new();
588*STORAGE_BUFFERS_UNSUPPORTED.get_or_init(|| limits.max_storage_buffers_per_shader_stage == 0)
589}