Files
DarkRoom/third_party/README.md
T
dtourolle 4b4c9e2e6d Pre-rotate Slint's Skia drawing on the wgpu swapchain on Android
The other half of the wgpu-hal patch: that one lets a caller promise a
pre-rotated swapchain, and this is the caller keeping the promise.

On configure, `WGPUSurface` reads the surface's `currentTransform`,
sizes the swapchain in the panel's orientation (swapped for a quarter
turn), tells wgpu-hal to use that transform, and before each frame
concatenates the matching rotation onto the Skia canvas. Everything
Slint draws goes through that one matrix, so an imported wgpu texture is
rotated with the rest of the window. Input is not rotated, and must not
be, because Android delivers it in window coordinates.

Three details that would each have been a visible bug:

- `resize_event` compared the new size against the swapchain's. The
  swapchain is transposed while a quarter turn is in effect, so the
  comparison now uses the window's size, kept beside it.
- A half turn, landscape to reverse landscape, changes the transform
  without resizing the window, and wgpu-hal hides the SUBOPTIMAL that
  would report it. So the transform is re-read before every frame. That
  costs one query into the native window.
- The item renderer snapped the origin to the pixel grid only when the
  canvas matrix was a pure translation. Under a rotation that is never
  true, so portrait would have lost pixel alignment everywhere. The check
  now accepts right-angle rotations and flips without scaling.

The direction of each rotation follows the Vulkan spec's reading of
preTransform (the image is drawn already rotated clockwise by the
transform). It has not been confirmed on the device yet.
2026-09-25 04:19:05 -04:00

3.3 KiB

Patched upstream crates

Each directory here is a crate exactly as crates.io publishes it, at the version Cargo.lock resolves, with a local patch on top. The root Cargo.toml routes the dependency here through [patch.crates-io]; the directory is excluded from the workspace, so cargo test --workspace, clippy and fmt leave it alone.

The first commit that adds a directory is the pristine copy (from ~/.cargo/registry/src/*/<crate>-<version>, minus .cargo-ok and the crate's own Cargo.lock). Every later commit touching it is ours, so git log -p -- third_party/<dir> is the patch and nothing else.

Carrying a patch forward

When Slint or wgpu is bumped, the version here stops matching and cargo warns that the patch is unused — the build then silently goes back to the unpatched crate. So a bump is:

  1. Copy the new version in beside the old one, as its own commit.
  2. Re-apply the diff from git log -p on the old directory.
  3. Point [patch.crates-io] at the new directory and delete the old one.
  4. Re-check on the device (below) — both patches are behaviour that only a rotated Android display exercises.

Drop a patch entirely once upstream has the fix; each section says what upstream change would make it unnecessary.

wgpu-hal 29.0.4 — Vulkan pre-rotation on Android

Upstream creates every Vulkan swapchain with preTransform = IDENTITY (src/vulkan/swapchain/native.rs, gfx-rs/wgpu#3345). On Android, a window whose orientation differs from the panel's is then rotated by the compositor on the GPU (composition=CLIENT), and on this tablet in portrait those frames tear.

The patch adds two methods to wgpu_hal::vulkan::Surface:

  • current_transform(&Adapter) — the surface's currentTransform.
  • set_pre_transform(transform) — the preTransform for the next swapchain. Opt-in: nothing calls it but the Skia patch below, and the default is still IDENTITY, so desktop and every other caller behave exactly as upstream.

Setting it is a promise that the caller draws rotated into a swapchain sized in the panel's orientation; wgpu itself rotates nothing.

Unnecessary once wgpu exposes pre-rotation itself (#3345).

i-slint-renderer-skia 1.17.1 — rotate the canvas to match

wgpu_29_surface.rs keeps the promise the wgpu-hal patch lets it make. On Android it reads the surface's transform whenever it configures, sizes the swapchain in the panel's orientation (width and height swapped for a quarter turn), calls set_pre_transform, and concatenates the matching rotation onto the Skia canvas before Slint draws — so the whole UI, including an imported wgpu::Texture, is drawn pre-rotated. It checks the transform before every frame too, because a half turn (landscape to reverse landscape) changes it without resizing the window. Touch input is untouched: only drawing is rotated.

itemrenderer.rs widens the pixel-alignment check from "pure translation" to "any right-angle rotation or flip without scaling". Without that, a rotated canvas silently loses pixel snapping everywhere.

Off Android every path is upstream's: the rotation is always None.

Unnecessary once Slint's Skia wgpu surface pre-rotates on its own — worth offering upstream, since the linuxkms backend already renders through the same rotate-and-translate in render_to_canvas.