Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Configurable wgpu features/limits priority #3452

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions crates/bevy_pbr/src/render/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use bevy_render::{
camera::{Camera, CameraProjection},
color::Color,
mesh::Mesh,
options::WgpuOptions,
render_asset::RenderAssets,
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
render_phase::{
Expand Down Expand Up @@ -576,6 +577,7 @@ pub fn prepare_lights(
directional_light_shadow_map: Res<ExtractedDirectionalLightShadowMap>,
point_lights: Query<(Entity, &ExtractedPointLight)>,
directional_lights: Query<(Entity, &ExtractedDirectionalLight)>,
wgpu_options: Res<WgpuOptions>,
) {
light_meta.view_gpu_lights.clear();

Expand Down Expand Up @@ -664,8 +666,10 @@ pub fn prepare_lights(
&render_device,
TextureDescriptor {
size: Extent3d {
width: directional_light_shadow_map.size as u32,
height: directional_light_shadow_map.size as u32,
width: (directional_light_shadow_map.size as u32)
.min(wgpu_options.limits.max_texture_dimension_2d),
height: (directional_light_shadow_map.size as u32)
.min(wgpu_options.limits.max_texture_dimension_2d),
depth_or_array_layers: DIRECTIONAL_SHADOW_LAYERS,
},
mip_level_count: 1,
Expand Down
24 changes: 13 additions & 11 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub mod prelude {
};
}

use bevy_utils::tracing::debug;
pub use once_cell;

use crate::{
Expand Down Expand Up @@ -107,7 +108,7 @@ 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 options = app
let mut options = app
.world
.get_resource::<options::WgpuOptions>()
.cloned()
Expand All @@ -122,21 +123,21 @@ impl Plugin for RenderPlugin {
});
raw_handle
};
let request_adapter_options = wgpu::RequestAdapterOptions {
power_preference: options.power_preference,
compatible_surface: surface.as_ref(),
..Default::default()
};
let (device, queue) = futures_lite::future::block_on(renderer::initialize_renderer(
&instance,
&wgpu::RequestAdapterOptions {
power_preference: options.power_preference,
compatible_surface: surface.as_ref(),
..Default::default()
},
&wgpu::DeviceDescriptor {
label: options.device_label.as_ref().map(|a| a.as_ref()),
features: options.features,
limits: options.limits,
},
&mut options,
&request_adapter_options,
));
debug!("Configured wgpu adapter Limits: {:#?}", &options.limits);
debug!("Configured wgpu adapter Features: {:#?}", &options.features);
app.insert_resource(device.clone())
.insert_resource(queue.clone())
.insert_resource(options.clone())
.add_asset::<Shader>()
.init_asset_loader::<ShaderLoader>()
.init_resource::<ScratchRenderWorld>()
Expand Down Expand Up @@ -167,6 +168,7 @@ impl Plugin for RenderPlugin {
.insert_resource(instance)
.insert_resource(device)
.insert_resource(queue)
.insert_resource(options)
.insert_resource(render_pipeline_cache)
.insert_resource(asset_server)
.init_resource::<RenderGraph>();
Expand Down
29 changes: 28 additions & 1 deletion crates/bevy_render/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@ use std::borrow::Cow;

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

#[derive(Clone)]
pub enum WgpuOptionsPriority {
Compatibility,
Functionality,
WebGL2,
}

#[derive(Clone)]
pub struct WgpuOptions {
pub device_label: Option<Cow<'static, str>>,
pub backends: Backends,
pub power_preference: PowerPreference,
pub priority: WgpuOptionsPriority,
pub features: WgpuFeatures,
pub limits: WgpuLimits,
}
Expand All @@ -21,7 +29,9 @@ impl Default for WgpuOptions {

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

let limits = if cfg!(feature = "webgl") {
let priority = options_priority_from_env().unwrap_or(WgpuOptionsPriority::Functionality);

let limits = if cfg!(feature = "webgl") || matches!(priority, WgpuOptionsPriority::WebGL2) {
wgpu::Limits::downlevel_webgl2_defaults()
} else {
#[allow(unused_mut)]
Expand All @@ -38,8 +48,25 @@ impl Default for WgpuOptions {
device_label: Default::default(),
backends,
power_preference: PowerPreference::HighPerformance,
priority,
features: wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
limits,
}
}
}

/// Get a features/limits priority from the environment variable WGPU_OPTIONS_PRIO
pub fn options_priority_from_env() -> Option<WgpuOptionsPriority> {
Some(
match std::env::var("WGPU_OPTIONS_PRIO")
.as_deref()
.map(str::to_lowercase)
.as_deref()
{
Ok("compatibility") => WgpuOptionsPriority::Compatibility,
Ok("functionality") => WgpuOptionsPriority::Functionality,
Ok("webgl2") => WgpuOptionsPriority::WebGL2,
_ => return None,
},
)
}
55 changes: 33 additions & 22 deletions crates/bevy_render/src/render_phase/draw_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
ShaderStages,
},
};
use bevy_utils::tracing::debug;
use bevy_utils::tracing::trace;
use std::ops::Range;
use wgpu::{IndexFormat, RenderPass};

Expand Down Expand Up @@ -108,7 +108,7 @@ impl<'a> TrackedRenderPass<'a> {
///
/// Subsequent draw calls will exhibit the behavior defined by the `pipeline`.
pub fn set_render_pipeline(&mut self, pipeline: &'a RenderPipeline) {
debug!("set pipeline: {:?}", pipeline);
trace!("set pipeline: {:?}", pipeline);
if self.state.is_pipeline_set(pipeline.id()) {
return;
}
Expand All @@ -128,15 +128,19 @@ impl<'a> TrackedRenderPass<'a> {
.state
.is_bind_group_set(index as usize, bind_group.id(), dynamic_uniform_indices)
{
debug!(
trace!(
"set bind_group {} (already set): {:?} ({:?})",
index, bind_group, dynamic_uniform_indices
index,
bind_group,
dynamic_uniform_indices
);
return;
} else {
debug!(
trace!(
"set bind_group {}: {:?} ({:?})",
index, bind_group, dynamic_uniform_indices
index,
bind_group,
dynamic_uniform_indices
);
}
self.pass
Expand All @@ -158,15 +162,15 @@ impl<'a> TrackedRenderPass<'a> {
.state
.is_vertex_buffer_set(slot_index, buffer_slice.id(), offset)
{
debug!(
trace!(
"set vertex buffer {} (already set): {:?} ({})",
slot_index,
buffer_slice.id(),
offset
);
return;
} else {
debug!(
trace!(
"set vertex buffer {}: {:?} ({})",
slot_index,
buffer_slice.id(),
Expand All @@ -193,14 +197,14 @@ impl<'a> TrackedRenderPass<'a> {
.state
.is_index_buffer_set(buffer_slice.id(), offset, index_format)
{
debug!(
trace!(
"set index buffer (already set): {:?} ({})",
buffer_slice.id(),
offset
);
return;
} else {
debug!("set index buffer: {:?} ({})", buffer_slice.id(), offset);
trace!("set index buffer: {:?} ({})", buffer_slice.id(), offset);
}
self.pass.set_index_buffer(*buffer_slice, index_format);
self.state
Expand All @@ -211,7 +215,7 @@ impl<'a> TrackedRenderPass<'a> {
///
/// The active vertex buffer(s) can be set with [`TrackedRenderPass::set_vertex_buffer`].
pub fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
debug!("draw: {:?} {:?}", vertices, instances);
trace!("draw: {:?} {:?}", vertices, instances);
self.pass.draw(vertices, instances);
}

Expand All @@ -220,15 +224,17 @@ impl<'a> TrackedRenderPass<'a> {
/// The active index buffer can be set with [`TrackedRenderPass::set_index_buffer`], while the
/// active vertex buffer(s) can be set with [`TrackedRenderPass::set_vertex_buffer`].
pub fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
debug!(
trace!(
"draw indexed: {:?} {} {:?}",
indices, base_vertex, instances
indices,
base_vertex,
instances
);
self.pass.draw_indexed(indices, base_vertex, instances);
}

pub fn set_stencil_reference(&mut self, reference: u32) {
debug!("set stencil reference: {}", reference);
trace!("set stencil reference: {}", reference);

self.pass.set_stencil_reference(reference);
}
Expand All @@ -237,15 +243,15 @@ impl<'a> TrackedRenderPass<'a> {
///
/// Subsequent draw calls will discard any fragments that fall outside this region.
pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
debug!("set_scissor_rect: {} {} {} {}", x, y, width, height);
trace!("set_scissor_rect: {} {} {} {}", x, y, width, height);
self.pass.set_scissor_rect(x, y, width, height);
}

/// Set push constant data.
///
/// Features::PUSH_CONSTANTS must be enabled on the device in order to call these functions.
pub fn set_push_constants(&mut self, stages: ShaderStages, offset: u32, data: &[u8]) {
debug!(
trace!(
"set push constants: {:?} offset: {} data.len: {}",
stages,
offset,
Expand All @@ -266,9 +272,14 @@ impl<'a> TrackedRenderPass<'a> {
min_depth: f32,
max_depth: f32,
) {
debug!(
trace!(
"set viewport: {} {} {} {} {} {}",
x, y, width, height, min_depth, max_depth
x,
y,
width,
height,
min_depth,
max_depth
);
self.pass
.set_viewport(x, y, width, height, min_depth, max_depth)
Expand All @@ -278,7 +289,7 @@ impl<'a> TrackedRenderPass<'a> {
///
/// This is a GPU debugging feature. This has no effect on the rendering itself.
pub fn insert_debug_marker(&mut self, label: &str) {
debug!("insert debug marker: {}", label);
trace!("insert debug marker: {}", label);
self.pass.insert_debug_marker(label)
}

Expand All @@ -303,7 +314,7 @@ impl<'a> TrackedRenderPass<'a> {
/// [`push_debug_group`]: TrackedRenderPass::push_debug_group
/// [`pop_debug_group`]: TrackedRenderPass::pop_debug_group
pub fn push_debug_group(&mut self, label: &str) {
debug!("push_debug_group marker: {}", label);
trace!("push_debug_group marker: {}", label);
self.pass.push_debug_group(label)
}

Expand All @@ -320,12 +331,12 @@ impl<'a> TrackedRenderPass<'a> {
/// [`push_debug_group`]: TrackedRenderPass::push_debug_group
/// [`pop_debug_group`]: TrackedRenderPass::pop_debug_group
pub fn pop_debug_group(&mut self) {
debug!("pop_debug_group");
trace!("pop_debug_group");
self.pass.pop_debug_group()
}

pub fn set_blend_constant(&mut self, color: Color) {
debug!("set blend constant: {:?}", color);
trace!("set blend constant: {:?}", color);
self.pass.set_blend_constant(wgpu::Color::from(color))
}
}
20 changes: 17 additions & 3 deletions crates/bevy_render/src/renderer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ pub use graph_runner::*;
pub use render_device::*;

use crate::{
options::{WgpuOptions, WgpuOptionsPriority},
render_graph::RenderGraph,
view::{ExtractedWindows, ViewTarget},
};
use bevy_ecs::prelude::*;
use std::sync::Arc;
use wgpu::{CommandEncoder, DeviceDescriptor, Instance, Queue, RequestAdapterOptions};
use wgpu::{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) {
Expand Down Expand Up @@ -64,8 +65,8 @@ pub type RenderInstance = Instance;
/// for the specified backend.
pub async fn initialize_renderer(
instance: &Instance,
options: &mut WgpuOptions,
request_adapter_options: &RequestAdapterOptions<'_>,
device_descriptor: &DeviceDescriptor<'_>,
) -> (RenderDevice, RenderQueue) {
let adapter = instance
.request_adapter(request_adapter_options)
Expand All @@ -84,8 +85,21 @@ pub async fn initialize_renderer(
#[cfg(not(feature = "wgpu_trace"))]
let trace_path = None;

if matches!(options.priority, WgpuOptionsPriority::Functionality) {
options.features =
adapter.features() | wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES;
options.limits = adapter.limits();
}

let (device, queue) = adapter
.request_device(device_descriptor, trace_path)
.request_device(
&wgpu::DeviceDescriptor {
label: options.device_label.as_ref().map(|a| a.as_ref()),
features: options.features,
limits: options.limits.clone(),
},
trace_path,
)
.await
.unwrap();
let device = Arc::new(device);
Expand Down