diff options
author | Lukas Rusak <lorusak@gmail.com> | 2021-09-28 23:34:03 -0700 |
---|---|---|
committer | Lukas Rusak <lorusak@gmail.com> | 2022-07-28 20:32:32 -0700 |
commit | 67454c590387333f51da84547d4766be6b96ff9b (patch) | |
tree | 32bdd8538fafac82e759f8d110f5037cba7d2316 | |
parent | ed4003583e54aa3699430e2830a5dd97ffb634d6 (diff) |
CWinSystemGbm: add ability to set HDR output
4 files changed, 160 insertions, 99 deletions
diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp index a82da2225b..b91a1705ac 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp @@ -8,8 +8,10 @@ #include "VideoLayerBridgeDRMPRIME.h" +#include "ServiceBroker.h" #include "cores/VideoPlayer/Buffers/VideoBufferDRMPRIME.h" #include "utils/log.h" +#include "windowing/WinSystem.h" #include "windowing/gbm/drm/DRMAtomic.h" #include <utility> @@ -35,17 +37,12 @@ void CVideoLayerBridgeDRMPRIME::Disable() m_DRM->AddProperty(plane, "FB_ID", 0); m_DRM->AddProperty(plane, "CRTC_ID", 0); - // disable HDR metadata - auto connector = m_DRM->GetConnector(); - if (connector->SupportsProperty("HDR_OUTPUT_METADATA")) - { - m_DRM->AddProperty(connector, "HDR_OUTPUT_METADATA", 0); - m_DRM->SetActive(true); + auto winSystem = CServiceBroker::GetWinSystem(); + if (!winSystem) + return; - if (m_hdr_blob_id) - drmModeDestroyPropertyBlob(m_DRM->GetFileDescriptor(), m_hdr_blob_id); - m_hdr_blob_id = 0; - } + // disable HDR metadata + winSystem->SetHDR(nullptr); } void CVideoLayerBridgeDRMPRIME::Acquire(CVideoBufferDRMPRIME* buffer) @@ -159,8 +156,14 @@ void CVideoLayerBridgeDRMPRIME::Unmap(CVideoBufferDRMPRIME* buffer) void CVideoLayerBridgeDRMPRIME::Configure(CVideoBufferDRMPRIME* buffer) { + auto winSystem = CServiceBroker::GetWinSystem(); + if (!winSystem) + return; + const VideoPicture& picture = buffer->GetPicture(); + winSystem->SetHDR(&picture); + auto plane = m_DRM->GetVideoPlane(); bool result; @@ -172,64 +175,6 @@ void CVideoLayerBridgeDRMPRIME::Configure(CVideoBufferDRMPRIME* buffer) std::tie(result, value) = plane->GetPropertyValue("COLOR_RANGE", GetColorRange(picture)); if (result) m_DRM->AddProperty(plane, "COLOR_RANGE", value); - - auto connector = m_DRM->GetConnector(); - if (connector->SupportsProperty("HDR_OUTPUT_METADATA")) - { - m_hdr_metadata.metadata_type = HDMI_STATIC_METADATA_TYPE1; - m_hdr_metadata.hdmi_metadata_type1.eotf = GetEOTF(picture); - m_hdr_metadata.hdmi_metadata_type1.metadata_type = HDMI_STATIC_METADATA_TYPE1; - - if (m_hdr_blob_id) - drmModeDestroyPropertyBlob(m_DRM->GetFileDescriptor(), m_hdr_blob_id); - m_hdr_blob_id = 0; - - if (m_hdr_metadata.hdmi_metadata_type1.eotf) - { - const AVMasteringDisplayMetadata* mdmd = GetMasteringDisplayMetadata(picture); - if (mdmd && mdmd->has_primaries) - { - // Convert to unsigned 16-bit values in units of 0.00002, - // where 0x0000 represents zero and 0xC350 represents 1.0000 - for (int i = 0; i < 3; i++) - { - m_hdr_metadata.hdmi_metadata_type1.display_primaries[i].x = - std::round(av_q2d(mdmd->display_primaries[i][0]) * 50000.0); - m_hdr_metadata.hdmi_metadata_type1.display_primaries[i].y = - std::round(av_q2d(mdmd->display_primaries[i][1]) * 50000.0); - } - m_hdr_metadata.hdmi_metadata_type1.white_point.x = - std::round(av_q2d(mdmd->white_point[0]) * 50000.0); - m_hdr_metadata.hdmi_metadata_type1.white_point.y = - std::round(av_q2d(mdmd->white_point[1]) * 50000.0); - } - if (mdmd && mdmd->has_luminance) - { - // Convert to unsigned 16-bit value in units of 1 cd/m2, - // where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2 - m_hdr_metadata.hdmi_metadata_type1.max_display_mastering_luminance = - std::round(av_q2d(mdmd->max_luminance)); - - // Convert to unsigned 16-bit value in units of 0.0001 cd/m2, - // where 0x0001 represents 0.0001 cd/m2 and 0xFFFF represents 6.5535 cd/m2 - m_hdr_metadata.hdmi_metadata_type1.min_display_mastering_luminance = - std::round(av_q2d(mdmd->min_luminance) * 10000.0); - } - - const AVContentLightMetadata* clmd = GetContentLightMetadata(picture); - if (clmd) - { - m_hdr_metadata.hdmi_metadata_type1.max_cll = clmd->MaxCLL; - m_hdr_metadata.hdmi_metadata_type1.max_fall = clmd->MaxFALL; - } - - drmModeCreatePropertyBlob(m_DRM->GetFileDescriptor(), &m_hdr_metadata, sizeof(m_hdr_metadata), - &m_hdr_blob_id); - } - - m_DRM->AddProperty(connector, "HDR_OUTPUT_METADATA", m_hdr_blob_id); - m_DRM->SetActive(true); - } } void CVideoLayerBridgeDRMPRIME::SetVideoPlane(CVideoBufferDRMPRIME* buffer, const CRect& destRect) diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.h b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.h index 3a46a91a13..8d9758f8d6 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.h +++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.h @@ -15,34 +15,6 @@ #include <drm_mode.h> -#ifndef HAVE_HDR_OUTPUT_METADATA -// HDR structs is copied from linux include/linux/hdmi.h -struct hdr_metadata_infoframe -{ - uint8_t eotf; - uint8_t metadata_type; - struct - { - uint16_t x, y; - } display_primaries[3]; - struct - { - uint16_t x, y; - } white_point; - uint16_t max_display_mastering_luminance; - uint16_t min_display_mastering_luminance; - uint16_t max_cll; - uint16_t max_fall; -}; -struct hdr_output_metadata -{ - uint32_t metadata_type; - union { - struct hdr_metadata_infoframe hdmi_metadata_type1; - }; -}; -#endif - namespace KODI { namespace WINDOWING @@ -78,7 +50,4 @@ private: CVideoBufferDRMPRIME* m_buffer = nullptr; CVideoBufferDRMPRIME* m_prev_buffer = nullptr; - - uint32_t m_hdr_blob_id = 0; - struct hdr_output_metadata m_hdr_metadata = {}; }; diff --git a/xbmc/windowing/gbm/WinSystemGbm.cpp b/xbmc/windowing/gbm/WinSystemGbm.cpp index a109e08c80..863f1ec1f7 100644 --- a/xbmc/windowing/gbm/WinSystemGbm.cpp +++ b/xbmc/windowing/gbm/WinSystemGbm.cpp @@ -12,6 +12,7 @@ #include "OptionalsReg.h" #include "ServiceBroker.h" #include "VideoSyncGbm.h" +#include "cores/VideoPlayer/Buffers/VideoBufferDRMPRIME.h" #include "drm/DRMAtomic.h" #include "drm/DRMLegacy.h" #include "drm/OffScreenModeSetting.h" @@ -27,6 +28,35 @@ #include <mutex> #include <string.h> +#ifndef HAVE_HDR_OUTPUT_METADATA +// HDR structs is copied from linux include/linux/hdmi.h +struct hdr_metadata_infoframe +{ + uint8_t eotf; + uint8_t metadata_type; + struct + { + uint16_t x, y; + } display_primaries[3]; + struct + { + uint16_t x, y; + } white_point; + uint16_t max_display_mastering_luminance; + uint16_t min_display_mastering_luminance; + uint16_t max_cll; + uint16_t max_fall; +}; +struct hdr_output_metadata +{ + uint32_t metadata_type; + union + { + struct hdr_metadata_infoframe hdmi_metadata_type1; + }; +}; +#endif + using namespace KODI::WINDOWING::GBM; using namespace std::chrono_literals; @@ -282,3 +312,114 @@ std::vector<std::string> CWinSystemGbm::GetConnectedOutputs() { return m_DRM->GetConnectedConnectorNames(); } + +bool CWinSystemGbm::SetHDR(const VideoPicture* videoPicture) +{ + auto settingsComponent = CServiceBroker::GetSettingsComponent(); + if (!settingsComponent) + return false; + + auto settings = settingsComponent->GetSettings(); + if (!settings) + return false; + + if (!settings->GetBool(SETTING_WINSYSTEM_IS_HDR_DISPLAY)) + return false; + + auto drm = std::dynamic_pointer_cast<CDRMAtomic>(m_DRM); + if (!drm) + return false; + + if (!videoPicture) + { + auto connector = drm->GetConnector(); + if (connector->SupportsProperty("HDR_OUTPUT_METADATA")) + { + drm->AddProperty(connector, "HDR_OUTPUT_METADATA", 0); + drm->SetActive(true); + + if (m_hdr_blob_id) + drmModeDestroyPropertyBlob(drm->GetFileDescriptor(), m_hdr_blob_id); + m_hdr_blob_id = 0; + } + + return true; + } + + auto connector = drm->GetConnector(); + if (connector->SupportsProperty("HDR_OUTPUT_METADATA")) + { + hdr_output_metadata hdr_metadata = {}; + + hdr_metadata.metadata_type = DRMPRIME::HDMI_STATIC_METADATA_TYPE1; + hdr_metadata.hdmi_metadata_type1.eotf = DRMPRIME::GetEOTF(*videoPicture); + hdr_metadata.hdmi_metadata_type1.metadata_type = DRMPRIME::HDMI_STATIC_METADATA_TYPE1; + + if (m_hdr_blob_id) + drmModeDestroyPropertyBlob(drm->GetFileDescriptor(), m_hdr_blob_id); + m_hdr_blob_id = 0; + + if (hdr_metadata.hdmi_metadata_type1.eotf) + { + const AVMasteringDisplayMetadata* mdmd = DRMPRIME::GetMasteringDisplayMetadata(*videoPicture); + if (mdmd && mdmd->has_primaries) + { + // Convert to unsigned 16-bit values in units of 0.00002, + // where 0x0000 represents zero and 0xC350 represents 1.0000 + for (int i = 0; i < 3; i++) + { + hdr_metadata.hdmi_metadata_type1.display_primaries[i].x = + std::round(av_q2d(mdmd->display_primaries[i][0]) * 50000.0); + hdr_metadata.hdmi_metadata_type1.display_primaries[i].y = + std::round(av_q2d(mdmd->display_primaries[i][1]) * 50000.0); + } + hdr_metadata.hdmi_metadata_type1.white_point.x = + std::round(av_q2d(mdmd->white_point[0]) * 50000.0); + hdr_metadata.hdmi_metadata_type1.white_point.y = + std::round(av_q2d(mdmd->white_point[1]) * 50000.0); + } + if (mdmd && mdmd->has_luminance) + { + // Convert to unsigned 16-bit value in units of 1 cd/m2, + // where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2 + hdr_metadata.hdmi_metadata_type1.max_display_mastering_luminance = + std::round(av_q2d(mdmd->max_luminance)); + + // Convert to unsigned 16-bit value in units of 0.0001 cd/m2, + // where 0x0001 represents 0.0001 cd/m2 and 0xFFFF represents 6.5535 cd/m2 + hdr_metadata.hdmi_metadata_type1.min_display_mastering_luminance = + std::round(av_q2d(mdmd->min_luminance) * 10000.0); + } + + const AVContentLightMetadata* clmd = DRMPRIME::GetContentLightMetadata(*videoPicture); + if (clmd) + { + hdr_metadata.hdmi_metadata_type1.max_cll = clmd->MaxCLL; + hdr_metadata.hdmi_metadata_type1.max_fall = clmd->MaxFALL; + } + + drmModeCreatePropertyBlob(drm->GetFileDescriptor(), &hdr_metadata, sizeof(hdr_metadata), + &m_hdr_blob_id); + } + + drm->AddProperty(connector, "HDR_OUTPUT_METADATA", m_hdr_blob_id); + drm->SetActive(true); + } + + return true; +} + +bool CWinSystemGbm::IsHDRDisplay() +{ + auto drm = std::dynamic_pointer_cast<CDRMAtomic>(m_DRM); + if (!drm) + return false; + + auto connector = drm->GetConnector(); + if (!connector) + return false; + + //! @todo: improve detection (edid?) + // we have no way to know if the display is actually HDR capable and we blindly set the HDR metadata + return connector->SupportsProperty("HDR_OUTPUT_METADATA"); +} diff --git a/xbmc/windowing/gbm/WinSystemGbm.h b/xbmc/windowing/gbm/WinSystemGbm.h index ab156be786..b313d331d5 100644 --- a/xbmc/windowing/gbm/WinSystemGbm.h +++ b/xbmc/windowing/gbm/WinSystemGbm.h @@ -57,6 +57,9 @@ public: void Register(IDispResource* resource) override; void Unregister(IDispResource* resource) override; + bool SetHDR(const VideoPicture* videoPicture) override; + bool IsHDRDisplay() override; + std::shared_ptr<CVideoLayerBridge> GetVideoLayerBridge() const { return m_videoLayerBridge; } void RegisterVideoLayerBridge(std::shared_ptr<CVideoLayerBridge> bridge) { @@ -83,6 +86,9 @@ protected: bool m_dispReset = false; XbmcThreads::EndTime<> m_dispResetTimer; std::unique_ptr<CLibInputHandler> m_libinput; + +private: + uint32_t m_hdr_blob_id = 0; }; } |