Skip to content

Commit 936468a

Browse files
committed
bevy_render: Use RenderDevice to get limits/features and expose AdapterInfo (#3931)
# Objective - `WgpuOptions` is mutated to be updated with the actual device limits and features, but this information is readily available to both the main and render worlds through the `RenderDevice` which has .limits() and .features() methods - Information about the adapter in terms of its name, the backend in use, etc were not being exposed but have clear use cases for being used to take decisions about what rendering code to use. For example, if something works well on AMD GPUs but poorly on Intel GPUs. Or perhaps something works well in Vulkan but poorly in DX12. ## Solution - Stop mutating `WgpuOptions `and don't insert the updated values into the main and render worlds - Return `AdapterInfo` from `initialize_renderer` and insert it into the main and render worlds - Use `RenderDevice` limits in the lighting code that was using `WgpuOptions.limits`. - Renamed `WgpuOptions` to `WgpuSettings`
1 parent d3e526b commit 936468a

File tree

8 files changed

+71
-65
lines changed

8 files changed

+71
-65
lines changed

crates/bevy_internal/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ pub mod pbr {
113113
#[cfg(feature = "bevy_render")]
114114
pub mod render {
115115
//! Cameras, meshes, textures, shaders, and pipelines.
116+
//! Use [`RenderDevice::features`](bevy_render::renderer::RenderDevice::features),
117+
//! [`RenderDevice::limits`](bevy_render::renderer::RenderDevice::limits), and the
118+
//! [`WgpuAdapterInfo`](bevy_render::render_resource::WgpuAdapterInfo) resource to
119+
//! get runtime information about the actual adapter, backend, features, and limits.
116120
pub use bevy_render::*;
117121
}
118122

crates/bevy_pbr/src/render/light.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use bevy_render::{
1515
camera::{Camera, CameraProjection},
1616
color::Color,
1717
mesh::Mesh,
18-
options::WgpuOptions,
1918
render_asset::RenderAssets,
2019
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
2120
render_phase::{
@@ -607,7 +606,6 @@ pub fn prepare_lights(
607606
directional_light_shadow_map: Res<ExtractedDirectionalLightShadowMap>,
608607
point_lights: Query<(Entity, &ExtractedPointLight)>,
609608
directional_lights: Query<(Entity, &ExtractedDirectionalLight)>,
610-
wgpu_options: Res<WgpuOptions>,
611609
) {
612610
light_meta.view_gpu_lights.clear();
613611

@@ -697,9 +695,9 @@ pub fn prepare_lights(
697695
TextureDescriptor {
698696
size: Extent3d {
699697
width: (directional_light_shadow_map.size as u32)
700-
.min(wgpu_options.limits.max_texture_dimension_2d),
698+
.min(render_device.limits().max_texture_dimension_2d),
701699
height: (directional_light_shadow_map.size as u32)
702-
.min(wgpu_options.limits.max_texture_dimension_2d),
700+
.min(render_device.limits().max_texture_dimension_2d),
703701
depth_or_array_layers: DIRECTIONAL_SHADOW_LAYERS,
704702
},
705703
mip_level_count: 1,

crates/bevy_render/src/lib.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
pub mod camera;
22
pub mod color;
33
pub mod mesh;
4-
pub mod options;
54
pub mod primitives;
65
pub mod render_asset;
76
pub mod render_component;
87
pub mod render_graph;
98
pub mod render_phase;
109
pub mod render_resource;
1110
pub mod renderer;
11+
pub mod settings;
1212
pub mod texture;
1313
pub mod view;
1414

@@ -108,9 +108,9 @@ struct ScratchRenderWorld(World);
108108
impl Plugin for RenderPlugin {
109109
/// Initializes the renderer, sets up the [`RenderStage`](RenderStage) and creates the rendering sub-app.
110110
fn build(&self, app: &mut App) {
111-
let mut options = app
111+
let options = app
112112
.world
113-
.get_resource::<options::WgpuOptions>()
113+
.get_resource::<settings::WgpuSettings>()
114114
.cloned()
115115
.unwrap_or_default();
116116

@@ -134,16 +134,14 @@ impl Plugin for RenderPlugin {
134134
compatible_surface: surface.as_ref(),
135135
..Default::default()
136136
};
137-
let (device, queue) = futures_lite::future::block_on(renderer::initialize_renderer(
138-
&instance,
139-
&mut options,
140-
&request_adapter_options,
141-
));
142-
debug!("Configured wgpu adapter Limits: {:#?}", &options.limits);
143-
debug!("Configured wgpu adapter Features: {:#?}", &options.features);
137+
let (device, queue, adapter_info) = futures_lite::future::block_on(
138+
renderer::initialize_renderer(&instance, &options, &request_adapter_options),
139+
);
140+
debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
141+
debug!("Configured wgpu adapter Features: {:#?}", device.features());
144142
app.insert_resource(device.clone())
145143
.insert_resource(queue.clone())
146-
.insert_resource(options.clone())
144+
.insert_resource(adapter_info.clone())
147145
.init_resource::<ScratchRenderWorld>()
148146
.register_type::<Frustum>()
149147
.register_type::<CubemapFrusta>();
@@ -171,7 +169,7 @@ impl Plugin for RenderPlugin {
171169
.insert_resource(instance)
172170
.insert_resource(device)
173171
.insert_resource(queue)
174-
.insert_resource(options)
172+
.insert_resource(adapter_info)
175173
.insert_resource(render_pipeline_cache)
176174
.insert_resource(asset_server)
177175
.init_resource::<RenderGraph>();

crates/bevy_render/src/render_resource/mod.rs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,24 @@ pub use uniform_vec::*;
2222

2323
// TODO: decide where re-exports should go
2424
pub use wgpu::{
25-
util::BufferInitDescriptor, AddressMode, BindGroupDescriptor, BindGroupEntry,
26-
BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, BlendComponent,
27-
BlendFactor, BlendOperation, BlendState, BufferAddress, BufferBinding, BufferBindingType,
28-
BufferDescriptor, BufferSize, BufferUsages, ColorTargetState, ColorWrites, CommandEncoder,
29-
CommandEncoderDescriptor, CompareFunction, ComputePassDescriptor, ComputePipelineDescriptor,
30-
DepthBiasState, DepthStencilState, Extent3d, Face, Features as WgpuFeatures, FilterMode,
31-
FragmentState as RawFragmentState, FrontFace, ImageCopyBuffer, ImageCopyBufferBase,
32-
ImageCopyTexture, ImageCopyTextureBase, ImageDataLayout, ImageSubresourceRange, IndexFormat,
33-
Limits as WgpuLimits, LoadOp, MapMode, MultisampleState, Operations, Origin3d, PipelineLayout,
34-
PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology,
35-
RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor,
36-
RenderPipelineDescriptor as RawRenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor,
37-
ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, StencilFaceState,
38-
StencilOperation, StencilState, StorageTextureAccess, TextureAspect, TextureDescriptor,
39-
TextureDimension, TextureFormat, TextureSampleType, TextureUsages, TextureViewDescriptor,
40-
TextureViewDimension, VertexAttribute, VertexBufferLayout as RawVertexBufferLayout,
41-
VertexFormat, VertexState as RawVertexState, VertexStepMode,
25+
util::BufferInitDescriptor, AdapterInfo as WgpuAdapterInfo, AddressMode, BindGroupDescriptor,
26+
BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType,
27+
BlendComponent, BlendFactor, BlendOperation, BlendState, BufferAddress, BufferBinding,
28+
BufferBindingType, BufferDescriptor, BufferSize, BufferUsages, ColorTargetState, ColorWrites,
29+
CommandEncoder, CommandEncoderDescriptor, CompareFunction, ComputePassDescriptor,
30+
ComputePipelineDescriptor, DepthBiasState, DepthStencilState, Extent3d, Face,
31+
Features as WgpuFeatures, FilterMode, FragmentState as RawFragmentState, FrontFace,
32+
ImageCopyBuffer, ImageCopyBufferBase, ImageCopyTexture, ImageCopyTextureBase, ImageDataLayout,
33+
ImageSubresourceRange, IndexFormat, Limits as WgpuLimits, LoadOp, MapMode, MultisampleState,
34+
Operations, Origin3d, PipelineLayout, PipelineLayoutDescriptor, PolygonMode, PrimitiveState,
35+
PrimitiveTopology, RenderPassColorAttachment, RenderPassDepthStencilAttachment,
36+
RenderPassDescriptor, RenderPipelineDescriptor as RawRenderPipelineDescriptor,
37+
SamplerBindingType, SamplerDescriptor, ShaderModule, ShaderModuleDescriptor, ShaderSource,
38+
ShaderStages, StencilFaceState, StencilOperation, StencilState, StorageTextureAccess,
39+
TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType,
40+
TextureUsages, TextureViewDescriptor, TextureViewDimension, VertexAttribute,
41+
VertexBufferLayout as RawVertexBufferLayout, VertexFormat, VertexState as RawVertexState,
42+
VertexStepMode,
4243
};
4344

4445
pub use bevy_crevice::*;

crates/bevy_render/src/renderer/mod.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ pub use graph_runner::*;
66
pub use render_device::*;
77

88
use crate::{
9-
options::{WgpuOptions, WgpuOptionsPriority},
109
render_graph::RenderGraph,
10+
settings::{WgpuSettings, WgpuSettingsPriority},
1111
view::{ExtractedWindows, ViewTarget},
1212
};
1313
use bevy_ecs::prelude::*;
1414
use std::sync::Arc;
15-
use wgpu::{CommandEncoder, Instance, Queue, RequestAdapterOptions};
15+
use wgpu::{AdapterInfo, CommandEncoder, Instance, Queue, RequestAdapterOptions};
1616

1717
/// Updates the [`RenderGraph`] with all of its nodes and then runs it to render the entire frame.
1818
pub fn render_system(world: &mut World) {
@@ -65,9 +65,9 @@ pub type RenderInstance = Instance;
6565
/// for the specified backend.
6666
pub async fn initialize_renderer(
6767
instance: &Instance,
68-
options: &mut WgpuOptions,
68+
options: &WgpuSettings,
6969
request_adapter_options: &RequestAdapterOptions<'_>,
70-
) -> (RenderDevice, RenderQueue) {
70+
) -> (RenderDevice, RenderQueue, AdapterInfo) {
7171
let adapter = instance
7272
.request_adapter(request_adapter_options)
7373
.await
@@ -89,7 +89,7 @@ pub async fn initialize_renderer(
8989
// Maybe get features and limits based on what is supported by the adapter/backend
9090
let mut features = wgpu::Features::empty();
9191
let mut limits = options.limits.clone();
92-
if matches!(options.priority, WgpuOptionsPriority::Functionality) {
92+
if matches!(options.priority, WgpuSettingsPriority::Functionality) {
9393
features = adapter.features() | wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES;
9494
if adapter_info.device_type == wgpu::DeviceType::DiscreteGpu {
9595
// `MAPPABLE_PRIMARY_BUFFERS` can have a significant, negative performance impact for
@@ -106,7 +106,7 @@ pub async fn initialize_renderer(
106106
features -= disabled_features;
107107
}
108108
// NOTE: |= is used here to ensure that any explicitly-enabled features are respected.
109-
options.features |= features;
109+
features |= options.features;
110110

111111
// Enforce the limit constraints
112112
if let Some(constrained_limits) = options.constrained_limits.as_ref() {
@@ -115,7 +115,7 @@ pub async fn initialize_renderer(
115115
// specified max_limits. For 'min' limits, take the maximum instead. This is intended to
116116
// err on the side of being conservative. We can't claim 'higher' limits that are supported
117117
// but we can constrain to 'lower' limits.
118-
options.limits = wgpu::Limits {
118+
limits = wgpu::Limits {
119119
max_texture_dimension_1d: limits
120120
.max_texture_dimension_1d
121121
.min(constrained_limits.max_texture_dimension_1d),
@@ -198,24 +198,22 @@ pub async fn initialize_renderer(
198198
.max_compute_workgroups_per_dimension
199199
.min(constrained_limits.max_compute_workgroups_per_dimension),
200200
};
201-
} else {
202-
options.limits = limits;
203201
}
204202

205203
let (device, queue) = adapter
206204
.request_device(
207205
&wgpu::DeviceDescriptor {
208206
label: options.device_label.as_ref().map(|a| a.as_ref()),
209-
features: options.features,
210-
limits: options.limits.clone(),
207+
features,
208+
limits,
211209
},
212210
trace_path,
213211
)
214212
.await
215213
.unwrap();
216214
let device = Arc::new(device);
217215
let queue = Arc::new(queue);
218-
(RenderDevice::from(device), queue)
216+
(RenderDevice::from(device), queue, adapter_info)
219217
}
220218

221219
/// The context with all information required to interact with the GPU.

crates/bevy_render/src/options.rs renamed to crates/bevy_render/src/settings.rs

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,38 @@ use std::borrow::Cow;
22

33
pub use wgpu::{Backends, Features as WgpuFeatures, Limits as WgpuLimits, PowerPreference};
44

5+
/// Configures the priority used when automatically configuring the features/limits of `wgpu`.
56
#[derive(Clone)]
6-
pub enum WgpuOptionsPriority {
7+
pub enum WgpuSettingsPriority {
8+
/// WebGPU default features and limits
79
Compatibility,
10+
/// The maximum supported features and limits of the adapter and backend
811
Functionality,
12+
/// WebGPU default limits plus additional constraints in order to be compatible with WebGL2
913
WebGL2,
1014
}
1115

16+
/// Provides configuration for renderer initialization. Use [`RenderDevice::features`](crate::renderer::RenderDevice::features),
17+
/// [`RenderDevice::limits`](crate::renderer::RenderDevice::limits), and the [`WgpuAdapterInfo`](crate::render_resource::WgpuAdapterInfo)
18+
/// resource to get runtime information about the actual adapter, backend, features, and limits.
1219
#[derive(Clone)]
13-
pub struct WgpuOptions {
20+
pub struct WgpuSettings {
1421
pub device_label: Option<Cow<'static, str>>,
1522
pub backends: Option<Backends>,
1623
pub power_preference: PowerPreference,
17-
pub priority: WgpuOptionsPriority,
18-
/// The enabled features. Setting features will require them to be enabled when initializing
19-
/// the renderer.
24+
pub priority: WgpuSettingsPriority,
25+
/// The features to ensure are enabled regardless of what the adapter/backend supports.
26+
/// Setting these explicitly may cause renderer initialization to fail.
2027
pub features: WgpuFeatures,
2128
/// The features to ensure are disabled regardless of what the adapter/backend supports
2229
pub disabled_features: Option<WgpuFeatures>,
23-
/// The imposed limits. Updated based on adapter/backend limits when initializing the renderer
24-
/// if using WgpuOptionsPriority::Functionality
30+
/// The imposed limits.
2531
pub limits: WgpuLimits,
2632
/// The constraints on limits allowed regardless of what the adapter/backend supports
2733
pub constrained_limits: Option<WgpuLimits>,
2834
}
2935

30-
impl Default for WgpuOptions {
36+
impl Default for WgpuSettings {
3137
fn default() -> Self {
3238
let default_backends = if cfg!(feature = "webgl") {
3339
Backends::GL
@@ -37,9 +43,10 @@ impl Default for WgpuOptions {
3743

3844
let backends = Some(wgpu::util::backend_bits_from_env().unwrap_or(default_backends));
3945

40-
let priority = options_priority_from_env().unwrap_or(WgpuOptionsPriority::Functionality);
46+
let priority = settings_priority_from_env().unwrap_or(WgpuSettingsPriority::Functionality);
4147

42-
let limits = if cfg!(feature = "webgl") || matches!(priority, WgpuOptionsPriority::WebGL2) {
48+
let limits = if cfg!(feature = "webgl") || matches!(priority, WgpuSettingsPriority::WebGL2)
49+
{
4350
wgpu::Limits::downlevel_webgl2_defaults()
4451
} else {
4552
#[allow(unused_mut)]
@@ -65,17 +72,17 @@ impl Default for WgpuOptions {
6572
}
6673
}
6774

68-
/// Get a features/limits priority from the environment variable `WGPU_OPTIONS_PRIO`
69-
pub fn options_priority_from_env() -> Option<WgpuOptionsPriority> {
75+
/// Get a features/limits priority from the environment variable `WGPU_SETTINGS_PRIO`
76+
pub fn settings_priority_from_env() -> Option<WgpuSettingsPriority> {
7077
Some(
71-
match std::env::var("WGPU_OPTIONS_PRIO")
78+
match std::env::var("WGPU_SETTINGS_PRIO")
7279
.as_deref()
7380
.map(str::to_lowercase)
7481
.as_deref()
7582
{
76-
Ok("compatibility") => WgpuOptionsPriority::Compatibility,
77-
Ok("functionality") => WgpuOptionsPriority::Functionality,
78-
Ok("webgl2") => WgpuOptionsPriority::WebGL2,
83+
Ok("compatibility") => WgpuSettingsPriority::Compatibility,
84+
Ok("functionality") => WgpuSettingsPriority::Functionality,
85+
Ok("webgl2") => WgpuSettingsPriority::WebGL2,
7986
_ => return None,
8087
},
8188
)

examples/3d/wireframe.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use bevy::{
22
pbr::wireframe::{Wireframe, WireframeConfig, WireframePlugin},
33
prelude::*,
4-
render::{options::WgpuOptions, render_resource::WgpuFeatures},
4+
render::{render_resource::WgpuFeatures, settings::WgpuSettings},
55
};
66

77
fn main() {
88
App::new()
99
.insert_resource(Msaa { samples: 4 })
10-
.insert_resource(WgpuOptions {
10+
.insert_resource(WgpuSettings {
1111
features: WgpuFeatures::POLYGON_MODE_LINE,
1212
..Default::default()
1313
})

examples/app/headless_defaults.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use bevy::{prelude::*, render::options::WgpuOptions};
1+
use bevy::{prelude::*, render::settings::WgpuSettings};
22

33
fn main() {
44
App::new()
5-
.insert_resource(WgpuOptions {
5+
.insert_resource(WgpuSettings {
66
backends: None,
77
..Default::default()
88
})

0 commit comments

Comments
 (0)