1 | /* |
2 | This file is part of the KDE project |
3 | SPDX-FileCopyrightText: 2023 Dave Vasilevsky <dave@vasilevsky.ca> |
4 | |
5 | SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only |
6 | */ |
7 | |
8 | #include "gpudetection_p.h" |
9 | |
10 | #ifndef KIO_ANDROID_STUB |
11 | #include <QDBusArgument> |
12 | #include <QDBusConnection> |
13 | #include <QDBusInterface> |
14 | #include <QDBusReply> |
15 | #include <QDBusVariant> |
16 | #endif |
17 | #include <QMap> |
18 | #include <QString> |
19 | |
20 | #include <KProcess> |
21 | |
22 | static void checkGpu(); |
23 | // Returns true if switcheroo present |
24 | static bool checkGpuWithSwitcheroo(); |
25 | static void checkGpuWithSolid(); |
26 | |
27 | // TODO: GPUs are hot-swappable, watch for changes using dbus PropertiesChanged |
28 | enum class GpuCheck { |
29 | NotChecked, |
30 | Present, |
31 | Absent, |
32 | }; |
33 | static GpuCheck s_gpuCheck = GpuCheck::NotChecked; |
34 | static QProcessEnvironment s_gpuEnv; |
35 | |
36 | static void checkGpu() |
37 | { |
38 | if (s_gpuCheck == GpuCheck::NotChecked) { |
39 | if (!checkGpuWithSwitcheroo()) { |
40 | checkGpuWithSolid(); |
41 | } |
42 | } |
43 | } |
44 | |
45 | static bool checkGpuWithSwitcheroo() |
46 | { |
47 | #ifndef KIO_ANDROID_STUB |
48 | QDBusInterface switcheroo(QStringLiteral("net.hadess.SwitcherooControl" ), |
49 | QStringLiteral("/net/hadess/SwitcherooControl" ), |
50 | QStringLiteral("org.freedesktop.DBus.Properties" ), |
51 | QDBusConnection::systemBus()); |
52 | if (!switcheroo.isValid()) { |
53 | return false; |
54 | } |
55 | |
56 | QDBusReply<QDBusVariant> reply = switcheroo.call(QStringLiteral("Get" ), QStringLiteral("net.hadess.SwitcherooControl" ), QStringLiteral("GPUs" )); |
57 | if (!reply.isValid()) { |
58 | return false; |
59 | } |
60 | |
61 | QDBusArgument arg = qvariant_cast<QDBusArgument>(v: reply.value().variant()); |
62 | QList<QVariantMap> gpus; |
63 | arg >> gpus; |
64 | |
65 | for (const auto &gpu : gpus) { |
66 | bool defaultGpu = qvariant_cast<bool>(v: gpu[QStringLiteral("Default" )]); |
67 | if (!defaultGpu) { |
68 | s_gpuCheck = GpuCheck::Present; |
69 | QStringList envList = qvariant_cast<QStringList>(v: gpu[QStringLiteral("Environment" )]); |
70 | for (int i = 0; i + 1 < envList.size(); i += 2) { |
71 | s_gpuEnv.insert(name: envList[i], value: envList[i + 1]); |
72 | } |
73 | return true; |
74 | } |
75 | } |
76 | #endif |
77 | |
78 | // No non-default GPU found |
79 | s_gpuCheck = GpuCheck::Absent; |
80 | return true; |
81 | } |
82 | |
83 | static void checkGpuWithSolid() |
84 | { |
85 | #ifndef KIO_ANDROID_STUB |
86 | // TODO: Consider moving this check into kio, instead of using Solid |
87 | QDBusInterface iface(QStringLiteral("org.kde.Solid.PowerManagement" ), |
88 | QStringLiteral("/org/kde/Solid/PowerManagement" ), |
89 | QStringLiteral("org.kde.Solid.PowerManagement" ), |
90 | QDBusConnection::sessionBus()); |
91 | if (iface.isValid()) { |
92 | QDBusReply<bool> reply = iface.call(QStringLiteral("hasDualGpu" )); |
93 | if (reply.isValid() && reply.value()) { |
94 | s_gpuCheck = GpuCheck::Present; |
95 | s_gpuEnv.insert(QStringLiteral("DRI_PRIME" ), QStringLiteral("1" )); |
96 | return; |
97 | } |
98 | } |
99 | |
100 | s_gpuCheck = GpuCheck::Absent; |
101 | #endif |
102 | } |
103 | |
104 | namespace KIO |
105 | { |
106 | |
107 | bool hasDiscreteGpu() |
108 | { |
109 | checkGpu(); |
110 | return s_gpuCheck == GpuCheck::Present; |
111 | } |
112 | |
113 | QProcessEnvironment discreteGpuEnvironment() |
114 | { |
115 | checkGpu(); |
116 | return s_gpuEnv; |
117 | } |
118 | |
119 | } |
120 | |