Skip to content

Commit 9ef610e

Browse files
authored
Make wgpu the default renderer for eframe and egui.rs (#7615)
* Closes #5889 See the above issue for motivation. To use glow instead, disable the default features of `eframe` and opt-in to `glow`. This also changes egui.rs to use wgpu, which means WebGPU when available, and WebGL otherwise
1 parent 51b0d0e commit 9ef610e

9 files changed

Lines changed: 90 additions & 43 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ iter_on_single_items = "warn"
232232
iter_over_hash_type = "warn"
233233
iter_without_into_iter = "warn"
234234
large_digit_groups = "warn"
235+
large_futures = "warn"
235236
large_include_file = "warn"
236237
large_stack_arrays = "warn"
237238
large_stack_frames = "warn"
@@ -329,6 +330,7 @@ unnecessary_semicolon = "warn"
329330
unnecessary_struct_initialization = "warn"
330331
unnecessary_wraps = "warn"
331332
unnested_or_patterns = "warn"
333+
unused_async = "warn"
332334
unused_peekable = "warn"
333335
unused_rounding = "warn"
334336
unused_self = "warn"

crates/eframe/Cargo.toml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ workspace = true
2828
default = [
2929
"accesskit",
3030
"default_fonts",
31-
"glow",
3231
"wayland", # Required for Linux support (including CI!)
3332
"web_screen_reader",
33+
"wgpu",
3434
"winit/default",
3535
"x11",
3636
]
@@ -52,7 +52,11 @@ android-native-activity = ["egui-winit/android-native-activity"]
5252
## If you plan on specifying your own fonts you may disable this feature.
5353
default_fonts = ["egui/default_fonts"]
5454

55-
## Use [`glow`](https://github.com/grovesNL/glow) for painting, via [`egui_glow`](https://github.com/emilk/egui/tree/main/crates/egui_glow).
55+
## Enable [`glow`](https://github.com/grovesNL/glow) for painting, via [`egui_glow`](https://github.com/emilk/egui/tree/main/crates/egui_glow).
56+
##
57+
## There is generally no need to enable both the `wgpu` and `glow` features,
58+
## but if you do you can pick the renderer to use with [`NativeOptions::renderer`]
59+
## and `WebOptions::renderer`.
5660
glow = ["dep:egui_glow", "dep:glow", "dep:glutin-winit", "dep:glutin"]
5761

5862
## Enable saving app state to disk.
@@ -74,9 +78,15 @@ wayland = [
7478
## For other platforms, use the `accesskit` feature instead.
7579
web_screen_reader = ["web-sys/SpeechSynthesis", "web-sys/SpeechSynthesisUtterance"]
7680

77-
## Use [`wgpu`](https://docs.rs/wgpu) for painting (via [`egui-wgpu`](https://github.com/emilk/egui/tree/main/crates/egui-wgpu)).
81+
## Enable [`wgpu`](https://docs.rs/wgpu) for painting (via [`egui-wgpu`](https://github.com/emilk/egui/tree/main/crates/egui-wgpu)).
82+
##
83+
## There is generally no need to enable both the `wgpu` and `glow` features,
84+
## but if you do you can pick the renderer to use with [`NativeOptions::renderer`]
85+
## and `WebOptions::renderer`.
7886
##
79-
## This overrides the `glow` feature.
87+
## Switching from `wgpu (the default)` to `glow` can significantly reduce your binary size
88+
## (including the .wasm of a web app).
89+
## See <https://github.com/emilk/egui/issues/5889> for more details.
8090
##
8191
## By default, eframe will prefer WebGPU over WebGL, but
8292
## you can configure this at run-time with [`NativeOptions::wgpu_options`].

crates/eframe/src/epi.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,10 @@ impl Default for NativeOptions {
471471
/// Options when using `eframe` in a web page.
472472
#[cfg(target_arch = "wasm32")]
473473
pub struct WebOptions {
474+
/// What rendering backend to use.
475+
#[cfg(any(feature = "glow", feature = "wgpu_no_default_features"))]
476+
pub renderer: Renderer,
477+
474478
/// Sets the number of bits in the depth buffer.
475479
///
476480
/// `egui` doesn't need the depth buffer, so the default value is 0.
@@ -519,6 +523,9 @@ pub struct WebOptions {
519523
impl Default for WebOptions {
520524
fn default() -> Self {
521525
Self {
526+
#[cfg(any(feature = "glow", feature = "wgpu_no_default_features"))]
527+
renderer: Renderer::default(),
528+
522529
depth_buffer: 0,
523530

524531
#[cfg(feature = "glow")]
@@ -592,8 +599,8 @@ impl Default for Renderer {
592599
#[cfg(feature = "wgpu_no_default_features")]
593600
return Self::Wgpu;
594601

595-
// By default, only the `glow` feature is enabled, so if the user added `wgpu` to the feature list
596-
// they probably wanted to use wgpu:
602+
// It's weird that the user has enabled both glow and wgpu,
603+
// but let's pick the better of the two (wgpu):
597604
#[cfg(feature = "glow")]
598605
#[cfg(feature = "wgpu_no_default_features")]
599606
return Self::Wgpu;

crates/eframe/src/web/app_runner.rs

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use egui::{TexturesDelta, UserData, ViewportCommand};
22

3-
use crate::{App, epi};
3+
use crate::{App, epi, web::web_painter::WebPainter};
44

5-
use super::{NeedRepaint, now_sec, text_agent::TextAgent, web_painter::WebPainter as _};
5+
use super::{NeedRepaint, now_sec, text_agent::TextAgent};
66

77
pub struct AppRunner {
88
#[allow(dead_code, clippy::allow_attributes)]
99
pub(crate) web_options: crate::WebOptions,
1010
pub(crate) frame: epi::Frame,
1111
egui_ctx: egui::Context,
12-
painter: super::ActiveWebPainter,
12+
painter: Box<dyn WebPainter>,
1313
pub(crate) input: super::WebInput,
1414
app: Box<dyn epi::App>,
1515
pub(crate) needs_repaint: std::sync::Arc<NeedRepaint>,
@@ -34,14 +34,52 @@ impl Drop for AppRunner {
3434
impl AppRunner {
3535
/// # Errors
3636
/// Failure to initialize WebGL renderer, or failure to create app.
37+
#[cfg_attr(
38+
not(feature = "wgpu_no_default_features"),
39+
expect(clippy::unused_async)
40+
)]
3741
pub async fn new(
3842
canvas: web_sys::HtmlCanvasElement,
3943
web_options: crate::WebOptions,
4044
app_creator: epi::AppCreator<'static>,
4145
text_agent: TextAgent,
4246
) -> Result<Self, String> {
4347
let egui_ctx = egui::Context::default();
44-
let painter = super::ActiveWebPainter::new(egui_ctx.clone(), canvas, &web_options).await?;
48+
49+
#[allow(clippy::allow_attributes, unused_assignments)]
50+
#[cfg(feature = "glow")]
51+
let mut gl = None;
52+
53+
#[allow(clippy::allow_attributes, unused_assignments)]
54+
#[cfg(feature = "wgpu_no_default_features")]
55+
let mut wgpu_render_state = None;
56+
57+
let painter = match web_options.renderer {
58+
#[cfg(feature = "glow")]
59+
epi::Renderer::Glow => {
60+
log::debug!("Using the glow renderer");
61+
let painter = super::web_painter_glow::WebPainterGlow::new(
62+
egui_ctx.clone(),
63+
canvas,
64+
&web_options,
65+
)?;
66+
gl = Some(painter.gl().clone());
67+
Box::new(painter) as Box<dyn WebPainter>
68+
}
69+
70+
#[cfg(feature = "wgpu_no_default_features")]
71+
epi::Renderer::Wgpu => {
72+
log::debug!("Using the wgpu renderer");
73+
let painter = super::web_painter_wgpu::WebPainterWgpu::new(
74+
egui_ctx.clone(),
75+
canvas,
76+
&web_options,
77+
)
78+
.await?;
79+
wgpu_render_state = painter.render_state();
80+
Box::new(painter) as Box<dyn WebPainter>
81+
}
82+
};
4583

4684
let info = epi::IntegrationInfo {
4785
web_info: epi::WebInfo {
@@ -79,15 +117,13 @@ impl AppRunner {
79117
storage: Some(&storage),
80118

81119
#[cfg(feature = "glow")]
82-
gl: Some(painter.gl().clone()),
120+
gl: gl.clone(),
83121

84122
#[cfg(feature = "glow")]
85123
get_proc_address: None,
86124

87-
#[cfg(all(feature = "wgpu_no_default_features", not(feature = "glow")))]
88-
wgpu_render_state: painter.render_state(),
89-
#[cfg(all(feature = "wgpu_no_default_features", feature = "glow"))]
90-
wgpu_render_state: None,
125+
#[cfg(feature = "wgpu_no_default_features")]
126+
wgpu_render_state: wgpu_render_state.clone(),
91127
};
92128
let app = app_creator(&cc).map_err(|err| err.to_string())?;
93129

@@ -96,12 +132,10 @@ impl AppRunner {
96132
storage: Some(Box::new(storage)),
97133

98134
#[cfg(feature = "glow")]
99-
gl: Some(painter.gl().clone()),
135+
gl,
100136

101-
#[cfg(all(feature = "wgpu_no_default_features", not(feature = "glow")))]
102-
wgpu_render_state: painter.render_state(),
103-
#[cfg(all(feature = "wgpu_no_default_features", feature = "glow"))]
104-
wgpu_render_state: None,
137+
#[cfg(feature = "wgpu_no_default_features")]
138+
wgpu_render_state,
105139
};
106140

107141
let needs_repaint: std::sync::Arc<NeedRepaint> =

crates/eframe/src/web/mod.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,9 @@ mod web_painter;
3030

3131
#[cfg(feature = "glow")]
3232
mod web_painter_glow;
33-
#[cfg(feature = "glow")]
34-
pub(crate) type ActiveWebPainter = web_painter_glow::WebPainterGlow;
3533

3634
#[cfg(feature = "wgpu_no_default_features")]
3735
mod web_painter_wgpu;
38-
#[cfg(all(feature = "wgpu_no_default_features", not(feature = "glow")))]
39-
pub(crate) type ActiveWebPainter = web_painter_wgpu::WebPainterWgpu;
4036

4137
pub use backend::*;
4238

crates/eframe/src/web/web_painter_glow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ impl WebPainterGlow {
2020
self.painter.gl()
2121
}
2222

23-
pub async fn new(
23+
pub fn new(
2424
_ctx: egui::Context,
2525
canvas: HtmlCanvasElement,
2626
options: &WebOptions,

crates/eframe/src/web/web_painter_wgpu.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
use std::sync::Arc;
22

3-
use super::web_painter::WebPainter;
4-
use crate::WebOptions;
53
use egui::{Event, UserData, ViewportId};
6-
use egui_wgpu::capture::{CaptureReceiver, CaptureSender, CaptureState, capture_channel};
7-
use egui_wgpu::{RenderState, SurfaceErrorAction};
4+
use egui_wgpu::{
5+
RenderState, SurfaceErrorAction,
6+
capture::{CaptureReceiver, CaptureSender, CaptureState, capture_channel},
7+
};
88
use wasm_bindgen::JsValue;
99
use web_sys::HtmlCanvasElement;
1010

11+
use super::web_painter::WebPainter;
12+
1113
pub(crate) struct WebPainterWgpu {
1214
canvas: HtmlCanvasElement,
1315
surface: wgpu::Surface<'static>,
@@ -23,7 +25,6 @@ pub(crate) struct WebPainterWgpu {
2325
}
2426

2527
impl WebPainterWgpu {
26-
#[expect(unused)] // only used if `wgpu` is the only active feature.
2728
pub fn render_state(&self) -> Option<RenderState> {
2829
self.render_state.clone()
2930
}
@@ -55,11 +56,10 @@ impl WebPainterWgpu {
5556
})
5657
}
5758

58-
#[expect(unused)] // only used if `wgpu` is the only active feature.
5959
pub async fn new(
6060
ctx: egui::Context,
6161
canvas: web_sys::HtmlCanvasElement,
62-
options: &WebOptions,
62+
options: &crate::WebOptions,
6363
) -> Result<Self, String> {
6464
log::debug!("Creating wgpu painter");
6565

crates/egui_demo_app/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ crate-type = ["cdylib", "rlib"]
2323

2424

2525
[features]
26-
default = ["glow", "persistence"]
26+
default = ["wgpu", "persistence"]
2727

2828
# image_viewer adds about 0.9 MB of WASM
2929
web_app = ["http", "persistence"]

scripts/build_demo_web.sh

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ OPEN=false
1313
OPTIMIZE=false
1414
BUILD=debug
1515
BUILD_FLAGS=""
16-
WGPU=false
16+
GLOW=false
1717
WASM_OPT_FLAGS="-O2 --fast-math"
1818

1919
while test $# -gt 0; do
2020
case "$1" in
2121
-h|--help)
22-
echo "build_demo_web.sh [--release] [--wgpu] [--open]"
22+
echo "build_demo_web.sh [--release] [--glow] [--open]"
2323
echo ""
2424
echo " -g: Keep debug symbols even with --release."
2525
echo " These are useful profiling and size trimming."
@@ -29,9 +29,7 @@ while test $# -gt 0; do
2929
echo " --release: Build with --release, and then run wasm-opt."
3030
echo " NOTE: --release also removes debug symbols, unless you also use -g."
3131
echo ""
32-
echo " --wgpu: Build a binary using wgpu instead of glow/webgl."
33-
echo " The resulting binary will automatically use WebGPU if available and"
34-
echo " fall back to a WebGL emulation layer otherwise."
32+
echo " --glow: Build a binary using glow instead of wgpu."
3533
exit 0
3634
;;
3735

@@ -52,9 +50,9 @@ while test $# -gt 0; do
5250
BUILD_FLAGS="--release"
5351
;;
5452

55-
--wgpu)
53+
--glow)
5654
shift
57-
WGPU=true
55+
GLOW=true
5856
;;
5957

6058
*)
@@ -66,10 +64,10 @@ done
6664

6765
OUT_FILE_NAME="egui_demo_app"
6866

69-
if [[ "${WGPU}" == true ]]; then
70-
FEATURES="${FEATURES},wgpu"
71-
else
67+
if [[ "${GLOW}" == true ]]; then
7268
FEATURES="${FEATURES},glow"
69+
else
70+
FEATURES="${FEATURES},wgpu"
7371
fi
7472

7573
FINAL_WASM_PATH=web_demo/${OUT_FILE_NAME}_bg.wasm

0 commit comments

Comments
 (0)