App: the window's GPU device asks for what the adapter has (#198)

eframe's default device request asks for wgpu's default limits (8
storage buffers per stage and more). An older GPU such as Intel HD
Graphics 5500 can't meet them, so the device request failed before
EffectCraft ran, and the release build on Windows quit without a word.

The device now asks for the adapter's own limits (textures capped at
16384 px like the headless renderer). The compositor already checks
what it needs and composites on the CPU when the device can't run it.
If the window still can't open, a message dialog says why instead of
the app vanishing.

Test: device_limits_fit_the_adapter. Not checked on that GPU.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018gnTnH3Jmk5zr4tMq1Mc9f
This commit is contained in:
Claude committed 2026-10-07 22:13:19 +00:00
1 parent 24aed7f219
commit 188cc06d2b
1 file changed
+59 -2
+59 -2
View File
@@ -89,9 +89,10 @@ fn main() -> eframe::Result {
// Wayland matches the window to `ai.storyteller.effectcraft.desktop` by this ID.
.with_app_id(appimage::APP_ID),
event_loop_builder: agent_event_loop(control_port.is_some()),
wgpu_options: wgpu_options(),
..Default::default()
};
eframe::run_native(
let result = eframe::run_native(
"EffectCraft",
options,
Box::new(move |cc| {
@@ -188,7 +189,50 @@ fn main() -> eframe::Result {
app,
}))
}),
)
);
if let Err(e) = &result {
startup_failed(e);
}
result
}
/// The window's wgpu device asks for the adapter's own limits (textures up to 16384 px)
/// instead of eframe's fixed set: an older GPU that can't meet those (Intel HD Graphics 5500,
/// #198) still opens the app, and the compositor then checks what it needs and falls back to
/// the CPU when the device can't run it.
fn wgpu_options() -> eframe::WgpuConfiguration {
use eframe::egui_wgpu::WgpuSetup;
let mut config = eframe::WgpuConfiguration::default();
if let WgpuSetup::CreateNew(setup) = &mut config.wgpu_setup {
setup.device_descriptor = std::sync::Arc::new(|adapter| eframe::wgpu::DeviceDescriptor {
label: Some("EffectCraft device"),
required_limits: device_limits(adapter.limits()),
..Default::default()
});
}
config
}
/// The limits to request from an adapter that offers `adapter`: all of them, with textures
/// capped at 16384 px like the headless renderer's device.
fn device_limits(adapter: eframe::wgpu::Limits) -> eframe::wgpu::Limits {
eframe::wgpu::Limits { max_texture_dimension_2d: adapter.max_texture_dimension_2d.min(16384), ..adapter }
}
/// The window couldn't open (no usable graphics adapter or device): say so instead of quitting
/// silently, since release builds on Windows have no console.
fn startup_failed(e: &eframe::Error) {
let message = format!(
"EffectCraft couldn't start its window: {e}\n\nUpdating the graphics driver often helps. If it keeps happening, please report it at https://github.com/storytold/effectcraft/issues with this message."
);
log::error!("{message}");
eprintln!("effectcraft: {message}");
let _ = rfd::MessageDialog::new()
.set_level(rfd::MessageLevel::Error)
.set_title("EffectCraft")
.set_description(message)
.set_buttons(rfd::MessageButtons::Ok)
.show();
}
/// The desktop app: the egui app plus, on macOS, the system menu bar.
@@ -254,6 +298,19 @@ mod tests {
parse_args(args.iter().map(|a| a.to_string()), None)
}
/// The window's device never asks for more than the adapter offers (#198).
#[test]
fn device_limits_fit_the_adapter() {
use eframe::wgpu::Limits;
for adapter in [Limits::downlevel_defaults(), Limits::downlevel_webgl2_defaults(), Limits::default()] {
let l = super::device_limits(adapter.clone());
assert!(l.check_limits(&adapter), "{l:?}");
assert_eq!(l.max_storage_buffers_per_shader_stage, adapter.max_storage_buffers_per_shader_stage);
}
let big = Limits { max_texture_dimension_2d: 32768, ..Limits::default() };
assert_eq!(super::device_limits(big).max_texture_dimension_2d, 16384);
}
/// Launching without a project opens an empty project, not the demo (#204).
#[test]
fn no_arguments_start_an_empty_project() {