From 82f0e027022fbf85e659bb1009739718551cef03 Mon Sep 17 00:00:00 2001 From: gongheng Date: Tue, 22 Jul 2025 17:02:10 +0800 Subject: [PATCH] feat: [GPU] Add logic to show GPU info. -- In some special computer, the GPU info not show. -- Add logic to show GPU info. pick from: https://github.com/linuxdeepin/deepin-devicemanager/commit/350c0a63c89cde2b3bb8aa521e59fd9ec5ec47e7 Log: add feature for GPU. Task: https://pms.uniontech.com/task-view-378987.html --- deepin-devicemanager-server/CMakeLists.txt | 1 + .../customgpuinfo/CMakeLists.txt | 24 ++++ .../customgpuinfo/main.cpp | 120 ++++++++++++++++++ .../src/loadinfo/deviceinterface.cpp | 29 +++++ .../src/loadinfo/deviceinterface.h | 2 + .../assets/org.deepin.devicemanager.json | 12 ++ .../src/DeviceManager/DeviceGpu.cpp | 9 ++ .../src/DeviceManager/DeviceGpu.h | 2 + .../src/GenerateDevice/CustomGenerator.cpp | 92 ++++++++++++++ .../src/GenerateDevice/CustomGenerator.h | 27 ++++ .../src/GenerateDevice/DBusInterface.cpp | 12 ++ .../src/GenerateDevice/DBusInterface.h | 2 + .../src/GenerateDevice/DeviceFactory.cpp | 3 + deepin-devicemanager/src/Tool/commontools.cpp | 57 +++++++++ deepin-devicemanager/src/Tool/commontools.h | 3 + deepin-devicemanager/src/commonfunction.cpp | 3 + deepin-devicemanager/src/commonfunction.h | 5 +- 17 files changed, 402 insertions(+), 1 deletion(-) create mode 100644 deepin-devicemanager-server/customgpuinfo/CMakeLists.txt create mode 100644 deepin-devicemanager-server/customgpuinfo/main.cpp create mode 100644 deepin-devicemanager/src/GenerateDevice/CustomGenerator.cpp create mode 100644 deepin-devicemanager/src/GenerateDevice/CustomGenerator.h diff --git a/deepin-devicemanager-server/CMakeLists.txt b/deepin-devicemanager-server/CMakeLists.txt index 242825003..c8b62421c 100644 --- a/deepin-devicemanager-server/CMakeLists.txt +++ b/deepin-devicemanager-server/CMakeLists.txt @@ -2,6 +2,7 @@ project(deepin-devicemanager-server C CXX) add_subdirectory(deepin-deviceinfo) add_subdirectory(deepin-devicecontrol) +add_subdirectory(customgpuinfo) #TEST-------------------------------------------------- if (CMAKE_COVERAGE_ARG STREQUAL "CMAKE_COVERAGE_ARG_ON") diff --git a/deepin-devicemanager-server/customgpuinfo/CMakeLists.txt b/deepin-devicemanager-server/customgpuinfo/CMakeLists.txt new file mode 100644 index 000000000..e9071dde6 --- /dev/null +++ b/deepin-devicemanager-server/customgpuinfo/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.7) + +set(BIN_NAME "customgpuinfo") + +find_package(Qt5 COMPONENTS Core REQUIRED) + +file(GLOB_RECURSE SRC + "${CMAKE_CURRENT_SOURCE_DIR}/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" +) + +add_executable(${BIN_NAME} + ${SRC} +) + +target_include_directories(${BIN_NAME} PUBLIC + Qt5::Core +) + +target_link_libraries(${BIN_NAME} PRIVATE + Qt5::Core +) + +install(TARGETS ${BIN_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/deepin-devicemanager) diff --git a/deepin-devicemanager-server/customgpuinfo/main.cpp b/deepin-devicemanager-server/customgpuinfo/main.cpp new file mode 100644 index 000000000..ec961e915 --- /dev/null +++ b/deepin-devicemanager-server/customgpuinfo/main.cpp @@ -0,0 +1,120 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include +#include +#include +#include + +#include + +// 名称("Name") 厂商("Vendor") 型号("Model") 显存("Graphics Memory") + +constexpr char kName[] { "Name" }; +constexpr char kVendor[] { "Vendor" }; +constexpr char kModel[] { "Model" }; +constexpr char kGraphicsMemory[] { "Graphics Memory" }; + +bool getGpuBaseInfo(QMap &mapInfo) +{ + QProcess process; + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + process.setProcessEnvironment(env); + process.start("/usr/bin/glxinfo", QStringList() << "-B"); + if (!process.waitForFinished(3000)) { + qCritical() << "Error executing glxinfo:" << process.errorString(); + return false; + } + + QString output = QString::fromLocal8Bit(process.readAllStandardOutput()); + QStringList lines = output.split('\n'); + QRegularExpression regex("^([^:]+):\\s*(.+)$"); + for (const QString &line : lines) { + QRegularExpressionMatch match = regex.match(line); + if (match.hasMatch()) { + QString key = match.captured(1).trimmed(); + QString value = match.captured(2).trimmed(); + if (key == "OpenGL renderer string") { + mapInfo.insert(kName, value); + mapInfo.insert(kModel, value); + } else if (key == "OpenGL vendor string") { + mapInfo.insert(kVendor, value); + } + } + } + + return true; +} + +bool getGpuMemInfoForFTDTM(QMap &mapInfo) +{ + const QString filePath = "/sys/kernel/debug/gc/meminfo"; + QString totalValue; + bool foundTotal = false; + + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qCritical() << "Error opening /sys/kernel/debug/gc/meminfo:" << file.errorString(); + return false; + } + + QString content = QString::fromUtf8(file.readAll()); + file.close(); + + if (content.isEmpty()) { + qCritical() << "Error: /sys/kernel/debug/gc/meminfo File is empty!"; + return false; + } + + QRegularExpression system0Regex(R"(POOL SYSTEM0:*(.*?)POOL VIRTUAL:)", + QRegularExpression::DotMatchesEverythingOption); + QRegularExpressionMatch system0Match = system0Regex.match(content); + + if (!system0Match.hasMatch()) { + qCritical() << "Error: Failed to find SYSTEM0 section"; + return false; + } + + QString system0Content = system0Match.captured(1); + QRegularExpression totalRegex(R"(Total\s*:\s*(\d+)\s+B)"); + QRegularExpressionMatch totalMatch = totalRegex.match(system0Content); + if (totalMatch.hasMatch()) { + totalValue = totalMatch.captured(1); + foundTotal = true; + } + + if (!foundTotal || totalValue.isEmpty()) { + qCritical() << "Error: Failed to find Total value in SYSTEM0 content"; + return false; + } + + bool ok; + quint64 memSize = totalValue.trimmed().toULong(&ok, 10); + if (ok && memSize >= 1048576) { + memSize /= 1048576; + auto curSize = memSize / 1024.0; + if (curSize >= 1) { + totalValue = QString::number(curSize) + "GB"; + } else { + totalValue = QString::number(memSize) + "MB"; + } + } + + mapInfo.insert(kGraphicsMemory, totalValue); + + return true; +} + +int main(int argc, char *argv[]) +{ + QMap mapInfo; + if (getGpuBaseInfo(mapInfo) && getGpuMemInfoForFTDTM(mapInfo)) { + for (auto it = mapInfo.begin(); it != mapInfo.end(); ++it) + std::cout << it.key().toStdString() << ": " << it.value().toStdString() << std::endl; + return 0; + } else { + return 1; + } +} diff --git a/deepin-devicemanager-server/deepin-deviceinfo/src/loadinfo/deviceinterface.cpp b/deepin-devicemanager-server/deepin-deviceinfo/src/loadinfo/deviceinterface.cpp index 38d79dd0c..f46caa6de 100644 --- a/deepin-devicemanager-server/deepin-deviceinfo/src/loadinfo/deviceinterface.cpp +++ b/deepin-devicemanager-server/deepin-deviceinfo/src/loadinfo/deviceinterface.cpp @@ -9,6 +9,8 @@ #include #include +#include +#include #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include #else @@ -88,3 +90,30 @@ void DeviceInterface::setMonitorDeviceFlag(bool flag) qCWarning(appLog) << "Failed to set monitor flag - parent MainJob not found"; } } + +QString DeviceInterface::getGpuInfoByCustom(const QString &cmd, const QStringList &arguments) +{ + static bool firstFlag = true; + static QString gpuinfo; + if (firstFlag) { + firstFlag = false; + + QProcess process; + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + if (arguments.size() > 1) { + env.insert("DISPLAY", arguments[0]); + env.insert("XAUTHORITY", arguments[1]); + } + process.setProcessEnvironment(env); + process.start(cmd, arguments); + if (!process.waitForFinished(4000)) { + qCritical() << QString("Error executing %1 :").arg(cmd) << process.errorString(); + return gpuinfo; + } + + if (process.exitCode() == 0) + gpuinfo = QString::fromLocal8Bit(process.readAllStandardOutput()); + } + + return gpuinfo; +} diff --git a/deepin-devicemanager-server/deepin-deviceinfo/src/loadinfo/deviceinterface.h b/deepin-devicemanager-server/deepin-deviceinfo/src/loadinfo/deviceinterface.h index f1ad9f158..01c656107 100644 --- a/deepin-devicemanager-server/deepin-deviceinfo/src/loadinfo/deviceinterface.h +++ b/deepin-devicemanager-server/deepin-deviceinfo/src/loadinfo/deviceinterface.h @@ -39,6 +39,8 @@ public slots: */ Q_SCRIPTABLE void setMonitorDeviceFlag(bool flag); + Q_SCRIPTABLE QString getGpuInfoByCustom(const QString &cmd, const QStringList &arguments); + private: bool getUserAuthorPasswd(); }; diff --git a/deepin-devicemanager/assets/org.deepin.devicemanager.json b/deepin-devicemanager/assets/org.deepin.devicemanager.json index ae30c0785..865d981a2 100644 --- a/deepin-devicemanager/assets/org.deepin.devicemanager.json +++ b/deepin-devicemanager/assets/org.deepin.devicemanager.json @@ -38,6 +38,18 @@ "description": "此配置项默认为无效的。如需让toml文件内容显示生效,请配置对应文件名。需保证操作者具备读取权限。", "permissions": "readwrite", "visibility": "private" + }, + "CommandToGetGPUInfo": { + "value": "", + "serial": 0, + "flags": [ + "global" + ], + "name": "Command to get GPU infomation", + "name[zh_CN]": "获取GPU信息的命令", + "description": "此配置项默认为空。如果specialComType==8,程序则启用此项配置。", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/deepin-devicemanager/src/DeviceManager/DeviceGpu.cpp b/deepin-devicemanager/src/DeviceManager/DeviceGpu.cpp index 4589e6caf..dfacb3f26 100644 --- a/deepin-devicemanager/src/DeviceManager/DeviceGpu.cpp +++ b/deepin-devicemanager/src/DeviceManager/DeviceGpu.cpp @@ -353,6 +353,15 @@ void DeviceGpu::setGpuInfo(const QMap &mapInfo) getOtherMapInfo(mapInfo); } +// 名称(Name) 厂商(Vendor) 型号(Model) 显存(Graphics Memory) +void DeviceGpu::setGpuInfoByCustom(const QMap &mapInfo) +{ + setAttribute(mapInfo, "Name", m_Name); + setAttribute(mapInfo, "Vendor", m_Vendor); + setAttribute(mapInfo, "Model", m_Model); + setAttribute(mapInfo, "Graphics Memory", m_GraphicsMemory); +} + const QString &DeviceGpu::name() const { // qCDebug(appLog) << "DeviceGpu::name called, returning: " << m_Name; diff --git a/deepin-devicemanager/src/DeviceManager/DeviceGpu.h b/deepin-devicemanager/src/DeviceManager/DeviceGpu.h index 46630a23e..857c4372b 100644 --- a/deepin-devicemanager/src/DeviceManager/DeviceGpu.h +++ b/deepin-devicemanager/src/DeviceManager/DeviceGpu.h @@ -56,6 +56,8 @@ class DeviceGpu: public DeviceBaseInfo */ void setGpuInfo(const QMap &mapInfo); + void setGpuInfoByCustom(const QMap &mapInfo); + /** * @brief name:获取名称属性值 * @return QString 名称属性值 diff --git a/deepin-devicemanager/src/GenerateDevice/CustomGenerator.cpp b/deepin-devicemanager/src/GenerateDevice/CustomGenerator.cpp new file mode 100644 index 000000000..046250a8b --- /dev/null +++ b/deepin-devicemanager/src/GenerateDevice/CustomGenerator.cpp @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "CustomGenerator.h" +#include "DeviceGpu.h" +#include "DBusInterface.h" +#include "commontools.h" + +#include +#include +#include +#include +#include + +CustomGenerator::CustomGenerator(QObject *parent) + : DeviceGenerator(parent) +{ +} + +void CustomGenerator::generatorGpuDevice() +{ + QString cmd = CommonTools::getGpuInfoCommandFromDConfig(); + if (cmd.isEmpty()) { + DeviceGenerator::generatorGpuDevice(); + return; + } + + QStringList arguments; + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + QString display = env.value("DISPLAY"); + QString xauthority = env.value("XAUTHORITY"); + if (display.isEmpty() || xauthority.isEmpty()) { + qWarning() << "DISPLAY or XAUTHORITY is not set!"; + } else { + arguments << display << xauthority; + } + + QString tmpGpuInfo; + DBusInterface::getInstance()->getGpuInfoByCustom(cmd, arguments, tmpGpuInfo); + if (tmpGpuInfo.isEmpty()) { + qCritical() << "Failed to get gpu info by commad " << cmd; + return; + } + + QList> gpuInfo; + QStringList mapBlocks = tmpGpuInfo.split("\n\n"); + for (const QString &block : mapBlocks) { + QMap infoMap; + QStringList lines = block.split("\n"); + for (const QString &line : lines) { + int colonIndex = line.indexOf(':'); + if (colonIndex != -1) { + QString key = line.left(colonIndex).trimmed(); + QString value = line.mid(colonIndex + 1).trimmed(); + infoMap.insert(key, value); + } + } + if (!infoMap.isEmpty()) + gpuInfo.push_back(infoMap); + } + + for(int i = 0; i < gpuInfo.count(); ++i) { + DeviceGpu *device = new DeviceGpu(); + device->setCanUninstall(false); + device->setForcedDisplay(true); + device->setGpuInfoByCustom(gpuInfo.at(i)); + DeviceManager::instance()->addGpuDevice(device); + } +} + +void CustomGenerator::generatorMonitorDevice() +{ + QString toDir = "/sys/class/drm"; + QDir toDir_(toDir); + + if (!toDir_.exists()) + return; + + QFileInfoList fileInfoList = toDir_.entryInfoList(QDir::NoFilter, QDir::Name); + foreach(QFileInfo fileInfo, fileInfoList) { + if (fileInfo.fileName() == "." || fileInfo.fileName() == ".." || !fileInfo.fileName().startsWith("card")) + continue; + + if (QFile::exists(fileInfo.filePath() + "/" + "edid")) { + QStringList allEDIDS_all; + allEDIDS_all.append(fileInfo.filePath() + "/" + "edid"); + QString interface = fileInfo.fileName().remove("card0-").remove("card1-").remove("card2-"); + CommonTools::parseEDID(allEDIDS_all, interface); + } + } +} diff --git a/deepin-devicemanager/src/GenerateDevice/CustomGenerator.h b/deepin-devicemanager/src/GenerateDevice/CustomGenerator.h new file mode 100644 index 000000000..9901d2ad4 --- /dev/null +++ b/deepin-devicemanager/src/GenerateDevice/CustomGenerator.h @@ -0,0 +1,27 @@ +// Copyright (C) 2025 Uniontech Software Technology Co.,Ltd. +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef CUSTOMGENERATOR_H +#define CUSTOMGENERATOR_H + +#include "DeviceGenerator.h" + +class CustomGenerator : public DeviceGenerator +{ +public: + CustomGenerator(QObject *parent = nullptr); + + /** + * @brief generatorGpuDevice:生成显卡信息 + */ + void generatorGpuDevice() override; + + /** + * @brief generatorMonitorDevice:生成显示设备信息 + */ + void generatorMonitorDevice() override; +}; + +#endif // CUSTOMGENERATOR_H diff --git a/deepin-devicemanager/src/GenerateDevice/DBusInterface.cpp b/deepin-devicemanager/src/GenerateDevice/DBusInterface.cpp index d0edd5f4c..d18b850e5 100644 --- a/deepin-devicemanager/src/GenerateDevice/DBusInterface.cpp +++ b/deepin-devicemanager/src/GenerateDevice/DBusInterface.cpp @@ -58,6 +58,18 @@ void DBusInterface::refreshInfo() mp_Iface->asyncCall("refreshInfo"); } +bool DBusInterface::getGpuInfoByCustom(const QString &cmd, const QStringList &arguments, QString &gpuInfo) +{ + QDBusReply replyList = mp_Iface->call("getGpuInfoByCustom", cmd, arguments); + if (replyList.isValid()) { + gpuInfo = replyList.value(); + return true; + } else { + qCritical() << "Error: failed to call dbus to get gpu memery info! "; + return false; + } +} + void DBusInterface::init() { qCDebug(appLog) << "DBusInterface::init start"; diff --git a/deepin-devicemanager/src/GenerateDevice/DBusInterface.h b/deepin-devicemanager/src/GenerateDevice/DBusInterface.h index a154a3377..c6a01898c 100644 --- a/deepin-devicemanager/src/GenerateDevice/DBusInterface.h +++ b/deepin-devicemanager/src/GenerateDevice/DBusInterface.h @@ -47,6 +47,8 @@ class DBusInterface */ void refreshInfo(); + bool getGpuInfoByCustom(const QString &cmd, const QStringList &arguments, QString &gpuInfo); + protected: DBusInterface(); diff --git a/deepin-devicemanager/src/GenerateDevice/DeviceFactory.cpp b/deepin-devicemanager/src/GenerateDevice/DeviceFactory.cpp index 42314b8ea..f5adec0f5 100644 --- a/deepin-devicemanager/src/GenerateDevice/DeviceFactory.cpp +++ b/deepin-devicemanager/src/GenerateDevice/DeviceFactory.cpp @@ -8,6 +8,7 @@ #include "MipsGenerator.h" #include "ArmGenerator.h" #include "HWGenerator.h" +#include "CustomGenerator.h" #include "commonfunction.h" #include "DDLog.h" @@ -52,6 +53,8 @@ DeviceGenerator *DeviceFactory::getDeviceGenerator() } else if (type == "PGUX") { qCDebug(appLog) << "DeviceFactory::getDeviceGenerator create PanguXGenerator"; generator = new HWGenerator(); + } else if (type == "CustomType") { + generator = new CustomGenerator(); } else { qCDebug(appLog) << "DeviceFactory::getDeviceGenerator create HWGenerator"; generator = new HWGenerator(); diff --git a/deepin-devicemanager/src/Tool/commontools.cpp b/deepin-devicemanager/src/Tool/commontools.cpp index af61d4c1a..cceca1ab0 100644 --- a/deepin-devicemanager/src/Tool/commontools.cpp +++ b/deepin-devicemanager/src/Tool/commontools.cpp @@ -4,6 +4,8 @@ #include "commontools.h" #include "DDLog.h" +#include "EDIDParser.h" +#include "DeviceMonitor.h" #include #include @@ -11,6 +13,8 @@ #include #include #include +#include +#include DWIDGET_USE_NAMESPACE using namespace DDLog; @@ -178,3 +182,56 @@ QString CommonTools::getBackupPath() qCDebug(appLog) << "Getting backup path"; return "/var/lib/deepin-devicemanager/"; } + +void CommonTools::parseEDID(const QStringList &allEDIDS, const QString &input) +{ + for (auto edid:allEDIDS) { + QProcess process; + process.start(QString("hexdump %1").arg(edid)); + process.waitForFinished(-1); + + QString deviceInfo = process.readAllStandardOutput(); + if (deviceInfo.isEmpty()) + continue; + + QString edidStr; + QStringList lines = deviceInfo.split("\n"); + for (auto line:lines) { + QStringList words = line.trimmed().split(" "); + if (words.size() != 9) + continue; + + words.removeAt(0); + QString l = words.join(""); + l.append("\n"); + edidStr.append(l); + } + + lines = edidStr.split("\n"); + if (lines.size() > 3){ + EDIDParser edidParser; + QString errorMsg; + edidParser.setEdid(edidStr,errorMsg,"\n", false); + + QMap mapInfo; + mapInfo.insert("Vendor",edidParser.vendor()); + mapInfo.insert("Model",edidParser.model()); + //mapInfo.insert("Date",edidParser.releaseDate()); + mapInfo.insert("Size",edidParser.screenSize()); + mapInfo.insert("Display Input",input); + + DeviceMonitor *device = new DeviceMonitor(); + device->setInfoFromEdid(mapInfo); + DeviceManager::instance()->addMonitor(device); + } + } +} + +QString CommonTools::getGpuInfoCommandFromDConfig() +{ + QString cmd; + DConfig *dconfig = DConfig::create("org.deepin.devicemanager","org.deepin.devicemanager"); + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("CommandToGetGPUInfo")) + cmd = dconfig->value("CommandToGetGPUInfo").toString(); + return cmd; +} diff --git a/deepin-devicemanager/src/Tool/commontools.h b/deepin-devicemanager/src/Tool/commontools.h index 6948c8f68..71b2bc890 100644 --- a/deepin-devicemanager/src/Tool/commontools.h +++ b/deepin-devicemanager/src/Tool/commontools.h @@ -78,6 +78,9 @@ class CommonTools : public QObject */ static QString getBackupPath(); + static void parseEDID(const QStringList &allEDIDS, const QString &input); + static QString getGpuInfoCommandFromDConfig(); + signals: public slots: diff --git a/deepin-devicemanager/src/commonfunction.cpp b/deepin-devicemanager/src/commonfunction.cpp index 74e007634..68c6e4d4e 100644 --- a/deepin-devicemanager/src/commonfunction.cpp +++ b/deepin-devicemanager/src/commonfunction.cpp @@ -168,6 +168,9 @@ QString Common::checkBoardVendorFlag() case PGUX: boardVendorKey = "PGUX"; break; + case kCustomType: + boardVendorKey = "CustomType"; + break; default: boardVendorKey = "PGUW"; break; diff --git a/deepin-devicemanager/src/commonfunction.h b/deepin-devicemanager/src/commonfunction.h index 4833ff8e5..1047de55c 100644 --- a/deepin-devicemanager/src/commonfunction.h +++ b/deepin-devicemanager/src/commonfunction.h @@ -22,7 +22,10 @@ class Common KLVV, KLVU, PGUV, - PGUX + PGUX, + kSpecialType6, + kSpecialType7, + kCustomType }; static QString getArch();