diff --git a/app/masterhook.c b/app/masterhook.c index 5ea02c82..3b3387dd 100644 --- a/app/masterhook.c +++ b/app/masterhook.c @@ -42,6 +42,7 @@ uint32_t* g_QtCrtcConnectors; int g_QtCrtcConnectorCount; bool removeSdlFd(int fd); +int takeMasterFromSdlFd(void); int drmIsMaster(int fd) { @@ -78,6 +79,24 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, return err; } +// This hook will temporarily retake DRM master to allow Qt to render while SDL has a DRM FD open +int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data) +{ + // Call into the real thing + int err = ((typeof(drmModePageFlip)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd, crtc_id, fb_id, flags, user_data); + if (err == -EACCES && fd == g_QtDrmMasterFd) { + // If SDL took master from us, try to grab it back temporarily + int oldMasterFd = takeMasterFromSdlFd(); + drmSetMaster(fd); + err = ((typeof(drmModePageFlip)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd, crtc_id, fb_id, flags, user_data); + drmDropMaster(fd); + if (oldMasterFd != -1) { + drmSetMaster(oldMasterFd); + } + } + return err; +} + // This hook will handle atomic DRM rendering int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, uint32_t flags, void *user_data) @@ -93,7 +112,18 @@ int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, } // Call into the real thing - return ((typeof(drmModeAtomicCommit)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd, req, flags, user_data); + int err = ((typeof(drmModeAtomicCommit)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd, req, flags, user_data); + if (err == -EACCES && fd == g_QtDrmMasterFd) { + // If SDL took master from us, try to grab it back temporarily + int oldMasterFd = takeMasterFromSdlFd(); + drmSetMaster(fd); + err = ((typeof(drmModeAtomicCommit)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd, req, flags, user_data); + drmDropMaster(fd); + if (oldMasterFd != -1) { + drmSetMaster(oldMasterFd); + } + } + return err; } // This hook will handle SDL's open() on the DRM device. We just need to diff --git a/app/masterhook_internal.c b/app/masterhook_internal.c index 0a177a31..6f9ae228 100644 --- a/app/masterhook_internal.c +++ b/app/masterhook_internal.c @@ -51,6 +51,7 @@ int getSdlFdEntryIndex(bool unused) return -1; } +// Returns true if the final SDL FD was removed bool removeSdlFd(int fd) { SDL_AtomicLock(&g_FdTableLock); @@ -73,6 +74,28 @@ bool removeSdlFd(int fd) return false; } +// Returns the previous master FD or -1 if none +int takeMasterFromSdlFd() +{ + int fd = -1; + + // Since all SDL FDs are actually dups of each other + // we can take master from any one of them. + SDL_AtomicLock(&g_FdTableLock); + int fdIndex = getSdlFdEntryIndex(false); + if (fdIndex != -1) { + fd = g_SdlDrmMasterFds[fdIndex]; + } + SDL_AtomicUnlock(&g_FdTableLock); + + if (fd >= 0 && drmDropMaster(fd) == 0) { + return fd; + } + else { + return -1; + } +} + int openHook(const char *funcname, const char *pathname, int flags, va_list va) { int fd;