diff --git a/crates/bevy_internal/src/lib.rs b/crates/bevy_internal/src/lib.rs index 7435fde7b0b4a..3df3d0c2c9ec7 100644 --- a/crates/bevy_internal/src/lib.rs +++ b/crates/bevy_internal/src/lib.rs @@ -113,6 +113,10 @@ pub mod pbr { #[cfg(feature = "bevy_render")] pub mod render { //! Cameras, meshes, textures, shaders, and pipelines. + //! Use [`RenderDevice::features`](bevy_render::renderer::RenderDevice::features), + //! [`RenderDevice::limits`](bevy_render::renderer::RenderDevice::limits), and the + //! [`WgpuAdapterInfo`](bevy_render::render_resource::WgpuAdapterInfo) resource to + //! get runtime information about the actual adapter, backend, features, and limits. pub use bevy_render::*; } diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index d939be0b593b1..d662480b2f848 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -15,7 +15,6 @@ use bevy_render::{ camera::{Camera, CameraProjection}, color::Color, mesh::Mesh, - options::WgpuOptions, render_asset::RenderAssets, render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, render_phase::{ @@ -607,7 +606,6 @@ pub fn prepare_lights( directional_light_shadow_map: Res, point_lights: Query<(Entity, &ExtractedPointLight)>, directional_lights: Query<(Entity, &ExtractedDirectionalLight)>, - wgpu_options: Res, ) { light_meta.view_gpu_lights.clear(); @@ -697,9 +695,9 @@ pub fn prepare_lights( TextureDescriptor { size: Extent3d { width: (directional_light_shadow_map.size as u32) - .min(wgpu_options.limits.max_texture_dimension_2d), + .min(render_device.limits().max_texture_dimension_2d), height: (directional_light_shadow_map.size as u32) - .min(wgpu_options.limits.max_texture_dimension_2d), + .min(render_device.limits().max_texture_dimension_2d), depth_or_array_layers: DIRECTIONAL_SHADOW_LAYERS, }, mip_level_count: 1, diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 788dd9365b48f..d44cb38ee8b8e 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -1,7 +1,6 @@ pub mod camera; pub mod color; pub mod mesh; -pub mod options; pub mod primitives; pub mod render_asset; pub mod render_component; @@ -9,6 +8,7 @@ pub mod render_graph; pub mod render_phase; pub mod render_resource; pub mod renderer; +pub mod settings; pub mod texture; pub mod view; @@ -108,9 +108,9 @@ struct ScratchRenderWorld(World); impl Plugin for RenderPlugin { /// Initializes the renderer, sets up the [`RenderStage`](RenderStage) and creates the rendering sub-app. fn build(&self, app: &mut App) { - let mut options = app + let options = app .world - .get_resource::() + .get_resource::() .cloned() .unwrap_or_default(); @@ -134,16 +134,14 @@ impl Plugin for RenderPlugin { 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); + let (device, queue, adapter_info) = futures_lite::future::block_on( + renderer::initialize_renderer(&instance, &options, &request_adapter_options), + ); + debug!("Configured wgpu adapter Limits: {:#?}", device.limits()); + debug!("Configured wgpu adapter Features: {:#?}", device.features()); app.insert_resource(device.clone()) .insert_resource(queue.clone()) - .insert_resource(options.clone()) + .insert_resource(adapter_info.clone()) .init_resource::() .register_type::() .register_type::(); @@ -171,7 +169,7 @@ impl Plugin for RenderPlugin { .insert_resource(instance) .insert_resource(device) .insert_resource(queue) - .insert_resource(options) + .insert_resource(adapter_info) .insert_resource(render_pipeline_cache) .insert_resource(asset_server) .init_resource::(); diff --git a/crates/bevy_render/src/render_resource/mod.rs b/crates/bevy_render/src/render_resource/mod.rs index f86934d1ca06f..8089199f790da 100644 --- a/crates/bevy_render/src/render_resource/mod.rs +++ b/crates/bevy_render/src/render_resource/mod.rs @@ -22,23 +22,24 @@ pub use uniform_vec::*; // TODO: decide where re-exports should go pub use wgpu::{ - util::BufferInitDescriptor, AddressMode, BindGroupDescriptor, BindGroupEntry, - BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, BlendComponent, - BlendFactor, BlendOperation, BlendState, BufferAddress, BufferBinding, BufferBindingType, - BufferDescriptor, BufferSize, BufferUsages, ColorTargetState, ColorWrites, CommandEncoder, - CommandEncoderDescriptor, CompareFunction, ComputePassDescriptor, ComputePipelineDescriptor, - DepthBiasState, DepthStencilState, Extent3d, Face, Features as WgpuFeatures, FilterMode, - FragmentState as RawFragmentState, FrontFace, ImageCopyBuffer, ImageCopyBufferBase, - ImageCopyTexture, ImageCopyTextureBase, ImageDataLayout, ImageSubresourceRange, IndexFormat, - Limits as WgpuLimits, LoadOp, MapMode, MultisampleState, Operations, Origin3d, PipelineLayout, - PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, - RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor, - RenderPipelineDescriptor as RawRenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, - ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, StencilFaceState, - StencilOperation, StencilState, StorageTextureAccess, TextureAspect, TextureDescriptor, - TextureDimension, TextureFormat, TextureSampleType, TextureUsages, TextureViewDescriptor, - TextureViewDimension, VertexAttribute, VertexBufferLayout as RawVertexBufferLayout, - VertexFormat, VertexState as RawVertexState, VertexStepMode, + util::BufferInitDescriptor, AdapterInfo as WgpuAdapterInfo, AddressMode, BindGroupDescriptor, + BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, + BlendComponent, BlendFactor, BlendOperation, BlendState, BufferAddress, BufferBinding, + BufferBindingType, BufferDescriptor, BufferSize, BufferUsages, ColorTargetState, ColorWrites, + CommandEncoder, CommandEncoderDescriptor, CompareFunction, ComputePassDescriptor, + ComputePipelineDescriptor, DepthBiasState, DepthStencilState, Extent3d, Face, + Features as WgpuFeatures, FilterMode, FragmentState as RawFragmentState, FrontFace, + ImageCopyBuffer, ImageCopyBufferBase, ImageCopyTexture, ImageCopyTextureBase, ImageDataLayout, + ImageSubresourceRange, IndexFormat, Limits as WgpuLimits, LoadOp, MapMode, MultisampleState, + Operations, Origin3d, PipelineLayout, PipelineLayoutDescriptor, PolygonMode, PrimitiveState, + PrimitiveTopology, RenderPassColorAttachment, RenderPassDepthStencilAttachment, + RenderPassDescriptor, RenderPipelineDescriptor as RawRenderPipelineDescriptor, + SamplerBindingType, SamplerDescriptor, ShaderModule, ShaderModuleDescriptor, ShaderSource, + ShaderStages, StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, + TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType, + TextureUsages, TextureViewDescriptor, TextureViewDimension, VertexAttribute, + VertexBufferLayout as RawVertexBufferLayout, VertexFormat, VertexState as RawVertexState, + VertexStepMode, }; pub use bevy_crevice::*; diff --git a/crates/bevy_render/src/renderer/mod.rs b/crates/bevy_render/src/renderer/mod.rs index 77cbd4e067288..430ae82376227 100644 --- a/crates/bevy_render/src/renderer/mod.rs +++ b/crates/bevy_render/src/renderer/mod.rs @@ -6,13 +6,13 @@ pub use graph_runner::*; pub use render_device::*; use crate::{ - options::{WgpuOptions, WgpuOptionsPriority}, render_graph::RenderGraph, + settings::{WgpuSettings, WgpuSettingsPriority}, view::{ExtractedWindows, ViewTarget}, }; use bevy_ecs::prelude::*; use std::sync::Arc; -use wgpu::{CommandEncoder, Instance, Queue, RequestAdapterOptions}; +use wgpu::{AdapterInfo, CommandEncoder, Instance, Queue, RequestAdapterOptions}; /// Updates the [`RenderGraph`] with all of its nodes and then runs it to render the entire frame. pub fn render_system(world: &mut World) { @@ -65,9 +65,9 @@ pub type RenderInstance = Instance; /// for the specified backend. pub async fn initialize_renderer( instance: &Instance, - options: &mut WgpuOptions, + options: &WgpuSettings, request_adapter_options: &RequestAdapterOptions<'_>, -) -> (RenderDevice, RenderQueue) { +) -> (RenderDevice, RenderQueue, AdapterInfo) { let adapter = instance .request_adapter(request_adapter_options) .await @@ -89,7 +89,7 @@ pub async fn initialize_renderer( // Maybe get features and limits based on what is supported by the adapter/backend let mut features = wgpu::Features::empty(); let mut limits = options.limits.clone(); - if matches!(options.priority, WgpuOptionsPriority::Functionality) { + if matches!(options.priority, WgpuSettingsPriority::Functionality) { features = adapter.features() | wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES; if adapter_info.device_type == wgpu::DeviceType::DiscreteGpu { // `MAPPABLE_PRIMARY_BUFFERS` can have a significant, negative performance impact for @@ -106,7 +106,7 @@ pub async fn initialize_renderer( features -= disabled_features; } // NOTE: |= is used here to ensure that any explicitly-enabled features are respected. - options.features |= features; + features |= options.features; // Enforce the limit constraints if let Some(constrained_limits) = options.constrained_limits.as_ref() { @@ -115,7 +115,7 @@ pub async fn initialize_renderer( // specified max_limits. For 'min' limits, take the maximum instead. This is intended to // err on the side of being conservative. We can't claim 'higher' limits that are supported // but we can constrain to 'lower' limits. - options.limits = wgpu::Limits { + limits = wgpu::Limits { max_texture_dimension_1d: limits .max_texture_dimension_1d .min(constrained_limits.max_texture_dimension_1d), @@ -198,16 +198,14 @@ pub async fn initialize_renderer( .max_compute_workgroups_per_dimension .min(constrained_limits.max_compute_workgroups_per_dimension), }; - } else { - options.limits = limits; } let (device, queue) = adapter .request_device( &wgpu::DeviceDescriptor { label: options.device_label.as_ref().map(|a| a.as_ref()), - features: options.features, - limits: options.limits.clone(), + features, + limits, }, trace_path, ) @@ -215,7 +213,7 @@ pub async fn initialize_renderer( .unwrap(); let device = Arc::new(device); let queue = Arc::new(queue); - (RenderDevice::from(device), queue) + (RenderDevice::from(device), queue, adapter_info) } /// The context with all information required to interact with the GPU. diff --git a/crates/bevy_render/src/options.rs b/crates/bevy_render/src/settings.rs similarity index 56% rename from crates/bevy_render/src/options.rs rename to crates/bevy_render/src/settings.rs index c071ed99c58af..229ce1a89defc 100644 --- a/crates/bevy_render/src/options.rs +++ b/crates/bevy_render/src/settings.rs @@ -2,32 +2,38 @@ use std::borrow::Cow; pub use wgpu::{Backends, Features as WgpuFeatures, Limits as WgpuLimits, PowerPreference}; +/// Configures the priority used when automatically configuring the features/limits of `wgpu`. #[derive(Clone)] -pub enum WgpuOptionsPriority { +pub enum WgpuSettingsPriority { + /// WebGPU default features and limits Compatibility, + /// The maximum supported features and limits of the adapter and backend Functionality, + /// WebGPU default limits plus additional constraints in order to be compatible with WebGL2 WebGL2, } +/// Provides configuration for renderer initialization. Use [`RenderDevice::features`](crate::renderer::RenderDevice::features), +/// [`RenderDevice::limits`](crate::renderer::RenderDevice::limits), and the [`WgpuAdapterInfo`](crate::render_resource::WgpuAdapterInfo) +/// resource to get runtime information about the actual adapter, backend, features, and limits. #[derive(Clone)] -pub struct WgpuOptions { +pub struct WgpuSettings { pub device_label: Option>, pub backends: Option, pub power_preference: PowerPreference, - pub priority: WgpuOptionsPriority, - /// The enabled features. Setting features will require them to be enabled when initializing - /// the renderer. + pub priority: WgpuSettingsPriority, + /// The features to ensure are enabled regardless of what the adapter/backend supports. + /// Setting these explicitly may cause renderer initialization to fail. pub features: WgpuFeatures, /// The features to ensure are disabled regardless of what the adapter/backend supports pub disabled_features: Option, - /// The imposed limits. Updated based on adapter/backend limits when initializing the renderer - /// if using WgpuOptionsPriority::Functionality + /// The imposed limits. pub limits: WgpuLimits, /// The constraints on limits allowed regardless of what the adapter/backend supports pub constrained_limits: Option, } -impl Default for WgpuOptions { +impl Default for WgpuSettings { fn default() -> Self { let default_backends = if cfg!(feature = "webgl") { Backends::GL @@ -37,9 +43,10 @@ impl Default for WgpuOptions { let backends = Some(wgpu::util::backend_bits_from_env().unwrap_or(default_backends)); - let priority = options_priority_from_env().unwrap_or(WgpuOptionsPriority::Functionality); + let priority = settings_priority_from_env().unwrap_or(WgpuSettingsPriority::Functionality); - let limits = if cfg!(feature = "webgl") || matches!(priority, WgpuOptionsPriority::WebGL2) { + let limits = if cfg!(feature = "webgl") || matches!(priority, WgpuSettingsPriority::WebGL2) + { wgpu::Limits::downlevel_webgl2_defaults() } else { #[allow(unused_mut)] @@ -65,17 +72,17 @@ impl Default for WgpuOptions { } } -/// Get a features/limits priority from the environment variable `WGPU_OPTIONS_PRIO` -pub fn options_priority_from_env() -> Option { +/// Get a features/limits priority from the environment variable `WGPU_SETTINGS_PRIO` +pub fn settings_priority_from_env() -> Option { Some( - match std::env::var("WGPU_OPTIONS_PRIO") + match std::env::var("WGPU_SETTINGS_PRIO") .as_deref() .map(str::to_lowercase) .as_deref() { - Ok("compatibility") => WgpuOptionsPriority::Compatibility, - Ok("functionality") => WgpuOptionsPriority::Functionality, - Ok("webgl2") => WgpuOptionsPriority::WebGL2, + Ok("compatibility") => WgpuSettingsPriority::Compatibility, + Ok("functionality") => WgpuSettingsPriority::Functionality, + Ok("webgl2") => WgpuSettingsPriority::WebGL2, _ => return None, }, ) diff --git a/examples/3d/wireframe.rs b/examples/3d/wireframe.rs index 953b12532cc89..dabd018d33063 100644 --- a/examples/3d/wireframe.rs +++ b/examples/3d/wireframe.rs @@ -1,13 +1,13 @@ use bevy::{ pbr::wireframe::{Wireframe, WireframeConfig, WireframePlugin}, prelude::*, - render::{options::WgpuOptions, render_resource::WgpuFeatures}, + render::{render_resource::WgpuFeatures, settings::WgpuSettings}, }; fn main() { App::new() .insert_resource(Msaa { samples: 4 }) - .insert_resource(WgpuOptions { + .insert_resource(WgpuSettings { features: WgpuFeatures::POLYGON_MODE_LINE, ..Default::default() }) diff --git a/examples/app/headless_defaults.rs b/examples/app/headless_defaults.rs index e3836be9f54e4..6e8cf0965a58d 100644 --- a/examples/app/headless_defaults.rs +++ b/examples/app/headless_defaults.rs @@ -1,8 +1,8 @@ -use bevy::{prelude::*, render::options::WgpuOptions}; +use bevy::{prelude::*, render::settings::WgpuSettings}; fn main() { App::new() - .insert_resource(WgpuOptions { + .insert_resource(WgpuSettings { backends: None, ..Default::default() })