Upgrade WGPU and Linebender dependencies (#4154)

This commit is contained in:
Timon
2026-05-17 15:00:32 +00:00
parent c4a978009a
commit d5f0140f26
23 changed files with 414 additions and 399 deletions

View File

@@ -1,3 +1,7 @@
[build]
# Keep `--cfg=web_sys_unstable_apis` here so the wasm wrapper crates build with the same web-sys API signatures (e.g. `put_image_data`/`get_image_data` taking `i32` rather than `f64`) on both native test builds and the wasm target. Cargo applies `[build]` rustflags only when no target-specific rustflags table matches, so the wasm-specific list below must continue to include this cfg.
rustflags = ["--cfg=web_sys_unstable_apis"]
[target.wasm32-unknown-unknown]
rustflags = [
# Currently disabled because of https://github.com/GraphiteEditor/Graphite/issues/1262

View File

@@ -6,7 +6,7 @@
},
"ghcr.io/devcontainers/features/node:1": {}
},
"onCreateCommand": "cargo install cargo-watch wasm-pack cargo-about && cargo install -f wasm-bindgen-cli@0.2.100",
"onCreateCommand": "cargo install cargo-watch wasm-pack cargo-about && cargo install -f wasm-bindgen-cli@0.2.121",
"customizations": {
"vscode": {
// NOTE: Keep this in sync with `.vscode/extensions.json`

View File

@@ -283,7 +283,7 @@ jobs:
pull-requests: write
env:
WASM_BINDGEN_CLI_VERSION: "0.2.100"
WASM_BINDGEN_CLI_VERSION: "0.2.121"
steps:
- name: 📥 Clone repository
@@ -474,7 +474,7 @@ jobs:
pull-requests: write
env:
WASM_BINDGEN_CLI_VERSION: "0.2.100"
WASM_BINDGEN_CLI_VERSION: "0.2.121"
steps:
- name: 📥 Clone repository

View File

@@ -57,7 +57,8 @@ jobs:
- name: 🧪 Run Rust tests
env:
RUSTFLAGS: -Dwarnings
# `--cfg=web_sys_unstable_apis` mirrors the `[build]` section of `.cargo/config.toml`
RUSTFLAGS: "-Dwarnings --cfg=web_sys_unstable_apis"
run: mold -run cargo test --all-features
# Rust format check on GitHub runner

View File

@@ -29,7 +29,7 @@ pkgs.mkShell (
pkgs.lld
pkgs.nodejs
pkgs.binaryen
pkgs.wasm-bindgen-cli_0_2_100
pkgs.wasm-bindgen-cli_0_2_121
pkgs.wasm-pack
pkgs.cargo-about

View File

@@ -1,10 +1,10 @@
{ pkgs, ... }:
let
version = "147.0.10+gd58e84d+chromium-147.0.7727.118";
version = "147.0.14+g76d2442+chromium-147.0.7727.138";
hashes = {
aarch64-linux = "sha256-kaRijMDacPcoeCcS31zmRSNOvgozx+uq2M34mD28bu4=";
x86_64-linux = "sha256-CHzPofBDhCniDZEpOxXK4I7p57SYjMAY1HVo3Vna0e8=";
aarch64-linux = "sha256-Gy2Xs1NHwmIr+buzoqDso1QJVkKlA/UMXytHjNGqpNk=";
x86_64-linux = "sha256-os7wAFJ+mVK65HCikvEjhMeQUj2ty7y+6Ad0OlOcbeA=";
};
selectSystem =

View File

@@ -83,7 +83,7 @@ deps.crane.lib.buildPackage (
pkgs.lld
pkgs.nodejs
pkgs.binaryen
pkgs.wasm-bindgen-cli_0_2_100
pkgs.wasm-bindgen-cli_0_2_121
pkgs.wasm-pack
pkgs.cargo-about
pkgs.removeReferencesTo

674
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -120,17 +120,17 @@ quote = "1.0"
chrono = "0.4"
ron = "0.12"
fastnoise-lite = "1.1"
wgpu = { version = "28.0", features = [
wgpu = { version = "29.0", features = [
# We don't have wgpu on multiple threads (yet) https://github.com/gfx-rs/wgpu/blob/trunk/CHANGELOG.md#wgpu-types-now-send-sync-on-wasm
"fragile-send-sync-non-atomic-wasm",
"spirv",
"strict_asserts",
] }
once_cell = "1.13" # Remove and replace with `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>)
wasm-bindgen = "=0.2.100" # NOTICE: ensure this stays in sync with the `wasm-bindgen-cli` version in `website/content/volunteer/guide/project-setup/_index.md`. We pin this version because wasm-bindgen upgrades may break various things.
wasm-bindgen = "=0.2.121" # NOTICE: keep in sync with the `wasm-bindgen-cli` version pinned across CI workflows, devcontainer, Nix, and the `cargo-run` tool. We pin this version because wasm-bindgen upgrades may break various things.
wasm-bindgen-futures = "0.4"
js-sys = "=0.3.77"
web-sys = { version = "=0.3.77", features = [
js-sys = "=0.3.98"
web-sys = { version = "=0.3.98", features = [
"Document",
"DomRect",
"Element",
@@ -154,12 +154,12 @@ url = "2.5"
tokio = { version = "1.29", features = ["fs", "macros", "io-std", "rt", "rt-multi-thread"] }
# Linebender ecosystem (BEGIN)
kurbo = { version = "0.13", features = ["serde"] }
vello = "0.8"
vello_encoding = "0.8"
vello = "0.9"
vello_encoding = "0.9"
resvg = "0.47"
usvg = "0.47"
parley = "0.6"
skrifa = "0.40"
parley = { version = "0.9", default-features = false, features = ["std"] }
skrifa = "0.42"
polycool = "0.4"
color = "0.3"
# Linebender ecosystem (END)
@@ -203,8 +203,8 @@ gungraun = { version = "0.18" }
ndarray = "0.16"
strum = { version = "0.27", features = ["derive"] }
dirs = "6.0"
cef = "147"
cef-dll-sys = "147"
cef = "148"
cef-dll-sys = "148"
include_dir = "0.7"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing = "0.1"
@@ -245,3 +245,5 @@ debug = true
# Force cargo to use only one version of the dpi crate (vendoring breaks without this)
dpi = { git = "https://github.com/rust-windowing/winit.git" }
rfd = { git = "https://github.com/timon-schelling/rfd.git", branch = "graphite" } # TODO: Remove this once https://github.com/PolyMeilex/rfd/pull/317 is merged and released
cef = { git = "https://github.com/timon-schelling/cef-rs.git", branch = "graphite" }
cef-dll-sys = { git = "https://github.com/timon-schelling/cef-rs.git", branch = "graphite" }

View File

@@ -582,14 +582,10 @@ impl ApplicationHandler for App {
Err(RenderError::OutdatedUITextureError) => {
self.cef_context.notify_view_info_changed();
}
Err(RenderError::SurfaceError(wgpu::SurfaceError::Lost)) => {
Err(RenderError::SurfaceLost) => {
tracing::warn!("lost surface");
}
Err(RenderError::SurfaceError(wgpu::SurfaceError::OutOfMemory)) => {
tracing::error!("GPU out of memory");
self.exit(None);
}
Err(RenderError::SurfaceError(e)) => tracing::error!("Render error: {:?}", e),
Err(other) => tracing::error!("Render error: {:?}", other),
}
let _ = self.start_render_sender.try_send(());
}

View File

@@ -120,7 +120,7 @@ impl RenderState {
let render_pipeline_layout = context.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[&texture_bind_group_layout],
bind_group_layouts: &[Some(&texture_bind_group_layout)],
immediate_size: size_of::<Immediates>() as u32,
});
@@ -262,7 +262,17 @@ impl RenderState {
self.render_overlays(scene);
}
let output = self.surface.get_current_texture().map_err(RenderError::SurfaceError)?;
let (output, suboptimal) = match self.surface.get_current_texture() {
wgpu::CurrentSurfaceTexture::Success(t) => (t, false),
// wgpu reports the swapchain no longer matches the underlying surface; present this frame and reconfigure after present, since `Surface::configure` panics while an acquired `SurfaceTexture` is still alive
wgpu::CurrentSurfaceTexture::Suboptimal(t) => (t, true),
// Window is minimized or behind another window: skip the frame silently and try again once it becomes visible
wgpu::CurrentSurfaceTexture::Occluded => return Ok(()),
wgpu::CurrentSurfaceTexture::Lost => return Err(RenderError::SurfaceLost),
wgpu::CurrentSurfaceTexture::Outdated => return Err(RenderError::SurfaceOutdated),
wgpu::CurrentSurfaceTexture::Timeout => return Err(RenderError::SurfaceTimeout),
wgpu::CurrentSurfaceTexture::Validation => return Err(RenderError::SurfaceValidation),
};
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
@@ -308,6 +318,10 @@ impl RenderState {
window.pre_present_notify();
output.present();
if suboptimal {
self.surface.configure(&self.context.device, &self.config);
}
if ui_scale.is_some() {
return Err(RenderError::OutdatedUITextureError);
}
@@ -349,9 +363,13 @@ impl RenderState {
}
}
#[derive(Debug)]
pub(crate) enum RenderError {
OutdatedUITextureError,
SurfaceError(wgpu::SurfaceError),
SurfaceLost,
SurfaceOutdated,
SurfaceTimeout,
SurfaceValidation,
}
#[repr(C)]

View File

@@ -1040,7 +1040,7 @@ impl OverlayContext {
}
let image_data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(wasm_bindgen::Clamped(&data), PATTERN_WIDTH as u32, PATTERN_HEIGHT as u32).unwrap();
pattern_context.put_image_data(&image_data, 0., 0.).unwrap();
pattern_context.put_image_data(&image_data, 0, 0).unwrap();
let pattern = self.render_context.create_pattern_with_offscreen_canvas(&pattern_canvas, "repeat").unwrap().unwrap();
self.push_path(subpaths, transform);

18
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": {
"crane": {
"locked": {
"lastModified": 1776635034,
"narHash": "sha256-OEOJrT3ZfwbChzODfIH4GzlNTtOFuZFWPtW7jIeR8xU=",
"lastModified": 1778106249,
"narHash": "sha256-cM/AuKy5tMhwOOQIbha8ZRRMHVfNf7cv2aljIw+qoCg=",
"owner": "ipetkov",
"repo": "crane",
"rev": "dc7496d8ea6e526b1254b55d09b966e94673750f",
"rev": "6d015ea29630b7ad2402841386da2cb617a470a7",
"type": "github"
},
"original": {
@@ -17,11 +17,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1776548001,
"narHash": "sha256-ZSK0NL4a1BwVbbTBoSnWgbJy9HeZFXLYQizjb2DPF24=",
"lastModified": 1778869304,
"narHash": "sha256-30sZNZoA1cqF5JNO9fVX+wgiQYjB7HJqqJ4ztCDeBZE=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "b12141ef619e0a9c1c84dc8c684040326f27cdcc",
"rev": "d233902339c02a9c334e7e593de68855ad26c4cb",
"type": "github"
},
"original": {
@@ -45,11 +45,11 @@
]
},
"locked": {
"lastModified": 1776741231,
"narHash": "sha256-k9G98qzn+7npROUaks8VqCFm7cFtEG8ulQLBBo5lItg=",
"lastModified": 1778987862,
"narHash": "sha256-V3qGt9P1eJP/r/1ONablphfGiH0RP4agQhrRANpDYx8=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "02061303f7c4c964f7b4584dabd9e985b4cd442b",
"rev": "6f44d8874ac29806c8d5cae42bf8e19ebb5ce0d3",
"type": "github"
},
"original": {

View File

@@ -172,7 +172,7 @@ pub(crate) fn render_image_data_to_canvases(image_data: &[(u64, Image<SRGBA8>)])
let clamped_u8_data = wasm_bindgen::Clamped(u8_data);
match ImageData::new_with_u8_clamped_array_and_sh(clamped_u8_data, image.width, image.height) {
Ok(image_data_obj) => {
if context.put_image_data(&image_data_obj, 0., 0.).is_err() {
if context.put_image_data(&image_data_obj, 0, 0).is_err() {
error!("Failed to put image data on canvas for id: {placeholder_id}");
}
}

View File

@@ -82,6 +82,7 @@ pub async fn export_document(
// Encode and write raster image when buffer is already provided
write_raster_image(output_path, file_type, data, width, height, transparent)?;
}
#[cfg(target_family = "wasm")]
other => {
return Err(format!("Unexpected render output type: {:?}. Expected Texture, Buffer for raster export or Svg for SVG export.", other).into());
}

View File

@@ -113,7 +113,10 @@ impl CanvasSurface for CanvasSurfaceHandle {
},
);
let surface_texture = surface.get_current_texture().expect("Failed to get surface texture");
let surface_texture = match surface.get_current_texture() {
wgpu::CurrentSurfaceTexture::Success(t) | wgpu::CurrentSurfaceTexture::Suboptimal(t) => t,
other => panic!("Failed to get surface texture: {other:?}"),
};
encoder.copy_texture_to_texture(
wgpu::TexelCopyTextureInfoBase {

View File

@@ -33,13 +33,13 @@ impl BackgroundCompositor {
let checker_rect_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("background_checker_rect_pipeline_layout"),
bind_group_layouts: &[&checker_bind_group_layout],
bind_group_layouts: &[Some(&checker_bind_group_layout)],
immediate_size: 0,
});
let checker_viewport_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("background_checker_viewport_pipeline_layout"),
bind_group_layouts: &[&checker_bind_group_layout],
bind_group_layouts: &[Some(&checker_bind_group_layout)],
immediate_size: 0,
});
@@ -67,7 +67,7 @@ impl BackgroundCompositor {
let fullscreen_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("background_fullscreen_pipeline_layout"),
bind_group_layouts: &[&fullscreen_bind_group_layout],
bind_group_layouts: &[Some(&fullscreen_bind_group_layout)],
immediate_size: 0,
});

View File

@@ -68,9 +68,9 @@ impl ContextBuilder {
}
impl ContextBuilder {
fn build_instance(&self) -> Instance {
Instance::new(&wgpu::InstanceDescriptor {
Instance::new(wgpu::InstanceDescriptor {
backends: self.backends,
..Default::default()
..wgpu::InstanceDescriptor::new_without_display_handle()
})
}
async fn request_adapter(&self, instance: &Instance) -> Option<Adapter> {

View File

@@ -38,7 +38,7 @@ impl Resampler {
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("resample_pipeline_layout"),
bind_group_layouts: &[&bind_group_layout],
bind_group_layouts: &[Some(&bind_group_layout)],
..Default::default()
});

View File

@@ -113,10 +113,10 @@ impl PerPixelAdjustGraphicsPipeline {
};
let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
label: Some(&format!("PerPixelAdjust {name} PipelineLayout")),
bind_group_layouts: &[&device.create_bind_group_layout(&BindGroupLayoutDescriptor {
bind_group_layouts: &[Some(&device.create_bind_group_layout(&BindGroupLayoutDescriptor {
label: Some(&format!("PerPixelAdjust {name} BindGroupLayout 0")),
entries,
})],
}))],
..Default::default()
});

View File

@@ -245,7 +245,7 @@ where
.draw_image_with_html_image_element_and_dw_and_dh(&image_data, 0., 0., resolution.x as f64, resolution.y as f64)
.unwrap();
let rasterized = context.get_image_data(0., 0., resolution.x as f64, resolution.y as f64).unwrap();
let rasterized = context.get_image_data(0, 0, resolution.x as i32, resolution.y as i32).unwrap();
let image = Image::from_image_data(&rasterized.data().0, resolution.x as u32, resolution.y as u32);
List::new_from_item(

View File

@@ -72,7 +72,9 @@ impl TextContext {
builder.push_default(StyleProperty::FontSize(typesetting.font_size as f32));
builder.push_default(StyleProperty::LetterSpacing(typesetting.character_spacing as f32));
builder.push_default(StyleProperty::FontStack(parley::FontStack::Single(parley::FontFamily::Named(std::borrow::Cow::Owned(font_family)))));
builder.push_default(StyleProperty::FontFamily(parley::FontFamily::Single(parley::FontFamilyName::Named(std::borrow::Cow::Owned(
font_family,
)))));
builder.push_default(StyleProperty::FontWeight(font_info.weight()));
builder.push_default(StyleProperty::FontStyle(font_info.style()));
builder.push_default(StyleProperty::FontWidth(font_info.width()));
@@ -81,7 +83,7 @@ impl TextContext {
let mut layout: Layout<()> = builder.build(text);
layout.break_all_lines(typesetting.max_width.map(|mw| mw as f32));
layout.align(typesetting.max_width.map(|max_w| max_w as f32), typesetting.align.into(), AlignmentOptions::default());
layout.align(typesetting.align.into(), AlignmentOptions::default());
Some(layout)
}

View File

@@ -50,8 +50,8 @@ fn requirements(task: &Task) -> Vec<Requirement> {
command: "wasm-bindgen",
args: &["--version"],
name: "wasm-bindgen-cli",
version: Some("0.2.100"),
install: Some("cargo install -f wasm-bindgen-cli@0.2.100"),
version: Some("0.2.121"),
install: Some("cargo install -f wasm-bindgen-cli@0.2.121"),
skip: Some(&|task| matches!(task.target, Target::Cli)),
},
Requirement {
@@ -173,7 +173,11 @@ pub fn check(task: &Task) -> Result<(), Error> {
eprintln!(" {}", dep.install.unwrap());
}
eprintln!();
eprint!("Install them now? [Y/n] ");
if installable.len() == 1 {
eprint!("Install it now? [Y/n] ");
} else {
eprint!("Install them now? [Y/n] ");
}
let mut input = String::new();
std::io::stdin().read_line(&mut input).map_err(|e| Error::Io(e, "Failed to read from stdin".into()))?;