mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2025-07-01 15:26:09 +00:00
Allow DrmRenderer to act as a non-DRM hwaccel backend
This case basically works like a degenerate case of a DRM hwaccel without DRM master where we just provide EGL export functionality except that we don't even need a DRM FD in this case. There are patches floating around the FFmpeg list for this: https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=12604
This commit is contained in:
parent
8e2aa87c4f
commit
1bb16be183
@ -71,10 +71,10 @@ extern "C" {
|
||||
|
||||
#include <QDir>
|
||||
|
||||
DrmRenderer::DrmRenderer(bool hwaccel, IFFmpegRenderer *backendRenderer)
|
||||
DrmRenderer::DrmRenderer(AVHWDeviceType hwDeviceType, IFFmpegRenderer *backendRenderer)
|
||||
: m_BackendRenderer(backendRenderer),
|
||||
m_DrmPrimeBackend(backendRenderer && backendRenderer->canExportDrmPrime()),
|
||||
m_HwAccelBackend(hwaccel),
|
||||
m_HwDeviceType(hwDeviceType),
|
||||
m_HwContext(nullptr),
|
||||
m_DrmFd(-1),
|
||||
m_SdlOwnsDrmFd(false),
|
||||
@ -180,7 +180,7 @@ bool DrmRenderer::prepareDecoderContext(AVCodecContext* context, AVDictionary**
|
||||
// https://doc-en.rvspace.org/VisionFive2/DG_Multimedia/JH7110_SDK/hevc_omx.html
|
||||
av_dict_set(options, "omx_pix_fmt", "nv12", 0);
|
||||
|
||||
if (m_HwAccelBackend) {
|
||||
if (m_HwDeviceType != AV_HWDEVICE_TYPE_NONE) {
|
||||
context->hw_device_ctx = av_buffer_ref(m_HwContext);
|
||||
}
|
||||
|
||||
@ -316,29 +316,19 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the device context first because it is needed whether we can
|
||||
// actually use direct rendering or not.
|
||||
if (m_HwDeviceType == AV_HWDEVICE_TYPE_DRM) {
|
||||
// A real DRM FD is required for DRM-backed hwaccels
|
||||
if (m_DrmFd < 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to open DRM device: %d",
|
||||
errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch version details about the DRM driver to use later
|
||||
m_Version = drmGetVersion(m_DrmFd);
|
||||
if (m_Version == nullptr) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"drmGetVersion() failed: %d",
|
||||
errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"GPU driver: %s", m_Version->name);
|
||||
|
||||
// Create the device context first because it is needed whether we can
|
||||
// actually use direct rendering or not.
|
||||
m_HwContext = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_DRM);
|
||||
if (m_HwContext == nullptr) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
@ -358,6 +348,19 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
|
||||
err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_HwDeviceType != AV_HWDEVICE_TYPE_NONE) {
|
||||
// We got some other non-DRM hwaccel that outputs DRM_PRIME frames.
|
||||
// Create it with default parameters and hope for the best.
|
||||
int err = av_hwdevice_ctx_create(&m_HwContext, m_HwDeviceType, nullptr, nullptr, 0);
|
||||
if (err < 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"av_hwdevice_ctx_create(%u) failed: %d",
|
||||
m_HwDeviceType,
|
||||
err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Still return true if we fail to initialize DRM direct rendering
|
||||
// stuff, since we have EGLRenderer and SDLRenderer that we can use
|
||||
@ -368,6 +371,24 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
|
||||
// that's the whole point it's trying to use us for.
|
||||
const bool DIRECT_RENDERING_INIT_FAILED = (m_BackendRenderer == nullptr);
|
||||
|
||||
if (m_DrmFd < 0) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Direct rendering via DRM is unavailable due to lack of DRM devices");
|
||||
return DIRECT_RENDERING_INIT_FAILED;
|
||||
}
|
||||
|
||||
// Fetch version details about the DRM driver to use later
|
||||
m_Version = drmGetVersion(m_DrmFd);
|
||||
if (m_Version == nullptr) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"drmGetVersion() failed: %d",
|
||||
errno);
|
||||
return DIRECT_RENDERING_INIT_FAILED;
|
||||
}
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"GPU driver: %s", m_Version->name);
|
||||
|
||||
// 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.
|
||||
@ -692,7 +713,7 @@ enum AVPixelFormat DrmRenderer::getPreferredPixelFormat(int videoFormat)
|
||||
}
|
||||
|
||||
bool DrmRenderer::isPixelFormatSupported(int videoFormat, AVPixelFormat pixelFormat) {
|
||||
if (m_HwAccelBackend) {
|
||||
if (m_HwDeviceType != AV_HWDEVICE_TYPE_NONE) {
|
||||
return pixelFormat == AV_PIX_FMT_DRM_PRIME;
|
||||
}
|
||||
else if (m_DrmPrimeBackend) {
|
||||
@ -765,7 +786,7 @@ int DrmRenderer::getRendererAttributes()
|
||||
// Restrict streaming resolution to 1080p on the Pi 4 while in the desktop environment.
|
||||
// EGL performance is extremely poor and just barely hits 1080p60 on Bookworm. This also
|
||||
// covers the MMAL H.264 case which maxes out at 1080p60 too.
|
||||
if (!m_SupportsDirectRendering &&
|
||||
if (!m_SupportsDirectRendering && m_Version &&
|
||||
(strcmp(m_Version->name, "vc4") == 0 || strcmp(m_Version->name, "v3d") == 0) &&
|
||||
qgetenv("RPI_ALLOW_EGL_4K") != "1") {
|
||||
drmDevicePtr device;
|
||||
|
@ -48,7 +48,7 @@ namespace DrmDefs
|
||||
|
||||
class DrmRenderer : public IFFmpegRenderer {
|
||||
public:
|
||||
DrmRenderer(bool hwaccel = false, IFFmpegRenderer *backendRenderer = nullptr);
|
||||
DrmRenderer(AVHWDeviceType hwDeviceType = AV_HWDEVICE_TYPE_NONE, IFFmpegRenderer *backendRenderer = nullptr);
|
||||
virtual ~DrmRenderer() override;
|
||||
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||
virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary** options) override;
|
||||
@ -80,7 +80,7 @@ private:
|
||||
IFFmpegRenderer* m_BackendRenderer;
|
||||
SDL_Window* m_Window;
|
||||
bool m_DrmPrimeBackend;
|
||||
bool m_HwAccelBackend;
|
||||
AVHWDeviceType m_HwDeviceType;
|
||||
AVBufferRef* m_HwContext;
|
||||
int m_DrmFd;
|
||||
bool m_SdlOwnsDrmFd;
|
||||
|
@ -324,7 +324,7 @@ bool FFmpegVideoDecoder::createFrontendRenderer(PDECODER_PARAMETERS params, bool
|
||||
// not currently support this (and even if it did, Mesa and Wayland don't
|
||||
// currently have protocols to actually get that metadata to the display).
|
||||
if (m_BackendRenderer->canExportDrmPrime()) {
|
||||
m_FrontendRenderer = new DrmRenderer(false, m_BackendRenderer);
|
||||
m_FrontendRenderer = new DrmRenderer(AV_HWDEVICE_TYPE_NONE, m_BackendRenderer);
|
||||
if (m_FrontendRenderer->initialize(params) && (m_FrontendRenderer->getRendererAttributes() & RENDERER_ATTRIBUTE_HDR_SUPPORT)) {
|
||||
return true;
|
||||
}
|
||||
@ -385,7 +385,7 @@ bool FFmpegVideoDecoder::createFrontendRenderer(PDECODER_PARAMETERS params, bool
|
||||
|
||||
#if (defined(VULKAN_IS_SLOW) || defined(GL_IS_SLOW)) && defined(HAVE_DRM)
|
||||
// Try DrmRenderer first if we have a slow GPU
|
||||
m_FrontendRenderer = new DrmRenderer(false, m_BackendRenderer);
|
||||
m_FrontendRenderer = new DrmRenderer(AV_HWDEVICE_TYPE_NONE, m_BackendRenderer);
|
||||
if (m_FrontendRenderer->initialize(params)) {
|
||||
return true;
|
||||
}
|
||||
@ -899,16 +899,25 @@ IFFmpegRenderer* FFmpegVideoDecoder::createHwAccelRenderer(const AVCodecHWConfig
|
||||
#endif
|
||||
#ifdef HAVE_DRM
|
||||
case AV_HWDEVICE_TYPE_DRM:
|
||||
return new DrmRenderer(true);
|
||||
return new DrmRenderer(hwDecodeCfg->device_type);
|
||||
#endif
|
||||
#ifdef HAVE_LIBPLACEBO_VULKAN
|
||||
case AV_HWDEVICE_TYPE_VULKAN:
|
||||
return new PlVkRenderer(true);
|
||||
#endif
|
||||
default:
|
||||
switch (hwDecodeCfg->pix_fmt) {
|
||||
#ifdef HAVE_DRM
|
||||
case AV_PIX_FMT_DRM_PRIME:
|
||||
// Support out-of-tree non-DRM hwaccels that output DRM_PRIME frames
|
||||
// https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=12604
|
||||
return new DrmRenderer(hwDecodeCfg->device_type);
|
||||
#endif
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Second pass for our second-tier hwaccel implementations
|
||||
else if (pass == 1) {
|
||||
switch (hwDecodeCfg->device_type) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user