Commit Graph
1473 Commits
Author SHA1 Message Date
vicrodh a0051ab513 fix(audio): default to shared System output and resolve Auto to a concrete backend (#470)
OOTB playback froze (seekbar advancing, no audio) on hosts where the
configured backend was not usable — e.g. PipeWire as the Linux default but
`pactl` absent (minimal Debian/Ubuntu). "Auto" (a null backend_type) fell
through to a legacy CPAL path that forced the track rate onto the shared
default device, producing a suspended/silent stream and leaving a
process-wide stuck audio handle that survived Reset.

- Add a cross-platform "System" backend (CpalDefaultBackend now on Linux
  too): opens the OS default output at its negotiated rate with rodio
  resampling and an explicit ~100ms CPAL buffer (MixerDeviceSink has zero
  internal buffering, so the bare default underran and stayed suspended).
  Shared, no exclusivity, no `pactl` — mixes with other apps like any
  normal player.
- Make System the OOTB default and what Reset lands on; seed it on first
  run. Drop the per-startup #375 NULL->PipeWire backfill migration.
- Resolve a null backend_type to System in the player so the legacy CPAL
  path is never reached (covers legacy installs and headless callers).
- "Auto" in Settings is now a resolve-and-set action: it picks the best
  available backend (PipeWire if available, else System), stores that
  concrete value and updates the dropdown + device picker, so backend_type
  is never null.
- Explicit PipeWire (DAC passthrough) and ALSA Direct (exclusive) configs
  are untouched and remain bit-perfect.

cc
2026-05-24 21:13:11 -06:00
vicrodh bf56eefd7a chore(deps): bump cpal 0.17.1 -> 0.17.3 and alsa 0.10 -> 0.11
cpal 0.17.3 requires alsa 0.11, which in turn pulls alsa-sys 0.4. The
`links = "alsa"` constraint permits only one alsa-sys in the dependency
graph, so qbz-audio's direct alsa stack is raised in lockstep:
alsa 0.10 -> 0.11 and alsa-sys 0.3 -> 0.4. Both workspace lockfiles
(crates/ and src-tauri/) are updated to cpal 0.17.3 / alsa 0.11.0 /
alsa-sys 0.4.0.

No source changes required: alsa_direct.rs uses only the stable
high-level alsa API (pcm, HwParams, Format, Direction, ValueOr, mixer),
and the snd_lib_error_set_handler FFI in alsa_error_handler.rs is
unchanged in alsa-sys 0.4. Both workspaces pass cargo check.

cc
2026-05-23 22:25:26 -06:00
vicrodh 97dd405bcf chore(deps): bump open from 5.3.4 to 5.3.5
cc
2026-05-23 14:04:48 -06:00
vicrodh 9b2c6743e6 chore(deps): bump tauri-build from 2.6.1 to 2.6.2
cc
2026-05-23 14:03:10 -06:00
vicrodh d5f9d0b83c chore(deps): bump tokio from 1.52.2 to 1.52.3
cc
2026-05-23 14:01:17 -06:00
vicrodh d5d2e93744 chore(deps): bump ashpd from 0.13.10 to 0.13.11
cc
2026-05-23 13:59:34 -06:00
vicrodh 9e505a9fa4 chore(deps): bump tower-http from 0.6.8 to 0.6.11
cc
2026-05-23 13:58:00 -06:00
vicrodh 50384d3d3c fix(player): never skip the gapless target offline + bound the skip cascade (#467)
The offline-skip recursion walked the entire remaining queue synchronously,
desyncing the logical queue from the still-playing engine. Fixes:

- The gapless-transition target is the track the engine is already playing;
  never run the availability-skip branch for it.
- isTrackAvailable now counts the in-memory/disk cache (new v2_is_track_cached
  command), not just downloaded copies.
- Cap consecutive offline skips and play-failure auto-skips at 5 in both
  +page.svelte and playbackService.ts.

cc
2026-05-22 21:46:34 -06:00
vicrodh 133e90f752 fix(offline): hysteresis + cheap probe + streaming liveness override (#467)
Long sessions died when a single transient blip flipped the app to offline and
the queue then skipped every cached-but-not-downloaded track. Harden the
detector:

- Consecutive-failure hysteresis: declare offline only after 2 failed polls,
  not a single blip.
- Replace the HEAD https://1.1.1.1 probe with a concurrent race of cheap
  generate_204 endpoints, so a saturated link (long Hi-Res tracks) no longer
  times the probe out.
- Positive liveness override: if a segment downloaded within the last 45s we
  are online by definition, regardless of the probe.

cc
2026-05-22 21:46:33 -06:00
vicrodh e4fa90c1b2 feat(prefetch): adaptive throttle based on observed bandwidth + underrun signal
Recovered from 63ecc324 (authored on the native-port branch, never merged to
pre-release). Backend-only, no Slint. Scales the prefetch cap down on slow
links and during audio underruns, and exposes the per-segment download signal
the offline detector reuses as a positive liveness override (#467).

cc
2026-05-22 21:46:07 -06:00
vicrodh 3477edfb76 refactor: share the image cache and credential store via crates
Extracts two self-contained, framework-agnostic modules out of
src-tauri so they can be reused by other clients without duplicating
logic:

- ImageCacheService / ImageCacheStats move into the qbz-cache crate
  (LRU disk cache, MD5-keyed, SQLite index).
- The credential store (keyring + AES-256-GCM encrypted file for Qobuz
  credentials and the OAuth token) moves into a new qbz-credentials
  crate.

src-tauri/image_cache.rs and src-tauri/credentials/mod.rs become thin
re-exports, keeping their Tauri managed-state wrappers. The Tauri app
is behavior-identical; both modules were already self-contained (no
Tauri and no crate:: references).

cc
2026-05-18 14:11:05 -06:00
vicrodh a213b37807 refactor(qbz-app): add AppRuntime shell facade skeleton
Adds a framework-agnostic composition root for non-Tauri UI shells
(Slint, TUI, headless) as Task 1 of the Slint POC readiness audit
(session-20-slint-poc-readiness-audit).

AppRuntime<A> owns an Arc<QbzCore<A>> plus the runtime state machine,
built with the same recipe as the Tauri CoreBridge but with no Tauri
dependency. Scope is composition and accessors only; per-user store
ownership and session activation are deferred to Task 2.

qbz-app now depends on qbz-core, qbz-player, qbz-audio, and qbz-models.
The Tauri app does not consume this module; it is purely additive.

cc
2026-05-18 07:28:19 -06:00
vicrodh 1052ff25b3 refactor(tauri): use qbz-app playback context
cx
2026-05-17 19:42:53 -06:00
vicrodh 8b850999f9 refactor(tauri): use qbz-app session store
cx
2026-05-17 19:19:47 -06:00
vicrodh 74d75f3fbf fix: persist session durably to survive reboot (#440)
Switch the session store SQLite connection from synchronous=NORMAL to
synchronous=FULL. With WAL + NORMAL the last writes can sit unsynced in
the WAL and be lost on a hard reboot / power loss, dropping the restored
session.

cc
2026-05-17 13:15:32 -06:00
vicrodh c747c72e9d chore(release): bump version to 1.2.13 "400+ stars"
Version bumped across Cargo.toml, tauri.conf.json, package.json, snapcraft.yaml (version + source-tag), flake.nix, and the lockfiles. metainfo.xml gains a 1.2.13 release entry, the About modal codename becomes "400+ stars", and the README contributors list adds @Vudgekek and @DoubleGate.

cc
2026-05-16 14:40:09 -06:00
vicrodh 3d29cf1384 fix(graphics): make recommendation advisory-only, GPU-aware DMA-BUF help
The graphics recommendation banner no longer writes settings: the Apply button and the v2_apply_graphics_recommendation command are removed, so the banner only detects and explains. The user applies the change with the real toggles, matching the HiFi Wizard's advisory model. write_recommendation stays for the qbz --autoconfig-graphics CLI.

The Force DMA-BUF help text is now GPU-aware: the instability warning only shows on NVIDIA-only systems; non-NVIDIA and hybrid hosts are told it is safe to enable. On hybrid hosts the rendering GPU dropdown marks the integrated GPU as recommended.

cc
2026-05-16 12:22:41 -06:00
vicrodh 1a5dbe07bb refactor(qbz-app): extract boot watchdog decision
cx
2026-05-16 09:04:34 -06:00
vicrodh 3c963cdaf3 refactor(qbz-app): extract graphics autoconfig
cx
2026-05-16 08:50:06 -06:00
vicrodh dceeacb57e refactor(tauri): use qbz-app graphics detection
cx
2026-05-16 00:47:11 -06:00
vicrodh b65feee511 refactor(tauri): use qbz-app user data paths
cx
2026-05-16 00:24:03 -06:00
vicrodh be500956ff refactor(qbz-app): add developer settings store
cx
2026-05-15 23:25:06 -06:00
vicrodh 87e426ab5d refactor(tauri): use qbz-audio settings
cx
2026-05-15 19:51:13 -06:00
vicrodh 441bcc5f0e refactor(tauri): use qbz-app graphics settings
cx
2026-05-15 18:53:24 -06:00
vicrodh 4d1feec75d refactor(tauri): use qbz-app image cache settings
cx
2026-05-15 18:20:56 -06:00
vicrodh 10b0e259f4 refactor(tauri): use qbz-app download settings
cx
2026-05-15 17:50:59 -06:00
vicrodh faca837658 chore(tauri): update qbz-app lock dependencies
cx
2026-05-15 14:21:17 -06:00
vicrodh f527186ca7 refactor(tauri): use qbz-app remote control settings
cx
2026-05-15 14:20:35 -06:00
vicrodh ebe03193c2 Merge refactor/qbz-app-ui-preferences-foundation: qbz-app UI preference stores
cx
2026-05-15 00:41:12 -06:00
vicrodh 3903086f36 fix(release-watch): drop upcoming and non-streamable albums
`/favorite/getNewReleases` includes albums whose stream availability is
still in the future, so they appear in the Release Watch grid even
though `get_album` 404s as soon as the user clicks them. Same shape for
regional restrictions and label takedowns surfaced via `streamable=false`.

Add `release_date_stream` and `streamable` to the Album struct (both
optional with serde defaults so existing call sites stay happy) and
filter the response inside `v2_get_release_watch` after the artist
blacklist pass: skip any album marked `streamable=false` or whose
`release_date_stream` is strictly greater than today (UTC). The total
count gets adjusted alongside so pagination math stays consistent.

cc
2026-05-15 00:35:38 -06:00
vicrodh 2d7639c637 refactor(tauri): use qbz-app ui preference stores
cx
2026-05-15 00:10:57 -06:00
vicrodh 7f38dbcc6f refactor(tauri): use qbz-app preference stores
cx
2026-05-14 19:49:11 -06:00
vicrodh dac1b3a762 refactor(tauri): use qbz-app settings stores
cx
2026-05-14 17:08:57 -06:00
vicrodh 0877f4a5a2 refactor(tauri): use qbz-app runtime types 2026-05-14 11:52:43 -06:00
vicrodh d16ef003a5 refactor(qbz-app): move runtime core 2026-05-14 11:45:59 -06:00
vicrodh 1bb8d53dd0 feat(graphics): NVIDIA Wayland compat toggle + watchdog fallback to CPU
Two-pronged improvement to the graphics safety net for users hitting
the NVIDIA + Wayland + WebKit GBM issue:

1) New opt-in toggle 'NVIDIA Wayland compatibility (experimental)' in
   Settings > Graphics. When ON:
   - Sets __NV_DISABLE_EXPLICIT_SYNC=1 to bypass libnvidia-egl-gbm's
     buggy implicit-sync paths that produce "Failed to create GBM
     buffer of size NxN: Invalid argument" on driver 550+.
   - Lifts the defensive compositing-mode shutdown that QBZ applies
     to NVIDIA-only Wayland sessions — the user is signaling the real
     fix is now in place, so the safety net is no longer needed.
   - Persisted in graphics_settings.db column nvidia_compat_mode (new,
     default off). Migrated via ALTER TABLE so existing installs don't
     pick up a behaviour change.

2) Reset-graphics CLI affordance, surfaced only when the toggle is on:
   inline copyable input + Copy button rendering `qbz --reset-graphics`
   (or `flatpak run com.blitzfc.qbz --reset-graphics` based on detected
   install method). Works around the global select-disable elsewhere
   in SettingsView via user-select: all + onclick={e.select()} + the
   explicit button. The boot watchdog still auto-reverts on crash, but
   this is the manual escape hatch when the user wants to recover
   without waiting for the watchdog to fire.

3) Watchdog recovery now lands in full CPU mode after ANY revert.
   The single-knob revert (hw_accel / dmabuf / preferred_gpu) still
   narrows the cause for the UI banner, but the safest post-crash
   state is full CPU mode (HW accel off + DMA-BUF off + preferred_gpu
   reset to auto). A partial revert can still hit the next crash if
   the failure was stack-wide (driver bug, missing extension); going
   all-the-way-CPU guarantees the user always reaches a paintable
   window after a recovery — they can selectively re-enable from the
   Settings banner.

4) preferred_gpu='software' now implies hardware_acceleration=off at
   env-var application time. Forcing Mesa llvmpipe while keeping
   WebKit GPU compositing on would just round-trip software pixels
   through a "GPU" path that has no GPU — nonsensical configuration
   that the watchdog had to clean up after. Now it's prevented at
   source.

i18n keys (en/es/de/fr/pt): settings.graphics.nvidiaCompatMode,
nvidiaCompatModeDesc, resetCmdTitle, resetCmdDesc;
actions.copiedToClipboard.

cc
2026-05-14 09:18:56 -06:00
vicrodh 8b176a1848 chore(deps): bump discord-rich-presence 0.2.5 → 1.1.0 with API adjustment
DiscordIpcClient::new became infallible in 1.0 — it now returns Self
directly instead of Result<Self>. Failures surface at connect() time
where the catch already lives. Removed the now-spurious `if let Ok()`
wrap around the constructor.

Closes #428 (applied manually because the bump needed a code change
that Dependabot can't author).

cc
2026-05-14 08:59:02 -06:00
Victor RH 47c9c61894 Merge pull request #432 from vicrodh/dependabot/cargo/src-tauri/pre-release/tower-http-0.6.8
chore(deps): bump tower-http from 0.5.2 to 0.6.8 in /src-tauri
2026-05-14 08:46:48 -06:00
Victor RH 0eae6a5609 Merge pull request #425 from vicrodh/dependabot/cargo/src-tauri/pre-release/tokio-1.52.3
chore(deps): bump tokio from 1.52.2 to 1.52.3 in /src-tauri
2026-05-14 08:35:07 -06:00
Victor RH dc6725b1da Merge pull request #431 from vicrodh/dependabot/cargo/src-tauri/pre-release/filetime-0.2.29
chore(deps): bump filetime from 0.2.27 to 0.2.29 in /src-tauri
2026-05-14 08:35:03 -06:00
Victor RH 91bfb05668 Merge pull request #433 from vicrodh/dependabot/cargo/src-tauri/pre-release/tauri-plugin-single-instance-2.4.2
chore(deps): bump tauri-plugin-single-instance from 2.4.1 to 2.4.2 in /src-tauri
2026-05-14 08:34:59 -06:00
vicrodh 921f8e1a49 fix(session): resume Qobuz streams at saved position without losing seek (#315)
Three bugs were stacking up to make session resume drop the saved offset
for streamed Qobuz tracks:

1. Position save was debounced, not throttled. Each playback tick reset
   the 5s timer, so the save never fired while a track played
   continuously — the persisted position froze at whatever value got
   written during the first quiet window after track start (typically
   ~2s). Switch to throttle: fire the first call immediately, then once
   per 5s window, with a tail call to flush the latest value when the
   window ends.

2. togglePlay tried to apply the restore offset via a separate cmdSeek
   right after cmdPlayTrack. For Qobuz streaming the audio thread's
   Seek handler bails when current_audio_data is unset — streaming
   uses current_streaming_source instead — so the seek was silently
   dropped and the track started at 0:00. Pass start_position_secs
   directly to v2_play_track. The streaming backend (legacy + V2
   player) waits for enough buffer to cover the offset plus 8s
   headroom, then eagerly decode-and-discards decoder output up to
   the offset before engaging the audio engine — no race, no
   first-pull underrun. Plex and local tracks keep the old play+seek
   path; they load full audio_data so Seek works as-is.

3. The seekbar showed 0:00 from app launch until the user hit play,
   even when a saved position was queued. setPendingSessionRestore
   now pre-positions currentTime when positionSecs > 0 so the UI
   reflects "paused at X" the moment the app opens.

Other plumbing:
- AudioCommand::PlayStreaming carries start_position_secs and
  content_length (used to estimate bytes-per-second for the resume
  buffer target).
- Player::play_streaming{,_dynamic} grow a start_position_secs
  parameter; QConnect and api_server callers pass 0 (remote-driven
  playback always starts fresh).
- cmdPlayTrack forwards startPositionSecs as a 5th optional arg.

cc
2026-05-14 02:18:59 -06:00
vicrodh b2960e8029 feat(graphics): smart GPU preference with boot watchdog and crash recovery
Solves the long-running performance complaints (especially Optimus
laptops where the dGPU silently hijacks WebKit). The end-to-end shape:

- graphics_detection enumerates physical GPUs from /sys/class/drm and
  cross-references EGL vendor JSONs under /usr/share/glvnd/egl_vendor.d
  to expose only stacks the running process can actually use. Works
  inside Flatpak/Snap because /sys is still mounted read-only and the
  sandbox-visible EGL vendor JSONs are the right thing to read.
- preferred_gpu column in graphics_settings.db (string: auto, integrated,
  discrete, software, or a specific PCI slot id). Migrated with
  ALTER TABLE ... DEFAULT 'auto'.
- env_vars_for_preferred_gpu returns Set/Unset actions applied at startup
  before WebKit init. Integrated/AMD path explicitly unsets
  __NV_PRIME_RENDER_OFFLOAD so KDE/Optimus sessions that pre-set it to 1
  no longer override the EGL pin and yank rendering back onto NVIDIA.
- Auto resolver: on hybrid systems (iGPU + dGPU both usable), Auto pins
  to the iGPU. Single-GPU and no-GPU systems remain no-op. The dropdown
  surfaces what Auto resolved to ("Auto (Intel Graphics)") so the user
  sees the decision without picking explicitly.
- boot_watchdog writes a pending.json before WebKit init listing the
  risky knobs in effect. Frontend calls v2_mark_boot_succeeded after
  first paint to clear it and promote to last-good.json. If the next
  launch sees pending without a success ack, it blames matching fields,
  reverts them in-DB, and increments per-knob failure counters; two
  consecutive failures lock the knob until the user clears it.
- Settings > Graphics gets a Rendering GPU dropdown (between HW accel
  and DMA-BUF) and a crash-recovery banner that lets the user re-enable
  any auto-disabled knob. Restart-required affordance shared with the
  other risky toggles.
- i18n keys for the dropdown, banner copy, and autoWithTarget label
  across all five locales.

cc
2026-05-14 00:36:52 -06:00
vicrodh cd035a34a4 feat(graphics): detect hybrid NVIDIA+iGPU and surface GPU + DE in Diagnostics
autoconfig_graphics gains a hybrid Intel/AMD + NVIDIA branch that keeps
GSK renderer on Auto and DMA-BUF off so the iGPU handles compositing
without the dGPU getting dragged in. detect_gpu_name is exposed and
labels hybrid setups explicitly (e.g. "NVIDIA (driver 580) + Intel
(i915)"). RuntimeDiagnostics gets runtime_gpu_name and
runtime_desktop_environment so the Diagnostics panel can show what the
app sees at runtime, which is the first thing useful to triage
performance reports from log uploads.

cc
2026-05-14 00:36:27 -06:00
dependabot[bot] 5880744822 chore(deps): bump tauri-plugin-single-instance in /src-tauri
Bumps [tauri-plugin-single-instance](https://github.com/tauri-apps/plugins-workspace) from 2.4.1 to 2.4.2.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](https://github.com/tauri-apps/plugins-workspace/compare/fs-v2.4.1...fs-v2.4.2)

---
updated-dependencies:
- dependency-name: tauri-plugin-single-instance
  dependency-version: 2.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-14 05:38:24 +00:00
dependabot[bot] 7ce112bae1 chore(deps): bump tower-http from 0.5.2 to 0.6.8 in /src-tauri
Bumps [tower-http](https://github.com/tower-rs/tower-http) from 0.5.2 to 0.6.8.
- [Release notes](https://github.com/tower-rs/tower-http/releases)
- [Commits](https://github.com/tower-rs/tower-http/compare/tower-http-0.5.2...tower-http-0.6.8)

---
updated-dependencies:
- dependency-name: tower-http
  dependency-version: 0.6.8
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-14 05:38:07 +00:00
dependabot[bot] 620a393b2d chore(deps): bump filetime from 0.2.27 to 0.2.29 in /src-tauri
Bumps [filetime](https://github.com/alexcrichton/filetime) from 0.2.27 to 0.2.29.
- [Commits](https://github.com/alexcrichton/filetime/compare/0.2.27...0.2.29)

---
updated-dependencies:
- dependency-name: filetime
  dependency-version: 0.2.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-14 05:37:51 +00:00
dependabot[bot] 060766e127 chore(deps): bump tokio from 1.52.2 to 1.52.3 in /src-tauri
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.52.2 to 1.52.3.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.52.2...tokio-1.52.3)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.52.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-14 05:37:18 +00:00
vicrodh 700d5ef2c6 feat(settings): surface graphics recommendation banner in the Graphics tab
The detection + decision matrix in autoconfig_graphics.rs already knew
the right combination for every (GPU vendor x display server x desktop)
case, but the only way to consume it was the qbz --autoconfig-graphics
CLI tool which most users never run. The recommendation sat invisible
while users hunted toggles by hand.

Lifts the same logic into the Settings UI as a persistent banner at
the top of the new Graphics tab:

  - autoconfig_graphics: Environment and Recommendation structs become
    public with Serialize, the three pieces (detect_environment,
    compute_recommendation, write_recommendation) become pub so they
    can be re-used. The existing apply_recommendation CLI helper now
    delegates writes to the shared write_recommendation, keeping the
    behaviour identical (and inverting the DMA-BUF mapping so that
    rec.disable_dmabuf=false now writes force_dmabuf=true, matching
    the 1.2.13 opt-in semantics).

  - commands_v2/graphics_recommendation.rs (new): two thin Tauri
    commands — v2_get_graphics_recommendation returns the environment
    plus the computed recommendation so the frontend can compare it
    to persisted settings; v2_apply_graphics_recommendation writes
    the whole bundle in one call.

  - Settings UI: the Graphics tab loads the recommendation on mount.
    A $derived computes whether at least one recommended value
    diverges from the four persisted settings (HW accel / force_x11 /
    gsk_renderer / force_dmabuf with the inverted DMA-BUF axis).
    When it does, a violet-accent banner appears above the profile
    grid showing the detected environment, the rationale lines from
    the matrix, and an Apply button. Persistent (no dismiss) — vanishes
    the moment the persisted state matches the recommendation, no
    second copy of state to keep in sync.

  - i18n: 4 new keys per locale (title / detected / apply / applied)
    across en/es/de/fr/pt. The rationale strings stay in English
    because they're hardcoded in autoconfig_graphics.rs and reword
    them per scenario would mean a structured i18n key per case —
    not worth it for diagnostic copy that's read once and dismissed.

cc
2026-05-13 16:46:29 -06:00
vicrodh dc96c5ac89 feat(graphics): flip DMA-BUF default to opt-in
The DMA-BUF renderer was on by default for AMD/Intel users with
specific NVIDIA carve-outs to disable it. The asymmetry was load-
bearing on a fragile feature: when DMA-BUF breaks on Linux the
failure mode is catastrophic (black window, missing textures, full
viewport corruption) rather than degraded, and the auto-detection
couldn't anticipate hybrid Intel+NVIDIA edge cases that surface only
on specific Mesa/NVIDIA driver pairings. The perf gain when it works
is marginal — ~5-10% memory bandwidth on heavy compositing, not
material for a music UI.

Flips the policy:
  - DMA-BUF off by default for everyone.
  - Users opt in via the existing Settings > Developer >
    force_dmabuf toggle (already persisted; just inverts the
    semantic from "force even though heuristics say off" to "turn
    it on at all").
  - QBZ_HARDWARE_ACCEL=1 explicit env override still bypasses
    everything as before (power-user escape hatch).
  - QBZ_DISABLE_DMABUF=1 still respected for explicit logging.

Removes the NVIDIA-Wayland / NVIDIA-X11 carve-outs because they're
strict subsets of "always off" now. Keeps the Wayland+NVIDIA-only
compositing disable — that's a separate axis (EGL protocol errors
corrupt the whole window, not just texture sharing) and still has
to fire on that specific stack.

User-visible startup log changes from "Using default WebKit
renderer (full hardware acceleration)" to "DMA-BUF renderer off by
default (opt-in via Settings > Developer)" for the common path.

cc
2026-05-13 16:18:17 -06:00