From a0349d40e3573ce9b868874b5567e36d9d9bd7bb Mon Sep 17 00:00:00 2001 From: Wan Shuang Date: Sun, 3 Nov 2019 01:50:14 +0800 Subject: [PATCH] Added the HDR & WCG support for Android. This is the initial draft patch to add HDR & WCG support for Android. It combines work from Kishore, Yue and Shuang. The patchset is follow the HWC 2.2/2.3 API defintion as the main reference for implementation and haven't tested on real device yet. Further revision is expected according to real test and debug iterations. Signed-off-by: HeYue yue.he@intel.com Signed-off-by: Kishore Kadiyala kishore.kadiyala@intel.com Signed-off-by: Wan Shuang --- common/core/logicaldisplay.cpp | 26 + common/core/logicaldisplay.h | 13 + common/core/mosaicdisplay.cpp | 25 + common/core/mosaicdisplay.h | 12 + common/core/overlaylayer.cpp | 2 + common/core/overlaylayer.h | 15 +- common/display/virtualdisplay.cpp | 26 + common/display/virtualdisplay.h | 12 + common/display/virtualpanoramadisplay.cpp | 28 + common/display/virtualpanoramadisplay.h | 10 + configure.ac | 1 + os/android/iahwc2.cpp | 120 +++- os/android/iahwc2.h | 9 + public/colorspace.h | 65 +++ public/hdr_metadata_defs.h | 82 +++ public/hwclayer.h | 106 +++- public/nativedisplay.h | 45 ++ tests/Makefile.am | 24 +- tests/apps/jsonlayerstest.cpp | 1 - tests/apps/linux_hdr_image_test.cpp | 657 ++++++++++++++++++++++ wsi/drm/drmdisplay.cpp | 429 ++++++++++++-- wsi/drm/drmdisplay.h | 119 +++- wsi/physicaldisplay.h | 11 + 23 files changed, 1763 insertions(+), 75 deletions(-) create mode 100644 public/colorspace.h create mode 100644 public/hdr_metadata_defs.h create mode 100644 tests/apps/linux_hdr_image_test.cpp diff --git a/common/core/logicaldisplay.cpp b/common/core/logicaldisplay.cpp index 6afd4b05c..94dc4ec6b 100644 --- a/common/core/logicaldisplay.cpp +++ b/common/core/logicaldisplay.cpp @@ -249,4 +249,30 @@ void LogicalDisplay::GetDisplayCapabilities(uint32_t *numCapabilities, physical_display_->GetDisplayCapabilities(numCapabilities, capabilities); } +bool LogicalDisplay::GetHdrCapabilities(uint32_t *outNumTypes, + int32_t *outTypes, + float *outMaxLuminance, + float *outMaxAverageLuminance, + float *outMinLuminance) { + return true; +} + +bool LogicalDisplay::GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents) { + return true; +} + +bool LogicalDisplay::GetPerFrameMetadataKeys(uint32_t *outNumKeys, + int32_t *outKeys) { + return true; +} + +bool LogicalDisplay::SetColorMode(int32_t mode) { + return true; +} + +bool LogicalDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) { + return true; +} + } // namespace hwcomposer diff --git a/common/core/logicaldisplay.h b/common/core/logicaldisplay.h index 30e3f1b66..089752129 100644 --- a/common/core/logicaldisplay.h +++ b/common/core/logicaldisplay.h @@ -111,6 +111,19 @@ class LogicalDisplay : public NativeDisplay { void GetDisplayCapabilities(uint32_t *numCapabilities, uint32_t *capabilities) override; + bool GetHdrCapabilities(uint32_t *outNumTypes, int32_t *outTypes, + float *outMaxLuminance, float *outMaxAverageLuminance, + float *outMinLuminance) override; + + bool GetPerFrameMetadataKeys(uint32_t *outNumKeys, int32_t *outKeys) override; + + bool GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents) override; + + bool SetColorMode(int32_t mode) override; + + bool GetColorModes(uint32_t *num_modes, int32_t *modes) override; + uint32_t GetXTranslation() override { return (((physical_display_->Width()) / total_divisions_) * index_); } diff --git a/common/core/mosaicdisplay.cpp b/common/core/mosaicdisplay.cpp index df13445bc..369ac0205 100644 --- a/common/core/mosaicdisplay.cpp +++ b/common/core/mosaicdisplay.cpp @@ -633,6 +633,31 @@ void MosaicDisplay::GetDisplayCapabilities(uint32_t *numCapabilities, } } +bool MosaicDisplay::GetHdrCapabilities(uint32_t *outNumTypes, int32_t *outTypes, + float *outMaxLuminance, + float *outMaxAverageLuminance, + float *outMinLuminance) { + return true; +} + +bool MosaicDisplay::SetColorMode(int32_t mode) { + return true; +} + +bool MosaicDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) { + return true; +} + +bool MosaicDisplay::GetPerFrameMetadataKeys(uint32_t *outNumKeys, + int32_t *outKeys) { + return true; +} + +bool MosaicDisplay::GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents) { + return true; +} + void MosaicDisplay::SetHDCPState(HWCContentProtection state, HWCContentType content_type) { uint32_t size = physical_displays_.size(); diff --git a/common/core/mosaicdisplay.h b/common/core/mosaicdisplay.h index 7f019d4aa..36a5fc1a2 100644 --- a/common/core/mosaicdisplay.h +++ b/common/core/mosaicdisplay.h @@ -107,6 +107,18 @@ class MosaicDisplay : public NativeDisplay { void GetDisplayCapabilities(uint32_t *numCapabilities, uint32_t *capabilities) override; + bool GetHdrCapabilities(uint32_t *outNumTypes, int32_t *outTypes, + float *outMaxLuminance, float *outMaxAverageLuminance, + float *outMinLuminance) override; + bool GetPerFrameMetadataKeys(uint32_t *outNumKeys, int32_t *outKeys) override; + + bool GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents) override; + + bool SetColorMode(int32_t mode) override; + + bool GetColorModes(uint32_t *num_modes, int32_t *modes) override; + uint32_t GetXTranslation() override { return 0; } diff --git a/common/core/overlaylayer.cpp b/common/core/overlaylayer.cpp index 8497a66ef..e38407e87 100644 --- a/common/core/overlaylayer.cpp +++ b/common/core/overlaylayer.cpp @@ -289,6 +289,8 @@ void OverlayLayer::InitializeState(HwcLayer* layer, dataspace_ = layer->GetDataSpace(); blending_ = layer->GetBlending(); solid_color_ = layer->GetSolidColor(); + hdrmetadata = layer->GetHdrMetadata(); + color_space = layer->GetColorSpace(); TransformDamage(layer, max_height, max_width); if (previous_layer && layer->HasZorderChanged()) { diff --git a/common/core/overlaylayer.h b/common/core/overlaylayer.h index 6847ea686..2f7f2eab6 100644 --- a/common/core/overlaylayer.h +++ b/common/core/overlaylayer.h @@ -18,10 +18,10 @@ #define COMMON_CORE_OVERLAYLAYER_H_ #include -#include - #include +#include #include +#include "hdr_metadata_defs.h" #include "overlaybuffer.h" @@ -241,6 +241,14 @@ struct OverlayLayer { return state_ & kForcePartialClear; } + struct hdr_metadata GetHdrMetadata() { + return hdrmetadata; + } + + uint32_t GetColorSpace() { + return color_space; + } + uint32_t GetSolidColor() { return solid_color_; } @@ -316,6 +324,9 @@ struct OverlayLayer { LayerComposition supported_composition_ = kAll; LayerComposition actual_composition_ = kAll; HWCLayerType type_ = kLayerNormal; + + struct hdr_metadata hdrmetadata; + uint32_t color_space; }; } // namespace hwcomposer diff --git a/common/display/virtualdisplay.cpp b/common/display/virtualdisplay.cpp index 9575a72a0..183243754 100644 --- a/common/display/virtualdisplay.cpp +++ b/common/display/virtualdisplay.cpp @@ -512,6 +512,32 @@ void VirtualDisplay::GetDisplayCapabilities(uint32_t *numCapabilities, uint32_t *capabilities) { } +bool VirtualDisplay::GetHdrCapabilities(uint32_t *outNumTypes, + int32_t *outTypes, + float *outMaxLuminance, + float *outMaxAverageLuminance, + float *outMinLuminance) { + return true; +} + +bool VirtualDisplay::GetPerFrameMetadataKeys(uint32_t *outNumKeys, + int32_t *outKeys) { + return true; +} + +bool VirtualDisplay::GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents) { + return true; +} + +bool VirtualDisplay::SetColorMode(int32_t mode) { + return true; +} + +bool VirtualDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) { + return true; +} + int VirtualDisplay::GetDisplayPipe() { return -1; } diff --git a/common/display/virtualdisplay.h b/common/display/virtualdisplay.h index 4b3593a15..b38836d3c 100644 --- a/common/display/virtualdisplay.h +++ b/common/display/virtualdisplay.h @@ -83,6 +83,18 @@ class VirtualDisplay : public NativeDisplay { void GetDisplayCapabilities(uint32_t *numCapabilities, uint32_t *capabilities) override; + bool GetHdrCapabilities(uint32_t *outNumTypes, int32_t *outTypes, + float *outMaxLuminance, float *outMaxAverageLuminance, + float *outMinLuminance) override; + bool GetPerFrameMetadataKeys(uint32_t *outNumKeys, int32_t *outKeys) override; + + bool GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents) override; + + bool SetColorMode(int32_t mode) override; + + bool GetColorModes(uint32_t *num_modes, int32_t *modes) override; + int GetDisplayPipe() override; bool SetPowerMode(uint32_t power_mode) override; diff --git a/common/display/virtualpanoramadisplay.cpp b/common/display/virtualpanoramadisplay.cpp index b9c045b4c..588d914ab 100644 --- a/common/display/virtualpanoramadisplay.cpp +++ b/common/display/virtualpanoramadisplay.cpp @@ -502,6 +502,34 @@ bool VirtualPanoramaDisplay::GetDisplayAttribute(uint32_t /*config*/, return true; } +bool VirtualPanoramaDisplay::GetHdrCapabilities(uint32_t *outNumTypes, + int32_t *outTypes, + float *outMaxLuminance, + float *outMaxAverageLuminance, + float *outMinLuminance) { + return true; +} + +bool VirtualPanoramaDisplay::GetPerFrameMetadataKeys(uint32_t *outNumKeys, + int32_t *outKeys) { + return true; +} + +bool VirtualPanoramaDisplay::GetRenderIntents(int32_t mode, + uint32_t *outNumIntents, + int32_t *outIntents) { + return true; +} + +bool VirtualPanoramaDisplay::SetColorMode(int32_t mode) { + return true; +} + +bool VirtualPanoramaDisplay::GetColorModes(uint32_t *num_modes, + int32_t *modes) { + return true; +} + bool VirtualPanoramaDisplay::GetDisplayConfigs(uint32_t *num_configs, uint32_t *configs) { if (!num_configs) diff --git a/common/display/virtualpanoramadisplay.h b/common/display/virtualpanoramadisplay.h index 36d76a028..f86df37b8 100644 --- a/common/display/virtualpanoramadisplay.h +++ b/common/display/virtualpanoramadisplay.h @@ -86,7 +86,17 @@ class VirtualPanoramaDisplay : public NativeDisplay { bool GetDisplayName(uint32_t *size, char *name) override; int GetDisplayPipe() override; + bool GetHdrCapabilities(uint32_t *outNumTypes, int32_t *outTypes, + float *outMaxLuminance, float *outMaxAverageLuminance, + float *outMinLuminance) override; + bool GetPerFrameMetadataKeys(uint32_t *outNumKeys, int32_t *outKeys) override; + + bool GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents) override; + bool SetPowerMode(uint32_t power_mode) override; + bool SetColorMode(int32_t mode) override; + bool GetColorModes(uint32_t *num_modes, int32_t *modes) override; #ifdef HYPER_DMABUF_SHARING bool SetHyperDmaBufMode(uint32_t mode); diff --git a/configure.ac b/configure.ac index 62385db71..513b79b78 100644 --- a/configure.ac +++ b/configure.ac @@ -213,6 +213,7 @@ AX_COMPILE_CHECK_SIZEOF(size_t, [#include ]) ####################################################################### PKG_CHECK_MODULES(DRM, [libdrm]) +PKG_CHECK_MODULES(DRM_INTEL, [libdrm_intel]) PKG_CHECK_MODULES(GBM, [gbm]) PKG_CHECK_MODULES(EGL, [egl]) PKG_CHECK_MODULES(GLES2, [glesv2]) diff --git a/os/android/iahwc2.cpp b/os/android/iahwc2.cpp index 655cf855e..048386d65 100644 --- a/os/android/iahwc2.cpp +++ b/os/android/iahwc2.cpp @@ -546,12 +546,17 @@ HWC2::Error IAHWC2::HwcDisplay::GetClientTargetSupport(uint32_t width, HWC2::Error IAHWC2::HwcDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) { supported(__func__); - if (!modes) - *num_modes = 1; - - if (modes) - *modes = HAL_COLOR_MODE_NATIVE; + if (!modes) { + display_->GetColorModes(num_modes, NULL); + } + if (modes) { + if (display_->GetColorModes(num_modes, modes)) { + return HWC2::Error::None; + } else { + return HWC2::Error::Unsupported; + } + } return HWC2::Error::None; } @@ -632,12 +637,58 @@ HWC2::Error IAHWC2::HwcDisplay::GetDozeSupport(int32_t *support) { return HWC2::Error::None; } -HWC2::Error IAHWC2::HwcDisplay::GetHdrCapabilities( - uint32_t *num_types, int32_t * /*types*/, float * /*max_luminance*/, - float * /*max_average_luminance*/, float * /*min_luminance*/) { +HWC2::Error IAHWC2::HwcDisplay::GetHdrCapabilities(uint32_t *num_types, + int32_t *types, + float *max_luminance, + float *max_average_luminance, + float *min_luminance) { supported(__func__); *num_types = 0; - return HWC2::Error::None; + + if (display_->GetHdrCapabilities(num_types, types, max_luminance, + max_average_luminance, min_luminance)) { + return HWC2::Error::None; + } else { + return HWC2::Error::Unsupported; + } +} + +HWC2::Error IAHWC2::HwcDisplay::GetPerFrameMetadataKeys(uint32_t *outNumKeys, + int32_t *outKeys) { + supported(__func__); + + if (NULL == outNumKeys || NULL == outKeys) { + return HWC2::Error::BadParameter; + } + + *outNumKeys = 0; + if (display_->GetPerFrameMetadataKeys(outNumKeys, outKeys)) { + return HWC2::Error::None; + } else { + return HWC2::Error::Unsupported; + } +} + +HWC2::Error IAHWC2::HwcDisplay::GetRenderIntents(int32_t mode, + uint32_t *outNumIntents, + int32_t *outIntents) { + supported(__func__); + + if (NULL == outNumIntents || NULL == outIntents) { + ALOGE("Null pointer error, outNumIntents: %p, outIntents: %p", + outNumIntents, outIntents); + return HWC2::Error::BadParameter; + } + + // Add the SDR render intents by default. + *outNumIntents = 2; + *(outIntents) = HAL_RENDER_INTENT_COLORIMETRIC; + *(outIntents + 1) = HAL_RENDER_INTENT_ENHANCE; + if (display_->GetRenderIntents(mode, outNumIntents, outIntents)) { + return HWC2::Error::None; + } else { + return HWC2::Error::BadParameter; + } } HWC2::Error IAHWC2::HwcDisplay::GetReleaseFences(uint32_t *num_elements, @@ -832,7 +883,15 @@ HWC2::Error IAHWC2::HwcDisplay::SetColorMode(int32_t mode) { // TODO: Use the parameter mode to set the color mode for the display to be // used. - return HWC2::Error::None; + if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_DISPLAY_P3) + return HWC2::Error::BadParameter; + + if (display_->SetColorMode(mode)) { + return HWC2::Error::None; + } else { + return HWC2::Error::Unsupported; + } + } HWC2::Error IAHWC2::HwcDisplay::SetColorModeWithRenderIntent(int32_t mode, @@ -878,13 +937,8 @@ HWC2::Error IAHWC2::HwcDisplay::SetColorTransform(const float *matrix, supported(__func__); // TODO: Force client composition if we get this - if (hint != HAL_COLOR_TRANSFORM_IDENTITY && - hint != HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX && - hint != HAL_COLOR_TRANSFORM_VALUE_INVERSE && - hint != HAL_COLOR_TRANSFORM_GRAYSCALE && - hint != HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA && - hint != HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA && - hint != HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA) + if (!matrix || (hint < HAL_COLOR_TRANSFORM_IDENTITY || + hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)) return HWC2::Error::BadParameter; display_->SetColorTransform(matrix, (HWCColorTransform)hint); @@ -1295,7 +1349,12 @@ HWC2::Error IAHWC2::Hwc2Layer::SetLayerZOrder(uint32_t order) { HWC2::Error IAHWC2::Hwc2Layer::SetLayerColorTransform(const float *matrix) { unsupported(__func__); - return HWC2::Error::None; + + if (hwc_layer_.SetLayerColorTransform(matrix)) { + return HWC2::Error::None; + } else { + return HWC2::Error::Unsupported; + } } HWC2::Error IAHWC2::Hwc2Layer::SetLayerPerFrameMetadataBlobs( @@ -1305,6 +1364,16 @@ HWC2::Error IAHWC2::Hwc2Layer::SetLayerPerFrameMetadataBlobs( return HWC2::Error::None; } +HWC2::Error IAHWC2::Hwc2Layer::SetLayerPerFrameMetadata(uint32_t numElements, + const int32_t *keys, + const float *metadata) { + if (hwc_layer_.SetLayerPerFrameMetadata(numElements, keys, metadata)) { + return HWC2::Error::None; + } else { + return HWC2::Error::BadParameter; + } +} + // static int IAHWC2::HookDevClose(hw_device_t * /*dev*/) { unsupported(__func__); @@ -1409,6 +1478,16 @@ hwc2_function_pointer_t IAHWC2::HookDevGetFunction(struct hwc2_device * /*dev*/, DisplayHook); + case HWC2::FunctionDescriptor::GetPerFrameMetadataKeys: + return ToHook( + DisplayHook); + case HWC2::FunctionDescriptor::GetRenderIntents: + return ToHook( + DisplayHook); case HWC2::FunctionDescriptor::GetReleaseFences: return ToHook( DisplayHook); + case HWC2::FunctionDescriptor::SetLayerPerFrameMetadata: + return ToHook( + LayerHook); case HWC2::FunctionDescriptor::Invalid: default: return NULL; diff --git a/os/android/iahwc2.h b/os/android/iahwc2.h index 4d995525f..b0ef22b63 100644 --- a/os/android/iahwc2.h +++ b/os/android/iahwc2.h @@ -151,6 +151,10 @@ class IAHWC2 : public hwc2_device_t { const uint32_t *sizes, const uint8_t *metadata); + HWC2::Error SetLayerPerFrameMetadata(uint32_t numElements, + const int32_t *keys, + const float *metadata); + private: // sf_type_ stores the initial type given to us by surfaceflinger, // validated_type_ stores the type after running ValidateDisplay @@ -228,6 +232,11 @@ class IAHWC2 : public hwc2_device_t { float *max_luminance, float *max_average_luminance, float *min_luminance); + HWC2::Error GetPerFrameMetadataKeys(uint32_t *outNumKeys, int32_t *outKeys); + + HWC2::Error GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents); + HWC2::Error GetReleaseFences(uint32_t *num_elements, hwc2_layer_t *layers, int32_t *fences); HWC2::Error PresentDisplay(int32_t *retire_fence); diff --git a/public/colorspace.h b/public/colorspace.h new file mode 100644 index 000000000..1672a68fd --- /dev/null +++ b/public/colorspace.h @@ -0,0 +1,65 @@ +/* + * Copyright © 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef PUBLIC_COLORSPACE_H +#define PUBLIC_COLORSPACE_H + +/** A CIE 1931 color space*/ +struct cie_xy { + double x; + double y; +}; + +struct color_primaries { + struct cie_xy r; + struct cie_xy g; + struct cie_xy b; + struct cie_xy white_point; +}; + +struct colorspace { + struct color_primaries primaries; + const char *name; + const char *whitepoint_name; +}; + +enum colorspace_enums { + CS_BT470M, + CS_BT470BG, + CS_SMPTE170M, + CS_SMPTE240M, + CS_BT709, + CS_BT2020, + CS_SRGB, + CS_ADOBERGB, + CS_DCI_P3, + CS_PROPHOTORGB, + CS_CIERGB, + CS_CIEXYZ, + CS_AP0, + CS_AP1, + CS_UNDEFINED +}; +#endif diff --git a/public/hdr_metadata_defs.h b/public/hdr_metadata_defs.h new file mode 100644 index 000000000..6d9daceb1 --- /dev/null +++ b/public/hdr_metadata_defs.h @@ -0,0 +1,82 @@ +/* + * Copyright © 2018 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef PUBLIC_HDR_METADATA_DEFS_H +#define PUBLIC_HDR_METADATA_DEFS_H + +#include +#include "colorspace.h" + +enum hdr_metadata_type { + HDR_METADATA_TYPE1, + HDR_METADATA_TYPE2, +}; + +enum hdr_metadata_eotf { + EOTF_TRADITIONAL_GAMMA_SDR, + EOTF_TRADITIONAL_GAMMA_HDR, + EOTF_ST2084, + EOTF_HLG, +}; + +enum hdr_per_frame_metadata_keys { + KEY_DISPLAY_RED_PRIMARY_X, + KEY_DISPLAY_RED_PRIMARY_Y, + KEY_DISPLAY_GREEN_PRIMARY_X, + KEY_DISPLAY_GREEN_PRIMARY_Y, + KEY_DISPLAY_BLUE_PRIMARY_X, + KEY_DISPLAY_BLUE_PRIMARY_Y, + KEY_WHITE_POINT_X, + KEY_WHITE_POINT_Y, + KEY_MAX_LUMINANCE, + KEY_MIN_LUMINANCE, + KEY_MAX_CONTENT_LIGHT_LEVEL, + KEY_MAX_FRAME_AVERAGE_LIGHT_LEVEL, + KEY_NUM_PER_FRAME_METADATA_KEYS +}; + +struct hdr_metadata_dynamic { + uint8_t size; + uint8_t *metadata; +}; + +struct hdr_metadata_static { + struct color_primaries primaries; + double max_luminance; + double min_luminance; + uint32_t max_cll; + uint32_t max_fall; + uint8_t eotf; +}; + +struct hdr_metadata { + enum hdr_metadata_type metadata_type; + union { + struct hdr_metadata_static static_metadata; + struct hdr_metadata_dynamic dynamic_metadata; + } metadata; +}; + +#endif diff --git a/public/hwclayer.h b/public/hwclayer.h index bd8a00402..97b1773a8 100644 --- a/public/hwclayer.h +++ b/public/hwclayer.h @@ -18,8 +18,10 @@ #define PUBLIC_HWCLAYER_H_ #include - #include +#include "hdr_metadata_defs.h" + +#define STATIC_METADATA(x) hdr_mdata.metadata.static_metadata.x namespace hwcomposer { @@ -70,10 +72,100 @@ struct HwcLayer { void SetDisplayFrame(const HwcRect& display_frame, int translate_x_pos, int translate_y_pos); + void SetColorSpace(int clrspace) { + colorspace = clrspace; + } + + void SetHdrMetadata(double primary_r_x, double primary_r_y, + double primary_g_x, double primary_g_y, + double primary_b_x, double primary_b_y, + double white_point_x, double white_point_y, + double max_luminance, double min_luminance, int max_cll, + int max_fall) { + STATIC_METADATA(primaries.r.x) = primary_r_x; + STATIC_METADATA(primaries.r.y) = primary_r_y; + STATIC_METADATA(primaries.g.x) = primary_g_x; + STATIC_METADATA(primaries.g.y) = primary_g_y; + STATIC_METADATA(primaries.b.x) = primary_b_x; + STATIC_METADATA(primaries.b.y) = primary_b_y; + STATIC_METADATA(primaries.white_point.x) = white_point_x; + STATIC_METADATA(primaries.white_point.y) = white_point_y; + STATIC_METADATA(max_luminance) = max_luminance; + STATIC_METADATA(min_luminance) = min_luminance; + STATIC_METADATA(max_cll) = max_cll; + STATIC_METADATA(max_fall) = max_fall; + } + + void SetHdrEotf(int internal_eotf) { + hdr_mdata.metadata_type = HDR_METADATA_TYPE1; + STATIC_METADATA(eotf) = internal_eotf; + } + uint32_t GetDataSpace() const { return dataspace_; } + bool SetLayerPerFrameMetadata(uint32_t numElements, const int32_t* keys, + const float* metadata) { + if (0 == numElements || NULL == keys || NULL == metadata) { + ALOGE("Bad parameters!"); + return false; + } + + for (uint32_t i = 0; i < numElements; i++) { + int32_t key = *(keys + i); + float keyvalue = *(metadata + i); + switch (key) { + case KEY_DISPLAY_RED_PRIMARY_X: + STATIC_METADATA(primaries.r.x) = keyvalue; + break; + case KEY_DISPLAY_RED_PRIMARY_Y: + STATIC_METADATA(primaries.r.y) = keyvalue; + break; + case KEY_DISPLAY_GREEN_PRIMARY_X: + STATIC_METADATA(primaries.g.x) = keyvalue; + break; + case KEY_DISPLAY_GREEN_PRIMARY_Y: + STATIC_METADATA(primaries.g.y) = keyvalue; + break; + case KEY_DISPLAY_BLUE_PRIMARY_X: + STATIC_METADATA(primaries.b.x) = keyvalue; + break; + case KEY_DISPLAY_BLUE_PRIMARY_Y: + STATIC_METADATA(primaries.b.y) = keyvalue; + break; + case KEY_WHITE_POINT_X: + STATIC_METADATA(primaries.white_point.x) = keyvalue; + break; + case KEY_WHITE_POINT_Y: + STATIC_METADATA(primaries.white_point.y) = keyvalue; + break; + case KEY_MAX_LUMINANCE: + STATIC_METADATA(max_luminance) = keyvalue; + break; + case KEY_MIN_LUMINANCE: + STATIC_METADATA(min_luminance) = keyvalue; + break; + case KEY_MAX_CONTENT_LIGHT_LEVEL: + STATIC_METADATA(max_cll) = keyvalue; + break; + case KEY_MAX_FRAME_AVERAGE_LIGHT_LEVEL: + STATIC_METADATA(max_fall) = keyvalue; + break; + default: + ALOGE("Unkonwn HDR metda key: %u, value: %f", key, keyvalue); + break; + } + } + + return true; + } + + bool SetLayerColorTransform(const float *matrix) { + memcpy(layer_color_transform_, matrix, sizeof(layer_color_transform_)); + return true; + } + const HwcRect& GetDisplayFrame() const { return display_frame_; } @@ -243,6 +335,14 @@ struct HwcLayer { return solid_color_; } + uint32_t GetColorSpace() { + return colorspace; + } + + struct hdr_metadata GetHdrMetadata() { + return hdr_mdata; + } + bool HasZorderChanged() const { return state_ & kZorderChanged; } @@ -317,6 +417,7 @@ struct HwcLayer { }; int32_t transform_ = 0; + float layer_color_transform_[16]; uint32_t source_crop_width_ = 0; uint32_t source_crop_height_ = 0; uint32_t display_frame_width_ = 0; @@ -344,6 +445,9 @@ struct HwcLayer { bool is_video_layer_ = false; uint32_t solid_color_ = 0xff; + struct hdr_metadata hdr_mdata; + uint32_t colorspace; + HWCLayerCompositionType composition_type_ = Composition_Device; }; diff --git a/public/nativedisplay.h b/public/nativedisplay.h index 4f17b1dbc..66e657161 100644 --- a/public/nativedisplay.h +++ b/public/nativedisplay.h @@ -96,6 +96,16 @@ class NativeDisplay { virtual void GetDisplayCapabilities(uint32_t *outNumCapabilities, uint32_t *outCapabilities) = 0; + virtual bool GetHdrCapabilities(uint32_t *outNumTypes, int32_t *outTypes, + float *outMaxLuminance, + float *outMaxAverageLuminance, + float *outMinLuminance) = 0; + + virtual bool GetPerFrameMetadataKeys(uint32_t *outNumKeys, + int32_t *outKeys) = 0; + + virtual bool GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents) = 0; /** * API for getting connected display's pipe id. * @return "-1" for unconnected display, valid values are 0 ~ 2. @@ -170,6 +180,41 @@ class NativeDisplay { virtual void SetGamma(float /*red*/, float /*green*/, float /*blue*/) { } + /** + * Sets the color mode of the given display. + * + * This must be called outside of validateDisplay/presentDisplay, and it takes + * effect on next presentDisplay. + * + * The valid color modes can be found in android_color_mode_t in + * . All HWC2 devices must support at least + * HAL_COLOR_MODE_NATIVE, and displays are assumed to be in this mode upon + * hotplug. + * + * Parameters: + * mode - the mode to set + */ + virtual bool SetColorMode(int32_t mode) = 0; + + /** + * Gets the color modes supported on this display. + * + * The valid color modes can be found in android_color_mode_t in + * . All HWC2 devices must support at least + * HAL_COLOR_MODE_NATIVE. + * + * outNumModes may be NULL to retrieve the number of modes which will be + * returned. + * + * Parameters: + * outNumModes - if outModes was NULL, the number of modes which would have + * been returned; if outModes was not NULL, the number of modes returned, + * which must not exceed the value stored in outNumModes prior to the + * call; pointer will be non-NULL + * outModes - an array of color modes + */ + virtual bool GetColorModes(uint32_t *num_modes, int32_t *modes) = 0; + /** * API for setting a color transform which will be applied after composition. * diff --git a/tests/Makefile.am b/tests/Makefile.am index c4a9c90c0..7002a55d9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -17,7 +17,8 @@ if ENABLE_DUMMY_COMPOSITOR AM_CPPFLAGS = -DUSE_DC else bin_PROGRAMS = testlayers \ - linux_test + linux_test \ + linux_hdr_image_test testlayers_LDFLAGS = \ -no-undefined @@ -46,10 +47,31 @@ testlayers_SOURCES = \ ./common/layerrenderer.cpp \ ./common/gllayerrenderer.cpp \ ./common/glcubelayerrenderer.cpp \ + ./common/videolayerrenderer.cpp \ ./common/esTransform.cpp \ ./common/jsonhandlers.cpp \ ./apps/jsonlayerstest.cpp +linux_hdr_image_test_LDADD = \ + $(DRM_LIBS) \ + $(DRM_INTEL_LIBS) \ + $(GBM_LIBS) \ + $(EGL_LIBS) \ + $(GLES2_LIBS) \ + $(top_builddir)/libhwcomposer.la + +linux_hdr_image_test_CFLAGS = \ + -O0 -g -lm \ + $(DRM_CFLAGS) \ + $(DRM_INTEL_CFLAGS) \ + $(GBM_CFLAGS) \ + $(EGL_CFLAGS) \ + $(GLES2_CFLAGS) \ + $(AM_CPPFLAGS) + +linux_hdr_image_test_SOURCES = \ + ./apps/linux_hdr_image_test.cpp + linux_test_LDFLAGS = \ -no-undefined diff --git a/tests/apps/jsonlayerstest.cpp b/tests/apps/jsonlayerstest.cpp index 96b531e25..c2a7f3dfb 100644 --- a/tests/apps/jsonlayerstest.cpp +++ b/tests/apps/jsonlayerstest.cpp @@ -702,7 +702,6 @@ static void init_frames(int32_t width, int32_t height) { printf("un-recognized layer type!\n"); exit(-1); } - if (!renderer->Init(layer_parameter.source_width, layer_parameter.source_height, gbm_format, usage_format, usage, &gl, diff --git a/tests/apps/linux_hdr_image_test.cpp b/tests/apps/linux_hdr_image_test.cpp new file mode 100644 index 000000000..6671b76d7 --- /dev/null +++ b/tests/apps/linux_hdr_image_test.cpp @@ -0,0 +1,657 @@ +/* +// Copyright (c) 2019 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "commondrmutils.h" +#include "hdr_metadata_defs.h" +#include "platformcommondefines.h" + +#define NUM_BUFFERS 1 + +#ifndef DRM_FORMAT_MOD_LINEAR +#define DRM_FORMAT_MOD_LINEAR 0 +#endif + +#ifndef DRM_FORMAT_P010 +#define DRM_FORMAT_P010 \ + fourcc_code('P', '0', '1', \ + '0') /* 2x2 subsampled Cb:Cr plane 10 bits per channel */ +#endif + +#ifndef DRM_FORMAT_P012 +#define DRM_FORMAT_P012 \ + fourcc_code('P', '0', '1', \ + '2') /* 2x2 subsampled Cr:Cb plane, 12 bit per channel */ +#endif + +#ifndef DRM_FORMAT_P016 +#define DRM_FORMAT_P016 \ + fourcc_code('P', '0', '1', \ + '6') /* 2x2 subsampled Cr:Cb plane, 16 bit per channel */ +#endif + +struct buffer; + +struct drm_device { + int fd; + char *name; + + int (*alloc_bo)(struct buffer *buf); + void (*free_bo)(struct buffer *buf); + int (*export_bo_to_prime)(struct buffer *buf); + int (*map_bo)(struct buffer *buf); + void (*unmap_bo)(struct buffer *buf); + void (*device_destroy)(struct buffer *buf); +}; + +struct buffer { + int busy; + + struct drm_device *dev; + int drm_fd; + + drm_intel_bufmgr *bufmgr; + drm_intel_bo *intel_bo; + + uint32_t gem_handle; + int dmabuf_fd; + uint8_t *mmap; + + int width; + int height; + int bpp; + unsigned long stride; + int format; +}; + +struct image { + int fd; + FILE *fp; + int size; + struct buffer buffers[NUM_BUFFERS]; + struct buffer *prev_buffer; +}; + +static int create_dmabuf_buffer(struct buffer *buffer, int width, int height, + int format); + +static void drm_shutdown(struct buffer *my_buf); + +static void destroy_dmabuf_buffer(struct buffer *buffer) { + close(buffer->dmabuf_fd); + buffer->dev->free_bo(buffer); + drm_shutdown(buffer); +} + +static struct buffer *image_next_buffer(struct image *s) { + int i; + + for (i = 0; i < NUM_BUFFERS; i++) + if (!s->buffers[i].busy) + return &s->buffers[i]; + + return NULL; +} + +static void fill_buffer(struct buffer *buffer, struct image *image) { + int i = 0; + + int frame_size = 0, y_size = 0; + + unsigned char *y_src = NULL, *u_src = NULL; + unsigned char *y_dst = NULL, *u_dst = NULL; + unsigned char *src_buffer = NULL; + + int bytes_per_pixel = 2; + assert(buffer->mmap); + + frame_size = buffer->width * buffer->height * bytes_per_pixel * 3 / 2; + y_size = buffer->width * buffer->height * bytes_per_pixel; + + src_buffer = (unsigned char *)malloc(frame_size); + fread(src_buffer, 1, frame_size, image->fp); + y_src = src_buffer; + u_src = src_buffer + y_size; // UV offset for P010 + + fprintf(stderr, "Test width %d height %d stride %ld\n", buffer->width, + buffer->height, buffer->stride); + + y_dst = (unsigned char *)buffer->mmap + 0; // Y plane + u_dst = (unsigned char *)buffer->mmap + + buffer->stride * buffer->height; // U offset for P010 + + for (i = 0; i < buffer->height; i++) { + memcpy(y_dst, y_src, buffer->width * 2); + y_dst += buffer->stride; + y_src += buffer->width * 2; + } + + for (i = 0; iheight>> 1; i++) { + memcpy(u_dst, u_src, buffer->width * 2); + u_dst += buffer->stride; + u_src += buffer->width * 2; + } +} + +static void image_close(struct image *s) { + fclose(s->fp); +} + +static bool image_open(struct image *image, const char *filename) { + image->fp = fopen(filename, "r"); + return true; +} + +static int intel_alloc_bo(struct buffer *my_buf) { + /* XXX: try different tiling modes for testing FB modifiers. */ + uint32_t tiling = I915_TILING_NONE; + + assert(my_buf->bufmgr); + + my_buf->intel_bo = drm_intel_bo_alloc_tiled( + my_buf->bufmgr, "test", my_buf->width, my_buf->height, (my_buf->bpp / 8), + &tiling, &my_buf->stride, 0); + + if (!my_buf->intel_bo) + return 0; + + if (tiling != I915_TILING_NONE) + return 0; + + return 1; +} + +static void intel_free_bo(struct buffer *my_buf) { + drm_intel_bo_unreference(my_buf->intel_bo); +} + +static int intel_map_bo(struct buffer *my_buf) { + if (drm_intel_gem_bo_map_gtt(my_buf->intel_bo) != 0) + return 0; + + my_buf->mmap = (uint8_t *)my_buf->intel_bo->virt; + + return 1; +} + +static int intel_bo_export_to_prime(struct buffer *buffer) { + return drm_intel_bo_gem_export_to_prime(buffer->intel_bo, &buffer->dmabuf_fd); +} + +static void intel_unmap_bo(struct buffer *my_buf) { + drm_intel_gem_bo_unmap_gtt(my_buf->intel_bo); +} + +static void intel_device_destroy(struct buffer *my_buf) { + drm_intel_bufmgr_destroy(my_buf->bufmgr); +} + +static void drm_device_destroy(struct buffer *buf) { + buf->dev->device_destroy(buf); + close(buf->drm_fd); +} + +static int drm_device_init(struct buffer *buf) { + struct drm_device *dev = (drm_device *)calloc(1, sizeof(struct drm_device)); + + drmVersionPtr version = drmGetVersion(buf->drm_fd); + + dev->fd = buf->drm_fd; + dev->name = strdup(version->name); + if (0) { + /* nothing */ + } else if (!strcmp(dev->name, "i915")) { + buf->bufmgr = drm_intel_bufmgr_gem_init(buf->drm_fd, 32); + if (!buf->bufmgr) { + free(dev->name); + free(dev); + return 0; + } + dev->alloc_bo = intel_alloc_bo; + dev->free_bo = intel_free_bo; + dev->export_bo_to_prime = intel_bo_export_to_prime; + dev->map_bo = intel_map_bo; + dev->unmap_bo = intel_unmap_bo; + dev->device_destroy = intel_device_destroy; + } else { + fprintf(stderr, "Error: drm device %s unsupported.\n", dev->name); + free(dev->name); + free(dev); + return 0; + } + buf->dev = dev; + return 1; +} + +static int drm_connect(struct buffer *my_buf) { + /* This won't work with card0 as we need to be authenticated; instead, + * boot with drm.rnodes=1 and use that. */ + my_buf->drm_fd = open("/dev/dri/renderD128", O_RDWR); + if (my_buf->drm_fd < 0) + return 0; + + return drm_device_init(my_buf); +} + +static void drm_shutdown(struct buffer *my_buf) { + drm_device_destroy(my_buf); +} + +class DisplayVSyncCallback : public hwcomposer::VsyncCallback { + public: + DisplayVSyncCallback() { + } + + void Callback(uint32_t /*display*/, int64_t /*timestamp*/) { + } +}; + +class HotPlugEventCallback : public hwcomposer::DisplayHotPlugEventCallback { + public: + HotPlugEventCallback() { + } + + void Callback(std::vector connected_displays) { + spin_lock_.lock(); + connected_displays_.swap(connected_displays); + if (connected_displays_.empty()) { + spin_lock_.unlock(); + return; + } + + hwcomposer::NativeDisplay *primary = connected_displays_.at(0); + for (size_t i = 1; i < connected_displays_.size(); i++) { + hwcomposer::NativeDisplay *cloned = connected_displays_.at(i); + cloned->CloneDisplay(primary); + } + + spin_lock_.unlock(); + } + + const std::vector &GetConnectedDisplays() { + spin_lock_.lock(); + PopulateConnectedDisplays(); + spin_lock_.unlock(); + return connected_displays_; + } + + void PresentLayers(std::vector &layers, + std::vector> &layers_fences, + std::vector &fences) { + hwcomposer::ScopedSpinLock lock(spin_lock_); + PopulateConnectedDisplays(); + + if (connected_displays_.empty()) + return; + + // We only support cloned mode for now. + hwcomposer::NativeDisplay *primary = connected_displays_.at(0); + int32_t retire_fence = -1; + primary->Present(layers, &retire_fence); + fences.emplace_back(retire_fence); + // store fences for each display for each layer + unsigned int fence_index = 0; + } + + void SetGamma(float red, float green, float blue) { + hwcomposer::ScopedSpinLock lock(spin_lock_); + PopulateConnectedDisplays(); + + if (connected_displays_.empty()) + return; + + for (auto &display : connected_displays_) { + display->SetGamma(red, green, blue); + } + } + + void SetBrightness(char red, char green, char blue) { + hwcomposer::ScopedSpinLock lock(spin_lock_); + PopulateConnectedDisplays(); + + if (connected_displays_.empty()) + return; + + for (auto &display : connected_displays_) { + display->SetBrightness(red, green, blue); + } + } + + void SetContrast(char red, char green, char blue) { + hwcomposer::ScopedSpinLock lock(spin_lock_); + PopulateConnectedDisplays(); + + if (connected_displays_.empty()) + return; + + for (auto &display : connected_displays_) { + display->SetContrast(red, green, blue); + } + } + + void SetBroadcastRGB(const char *range_property) { + hwcomposer::ScopedSpinLock lock(spin_lock_); + PopulateConnectedDisplays(); + + if (connected_displays_.empty()) + return; + + for (auto &display : connected_displays_) + display->SetBroadcastRGB(range_property); + } + + void SetPowerMode(uint32_t power_mode) { + hwcomposer::ScopedSpinLock lock(spin_lock_); + PopulateConnectedDisplays(); + + if (connected_displays_.empty()) + return; + + for (auto &display : connected_displays_) + display->SetPowerMode(power_mode); + } + + void SetCanvasColor(uint64_t color, uint16_t bpc) { + hwcomposer::ScopedSpinLock lock(spin_lock_); + PopulateConnectedDisplays(); + + if (connected_displays_.empty()) + return; + + /** + * We are assuming that the color provided the user is in hex and in + * ABGR format with R in LSB. For example, 0x000000ff would be Red. + */ + } + + void SetActiveConfig(uint32_t config) { + hwcomposer::ScopedSpinLock lock(spin_lock_); + PopulateConnectedDisplays(); + + if (connected_displays_.empty()) + return; + + for (auto &display : connected_displays_) + display->SetActiveConfig(config); + } + + void GetDisplayAttribute(uint32_t config, + hwcomposer::HWCDisplayAttribute attribute, + int32_t *value) { + hwcomposer::ScopedSpinLock lock(spin_lock_); + PopulateConnectedDisplays(); + + if (connected_displays_.empty()) + return; + int32_t tempValue; + for (auto &display : connected_displays_) + display->GetDisplayAttribute(config, attribute, &tempValue); + *value = tempValue; + } + + void GetDisplayConfigs(uint32_t *num_configs, uint32_t *configs) { + hwcomposer::ScopedSpinLock lock(spin_lock_); + PopulateConnectedDisplays(); + + uint32_t numConfigs, configIndex; + + if (connected_displays_.empty()) + return; + for (auto &display : connected_displays_) + display->GetDisplayConfigs(&numConfigs, NULL); + *num_configs = numConfigs; + } + + void PopulateConnectedDisplays() { + if (connected_displays_.empty()) { + device_.GetConnectedPhysicalDisplays(connected_displays_); + + for (auto &display : connected_displays_) { + auto callback = std::make_shared(); + display->RegisterVsyncCallback(callback, 0); + display->VSyncControl(true); + } + } + } + + private: + std::vector connected_displays_; + hwcomposer::GpuDevice &device_ = hwcomposer::GpuDevice::getInstance(); + hwcomposer::SpinLock spin_lock_; +}; + +static int create_dmabuf_buffer(struct buffer *buffer, int width, int height, + int format) { + uint64_t modifier = 0; + uint32_t flags = 0; + struct drm_device *drm_dev; + + if (!drm_connect(buffer)) { + fprintf(stderr, "drm_connect failed\n"); + goto error; + } + + drm_dev = buffer->dev; + + buffer->width = width; + switch (format) { + case DRM_FORMAT_NV12: + /* adjust height for allocation of NV12 Y and UV planes */ + buffer->height = height * 3 / 2; + buffer->bpp = 8; + break; + case DRM_FORMAT_YUV420: + buffer->height = height * 2; + buffer->bpp = 8; + break; + case DRM_FORMAT_P010: + buffer->height = height * 3 / 2; + buffer->bpp = 16; + break; + default: + buffer->height = height; + buffer->bpp = 32; + } + buffer->format = format; + + if (!drm_dev->alloc_bo(buffer)) { + fprintf(stderr, "alloc_bo failed\n"); + goto error1; + } + + if (drm_dev->export_bo_to_prime(buffer) != 0) { + fprintf(stderr, "gem_export_to_prime failed\n"); + goto error2; + } + if (buffer->dmabuf_fd < 0) { + fprintf(stderr, "error: dmabuf_fd < 0\n"); + goto error2; + } + + buffer->height = height; + + return 0; + +error2: + drm_dev->free_bo(buffer); +error1: + drm_shutdown(buffer); +error: + return -1; +} + +static struct image *image_create(const char *filename) { + uint32_t i, width, height, format; + int ret; + struct buffer *buffer; + struct image *image; + + image = new struct image; + memset(image, 0, sizeof(image)); + + if (!image_open(image, filename)) + goto err; + + width = 1920; + height = 1080; + format = DRM_FORMAT_P010; + + for (i = 0; i < NUM_BUFFERS; i++) { + buffer = &image->buffers[i]; + ret = create_dmabuf_buffer(buffer, width, height, format); + + if (ret < 0) + goto err; + } + + return image; + +err: + free(image); + return NULL; +} + +static void image_destroy(struct image *image) { + image_close(image); + free(image); +} + +void copy_buffer_to_handle(struct gbm_handle *handle, buffer *buffer) { + memset(&handle->import_data, 0, sizeof(handle->import_data)); + handle->import_data.fd_modifier_data.width = buffer->width; + handle->import_data.fd_modifier_data.height = buffer->height; + handle->import_data.fd_modifier_data.format = buffer->format; + handle->import_data.fd_modifier_data.num_fds = 2; + handle->import_data.fd_modifier_data.fds[0] = buffer->dmabuf_fd; + handle->import_data.fd_modifier_data.strides[0] = buffer->stride; + handle->import_data.fd_modifier_data.offsets[0] = 0; + handle->import_data.fd_modifier_data.fds[1] = buffer->dmabuf_fd; + handle->import_data.fd_modifier_data.strides[1] = buffer->stride; + handle->import_data.fd_modifier_data.offsets[1] = + buffer->stride * buffer->height; + + handle->meta_data_.num_planes_ = drm_bo_get_num_planes(buffer->format); + handle->bo = nullptr; + handle->hwc_buffer_ = true; + handle->gbm_flags = 0; +} + +int main(int argc, char *argv[]) { + int ret, fd, primary_width, primary_height; + struct image *image; + std::vector layers; + std::vector> layers_fences; + std::vector fences; + + hwcomposer::HwcLayer layer; + struct gbm_handle native_handle; + buffer *buffer = NULL; + + image = image_create(argv[1]); + if (!image) { + fprintf(stderr, "Failed to initialize!"); + exit(EXIT_FAILURE); + } + + hwcomposer::GpuDevice &device = hwcomposer::GpuDevice::getInstance(); + device.Initialize(); + auto callback = std::make_shared(); + device.RegisterHotPlugEventCallback(callback); + const std::vector &displays = + device.GetAllDisplays(); + if (displays.empty()) + return 0; + + hwcomposer::NativeDisplay *primary = displays.at(0); + + primary->SetActiveConfig(0); + primary->SetPowerMode(hwcomposer::kOn); + primary_width = primary->Width(); + primary_height = primary->Height(); + + layer.SetSourceCrop(hwcomposer::HwcRect(0, 0, 1920, 1080)); + + // layer.SetDisplayFrame(hwcomposer::HwcRect(0, 0, + // primary_width, + // primary_height), 0, 0); + + layer.SetDisplayFrame(hwcomposer::HwcRect(0, 0, 1920, 1080), 0, 0); + // redraw loop + // Draw here + buffer = image_next_buffer(image); + if (!buffer) { + fprintf(stderr, "no free buffer\n"); + } + + if (!buffer->dev->map_bo(buffer)) { + fprintf(stderr, "map_bo failed\n"); + return 1; + } + + fill_buffer(buffer, image); + + buffer->dev->unmap_bo(buffer); + + copy_buffer_to_handle(&native_handle, buffer); + + layer.SetColorSpace(CS_BT2020); + layer.SetHdrMetadata(6550, 2300, 8500, 39850, 35400, 14600, 15635, 16450, + 1000, 100, 4000, 100); + layer.SetHdrEotf(EOTF_ST2084); + + layer.SetAcquireFence(-1); + std::vector> damage_region; + damage_region.emplace_back(layer.GetDisplayFrame()); + layer.SetSurfaceDamage(damage_region); + layer.SetNativeHandle(&native_handle); + layers.emplace_back(&layer); + + callback->PresentLayers(layers, layers_fences, fences); + + while (1) { + sleep(1); + } + + image_destroy(image); + + return 0; +} diff --git a/wsi/drm/drmdisplay.cpp b/wsi/drm/drmdisplay.cpp index 0759c6c3f..03ce02619 100644 --- a/wsi/drm/drmdisplay.cpp +++ b/wsi/drm/drmdisplay.cpp @@ -15,6 +15,7 @@ */ #include "drmdisplay.h" +#include "hdr_metadata_defs.h" #include #include @@ -26,6 +27,7 @@ #include #include +#include #include #include #include @@ -33,11 +35,13 @@ #include "displayplanemanager.h" #include "displayqueue.h" #include "drmdisplaymanager.h" +#include "hdr_metadata_defs.h" #include "wsi_utils.h" #define CTA_EXTENSION_TAG 0x02 -#define CTA_EXTENDED_TAG_CODE 0x07 #define CTA_COLORIMETRY_CODE 0x05 +#define CTA_HDR_STATIC_METADATA 0x06 +#define CTA_EXTENDED_TAG_CODE 0x07 namespace hwcomposer { @@ -78,8 +82,112 @@ bool DrmDisplay::InitializeDisplay() { return true; } -std::vector DrmDisplay::FindExtendedBlocksForTag(uint8_t *edid, - uint8_t block_tag) { +void DrmDisplay::DrmConnectorGetDCIP3Support(uint8_t *b, uint8_t length) { + dcip3_ = false; + if (b && length >= 2) { + dcip3_ = !!(b[1] & 0x80); + clrspaces = ((!!(b[1] & 0x80)) << 8) | (b[0]); + } + return; +} + +uint16_t DrmDisplay::DrmConnectorColorPrimary(short val) { + short temp = val & 0x3FF; + short count = 1; + float result = 0; + uint16_t output; + + /* Primary values in EDID are ecoded in 10 bit format, where every bit + * represents 2 pow negative bit position, ex 0.500 = 1/2 = 2 ^ -1 = (1 << 9) + */ + while (temp) { + result += ((!!(temp & (1 << 9))) * pow(2, -count)); + count++; + temp <<= 1; + } + + /* Primaries are to represented in uint16 format, in power of 0.00002, + * * max allowed value is 500,00 */ + output = result * 50000; + if (output > 50000) + output = 50000; + + return output; +} + +void DrmDisplay::DrmConnectorGetHDRStaticMetadata(uint8_t *b, uint8_t length) { + uint8_t i; + + if (length < 2) { + ITRACE("Invalid metadata input to static parser\n"); + return; + } + + display_hdrMd = (struct drm_edid_hdr_metadata_static *)malloc( + sizeof(struct drm_edid_hdr_metadata_static)); + if (!display_hdrMd) { + ITRACE("OOM while parsing static metadata\n"); + return; + } + memset(display_hdrMd, 0, sizeof(struct drm_edid_hdr_metadata_static)); + + display_hdrMd->eotf = b[0] & 0x3F; + display_hdrMd->metadata_type = b[1]; + + if (length > 2 && length < 6) { + display_hdrMd->desired_max_ll = b[2]; + display_hdrMd->desired_max_fall = b[3]; + display_hdrMd->desired_min_ll = b[4]; + + if (!display_hdrMd->desired_max_ll) + display_hdrMd->desired_max_ll = 0xFF; + } + return; +} + +#define HIGH_X(val) (val >> 6) +#define HIGH_Y(val) ((val >> 4) & 0x3) +#define LOW_X(val) ((val >> 2) & 0x3) +#define LOW_Y(val) ((val >> 4) & 0x3) + +void DrmDisplay::DrmConnectorGetcolorPrimaries( + uint8_t *b, struct drm_display_color_primaries *p) { + uint8_t rxrygxgy_0_1; + uint8_t bxbywxwy_0_1; + uint8_t count = 0x19; /* base of chromaticity block values */ + uint16_t val; + + if (!b || !p) + return; + + rxrygxgy_0_1 = b[count++]; + bxbywxwy_0_1 = b[count++]; + + val = (b[count++] << 2) | HIGH_X(rxrygxgy_0_1); + p->display_primary_r_x = DrmConnectorColorPrimary(val); + + val = (b[count++] << 2) | HIGH_Y(rxrygxgy_0_1); + p->display_primary_r_y = DrmConnectorColorPrimary(val); + + val = (b[count++] << 2) | LOW_X(rxrygxgy_0_1); + p->display_primary_g_x = DrmConnectorColorPrimary(val); + + val = (b[count++] << 2) | LOW_Y(rxrygxgy_0_1); + p->display_primary_g_y = DrmConnectorColorPrimary(val); + + val = (b[count++] << 2) | HIGH_X(bxbywxwy_0_1); + p->display_primary_b_x = DrmConnectorColorPrimary(val); + + val = (b[count++] << 2) | HIGH_Y(bxbywxwy_0_1); + p->display_primary_b_y = DrmConnectorColorPrimary(val); + + val = (b[count++] << 2) | LOW_X(bxbywxwy_0_1); + p->white_point_x = DrmConnectorColorPrimary(val); + + val = (b[count++] << 2) | LOW_X(bxbywxwy_0_1); + p->white_point_y = DrmConnectorColorPrimary(val); +} +void DrmDisplay::ParseCTAFromExtensionBlock(uint8_t *edid) { int current_block; uint8_t *cta_ext_blk; uint8_t dblen; @@ -88,11 +196,10 @@ std::vector DrmDisplay::FindExtendedBlocksForTag(uint8_t *edid, uint8_t *cta_db_end; uint8_t *dbptr; uint8_t tag; - std::vector addrs; int num_blocks = edid[126]; if (!num_blocks) { - return addrs; + return; } for (current_block = 1; current_block <= num_blocks; current_block++) { @@ -108,51 +215,23 @@ std::vector DrmDisplay::FindExtendedBlocksForTag(uint8_t *edid, dblen = dbptr[0] & 0x1F; // Check if the extension has an extended block - if (tag == block_tag) - addrs.emplace_back(dbptr); - } - } - - return addrs; -} - -void DrmDisplay::DrmConnectorGetDCIP3Support( - const ScopedDrmObjectPropertyPtr &props) { - uint8_t *edid = NULL; - uint64_t edid_blob_id; - drmModePropertyBlobPtr blob; - uint8_t block_tag; - std::vector blocks; - - dcip3_ = false; - - GetDrmObjectPropertyValue("EDID", props, &edid_blob_id); - blob = drmModeGetPropertyBlob(gpu_fd_, edid_blob_id); - if (!blob) { - return; - } - - edid = (uint8_t *)blob->data; - if (!edid) { - drmModeFreePropertyBlob(blob); - return; - } - - blocks = FindExtendedBlocksForTag(edid, CTA_EXTENDED_TAG_CODE); - - for (uint8_t *ext_block : blocks) { - block_tag = ext_block[1]; - - if (block_tag == CTA_COLORIMETRY_CODE) { - dcip3_ = !!(ext_block[3] & 0x80); - if (dcip3_) - break; + if (tag == CTA_EXTENDED_TAG_CODE) { + switch (dbptr[1]) { + case CTA_COLORIMETRY_CODE: + ITRACE(" Colorimetry Data block\n"); + DrmConnectorGetDCIP3Support(dbptr + 2, dblen - 1); + break; + case CTA_HDR_STATIC_METADATA: + ITRACE(" HDR STATICMETADATA block\n"); + DrmConnectorGetHDRStaticMetadata(dbptr + 2, dblen - 1); + break; + default: + ITRACE(" Unknown tag/Parsing option\n"); + } + DrmConnectorGetcolorPrimaries(dbptr + 2, &primaries); + } } } - - drmModeFreePropertyBlob(blob); - - return; } bool DrmDisplay::ConnectDisplay(const drmModeModeInfo &mode_info, @@ -222,8 +301,23 @@ bool DrmDisplay::ConnectDisplay(const drmModeModeInfo &mode_info, GetDrmObjectProperty("Broadcast RGB", connector_props, &broadcastrgb_id_); GetDrmObjectProperty("DPMS", connector_props, &dpms_prop_); GetDrmObjectProperty("max bpc", connector_props, &max_bpc_prop_); + GetDrmObjectProperty("HDR_OUTPUT_METADATA", connector_props, + &hdr_op_metadata_prop_); + GetDrmObjectProperty("Colorspace", connector_props, &colorspace_op_prop_); + + uint8_t *edid = NULL; + uint64_t edid_blob_id; + drmModePropertyBlobPtr blob; + + GetDrmObjectPropertyValue("EDID", connector_props, &edid_blob_id); + blob = drmModeGetPropertyBlob(gpu_fd_, edid_blob_id); + if (blob == nullptr || blob->data == nullptr) { + ETRACE("Failed to get EDID blob data\n"); + return false; + } - DrmConnectorGetDCIP3Support(connector_props); + edid = (uint8_t *)blob->data; + ParseCTAFromExtensionBlock(edid); if (dcip3_) { ITRACE("DCIP3 support available"); if (!SetPipeMaxBpc(PIPE_BPC_TWELVE)) @@ -232,6 +326,7 @@ bool DrmDisplay::ConnectDisplay(const drmModeModeInfo &mode_info, ITRACE("DCIP3 support not available"); } + drmModeFreePropertyBlob(blob); PhysicalDisplay::Connect(); SetHDCPState(desired_protection_support_, content_type_); @@ -556,6 +651,86 @@ void DrmDisplay::GetDisplayCapabilities(uint32_t *numCapabilities, } } +bool DrmDisplay::GetHdrCapabilities(uint32_t *outNumTypes, int32_t *outTypes, + float *outMaxLuminance, + float *outMaxAverageLuminance, + float *outMinLuminance) { + if (NULL == outNumTypes) { + ALOGE("outNumTypes couldn't be NULL!"); + return false; + } + + if (NULL == outTypes) { + ALOGE("outTypes couldn't be NULL!"); + return false; + } + + if (NULL == outMaxLuminance) { + ALOGE("outMaxLuminance couldn't be NULL!"); + return false; + } + + if (NULL == outMaxAverageLuminance) { + ALOGE("outMaxAverageLuminance couldn't be NULL!"); + return false; + } + + if (NULL == outMinLuminance) { + ALOGE("outMinLuminance couldn't be NULL!"); + return false; + } + + if (display_hdrMd) { + // HDR meta block bit 3 of byte 3: STPTE ST 2084 + if (display_hdrMd->eotf & 0x04) { + *(outTypes + *outNumTypes) = (uint32_t)EOTF_ST2084; + *outNumTypes++; + } + // HDR meta block bit 4 of byte 3: HLG + if (display_hdrMd->eotf & 0x08) { + *(outTypes + *outNumTypes) = (uint32_t)EOTF_HLG; + *outNumTypes++; + } + double outmaxluminance, outmaxaverageluminance, outminluminance; + // Luminance value = 50 * POW(2, coded value / 32) + // Desired Content Min Luminance = Desired Content Max Luminance * POW(2, + // coded value/255) / 100 + outmaxluminance = pow(2.0, display_hdrMd->desired_max_ll / 32.0) * 50.0; + *outMaxLuminance = float(outmaxluminance); + outmaxaverageluminance = + pow(2.0, display_hdrMd->desired_max_fall / 32.0) * 50.0; + *outMaxAverageLuminance = float(outmaxaverageluminance); + outminluminance = display_hdrMd->desired_max_ll * + pow(2.0, display_hdrMd->desired_min_ll / 255.0) / 100; + *outMinLuminance = float(outminluminance); + } + + return true; +} + +bool DrmDisplay::GetPerFrameMetadataKeys(uint32_t *outNumKeys, + int32_t *outKeys) { + *outNumKeys = KEY_NUM_PER_FRAME_METADATA_KEYS; + + for (int i = 0; i < KEY_NUM_PER_FRAME_METADATA_KEYS; i++) { + *(outKeys + i) = i; + } + return true; +} + +bool DrmDisplay::GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents) { + // If HDR is supported, adds HDR render intents accordingly. + if (display_hdrMd && display_hdrMd->eotf & 0x0C) { + *(outIntents + *outNumIntents) = HAL_RENDER_INTENT_TONE_MAP_COLORIMETRIC; + *(outNumIntents)++; + *(outIntents + *outNumIntents) = HAL_RENDER_INTENT_TONE_MAP_ENHANCE; + *(outNumIntents)++; + } + + return true; +} + void DrmDisplay::UpdateDisplayConfig() { // update the activeConfig SPIN_LOCK(display_lock_); @@ -657,11 +832,89 @@ void DrmDisplay::TraceFirstCommit() { ITRACE("First frame is Committed at %lld.", milliseconds); } +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define MIN_IF_NT_ZERO(c, d) (c ? MIN(c, d) : d) + +void DrmDisplay::Accumulated_HdrMetadata(struct hdr_metadata *hdr_mdata1, + struct hdr_metadata *hdr_mdata2) { + struct hdr_metadata_static *l1_md = &hdr_mdata1->metadata.static_metadata; + struct hdr_metadata_static *l2_md = &hdr_mdata2->metadata.static_metadata; + + hdr_mdata1->metadata_type = + MIN_IF_NT_ZERO(hdr_mdata1->metadata_type, hdr_mdata2->metadata_type); + l1_md->primaries.r.x = + MIN_IF_NT_ZERO(l1_md->primaries.r.x, l2_md->primaries.r.x); + l1_md->primaries.r.y = + MIN_IF_NT_ZERO(l1_md->primaries.r.y, l2_md->primaries.r.y); + l1_md->primaries.g.x = + MIN_IF_NT_ZERO(l1_md->primaries.g.x, l2_md->primaries.g.x); + l1_md->primaries.g.y = + MIN_IF_NT_ZERO(l1_md->primaries.g.y, l2_md->primaries.g.y); + l1_md->primaries.b.x = + MIN_IF_NT_ZERO(l1_md->primaries.b.x, l2_md->primaries.b.x); + l1_md->primaries.b.y = + MIN_IF_NT_ZERO(l1_md->primaries.b.y, l2_md->primaries.b.y); + l1_md->primaries.white_point.x = MIN_IF_NT_ZERO( + l1_md->primaries.white_point.x, l2_md->primaries.white_point.x); + l1_md->primaries.white_point.y = MIN_IF_NT_ZERO( + l1_md->primaries.white_point.y, l2_md->primaries.white_point.y); + l1_md->max_luminance = + MIN_IF_NT_ZERO(l1_md->max_luminance, l2_md->max_luminance); + l1_md->min_luminance = + MIN_IF_NT_ZERO(l1_md->min_luminance, l2_md->min_luminance); + l1_md->max_cll = MIN_IF_NT_ZERO(l1_md->max_cll, l2_md->max_cll); + l1_md->max_fall = MIN_IF_NT_ZERO(l1_md->max_fall, l2_md->max_fall); + l1_md->eotf = MIN_IF_NT_ZERO(l1_md->eotf, l2_md->eotf); +} + +void DrmDisplay::PrepareHdrMetadata(struct hdr_metadata *l_hdr_mdata, + struct drm_hdr_metadata *out_md) { + struct hdr_metadata_static *l_md = &l_hdr_mdata->metadata.static_metadata; + struct drm_hdr_metadata_static *out_static_md = + &out_md->drm_hdr_static_metadata; + + out_static_md->max_cll = l_md->max_cll; + out_static_md->max_fall = l_md->max_fall; + out_static_md->max_mastering_luminance = l_md->max_luminance; + out_static_md->min_mastering_luminance = l_md->min_luminance; + out_static_md->primaries[0].x = + MIN_IF_NT_ZERO(DrmConnectorColorPrimary(l_md->primaries.r.x), + primaries.display_primary_r_x); + out_static_md->primaries[0].y = + MIN_IF_NT_ZERO(DrmConnectorColorPrimary(l_md->primaries.r.y), + primaries.display_primary_r_y); + out_static_md->primaries[1].x = + MIN_IF_NT_ZERO(DrmConnectorColorPrimary(l_md->primaries.g.x), + primaries.display_primary_g_x); + out_static_md->primaries[1].y = + MIN_IF_NT_ZERO(DrmConnectorColorPrimary(l_md->primaries.g.y), + primaries.display_primary_g_y); + out_static_md->primaries[2].x = + MIN_IF_NT_ZERO(DrmConnectorColorPrimary(l_md->primaries.g.x), + primaries.display_primary_b_x); + out_static_md->primaries[2].y = + MIN_IF_NT_ZERO(DrmConnectorColorPrimary(l_md->primaries.g.y), + primaries.display_primary_b_y); + out_static_md->white_point.x = + MIN_IF_NT_ZERO(DrmConnectorColorPrimary(l_md->primaries.white_point.x), + primaries.white_point_x); + out_static_md->white_point.y = + MIN_IF_NT_ZERO(DrmConnectorColorPrimary(l_md->primaries.white_point.y), + primaries.white_point_y); + out_static_md->eotf = DRM_EOTF_HDR_ST2084; + out_static_md->metadata_type = 1; +} + bool DrmDisplay::Commit( const DisplayPlaneStateList &composition_planes, const DisplayPlaneStateList &previous_composition_planes, bool disable_explicit_fence, int32_t previous_fence, int32_t *commit_fence, bool *previous_fence_released) { + struct hdr_metadata final_hdr_metadata, layer_metadata; + int layer_colorspace; + + memset(&final_hdr_metadata, 0, sizeof(struct hdr_metadata)); + if (!manager_->IsDrmMaster()) { ETRACE("Failed to commit without DrmMaster"); return true; @@ -680,10 +933,29 @@ bool DrmDisplay::Commit( display_queue_->ResetPlanes(pset.get()); if (display_state_ & kNeedsModeset) { + /* KK: Put to check only if input layer is a hdr */ + for (const DisplayPlaneState &comp_plane : composition_planes) { + OverlayLayer *layer = (OverlayLayer *)comp_plane.GetOverlayLayer(); + layer_metadata = layer->GetHdrMetadata(); + layer_colorspace = layer->GetColorSpace(); + + Accumulated_HdrMetadata(&final_hdr_metadata, &layer_metadata); + } + + PrepareHdrMetadata(&final_hdr_metadata, &color_state.o_md); + + /*KK: end */ + if (!ApplyPendingModeset(pset.get())) { ETRACE("Failed to Modeset."); return false; } + + if (!ApplyPendingHdr(pset.get(), &color_state)) { + ETRACE("Failed updating Hdr prop."); + return false; + } + } else if (!disable_explicit_fence && out_fence_ptr_prop_) { GetFence(pset.get(), commit_fence); } @@ -1038,6 +1310,29 @@ float DrmDisplay::TransformGamma(float value, float gamma) const { return result; } +bool DrmDisplay::SetColorMode(int32_t mode) { + auto it = + std::find(current_color_mode_.begin(), current_color_mode_.end(), mode); + if (it == current_color_mode_.end()) { + current_color_mode_.push_back(mode); + } + return true; +} + +bool DrmDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) { + if (!modes) { + *num_modes = current_color_mode_.size(); + return true; + } + + *num_modes = current_color_mode_.size(); + for (int i = 0; i < current_color_mode_.size(); i++) { + *(modes + i) == current_color_mode_[i]; + } + + return true; +} + void DrmDisplay::SetColorTransformMatrix( const float *color_transform_matrix, HWCColorTransform color_transform_hint) const { @@ -1156,6 +1451,19 @@ void DrmDisplay::SetColorCorrection(struct gamma_colors gamma, free(lut); } +/* Return the colorspace values to be going to AVI infoframe */ +static inline uint32_t to_kernel_colorspace(uint8_t colorspace) { + switch (colorspace) { + case DRM_COLORSPACE_DCIP3: + return DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65; + case DRM_COLORSPACE_REC2020: + return DRM_MODE_COLORIMETRY_BT2020_RGB; + case DRM_COLORSPACE_REC709: + default: + return DRM_MODE_COLORIMETRY_DEFAULT; + } +} + bool DrmDisplay::ApplyPendingModeset(drmModeAtomicReqPtr property_set) { if (old_blob_id_) { drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_); @@ -1175,6 +1483,7 @@ bool DrmDisplay::ApplyPendingModeset(drmModeAtomicReqPtr property_set) { crtc_id_) < 0 || drmModeAtomicAddProperty(property_set, crtc_id_, active_prop_, active) < 0; + if (ret) { ETRACE("Failed to add blob %d to pset", blob_id_); return false; @@ -1186,6 +1495,28 @@ bool DrmDisplay::ApplyPendingModeset(drmModeAtomicReqPtr property_set) { return true; } +bool DrmDisplay::ApplyPendingHdr(drmModeAtomicReqPtr property_set, + struct drm_conn_color_state *target) { + /* KK : TODO: set old_blob */ + drmModeCreatePropertyBlob(gpu_fd_, (void *)&target->o_md, + sizeof(target->o_md), + (uint32_t *)&target->hdr_md_blob_id); + if (target->hdr_md_blob_id == 0) + return false; + + int ret = + drmModeAtomicAddProperty(property_set, connector_, hdr_op_metadata_prop_, + target->hdr_md_blob_id) < 0 || + drmModeAtomicAddProperty(property_set, connector_, colorspace_op_prop_, + to_kernel_colorspace(color_state.o_cs)) < 0; + if (ret) { + ETRACE("Failed to add blob %d to pset", target->hdr_md_blob_id); + return false; + } + + return true; +} + bool DrmDisplay::GetFence(drmModeAtomicReqPtr property_set, int32_t *out_fence) { int ret = drmModeAtomicAddProperty(property_set, crtc_id_, diff --git a/wsi/drm/drmdisplay.h b/wsi/drm/drmdisplay.h index 3dffe9cd0..a0a99a24f 100644 --- a/wsi/drm/drmdisplay.h +++ b/wsi/drm/drmdisplay.h @@ -24,6 +24,7 @@ #include #include "drmplane.h" +#include "hdr_metadata_defs.h" #include "physicaldisplay.h" #ifndef DRM_RGBA8888 @@ -42,6 +43,85 @@ enum pipe_bpc { PIPE_BPC_SIXTEEN = 16 }; +/* CTA-861-G: HDR Metadata names and types */ +enum drm_hdr_eotf_type { + DRM_EOTF_SDR_TRADITIONAL = 0, + DRM_EOTF_HDR_TRADITIONAL, + DRM_EOTF_HDR_ST2084, + DRM_EOTF_HLG_BT2100, + DRM_EOTF_MAX +}; + +#define DRM_MODE_COLORIMETRY_DEFAULT 0 +#define DRM_MODE_COLORIMETRY_BT2020_RGB 9 +#define DRM_MODE_COLORIMETRY_BT2020_YCC 10 +#define DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65 11 +#define DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER 12 + +enum drm_colorspace { + DRM_COLORSPACE_INVALID, + DRM_COLORSPACE_REC709, + DRM_COLORSPACE_DCIP3, + DRM_COLORSPACE_REC2020, + DRM_COLORSPACE_MAX, +}; + +/* Monitors HDR Metadata */ +struct drm_edid_hdr_metadata_static { + uint8_t eotf; + uint8_t metadata_type; + uint8_t desired_max_ll; + uint8_t desired_max_fall; + uint8_t desired_min_ll; +}; + +/* Monitor's color primaries */ +struct drm_display_color_primaries { + uint16_t display_primary_r_x; + uint16_t display_primary_r_y; + uint16_t display_primary_g_x; + uint16_t display_primary_g_y; + uint16_t display_primary_b_x; + uint16_t display_primary_b_y; + uint16_t white_point_x; + uint16_t white_point_y; +}; + +/* Static HDR metadata to be sent to kernel, matches kernel structure */ +struct drm_hdr_metadata_static { + uint8_t eotf; + uint8_t metadata_type; + struct { + uint16_t x, y; + } primaries[3]; + struct { + uint16_t x, y; + } white_point; + uint16_t max_mastering_luminance; + uint16_t min_mastering_luminance; + uint16_t max_cll; + uint16_t max_fall; +}; + +struct drm_hdr_metadata { + uint32_t metadata_type; + union { + struct drm_hdr_metadata_static drm_hdr_static_metadata; + }; +}; + +/* Connector's color correction status */ +struct drm_conn_color_state { + bool changed; + bool can_handle_hdr; + bool output_is_hdr; + + uint8_t o_cs; + uint8_t o_eotf; + uint32_t hdr_md_blob_id; + struct drm_hdr_metadata o_md; +}; + class DrmDisplayManager; class DisplayPlaneState; class DisplayQueue; @@ -64,8 +144,16 @@ class DrmDisplay : public PhysicalDisplay { void GetDisplayCapabilities(uint32_t *numCapabilities, uint32_t *capabilities) override; + bool GetHdrCapabilities(uint32_t *outNumTypes, int32_t *outTypes, + float *outMaxLuminance, float *outMaxAverageLuminance, + float *outMinLuminance) override; + + bool GetPerFrameMetadataKeys(uint32_t *outNumKeys, int32_t *outKeys) override; + bool GetDisplayIdentificationData(uint8_t *outPort, uint32_t *outDataSize, uint8_t *outData) override; + bool GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents) override; bool SetBroadcastRGB(const char *range_property) override; @@ -83,6 +171,8 @@ class DrmDisplay : public PhysicalDisplay { void SetPipeCanvasColor(uint16_t bpc, uint16_t red, uint16_t green, uint16_t blue, uint16_t alpha) const override; bool SetPipeMaxBpc(uint16_t max_bpc) const override; + bool SetColorMode(int32_t mode) override; + bool GetColorModes(uint32_t *num_modes, int32_t *modes) override; void SetColorTransformMatrix( const float *color_transform_matrix, HWCColorTransform color_transform_hint) const override; @@ -158,6 +248,12 @@ class DrmDisplay : public PhysicalDisplay { struct drm_color_ctm_post_offset *ctm_post_offset) const; void ApplyPendingLUT(struct drm_color_lut *lut) const; bool ApplyPendingModeset(drmModeAtomicReqPtr property_set); + bool ApplyPendingHdr(drmModeAtomicReqPtr property_set, + struct drm_conn_color_state *target); + void Accumulated_HdrMetadata(struct hdr_metadata *hdr_mdata1, + struct hdr_metadata *hdr_mdata2); + void PrepareHdrMetadata(struct hdr_metadata *l_hdr_mdata, + struct drm_hdr_metadata *out_metadata); bool GetFence(drmModeAtomicReqPtr property_set, int32_t *out_fence); bool CommitFrame(const DisplayPlaneStateList &comp_planes, const DisplayPlaneStateList &previous_composition_planes, @@ -169,8 +265,12 @@ class DrmDisplay : public PhysicalDisplay { uint32_t possible_crtcs); std::vector FindExtendedBlocksForTag(uint8_t *edid, uint8_t block_tag); - void DrmConnectorGetDCIP3Support(const ScopedDrmObjectPropertyPtr &props); - + void ParseCTAFromExtensionBlock(uint8_t *edid); + void DrmConnectorGetDCIP3Support(uint8_t *b, uint8_t length); + void DrmConnectorGetHDRStaticMetadata(uint8_t *b, uint8_t length); + uint16_t DrmConnectorColorPrimary(short val); + void DrmConnectorGetcolorPrimaries( + uint8_t *b, struct drm_display_color_primaries *primaries); void TraceFirstCommit(); uint32_t FindPreferedDisplayMode(size_t modes_size); @@ -197,6 +297,8 @@ class DrmDisplay : public PhysicalDisplay { uint32_t connector_ = 0; bool dcip3_ = false; uint32_t max_bpc_prop_ = 0; + uint32_t hdr_op_metadata_prop_ = 0; + uint32_t colorspace_op_prop_ = 0; uint64_t lut_size_ = 0; int64_t broadcastrgb_full_ = -1; int64_t broadcastrgb_automatic_ = -1; @@ -205,7 +307,18 @@ class DrmDisplay : public PhysicalDisplay { bool first_commit_ = false; uint32_t prefer_display_mode_ = 0; uint32_t perf_display_mode_ = 0; - std::string display_name_ = ""; + std::string display_name_; + std::vector current_color_mode_ = {HAL_COLOR_MODE_NATIVE}; + + /* Display's static HDR metadata */ + struct drm_edid_hdr_metadata_static *display_hdrMd; + /* Display's color primaries */ + struct drm_display_color_primaries primaries; + /* Display's supported color spaces */ + uint32_t clrspaces; + /* Connector's color correction status */ + struct drm_conn_color_state color_state; + HWCContentProtection current_protection_support_ = HWCContentProtection::kUnSupported; HWCContentProtection desired_protection_support_ = diff --git a/wsi/physicaldisplay.h b/wsi/physicaldisplay.h index a9c44b184..5c077616d 100644 --- a/wsi/physicaldisplay.h +++ b/wsi/physicaldisplay.h @@ -88,6 +88,8 @@ class PhysicalDisplay : public NativeDisplay, public DisplayPlaneHandler { bool CheckPlaneFormat(uint32_t format) override; void SetGamma(float red, float green, float blue) override; void SetContrast(uint32_t red, uint32_t green, uint32_t blue) override; + bool SetColorMode(int32_t mode) = 0; + bool GetColorModes(uint32_t *num_modes, int32_t *modes) = 0; void SetColorTransform(const float *matrix, HWCColorTransform hint) override; void SetBrightness(uint32_t red, uint32_t green, uint32_t blue) override; void SetDisableExplicitSync(bool disable_explicit_sync) override; @@ -129,6 +131,15 @@ class PhysicalDisplay : public NativeDisplay, public DisplayPlaneHandler { void GetDisplayCapabilities(uint32_t *outNumCapabilities, uint32_t *outCapabilities) override; + bool GetHdrCapabilities(uint32_t *outNumTypes, int32_t *outTypes, + float *outMaxLuminance, float *outMaxAverageLuminance, + float *outMinLuminance) = 0; + + bool GetPerFrameMetadataKeys(uint32_t *outNumKeys, int32_t *outKeys) = 0; + + bool GetRenderIntents(int32_t mode, uint32_t *outNumIntents, + int32_t *outIntents) = 0; + bool EnableDRMCommit(bool enable) override; /**