File indexing completed on 2024-04-28 03:55:31

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2023 Dave Vasilevsky <dave@vasilevsky.ca>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only
0006 */
0007 
0008 #include "gpudetection_p.h"
0009 
0010 #ifndef KIO_ANDROID_STUB
0011 #include <QDBusArgument>
0012 #include <QDBusConnection>
0013 #include <QDBusInterface>
0014 #include <QDBusReply>
0015 #include <QDBusVariant>
0016 #endif
0017 #include <QMap>
0018 #include <QString>
0019 
0020 #include <KProcess>
0021 
0022 static void checkGpu();
0023 // Returns true if switcheroo present
0024 static bool checkGpuWithSwitcheroo();
0025 static void checkGpuWithSolid();
0026 
0027 // TODO: GPUs are hot-swappable, watch for changes using dbus PropertiesChanged
0028 enum class GpuCheck {
0029     NotChecked,
0030     Present,
0031     Absent,
0032 };
0033 static GpuCheck s_gpuCheck = GpuCheck::NotChecked;
0034 static QProcessEnvironment s_gpuEnv;
0035 
0036 static void checkGpu()
0037 {
0038     if (s_gpuCheck == GpuCheck::NotChecked) {
0039         if (!checkGpuWithSwitcheroo()) {
0040             checkGpuWithSolid();
0041         }
0042     }
0043 }
0044 
0045 static bool checkGpuWithSwitcheroo()
0046 {
0047 #ifndef KIO_ANDROID_STUB
0048     QDBusInterface switcheroo(QStringLiteral("net.hadess.SwitcherooControl"),
0049                               QStringLiteral("/net/hadess/SwitcherooControl"),
0050                               QStringLiteral("org.freedesktop.DBus.Properties"),
0051                               QDBusConnection::systemBus());
0052     if (!switcheroo.isValid()) {
0053         return false;
0054     }
0055 
0056     QDBusReply<QDBusVariant> reply = switcheroo.call(QStringLiteral("Get"), QStringLiteral("net.hadess.SwitcherooControl"), QStringLiteral("GPUs"));
0057     if (!reply.isValid()) {
0058         return false;
0059     }
0060 
0061     QDBusArgument arg = qvariant_cast<QDBusArgument>(reply.value().variant());
0062     QList<QVariantMap> gpus;
0063     arg >> gpus;
0064 
0065     for (const auto &gpu : gpus) {
0066         bool defaultGpu = qvariant_cast<bool>(gpu[QStringLiteral("Default")]);
0067         if (!defaultGpu) {
0068             s_gpuCheck = GpuCheck::Present;
0069             QStringList envList = qvariant_cast<QStringList>(gpu[QStringLiteral("Environment")]);
0070             for (int i = 0; i + 1 < envList.size(); i += 2) {
0071                 s_gpuEnv.insert(envList[i], envList[i + 1]);
0072             }
0073             return true;
0074         }
0075     }
0076 #endif
0077 
0078     // No non-default GPU found
0079     s_gpuCheck = GpuCheck::Absent;
0080     return true;
0081 }
0082 
0083 static void checkGpuWithSolid()
0084 {
0085 #ifndef KIO_ANDROID_STUB
0086     // TODO: Consider moving this check into kio, instead of using Solid
0087     QDBusInterface iface(QStringLiteral("org.kde.Solid.PowerManagement"),
0088                          QStringLiteral("/org/kde/Solid/PowerManagement"),
0089                          QStringLiteral("org.kde.Solid.PowerManagement"),
0090                          QDBusConnection::sessionBus());
0091     if (iface.isValid()) {
0092         QDBusReply<bool> reply = iface.call(QStringLiteral("hasDualGpu"));
0093         if (reply.isValid() && reply.value()) {
0094             s_gpuCheck = GpuCheck::Present;
0095             s_gpuEnv.insert(QStringLiteral("DRI_PRIME"), QStringLiteral("1"));
0096             return;
0097         }
0098     }
0099 
0100     s_gpuCheck = GpuCheck::Absent;
0101 #endif
0102 }
0103 
0104 namespace KIO
0105 {
0106 
0107 bool hasDiscreteGpu()
0108 {
0109     checkGpu();
0110     return s_gpuCheck == GpuCheck::Present;
0111 }
0112 
0113 QProcessEnvironment discreteGpuEnvironment()
0114 {
0115     checkGpu();
0116     return s_gpuEnv;
0117 }
0118 
0119 }