From cfb130d42a8fce7fc6a12015e34a9df8388e47de Mon Sep 17 00:00:00 2001 From: boogie Date: Sat, 13 Jan 2024 19:39:52 +0100 Subject: windowing/gbm: Dynamic plane selection This commit allows kodi to select gui and video planes according to format and modifier combination and sorts to gui plane on top of video plane if zpos is supported and not immutable by the planes. --- .../HwDecRender/RendererDRMPRIME.cpp | 2 +- xbmc/windowing/gbm/drm/DRMObject.cpp | 30 ++++ xbmc/windowing/gbm/drm/DRMObject.h | 3 + xbmc/windowing/gbm/drm/DRMUtils.cpp | 169 ++++++++++++++------- xbmc/windowing/gbm/drm/DRMUtils.h | 5 +- 5 files changed, 149 insertions(+), 60 deletions(-) diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp index 66df0e49c7..2ef7f4d521 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp @@ -77,7 +77,7 @@ CBaseRenderer* CRendererDRMPRIME::Create(CVideoBuffer* buffer) if (!plane) return nullptr; - if (!plane->SupportsFormatAndModifier(format, modifier)) + if (!drm->FindVideoPlane(format, modifier)) return nullptr; return new CRendererDRMPRIME(); diff --git a/xbmc/windowing/gbm/drm/DRMObject.cpp b/xbmc/windowing/gbm/drm/DRMObject.cpp index 5ffce40fa3..99dda24490 100644 --- a/xbmc/windowing/gbm/drm/DRMObject.cpp +++ b/xbmc/windowing/gbm/drm/DRMObject.cpp @@ -105,6 +105,25 @@ std::optional CDRMObject::GetPropertyValue(std::string_view name, return {}; } +std::optional> CDRMObject::GetRangePropertyLimits(std::string_view name) +{ + auto property = std::find_if(m_propsInfo.begin(), m_propsInfo.end(), + [&name](const auto& prop) { return prop->name == name; }); + + if (property == m_propsInfo.end()) + return {}; + + auto prop = property->get(); + + if (!static_cast(drm_property_type_is(prop, DRM_MODE_PROP_RANGE))) + return {}; + + if (prop->count_values != 2) + return {}; + + return std::make_optional>(prop->values, 2); +} + bool CDRMObject::SetProperty(const std::string& name, uint64_t value) { auto property = std::find_if(m_propsInfo.begin(), m_propsInfo.end(), @@ -130,3 +149,14 @@ bool CDRMObject::SupportsProperty(const std::string& name) return false; } + +std::optional CDRMObject::IsPropertyImmutable(std::string_view name) +{ + auto property = std::find_if(m_propsInfo.begin(), m_propsInfo.end(), + [&name](const auto& prop) { return prop->name == name; }); + + if (property == m_propsInfo.end()) + return {}; + + return static_cast(drm_property_type_is(property->get(), DRM_MODE_PROP_IMMUTABLE)); +} diff --git a/xbmc/windowing/gbm/drm/DRMObject.h b/xbmc/windowing/gbm/drm/DRMObject.h index c4200b1a86..39ba28a004 100644 --- a/xbmc/windowing/gbm/drm/DRMObject.h +++ b/xbmc/windowing/gbm/drm/DRMObject.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,8 @@ public: bool SetProperty(const std::string& name, uint64_t value); bool SupportsProperty(const std::string& name); + std::optional IsPropertyImmutable(std::string_view name); + std::optional> GetRangePropertyLimits(std::string_view name); protected: explicit CDRMObject(int fd); diff --git a/xbmc/windowing/gbm/drm/DRMUtils.cpp b/xbmc/windowing/gbm/drm/DRMUtils.cpp index 3dd4ee9783..22db758ab6 100644 --- a/xbmc/windowing/gbm/drm/DRMUtils.cpp +++ b/xbmc/windowing/gbm/drm/DRMUtils.cpp @@ -181,77 +181,130 @@ bool CDRMUtils::FindPreferredMode() return true; } -bool CDRMUtils::FindPlanes() +bool CDRMUtils::FindGuiPlane() { - for (size_t i = 0; i < m_crtcs.size(); i++) - { - if (!(m_encoder->GetPossibleCrtcs() & (1 << i))) + /* find the gui plane which support ARGB and 8bit or 10 bit XRGB + * prefer the one which does not support NV12, because it can be re-used in future for video + * prefer the highest id number because they are listed on top where zpos is not available + * and use the gui plane crtc as the crtc + * */ + CDRMPlane* gui_plane_nv12{nullptr}; + CDRMPlane* gui_plane{nullptr}; + CDRMCrtc* gui_crtc_nv12{nullptr}; + CDRMCrtc* gui_crtc{nullptr}; + + for (size_t crtc_offset = 0; crtc_offset < m_crtcs.size(); crtc_offset++) + { + if (!(m_encoder->GetPossibleCrtcs() & (1 << crtc_offset))) continue; - auto videoPlane = std::find_if(m_planes.begin(), m_planes.end(), [&i](auto& plane) { - if (plane->GetPossibleCrtcs() & (1 << i)) - { - return plane->SupportsFormat(DRM_FORMAT_NV12); - } - return false; - }); - - uint32_t videoPlaneId{0}; - - if (videoPlane != m_planes.end()) - videoPlaneId = videoPlane->get()->GetPlaneId(); - - auto guiPlane = - std::find_if(m_planes.begin(), m_planes.end(), [&i, &videoPlaneId](auto& plane) { - if (plane->GetPossibleCrtcs() & (1 << i)) - { - return (plane->GetPlaneId() != videoPlaneId && - (videoPlaneId == 0 || plane->SupportsFormat(DRM_FORMAT_ARGB8888)) && - (plane->SupportsFormat(DRM_FORMAT_XRGB2101010) || - plane->SupportsFormat(DRM_FORMAT_XRGB8888))); - } - return false; - }); - - if (videoPlane != m_planes.end() && guiPlane != m_planes.end()) + for (auto& plane : m_planes) { - m_crtc = m_crtcs[i].get(); - m_video_plane = videoPlane->get(); - m_gui_plane = guiPlane->get(); - break; - } + if (!(plane.get()->GetPossibleCrtcs() & (1 << crtc_offset))) + continue; - if (guiPlane != m_planes.end()) - { - if (!m_crtc && m_encoder->GetCrtcId() == m_crtcs[i]->GetCrtcId()) + if (plane.get()->SupportsFormat(DRM_FORMAT_ARGB8888) && + (plane.get()->SupportsFormat(DRM_FORMAT_XRGB2101010) || + plane.get()->SupportsFormat(DRM_FORMAT_XRGB8888))) { - m_crtc = m_crtcs[i].get(); - m_gui_plane = guiPlane->get(); - m_video_plane = nullptr; + if (plane.get()->SupportsFormat(DRM_FORMAT_NV12) && + (gui_plane_nv12 == nullptr || gui_plane_nv12->GetId() < plane.get()->GetId())) + { + gui_plane_nv12 = plane.get(); + gui_crtc_nv12 = m_crtcs[crtc_offset].get(); + } + else if (!plane.get()->SupportsFormat(DRM_FORMAT_NV12) && + (gui_plane == nullptr || gui_plane->GetId() < plane.get()->GetId())) + { + gui_plane = plane.get(); + gui_crtc = m_crtcs[crtc_offset].get(); + } } } } - CLog::Log(LOGINFO, "CDRMUtils::{} - using crtc: {}", __FUNCTION__, m_crtc->GetCrtcId()); - - // video plane may not be available - if (m_video_plane) - CLog::Log(LOGDEBUG, "CDRMUtils::{} - using video plane {}", __FUNCTION__, - m_video_plane->GetPlaneId()); - - if (m_gui_plane->SupportsFormat(DRM_FORMAT_XRGB2101010)) + // fallback to NV12 supporting plane + if (gui_plane == nullptr) { - m_gui_plane->SetFormat(DRM_FORMAT_XRGB2101010); - CLog::Log(LOGDEBUG, "CDRMUtils::{} - using 10bit gui plane {}", __FUNCTION__, - m_gui_plane->GetPlaneId()); + gui_crtc = gui_crtc_nv12; + gui_plane = gui_plane_nv12; } - else + + if (gui_plane != nullptr) { - m_gui_plane->SetFormat(DRM_FORMAT_XRGB8888); - CLog::Log(LOGDEBUG, "CDRMUtils::{} - using gui plane {}", __FUNCTION__, - m_gui_plane->GetPlaneId()); + m_crtc = gui_crtc; + m_gui_plane = gui_plane; + + CLog::Log(LOGINFO, "CDRMUtils::{} - using crtc: {}", __FUNCTION__, m_crtc->GetCrtcId()); + if (m_gui_plane->SupportsFormat(DRM_FORMAT_XRGB2101010)) + { + m_gui_plane->SetFormat(DRM_FORMAT_XRGB2101010); + CLog::Log(LOGDEBUG, "CDRMUtils::{} - using 10bit gui plane {}", __FUNCTION__, + m_gui_plane->GetPlaneId()); + } + else + { + m_gui_plane->SetFormat(DRM_FORMAT_XRGB8888); + CLog::Log(LOGDEBUG, "CDRMUtils::{} - using gui plane {}", __FUNCTION__, + m_gui_plane->GetPlaneId()); + } + return true; } + CLog::Log(LOGERROR, "CDRMUtils::{} - Can not find a GUI plane", __FUNCTION__); + return false; +} + +bool CDRMUtils::FindVideoPlane(uint32_t format, uint64_t modifier) +{ + bool supports_zpos = m_gui_plane->SupportsProperty("zpos"); + bool zpos_immutable = supports_zpos && m_gui_plane->IsPropertyImmutable("zpos").value(); + + auto crtc_offset = std::distance( + m_crtcs.begin(), + std::find_if(m_crtcs.begin(), m_crtcs.end(), + [this](auto& crtc) { return crtc->GetCrtcId() == m_crtc->GetCrtcId(); })); + + auto guiplane_id = m_gui_plane->GetId(); + auto videoPlane = std::find_if(m_planes.begin(), m_planes.end(), + [&crtc_offset, &format, &modifier, &guiplane_id](auto& plane) + { + if (plane->GetPossibleCrtcs() & (1 << crtc_offset)) + { + return (guiplane_id != plane->GetPlaneId() && + plane->SupportsFormatAndModifier(format, modifier)); + } + return false; + }); + + if (videoPlane == m_planes.end()) + { + CLog::Log(LOGERROR, + "CDRMUtils::{} - Can not find a Video Plane plane for format {}, modifier {}", + __FUNCTION__, format, modifier); + return false; + } + + m_video_plane = videoPlane->get(); + CLog::Log(LOGDEBUG, "CDRMUtils::{} - using video plane {}", __FUNCTION__, + m_video_plane->GetPlaneId()); + + if (!supports_zpos || zpos_immutable) + return true; + + // re-sort the video and gui planes + auto limits = m_gui_plane->GetRangePropertyLimits("zpos"); + + if (!limits) + return true; + + m_gui_plane->SetProperty("zpos", limits.value()[1]); + m_video_plane->SetProperty("zpos", limits.value()[0]); + CLog::Log(LOGDEBUG, "CDRMUtils::{} - gui plane id,zpos: {}, {}", __FUNCTION__, + m_gui_plane->GetId(), limits.value()[1]); + CLog::Log(LOGDEBUG, "CDRMUtils::{} - video plane id,zpos: {}, {}", __FUNCTION__, + m_video_plane->GetId(), limits.value()[0]); + return true; } @@ -467,9 +520,11 @@ bool CDRMUtils::InitDrm() if (!FindCrtc()) return false; - if (!FindPlanes()) + if (!FindGuiPlane()) return false; + FindVideoPlane(DRM_FORMAT_NV12, DRM_FORMAT_MOD_LINEAR); + if (!FindPreferredMode()) return false; diff --git a/xbmc/windowing/gbm/drm/DRMUtils.h b/xbmc/windowing/gbm/drm/DRMUtils.h index f92f716fc4..b99a6dc4fe 100644 --- a/xbmc/windowing/gbm/drm/DRMUtils.h +++ b/xbmc/windowing/gbm/drm/DRMUtils.h @@ -64,6 +64,8 @@ public: static uint32_t FourCCWithoutAlpha(uint32_t fourcc); void SetInFenceFd(int fd) { m_inFenceFd = fd; } + bool FindVideoPlane(uint32_t format, uint64_t modifier); + bool FindGuiPlane(); int TakeOutFenceFd() { int fd{-1}; @@ -89,13 +91,13 @@ protected: int m_inFenceFd{-1}; int m_outFenceFd{-1}; + std::vector> m_crtcs; std::vector> m_planes; private: bool FindConnector(); bool FindEncoder(); bool FindCrtc(); - bool FindPlanes(); bool FindPreferredMode(); bool RestoreOriginalMode(); RESOLUTION_INFO GetResolutionInfo(drmModeModeInfoPtr mode); @@ -106,7 +108,6 @@ private: std::vector> m_connectors; std::vector> m_encoders; - std::vector> m_crtcs; }; } -- cgit v1.2.3 From ca63e568cf6b5d44652c1b187088c3a8f9675d0d Mon Sep 17 00:00:00 2001 From: boogie Date: Sat, 13 Jan 2024 21:48:53 +0100 Subject: VideoLayerBridgeDRMPRIME: Use crop fields to render the picture offsets Hardware decoders when used with AFBC compression, may output picture with offsets which may be different for each frame. Since this offset is applied after the decompression is done, only way to represent this in SRC_X and SRC_Y plane props. This commits utilizes AVFrame crop fields to pass picture offsets. --- xbmc/cores/VideoPlayer/Buffers/VideoBufferDRMPRIME.h | 2 ++ xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.cpp | 2 ++ xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h | 2 ++ .../VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp | 2 ++ .../VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp | 11 ++++++----- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/xbmc/cores/VideoPlayer/Buffers/VideoBufferDRMPRIME.h b/xbmc/cores/VideoPlayer/Buffers/VideoBufferDRMPRIME.h index b83ee8ca68..dca6e82177 100644 --- a/xbmc/cores/VideoPlayer/Buffers/VideoBufferDRMPRIME.h +++ b/xbmc/cores/VideoPlayer/Buffers/VideoBufferDRMPRIME.h @@ -54,6 +54,8 @@ public: virtual const VideoPicture& GetPicture() const { return m_picture; } virtual uint32_t GetWidth() const { return GetPicture().iWidth; } virtual uint32_t GetHeight() const { return GetPicture().iHeight; } + virtual uint32_t GetXOffset() const { return GetPicture().m_xOffset; } + virtual uint32_t GetYOffset() const { return GetPicture().m_yOffset; } virtual AVDRMFrameDescriptor* GetDescriptor() const = 0; virtual bool IsValid() const { return true; } diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.cpp index 495d6a25f5..a5468d12a0 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.cpp @@ -58,6 +58,8 @@ void VideoPicture::Reset() iWidth = 0; iHeight = 0; + m_xOffset = 0; + m_yOffset = 0; iDisplayWidth = 0; iDisplayHeight = 0; } diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h index ca83b1a04f..f3373612e8 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h @@ -75,6 +75,8 @@ public: unsigned int iWidth; unsigned int iHeight; + unsigned int m_xOffset{0}; + unsigned int m_yOffset{0}; unsigned int iDisplayWidth; //< width of the picture without black bars unsigned int iDisplayHeight; //< height of the picture without black bars diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp index eb2943bb8c..0d407043dd 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp @@ -505,6 +505,8 @@ void CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture) { pVideoPicture->iWidth = m_pFrame->width; pVideoPicture->iHeight = m_pFrame->height; + pVideoPicture->m_xOffset = m_pFrame->crop_left; + pVideoPicture->m_yOffset = m_pFrame->crop_top; double aspect_ratio = 0; AVRational pixel_aspect = m_pFrame->sample_aspect_ratio; diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp index 34d1ab6235..33db29b140 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp @@ -118,9 +118,10 @@ bool CVideoLayerBridgeDRMPRIME::Map(CVideoBufferDRMPRIME* buffer) flags = DRM_MODE_FB_MODIFIERS; // add the video frame FB - ret = drmModeAddFB2WithModifiers(m_DRM->GetFileDescriptor(), buffer->GetWidth(), - buffer->GetHeight(), layer->format, handles, pitches, offsets, - modifier, &buffer->m_fb_id, flags); + ret = drmModeAddFB2WithModifiers(m_DRM->GetFileDescriptor(), + buffer->GetWidth() + buffer->GetXOffset(), + buffer->GetHeight() + buffer->GetYOffset(), layer->format, + handles, pitches, offsets, modifier, &buffer->m_fb_id, flags); if (ret < 0) { CLog::Log(LOGERROR, "CVideoLayerBridgeDRMPRIME::{} - failed to add fb {}, ret = {}", @@ -188,8 +189,8 @@ void CVideoLayerBridgeDRMPRIME::SetVideoPlane(CVideoBufferDRMPRIME* buffer, cons auto plane = m_DRM->GetVideoPlane(); m_DRM->AddProperty(plane, "FB_ID", buffer->m_fb_id); m_DRM->AddProperty(plane, "CRTC_ID", m_DRM->GetCrtc()->GetCrtcId()); - m_DRM->AddProperty(plane, "SRC_X", 0); - m_DRM->AddProperty(plane, "SRC_Y", 0); + m_DRM->AddProperty(plane, "SRC_X", buffer->GetXOffset() << 16); + m_DRM->AddProperty(plane, "SRC_Y", buffer->GetYOffset() << 16); m_DRM->AddProperty(plane, "SRC_W", buffer->GetWidth() << 16); m_DRM->AddProperty(plane, "SRC_H", buffer->GetHeight() << 16); m_DRM->AddProperty(plane, "CRTC_X", static_cast(destRect.x1) & ~1); -- cgit v1.2.3