From 3d5d13f259f8bf1d88c8158a46d924259f2227b3 Mon Sep 17 00:00:00 2001 From: Pier Luigi Fiorini Date: Sat, 30 Sep 2023 09:13:56 +0200 Subject: [PATCH] Device integration for DRM/KMS Closes: #43 --- CMakeLists.txt | 3 + features.cmake | 29 +++ .../deviceintegration/drm/CMakeLists.txt | 42 ++++ src/plugins/deviceintegration/drm/drm.json | 3 + .../deviceintegration/drm/drmbackend.cpp | 227 ++++++++++++++++++ .../deviceintegration/drm/drmbackend.h | 68 ++++++ .../deviceintegration/drm/drmcursor.cpp | 46 ++++ src/plugins/deviceintegration/drm/drmcursor.h | 27 +++ src/plugins/deviceintegration/drm/drmgpu.cpp | 110 +++++++++ src/plugins/deviceintegration/drm/drmgpu.h | 89 +++++++ .../deviceintegration/drm/drmintegration.cpp | 116 +++++++++ .../deviceintegration/drm/drmintegration.h | 46 ++++ .../drm/drmintegrationplugin.cpp | 23 ++ .../drm/drmintegrationplugin.h | 24 ++ .../deviceintegration/drm/drmobject.cpp | 109 +++++++++ src/plugins/deviceintegration/drm/drmobject.h | 75 ++++++ .../deviceintegration/drm/drmoutput.cpp | 22 ++ src/plugins/deviceintegration/drm/drmoutput.h | 23 ++ .../deviceintegration/drm/drmplane.cpp | 17 ++ src/plugins/deviceintegration/drm/drmplane.h | 20 ++ .../deviceintegration/drm/drmpointer.h | 150 ++++++++++++ .../deviceintegration/drm/drmproperty.cpp | 145 +++++++++++ .../deviceintegration/drm/drmproperty.h | 135 +++++++++++ .../deviceintegration/drm/drmwindow.cpp | 19 ++ src/plugins/deviceintegration/drm/drmwindow.h | 28 +++ 25 files changed, 1596 insertions(+) create mode 100644 src/plugins/deviceintegration/drm/CMakeLists.txt create mode 100644 src/plugins/deviceintegration/drm/drm.json create mode 100644 src/plugins/deviceintegration/drm/drmbackend.cpp create mode 100644 src/plugins/deviceintegration/drm/drmbackend.h create mode 100644 src/plugins/deviceintegration/drm/drmcursor.cpp create mode 100644 src/plugins/deviceintegration/drm/drmcursor.h create mode 100644 src/plugins/deviceintegration/drm/drmgpu.cpp create mode 100644 src/plugins/deviceintegration/drm/drmgpu.h create mode 100644 src/plugins/deviceintegration/drm/drmintegration.cpp create mode 100644 src/plugins/deviceintegration/drm/drmintegration.h create mode 100644 src/plugins/deviceintegration/drm/drmintegrationplugin.cpp create mode 100644 src/plugins/deviceintegration/drm/drmintegrationplugin.h create mode 100644 src/plugins/deviceintegration/drm/drmobject.cpp create mode 100644 src/plugins/deviceintegration/drm/drmobject.h create mode 100644 src/plugins/deviceintegration/drm/drmoutput.cpp create mode 100644 src/plugins/deviceintegration/drm/drmoutput.h create mode 100644 src/plugins/deviceintegration/drm/drmplane.cpp create mode 100644 src/plugins/deviceintegration/drm/drmplane.h create mode 100644 src/plugins/deviceintegration/drm/drmpointer.h create mode 100644 src/plugins/deviceintegration/drm/drmproperty.cpp create mode 100644 src/plugins/deviceintegration/drm/drmproperty.h create mode 100644 src/plugins/deviceintegration/drm/drmwindow.cpp create mode 100644 src/plugins/deviceintegration/drm/drmwindow.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d8147b0a..eda05575 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,9 @@ if(FEATURE_aurora_qpa) add_subdirectory(src/plugins/platforms/eglfs/deviceintegration/eglfs_x11) endif() endif() +if(FEATURE_aurora_deviceintegration_drm) + add_subdirectory(src/plugins/deviceintegration/drm) +endif() if(FEATURE_aurora_deviceintegration_wayland) add_subdirectory(src/plugins/deviceintegration/wayland) endif() diff --git a/features.cmake b/features.cmake index 2adba8e9..8eafdab3 100644 --- a/features.cmake +++ b/features.cmake @@ -471,6 +471,35 @@ if(FEATURE_aurora_vulkan_server_buffer) endif() set(LIRI_FEATURE_aurora_vulkan_server_buffer "$") +# Device Integration: drm +option(FEATURE_aurora_deviceintegration_drm "Device Integration: drm" ON) +if(FEATURE_aurora_deviceintegration_drm) + find_package(EGL QUIET) + + if(NOT TARGET EGL::EGL) + message(WARNING "You need EGL for Aurora::DeviceIntegration::DRM") + set(FEATURE_aurora_deviceintegration_drm OFF) + endif() + if(NOT TARGET PkgConfig::Libudev) + message(WARNING "You need udev for Aurora::DeviceIntegration::DRM") + set(FEATURE_aurora_deviceintegration_drm OFF) + endif() + if(NOT TARGET PkgConfig::Libinput) + message(WARNING "You need libinput for Aurora::DeviceIntegration::DRM") + set(FEATURE_aurora_deviceintegration_drm OFF) + endif() + if(NOT TARGET PkgConfig::Libdrm) + message(WARNING "You need libdrm for Aurora::DeviceIntegration::DRM") + set(FEATURE_aurora_deviceintegration_drm OFF) + endif() + if(NOT TARGET PkgConfig::Gbm) + message(WARNING "You need gbm for Aurora::DeviceIntegration::DRM") + set(FEATURE_aurora_deviceintegration_drm OFF) + endif() +endif() +add_feature_info("Aurora::DeviceIntegration::DRM" FEATURE_aurora_deviceintegration_drm "Build DRM/KMS device integration") +set(LIRI_FEATURE_aurora_deviceintegration_drm "$") + # Device Integration: wayland option(FEATURE_aurora_deviceintegration_wayland "Device Integration: wayland" ON) if(FEATURE_aurora_deviceintegration_wayland) diff --git a/src/plugins/deviceintegration/drm/CMakeLists.txt b/src/plugins/deviceintegration/drm/CMakeLists.txt new file mode 100644 index 00000000..d8ece9f9 --- /dev/null +++ b/src/plugins/deviceintegration/drm/CMakeLists.txt @@ -0,0 +1,42 @@ +include(ECMQtDeclareLoggingCategory) +ecm_qt_declare_logging_category( + AuroraDeviceIntegrationDrm_SOURCES + HEADER "drmloggingcategories.h" + IDENTIFIER "Aurora::Platform::gLcDrm" + CATEGORY_NAME "aurora.platform.drm" + DEFAULT_SEVERITY "Info" + DESCRIPTION "Aurora device integration for DRM/KMS" +) + +liri_add_plugin(AuroraDeviceIntegrationDrm + TYPE + "aurora/deviceintegration" + OUTPUT_NAME + drm + SOURCES + drm.json + drmbackend.cpp drmbackend.h + drmcursor.cpp drmcursor.h + drmgpu.cpp drmgpu.h + drmintegration.cpp drmintegration.h + drmintegrationplugin.cpp drmintegrationplugin.h + drmobject.cpp drmobject.h + drmoutput.cpp drmoutput.h + drmplane.cpp drmplane.h + drmpointer.h + drmproperty.cpp drmproperty.h + drmwindow.cpp drmwindow.h + ${AuroraDeviceIntegrationDrm_SOURCES} + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui + Liri::AuroraCore + Liri::AuroraPlatform + Liri::AuroraPlatformPrivate + Liri::AuroraUdev + EGL::EGL + PkgConfig::Libdrm + PkgConfig::Gbm +) + +liri_finalize_plugin(AuroraDeviceIntegrationDrm) diff --git a/src/plugins/deviceintegration/drm/drm.json b/src/plugins/deviceintegration/drm/drm.json new file mode 100644 index 00000000..735ca9ae --- /dev/null +++ b/src/plugins/deviceintegration/drm/drm.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "drm" ] +} diff --git a/src/plugins/deviceintegration/drm/drmbackend.cpp b/src/plugins/deviceintegration/drm/drmbackend.cpp new file mode 100644 index 00000000..45c684ed --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmbackend.cpp @@ -0,0 +1,227 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include "drmbackend.h" +#include "drmgpu.h" +#include "drmloggingcategories.h" +#include "drmoutput.h" + +#include + +#include +#include +#include +#include + +#ifndef EGL_EXT_platform_base +typedef EGLDisplay(EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum platform, + void *native_display, + const EGLint *attrib_list); +#endif + +#ifndef EGL_PLATFORM_GBM_KHR +# define EGL_PLATFORM_GBM_KHR 0x31D7 +#endif + +namespace Aurora { + +namespace Platform { + +Q_GLOBAL_STATIC(DrmBackend, gDrmBackend) + +DrmBackend::DrmBackend(QObject *parent) + : QObject(parent) + , m_session(Session::create(Session::Type::Logind, this)) + , m_udev(new Aurora::PlatformSupport::Udev()) +{ +} + +DrmBackend::~DrmBackend() +{ + if (m_udev) { + delete m_udev; + m_udev = nullptr; + } +} + +Session *DrmBackend::session() const +{ + return m_session; +} + +EGLDisplay DrmBackend::eglDisplay() const +{ + return m_eglDisplay; +} + +EGLNativeDisplayType DrmBackend::platformDisplay() const +{ + if (m_gpu) + return reinterpret_cast(m_gpu->gbmDevice()); + return EGL_CAST(EGLNativeDisplayType, 0); +} + +bool DrmBackend::isAtomicEnabled() const +{ + return m_enableAtomic; +} + +DrmGpu *DrmBackend::primaryGpu() const +{ + return m_gpu; +} + +void DrmBackend::initialize() +{ + if (m_initialized) + return; + + m_initialized = true; + + // Session + connect(m_session, &Session::devicePaused, this, [this](dev_t deviceId) { + if (auto *gpu = findGpu(deviceId)) + gpu->setActive(false); + }); + connect(m_session, &Session::deviceResumed, this, [this](dev_t deviceId) { + if (auto *gpu = findGpu(deviceId)) + gpu->setActive(true); + }); + + // Find all GPUs + Aurora::PlatformSupport::UdevEnumerate enumerate( + Aurora::PlatformSupport::UdevDevice::PrimaryVideoDevice + | Aurora::PlatformSupport::UdevDevice::GenericVideoDevice, + m_udev); + auto udevDevices = enumerate.scan(); + if (Q_UNLIKELY(udevDevices.isEmpty())) + qFatal("Could not find DRM device!"); + + // Create GPUs + if (!udevDevices.isEmpty()) { + qCDebug(gLcDrm, "Found the following video devices for the \"%s\" seat:", + qPrintable(m_session->seat())); + for (auto *udevDevice : qAsConst(udevDevices)) { + if (udevDevice->seat() == m_session->seat()) { + const auto path = udevDevice->deviceNode(); + qCDebug(gLcDrm) << '\t' << path.toLocal8Bit().constData(); + addGpu(path); + } + } + } + if (Q_UNLIKELY(m_gpus.isEmpty())) + qFatal("No suitable DRM device have been found"); + + // Select the first one + m_gpu = m_gpus.first(); + + // Create EGL display + createDisplay(); +} + +void DrmBackend::destroy() +{ +} + +DrmBackend *DrmBackend::instance() +{ + return gDrmBackend(); +} + +DrmGpu *DrmBackend::addGpu(const QString &path) +{ + // Open the DRM device + int fd = m_session->openRestricted(path); + if (fd < 0) { + qCWarning(gLcDrm) << "Failed to open DRM device" << path; + return nullptr; + } + + // Make a simpel DRM call to check if the device is usable + drmModeResPtr resources = drmModeGetResources(fd); + if (!resources) { + qCDebug(gLcDrm) << "Skipping KMS incapable DRM device" << path; + m_session->closeRestricted(fd); + return nullptr; + } + drmModeFreeResources(resources); + + struct stat sbuf; + if (fstat(fd, &sbuf) < 0) { + qCDebug(gLcDrm, "Failed to fstat \"%s\": %s", qPrintable(path), strerror(errno)); + m_session->closeRestricted(fd); + return nullptr; + } + + qCInfo(gLcDrm) << "Adding DRM device:" << path; + + auto *gpu = new DrmGpu(path, fd, sbuf.st_rdev); + m_gpus.append(gpu); + emit gpuAdded(gpu); + return gpu; +} + +DrmGpu *DrmBackend::findGpu(dev_t deviceId) const +{ + auto it = std::find_if(m_gpus.begin(), m_gpus.end(), + [deviceId](const auto *gpu) { return gpu->deviceId() == deviceId; }); + return it == m_gpus.end() ? nullptr : *it; +} + +void DrmBackend::createDisplay() +{ + EGLNativeDisplayType nativeDisplay = platformDisplay(); + + PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay = nullptr; + const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (extensions + && (strstr(extensions, "EGL_KHR_platform_gbm") + || strstr(extensions, "EGL_MESA_platform_gbm"))) { + getPlatformDisplay = reinterpret_cast( + eglGetProcAddress("eglGetPlatformDisplayEXT")); + } + + if (getPlatformDisplay) { + m_eglDisplay = getPlatformDisplay(EGL_PLATFORM_GBM_KHR, nativeDisplay, nullptr); + } else { + qCDebug(gLcDrm, "No eglGetPlatformDisplay for GBM, falling back to eglGetDisplay"); + m_eglDisplay = eglGetDisplay(nativeDisplay); + } +} + +void DrmBackend::updateOutputs() +{ + for (auto it = m_gpus.begin(); it != m_gpus.end(); ++it) { + auto *gpu = (*it); + if (gpu->isRemoved()) + gpu->removeOutputs(); + else + gpu->updateOutputs(); + } + + for (auto it = m_gpus.begin(); it != m_gpus.end();) { + auto *gpu = (*it); + + if (gpu->isRemoved() || (gpu != m_gpu && gpu->hasDrmOutputs())) { + qCDebug(gLcDrm, "Removing GPU \"%s\"", qPrintable(gpu->deviceNode())); + it = m_gpus.erase(it); + emit gpuRemoved(gpu); + } else { + it++; + } + } +} + +void DrmBackend::addOutput(DrmOutput *output) +{ +} + +void DrmBackend::removeOutput(DrmOutput *output) +{ +} + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmbackend.h b/src/plugins/deviceintegration/drm/drmbackend.h new file mode 100644 index 00000000..94950bb5 --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmbackend.h @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include +#include + +#include + +namespace Aurora { + +namespace Platform { + +class DrmGpu; +class DrmOutput; + +class DrmBackend : public QObject +{ + Q_OBJECT +public: + explicit DrmBackend(QObject *parent = nullptr); + ~DrmBackend(); + + Session *session() const; + + EGLDisplay eglDisplay() const; + EGLNativeDisplayType platformDisplay() const; + + bool isAtomicEnabled() const; + + DrmGpu *primaryGpu() const; + + void initialize(); + void destroy(); + + static DrmBackend *instance(); + +signals: + void gpuAdded(DrmGpu *gpu); + void gpuRemoved(DrmGpu *gpu); + +private: + bool m_initialized = false; + Session *m_session = nullptr; + Aurora::PlatformSupport::Udev *m_udev = nullptr; + DrmGpu *m_gpu = nullptr; + QList m_gpus; + EGLDisplay m_eglDisplay = EGL_NO_DISPLAY; + bool m_enableAtomic = true; + + DrmGpu *findGpu(dev_t deviceId) const; + DrmGpu *addGpu(const QString &path); + + void createDisplay(); + void updateOutputs(); + +private slots: + void addOutput(DrmOutput *output); + void removeOutput(DrmOutput *output); + void updateOutputs(); +}; + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmcursor.cpp b/src/plugins/deviceintegration/drm/drmcursor.cpp new file mode 100644 index 00000000..85a7c624 --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmcursor.cpp @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "drmbackend.h" +#include "drmcursor.h" +#include "drmgpu.h" +#include "drmloggingcategories.h" + +#include +#include +#include + +#ifndef DRM_CAP_CURSOR_WIDTH +# define DRM_CAP_CURSOR_WIDTH 0x8 +#endif + +#ifndef DRM_CAP_CURSOR_HEIGHT +# define DRM_CAP_CURSOR_HEIGHT 0x9 +#endif + +namespace Aurora { + +namespace Platform { + +DrmCursor::DrmCursor(QObject *parent) + : QObject(parent) +{ + const auto fd = DrmBackend::instance()->primaryGpu()->fd(); + auto *gbmDevice = DrmBackend::instance()->primaryGpu()->gbmDevice(); + + uint64_t width, height; + if ((drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &width) == 0) + && (drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &height) == 0)) { + m_cursorSize.setWidth(width); + m_cursorSize.setHeight(height); + } + + m_gbmBo = gbm_bo_create(gbmDevice, m_cursorSize.width(), m_cursorSize.height(), + GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE); + if (!m_gbmBo) + qCWarning(gLcDrm) << "Failed to create buffer for cursor"; +} + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmcursor.h b/src/plugins/deviceintegration/drm/drmcursor.h new file mode 100644 index 00000000..b2ab057e --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmcursor.h @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include + +struct gbm_bo; + +namespace Aurora { + +namespace Platform { + +class DrmCursor : public QObject +{ +public: + explicit DrmCursor(QObject *parent = nullptr); + +private: + QSize m_cursorSize = QSize(64, 64); + gbm_bo *m_gbmBo; +}; + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmgpu.cpp b/src/plugins/deviceintegration/drm/drmgpu.cpp new file mode 100644 index 00000000..01a7a105 --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmgpu.cpp @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "drmbackend.h" +#include "drmgpu.h" +#include "drmloggingcategories.h" + +#include + +namespace Aurora { + +namespace Platform { + +DrmGpu::DrmGpu(const QString &path, int fd, dev_t deviceId, QObject *parent) + : QObject(parent) + , m_deviceNode(path) + , m_fd(fd) + , m_deviceId(deviceId) +{ + m_gbmDevice = gbm_create_device(m_fd); + if (!m_gbmDevice) + qFatal("Unable to create GBM device for \"%s\"", qPrintable(path)); + + // We want all planes + drmSetClientCap(m_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + + // Check atomic support + m_hasAtomicSupport = drmSetClientCap(m_fd, DRM_CLIENT_CAP_ATOMIC, 1) == 0; + if (m_hasAtomicSupport) { + if (DrmBackend::instance()->isAtomicEnabled()) { + qCDebug(gLcDrm, "GPU \"%s\" supports atomic and it's enabled", qPrintable(path)); + } else { + qCDebug(gLcDrm, "GPU \"%s\" supports atomic but it's disable", qPrintable(path)); + m_hasAtomicSupport = false; + } + } +} + +DrmGpu::~DrmGpu() +{ + if (m_gbmDevice) { + gbm_device_destroy(m_gbmDevice); + m_gbmDevice = nullptr; + } + + if (m_fd >= 0) { + DrmBackend::instance()->session()->closeRestricted(m_fd); + m_fd = -1; + } +} + +int DrmGpu::fd() const +{ + return m_fd; +} + +dev_t DrmGpu::deviceId() const +{ + return m_deviceId; +} + +QString DrmGpu::deviceNode() const +{ + return m_deviceNode; +} + +gbm_device *DrmGpu::gbmDevice() const +{ + return m_gbmDevice; +} + +bool DrmGpu::isActive() const +{ + return m_active; +} + +void DrmGpu::setActive(bool value) +{ + if (m_active == value) + return; + + m_active = value; + emit activeChanged(value); +} + +bool DrmGpu::isRemoved() const +{ + return m_removed; +} + +void DrmGpu::setRemoved() +{ + m_removed = true; +} + +bool DrmGpu::updateOutputs() +{ + if (!m_active) + return false; + + drmModeResPtr resources = drmModeGetResources(m_fd); + if (!resources) { + qErrnoWarning(errno, "drmModeGetResources failed"); + return false; + } +} + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmgpu.h b/src/plugins/deviceintegration/drm/drmgpu.h new file mode 100644 index 00000000..51b988ae --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmgpu.h @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include +#include +#include + +#ifndef DRM_PLANE_TYPE_OVERLAY +# define DRM_PLANE_TYPE_OVERLAY 0 +#endif +#ifndef DRM_PLANE_TYPE_PRIMARY +# define DRM_PLANE_TYPE_PRIMARY 1 +#endif +#ifndef DRM_PLANE_TYPE_CURSOR +# define DRM_PLANE_TYPE_CURSOR 2 +#endif + +#ifndef DRM_CLIENT_CAP_UNIVERSAL_PLANES +# define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 +#endif +#ifndef DRM_CLIENT_CAP_ATOMIC +# define DRM_CLIENT_CAP_ATOMIC 3 +#endif + +#ifndef DRM_MODE_PROP_EXTENDED_TYPE +# define DRM_MODE_PROP_EXTENDED_TYPE 0x0000ffc0 +#endif +#ifndef DRM_MODE_PROP_TYPE +# define DRM_MODE_PROP_TYPE(n) ((n) << 6) +#endif +#ifndef DRM_MODE_PROP_OBJECT +# define DRM_MODE_PROP_OBJECT DRM_MODE_PROP_TYPE(1) +#endif +#ifndef DRM_MODE_PROP_SIGNED_RANGE +# define DRM_MODE_PROP_SIGNED_RANGE DRM_MODE_PROP_TYPE(2) +#endif + +struct gbm_device; + +namespace Aurora { + +namespace Platform { + +class DrmOutput; + +class DrmGpu : public QObject +{ + Q_OBJECT +public: + explicit DrmGpu(const QString &path, int fd, dev_t deviceId, QObject *parent = nullptr); + ~DrmGpu(); + + int fd() const; + dev_t deviceId() const; + QString deviceNode() const; + + gbm_device *gbmDevice() const; + + bool isActive() const; + void setActive(bool value); + + bool isRemoved() const; + void setRemoved(); + + bool updateOutputs(); + +signals: + void activeChanged(bool active); + void outputAdded(DrmOutput *output); + void outputRemoved(DrmOutput *output); + +private: + QString m_deviceNode; + int m_fd = -1; + dev_t m_deviceId = -1; + gbm_device *m_gbmDevice = nullptr; + bool m_active = true; + bool m_removed = false; + bool m_hasAtomicSupport = false; + QList m_planes; +}; + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmintegration.cpp b/src/plugins/deviceintegration/drm/drmintegration.cpp new file mode 100644 index 00000000..fcc6c8f4 --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmintegration.cpp @@ -0,0 +1,116 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include "drmbackend.h" +#include "drmintegration.h" +#include "drmgpu.h" +#include "drmloggingcategories.h" +#include "drmoutput.h" +#include "drmwindow.h" + +#include + +namespace Aurora { + +namespace Platform { + +DrmIntegration::DrmIntegration(QObject *parent) + : DeviceIntegration(parent) +{ +} + +DrmIntegration::~DrmIntegration() +{ +} + +void DrmIntegration::initialize() +{ + DrmBackend::instance()->initialize(); +} + +void DrmIntegration::destroy() +{ + qCDebug(gLcDrm, "DRM device integration is about to be destroyed..."); + + DrmBackend::instance()->destroy(); + + qCInfo(gLcDrm, "DRM device integration destroyed successfully"); +} + +EGLNativeDisplayType DrmIntegration::platformDisplay() const +{ + return DrmBackend::instance()->platformDisplay(); +} + +EGLDisplay DrmIntegration::eglDisplay() const +{ + return DrmBackend::instance()->eglDisplay(); +} + +EGLNativeWindowType DrmIntegration::createNativeWindow(Window *window, const QSize &size, + const QSurfaceFormat &format) +{ + Q_UNUSED(format) + + auto *drmOutput = static_cast(window->output()); + auto *gbmDevice = DrmBackend::instance()->primaryGpu()->gbmDevice(); + auto *gbmSurface = + gbm_surface_create(gbmDevice, size.width(), size.height(), drmOutput->format(), + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + + return reinterpret_cast(gbmSurface); +} + +void DrmIntegration::destroyNativeWindow(EGLNativeWindowType nativeWindow) +{ + auto *surface = reinterpret_cast(nativeWindow); + gbm_surface_destroy(surface); +} + +QSurfaceFormat DrmIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const +{ + QSurfaceFormat format(inputFormat); + format.setRenderableType(QSurfaceFormat::OpenGLES); + format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + format.setRedBufferSize(8); + format.setGreenBufferSize(8); + format.setBlueBufferSize(8); + return format; +} + +void DrmIntegration::waitForVSync(Window *window) const +{ + Q_UNUSED(window) +} + +void DrmIntegration::presentBuffer(Window *window) +{ + Q_UNUSED(window) +} + +Window *DrmIntegration::createWindow(Output *output, QWindow *qtWindow) +{ + return nullptr; +} + +Window *DrmIntegration::getWindow(QWindow *qtWindow) const +{ + return nullptr; +} + +InputManager *DrmIntegration::createInputManager(QObject *parent) +{ + Q_UNUSED(parent) + return nullptr; +} + +Outputs DrmIntegration::outputs() const +{ + return Outputs(); +} + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmintegration.h b/src/plugins/deviceintegration/drm/drmintegration.h new file mode 100644 index 00000000..6f325337 --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmintegration.h @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +namespace Aurora { + +namespace Platform { + +class DrmWindow; + +class DrmIntegration : public DeviceIntegration +{ + Q_OBJECT +public: + explicit DrmIntegration(QObject *parent = nullptr); + ~DrmIntegration(); + + void initialize() override; + void destroy() override; + + EGLNativeDisplayType platformDisplay() const override; + EGLDisplay eglDisplay() const override; + + EGLNativeWindowType createNativeWindow(Window *window, const QSize &size, + const QSurfaceFormat &format) override; + void destroyNativeWindow(EGLNativeWindowType nativeWindow) override; + + QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const override; + + void waitForVSync(Window *window) const override; + void presentBuffer(Window *window) override; + + Window *createWindow(Output *output, QWindow *qtWindow) override; + Window *getWindow(QWindow *qtWindow) const override; + + InputManager *createInputManager(QObject *parent = nullptr) override; + + Outputs outputs() const override; +}; + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmintegrationplugin.cpp b/src/plugins/deviceintegration/drm/drmintegrationplugin.cpp new file mode 100644 index 00000000..8742cb97 --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmintegrationplugin.cpp @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "drmintegration.h" +#include "drmintegrationplugin.h" + +namespace Aurora { + +namespace Platform { + +DrmIntegrationPlugin::DrmIntegrationPlugin(QObject *parent) + : DeviceIntegrationPlugin(parent) +{ +} + +DeviceIntegration *DrmIntegrationPlugin::create() +{ + return new DrmIntegration(this); +} + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmintegrationplugin.h b/src/plugins/deviceintegration/drm/drmintegrationplugin.h new file mode 100644 index 00000000..ec9d24bf --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmintegrationplugin.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include + +namespace Aurora { + +namespace Platform { + +class DrmIntegrationPlugin : public DeviceIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "io.liri.Aurora.DeviceIntegrationPlugin/1" FILE "drm.json") +public: + explicit DrmIntegrationPlugin(QObject *parent = nullptr); + + DeviceIntegration *create() override; +}; + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmobject.cpp b/src/plugins/deviceintegration/drm/drmobject.cpp new file mode 100644 index 00000000..52005d85 --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmobject.cpp @@ -0,0 +1,109 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "drmgpu.h" +#include "drmloggingcategories.h" +#include "drmobject.h" +#include "drmpointer.h" + +#include + +namespace Aurora { + +namespace Platform { + +DrmObject::DrmObject(uint32_t id, uint32_t type, DrmGpu *gpu) + : m_id(id) + , m_type(type) + , m_gpu(gpu) +{ +} + +bool DrmObject::init() +{ + return updateProperties(); +} + +DrmPropertyList DrmObject::queryProperties() const +{ + DrmUniquePtr properties( + drmModeObjectGetProperties(m_gpu->fd(), m_id, m_type)); + if (!properties) { + qCWarning(gLcDrm) << "Failed to get properties for object" << m_id; + return {}; + } + DrmPropertyList ret; + for (uint32_t i = 0; i < properties->count_props; i++) { + DrmUniquePtr prop( + drmModeGetProperty(m_gpu->fd(), properties->props[i])); + if (!prop) { + qCWarning(gLcDrm, "Getting property %d of object %d failed!", properties->props[i], + m_id); + continue; + } + ret.addProperty(std::move(prop), properties->prop_values[i]); + } + return ret; +} + +uint32_t DrmObject::id() const +{ + return m_id; +} + +uint32_t DrmObject::type() const +{ + return m_type; +} + +QString DrmObject::typeName() const +{ + switch (m_type) { + case DRM_MODE_OBJECT_CONNECTOR: + return QStringLiteral("connector"); + case DRM_MODE_OBJECT_CRTC: + return QStringLiteral("crtc"); + case DRM_MODE_OBJECT_PLANE: + return QStringLiteral("plane"); + default: + return QStringLiteral("unknown?"); + } +} + +DrmGpu *DrmObject::gpu() const +{ + return m_gpu; +} + +void DrmPropertyList::addProperty(DrmUniquePtr &&prop, uint64_t value) +{ + m_properties.push_back(std::make_pair(std::move(prop), value)); +} + +std::optional, uint64_t>> +DrmPropertyList::takeProperty(const QByteArray &name) +{ + const auto it = std::find_if(m_properties.begin(), m_properties.end(), + [&name](const auto &pair) { return pair.first->name == name; }); + if (it != m_properties.end()) { + auto ret = std::move(*it); + m_properties.erase(it); + return ret; + } else { + return std::nullopt; + } +} + +} // namespace Platform + +} // namespace Aurora + +QDebug operator<<(QDebug s, const Aurora::Platform::DrmObject *obj) +{ + QDebugStateSaver saver(s); + if (obj) + s.nospace() << "DrmObject(id=" << obj->id() << ", gpu=" << obj->gpu() << ')'; + else + s << "DrmObject(0x0)"; + return s; +} diff --git a/src/plugins/deviceintegration/drm/drmobject.h b/src/plugins/deviceintegration/drm/drmobject.h new file mode 100644 index 00000000..305c0187 --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmobject.h @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-FileCopyrightText: 2016 Roman Gilg +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include + +#include + +#include + +#include "drmpointer.h" +#include "drmproperty.h" + +namespace Aurora { + +namespace Platform { + +class DrmAtomicCommit; +class DrmGpu; + +class DrmPropertyList +{ +public: + void addProperty(DrmUniquePtr &&prop, uint64_t value); + std::optional, uint64_t>> + takeProperty(const QByteArray &name); + +private: + std::vector, uint64_t>> m_properties; +}; + +class DrmObject +{ +public: + virtual ~DrmObject() = default; + DrmObject(const DrmObject &) = delete; + + /** + * Must be called to query necessary data directly after creation. + * @return true when initializing was successful + */ + bool init(); + + /** + * Set the properties in such a way that this resource won't be used anymore + */ + virtual void disable(DrmAtomicCommit *commit) = 0; + + virtual bool updateProperties() = 0; + + uint32_t id() const; + uint32_t type() const; + QString typeName() const; + DrmGpu *gpu() const; + +protected: + DrmObject(uint32_t id, uint32_t type, DrmGpu *gpu); + + DrmPropertyList queryProperties() const; + +private: + const uint32_t m_id; + const uint32_t m_type; + DrmGpu *m_gpu = nullptr; +}; + +} // namespace Platform + +} // namespace Aurora + +QDebug operator<<(QDebug stream, const Aurora::Platform::DrmObject *); diff --git a/src/plugins/deviceintegration/drm/drmoutput.cpp b/src/plugins/deviceintegration/drm/drmoutput.cpp new file mode 100644 index 00000000..ca8ef48f --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmoutput.cpp @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "drmoutput.h" + +namespace Aurora { + +namespace Platform { + +DrmOutput::DrmOutput(QObject *parent) + : Output(parent) +{ +} + +uint32_t DrmOutput::format() const +{ + return 0; +} + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmoutput.h b/src/plugins/deviceintegration/drm/drmoutput.h new file mode 100644 index 00000000..07f5d18f --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmoutput.h @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +namespace Aurora { + +namespace Platform { + +class DrmOutput : public Output +{ + Q_OBJECT +public: + explicit DrmOutput(QObject *parent = nullptr); + + uint32_t format() const; +}; + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmplane.cpp b/src/plugins/deviceintegration/drm/drmplane.cpp new file mode 100644 index 00000000..073ccaaf --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmplane.cpp @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "drmplane.h" + +namespace Aurora { + +namespace Platform { + +DrmPlane::DrmPlane(uint32_t id, DrmGpu *gpu) + : DrmObject(id, DRM_MODE_OBJECT_PLANE, gpu) +{ +} + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmplane.h b/src/plugins/deviceintegration/drm/drmplane.h new file mode 100644 index 00000000..17184180 --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmplane.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "drmobject.h" + +namespace Aurora { + +namespace Platform { + +class DrmPlane : public DrmObject +{ +public: + explicit DrmPlane(uint32_t id, DrmGpu *gpu); +}; + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmpointer.h b/src/plugins/deviceintegration/drm/drmpointer.h new file mode 100644 index 00000000..bfbf8d6b --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmpointer.h @@ -0,0 +1,150 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-FileCopyrightText: 2015 Martin Gräßlin +// SPDX-FileCopyrightText: 2019 Vlad Zahorodnii +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include + +namespace Aurora { + +namespace Platform { + +template +struct DrmDeleter; + +template <> +struct DrmDeleter +{ + void operator()(drmVersion *version) + { + drmFreeVersion(version); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModeAtomicReq *req) + { + drmModeAtomicFree(req); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModeConnector *connector) + { + drmModeFreeConnector(connector); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModeCrtc *crtc) + { + drmModeFreeCrtc(crtc); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModeFB *fb) + { + drmModeFreeFB(fb); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModeEncoder *encoder) + { + drmModeFreeEncoder(encoder); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModeModeInfo *info) + { + drmModeFreeModeInfo(info); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModeObjectProperties *properties) + { + drmModeFreeObjectProperties(properties); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModePlane *plane) + { + drmModeFreePlane(plane); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModePlaneRes *resources) + { + drmModeFreePlaneResources(resources); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModePropertyRes *property) + { + drmModeFreeProperty(property); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModePropertyBlobRes *blob) + { + drmModeFreePropertyBlob(blob); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModeRes *resources) + { + drmModeFreeResources(resources); + } +}; + +template <> +struct DrmDeleter +{ + void operator()(drmModeLesseeListRes *ptr) + { + drmFree(ptr); + } +}; + +template +using DrmUniquePtr = std::unique_ptr>; + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmproperty.cpp b/src/plugins/deviceintegration/drm/drmproperty.cpp new file mode 100644 index 00000000..1897f2bb --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmproperty.cpp @@ -0,0 +1,145 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-FileCopyrightText: 2016 Roman Gilg +// SPDX-FileCopyrightText: 2021-2022 Xaver Hugl +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "drmgpu.h" +#include "drmobject.h" +#include "drmproperty.h" + +#include + +namespace Aurora { + +namespace Platform { + +DrmProperty::DrmProperty(DrmObject *obj, const QByteArray &name, + const QVector &enumNames) + : m_obj(obj) + , m_propName(name) + , m_enumNames(enumNames) +{ +} + +bool DrmProperty::setPropertyLegacy(uint64_t value) +{ + if (m_current == value) { + return true; + } else if (drmModeObjectSetProperty(m_obj->gpu()->fd(), m_obj->id(), m_obj->type(), m_propId, + value) + == 0) { + m_current = value; + return true; + } else { + return false; + } +} + +void DrmProperty::update(DrmPropertyList &propertyList) +{ + if (const auto opt = propertyList.takeProperty(m_propName)) { + const auto &[prop, value] = *opt; + m_propId = prop->prop_id; + m_current = value; + m_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE; + m_isBlob = prop->flags & DRM_MODE_PROP_BLOB; + m_isBitmask = prop->flags & DRM_MODE_PROP_BITMASK; + if (prop->flags & DRM_MODE_PROP_RANGE) { + Q_ASSERT(prop->count_values > 1); + m_minValue = prop->values[0]; + m_maxValue = prop->values[1]; + } + m_enumToPropertyMap.clear(); + m_propertyToEnumMap.clear(); + // bitmasks need translation too, not just enums + if (prop->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) { + for (int i = 0; i < prop->count_enums; i++) { + struct drm_mode_property_enum *en = &prop->enums[i]; + int j = m_enumNames.indexOf(QByteArray(en->name)); + if (j >= 0) { + if (m_isBitmask) { + m_enumToPropertyMap[1 << j] = 1 << en->value; + m_propertyToEnumMap[1 << en->value] = 1 << j; + } else { + m_enumToPropertyMap[j] = en->value; + m_propertyToEnumMap[en->value] = j; + } + } + } + } + if (m_immutable && m_isBlob) { + if (m_current != 0) { + m_immutableBlob.reset(drmModeGetPropertyBlob(m_obj->gpu()->fd(), m_current)); + if (m_immutableBlob && (!m_immutableBlob->data || !m_immutableBlob->length)) { + m_immutableBlob.reset(); + } + } else { + m_immutableBlob.reset(); + } + } + } else { + m_propId = 0; + m_immutableBlob.reset(); + m_enumToPropertyMap.clear(); + m_propertyToEnumMap.clear(); + } +} + +uint64_t DrmProperty::value() const +{ + return m_current; +} + +bool DrmProperty::hasAllEnums() const +{ + return m_enumToPropertyMap.count() == m_enumNames.count(); +} + +uint32_t DrmProperty::propId() const +{ + return m_propId; +} + +const QByteArray &DrmProperty::name() const +{ + return m_propName; +} + +bool DrmProperty::isImmutable() const +{ + return m_immutable; +} + +bool DrmProperty::isBitmask() const +{ + return m_isBitmask; +} + +uint64_t DrmProperty::minValue() const +{ + return m_minValue; +} + +uint64_t DrmProperty::maxValue() const +{ + return m_maxValue; +} + +drmModePropertyBlobRes *DrmProperty::immutableBlob() const +{ + return m_immutableBlob.get(); +} + +DrmObject *DrmProperty::drmObject() const +{ + return m_obj; +} + +bool DrmProperty::isValid() const +{ + return m_propId != 0; +} + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmproperty.h b/src/plugins/deviceintegration/drm/drmproperty.h new file mode 100644 index 00000000..643127b8 --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmproperty.h @@ -0,0 +1,135 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-FileCopyrightText: 2016 Roman Gilg +// SPDX-FileCopyrightText: 2021-2022 Xaver Hugl +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include + +#include + +#include "drmpointer.h" + +namespace Aurora { + +namespace Platform { + +class DrmObject; +class DrmPropertyList; + +class DrmProperty +{ +public: + DrmProperty(DrmObject *obj, const QByteArray &name, const QVector &enumNames = {}); + + const QByteArray &name() const; + DrmObject *drmObject() const; + + uint32_t propId() const; + bool isImmutable() const; + bool isBitmask() const; + bool hasAllEnums() const; + uint64_t value() const; + drmModePropertyBlobRes *immutableBlob() const; + uint64_t minValue() const; + uint64_t maxValue() const; + bool isValid() const; + + void update(DrmPropertyList &propertyList); + bool setPropertyLegacy(uint64_t value); + +protected: + DrmObject *const m_obj; + const QByteArray m_propName; + const QVector m_enumNames; + + uint32_t m_propId = 0; + // the last known value from the kernel + uint64_t m_current = 0; + DrmUniquePtr m_immutableBlob; + + uint64_t m_minValue = -1; + uint64_t m_maxValue = -1; + + QMap m_enumToPropertyMap; + QMap m_propertyToEnumMap; + bool m_immutable = false; + bool m_isBlob = false; + bool m_isBitmask = false; +}; + +template +class DrmEnumProperty : public DrmProperty +{ +public: + DrmEnumProperty(DrmObject *obj, const QByteArray &name, const QVector &enumNames) + : DrmProperty(obj, name, enumNames) + { + } + + Enum enumValue() const + { + return enumForValue(value()); + } + + bool hasEnum(Enum value) const + { + const uint64_t integerValue = static_cast(value); + if (m_isBitmask) { + for (uint64_t mask = 1; integerValue >= mask && mask != 0; mask <<= 1) { + if ((integerValue & mask) && !m_enumToPropertyMap.contains(mask)) { + return false; + } + } + return true; + } else { + return m_enumToPropertyMap.contains(integerValue); + } + } + + Enum enumForValue(uint64_t value) const + { + if (m_isBitmask) { + uint64_t ret = 0; + for (uint64_t mask = 1; value >= mask && mask != 0; mask <<= 1) { + if (value & mask) { + ret |= m_propertyToEnumMap[mask]; + } + } + return static_cast(ret); + } else { + return static_cast(m_propertyToEnumMap[value]); + } + } + + uint64_t valueForEnum(Enum enumValue) const + { + const uint64_t integer = static_cast(enumValue); + if (m_isBitmask) { + uint64_t set = 0; + for (uint64_t mask = 1; integer >= mask && mask != 0; mask <<= 1) { + if (integer & mask) { + set |= m_enumToPropertyMap[mask]; + } + } + return set; + } else { + return m_enumToPropertyMap[integer]; + } + } + + bool setEnumLegacy(Enum value) + { + if (hasEnum(value)) + return setPropertyLegacy(valueForEnum(value)); + else + return false; + } +}; + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmwindow.cpp b/src/plugins/deviceintegration/drm/drmwindow.cpp new file mode 100644 index 00000000..0a1c13e3 --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmwindow.cpp @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "drmcursor.h" +#include "drmwindow.h" + +namespace Aurora { + +namespace Platform { + +DrmWindow::DrmWindow(DrmOutput *output, QWindow *qtWindow, QObject *parent) + : Window(output, qtWindow, parent) + , m_cursor(new DrmCursor(this)) +{ +} + +} // namespace Platform + +} // namespace Aurora diff --git a/src/plugins/deviceintegration/drm/drmwindow.h b/src/plugins/deviceintegration/drm/drmwindow.h new file mode 100644 index 00000000..0e845d46 --- /dev/null +++ b/src/plugins/deviceintegration/drm/drmwindow.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include "drmoutput.h" + +namespace Aurora { + +namespace Platform { + +class DrmCursor; + +class DrmWindow : public Window +{ + Q_OBJECT +public: + explicit DrmWindow(DrmOutput *output, QWindow *qtWindow, QObject *parent = nullptr); + +private: + DrmCursor *m_cursor = nullptr; +}; + +} // namespace Platform + +} // namespace Aurora