* Choose the Linux GPU backend at runtime and pace Wayland frames adaptively
A Vulkan-capable desktop Linux build (the `vulkan` feature, or
`MAKEPAD=vulkan`) now carries OpenGL ES as well and picks between them
when its event loop starts: Vulkan on Wayland when a hardware device
answers, OpenGL ES when none does (no driver, only a software rasterizer,
or an X11 session). `MAKEPAD_GPU=auto|gl|vulkan` overrides the choice, and
`MAKEPAD=gl` still produces an OpenGL-only binary. The feature stays
opt-in: the hosted (`--stdin-loop`) and direct renderers of such a build
are Vulkan-only, and Vulkan has no video texture import yet.
Wayland frame pacing
- Pace presents by what the backend and the session can actually do,
rather than by a fixed number (new `wayland/frame_pacer.rs`). Vulkan
runs two presents in flight only when the compositor offers `fifo-v1`
and the driver uses it; otherwise a second present would block inside
`vkQueuePresentKHR` on a callback an occluded window never receives.
OpenGL starts the next frame early only when its measured cost says the
swap would land after the outstanding callback is due, so cheap frames
are not committed twice per refresh. One present in flight, which is
what this did before, left a heavy scene at half the display rate.
- Bound the pacing gate at 250 ms so an occluded window cannot freeze the
app's clocks, and let pending screenshot requests through it.
- Treat WouldBlock on the display flush as transient.
Vulkan
- Bound the frame fence wait and the swapchain acquire on Linux instead of
waiting forever.
- Keep the per-frame packet arena mapped, recycle completed frame
resources on the window path, and ask for one more swapchain image on
Linux, where the pacing can keep two presents queued.
- Skip CPU devices unless `MAKEPAD_GPU=vulkan` asks for Vulkan explicitly.
OpenGL
- Stop repainting forever at rest: poll the texture lifetime fence once
per frame, and check for time-driven shaders only after the
zero-instance skip, as Vulkan does. The explicit
`Cx::frame_completion_serial` poll still always arms a fence.
- Upload draw-call uniforms only when they changed; they were uploaded
twice per draw call per frame. A zbias shift now marks them dirty, so a
call skipped that frame still uploads when it next draws.
- Compute the retained-instance upload plan once per buffer per frame; it
was computed three times.
- Target remote screenshot requests at the presenting window. Every
`--remote` grab timed out on OpenGL before this.
- Emit the `gpu.present` trace with render and swap timings.
Retained instances
- `upload_plan` settles segments that kept their slot and offset by `Arc`
identity, scans for the first few that moved, and only then builds a
pointer-keyed map. On a large map this took a plan from 0.3-1.5 ms to
about 0.07 ms. Results are identical to the previous planner.
- Add `collect_backlog` so a renderer can drain retirements once a frame.
Runtime backend consistency
- `CxOs::vulkan_active()` replaces the compile-time branches that decided
between the two renderers, so a build that fell back to OpenGL releases
its uniform buffers, shares host swapchains and retires textures the way
an OpenGL build does.
Wayland teardown
- Drop windows before the `Connection`, and destroy a window's EGL surface
and `wl_egl_window` before its `wl_surface`. Every OpenGL exit on
Wayland segfaulted inside NVIDIA's egl-wayland.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Make Vulkan the default on desktop Linux, with mipmaps and hosted fallback
Every desktop Linux binary now carries both renderers and picks at startup,
instead of only the apps that asked for Vulkan by name. Three things had to
be true first.
Gate the feature where the fallback exists. build.rs derived `use_vulkan`
from `target_os == "linux"` alone, which also matches OpenHarmony and every
other Linux triple, none of which carry `naga`, and it ignored
`MAKEPAD=linux_direct`, whose DRM/KMS renderer has no OpenGL fallback of its
own. The feature now only reaches x86_64/aarch64 gnu windowed builds;
`MAKEPAD=linux_direct+vulkan` remains the way to ask for direct Vulkan.
Give Vulkan a mip chain. `image_cache_use_mipmaps` was off for Vulkan
because the uploader only ever filled level 0, so every minified image
aliased. Images now allocate their full chain and fill levels below the
first with `vkCmdBlitImage`, the way `glGenerateMipmap` does, skipping
formats the device cannot linearly blit. On Robrix's sign-in icons this
takes Vulkan from 2153 pixels differing from the OpenGL render by more than
8, to 400.
Choose the hosted renderer at runtime too. `--stdin-loop` mode was
Vulkan-only in a Vulkan-capable build and panicked when no device answered,
while its host, on an X11 session, had already fallen back to OpenGL: with
the feature on by default that combination would have killed every child the
wm launches. The hosted path now selects the way the windowed one does, its
import follows the renderer the process actually started, and a hosted child
rejects software devices for the same reason a window does.
Video and `Texture::read_back` are still OpenGL-only; the video error now
names `MAKEPAD_GPU=gl`, and the feature comment says so.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* workspace: drop the renderer-routing argument and its build-time wording
One desktop Linux binary now carries both GPU backends and picks at startup,
so an app honouring a saved renderer choice passes it to the platform as
MAKEPAD_GPU and restarts itself. Nothing produces `--renderer-routed` any
more; an argument this parser does not know was already ignored, so dropping
its arm changes nothing for anyone still passing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Keep the shared Android and direct-display paths as they were
An audit of what this branch reaches on platforms that share these files
found five places where it changed behaviour it was never meant to touch.
All of them come from code this branch made runtime-selected or relaxed.
Mipmaps are desktop Linux only, matching `image_cache_use_mipmaps`, which
is what asks for the format. An Android or Quest Vulkan build shared the
new chain code and would have allocated levels and recorded blits that
nothing there requests and nothing measured.
The mip chain also needs more of the format than it asked for. It checked
only that the format samples linearly, while `record_mip_chain` blits
between levels, so it now requires BLIT_SRC and BLIT_DST too and keeps a
single level otherwise.
Shader compilation stays a compile-time answer off desktop Linux. Whether
a draw shader is compiled to SPIR-V became a runtime `vulkan_active()`
test, which on Quest would follow an Android Vulkan init failure instead
of the build. Only desktop Linux has that fallback.
The hosted loop compiles GLSL only when OpenGL is the renderer. Losing its
cfg left it calling `gl()` in a Vulkan hosted child, which has no EGL
context, so it panicked. Its Wayland sibling already guards this way.
The direct display build keeps its software-buffer upload. `texture_for_draw`
gained a `not(linux_direct)` that was never needed: `MAKEPAD=linux_direct`
without Vulkan has its own `upload_presentable_image_software_buffer` in
os/linux/presentable.rs, and the outer gate already excludes the direct
Vulkan build.
Also: `gpu_preference` is now gated exactly where its caller is compiled,
since `vulkan_linux.rs` builds for every `target_os = "linux"` under
`use_vulkan`, and the hosted loop's imports follow the block that uses
them, which the direct Vulkan build does not compile.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Retained renderer support is back for Scope on Metal, Vulkan, OpenGL,
WebGL and the simulated GPU. A `vulkan` cargo feature picks Vulkan on
desktop Linux, Cx::gpu_backend() names the compiled GPU API, and the
direct WM builds again. Settings.renderer in libs/workspace keeps the
saved GPU API choice (Vulkan | OpenGL) behind the --renderer-routed
argument. The Android build keeps the texture alloc types imported for
OES adoption, and that import stays off the web build. The simulated
GPU builds on Linux again.
Squashed from work, without the cargo vendor snapshot the retained
renderer commit carried there:
- platform: a `vulkan` cargo feature picks Vulkan on desktop Linux; Cx::gpu_backend() names the compiled GPU API; the direct WM builds again
- workspace: Settings.renderer — the saved GPU API choice (Vulkan | OpenGL) and the --renderer-routed argument
- Restore retained renderer support for Scope
- platform: Android builds again — the texture alloc types stay imported for OES adoption
- platform: the Android texture-adoption import stays off the web build
- platform: the simulated GPU builds on Linux again
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Squash of 1 work commits (Sep 12–12):
e74b919 platform: the CPU simulated-GPU backend is `gpusim` — the word "headless" now means only window-less
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Squash of 10 work commits (Sep 2–12):
3389475 trace: one switch — MAKEPAD_TRACE=<topics>, trace!(topic, …), and /trace on the bridge
c55a315 platform: monotonic clock beside the wall clock, trap-safe dispatch, studio worker only with a studio
89fe453 platform: wheels and flight sticks are game inputs, with an output-report handle
e5d37e0 platform: a web file picker and file drop that hand apps bytes
19cf377 platform: the thread runtime contract — spawner, tasks, pools, scheduler, UI waker
cf2b8ca platform: no std::time on web — clippy guard and the platform clock everywhere a web build runs
c527cd8 vj: the web thumbnail pipeline never blocks the main thread
2a064d3 workspace: add loader, haptics, voice, and runtime fixes
541c886 platform: name heavy pool jobs over 250 ms; headless Startup sent once per Cx
d476e52 Fix Linux worker sizing and screen recording defaults
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- The SCK loopback device claimed is_default and default_input() fell
through to it when the real mic errored — the voice pipeline silently
became SYSTEM-AUDIO capture behind screen-recording privileges. Loopback
is no longer default and default_input() only auto-picks real Input
devices; system-audio capture is explicit-opt-in by device id.
- VoiceProcessingIO input failed FailedInitialization on macOS when pinned
via setDeviceID (it aggregates its own devices; follows system default
input now). If VPIO still fails, degrade to plain capture instead of
marking the DEVICE failed (voice_input_unusable flag + device-change
re-arm); input error log no longer says "output".
- VPIO voice-chat mode ducks all other app audio to a whisper: request
advanced ducking at minimum level (macOS 14+/iOS 17+) so music stays
near full volume while AEC keeps running. Links AudioToolbox.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Support overriding the dpi factor at runtime, on all platforms
Add `Cx::set_window_dpi_override` for runtime UI zoom, but dispatch it
in a deferred manner so it's safe to call in an event handler.
For each platform, we connect the dpi override to the click/tap
coordinates to remap it properly, which was done on some platforms
but not most.
* Don't always set the app's icon (e.g., for packaged app bundles)
* App menu bar: restore Quit option, use proper app name
The menu bar shows "MakepadStdInLoop" by default, which is really strange
especially for published apps. This fixes that and also allows the app
to set the name, as well as using a sensible default for it if the app
didn't specify it.
We also now restore the previous Makepad 1.0 behavior of having a default
"Quit" entry in the main app's first menu bar entry.
* ensure Exit flow actually makes it out, on macOS
Video playback: extended API with volume, playback rate, seek ranges,
buffered ranges, can_play_type, audio-only mode. Unified player wrapping
native backend (AVPlayer/GStreamer/MediaFoundation) with software fallback.
YUV shader pipeline (BT.601/709/2020, NV12 biplanar, rotation).
Camera: V4L2 backend (Linux), expanded NDK Camera2 (Android), AVCapture
stream refactor (iOS/macOS) with shared session architecture. NV12
zero-copy paths on iOS (CVMetalTextureCache) and Android (AImage planes).
Camera preview modes (texture/native/auto).
Video encoding: H264 hardware encode on Apple (VideoToolbox) and Android
(MediaCodec). Camera-to-encoder pipeline with pixel buffer passthrough.
Media plugin system: externalized codec implementation via MediaPlugin
trait. MsePlayer, VideoFrameDecoder, MediaVideoEncoder, SoftwareVideoPlayer
interfaces. Runtime codec capability query and merge.
Includes camera example app.
Co-authored-by: ant <ant@offline.click>
Refactor app icon handling into a unified app_icon module that replaces
the old window_icon.rs. Build-time icon generation produces platform-
native formats (ICO with multiple sizes for Windows, ICNS for macOS,
multi-resolution PNGs for Linux/Wayland/X11).
Add `cargo makepad desktop` subcommand for desktop packaging with
automatic icon detection from MAKEPAD_APP_ICON_PATH env var, or from
Cargo package metadata.
Resolve binary names from [[bin]] targets in Cargo.toml so .app bundles,
.exe outputs, and APK labels use the correct name instead of defaulting
to the package name.
Use llvm-rc for Windows .res generation (cross-compilation compatible)
with absolute link paths for reliable resource embedding.
Co-authored-by: ant <ant@offline.click>
* initialize the event loop for wayland backend
Signed-off-by: drindr <dreamchancn@qq.com>
* feat: hidpi wayland and mouse event
- hidpi support with wayland
- mouse event support
- refactor some code
Signed-off-by: drindr <dreamchancn@qq.com>
* wayland xkbcommon for key pressing event
Signed-off-by: drindr <dreamchancn@qq.com>
* add support for IME in with wayland
---------
Signed-off-by: drindr <dreamchancn@qq.com>
Co-authored-by: makepaddev <20386332+makepaddev@users.noreply.github.com>