mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-01 13:47:21 -06:00
Fix #2105: the window asks the GPU for no more than it offers
eframe's default device descriptor asks for wgpu's default limits (WebGL2 defaults on OpenGL) with 8192 px textures, whatever the adapter offers. A GPU short of any one of them, such as a Raspberry Pi 5's V3D 7.1 (15 inter-stage shader variables on Vulkan, 4096 px textures on OpenGL), failed to create a device, and the window fell back to the software rasterizer. The device now asks for eframe's limits lowered to the adapter's wherever the adapter offers less, and for the adapter's own texture side, which still raises it above 8192 px when the adapter allows more (#1459).
This commit is contained in:
@@ -182,11 +182,14 @@ fn any_hardware(kinds: &[DeviceType]) -> bool {
|
||||
kinds.iter().any(|k| *k != DeviceType::Cpu)
|
||||
}
|
||||
|
||||
/// The largest texture side to ask the device for, which bounds the window's surface: the
|
||||
/// adapter's own limit when it is above eframe's `default` (8192 px), so a window larger than
|
||||
/// that keeps its surface (#1459). Never below `default`, which is what was asked for before.
|
||||
pub fn surface_limit(default: u32, adapter: u32) -> u32 {
|
||||
default.max(adapter)
|
||||
/// The limits to ask the device for: what eframe `asked` for, lowered to what the `adapter` offers
|
||||
/// wherever it offers less, so a GPU short of one of them still gets a device (#2105). The texture
|
||||
/// side, which bounds the window's surface, is the adapter's own, above eframe's 8192 px when the
|
||||
/// adapter allows more, so a window larger than that keeps its surface (#1459).
|
||||
pub fn device_limits(asked: wgpu::Limits, adapter: &wgpu::Limits) -> wgpu::Limits {
|
||||
let mut limits = asked.or_worse_values_from(adapter);
|
||||
limits.max_texture_dimension_2d = adapter.max_texture_dimension_2d;
|
||||
limits
|
||||
}
|
||||
|
||||
/// One adapter, as [`adapter_order`] sees it.
|
||||
|
||||
@@ -5,11 +5,34 @@ fn gpu(name: &str, backend: Backend, device_type: DeviceType) -> Candidate {
|
||||
}
|
||||
|
||||
/// #1459: a 9048 px wide window (two display scales' ratio past 8192) fits an adapter that
|
||||
/// takes 16384 px textures; an adapter with less than eframe asks for changes nothing.
|
||||
/// takes 16384 px textures.
|
||||
#[test]
|
||||
fn the_surface_may_be_as_large_as_the_adapter_allows() {
|
||||
assert_eq!(surface_limit(8192, 16384), 16384);
|
||||
assert_eq!(surface_limit(8192, 4096), 8192);
|
||||
let adapter = wgpu::Limits { max_texture_dimension_2d: 16384, ..wgpu::Limits::default() };
|
||||
let asked = wgpu::Limits { max_texture_dimension_2d: 8192, ..wgpu::Limits::default() };
|
||||
assert_eq!(device_limits(asked, &adapter).max_texture_dimension_2d, 16384);
|
||||
}
|
||||
|
||||
/// #2105: a GPU that offers less than eframe asks for on any limit (here a Raspberry Pi 5's V3D 7.1:
|
||||
/// 15 inter-stage variables on Vulkan, 4096 px textures on OpenGL) gets a device with what it
|
||||
/// offers, instead of failing and leaving the window to the software rasterizer. A GPU that offers
|
||||
/// more is asked for no more than before, except for the texture side.
|
||||
#[test]
|
||||
fn the_device_asks_for_no_more_than_the_adapter_offers() {
|
||||
let asked = wgpu::Limits { max_texture_dimension_2d: 8192, ..wgpu::Limits::default() };
|
||||
let vulkan = wgpu::Limits { max_inter_stage_shader_variables: 15, max_texture_dimension_2d: 7680, ..wgpu::Limits::default() };
|
||||
let limits = device_limits(asked.clone(), &vulkan);
|
||||
assert_eq!((limits.max_inter_stage_shader_variables, limits.max_texture_dimension_2d), (15, 7680));
|
||||
assert!(limits.check_limits(&vulkan), "{limits:?}");
|
||||
let gl = wgpu::Limits { max_texture_dimension_2d: 4096, ..wgpu::Limits::downlevel_webgl2_defaults() };
|
||||
let webgl2 = wgpu::Limits { max_texture_dimension_2d: 8192, ..wgpu::Limits::downlevel_webgl2_defaults() };
|
||||
let limits = device_limits(webgl2.clone(), &gl);
|
||||
assert_eq!(limits.max_texture_dimension_2d, 4096);
|
||||
assert!(limits.check_limits(&gl), "{limits:?}");
|
||||
let ample = wgpu::Limits { max_texture_dimension_2d: 8192, ..wgpu::Limits::default() };
|
||||
assert_eq!(device_limits(asked.clone(), &le), asked);
|
||||
let better = wgpu::Limits { max_inter_stage_shader_variables: 31, max_texture_dimension_2d: 8192, ..wgpu::Limits::default() };
|
||||
assert_eq!(device_limits(asked.clone(), &better), asked, "never more than eframe asked for");
|
||||
}
|
||||
|
||||
fn names(c: &[Candidate], order: &[usize]) -> Vec<String> {
|
||||
|
||||
@@ -346,14 +346,15 @@ fn main() -> std::process::ExitCode {
|
||||
// losing the device before the first frame (#1194). `WGPU_DX12_COMPILER` picks another.
|
||||
create.instance_descriptor.backend_options.dx12.shader_compiler =
|
||||
eframe::wgpu::Dx12Compiler::from_env().unwrap_or(eframe::wgpu::Dx12Compiler::Fxc);
|
||||
// The window's surface may be as large as the adapter allows, not eframe's fixed
|
||||
// 8192 px: a window stretched over several monitors, or grown by a display scale
|
||||
// change, otherwise fails to configure its surface and the app closes (#1459).
|
||||
// The device asks for no more than the adapter offers, so a GPU short of one of
|
||||
// eframe's limits still gets a device (#2105). The window's surface may be as large as
|
||||
// the adapter allows, not eframe's fixed 8192 px: a window stretched over several
|
||||
// monitors, or grown by a display scale change, otherwise fails to configure its
|
||||
// surface and the app closes (#1459).
|
||||
let device = create.device_descriptor.clone();
|
||||
create.device_descriptor = std::sync::Arc::new(move |adapter: &eframe::wgpu::Adapter| {
|
||||
let mut descriptor = device(adapter);
|
||||
let limit = &mut descriptor.required_limits.max_texture_dimension_2d;
|
||||
*limit = gpu::surface_limit(*limit, adapter.limits().max_texture_dimension_2d);
|
||||
descriptor.required_limits = gpu::device_limits(descriptor.required_limits, &adapter.limits());
|
||||
descriptor
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user