drm: check syncobj timeline support before advertising protocol (#11117)

Prevents crashes on systems where DRM driver lacks syncobj timeline
support (e.g., Apple Silicon with Honeykrisp driver). Applications
like Zed and WezTerm would crash with 'Timeline failed importing'
when trying to use explicit sync.

Fixes #8158 #8803

---------

Co-authored-by: mvonarx <matthias.vonarx@sitrox.com>
This commit is contained in:
mavonarx 2025-07-23 23:11:07 +02:00 committed by GitHub
parent c51c6e38ac
commit ecc04e8ba7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 33 additions and 2 deletions

View file

@ -73,6 +73,7 @@
#include <sys/resource.h> #include <sys/resource.h>
#include <malloc.h> #include <malloc.h>
#include <unistd.h> #include <unistd.h>
#include <xf86drm.h>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Aquamarine; using namespace Aquamarine;
@ -167,6 +168,10 @@ void CCompositor::restoreNofile() {
Debug::log(ERR, "Failed restoring NOFILE limits"); Debug::log(ERR, "Failed restoring NOFILE limits");
} }
bool CCompositor::supportsDrmSyncobjTimeline() const {
return m_bDrmSyncobjTimelineSupported;
}
void CCompositor::setMallocThreshold() { void CCompositor::setMallocThreshold() {
#ifdef M_TRIM_THRESHOLD #ifdef M_TRIM_THRESHOLD
// The default is 128 pages, // The default is 128 pages,
@ -354,6 +359,16 @@ void CCompositor::initServer(std::string socketName, int socketFd) {
m_drmFD = m_aqBackend->drmFD(); m_drmFD = m_aqBackend->drmFD();
Debug::log(LOG, "Running on DRMFD: {}", m_drmFD); Debug::log(LOG, "Running on DRMFD: {}", m_drmFD);
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)");
}
if (!socketName.empty() && socketFd != -1) { if (!socketName.empty() && socketFd != -1) {
fcntl(socketFd, F_SETFD, FD_CLOEXEC); fcntl(socketFd, F_SETFD, FD_CLOEXEC);
const auto RETVAL = wl_display_add_socket_fd(m_wlDisplay, socketFd); const auto RETVAL = wl_display_add_socket_fd(m_wlDisplay, socketFd);

View file

@ -152,6 +152,7 @@ class CCompositor {
NColorManagement::SImageDescription getPreferredImageDescription(); NColorManagement::SImageDescription getPreferredImageDescription();
bool shouldChangePreferredImageDescription(); bool shouldChangePreferredImageDescription();
bool supportsDrmSyncobjTimeline() const;
std::string m_explicitConfigPath; std::string m_explicitConfigPath;
private: private:
@ -165,6 +166,8 @@ class CCompositor {
void removeLockFile(); void removeLockFile();
void setMallocThreshold(); void setMallocThreshold();
bool m_bDrmSyncobjTimelineSupported = false;
uint64_t m_hyprlandPID = 0; uint64_t m_hyprlandPID = 0;
wl_event_source* m_critSigSource = nullptr; wl_event_source* m_critSigSource = nullptr;
rlimit m_originalNofile = {}; rlimit m_originalNofile = {};

View file

@ -1,12 +1,16 @@
#include "SyncTimeline.hpp" #include "SyncTimeline.hpp"
#include "../../defines.hpp" #include "../../defines.hpp"
#include "../../managers/eventLoop/EventLoopManager.hpp" #include "../../managers/eventLoop/EventLoopManager.hpp"
#include "../../Compositor.hpp"
#include <xf86drm.h> #include <xf86drm.h>
#include <sys/eventfd.h> #include <sys/eventfd.h>
using namespace Hyprutils::OS; using namespace Hyprutils::OS;
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_) { SP<CSyncTimeline> CSyncTimeline::create(int drmFD_) {
if (!g_pCompositor->supportsDrmSyncobjTimeline())
return nullptr;
auto timeline = SP<CSyncTimeline>(new CSyncTimeline); auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
timeline->m_drmFD = drmFD_; timeline->m_drmFD = drmFD_;
timeline->m_self = timeline; timeline->m_self = timeline;
@ -20,6 +24,9 @@ SP<CSyncTimeline> CSyncTimeline::create(int drmFD_) {
} }
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, CFileDescriptor&& drmSyncobjFD) { SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, CFileDescriptor&& drmSyncobjFD) {
if (!g_pCompositor->supportsDrmSyncobjTimeline())
return nullptr;
auto timeline = SP<CSyncTimeline>(new CSyncTimeline); auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
timeline->m_drmFD = drmFD_; timeline->m_drmFD = drmFD_;
timeline->m_syncobjFD = std::move(drmSyncobjFD); timeline->m_syncobjFD = std::move(drmSyncobjFD);

View file

@ -70,6 +70,7 @@
#include "content-type-v1.hpp" #include "content-type-v1.hpp"
#include <aquamarine/buffer/Buffer.hpp> #include <aquamarine/buffer/Buffer.hpp>
#include <xf86drm.h>
#include <aquamarine/backend/Backend.hpp> #include <aquamarine/backend/Backend.hpp>
#include <hyprutils/memory/UniquePtr.hpp> #include <hyprutils/memory/UniquePtr.hpp>
@ -210,8 +211,13 @@ CProtocolManager::CProtocolManager() {
else else
lease.reset(); lease.reset();
if (g_pHyprOpenGL->m_exts.EGL_ANDROID_native_fence_sync_ext && !PROTO::sync) if (g_pHyprOpenGL->m_exts.EGL_ANDROID_native_fence_sync_ext && !PROTO::sync) {
PROTO::sync = makeUnique<CDRMSyncobjProtocol>(&wp_linux_drm_syncobj_manager_v1_interface, 1, "DRMSyncobj"); if (g_pCompositor->supportsDrmSyncobjTimeline()) {
PROTO::sync = makeUnique<CDRMSyncobjProtocol>(&wp_linux_drm_syncobj_manager_v1_interface, 1, "DRMSyncobj");
Debug::log(LOG, "DRM Syncobj Timeline support detected, enabling explicit sync protocol");
} else
Debug::log(WARN, "DRM Syncobj Timeline not supported, skipping explicit sync protocol");
}
} }
if (!g_pHyprOpenGL->getDRMFormats().empty()) { if (!g_pHyprOpenGL->getDRMFormats().empty()) {