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
This commit is contained in:
vicrodh committed 2026-05-16 12:22:41 -06:00
1 parent 29b766ae24
commit 3d29cf1384
9 files changed
+56 -81

No files matched your search

+5 -5
View File
@@ -106,17 +106,17 @@ fn apply_recommendation(rec: &Recommendation) {
}
}
/// Apply the recommendation to the persistence layer. Shared between the CLI
/// prompt (`apply_recommendation`) and the V2 command surface. Returns the
/// list of write errors so the caller can surface them appropriately (stderr
/// for CLI, frontend toast for the Settings UI).
/// Apply the recommendation to the persistence layer. Used by the CLI prompt
/// (`apply_recommendation`); the Settings UI is advisory-only and no longer
/// writes the recommendation. Returns the list of write errors so the caller
/// can surface them on stderr.
///
/// DMA-BUF semantics after the 1.2.13 opt-in flip:
/// - `rec.disable_dmabuf = true` -> force_dmabuf = false (matches default;
/// runtime keeps DMA-BUF off).
/// - `rec.disable_dmabuf = false` -> force_dmabuf = true (user opts in via
/// this recommendation; runtime turns DMA-BUF on).
pub fn write_recommendation(rec: &Recommendation) -> Result<(), Vec<String>> {
fn write_recommendation(rec: &Recommendation) -> Result<(), Vec<String>> {
let mut errors = Vec::new();
match GraphicsSettingsStore::new() {
@@ -4,7 +4,6 @@
//! tool); this module is just the Tauri surface that the Graphics tab uses
//! to render the "Detected / Recommended" banner.
use crate::autoconfig_graphics::write_recommendation;
use qbz_app::graphics_autoconfig::{
compute_recommendation, detect_environment, Environment, Recommendation,
};
@@ -34,21 +33,6 @@ pub fn v2_get_graphics_recommendation() -> GraphicsRecommendationPayload {
}
}
/// Write the current recommendation to the persistence layer.
/// `force_dmabuf` is derived from `disable_dmabuf` per the 1.2.13
/// opt-in semantics (see `write_recommendation` in autoconfig_graphics).
/// Returns the list of per-field errors so the UI can surface them.
/// Empty `Ok(Vec)` means "everything written, restart required".
#[tauri::command]
pub fn v2_apply_graphics_recommendation() -> Result<Vec<String>, Vec<String>> {
let environment = detect_environment();
let recommendation = compute_recommendation(&environment);
match write_recommendation(&recommendation) {
Ok(()) => Ok(Vec::new()),
Err(errors) => Err(errors),
}
}
/// Payload for the rendering-GPU dropdown in Settings > Graphics.
/// `gpus` is the full list (physical PCI devices intersected with
/// available EGL vendor stacks, plus the Software fallback).
-1
View File
@@ -1661,7 +1661,6 @@ pub fn run(qconnect_cli_override: Option<bool>) {
commands_v2::v2_set_preferred_gpu,
commands_v2::v2_set_nvidia_compat_mode,
commands_v2::v2_get_graphics_recommendation,
commands_v2::v2_apply_graphics_recommendation,
commands_v2::v2_enumerate_gpus,
commands_v2::v2_mark_boot_succeeded,
commands_v2::v2_get_crash_flags,
+31 -49
View File
@@ -440,10 +440,10 @@
// Graphics recommendation surfaced in the Graphics tab. Populated on
// mount via v2_get_graphics_recommendation (matrix lives in
// autoconfig_graphics.rs). The banner fires only when at least one
// recommended value differs from the currently persisted setting; the
// "Apply" button writes the entire recommendation via
// v2_apply_graphics_recommendation.
// autoconfig_graphics.rs). The banner is advisory-only: it fires when
// at least one recommended value differs from the currently persisted
// setting and tells the user what to change. There is no Apply button
// by design - the user toggles the real settings manually.
type GraphicsRecommendation = {
environment: {
display_server: string;
@@ -4248,6 +4248,11 @@
}
const preferredGpuOptions = $derived.by(() => {
// On a hybrid NVIDIA + iGPU host, the iGPU is the recommended pick:
// WebKit composites there and the NVIDIA card stays idle. Mark it so
// the user does not leave the dropdown on the ambiguous Auto.
const env = graphicsRecommendation?.environment;
const igpuRecommended = !!env && env.gpu_nvidia && (env.gpu_intel || env.gpu_amd);
const autoTarget = autoResolvedGpuId
? detectedGpus.find((g) => g.id === autoResolvedGpuId)
: null;
@@ -4262,7 +4267,13 @@
for (const g of detectedGpus) {
if (!g.is_usable) continue;
if (g.kind === 'integrated' && !hasIntegrated) {
opts.push({ value: 'integrated', label: $t('settings.graphics.gpu.integrated', { values: { name: g.name } }) });
const integratedLabel = $t('settings.graphics.gpu.integrated', { values: { name: g.name } });
opts.push({
value: 'integrated',
label: igpuRecommended
? `${integratedLabel} ${$t('settings.graphics.gpu.recommendedSuffix')}`
: integratedLabel,
});
hasIntegrated = true;
}
if (g.kind === 'discrete' && !hasDiscrete) {
@@ -4310,32 +4321,21 @@
return recommendationSignature(graphicsRecommendation) !== dismissedRecommendationSignature;
});
async function handleApplyGraphicsRecommendation() {
try {
const errors = await invoke<string[]>('v2_apply_graphics_recommendation');
if (errors && errors.length > 0) {
console.error('Failed to apply some graphics settings:', errors);
showToast(errors.join('; '), 'error');
return;
}
// Refresh local state from DB so the toggles snap to the new values
const gs = await invoke<any>('v2_get_graphics_settings');
forceX11 = gs.force_x11;
gskRenderer = gs.gsk_renderer || '';
hardwareAcceleration = gs.hardware_acceleration;
const ds = await invoke<any>('v2_get_developer_settings');
forceDmabuf = ds.force_dmabuf;
// Banner will hide naturally because diff is now false. Clear the
// dismiss flag too so the next environment change re-evaluates
// cleanly without a stale signature blocking the new banner.
dismissedRecommendationSignature = null;
removeUserItem(RECOMMENDATION_DISMISS_KEY);
showToast($t('settings.graphics.recommendation.applied'), 'success');
} catch (err) {
console.error('Failed to apply graphics recommendation:', err);
showToast(String(err), 'error');
// DMA-BUF help text is GPU-aware. The instability warning only
// applies to NVIDIA-only systems; non-NVIDIA and hybrid setups (the
// iGPU composites) can enable it safely. Returns an i18n key so $t()
// stays in the template, not inside $derived (CSS-extraction rule).
const forceDmabufDescKey = $derived.by(() => {
const env = graphicsRecommendation?.environment;
if (!env) return 'settings.graphics.forceDmabufDesc';
if (env.gpu_nvidia && (env.gpu_intel || env.gpu_amd)) {
return 'settings.graphics.forceDmabufDescHybrid';
}
}
if (env.gpu_nvidia) {
return 'settings.graphics.forceDmabufDescNvidiaOnly';
}
return 'settings.graphics.forceDmabufDescSafe';
});
function handleDismissRecommendation() {
if (!graphicsRecommendation) return;
@@ -5547,9 +5547,6 @@
{/if}
</div>
<div class="recommendation-actions">
<button class="primary-btn" onclick={handleApplyGraphicsRecommendation}>
{$t('settings.graphics.recommendation.apply')}
</button>
<button class="secondary-btn" onclick={handleDismissRecommendation}>
{$t('settings.graphics.recommendation.dismiss')}
</button>
@@ -5663,7 +5660,7 @@
<div class="setting-row">
<div class="setting-info">
<span class="setting-label">{$t('settings.graphics.forceDmabuf')}</span>
<span class="setting-desc">{$t('settings.graphics.forceDmabufDesc')}</span>
<span class="setting-desc">{$t(forceDmabufDescKey)}</span>
</div>
<Toggle enabled={forceDmabuf} onchange={(v) => handleForceDmabufChange(v)} />
</div>
@@ -7581,21 +7578,6 @@ flatpak override --user --filesystem=/home/USUARIO/Música com.blitzfc.qbz</pre>
filter: brightness(1.15);
}
.primary-btn {
background: var(--accent-primary, #7c3aed);
color: var(--btn-primary-text, #fff);
border: 1px solid transparent;
border-radius: 6px;
padding: 6px 14px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
}
.primary-btn:hover {
filter: brightness(1.1);
}
.secondary-btn {
background: transparent;
color: var(--text-secondary);
+4 -2
View File
@@ -2792,6 +2792,9 @@
"hardwareAccelerationDesc": "GPU-Rendering aktivieren. Deaktivieren erzwingt Software-Rendering (nur CPU). Deaktivieren bei Abstuerzen oder visuellen Artefakten.",
"forceDmabuf": "DMA-BUF-Renderer erzwingen",
"forceDmabufDesc": "DMA-BUF-Pufferfreigabe mit dem Compositor erzwingen. Kann die Leistung verbessern, aber auf manchen Systemen abstuerzen (besonders NVIDIA + Wayland).",
"forceDmabufDescSafe": "Aktiviert die DMA-BUF-Pufferfreigabe mit dem Compositor für flüssigeres Rendering. Auf deiner Hardware unbedenklich. Neustart erforderlich.",
"forceDmabufDescHybrid": "Deine integrierte GPU übernimmt das Rendering, daher ist DMA-BUF hier unbedenklich. Verbessert die Render-Flüssigkeit. Neustart erforderlich.",
"forceDmabufDescNvidiaOnly": "Auf reinen NVIDIA-Systemen nicht empfohlen — DMA-BUF kann Rendering-Instabilität verursachen. Neustart erforderlich.",
"forceX11": "X11-Backend erzwingen (Wayland)",
"forceX11Desc": "XWayland statt nativem Wayland verwenden. Empfohlen fuer NVIDIA-GPUs mit Wayland-Abstuerzen.",
"gdkScale": "Anzeigeskalierung (XWayland)",
@@ -2826,8 +2829,6 @@
"recommendation": {
"title": "Empfohlen für dein System",
"detected": "Erkannt",
"apply": "Übernehmen",
"applied": "Konfiguration übernommen. QBZ neu starten, damit es wirksam wird.",
"dismiss": "Verwerfen",
"redetect": "Empfohlene Einstellungen erkennen",
"noChanges": "Die Einstellungen entsprechen bereits der Empfehlung für dieses System."
@@ -2839,6 +2840,7 @@
"auto": "Automatisch (System-Standard)",
"autoWithTarget": "Automatisch ({name})",
"integrated": "Integriert — {name}",
"recommendedSuffix": "(empfohlen)",
"discrete": "Dediziert — {name}",
"software": "Software (CPU, llvmpipe)"
},
+4 -2
View File
@@ -2798,6 +2798,9 @@
"hardwareAccelerationDesc": "Enable GPU rendering. Disabling forces software rendering (CPU only). Turn off if you experience crashes or visual artifacts.",
"forceDmabuf": "Force DMA-BUF Renderer",
"forceDmabufDesc": "Force DMA-BUF buffer sharing with compositor. May improve performance but can crash on some systems (especially NVIDIA + Wayland).",
"forceDmabufDescSafe": "Enables DMA-BUF buffer sharing with the compositor for smoother rendering. Safe on your hardware. Restart required.",
"forceDmabufDescHybrid": "Your integrated GPU handles rendering, so DMA-BUF is safe to enable here. Improves rendering smoothness. Restart required.",
"forceDmabufDescNvidiaOnly": "Not recommended on NVIDIA-only systems — DMA-BUF can cause rendering instability. Restart required.",
"forceX11": "Force X11 backend (Wayland)",
"forceX11Desc": "Use XWayland instead of native Wayland. Recommended for NVIDIA GPUs that crash on Wayland.",
"gdkScale": "Display scale (XWayland)",
@@ -2832,8 +2835,6 @@
"recommendation": {
"title": "Recommended for your system",
"detected": "Detected",
"apply": "Apply",
"applied": "Configuration applied. Restart QBZ to take effect.",
"dismiss": "Dismiss",
"redetect": "Detect recommended settings",
"noChanges": "Settings already match the recommendation for this system."
@@ -2845,6 +2846,7 @@
"auto": "Auto (system default)",
"autoWithTarget": "Auto ({name})",
"integrated": "Integrated — {name}",
"recommendedSuffix": "(recommended)",
"discrete": "Discrete — {name}",
"software": "Software (CPU, llvmpipe)"
},
+4 -2
View File
@@ -2798,6 +2798,9 @@
"hardwareAccelerationDesc": "Habilitar renderizado GPU. Desactivar fuerza renderizado por software (solo CPU). Desactivar si experimentas crashes o artefactos visuales.",
"forceDmabuf": "Forzar Renderizador DMA-BUF",
"forceDmabufDesc": "Forzar comparticion de buffers DMA-BUF con el compositor. Puede mejorar rendimiento pero puede crashear en algunos sistemas (especialmente NVIDIA + Wayland).",
"forceDmabufDescSafe": "Activa el uso compartido de buffers DMA-BUF con el compositor para un render más fluido. Es seguro en tu hardware. Requiere reiniciar.",
"forceDmabufDescHybrid": "Tu GPU integrada se encarga del render, así que aquí es seguro activar DMA-BUF. Mejora la fluidez del render. Requiere reiniciar.",
"forceDmabufDescNvidiaOnly": "No se recomienda en sistemas solo con NVIDIA: DMA-BUF puede causar inestabilidad de render. Requiere reiniciar.",
"forceX11": "Forzar X11 (Wayland)",
"forceX11Desc": "Usar XWayland en lugar de Wayland nativo. Recomendado para GPUs NVIDIA con crashes en Wayland.",
"gdkScale": "Escala de pantalla (XWayland)",
@@ -2832,8 +2835,6 @@
"recommendation": {
"title": "Recomendado para tu sistema",
"detected": "Detectado",
"apply": "Aplicar",
"applied": "Configuracion aplicada. Reinicia QBZ para que surta efecto.",
"dismiss": "Descartar",
"redetect": "Detectar configuracion recomendada",
"noChanges": "La configuracion actual ya coincide con la recomendacion para este sistema."
@@ -2845,6 +2846,7 @@
"auto": "Auto (predeterminado del sistema)",
"autoWithTarget": "Auto ({name})",
"integrated": "Integrada — {name}",
"recommendedSuffix": "(recomendada)",
"discrete": "Dedicada — {name}",
"software": "Software (CPU, llvmpipe)"
},
+4 -2
View File
@@ -2792,6 +2792,9 @@
"hardwareAccelerationDesc": "Activer le rendu GPU. Désactiver force le rendu logiciel (CPU uniquement). Désactiver en cas de crashes ou d'artéfacts visuels.",
"forceDmabuf": "Forcer le rendu DMA-BUF",
"forceDmabufDesc": "Forcer le partage de tampons DMA-BUF avec le compositeur. Peut améliorer les performances mais peut planter sur certains systèmes (en particulier NVIDIA + Wayland).",
"forceDmabufDescSafe": "Active le partage de tampons DMA-BUF avec le compositeur pour un rendu plus fluide. Sans risque sur votre matériel. Redémarrage requis.",
"forceDmabufDescHybrid": "Votre GPU intégré gère le rendu, donc DMA-BUF peut être activé ici sans risque. Améliore la fluidité du rendu. Redémarrage requis.",
"forceDmabufDescNvidiaOnly": "Déconseillé sur les systèmes NVIDIA uniquement — DMA-BUF peut provoquer une instabilité du rendu. Redémarrage requis.",
"forceX11": "Forcer le backend X11 (Wayland)",
"forceX11Desc": "Utiliser XWayland au lieu du Wayland natif. Recommandé pour les GPU NVIDIA avec des crashes sous Wayland.",
"gdkScale": "Échelle d'affichage (XWayland)",
@@ -2826,8 +2829,6 @@
"recommendation": {
"title": "Recommandé pour votre système",
"detected": "Détecté",
"apply": "Appliquer",
"applied": "Configuration appliquée. Redémarrez QBZ pour qu'elle prenne effet.",
"dismiss": "Ignorer",
"redetect": "Détecter les paramètres recommandés",
"noChanges": "Les paramètres correspondent déjà à la recommandation pour ce système."
@@ -2839,6 +2840,7 @@
"auto": "Auto (par défaut)",
"autoWithTarget": "Auto ({name})",
"integrated": "Intégré — {name}",
"recommendedSuffix": "(recommandé)",
"discrete": "Dédié — {name}",
"software": "Logiciel (CPU, llvmpipe)"
},
+4 -2
View File
@@ -2792,6 +2792,9 @@
"hardwareAccelerationDesc": "Ativar renderização por GPU. Desativar força renderização por software (apenas CPU). Desative se tiver travamentos ou artefatos visuais.",
"forceDmabuf": "Forçar Renderizador DMA-BUF",
"forceDmabufDesc": "Forçar compartilhamento de buffer DMA-BUF com o compositor. Pode melhorar o desempenho, mas pode travar em alguns sistemas (especialmente NVIDIA + Wayland).",
"forceDmabufDescSafe": "Ativa o compartilhamento de buffers DMA-BUF com o compositor para uma renderização mais fluida. Seguro no seu hardware. Reinício necessário.",
"forceDmabufDescHybrid": "Sua GPU integrada faz a renderização, então é seguro ativar o DMA-BUF aqui. Melhora a fluidez da renderização. Reinício necessário.",
"forceDmabufDescNvidiaOnly": "Não recomendado em sistemas apenas com NVIDIA — o DMA-BUF pode causar instabilidade de renderização. Reinício necessário.",
"forceX11": "Forçar backend X11 (Wayland)",
"forceX11Desc": "Usar XWayland em vez do Wayland nativo. Recomendado para GPUs NVIDIA que travam no Wayland.",
"gdkScale": "Escala de exibição (XWayland)",
@@ -2826,8 +2829,6 @@
"recommendation": {
"title": "Recomendado para o seu sistema",
"detected": "Detectado",
"apply": "Aplicar",
"applied": "Configuracao aplicada. Reinicie o QBZ para que tenha efeito.",
"dismiss": "Descartar",
"redetect": "Detectar configuracoes recomendadas",
"noChanges": "As configuracoes ja correspondem a recomendacao para este sistema."
@@ -2839,6 +2840,7 @@
"auto": "Auto (padrao do sistema)",
"autoWithTarget": "Auto ({name})",
"integrated": "Integrada — {name}",
"recommendedSuffix": "(recomendada)",
"discrete": "Dedicada — {name}",
"software": "Software (CPU, llvmpipe)"
},