pragma Singleton // The GPUs that can report utilisation. // // The vitals readout needs one specific sysfs file, and card numbering is // neither stable across machines nor meaningful to a person -- this machine has // two amdgpu cards, one discrete and one integrated, and picking a number // blindly measures whichever the kernel enumerated first. // // Enumerated on demand rather than polled: hardware does not appear while you // are looking at a settings page. import Quickshell import Quickshell.Io import QtQuick import qs.config Singleton { id: root readonly property string helperPath: Quickshell.shellDir + "/scripts/panama-gpus" // [{ card, path, name, busy }] property var devices: [] property bool scanning: false property string lastError: "" readonly property string selectedPath: DesktopPreferences.get("gpuBusyPath") readonly property var selected: root.devices.find(device => device.path === root.selectedPath) ?? null // True when a GPU is stored that this machine does not have -- after moving // the settings file between machines, say. readonly property bool selectionMissing: root.devices.length > 0 && root.selected === null Process { id: scan command: [root.helperPath] stdout: StdioCollector { onStreamFinished: { try { const parsed = JSON.parse(this.text); root.devices = Array.isArray(parsed) ? parsed : []; root.lastError = ""; } catch (error) { root.devices = []; root.lastError = "The graphics devices could not be read."; } root.scanning = false; } } onExited: (exitCode, exitStatus) => { root.scanning = false; if (exitCode !== 0) root.lastError = "The graphics devices could not be read."; } } Component.onCompleted: root.refresh() function refresh(): void { if (scan.running) return; root.scanning = true; scan.running = true; } // Only a path this machine actually reported is accepted, so a hand-edited // settings file cannot point the readout at an arbitrary file. function select(path: string): bool { if (!root.devices.some(device => device.path === path)) { root.lastError = "That graphics device is not present."; return false; } if (!DesktopPreferences.set("gpuBusyPath", path)) { root.lastError = "That graphics device could not be saved."; return false; } root.lastError = ""; return true; } // "AMD ... [Radeon RX 7700 XT / 7800 XT] (rev c8)" is what lspci gives; the // bracketed marketing name is the part anyone recognizes. function shortName(name: string): string { const bracketed = String(name).match(/\[([^\]]+)\]\s*(?:\(rev[^)]*\))?\s*$/); return bracketed ? bracketed[1] : String(name).replace(/\s*\(rev[^)]*\)\s*$/, ""); } }