Skip to content

Commit efba98a

Browse files
authored
Improve error message when using an under-powered GPU (#6252)
### What Using `scripts/fetch_crashes.py` to look at our analytics, I noticed that missing wgpu capabilities would lead to a assert/panic, which is not a nice way to report errors to users. I added an egui issue to improve this further in the future: * emilk/egui#4474 ### Checklist * [x] I have read and agree to [Contributor Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and the [Code of Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md) * [x] I've included a screenshot or gif (if applicable) * [x] I have tested the web demo (if applicable): * Using examples from latest `main` build: [rerun.io/viewer](https://rerun.io/viewer/pr/6252?manifest_url=https://app.rerun.io/version/main/examples_manifest.json) * Using full set of examples from `nightly` build: [rerun.io/viewer](https://rerun.io/viewer/pr/6252?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json) * [x] The PR title and labels are set such as to maximize their usefulness for the next release's CHANGELOG * [x] If applicable, add a new check to the [release checklist](https://github.com/rerun-io/rerun/blob/main/tests/python/release_checklist)! - [PR Build Summary](https://build.rerun.io/pr/6252) - [Recent benchmark results](https://build.rerun.io/graphs/crates.html) - [Wasm size tracking](https://build.rerun.io/graphs/sizes.html) To run all checks from `main`, comment on the PR with `@rerun-bot full-check`.
1 parent 0f34aaa commit efba98a

File tree

6 files changed

+66
-42
lines changed

6 files changed

+66
-42
lines changed

crates/re_renderer/src/context.rs

+43-35
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ impl RenderContext {
120120
device: Arc<wgpu::Device>,
121121
queue: Arc<wgpu::Queue>,
122122
config: RenderContextConfig,
123-
) -> Self {
123+
) -> Result<Self, String> {
124124
re_tracing::profile_function!();
125125

126126
let frame_index_for_uncaptured_errors = Arc::new(AtomicU64::new(STARTUP_FRAME_IDX));
@@ -155,38 +155,46 @@ impl RenderContext {
155155
let global_bindings = GlobalBindings::new(&gpu_resources, &device);
156156

157157
// Validate capabilities of the device.
158-
assert!(
159-
config.device_caps.limits().check_limits(&device.limits()),
160-
"The given device doesn't support the required limits for the given hardware caps {:?}.
161-
Required:
162-
{:?}
163-
Actual:
164-
{:?}",
165-
config.device_caps,
166-
config.device_caps.limits(),
167-
device.limits(),
168-
);
169-
assert!(
170-
device.features().contains(config.device_caps.features()),
171-
"The given device doesn't support the required features for the given hardware caps {:?}.
172-
Required:
173-
{:?}
174-
Actual:
175-
{:?}",
176-
config.device_caps,
177-
config.device_caps.features(),
178-
device.features(),
179-
);
180-
assert!(adapter.get_downlevel_capabilities().flags.contains(config.device_caps.required_downlevel_capabilities().flags),
181-
"The given device doesn't support the required downlevel capabilities for the given hardware caps {:?}.
182-
Required:
183-
{:?}
184-
Actual:
185-
{:?}",
186-
config.device_caps,
187-
config.device_caps.required_downlevel_capabilities(),
188-
adapter.get_downlevel_capabilities(),
189-
);
158+
if !config.device_caps.limits().check_limits(&device.limits()) {
159+
return Err(format!(
160+
"The given device doesn't support the required limits for the given hardware caps {:?}.
161+
Required:
162+
{:?}
163+
Actual:
164+
{:?}",
165+
config.device_caps,
166+
config.device_caps.limits(),
167+
device.limits(),
168+
));
169+
}
170+
if !device.features().contains(config.device_caps.features()) {
171+
return Err(format!(
172+
"The given device doesn't support the required features for the given hardware caps {:?}.
173+
Required:
174+
{:?}
175+
Actual:
176+
{:?}",
177+
config.device_caps,
178+
config.device_caps.features(),
179+
device.features(),
180+
));
181+
}
182+
if !adapter
183+
.get_downlevel_capabilities()
184+
.flags
185+
.contains(config.device_caps.required_downlevel_capabilities().flags)
186+
{
187+
return Err(format!(
188+
"The given device doesn't support the required downlevel capabilities for the given hardware caps {:?}.
189+
Required:
190+
{:?}
191+
Actual:
192+
{:?}",
193+
config.device_caps,
194+
config.device_caps.required_downlevel_capabilities(),
195+
adapter.get_downlevel_capabilities(),
196+
));
197+
}
190198

191199
let resolver = crate::new_recommended_file_resolver();
192200
let mesh_manager = RwLock::new(MeshManager::new());
@@ -222,7 +230,7 @@ impl RenderContext {
222230
Self::GPU_READBACK_BELT_DEFAULT_CHUNK_SIZE.unwrap(),
223231
));
224232

225-
RenderContext {
233+
Ok(RenderContext {
226234
device,
227235
queue,
228236
config,
@@ -240,7 +248,7 @@ impl RenderContext {
240248
active_frame,
241249
frame_index_for_uncaptured_errors,
242250
gpu_resources,
243-
}
251+
})
244252
}
245253

246254
fn poll_device(&mut self) {

crates/re_renderer_examples/framework.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ impl<E: Example + 'static> Application<E> {
152152
output_format_color,
153153
device_caps,
154154
},
155-
);
155+
)
156+
.map_err(|err| anyhow::format_err!("{err}"))?;
156157

