[plasma/kwin/Plasma/6.7] src: core/gpumanager: add KWIN_RENDER_NODES environment variable
Xaver Hugl <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 6ca3d111c5081850248975ab5ab9dcac73da522a by Xaver Hugl, on behalf of Méven Car. Committed on 20/07/2026 at 19:27. Pushed by zamundaaa into branch 'Plasma/6.7'. core/gpumanager: add KWIN_RENDER_NODES environment variable This is mostly for autotests, but may be useful in some other cases as well, like for debugging or for VFIO. Different to the KWIN_DRM_DEVICES env var, the order doesn't matter for this. It only restricts which render nodes KWin may open directly (Vulkan may open other render nodes internally). CCBUG: 521814 (cherry picked from commit 61aae2174ceb57a12583f4382f856a3dab07cacd) Co-authored-by: Xaver Hugl <[email protected]> M +2 -23 src/backends/drm/drm_backend.cpp M +57 -8 src/core/gpumanager.cpp M +3 -0 src/core/gpumanager.h https://invent.kde.org/plasma/kwin/-/commit/6ca3d111c5081850248975ab5ab9dcac73da522a diff --git a/src/backends/drm/drm_backend.cpp b/src/backends/drm/drm_backend.cpp index aa73aa7e259..ff8f2d8b271 100644 --- a/src/backends/drm/drm_backend.cpp +++ b/src/backends/drm/drm_backend.cpp @@ -11,6 +11,7 @@ #include "config-kwin.h" #include "backends/libinput/libinputbackend.h" +#include "core/gpumanager.h" #include "core/outputconfiguration.h" #include "core/renderdevice.h" #include "core/session.h" @@ -51,28 +52,6 @@ using namespace std::chrono_literals; namespace KWin { -static QStringList splitPathList(const QString &input, const QChar delimiter) -{ - QStringList ret; - QString tmp; - for (int i = 0; i < input.size(); i++) { - if (input[i] == delimiter) { - if (i > 0 && input[i - 1] == '\\') { - tmp[tmp.size() - 1] = delimiter; - } else if (!tmp.isEmpty()) { - ret.append(tmp); - tmp = QString(); - } - } else { - tmp.append(input[i]); - } - } - if (!tmp.isEmpty()) { - ret.append(tmp); - } - return ret; -} - DrmBackend::DrmBackend(Session *session, QObject *parent) : OutputBackend(parent) , m_udev(std::make_unique<Udev>()) @@ -95,7 +74,7 @@ QList<BackendOutput *> DrmBackend::outputs() const bool DrmBackend::initialize() { - m_explicitGpus = splitPathList(qEnvironmentVariable("KWIN_DRM_DEVICES"), ':'); + m_explicitGpus = GpuManager::splitPathList(qEnvironmentVariable("KWIN_DRM_DEVICES")); connect(m_session, &Session::devicePaused, this, [this](dev_t deviceId) { if (const auto gpu = findGpu(deviceId)) { diff --git a/src/core/gpumanager.cpp b/src/core/gpumanager.cpp index 5ab30d81d11..e6f5ac646df 100644 --- a/src/core/gpumanager.cpp +++ b/src/core/gpumanager.cpp @@ -14,6 +14,7 @@ #include "utils/udev.h" #include "vulkan/vulkan_device.h" +#include <QFileInfo> #include <QSocketNotifier> #include <fcntl.h> #include <sys/ioctl.h> @@ -47,12 +48,36 @@ static std::optional<dev_t> getDevId(const FileDescriptor &fd) return buf.st_rdev; } +QStringList GpuManager::splitPathList(const QString &input) +{ + const QChar delimiter = ':'; + QStringList ret; + QString tmp; + for (int i = 0; i < input.size(); i++) { + if (input[i] == delimiter) { + if (i > 0 && input[i - 1] == '\\') { + tmp[tmp.size() - 1] = delimiter; + } else if (!tmp.isEmpty()) { + ret.append(tmp); + tmp = QString(); + } + } else { + tmp.append(input[i]); + } + } + if (!tmp.isEmpty()) { + ret.append(tmp); + } + return ret; +} + GpuManager::GpuManager() : m_udmabuf(::open("/dev/udmabuf", O_RDWR | O_CLOEXEC)) , m_udmabufDevId(getDevId(m_udmabuf)) , m_udev(std::make_unique<Udev>()) , m_udevMonitor(m_udev->createMonitor()) , m_udevNotifier(std::make_unique<QSocketNotifier>(m_udevMonitor->fd(), QSocketNotifier::Read)) + , m_explicitRenderNodes(qEnvironmentVariableIsSet("KWIN_RENDER_NODES") ? splitPathList(qEnvironmentVariable("KWIN_RENDER_NODES")) : std::optional<QStringList>()) { m_udevMonitor->filterSubsystemDevType("drm"); connect(m_udevNotifier.get(), &QSocketNotifier::activated, this, &GpuManager::handleUdevEvent); @@ -171,6 +196,22 @@ RenderDevice *GpuManager::findCompatibleRenderDevice(drmDevicePtr device) const void GpuManager::scanForRenderDevices() { + if (m_explicitRenderNodes.has_value()) { + for (const QString &path : *m_explicitRenderNodes) { + const bool hasDevice = std::ranges::contains(m_renderDevices, path, [](const auto &device) { + return device->drmDevice()->path(); + }); + if (hasDevice) { + continue; + } + auto device = RenderDevice::open(path); + if (!device) { + continue; + } + addDevice(std::move(device)); + } + return; + } const auto devices = m_udev->listRenderNodes(); for (const auto &udevDevice : devices) { if (findDevice(udevDevice->devNum())) { @@ -180,10 +221,7 @@ void GpuManager::scanForRenderDevices() if (!device) { continue; } - qCDebug(KWIN_CORE, "Adding render device %s", qPrintable(device->drmDevice()->path())); - m_renderDevices.push_back(std::move(device)); - updateCompatibilityMap(); - Q_EMIT renderDeviceAdded(m_renderDevices.back().get()); + addDevice(std::move(device)); } } @@ -202,6 +240,12 @@ void GpuManager::handleUdevEvent() if (!isRenderNode) { continue; } + if (m_explicitRenderNodes.has_value()) { + const auto canonicalPath = QFileInfo(udevDevice->devNode()).canonicalFilePath(); + if (!m_explicitRenderNodes->contains(udevDevice->devNode())) { + continue; + } + } const auto renderDevIt = std::ranges::find_if(m_renderDevices, [&udevDevice](const auto &device) { return udevDevice->devNum() == device->drmDevice()->deviceId(); }); @@ -213,10 +257,7 @@ void GpuManager::handleUdevEvent() if (!device) { continue; } - m_renderDevices.push_back(std::move(device)); - updateCompatibilityMap(); - qCDebug(KWIN_CORE, "Added render device %s", qPrintable(m_renderDevices.back()->drmDevice()->path())); - Q_EMIT renderDeviceAdded(m_renderDevices.back().get()); + addDevice(std::move(device)); } else if (udevDevice->action() == QLatin1StringView("remove")) { if (renderDevIt == m_renderDevices.end()) { continue; @@ -230,6 +271,14 @@ void GpuManager::handleUdevEvent() } } +void GpuManager::addDevice(std::unique_ptr<RenderDevice> &&device) +{ + m_renderDevices.push_back(std::move(device)); + updateCompatibilityMap(); + qCDebug(KWIN_CORE, "Added render device %s", qPrintable(m_renderDevices.back()->drmDevice()->path())); + Q_EMIT renderDeviceAdded(m_renderDevices.back().get()); +} + static uint64_t align(uint64_t size, uint64_t minimum) { if (auto remainder = size % minimum) { diff --git a/src/core/gpumanager.h b/src/core/gpumanager.h index b6882fc8b5d..03be9442a22 100644 --- a/src/core/gpumanager.h +++ b/src/core/gpumanager.h @@ -30,6 +30,7 @@ class KWIN_EXPORT GpuManager : public QObject public: static std::unique_ptr<GpuManager> s_self; static GpuManager *self(); + static QStringList splitPathList(const QString &input); explicit GpuManager(); ~GpuManager(); @@ -62,12 +63,14 @@ private: void handleUdevEvent(); void updateCompatibilityMap(); RenderDevice *findCompatibleRenderDevice(drmDevicePtr device) const; + void addDevice(std::unique_ptr<RenderDevice> &&device); const FileDescriptor m_udmabuf; const std::optional<dev_t> m_udmabufDevId; const std::unique_ptr<Udev> m_udev; const std::unique_ptr<UdevMonitor> m_udevMonitor; const std::unique_ptr<QSocketNotifier> m_udevNotifier; + const std::optional<QStringList> m_explicitRenderNodes; std::vector<std::unique_ptr<RenderDevice>> m_renderDevices; QHash<dev_t, RenderDevice *> m_compatibleDeviceMap; };