mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Draw on the GPU that drives the primary display on Windows and Linux
On a desktop with a Ryzen integrated GPU without a monitor and an NVIDIA card driving both monitors, Automatic (power saving on Windows) picked the integrated GPU; Windows presented every frame across adapters and the integrated GPU's driver reset, losing the graphics device or taking every monitor down for minutes (same bug as pdfcraft#378). Automatic now asks the system which GPU drives which display (Windows: EnumDisplayDevices through winsafe; Linux: /sys/class/drm) and ranks the GPU driving a display, and among those the primary display's, ahead of the power preference. Where the system can't say, or no adapter's PCI ids match (OpenGL, Metal), the order is the power preference's as before, so nothing gets worse. Power Saving and High Performance chosen by the user, and WGPU_POWER_PREF, keep ordering by kind alone. The log now lists the display GPUs, which adapters drive a display, and the adapter drawn on with the reason, the first question in every black-window report. Tests cover the device-id parser, the rankings (desktop with all monitors on the discrete GPU, hybrid laptop, a monitor on each GPU, no match), the sysfs reader and a live EnumDisplayDevices call. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ZwZjADUZP4VzvrFGpiZch
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
4cf912fa94
commit
77a3cef4d1
+9
-4
@@ -45,10 +45,15 @@ How the web shell (`apps/vectorcraft-web/src/web.rs`) differs from desktop:
|
||||
|
||||
The canvas is rasterized on the CPU (`vectorcraft-render`, vello_cpu); the GPU (wgpu, through eframe) only composites the canvas texture and draws the UI, so any GPU that can show the window will do. The desktop app picks the window's adapter itself (`apps/vectorcraft/src/gpu.rs`, eframe's `native_adapter_selector`) and logs every adapter it found and the one it uses.
|
||||
|
||||
- **Order:** adapters that report they can't present to the window are never tried; then the one `WGPU_ADAPTER_NAME` names; hardware before software (llvmpipe, WARP); the native backends (Vulkan, Metal, DX12) before OpenGL; then the power preference; then, on Windows, where each GPU is listed under both, a GPU's DX12 adapter before its Vulkan one (Intel's Vulkan driver made the whole window flicker black, #545), keeping the system's order among equals. `WGPU_BACKEND=vulkan` still picks Vulkan.
|
||||
- **Preferences › Performance › Graphics Processor** (`gpuPreference`): `automatic` (the default), `lowPower` (Power Saving, the integrated GPU) or `highPerformance` (the discrete GPU). The adapter is chosen when the window opens, so a change applies after a restart.
|
||||
- **Automatic on Windows and macOS** is power saving: the system shows frames from any GPU, and presenting frames rendered on a discrete GPU through the integrated one made the window flicker on some hybrid laptops (#306).
|
||||
- **Automatic on Linux and the BSDs** keeps the system's order: Mesa's Vulkan device-select layer puts the GPU the desktop runs on first (the integrated one on hybrid laptops; `DRI_PRIME` and `MESA_VK_DEVICE_SELECT` steer it). A Wayland compositor may not accept frames from another GPU: on a desktop whose compositor ran on an NVIDIA GPU, rendering on the Ryzen's integrated GPU made KWin end the window's connection ("importing the supplied dmabufs failed") and 0.5.0 crashed at startup (#502).
|
||||
- **Order:** adapters that report they can't present to the window are never tried; then the one `WGPU_ADAPTER_NAME` names; hardware before software (llvmpipe, WARP); the native backends (Vulkan, Metal, DX12) before OpenGL; with Automatic, the GPU that drives a display, and among those the one that drives the primary display; then the power preference; then, on Windows, where each GPU is listed under both, a GPU's DX12 adapter before its Vulkan one (Intel's Vulkan driver made the whole window flicker black, #545), keeping the system's order among equals. `WGPU_BACKEND=vulkan` still picks Vulkan.
|
||||
- **The GPU that drives the display.** A GPU without a monitor is the wrong one even when it says it can show the window: on a desktop with a Ryzen's integrated GPU (no monitor) and an NVIDIA card driving both monitors, power saving picked the integrated GPU, Windows had to present every frame across adapters, and the integrated GPU's driver reset under that: the graphics device was lost, or the desktop's compositor went down and every monitor stayed black for minutes (pdfcraft#378). So Automatic asks the system which GPU drives which display and puts that GPU first; the power preference only orders the rest, and decides alone where the system can't say.
|
||||
- **Windows:** `EnumDisplayDevices` (the display devices attached to the desktop, and the primary one), through the `winsafe` crate; the PCI ids in each device id are matched against wgpu's adapters. The registry doesn't tell a user which adapter drives a display, and WMI reports a resolution for a GPU without a monitor, so neither is used.
|
||||
- **Linux:** the connected connectors in `/sys/class/drm` and their cards' PCI ids; a built-in panel (`eDP`, `LVDS`, `DSI`) counts as the primary display.
|
||||
- **macOS**, OpenGL adapters (no device id) and Metal (no ids at all): no match, so the power preference decides as before.
|
||||
- The log's first lines list the display GPUs (`display GPUs (PCI vendor:device): 10de:2204 (primary)`), every adapter with whether it drives a display, and the one drawn on and why (`drawing on NVIDIA GeForce RTX 3090 (Dx12, DiscreteGpu): it drives the primary display`). That is the first thing to look for in a black-window report.
|
||||
- **Preferences › Performance › Graphics Processor** (`gpuPreference`): `automatic` (the default), `lowPower` (Power Saving, the integrated GPU) or `highPerformance` (the discrete GPU). The adapter is chosen when the window opens, so a change applies after a restart. Power Saving and High Performance are the user's own choice and order by kind alone, without looking at the displays; so does `WGPU_POWER_PREF`.
|
||||
- **Automatic on Windows and macOS** is the GPU that drives the primary display, then power saving: the system shows frames from any GPU, and presenting frames rendered on a discrete GPU through the integrated one made the window flicker on some hybrid laptops (#306). On a hybrid laptop the integrated GPU drives the panel, so both rules agree.
|
||||
- **Automatic on Linux and the BSDs** is the GPU that drives the panel or a monitor, then the system's order: Mesa's Vulkan device-select layer puts the GPU the desktop runs on first (the integrated one on hybrid laptops; `DRI_PRIME` and `MESA_VK_DEVICE_SELECT` steer it). A Wayland compositor may not accept frames from another GPU: on a desktop whose compositor ran on an NVIDIA GPU, rendering on the Ryzen's integrated GPU made KWin end the window's connection ("importing the supplied dmabufs failed") and 0.5.0 crashed at startup (#502).
|
||||
- 0.5.0 saved `powerSaving`, its default, for everyone; it reads as `automatic`.
|
||||
- **If the window fails on its adapter while starting up** (an error from wgpu, or a panic inside wgpu or egui-wgpu during the first frames), the app starts again without that adapter and tries the next one, telling which in the status bar; the run that failed keeps its log as `vectorcraft.1.log`. On Unix the new app replaces the process (an AppImage stays mounted); on Windows it starts beside it. Adapters are told apart by backend and PCI ids, or by name where the backend reports no ids (Metal lists every GPU of a dual-GPU Mac as `0000:0000`, #651). The adapters left out travel in `VECTORCRAFT_GPU_SKIP` (`backend:vendor:device`, such as `Vulkan:1002:164e`), one more on each restart, so the restarts end. When no adapter is left, the app logs why and exits with an error instead of panicking.
|
||||
- **Environment variables** for when the choice still goes wrong, all read at startup and stronger than the preference:
|
||||
|
||||
Reference in New Issue
Block a user