diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d053742..643f7dc6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,7 +105,7 @@ find_package(Threads REQUIRED) set(GLES_VERSION "GLES3") find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) -pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.9.0) +pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.9.3) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.8.2) diff --git a/flake.lock b/flake.lock index 13254efb..62d536ef 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1753216019, - "narHash": "sha256-zik7WISrR1ks2l6T1MZqZHb/OqroHdJnSnAehkE0kCk=", + "lastModified": 1755632680, + "narHash": "sha256-EjaD8+d7AiAV2fGRN4NTMboWDwk8szDfwbzZ8DL1PhQ=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "be166e11d86ba4186db93e10c54a141058bdce49", + "rev": "50637ed23e962f0db294d6b0ef534f37b144644b", "type": "github" }, "original": { @@ -238,11 +238,11 @@ ] }, "locked": { - "lastModified": 1754481650, - "narHash": "sha256-6u6HdEFJh5gY6VfyMQbhP7zDdVcqOrCDTkbiHJmAtMI=", + "lastModified": 1755416120, + "narHash": "sha256-PosTxeL39YrLvCX5MqqPA6NNWQ4T5ea5K55nmN7ju9Q=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "df6b8820c4a0835d83d0c7c7be86fbc555f1f7fd", + "rev": "e631ea36ddba721eceda69bfee6dd01068416489", "type": "github" }, "original": { @@ -261,11 +261,11 @@ ] }, "locked": { - "lastModified": 1751897909, - "narHash": "sha256-FnhBENxihITZldThvbO7883PdXC/2dzW4eiNvtoV5Ao=", + "lastModified": 1755184602, + "narHash": "sha256-RCBQN8xuADB0LEgaKbfRqwm6CdyopE1xIEhNc67FAbw=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "fcca0c61f988a9d092cbb33e906775014c61579d", + "rev": "b3b0f1f40ae09d4447c20608e5a4faf8bf3c492d", "type": "github" }, "original": { @@ -276,11 +276,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1754725699, - "narHash": "sha256-iAcj9T/Y+3DBy2J0N+yF9XQQQ8IEb5swLFzs23CdP88=", + "lastModified": 1755186698, + "narHash": "sha256-wNO3+Ks2jZJ4nTHMuks+cxAiVBGNuEBXsT29Bz6HASo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "85dbfc7aaf52ecb755f87e577ddbe6dbbdbc1054", + "rev": "fbcf476f790d8a217c3eab4e12033dc4a0f6d23c", "type": "github" }, "original": { @@ -299,11 +299,11 @@ ] }, "locked": { - "lastModified": 1754416808, - "narHash": "sha256-c6yg0EQ9xVESx6HGDOCMcyRSjaTpNJP10ef+6fRcofA=", + "lastModified": 1755446520, + "narHash": "sha256-I0Ok1OGDwc1jPd8cs2VvAYZsHriUVFGIUqW+7uSsOUM=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "9c52372878df6911f9afc1e2a1391f55e4dfc864", + "rev": "4b04db83821b819bbbe32ed0a025b31e7971f22e", "type": "github" }, "original": { @@ -365,11 +365,11 @@ ] }, "locked": { - "lastModified": 1753633878, - "narHash": "sha256-js2sLRtsOUA/aT10OCDaTjO80yplqwOIaLUqEe0nMx0=", + "lastModified": 1755354946, + "narHash": "sha256-zdov5f/GcoLQc9qYIS1dUTqtJMeDqmBmo59PAxze6e4=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "371b96bd11ad2006ed4f21229dbd1be69bed3e8a", + "rev": "a10726d6a8d0ef1a0c645378f983b6278c42eaa0", "type": "github" }, "original": { diff --git a/meson.build b/meson.build index e2b520d3..6b04ff9a 100644 --- a/meson.build +++ b/meson.build @@ -31,7 +31,7 @@ if cpp_compiler.check_header('execinfo.h') add_project_arguments('-DHAS_EXECINFO', language: 'cpp') endif -aquamarine = dependency('aquamarine', version: '>=0.9.0') +aquamarine = dependency('aquamarine', version: '>=0.9.3') hyprcursor = dependency('hyprcursor', version: '>=0.1.7') hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.3') hyprlang = dependency('hyprlang', version: '>= 0.3.2') diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a2733042..cbb70e2b 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -169,7 +169,7 @@ void CCompositor::restoreNofile() { } bool CCompositor::supportsDrmSyncobjTimeline() const { - return m_bDrmSyncobjTimelineSupported; + return m_drm.syncobjSupport || m_drmRenderNode.syncObjSupport; } void CCompositor::setMallocThreshold() { @@ -356,22 +356,32 @@ void CCompositor::initServer(std::string socketName, int socketFd) { m_initialized = true; - m_drmFD = m_aqBackend->drmFD(); - Debug::log(LOG, "Running on DRMFD: {}", m_drmFD); + m_drm.fd = m_aqBackend->drmFD(); + Debug::log(LOG, "Running on DRMFD: {}", m_drm.fd); + + m_drmRenderNode.fd = m_aqBackend->drmRenderNodeFD(); + Debug::log(LOG, "Using RENDERNODEFD: {}", m_drmRenderNode.fd); #if defined(__linux__) - if (m_drmFD >= 0) { - uint64_t cap = 0; - int ret = drmGetCap(m_drmFD, DRM_CAP_SYNCOBJ_TIMELINE, &cap); - m_bDrmSyncobjTimelineSupported = (ret == 0 && cap != 0); - Debug::log(LOG, "DRM syncobj timeline support: {}", m_bDrmSyncobjTimelineSupported ? "yes" : "no"); - } else { - m_bDrmSyncobjTimelineSupported = false; - Debug::log(LOG, "DRM syncobj timeline support: no (no DRM FD)"); - } + auto syncObjSupport = [](auto fd) { + if (fd < 0) + return false; + + uint64_t cap = 0; + int ret = drmGetCap(fd, DRM_CAP_SYNCOBJ_TIMELINE, &cap); + return ret == 0 && cap != 0; + }; + + if ((m_drm.syncobjSupport = syncObjSupport(m_drm.fd))) + Debug::log(LOG, "DRM DisplayNode syncobj timeline support: {}", m_drm.syncobjSupport ? "yes" : "no"); + + if ((m_drmRenderNode.syncObjSupport = syncObjSupport(m_drmRenderNode.fd))) + Debug::log(LOG, "DRM RenderNode syncobj timeline support: {}", m_drmRenderNode.syncObjSupport ? "yes" : "no"); + + if (!m_drm.syncobjSupport && !m_drmRenderNode.syncObjSupport) + Debug::log(LOG, "DRM no syncobj support, disabling explicit sync"); #else Debug::log(LOG, "DRM syncobj timeline support: no (not linux)"); - m_bDrmSyncobjTimelineSupported = false; #endif if (!socketName.empty() && socketFd != -1) { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 70b18691..eddbe677 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -27,9 +27,18 @@ class CCompositor { CCompositor(bool onlyConfig = false); ~CCompositor(); - wl_display* m_wlDisplay = nullptr; - wl_event_loop* m_wlEventLoop = nullptr; - int m_drmFD = -1; + wl_display* m_wlDisplay = nullptr; + wl_event_loop* m_wlEventLoop = nullptr; + struct { + int fd = -1; + bool syncobjSupport = false; + } m_drm; + + struct { + int fd = -1; + bool syncObjSupport = false; + } m_drmRenderNode; + bool m_initialized = false; SP m_aqBackend; @@ -175,8 +184,6 @@ class CCompositor { void removeLockFile(); void setMallocThreshold(); - bool m_bDrmSyncobjTimelineSupported = false; - uint64_t m_hyprlandPID = 0; wl_event_source* m_critSigSource = nullptr; rlimit m_originalNofile = {}; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 318ec343..f5635810 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -432,7 +432,7 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->m_output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_drmFD; + options.multigpu = state->monitor->m_output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_drm.fd; // We do not set the format (unless shm). If it's unset (DRM_FORMAT_INVALID) then the swapchain will pick for us, // but if it's set, we don't wanna change it. if (shouldUseCpuBuffer) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index bedec422..0896b904 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -199,8 +199,18 @@ bool CDRMSyncobjManagerResource::good() { return m_resource->resource(); } -CDRMSyncobjProtocol::CDRMSyncobjProtocol(const wl_interface* iface, const int& ver, const std::string& name) : - IWaylandProtocol(iface, ver, name), m_drmFD(g_pCompositor->m_drmFD) {} +CDRMSyncobjProtocol::CDRMSyncobjProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + if (g_pCompositor->m_drmRenderNode.syncObjSupport) + m_drmFD = g_pCompositor->m_drmRenderNode.fd; + else if (g_pCompositor->m_drm.syncobjSupport) + m_drmFD = g_pCompositor->m_drm.fd; + else { + LOGM(ERR, "CDRMSyncobjProtocol: no nodes support explicit sync?"); + return; + } + + LOGM(LOG, "CDRMSyncobjProtocol: using fd {}", m_drmFD); +} void CDRMSyncobjProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto& RESOURCE = m_managers.emplace_back(makeUnique(makeUnique(client, ver, id))); diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 24cf2951..c7de03a2 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -408,7 +408,7 @@ void CLinuxDMABUFResource::sendMods() { CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("ready", [this](void* self, SCallbackInfo& info, std::any d) { - int rendererFD = g_pCompositor->m_drmFD; + int rendererFD = g_pCompositor->m_drmRenderNode.fd >= 0 ? g_pCompositor->m_drmRenderNode.fd : g_pCompositor->m_drm.fd; auto dev = devIDFromFD(rendererFD); if (!dev.has_value()) { @@ -467,6 +467,19 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const return; } + if (g_pCompositor->m_drmRenderNode.fd >= 0 && rendererFD == g_pCompositor->m_drmRenderNode.fd) { + // Already using the compositor's render node, reuse it. + m_mainDeviceFD = CFileDescriptor{fcntl(g_pCompositor->m_drmRenderNode.fd, F_DUPFD_CLOEXEC, 0)}; + drmFreeDevice(&device); + if (!m_mainDeviceFD.isValid()) { + LOGM(ERR, "failed to open rendernode, disabling linux dmabuf"); + removeGlobal(); + return; + } + + return; // already using rendernode. + } + if (device->available_nodes & (1 << DRM_NODE_RENDER)) { const char* name = device->nodes[DRM_NODE_RENDER]; m_mainDeviceFD = CFileDescriptor{open(name, O_RDWR | O_CLOEXEC)}; diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp index 45ee24c5..789f90b6 100644 --- a/src/protocols/MesaDRM.cpp +++ b/src/protocols/MesaDRM.cpp @@ -113,28 +113,26 @@ bool CMesaDRMResource::good() { CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { drmDevice* dev = nullptr; - int drmFD = g_pCompositor->m_drmFD; + int drmFD = g_pCompositor->m_drmRenderNode.fd >= 0 ? g_pCompositor->m_drmRenderNode.fd : g_pCompositor->m_drm.fd; + if (drmGetDevice2(drmFD, 0, &dev) != 0) { - LOGM(ERR, "Failed to get device, disabling MesaDRM"); + LOGM(ERR, "Failed to get device from fd {}, disabling MesaDRM", drmFD); removeGlobal(); return; } - if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { + if (dev->available_nodes & (1 << DRM_NODE_RENDER) && dev->nodes[DRM_NODE_RENDER]) { m_nodeName = dev->nodes[DRM_NODE_RENDER]; - } else { - ASSERT(dev->available_nodes & (1 << DRM_NODE_PRIMARY)); - - if (!dev->nodes[DRM_NODE_PRIMARY]) { - LOGM(ERR, "No DRM render node available, both render and primary are null, disabling MesaDRM"); - drmFreeDevice(&dev); - removeGlobal(); - return; - } - + } else if (dev->available_nodes & (1 << DRM_NODE_PRIMARY) && dev->nodes[DRM_NODE_PRIMARY]) { LOGM(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); m_nodeName = dev->nodes[DRM_NODE_PRIMARY]; + } else { + LOGM(ERR, "No usable DRM node (render or primary) found, disabling MesaDRM"); + drmFreeDevice(&dev); + removeGlobal(); + return; } + drmFreeDevice(&dev); } diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 27abe81f..f4599a84 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -254,7 +254,7 @@ EGLDeviceEXT CHyprOpenGLImpl::eglDeviceFromDRMFD(int drmFD) { return EGL_NO_DEVICE_EXT; } -CHyprOpenGLImpl::CHyprOpenGLImpl() : m_drmFD(g_pCompositor->m_drmFD) { +CHyprOpenGLImpl::CHyprOpenGLImpl() : m_drmFD(g_pCompositor->m_drmRenderNode.fd >= 0 ? g_pCompositor->m_drmRenderNode.fd : g_pCompositor->m_drm.fd) { const std::string EGLEXTENSIONS = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); Debug::log(LOG, "Supported EGL global extensions: ({}) {}", std::ranges::count(EGLEXTENSIONS, ' '), EGLEXTENSIONS); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index beeb0f5a..cf8ed0ba 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -69,6 +69,8 @@ CHyprRenderer::CHyprRenderer() { m_nvidia = true; else if (name.contains("i915")) m_intel = true; + else if (name.contains("softpipe") || name.contains("Software Rasterizer") || name.contains("llvmpipe")) + m_software = true; Debug::log(LOG, "DRM driver information: {} v{}.{}.{} from {} description {}", name, DRMV->version_major, DRMV->version_minor, DRMV->version_patchlevel, std::string{DRMV->date, DRMV->date_len}, std::string{DRMV->desc, DRMV->desc_len}); @@ -79,7 +81,7 @@ CHyprRenderer::CHyprRenderer() { } else { Debug::log(LOG, "Aq backend has no session, omitting full DRM node checks"); - const auto DRMV = drmGetVersion(g_pCompositor->m_drmFD); + const auto DRMV = drmGetVersion(g_pCompositor->m_drm.fd); if (DRMV) { std::string name = std::string{DRMV->name, DRMV->name_len}; @@ -89,6 +91,8 @@ CHyprRenderer::CHyprRenderer() { m_nvidia = true; else if (name.contains("i915")) m_intel = true; + else if (name.contains("softpipe") || name.contains("Software Rasterizer") || name.contains("llvmpipe")) + m_software = true; Debug::log(LOG, "Primary DRM driver information: {} v{}.{}.{} from {} description {}", name, DRMV->version_major, DRMV->version_minor, DRMV->version_patchlevel, std::string{DRMV->date, DRMV->date_len}, std::string{DRMV->desc, DRMV->desc_len}); @@ -2234,8 +2238,8 @@ void CHyprRenderer::endRender(const std::function& renderingDoneCallback if (!g_pHyprOpenGL->explicitSyncSupported()) { Debug::log(TRACE, "renderer: Explicit sync unsupported, falling back to implicit in endRender"); - // nvidia doesn't have implicit sync, so we have to explicitly wait here - if (isNvidia() && *PNVIDIAANTIFLICKER) + // nvidia doesn't have implicit sync, so we have to explicitly wait here, llvmpipe and other software renderer seems to bug out aswell. + if ((isNvidia() && *PNVIDIAANTIFLICKER) || isSoftware()) glFinish(); else glFlush(); // mark an implicit sync point @@ -2295,6 +2299,10 @@ bool CHyprRenderer::isIntel() { return m_intel; } +bool CHyprRenderer::isSoftware() { + return m_software; +} + bool CHyprRenderer::isMgpu() { return m_mgpu; } diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index a986b63b..b1e514f3 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -75,6 +75,7 @@ class CHyprRenderer { SP getCurrentRBO(); bool isNvidia(); bool isIntel(); + bool isSoftware(); bool isMgpu(); void makeEGLCurrent(); void unsetEGL(); @@ -143,6 +144,7 @@ class CHyprRenderer { eRenderMode m_renderMode = RENDER_MODE_NORMAL; bool m_nvidia = false; bool m_intel = false; + bool m_software = false; bool m_mgpu = false; struct {