[plasma/kwin] src: core/renderdevice: make the drm device optional
Xaver Hugl <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 5299b3726b2034ce6f18ceb00d7c0c9e14b5a22a by Xaver Hugl.
Committed on 16/07/2026 at 18:38.
Pushed by zamundaaa into branch 'master'.
core/renderdevice: make the drm device optional
This will be used in the next commit
M +1 -1 src/backends/drm/drm_egl_layer.cpp
M +3 -2 src/compositor.cpp
M +24 -21 src/core/gpumanager.cpp
M +17 -5 src/core/renderdevice.cpp
M +5 -1 src/core/renderdevice.h
M +1 -1 src/multigpuswapchain.cpp
M +3 -7 src/opengl/eglbackend.cpp
M +1 -1 src/plugins/qpa/window.cpp
M +1 -1 src/wayland/linuxdmabufv1clientbuffer.cpp
M +2 -1 src/wayland_server.cpp
https://invent.kde.org/plasma/kwin/-/commit/5299b3726b2034ce6f18ceb00d7c0c9e14b5a22a
diff --git a/src/backends/drm/drm_egl_layer.cpp b/src/backends/drm/drm_egl_layer.cpp
index 7ef07821379..28830eb0e2f 100644
--- a/src/backends/drm/drm_egl_layer.cpp
+++ b/src/backends/drm/drm_egl_layer.cpp
@@ -136,7 +136,7 @@ bool EglGbmLayer::earlyScanoutChecks()
bool EglGbmLayer::importScanoutBuffer(GraphicsBuffer *buffer, const std::shared_ptr<OutputFrame> &frame)
{
if (buffer->dmabufAttributes()->device != gpu()->drmDevice()->deviceId()
- && (!gpu()->renderDevice() || buffer->dmabufAttributes()->device != gpu()->renderDevice()->drmDevice()->deviceId())) {
+ && (!gpu()->renderDevice() || buffer->dmabufAttributes()->device != gpu()->renderDevice()->deviceId())) {
// Disallow direct scanout between GPUs, as
// - there are some significant driver bugs with direct scanout from other GPUs,
// like https://gitlab.freedesktop.org/drm/amd/-/issues/2075
diff --git a/src/compositor.cpp b/src/compositor.cpp
index 57ad3ed9fb8..861eb44276f 100644
--- a/src/compositor.cpp
+++ b/src/compositor.cpp
@@ -148,7 +148,8 @@ static QVariantHash collectCrashInformation(const EglBackend *backend)
QVariantHash gpuInformation;
gpuInformation[QStringLiteral("api_type")] = QStringLiteral("OpenGL");
gpuInformation[QStringLiteral("name")] = QString::fromUtf8(glPlatform->glRendererString());
- if (const auto pciInfo = backend->renderDevice()->drmDevice()->pciDeviceInfo()) {
+ if (backend->renderDevice()->drmDevice() && backend->renderDevice()->drmDevice()->pciDeviceInfo()) {
+ const auto pciInfo = backend->renderDevice()->drmDevice()->pciDeviceInfo();
gpuInformation[QStringLiteral("id")] = QString::number(pciInfo->device_id, 16);
gpuInformation[QStringLiteral("vendor_id")] = QString::number(pciInfo->vendor_id, 16);
}
@@ -249,7 +250,7 @@ bool Compositor::attemptOpenGLCompositing()
qCWarning(KWIN_CORE, "Found no render device!");
return false;
}
- qCDebug(KWIN_CORE, "Chose %s as the primary GPU", qPrintable(m_renderDevice->drmDevice()->path()));
+ qCDebug(KWIN_CORE, "Chose %s as the primary GPU", qPrintable(m_renderDevice->path()));
}
std::unique_ptr<EglBackend> backend = kwinApp()->outputBackend()->createOpenGLBackend(m_renderDevice);
if (!backend->init()) {
diff --git a/src/core/gpumanager.cpp b/src/core/gpumanager.cpp
index ede33cfad9b..4c44e9143d6 100644
--- a/src/core/gpumanager.cpp
+++ b/src/core/gpumanager.cpp
@@ -108,9 +108,7 @@ RenderDevice *GpuManager::compatibleRenderDevice(dev_t id) const
RenderDevice *GpuManager::findDevice(dev_t id) const
{
- const auto it = std::ranges::find_if(m_renderDevices, [id](const auto &device) {
- return device->drmDevice()->deviceId() == id;
- });
+ const auto it = std::ranges::find(m_renderDevices, id, &RenderDevice::deviceId);
return it == m_renderDevices.end() ? nullptr : it->get();
}
@@ -153,6 +151,9 @@ void GpuManager::updateCompatibilityMap()
RenderDevice *GpuManager::findCompatibleRenderDevice(drmDevicePtr device) const
{
auto candidates = m_renderDevices | std::views::filter([device](const auto &renderDevice) {
+ if (!renderDevice->drmDevice()) {
+ return true;
+ }
if (device->bustype == DRM_BUS_PLATFORM) {
// devices with bus "platform" can be assumed to be compatible.
return renderDevice->drmDevice()->busType() == DRM_BUS_PLATFORM;
@@ -180,19 +181,26 @@ RenderDevice *GpuManager::findCompatibleRenderDevice(drmDevicePtr device) const
&& left->vulkanDevice()->isSoftwareRenderer() != right->vulkanDevice()->isSoftwareRenderer()) {
return !left->vulkanDevice()->isSoftwareRenderer();
}
- // if both have hardware acceleration, prefer a matching device
- const bool sameDeviceLeft = drmDevicesEqual(device, left->drmDevice()->libdrmDevice()) == 1;
- const bool sameDeviceRight = drmDevicesEqual(device, right->drmDevice()->libdrmDevice()) == 1;
- if (sameDeviceLeft != sameDeviceRight) {
- return sameDeviceLeft;
+ if (bool(left->drmDevice()) != bool(right->drmDevice())) {
+ // prefer udmabuf over software rendering on dumb buffers,
+ // since the latter is usually slower
+ return left->drmDevice() == nullptr;
}
- // prefer render nodes over KMS nodes
- if (left->drmDevice()->isKMS() != right->drmDevice()->isKMS()) {
- return !left->drmDevice()->isKMS();
+ if (left->drmDevice()) {
+ // if both have hardware acceleration, prefer a matching device
+ const bool sameDeviceLeft = drmDevicesEqual(device, left->drmDevice()->libdrmDevice()) == 1;
+ const bool sameDeviceRight = drmDevicesEqual(device, right->drmDevice()->libdrmDevice()) == 1;
+ if (sameDeviceLeft != sameDeviceRight) {
+ return sameDeviceLeft;
+ }
+ // prefer render nodes over KMS nodes
+ if (left->drmDevice()->isKMS() != right->drmDevice()->isKMS()) {
+ return !left->drmDevice()->isKMS();
+ }
}
// fallback: if both are equally good,
// make sure we always get the same device
- return left->drmDevice()->deviceId() < right->drmDevice()->deviceId();
+ return left->deviceId() < right->deviceId();
})->get();
}
@@ -200,10 +208,7 @@ 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) {
+ if (std::ranges::contains(m_renderDevices, path, &RenderDevice::path)) {
continue;
}
auto device = RenderDevice::open(path);
@@ -248,9 +253,7 @@ void GpuManager::handleUdevEvent()
continue;
}
}
- const auto renderDevIt = std::ranges::find_if(m_renderDevices, [&udevDevice](const auto &device) {
- return udevDevice->devNum() == device->drmDevice()->deviceId();
- });
+ const auto renderDevIt = std::ranges::find(m_renderDevices, udevDevice->devNum(), &RenderDevice::deviceId);
if (udevDevice->action() == QLatin1StringView("add")) {
if (renderDevIt != m_renderDevices.end()) {
continue;
@@ -326,7 +329,7 @@ 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()));
+ qCDebug(KWIN_CORE, "Added render device %s", qPrintable(m_renderDevices.back()->path()));
Q_EMIT renderDeviceAdded(m_renderDevices.back().get());
}
@@ -341,7 +344,7 @@ void GpuManager::removeDevice(RenderDevice *device)
auto ref = std::move(*it);
m_renderDevices.erase(it);
updateCompatibilityMap();
- qCDebug(KWIN_CORE, "Removed render device %s", qPrintable(device->drmDevice()->path()));
+ qCDebug(KWIN_CORE, "Removed render device %s", qPrintable(device->path()));
Q_EMIT renderDeviceRemoved(device);
}
diff --git a/src/core/renderdevice.cpp b/src/core/renderdevice.cpp
index 02b1ca7e684..2d87fe63966 100644
--- a/src/core/renderdevice.cpp
+++ b/src/core/renderdevice.cpp
@@ -82,6 +82,8 @@ RenderDevice::RenderDevice(std::unique_ptr<DrmDevice> &&device, std::unique_ptr<
: m_device(std::move(device))
, m_display(std::move(display))
, m_vulkanInstance(createVulkanInstance(m_vulkanContext))
+ , m_path(m_device->path())
+ , m_deviceId(m_device->deviceId())
{
createVulkanDevice();
m_allImportableFormats = getImportFormats(m_display.get(), m_vulkanDevice.get());
@@ -96,6 +98,16 @@ DrmDevice *RenderDevice::drmDevice() const
return m_device.get();
}
+QString RenderDevice::path() const
+{
+ return m_path;
+}
+
+dev_t RenderDevice::deviceId() const
+{
+ return m_deviceId;
+}
+
GraphicsBufferAllocator *RenderDevice::allocator() const
{
return m_device->allocator();
@@ -138,7 +150,7 @@ static constexpr std::array s_requiredVulkanExtensions = {
VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
};
-static std::unique_ptr<VulkanDevice> openVulkanDevice(const vk::raii::Instance &instance, DrmDevice *drm)
+static std::unique_ptr<VulkanDevice> openVulkanDevice(const vk::raii::Instance &instance, DrmDevice *drm, const QString &path)
{
const auto [enumerateResult, physicalDevices] = instance.enumeratePhysicalDevices();
if (enumerateResult != vk::Result::eSuccess) {
@@ -146,7 +158,7 @@ static std::unique_ptr<VulkanDevice> openVulkanDevice(const vk::raii::Instance &
return nullptr;
}
// with faux devices like vkms and vgem, we can only do software rendering
- const bool needsSoftwareDevice = drm->busType() == DRM_BUS_FAUX;
+ const bool needsSoftwareDevice = !drm || drm->busType() == DRM_BUS_FAUX;
for (const vk::raii::PhysicalDevice &physicalDevice : physicalDevices) {
const auto basicProperties = physicalDevice.getProperties2();
const bool isSoftwareDevice = basicProperties.properties.deviceType == vk::PhysicalDeviceType::eCpu;
@@ -250,10 +262,10 @@ static std::unique_ptr<VulkanDevice> openVulkanDevice(const vk::raii::Instance &
if (ret->supportedFormats().isEmpty()) {
continue;
}
- qCDebug(KWIN_VULKAN, "Found Vulkan device %s for %s", deviceName, qPrintable(drm->path()));
+ qCDebug(KWIN_VULKAN, "Found Vulkan device %s for %s", deviceName, qPrintable(path));
return ret;
}
- qCDebug(KWIN_VULKAN, "No Vulkan device found for %s", qPrintable(drm->path()));
+ qCDebug(KWIN_VULKAN, "No Vulkan device found for %s", qPrintable(path));
return nullptr;
}
@@ -273,7 +285,7 @@ void RenderDevice::createVulkanDevice()
if (!*m_vulkanInstance) {
return;
}
- m_vulkanDevice = openVulkanDevice(m_vulkanInstance, m_device.get());
+ m_vulkanDevice = openVulkanDevice(m_vulkanInstance, m_device.get(), m_path);
if (m_vulkanDevice) {
connect(m_vulkanDevice.get(), &VulkanDevice::deviceLost, this, &RenderDevice::handleVulkanDeviceLoss);
}
diff --git a/src/core/renderdevice.h b/src/core/renderdevice.h
index 386854180b1..78901f02a46 100644
--- a/src/core/renderdevice.h
+++ b/src/core/renderdevice.h
@@ -36,10 +36,12 @@ public:
/**
* the underlying drm device that can be used to allocate buffers for this render device
- * This doesn't necessarily represent a render node!
+ * This doesn't necessarily represent a render node, and may be nullptr!
*/
DrmDevice *drmDevice() const;
GraphicsBufferAllocator *allocator() const;
+ QString path() const;
+ dev_t deviceId() const;
EglDisplay *eglDisplay() const;
/**
* @returns an EGL context suitable for rendering with this render device,
@@ -84,6 +86,8 @@ private:
FormatModifierMap m_allImportableFormats;
std::weak_ptr<EglContext> m_eglContext;
bool m_inReset = false;
+ const QString m_path;
+ const dev_t m_deviceId;
};
}
diff --git a/src/multigpuswapchain.cpp b/src/multigpuswapchain.cpp
index 9e19eac8965..330feeaea35 100644
--- a/src/multigpuswapchain.cpp
+++ b/src/multigpuswapchain.cpp
@@ -115,7 +115,7 @@ std::unique_ptr<MultiGpuSwapchain> MultiGpuSwapchain::create(RenderDevice *copyD
.software = false,
.scanout = scanout,
};
- auto eglSwapchain = EglSwapchain::create(copyDevice->drmDevice()->allocator(), context.get(), options);
+ auto eglSwapchain = EglSwapchain::create(copyDevice->allocator(), context.get(), options);
if (eglSwapchain) {
return std::make_unique<MultiGpuSwapchain>(copyDevice, targetDevice, context, std::move(eglSwapchain));
}
diff --git a/src/opengl/eglbackend.cpp b/src/opengl/eglbackend.cpp
index 0a88b909097..81172f89139 100644
--- a/src/opengl/eglbackend.cpp
+++ b/src/opengl/eglbackend.cpp
@@ -100,10 +100,6 @@ void EglBackend::cleanup()
void EglBackend::initWayland()
{
- if (!WaylandServer::self()) {
- return;
- }
-
auto filterFormats = [this](std::optional<uint32_t> bpc, bool withExternalOnlyYUV) {
FormatModifierMap set;
const auto &allFormats = m_renderDevice->eglDisplay()->allSupportedDrmFormats();
@@ -155,17 +151,17 @@ void EglBackend::initWayland()
};
m_tranches.append({
- .device = m_renderDevice->drmDevice()->deviceId(),
+ .device = m_renderDevice->deviceId(),
.flags = LinuxDmaBufV1Feedback::TrancheFlag::Sampling,
.formatTable = filterFormats(10, false),
});
m_tranches.append({
- .device = m_renderDevice->drmDevice()->deviceId(),
+ .device = m_renderDevice->deviceId(),
.flags = LinuxDmaBufV1Feedback::TrancheFlag::Sampling,
.formatTable = filterFormats(8, false),
});
m_tranches.append({
- .device = m_renderDevice->drmDevice()->deviceId(),
+ .device = m_renderDevice->deviceId(),
.flags = LinuxDmaBufV1Feedback::TrancheFlag::Sampling,
.formatTable = includeShaderConversions(filterFormats(std::nullopt, true)),
});
diff --git a/src/plugins/qpa/window.cpp b/src/plugins/qpa/window.cpp
index 79ed0cbe32e..ccd770ea585 100644
--- a/src/plugins/qpa/window.cpp
+++ b/src/plugins/qpa/window.cpp
@@ -58,7 +58,7 @@ Swapchain *Window::swapchain(const std::shared_ptr<EglContext> &context, const F
static ShmGraphicsBufferAllocator shmAllocator;
allocator = &shmAllocator;
} else {
- allocator = Compositor::self()->backend()->renderDevice()->drmDevice()->allocator();
+ allocator = Compositor::self()->backend()->renderDevice()->allocator();
}
for (auto it = formats.begin(); it != formats.end(); it++) {
diff --git a/src/wayland/linuxdmabufv1clientbuffer.cpp b/src/wayland/linuxdmabufv1clientbuffer.cpp
index eda7b3709bc..8e5bab213f1 100644
--- a/src/wayland/linuxdmabufv1clientbuffer.cpp
+++ b/src/wayland/linuxdmabufv1clientbuffer.cpp
@@ -468,7 +468,7 @@ QList<LinuxDmaBufV1Feedback::Tranche> LinuxDmaBufV1Feedback::createScanoutTranch
if (tranche.device != mainDevice) {
continue;
}
- if (compatibleWithScanout && tranche.device != compatibleWithScanout->drmDevice()->deviceId()) {
+ if (compatibleWithScanout && tranche.device != compatibleWithScanout->deviceId()) {
// limit scanout tranches to devices we can also sample from
continue;
}
diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp
index f522edd4662..ce25711d535 100644
--- a/src/wayland_server.cpp
+++ b/src/wayland_server.cpp
@@ -817,7 +817,8 @@ ExtBackgroundEffectManagerV1 *WaylandServer::backgroundEffectManager() const
void WaylandServer::setRenderBackend(RenderBackend *backend)
{
- if (backend->renderDevice()->drmDevice()->supportsSyncObjTimelines()) {
+ if (backend->renderDevice()->drmDevice()
+ && backend->renderDevice()->drmDevice()->supportsSyncObjTimelines()) {
// ensure the DRM_IOCTL_SYNCOBJ_EVENTFD ioctl is supported
const auto linuxVersion = linuxKernelVersion();
if (linuxVersion.majorVersion() < 6 && linuxVersion.minorVersion() < 6) {