mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2025-07-01 23:35:55 +00:00
Add support for managing multiple SDL DRM FDs
This is required for Vulkan+KMSDRM rendering.
This commit is contained in:
parent
6b11f43302
commit
9cf305865b
@ -36,8 +36,8 @@
|
|||||||
int g_QtDrmMasterFd = -1;
|
int g_QtDrmMasterFd = -1;
|
||||||
struct stat g_DrmMasterStat;
|
struct stat g_DrmMasterStat;
|
||||||
|
|
||||||
// The DRM master FD created for SDL
|
bool removeSdlFd(int fd);
|
||||||
int g_SdlDrmMasterFd = -1;
|
bool createSdlFd();
|
||||||
|
|
||||||
int drmIsMaster(int fd)
|
int drmIsMaster(int fd)
|
||||||
{
|
{
|
||||||
@ -111,23 +111,21 @@ int open64(const char *pathname, int flags, ...)
|
|||||||
// after SDL closes its DRM FD.
|
// after SDL closes its DRM FD.
|
||||||
int close(int fd)
|
int close(int fd)
|
||||||
{
|
{
|
||||||
|
// Remove this entry from the SDL FD table
|
||||||
|
bool lastSdlFd = removeSdlFd(fd);
|
||||||
|
|
||||||
// Call the real thing
|
// Call the real thing
|
||||||
int ret = ((typeof(close)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd);
|
int ret = ((typeof(close)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd);
|
||||||
if (ret == 0) {
|
|
||||||
// If we just closed the SDL DRM master FD, restore master
|
|
||||||
// to the Qt DRM FD. This works because the Qt DRM master FD
|
|
||||||
// was master once before, so we can set it as master again
|
|
||||||
// using drmSetMaster() without CAP_SYS_ADMIN.
|
|
||||||
if (g_SdlDrmMasterFd != -1 && fd == g_SdlDrmMasterFd) {
|
|
||||||
if (drmSetMaster(g_QtDrmMasterFd) < 0) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Failed to restore master to Qt DRM FD: %d",
|
|
||||||
errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_SdlDrmMasterFd = -1;
|
// If we closed the last SDL FD, restore master to the Qt FD
|
||||||
|
if (ret == 0 && lastSdlFd) {
|
||||||
|
if (drmSetMaster(g_QtDrmMasterFd) < 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Failed to restore master to Qt DRM FD: %d",
|
||||||
|
errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,50 @@
|
|||||||
|
|
||||||
extern int g_QtDrmMasterFd;
|
extern int g_QtDrmMasterFd;
|
||||||
extern struct stat g_DrmMasterStat;
|
extern struct stat g_DrmMasterStat;
|
||||||
extern int g_SdlDrmMasterFd;
|
|
||||||
|
#define MAX_SDL_FD_COUNT 8
|
||||||
|
int g_SdlDrmMasterFds[MAX_SDL_FD_COUNT];
|
||||||
|
int g_SdlDrmMasterFdCount = 0;
|
||||||
|
SDL_SpinLock g_FdTableLock = 0;
|
||||||
|
|
||||||
|
// Caller must hold g_FdTableLock
|
||||||
|
int getSdlFdEntryIndex(bool unused)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_SDL_FD_COUNT; i++) {
|
||||||
|
// We slightly bend the FD rules here by treating 0
|
||||||
|
// as invalid since that's our global default value.
|
||||||
|
if (unused && g_SdlDrmMasterFds[i] <= 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
else if (!unused && g_SdlDrmMasterFds[i] > 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool removeSdlFd(int fd)
|
||||||
|
{
|
||||||
|
SDL_AtomicLock(&g_FdTableLock);
|
||||||
|
if (g_SdlDrmMasterFdCount != 0) {
|
||||||
|
// Clear the entry for this fd from the table
|
||||||
|
for (int i = 0; i < MAX_SDL_FD_COUNT; i++) {
|
||||||
|
if (fd == g_SdlDrmMasterFds[i]) {
|
||||||
|
g_SdlDrmMasterFds[i] = -1;
|
||||||
|
g_SdlDrmMasterFdCount--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_SdlDrmMasterFdCount == 0) {
|
||||||
|
SDL_AtomicUnlock(&g_FdTableLock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_AtomicUnlock(&g_FdTableLock);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int openHook(const char *funcname, const char *pathname, int flags, va_list va)
|
int openHook(const char *funcname, const char *pathname, int flags, va_list va)
|
||||||
{
|
{
|
||||||
@ -55,32 +98,61 @@ int openHook(const char *funcname, const char *pathname, int flags, va_list va)
|
|||||||
fstat(fd, &fdstat);
|
fstat(fd, &fdstat);
|
||||||
if (g_DrmMasterStat.st_dev == fdstat.st_dev &&
|
if (g_DrmMasterStat.st_dev == fdstat.st_dev &&
|
||||||
g_DrmMasterStat.st_ino == fdstat.st_ino) {
|
g_DrmMasterStat.st_ino == fdstat.st_ino) {
|
||||||
|
int freeFdIndex;
|
||||||
|
int allocatedFdIndex;
|
||||||
|
|
||||||
// It is our device. Time to do the magic!
|
// It is our device. Time to do the magic!
|
||||||
|
SDL_AtomicLock(&g_FdTableLock);
|
||||||
|
|
||||||
// This code assumes SDL only ever opens a single FD
|
// Get a free index for us to put the new entry
|
||||||
// for a given DRM device.
|
freeFdIndex = getSdlFdEntryIndex(true);
|
||||||
SDL_assert(g_SdlDrmMasterFd == -1);
|
if (freeFdIndex < 0) {
|
||||||
|
SDL_AtomicUnlock(&g_FdTableLock);
|
||||||
// Drop master on Qt's FD so we can pick it up for SDL.
|
SDL_assert(freeFdIndex >= 0);
|
||||||
if (drmDropMaster(g_QtDrmMasterFd) < 0) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Failed to drop master on Qt DRM FD: %d",
|
"No unused SDL FD table entries!");
|
||||||
errno);
|
|
||||||
// Hope for the best
|
// Hope for the best
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are not allowed to call drmSetMaster() without CAP_SYS_ADMIN,
|
// Check if we have an allocated entry already
|
||||||
// but since we just dropped the master, we can become master by
|
allocatedFdIndex = getSdlFdEntryIndex(false);
|
||||||
// simply creating a new FD. Let's do it.
|
if (allocatedFdIndex >= 0) {
|
||||||
close(fd);
|
// Close fd that we opened earlier (skipping our close() hook)
|
||||||
if (__OPEN_NEEDS_MODE(flags)) {
|
((typeof(close)*)dlsym(RTLD_NEXT, "close"))(fd);
|
||||||
fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags, mode);
|
|
||||||
|
// dup() an existing FD into the unused slot
|
||||||
|
fd = dup(g_SdlDrmMasterFds[allocatedFdIndex]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags);
|
// Drop master on Qt's FD so we can pick it up for SDL.
|
||||||
|
if (drmDropMaster(g_QtDrmMasterFd) < 0) {
|
||||||
|
SDL_AtomicUnlock(&g_FdTableLock);
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Failed to drop master on Qt DRM FD: %d",
|
||||||
|
errno);
|
||||||
|
// Hope for the best
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close fd that we opened earlier (skipping our close() hook)
|
||||||
|
((typeof(close)*)dlsym(RTLD_NEXT, "close"))(fd);
|
||||||
|
|
||||||
|
// We are not allowed to call drmSetMaster() without CAP_SYS_ADMIN,
|
||||||
|
// but since we just dropped the master, we can become master by
|
||||||
|
// simply creating a new FD. Let's do it.
|
||||||
|
if (__OPEN_NEEDS_MODE(flags)) {
|
||||||
|
fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags, mode);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g_SdlDrmMasterFd = fd;
|
|
||||||
|
// Insert the FD into the table
|
||||||
|
g_SdlDrmMasterFds[freeFdIndex] = fd;
|
||||||
|
g_SdlDrmMasterFdCount++;
|
||||||
|
SDL_AtomicUnlock(&g_FdTableLock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user