3
0
mirror of https://github.com/hyprwm/Hyprland.git synced 2025-10-29 19:34:47 +00:00

syncobj: use rendernode for timelines (#11087)

* syncobj: use rendernode for timelines

use rendernode for timelines instead of the drmfd, some devices dont
support to use the drmfd for this.

* opengl: use rendernode if available

use rendernode if available for CHyprOpenglImpl

* MesaDRM: use the m_drmRenderNodeFD if it exist

try use the rendernode we got from AQ if it exist.

* linuxdmabuf: use rendernode if available

use the rendernode if available already from AQ

* syncobj: prefer rendernode over displaynode

prefer the rendernode over the displaynode, and log a error if
attempting to use the protocol without explicit sync support on any of
the nodes.

* syncobj: check support on both nodes always

check support on both nodes always so it can be used later for
preferring rendernode if possible in syncobj protocol.

* syncobj: remove old var in non linux if else case

remove old m_bDrmSyncobjTimelineSupported from non linux if else case
that will fail to compile on non linux. the nodes sets support by
default to false, and if non linux it wont check for support and set it
to true.

* build: bump aq requirement

bump to 0.9.3 where rendernode support got added.

* flake.lock: update

* renderer: glfinish on software renderer

software renderers apparently bug out on implicit sync, use glfinish as
with nvidia case on implicit paths.

* flake.lock: update

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
This commit is contained in:
Tom Englund 2025-08-24 22:32:13 +02:00 committed by GitHub
parent ced38b1b0f
commit b329ea8e96
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 107 additions and 59 deletions

View File

@ -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)

36
flake.lock generated
View File

@ -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": {

View File

@ -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')

View File

@ -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) {

View File

@ -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<Aquamarine::CBackend> 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 = {};

View File

@ -432,7 +432,7 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
options.length = 2;
options.scanout = true;
options.cursor = true;
options.multigpu = state->monitor->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)

View File

@ -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<CDRMSyncobjManagerResource>(makeUnique<CWpLinuxDrmSyncobjManagerV1>(client, ver, id)));

View File

@ -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)};

View File

@ -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);
}

View File

@ -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);

View File

@ -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<void()>& 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;
}

View File

@ -75,6 +75,7 @@ class CHyprRenderer {
SP<CRenderbuffer> 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 {