157158
let example = E::new(&re_ctx);
158159

crates/re_viewer/src/lib.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -198,23 +198,38 @@ pub(crate) fn wgpu_options(force_wgpu_backend: Option<String>) -> egui_wgpu::Wgp
198198

199199
/// Customize eframe and egui to suit the rerun viewer.
200200
#[must_use]
201-
pub fn customize_eframe(cc: &eframe::CreationContext<'_>) -> re_ui::ReUi {
201+
pub fn customize_eframe_and_setup_renderer(cc: &eframe::CreationContext<'_>) -> re_ui::ReUi {
202202
re_tracing::profile_function!();
203203

204204
if let Some(render_state) = &cc.wgpu_render_state {
205205
use re_renderer::{config::RenderContextConfig, RenderContext};
206206

207207
let paint_callback_resources = &mut render_state.renderer.write().callback_resources;
208208

209-
paint_callback_resources.insert(RenderContext::new(
209+
let render_ctx = RenderContext::new(
210210
&render_state.adapter,
211211
render_state.device.clone(),
212212
render_state.queue.clone(),
213213
RenderContextConfig {
214214
output_format_color: render_state.target_format,
215215
device_caps: re_renderer::config::DeviceCaps::from_adapter(&render_state.adapter),
216216
},
217-
));
217+
);
218+
219+
match render_ctx {
220+
Ok(render_ctx) => {
221+
paint_callback_resources.insert(render_ctx);
222+
}
223+
Err(err) => {
224+
re_log::error!("Failed to create render context: {err}");
225+
226+
#[allow(clippy::exit)]
227+
{
228+
// TODO(egui#4474): return errors to eframe -> `main`
229+
std::process::exit(1);
230+
}
231+
}
232+
};
218233
}
219234

220235
re_ui::ReUi::load_and_apply(&cc.egui_ctx)

crates/re_viewer/src/native.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub fn run_native_app(
1818
window_title,
1919
native_options,
2020
Box::new(move |cc| {
21-
let re_ui = crate::customize_eframe(cc);
21+
let re_ui = crate::customize_eframe_and_setup_renderer(cc);
2222
app_creator(cc, re_ui)
2323
}),
2424
)

crates/re_viewer/src/web.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ fn create_app(
229229
expect_data_soon: None,
230230
force_wgpu_backend: None,
231231
};
232-
let re_ui = crate::customize_eframe(cc);
232+
let re_ui = crate::customize_eframe_and_setup_renderer(cc);
233233

234234
let mut app = crate::App::new(build_info, &app_env, startup_options, re_ui, cc.storage);
235235

examples/rust/extend_viewer_ui/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
4242
window_title,
4343
native_options,
4444
Box::new(move |cc| {
45-
let re_ui = re_viewer::customize_eframe(cc);
45+
let re_ui = re_viewer::customize_eframe_and_setup_renderer(cc);
4646

4747
let mut rerun_app = re_viewer::App::new(
4848
re_viewer::build_info(),

0 commit comments

Comments
 (0)