Merge pull request #4989 from dotCooCoo/fix/issue-2105

Fix #2105: the window asks the GPU for no more than it offers
This commit is contained in:
BFlat
2026-11-01 05:28:44 +07:00
committed by GitHub
3 changed files with 40 additions and 13 deletions
+8 -5
View File
@@ -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.
+26 -3
View File
@@ -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(), &ample), 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> {
+6 -5
View File
@@ -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
});
}