From d5a2c380ab5b1e70972a62659b4d8db2828c358c Mon Sep 17 00:00:00 2001 From: jokul Date: Tue, 14 Jul 2026 00:19:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0GPU=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E6=A3=80=E6=B5=8B=E5=92=8C=E4=B8=BB=E5=89=AF?= =?UTF-8?q?=E6=98=BE=E6=A0=87=E8=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - C++后端:GpuInfo添加isPrimary字段,读取boot_vga判断主副显 - C++后端:detectGpuMode()检测PRIME/Bumblebee/Solo/Hybrid模式 - C++后端:新增gpuMode和gpuPrimary属性 - QML前端:卡片显示绿色主显标签(boot_vga=1的GPU) - QML前端:弹窗显示GPU模式标签(PRIME等)和帮助图标 - 帮助图标悬停显示模式说明文字 - 翻译更新:主显/主顯 + 四种模式的中文说明 --- graphicsdriverapplet.cpp | 66 +++++++++++++ graphicsdriverapplet.h | 10 ++ package/driverview.qml | 96 +++++++++++++++++-- .../org.deepin.ds.graphics-driver_zh_CN.ts | 25 +++++ .../org.deepin.ds.graphics-driver_zh_TW.ts | 25 +++++ 5 files changed, 216 insertions(+), 6 deletions(-) diff --git a/graphicsdriverapplet.cpp b/graphicsdriverapplet.cpp index 34cdc45..76fcfd8 100644 --- a/graphicsdriverapplet.cpp +++ b/graphicsdriverapplet.cpp @@ -63,6 +63,16 @@ QStringList GraphicsDriverApplet::gpuStats() const return m_gpuStats; } +QString GraphicsDriverApplet::gpuMode() const +{ + return m_gpuMode; +} + +QStringList GraphicsDriverApplet::gpuPrimary() const +{ + return m_gpuPrimary; +} + void GraphicsDriverApplet::refreshDeviceInfo() { detectGpus(); @@ -87,6 +97,7 @@ void GraphicsDriverApplet::detectGpus() GpuInfo gpu; // 初始化统计字段 gpu.drmCard = -1; + gpu.isPrimary = false; gpu.temperature = -1; gpu.gpuUsage = -1; gpu.memUsage = -1; @@ -119,6 +130,12 @@ void GraphicsDriverApplet::detectGpus() // 查找 DRM 卡号 gpu.drmCard = findDrmCard(gpu.pciId); + // 读取 boot_vga 判断主副显 + QFile bootVgaFile("/sys/bus/pci/devices/0000:" + gpu.pciId + "/boot_vga"); + if (bootVgaFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + gpu.isPrimary = QTextStream(&bootVgaFile).readAll().trimmed() == "1"; + } + m_gpus.append(gpu); } } @@ -146,16 +163,27 @@ void GraphicsDriverApplet::detectGpus() m_gpuSummary = parts.join(" | "); m_ready = !m_gpus.isEmpty(); + // 生成主副显标识 + m_gpuPrimary.clear(); + for (const GpuInfo &gpu : m_gpus) { + m_gpuPrimary << (gpu.isPrimary ? "true" : "false"); + } + qDebug() << "Detected GPUs:" << m_deviceInfo; qDebug() << "Current drivers:" << m_currentDriver; emit deviceInfoChanged(); emit currentDriverChanged(); emit gpuSummaryChanged(); + emit gpuStatsChanged(); + emit gpuPrimaryChanged(); emit readyChanged(); // 读取实时统计信息 readGpuStats(); + + // 检测 GPU 切换模式 + detectGpuMode(); } QStringList GraphicsDriverApplet::runCommand(const QString &cmd, const QStringList &args) @@ -238,6 +266,44 @@ QString GraphicsDriverApplet::readDriverVersion(const QString &driverName) return QString(); } +void GraphicsDriverApplet::detectGpuMode() +{ + // 单 GPU + if (m_gpus.size() <= 1) { + m_gpuMode = "Solo"; + emit gpuModeChanged(); + return; + } + + // 多 GPU:检测 PRIME / Bumblebee + // PRIME: nvidia-drm-outputclass.conf 存在 + if (QFile::exists("/usr/share/X11/xorg.conf.d/nvidia-drm-outputclass.conf") || + QFile::exists("/etc/X11/xorg.conf.d/70-nvidia.conf")) { + m_gpuMode = "PRIME"; + emit gpuModeChanged(); + return; + } + + // Bumblebee: 检查 bumblebeed 服务 + QStringList lsmod = runCommand("lsmod", {}); + bool bumblebeeLoaded = false; + for (const QString &line : lsmod) { + if (line.contains("bumblebee", Qt::CaseInsensitive)) { + bumblebeeLoaded = true; + break; + } + } + if (bumblebeeLoaded || QFile::exists("/usr/sbin/bumblebeed")) { + m_gpuMode = "Bumblebee"; + emit gpuModeChanged(); + return; + } + + // 多 GPU 但无已知切换方案 + m_gpuMode = "Hybrid"; + emit gpuModeChanged(); +} + int GraphicsDriverApplet::findDrmCard(const QString &pciId) { // 扫描 /sys/bus/pci/devices/0000:XX:XX.X/drm/ 目录,找到 cardN 条目 diff --git a/graphicsdriverapplet.h b/graphicsdriverapplet.h index 8c67d34..f483e69 100644 --- a/graphicsdriverapplet.h +++ b/graphicsdriverapplet.h @@ -18,6 +18,7 @@ struct GpuInfo { QString driverVersion; // 驱动版本 QString pciId; // PCI ID,如 "01:00.0" int drmCard; // DRM 卡号,如 0, 1(-1 表示未找到) + bool isPrimary; // 是否为主显卡(boot_vga=1) // 实时统计 int temperature; // 温度 (°C),-1 表示不可用 @@ -35,6 +36,8 @@ class GraphicsDriverApplet : public DApplet Q_PROPERTY(QString currentDriver READ currentDriver NOTIFY currentDriverChanged) Q_PROPERTY(QString gpuSummary READ gpuSummary NOTIFY gpuSummaryChanged) Q_PROPERTY(QStringList gpuStats READ gpuStats NOTIFY gpuStatsChanged) + Q_PROPERTY(QString gpuMode READ gpuMode NOTIFY gpuModeChanged) + Q_PROPERTY(QStringList gpuPrimary READ gpuPrimary NOTIFY gpuPrimaryChanged) Q_PROPERTY(bool ready READ ready NOTIFY readyChanged) public: @@ -48,6 +51,8 @@ public: QString currentDriver() const; QString gpuSummary() const; QStringList gpuStats() const; + QString gpuMode() const; + QStringList gpuPrimary() const; bool ready() const; Q_INVOKABLE void refreshDeviceInfo(); @@ -58,11 +63,14 @@ signals: void currentDriverChanged(); void gpuSummaryChanged(); void gpuStatsChanged(); + void gpuModeChanged(); + void gpuPrimaryChanged(); void readyChanged(); private: void detectGpus(); void readGpuStats(); + void detectGpuMode(); static int findDrmCard(const QString &pciId); static QStringList runCommand(const QString &cmd, const QStringList &args); static QString parseGpuName(const QString &line); @@ -73,6 +81,8 @@ private: QString m_currentDriver; QString m_gpuSummary; QStringList m_gpuStats; + QString m_gpuMode; + QStringList m_gpuPrimary; bool m_ready; }; diff --git a/package/driverview.qml b/package/driverview.qml index 1945943..a369da3 100644 --- a/package/driverview.qml +++ b/package/driverview.qml @@ -23,6 +23,7 @@ AppletItem { readonly property string gpuSummary: applet ? (applet.gpuSummary || qsTr("No GPU detected")) : qsTr("No GPU detected") readonly property string deviceInfo: applet ? (applet.deviceInfo || qsTr("Unknown")) : qsTr("Unknown") readonly property string currentDriver: applet ? (applet.currentDriver || qsTr("Unknown")) : qsTr("Unknown") + readonly property string gpuMode: applet ? (applet.gpuMode || "") : "" property Palette basePalette: DockPalette.iconTextPalette readonly property color primaryText: Qt.rgba(basePalette.r, basePalette.g, basePalette.b, 0.9) @@ -189,6 +190,65 @@ AppletItem { Layout.fillWidth: true elide: Text.ElideRight } + + // GPU 模式标签 + Rectangle { + visible: root.gpuMode.length > 0 + width: modeText.implicitWidth + 16 + height: 20 + color: root.accentBlueLight + radius: 10 + + Text { + id: modeText + anchors.centerIn: parent + text: root.gpuMode + font.pixelSize: 11 + font.bold: true + color: root.accentBlue + } + } + + // 帮助图标 + Item { + visible: root.gpuMode.length > 0 + width: 16 + height: 16 + + Rectangle { + anchors.fill: parent + radius: width / 2 + color: helpHover.hovered ? root.accentBlue : root.tertiaryText + } + + Text { + anchors.centerIn: parent + text: "?" + font.pixelSize: 10 + font.bold: true + color: "white" + } + + HoverHandler { + id: helpHover + } + + ToolTip { + visible: helpHover.hovered + delay: 200 + text: { + if (root.gpuMode === "PRIME") + return qsTr("PRIME mode: the integrated GPU handles display, the discrete GPU renders on demand. 3D apps use PRIME Render Offload to invoke the discrete GPU.") + if (root.gpuMode === "Bumblebee") + return qsTr("Bumblebee mode: a legacy dual-GPU solution, now deprecated.") + if (root.gpuMode === "Solo") + return qsTr("Solo mode: only one GPU detected.") + if (root.gpuMode === "Hybrid") + return qsTr("Hybrid mode: dual GPU detected, but no known switching solution found.") + return "" + } + } + } } // GPU 列表区域 @@ -220,6 +280,7 @@ AppletItem { border.color: root.cardBorder property string statsLine: root.applet && root.applet.gpuStats ? (root.applet.gpuStats[index] || "") : "" + property bool isPrimaryGpu: root.applet && root.applet.gpuPrimary ? (root.applet.gpuPrimary[index] === "true") : false property string tempStr: { var parts = statsLine.split("|") var temp = parts[0] @@ -300,13 +361,36 @@ AppletItem { spacing: 4 Layout.fillWidth: true - Text { - text: parseGpuName(modelData) - font.pixelSize: 13 - font.bold: true - color: root.primaryText + RowLayout { + spacing: 6 Layout.fillWidth: true - elide: Text.ElideRight + + Text { + text: parseGpuName(modelData) + font.pixelSize: 13 + font.bold: true + color: root.primaryText + Layout.fillWidth: true + elide: Text.ElideRight + } + + // 主/副显标识 + Rectangle { + visible: gpuCard.isPrimaryGpu + width: badgeText.implicitWidth + 12 + height: 16 + color: Qt.rgba(22/255, 163/255, 74/255, 0.15) + radius: 8 + + Text { + id: badgeText + anchors.centerIn: parent + text: qsTr("Primary") + font.pixelSize: 10 + font.bold: true + color: Qt.rgba(22/255, 163/255, 74/255, 1) + } + } } Text { diff --git a/translations/org.deepin.ds.graphics-driver_zh_CN.ts b/translations/org.deepin.ds.graphics-driver_zh_CN.ts index c9d185e..118c9a1 100644 --- a/translations/org.deepin.ds.graphics-driver_zh_CN.ts +++ b/translations/org.deepin.ds.graphics-driver_zh_CN.ts @@ -43,5 +43,30 @@ Version: 版本号: + + + Primary + 主显 + + + + PRIME mode: the integrated GPU handles display, the discrete GPU renders on demand. 3D apps use PRIME Render Offload to invoke the discrete GPU. + PRIME 模式:核显负责日常显示,独显按需渲染。运行 3D 应用时通过 PRIME Render Offload 调用独显。 + + + + Bumblebee mode: a legacy dual-GPU solution, now deprecated. + Bumblebee 模式:旧版双 GPU 方案,已淘汰。 + + + + Solo mode: only one GPU detected. + Solo 模式:仅检测到一块 GPU。 + + + + Hybrid mode: dual GPU detected, but no known switching solution found. + Hybrid 模式:检测到双 GPU,但未发现已知切换方案。 + diff --git a/translations/org.deepin.ds.graphics-driver_zh_TW.ts b/translations/org.deepin.ds.graphics-driver_zh_TW.ts index 4020ff1..4d2a205 100644 --- a/translations/org.deepin.ds.graphics-driver_zh_TW.ts +++ b/translations/org.deepin.ds.graphics-driver_zh_TW.ts @@ -43,5 +43,30 @@ Version: 版本號: + + + Primary + 主顯 + + + + PRIME mode: the integrated GPU handles display, the discrete GPU renders on demand. 3D apps use PRIME Render Offload to invoke the discrete GPU. + PRIME 模式:核顯負責日常顯示,獨顯按需渲染。運行 3D 應用時通過 PRIME Render Offload 調用獨顯。 + + + + Bumblebee mode: a legacy dual-GPU solution, now deprecated. + Bumblebee 模式:舊版雙 GPU 方案,已淘汰。 + + + + Solo mode: only one GPU detected. + Solo 模式:僅偵測到一塊 GPU。 + + + + Hybrid mode: dual GPU detected, but no known switching solution found. + Hybrid 模式:偵測到雙 GPU,但未發現已知切換方案。 +