Unify handling of DRM devices between DRM and VAAPI

SDL may not be able to give us a DRM FD for Vulkan windows.
This commit is contained in:
Cameron Gutman
2024-09-21 20:46:11 -05:00
parent 9cf305865b
commit 6f39d120cb
5 changed files with 147 additions and 75 deletions

View File

@@ -72,15 +72,6 @@ extern "C" {
#include <Limelight.h>
// HACK: Avoid including X11 headers which conflict with QDir
#ifdef SDL_VIDEO_DRIVER_X11
#undef SDL_VIDEO_DRIVER_X11
#endif
#include <SDL_syswm.h>
#include <QDir>
#include <map>
// This map is used to lookup characteristics of a given DRM format
@@ -149,6 +140,7 @@ DrmRenderer::DrmRenderer(AVHWDeviceType hwDeviceType, IFFmpegRenderer *backendRe
m_HwDeviceType(hwDeviceType),
m_HwContext(nullptr),
m_DrmFd(-1),
m_DrmIsMaster(false),
m_SdlOwnsDrmFd(false),
m_SupportsDirectRendering(false),
m_VideoFormat(0),
@@ -265,6 +257,9 @@ bool DrmRenderer::prepareDecoderContext(AVCodecContext* context, AVDictionary**
void DrmRenderer::prepareToRender()
{
// Retake DRM master if we dropped it earlier
drmSetMaster(m_DrmFd);
// Create a dummy renderer to force SDL to complete the modesetting
// operation that the KMSDRM backend keeps pending until the next
// time we swap buffers. We have to do this before we enumerate
@@ -350,68 +345,26 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
m_VideoFormat = params->videoFormat;
m_SwFrameMapper.setVideoFormat(params->videoFormat);
#if SDL_VERSION_ATLEAST(2, 0, 15)
SDL_SysWMinfo info;
// Try to get the FD that we're sharing with SDL
m_DrmFd = StreamUtils::getDrmFdForWindow(m_Window, &m_SdlOwnsDrmFd);
if (m_DrmFd >= 0) {
// If we got a DRM FD for the window, we can render to it
m_DrmIsMaster = true;
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(params->window, &info)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_GetWindowWMInfo() failed: %s",
SDL_GetError());
return false;
}
if (info.subsystem == SDL_SYSWM_KMSDRM) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Sharing DRM FD with SDL");
SDL_assert(info.info.kmsdrm.drm_fd >= 0);
m_DrmFd = info.info.kmsdrm.drm_fd;
m_SdlOwnsDrmFd = true;
}
else
#endif
{
const char* userDevice = SDL_getenv("DRM_DEV");
if (userDevice != nullptr) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Opening user-specified DRM device: %s",
userDevice);
m_DrmFd = open(userDevice, O_RDWR | O_CLOEXEC);
// If we just opened a new FD, let's drop master on it
// so SDL can take master for Vulkan rendering. We'll
// regrab master later if we end up direct rendering.
if (!m_SdlOwnsDrmFd) {
drmDropMaster(m_DrmFd);
}
else {
QDir driDir("/dev/dri");
}
else {
// Try to open any DRM render node
m_DrmFd = StreamUtils::getDrmFd(true);
// We have to explicitly ask for devices to be returned
driDir.setFilter(QDir::Files | QDir::System);
// Try a render node first since we aren't using DRM for output in this codepath
for (QFileInfo& node : driDir.entryInfoList(QStringList("renderD*"))) {
QByteArray absolutePath = node.absoluteFilePath().toUtf8();
m_DrmFd = open(absolutePath.constData(), O_RDWR | O_CLOEXEC);
if (m_DrmFd >= 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Opened DRM render node: %s",
absolutePath.constData());
break;
}
}
// If that fails, try to use a primary node and hope for the best
if (m_DrmFd < 0) {
for (QFileInfo& node : driDir.entryInfoList(QStringList("card*"))) {
QByteArray absolutePath = node.absoluteFilePath().toUtf8();
m_DrmFd = open(absolutePath.constData(), O_RDWR | O_CLOEXEC);
if (m_DrmFd >= 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Opened DRM primary node: %s",
absolutePath.constData());
break;
}
}
}
// Drop master in case we somehow got a primary node
if (m_DrmFd >= 0) {
drmDropMaster(m_DrmFd);
}
}
@@ -489,7 +442,7 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
// If we're not sharing the DRM FD with SDL, that means we don't
// have DRM master, so we can't call drmModeSetPlane(). We can
// use EGLRenderer or SDLRenderer to render in this situation.
if (!m_SdlOwnsDrmFd) {
if (!m_DrmIsMaster) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Direct rendering via DRM is disabled");
return DIRECT_RENDERING_INIT_FAILED;