Allow DRMRenderer to be used for indirect rendering

This commit is contained in:
Cameron Gutman 2021-01-31 15:19:19 -06:00
parent 1e31f6fe77
commit 6a66b462ce
2 changed files with 57 additions and 23 deletions

View file

@ -24,6 +24,7 @@ DrmRenderer::DrmRenderer()
: m_HwContext(nullptr), : m_HwContext(nullptr),
m_DrmFd(-1), m_DrmFd(-1),
m_SdlOwnsDrmFd(false), m_SdlOwnsDrmFd(false),
m_SupportsDirectRendering(false),
m_CrtcId(0), m_CrtcId(0),
m_PlaneId(0), m_PlaneId(0),
m_CurrentFbId(0) m_CurrentFbId(0)
@ -101,12 +102,43 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
} }
} }
// 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,
"av_hwdevice_ctx_alloc(DRM) failed");
return false;
}
AVHWDeviceContext* deviceContext = (AVHWDeviceContext*)m_HwContext->data;
AVDRMDeviceContext* drmDeviceContext = (AVDRMDeviceContext*)deviceContext->hwctx;
drmDeviceContext->fd = m_DrmFd;
int err = av_hwdevice_ctx_init(m_HwContext);
if (err < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"av_hwdevice_ctx_init(DRM) failed: %d",
err);
return false;
}
#ifdef HAVE_EGL
// Still return true if we fail to initialize DRM direct rendering
// stuff, since we have EGL that we can use for indirect rendering.
const bool DIRECT_RENDERING_INIT_FAILED = true;
#else
// Fail if we can't initialize direct rendering and we don't have EGL.
const bool DIRECT_RENDERING_INIT_FAILED = false;
#endif
drmModeRes* resources = drmModeGetResources(m_DrmFd); drmModeRes* resources = drmModeGetResources(m_DrmFd);
if (resources == nullptr) { if (resources == nullptr) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"drmModeGetResources() failed: %d", "drmModeGetResources() failed: %d",
errno); errno);
return false; return DIRECT_RENDERING_INIT_FAILED;
} }
// Look for a connected connector and get the associated encoder // Look for a connected connector and get the associated encoder
@ -126,7 +158,7 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"No connected displays found!"); "No connected displays found!");
drmModeFreeResources(resources); drmModeFreeResources(resources);
return false; return DIRECT_RENDERING_INIT_FAILED;
} }
// Now find the CRTC from the encoder // Now find the CRTC from the encoder
@ -146,7 +178,7 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"DRM encoder not found!"); "DRM encoder not found!");
drmModeFreeResources(resources); drmModeFreeResources(resources);
return false; return DIRECT_RENDERING_INIT_FAILED;
} }
int crtcIndex = -1; int crtcIndex = -1;
@ -167,7 +199,7 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
if (crtcIndex == -1) { if (crtcIndex == -1) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to get CRTC!"); "Failed to get CRTC!");
return false; return DIRECT_RENDERING_INIT_FAILED;
} }
drmSetClientCap(m_DrmFd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); drmSetClientCap(m_DrmFd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
@ -177,7 +209,7 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"drmGetPlaneResources() failed: %d", "drmGetPlaneResources() failed: %d",
errno); errno);
return false; return DIRECT_RENDERING_INIT_FAILED;
} }
// Find an NV12 overlay plane to render on // Find an NV12 overlay plane to render on
@ -222,25 +254,14 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
drmModeFreePlaneResources(planeRes); drmModeFreePlaneResources(planeRes);
m_HwContext = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_DRM); if (m_PlaneId == 0) {
if (m_HwContext == nullptr) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"av_hwdevice_ctx_alloc(DRM) failed"); "Failed to find suitable NV12 overlay plane!");
return false; return DIRECT_RENDERING_INIT_FAILED;
} }
AVHWDeviceContext* deviceContext = (AVHWDeviceContext*)m_HwContext->data; // If we got this far, we can do direct rendering via the DRM FD.
AVDRMDeviceContext* drmDeviceContext = (AVDRMDeviceContext*)deviceContext->hwctx; m_SupportsDirectRendering = true;
drmDeviceContext->fd = m_DrmFd;
int err = av_hwdevice_ctx_init(m_HwContext);
if (err < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"av_hwdevice_ctx_init(DRM) failed: %d",
err);
return false;
}
return true; return true;
} }
@ -335,6 +356,16 @@ void DrmRenderer::renderFrame(AVFrame* frame)
drmModeRmFB(m_DrmFd, lastFbId); drmModeRmFB(m_DrmFd, lastFbId);
} }
bool DrmRenderer::needsTestFrame()
{
return true;
}
bool DrmRenderer::isDirectRenderingSupported()
{
return m_SupportsDirectRendering;
}
#ifdef HAVE_EGL #ifdef HAVE_EGL
bool DrmRenderer::canExportEGL() { bool DrmRenderer::canExportEGL() {

View file

@ -14,6 +14,8 @@ public:
virtual void renderFrame(AVFrame* frame) override; virtual void renderFrame(AVFrame* frame) override;
virtual enum AVPixelFormat getPreferredPixelFormat(int videoFormat) override; virtual enum AVPixelFormat getPreferredPixelFormat(int videoFormat) override;
virtual int getRendererAttributes() override; virtual int getRendererAttributes() override;
virtual bool needsTestFrame() override;
virtual bool isDirectRenderingSupported() override;
#ifdef HAVE_EGL #ifdef HAVE_EGL
virtual bool canExportEGL() override; virtual bool canExportEGL() override;
virtual bool initializeEGL(EGLDisplay dpy, const EGLExtensions &ext) override; virtual bool initializeEGL(EGLDisplay dpy, const EGLExtensions &ext) override;
@ -25,6 +27,7 @@ private:
AVBufferRef* m_HwContext; AVBufferRef* m_HwContext;
int m_DrmFd; int m_DrmFd;
bool m_SdlOwnsDrmFd; bool m_SdlOwnsDrmFd;
bool m_SupportsDirectRendering;
uint32_t m_CrtcId; uint32_t m_CrtcId;
uint32_t m_PlaneId; uint32_t m_PlaneId;
uint32_t m_CurrentFbId; uint32_t m_CurrentFbId;