mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-01 13:47:21 -06:00
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:
@@ -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