diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,6 +177,10 @@ if (Libinput_FOUND AND UDEV_FOUND) set(HAVE_INPUT TRUE) endif() +set(HAVE_UDEV FALSE) +if (UDEV_FOUND) + set(HAVE_UDEV TRUE) +endif() find_package(Libdrm) set_package_properties(Libdrm PROPERTIES TYPE OPTIONAL PURPOSE "Required for drm output on Wayland.") diff --git a/config-kwin.h.cmake b/config-kwin.h.cmake --- a/config-kwin.h.cmake +++ b/config-kwin.h.cmake @@ -21,6 +21,7 @@ #cmakedefine01 HAVE_SYS_PROCCTL_H #cmakedefine01 HAVE_PROC_TRACE_CTL #cmakedefine01 HAVE_BREEZE_DECO +#cmakedefine01 HAVE_UDEV #if HAVE_BREEZE_DECO #define BREEZE_KDECORATION_PLUGIN_ID "${BREEZE_KDECORATION_PLUGIN_ID}" #endif diff --git a/plugins/platforms/virtual/CMakeLists.txt b/plugins/platforms/virtual/CMakeLists.txt --- a/plugins/platforms/virtual/CMakeLists.txt +++ b/plugins/platforms/virtual/CMakeLists.txt @@ -5,9 +5,16 @@ screens_virtual.cpp ) +include(ECMQtDeclareLoggingCategory) +ecm_qt_declare_logging_category(VIRTUAL_SOURCES HEADER logging.h IDENTIFIER KWIN_VIRTUAL CATEGORY_NAME kwin_platform_virtual DEFAULT_SEVERITY Critical) + add_library(KWinWaylandVirtualBackend MODULE ${VIRTUAL_SOURCES}) target_link_libraries(KWinWaylandVirtualBackend kwin) +if(HAVE_GBM) + target_link_libraries(KWinWaylandVirtualBackend gbm::gbm) +endif() + install( TARGETS KWinWaylandVirtualBackend diff --git a/plugins/platforms/virtual/egl_gbm_backend.h b/plugins/platforms/virtual/egl_gbm_backend.h --- a/plugins/platforms/virtual/egl_gbm_backend.h +++ b/plugins/platforms/virtual/egl_gbm_backend.h @@ -21,6 +21,11 @@ #define KWIN_EGL_GBM_BACKEND_H #include "abstract_egl_backend.h" #include "scene_opengl.h" +#include + +#if HAVE_GBM +struct gbm_device; +#endif namespace KWin { @@ -51,10 +56,15 @@ bool initializeEgl(); bool initBufferConfigs(); bool initRenderingContext(); + void initGbmDevice(); VirtualBackend *m_backend; GLTexture *m_backBuffer = nullptr; GLRenderTarget *m_fbo = nullptr; int m_frameCounter = 0; +#if HAVE_GBM + gbm_device *m_device = nullptr; +#endif + int m_drmFd = -1; friend class EglGbmTexture; }; diff --git a/plugins/platforms/virtual/egl_gbm_backend.cpp b/plugins/platforms/virtual/egl_gbm_backend.cpp --- a/plugins/platforms/virtual/egl_gbm_backend.cpp +++ b/plugins/platforms/virtual/egl_gbm_backend.cpp @@ -23,10 +23,20 @@ #include "virtual_backend.h" #include "options.h" #include "screens.h" +#if HAVE_UDEV +#include "udev.h" +#endif +#include // kwin libs #include // Qt #include +// system +#include +#include +#if HAVE_GBM +#include +#endif namespace KWin { @@ -48,6 +58,47 @@ delete m_fbo; delete m_backBuffer; cleanup(); +#if HAVE_GBM + if (m_device) { + gbm_device_destroy(m_device); + } +#endif + if (m_drmFd != -1) { + close(m_drmFd); + } +} + +void EglGbmBackend::initGbmDevice() +{ +#if HAVE_UDEV + if (m_drmFd != -1) { + // already initialized + return; + } + QScopedPointer udev(new Udev); + UdevDevice::Ptr device = udev->renderNode(); + if (!device) { + // if we don't have a render node, try to find a virtual (vgem) device + qCDebug(KWIN_VIRTUAL) << "No render node, looking for a vgem device"; + device = udev->virtualGpu(); + } + if (!device) { + qCDebug(KWIN_VIRTUAL) << "Neither a render node, nor a vgem device found"; + return; + } + qCDebug(KWIN_VIRTUAL) << "Found a device: " << device->devNode(); + m_drmFd = open(device->devNode(), O_RDWR | O_CLOEXEC); + if (m_drmFd == -1) { + qCWarning(KWIN_VIRTUAL) << "Failed to open: " << device->devNode(); + return; + } +#if HAVE_GBM + m_device = gbm_create_device(m_drmFd); + if (!m_device) { + qCWarning(KWIN_VIRTUAL) << "Failed to open gbm device"; + } +#endif +#endif } bool EglGbmBackend::initializeEgl() @@ -64,7 +115,17 @@ return false; } - display = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, EGL_DEFAULT_DISPLAY, nullptr); +#if HAVE_GBM + initGbmDevice(); + if (m_device) { + display = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, m_device, nullptr); + } +#endif + + if (display == EGL_NO_DISPLAY) { + qCWarning(KWIN_VIRTUAL) << "Failed to create EGLDisplay through GBM device, trying with default device"; + display = eglGetPlatformDisplay(EGL_PLATFORM_GBM_MESA, EGL_DEFAULT_DISPLAY, nullptr); + } } if (display == EGL_NO_DISPLAY) diff --git a/udev.h b/udev.h --- a/udev.h +++ b/udev.h @@ -83,6 +83,8 @@ return m_udev != nullptr; } UdevDevice::Ptr primaryGpu(); + UdevDevice::Ptr virtualGpu(); + UdevDevice::Ptr renderNode(); UdevDevice::Ptr deviceFromSyspath(const char *syspath); UdevMonitor *monitor(); operator udev*() const { diff --git a/udev.cpp b/udev.cpp --- a/udev.cpp +++ b/udev.cpp @@ -148,6 +148,36 @@ }); } +UdevDevice::Ptr Udev::virtualGpu() +{ + if (!m_udev) { + return UdevDevice::Ptr(); + } + UdevEnumerate enumerate(this); + enumerate.addMatch(UdevEnumerate::Match::SubSystem, "drm"); + enumerate.addMatch(UdevEnumerate::Match::SysName, "card[0-9]*"); + enumerate.scan(); + return enumerate.find([](const UdevDevice::Ptr &device) { + const QByteArray deviceName(udev_device_get_syspath(*device)); + return deviceName.contains("virtual"); + }); +} + +UdevDevice::Ptr Udev::renderNode() +{ + if (!m_udev) { + return UdevDevice::Ptr(); + } + UdevEnumerate enumerate(this); + enumerate.addMatch(UdevEnumerate::Match::SubSystem, "drm"); + enumerate.addMatch(UdevEnumerate::Match::SysName, "renderD[0-9]*"); + enumerate.scan(); + return enumerate.find([](const UdevDevice::Ptr &device) { + Q_UNUSED(device) + return true; + }); +} + UdevDevice::Ptr Udev::deviceFromSyspath(const char *syspath) { return std::move(UdevDevice::Ptr(new UdevDevice(udev_device_new_from_syspath(m_udev, syspath))));