| /* |
| * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of The Linux Foundation nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| /* |
| * Changes from Qualcomm Innovation Center are provided under the following license: |
| * |
| * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted (subject to the limitations in the |
| * disclaimer below) provided that the following conditions are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * |
| * * Neither the name of Qualcomm Innovation Center, Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE |
| * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT |
| * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
| * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "hw_tv_drm.h" |
| #include <math.h> |
| #include <sys/time.h> |
| #include <utils/debug.h> |
| #include <utils/sys.h> |
| #include <utils/formats.h> |
| #include <drm_lib_loader.h> |
| #include <drm_master.h> |
| #include <drm_res_mgr.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <string> |
| #include <vector> |
| #include <map> |
| #include <utility> |
| |
| #ifndef HDR_EOTF_SMTPE_ST2084 |
| #define HDR_EOTF_SMTPE_ST2084 2 |
| #endif |
| #ifndef HDR_EOTF_HLG |
| #define HDR_EOTF_HLG 3 |
| #endif |
| |
| #define __CLASS__ "HWTVDRM" |
| |
| #define HDR_DISABLE 0 |
| #define HDR_ENABLE 1 |
| #define MIN_HDR_RESET_WAITTIME 2 |
| |
| using drm_utils::DRMMaster; |
| using drm_utils::DRMResMgr; |
| using drm_utils::DRMLibLoader; |
| using drm_utils::DRMBuffer; |
| using sde_drm::GetDRMManager; |
| using sde_drm::DestroyDRMManager; |
| using sde_drm::DRMDisplayType; |
| using sde_drm::DRMDisplayToken; |
| using sde_drm::DRMConnectorInfo; |
| using sde_drm::DRMPPFeatureInfo; |
| using sde_drm::DRMOps; |
| using sde_drm::DRMTopology; |
| using sde_drm::DRMPowerMode; |
| using sde_drm::DRMColorspace; |
| |
| namespace sdm { |
| |
| static uint64_t timeval_diff(std::chrono::time_point<SteadyClock> &start, |
| std::chrono::time_point<SteadyClock> &end) { |
| return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); |
| } |
| |
| static int32_t GetEOTF(const GammaTransfer &transfer) { |
| int32_t hdr_transfer = -1; |
| |
| switch (transfer) { |
| case Transfer_SMPTE_ST2084: |
| hdr_transfer = HDR_EOTF_SMTPE_ST2084; |
| break; |
| case Transfer_HLG: |
| hdr_transfer = HDR_EOTF_HLG; |
| break; |
| default: |
| DLOGW("Unknown Transfer: %d", transfer); |
| } |
| |
| return hdr_transfer; |
| } |
| |
| static float GetMaxOrAverageLuminance(float luminance) { |
| return (50.0f * powf(2.0f, (luminance / 32.0f))); |
| } |
| |
| static float GetMinLuminance(float luminance, float max_luminance) { |
| return (max_luminance * ((luminance / 255.0f) * (luminance / 255.0f)) / 100.0f); |
| } |
| |
| HWTVDRM::HWTVDRM(int32_t display_id, BufferAllocator *buffer_allocator, |
| HWInfoInterface *hw_info_intf) |
| : HWDeviceDRM(buffer_allocator, hw_info_intf) { |
| disp_type_ = DRMDisplayType::TV; |
| device_name_ = "TV"; |
| display_id_ = display_id; |
| } |
| |
| DisplayError HWTVDRM::SetDisplayAttributes(uint32_t index) { |
| if (index >= connector_info_.modes.size()) { |
| DLOGE("Invalid mode index %d mode size %d", index, UINT32(connector_info_.modes.size())); |
| return kErrorNotSupported; |
| } |
| |
| current_mode_index_ = index; |
| PopulateHWPanelInfo(); |
| UpdateMixerAttributes(); |
| |
| DLOGI("Display attributes[%d]: WxH: %dx%d, DPI: %fx%f, FPS: %d, LM_SPLIT: %d, V_BACK_PORCH: %d," \ |
| " V_FRONT_PORCH: %d, V_PULSE_WIDTH: %d, V_TOTAL: %d, H_TOTAL: %d, CLK: %dKHZ, TOPOLOGY: %d", |
| index, display_attributes_[index].x_pixels, display_attributes_[index].y_pixels, |
| display_attributes_[index].x_dpi, display_attributes_[index].y_dpi, |
| display_attributes_[index].fps, display_attributes_[index].is_device_split, |
| display_attributes_[index].v_back_porch, display_attributes_[index].v_front_porch, |
| display_attributes_[index].v_pulse_width, display_attributes_[index].v_total, |
| display_attributes_[index].h_total, display_attributes_[index].clock_khz, |
| display_attributes_[index].topology); |
| |
| return kErrorNone; |
| } |
| |
| DisplayError HWTVDRM::GetConfigIndex(char *mode, uint32_t *index) { |
| uint32_t width = 0, height = 0, fps = 0; |
| std::string str(mode); |
| |
| // mode should be in width:height:fps:format |
| // TODO(user): it is not fully robust, User needs to provide in above format only |
| if (str.length() != 0) { |
| width = UINT32(stoi(str)); |
| height = UINT32(stoi(str.substr(str.find(':') + 1))); |
| std::string str3 = str.substr(str.find(':') + 1); |
| fps = UINT32(stoi(str3.substr(str3.find(':') + 1))); |
| std::string str4 = str3.substr(str3.find(':') + 1); |
| } |
| |
| for (size_t idex = 0; idex < connector_info_.modes.size(); idex ++) { |
| if ((height == connector_info_.modes[idex].mode.vdisplay) && |
| (width == connector_info_.modes[idex].mode.hdisplay) && |
| (fps == connector_info_.modes[idex].mode.vrefresh)) { |
| *index = UINT32(idex); |
| break; |
| } |
| } |
| |
| return kErrorNone; |
| } |
| |
| DisplayError HWTVDRM::Flush(HWLayersInfo *hw_layers_info) { |
| if (hw_panel_info_.hdr_enabled) { |
| memset(&hdr_metadata_, 0, sizeof(hdr_metadata_)); |
| hdr_metadata_.hdr_supported = 1; |
| hdr_metadata_.hdr_state = HDR_DISABLE; |
| drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, |
| &hdr_metadata_); |
| } |
| |
| return HWDeviceDRM::Flush(hw_layers_info); |
| } |
| |
| DisplayError HWTVDRM::Deinit() { |
| if (hw_panel_info_.hdr_enabled) { |
| memset(&hdr_metadata_, 0, sizeof(hdr_metadata_)); |
| hdr_metadata_.hdr_supported = 1; |
| hdr_metadata_.hdr_state = HDR_DISABLE; |
| drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, |
| &hdr_metadata_); |
| } |
| |
| return HWDeviceDRM::Deinit(); |
| } |
| |
| DisplayError HWTVDRM::GetDefaultConfig(uint32_t *default_config) { |
| bool found = false; |
| |
| for (uint32_t i = 0; i < connector_info_.modes.size(); i++) { |
| auto &mode = connector_info_.modes[i].mode; |
| if (mode.hdisplay == 640 && mode.vdisplay == 480) { |
| *default_config = i; |
| found = true; |
| DLOGI("Found 640x480 default mode, using as failure fallback"); |
| break; |
| } |
| } |
| |
| return found ? kErrorNone : kErrorNotSupported; |
| } |
| |
| DisplayError HWTVDRM::PowerOff(bool teardown, SyncPoints *sync_points) { |
| DTRACE_SCOPED(); |
| if (!drm_atomic_intf_) { |
| DLOGE("DRM Atomic Interface is null!"); |
| return kErrorUndefined; |
| } |
| |
| if (first_cycle_) { |
| return kErrorNone; |
| } |
| |
| if (tui_state_ != kTUIStateNone && tui_state_ != kTUIStateEnd) { |
| DLOGI("Request deferred TUI state %d", tui_state_); |
| pending_power_state_ = kPowerStateOff; |
| return kErrorDeferred; |
| } |
| |
| if (teardown) { |
| // LP connecter prop N/A for External |
| drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 0); |
| } |
| ClearSolidfillStages(); |
| int ret = drm_atomic_intf_->Commit(true /* synchronous */, false /* retain_planes*/); |
| if (ret) { |
| DLOGE("%s failed with error %d", __FUNCTION__, ret); |
| return kErrorHardware; |
| } |
| |
| return kErrorNone; |
| } |
| |
| DisplayError HWTVDRM::Doze(const HWQosData &qos_data, SyncPoints *sync_points) { |
| return kErrorNone; |
| } |
| |
| DisplayError HWTVDRM::DozeSuspend(const HWQosData &qos_data, SyncPoints *sync_points) { |
| return kErrorNone; |
| } |
| |
| DisplayError HWTVDRM::Standby(SyncPoints *sync_points) { |
| return kErrorNone; |
| } |
| |
| void HWTVDRM::PopulateHWPanelInfo() { |
| hw_panel_info_ = {}; |
| |
| HWDeviceDRM::PopulateHWPanelInfo(); |
| hw_panel_info_.hdr_enabled = connector_info_.ext_hdr_prop.hdr_supported; |
| hw_panel_info_.hdr_plus_enabled = connector_info_.ext_hdr_prop.hdr_plus_supported; |
| hw_panel_info_.hdr_metadata_type_one = connector_info_.ext_hdr_prop.hdr_metadata_type_one; |
| hw_panel_info_.hdr_eotf = connector_info_.ext_hdr_prop.hdr_eotf; |
| hw_panel_info_.supported_colorspaces = connector_info_.supported_colorspaces; |
| |
| // Convert the raw luminance values from driver to Candela per meter^2 unit. |
| float max_luminance = FLOAT(connector_info_.ext_hdr_prop.hdr_max_luminance); |
| if (max_luminance != 0.0f) { |
| max_luminance = GetMaxOrAverageLuminance(max_luminance); |
| } |
| bool valid_luminance = (max_luminance > kMinPeakLuminance) && (max_luminance < kMaxPeakLuminance); |
| hw_panel_info_.peak_luminance = valid_luminance ? max_luminance : kDefaultMaxLuminance; |
| |
| float min_luminance = FLOAT(connector_info_.ext_hdr_prop.hdr_min_luminance); |
| if (min_luminance != 0.0f) { |
| min_luminance = GetMinLuminance(min_luminance, hw_panel_info_.peak_luminance); |
| } |
| hw_panel_info_.blackness_level = (min_luminance < 1.0f) ? min_luminance : kDefaultMinLuminance; |
| |
| float average_luminance = FLOAT(connector_info_.ext_hdr_prop.hdr_avg_luminance); |
| if (average_luminance != 0.0f) { |
| average_luminance = GetMaxOrAverageLuminance(average_luminance); |
| } else { |
| average_luminance = (hw_panel_info_.peak_luminance + hw_panel_info_.blackness_level) / 2.0f; |
| } |
| hw_panel_info_.average_luminance = average_luminance; |
| |
| DLOGI("TV Panel: %s%s, type_one = %d, eotf = %d, luminance[max = %f, min = %f, avg = %f]", |
| hw_panel_info_.hdr_enabled ? "HDR" : "Non-HDR", |
| hw_panel_info_.hdr_plus_enabled ? "10+" : "", hw_panel_info_.hdr_metadata_type_one, |
| hw_panel_info_.hdr_eotf, hw_panel_info_.peak_luminance, hw_panel_info_.blackness_level, |
| hw_panel_info_.average_luminance); |
| } |
| |
| DisplayError HWTVDRM::Commit(HWLayersInfo *hw_layers_info) { |
| DisplayError error = UpdateHDRMetaData(hw_layers_info); |
| if (error != kErrorNone) { |
| return error; |
| } |
| |
| int64_t cwb_fence_fd = -1; |
| bool has_fence = SetupConcurrentWriteback(*hw_layers_info, false, &cwb_fence_fd); |
| |
| error = HWDeviceDRM::Commit(hw_layers_info); |
| if (error != kErrorNone) { |
| return error; |
| } |
| |
| if (has_fence) { |
| hw_layers_info->output_buffer->release_fence = Fence::Create(INT(cwb_fence_fd), "release_cwb"); |
| } |
| |
| PostCommitConcurrentWriteback(hw_layers_info->output_buffer); |
| |
| return error; |
| } |
| |
| DisplayError HWTVDRM::UpdateHDRMetaData(HWLayersInfo *hw_layers_info) { |
| // Set colorspace on external DP when DP supports colorspace. |
| // For P3 use case set colorspace only. |
| // For HDR use case set both hdr metadata and colorspace. |
| if (hw_panel_info_.port == kPortDP && hw_panel_info_.supported_colorspaces) { |
| sde_drm::DRMColorspace colorspace = sde_drm::DRMColorspace::DEFAULT; |
| if (blend_space_.primaries == ColorPrimaries_DCIP3 && |
| blend_space_.transfer == Transfer_sRGB) { |
| colorspace = sde_drm::DRMColorspace::DCI_P3_RGB_D65; |
| /* In case of BT2020_YCC, BT2020_RGB is not set based on the layer format. We set it based on |
| the final output of display port controller. Here even though the layer as YUV , it will be |
| color converted to RGB using SSPP and the format going out of DP will be RGB. Hence we |
| should set BT2020_RGB. */ |
| } else if (blend_space_.primaries == ColorPrimaries_BT2020) { |
| colorspace = sde_drm::DRMColorspace::BT2020_RGB; |
| } |
| DLOGV_IF(kTagDriverConfig, "Set colorspace = %d", colorspace); |
| drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_COLORSPACE, token_.conn_id, colorspace); |
| } |
| |
| if (!hw_panel_info_.hdr_enabled) { |
| return kErrorNone; |
| } |
| |
| const HWHDRLayerInfo &hdr_layer_info = hw_layers_info->hdr_layer_info; |
| DisplayError error = kErrorNone; |
| HWHDRLayerInfo::HDROperation hdr_op = hdr_layer_info.operation; |
| |
| Layer hdr_layer = {}; |
| if (hdr_op == HWHDRLayerInfo::kSet && hdr_layer_info.layer_index > -1) { |
| int hdr_hw_layer_index = 0; |
| for (uint32_t i = 0; i < hw_layers_info->index.size(); i++) { |
| if (UINT32(hdr_layer_info.layer_index) == hw_layers_info->index[i]) { |
| hdr_hw_layer_index = i; |
| break; |
| } |
| } |
| hdr_layer = hw_layers_info->hw_layers.at(UINT32(hdr_hw_layer_index)); |
| } |
| |
| const LayerBuffer *layer_buffer = &hdr_layer.input_buffer; |
| const MasteringDisplay &mastering_display = layer_buffer->color_metadata.masteringDisplayInfo; |
| const ContentLightLevel &light_level = layer_buffer->color_metadata.contentLightLevel; |
| const Primaries &primaries = mastering_display.primaries; |
| |
| if (hdr_op == HWHDRLayerInfo::kSet && hdr_layer_info.hdr_layers.size() == 1) { |
| // Reset reset_hdr_flag_ to handle where there are two consecutive HDR video playbacks with not |
| // enough non-HDR frames in between to reset the HDR metadata. |
| reset_hdr_flag_ = false; |
| in_multiset_ = false; |
| |
| int32_t eotf = GetEOTF(layer_buffer->color_metadata.transfer); |
| hdr_metadata_.hdr_supported = 1; |
| hdr_metadata_.hdr_state = HDR_ENABLE; |
| hdr_metadata_.eotf = (eotf < 0) ? 0 : UINT32(eotf); |
| hdr_metadata_.white_point_x = primaries.whitePoint[0]; |
| hdr_metadata_.white_point_y = primaries.whitePoint[1]; |
| hdr_metadata_.display_primaries_x[0] = primaries.rgbPrimaries[0][0]; |
| hdr_metadata_.display_primaries_y[0] = primaries.rgbPrimaries[0][1]; |
| hdr_metadata_.display_primaries_x[1] = primaries.rgbPrimaries[1][0]; |
| hdr_metadata_.display_primaries_y[1] = primaries.rgbPrimaries[1][1]; |
| hdr_metadata_.display_primaries_x[2] = primaries.rgbPrimaries[2][0]; |
| hdr_metadata_.display_primaries_y[2] = primaries.rgbPrimaries[2][1]; |
| hdr_metadata_.min_luminance = mastering_display.minDisplayLuminance; |
| hdr_metadata_.max_luminance = mastering_display.maxDisplayLuminance; |
| hdr_metadata_.max_content_light_level = light_level.maxContentLightLevel; |
| hdr_metadata_.max_average_light_level = light_level.minPicAverageLightLevel; |
| if (hw_panel_info_.hdr_plus_enabled && hdr_layer_info.dyn_hdr_vsif_payload.size()) { |
| hdr_metadata_.hdr_plus_payload = reinterpret_cast<uint64_t> |
| (hdr_layer_info.dyn_hdr_vsif_payload.data()); |
| hdr_metadata_.hdr_plus_payload_size = UINT32(hdr_layer_info.dyn_hdr_vsif_payload.size()); |
| } else { |
| hdr_metadata_.hdr_plus_payload = reinterpret_cast<uint64_t>(nullptr); |
| hdr_metadata_.hdr_plus_payload_size = 0; |
| } |
| |
| drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, &hdr_metadata_); |
| DumpHDRMetaData(hdr_op); |
| } else if (hdr_op == HWHDRLayerInfo::kSet && !in_multiset_) { |
| // Special case to handle multiple HDR layers. |
| // If there are multiple HDR layers, then simply drop all metadata (which is optional) since |
| // content going in and out of view (e.g., video start/stop, scrolling video preview thumbnails) |
| // will cause flicker. |
| InitMaxHDRMetaData(); |
| in_multiset_ = true; |
| reset_hdr_flag_ = false; |
| drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, &hdr_metadata_); |
| DumpHDRMetaData(hdr_op); |
| } else if (hdr_op == HWHDRLayerInfo::kReset) { |
| memset(&hdr_metadata_, 0, sizeof(hdr_metadata_)); |
| hdr_metadata_.hdr_supported = 1; |
| hdr_metadata_.hdr_state = HDR_ENABLE; |
| reset_hdr_flag_ = true; |
| in_multiset_ = false; |
| hdr_reset_start_ = SteadyClock::now(); |
| |
| drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, &hdr_metadata_); |
| DumpHDRMetaData(hdr_op); |
| } else if (hdr_op == HWHDRLayerInfo::kNoOp) { |
| // TODO(user): This case handles the state transition from HDR_ENABLED to HDR_DISABLED. |
| // As per HDMI spec requirement, we need to send zero metadata for atleast 2 sec after end of |
| // playback. This timer calculates the 2 sec window after playback stops to stop sending HDR |
| // metadata. This will be replaced with an idle timer implementation in the future. |
| if (reset_hdr_flag_) { |
| hdr_reset_end_ = SteadyClock::now(); |
| const uint64_t hdr_reset_duration_ms = timeval_diff(hdr_reset_start_, hdr_reset_end_); |
| |
| if (hdr_reset_duration_ms >= UINT64(MIN_HDR_RESET_WAITTIME) * 1000ull) { |
| memset(&hdr_metadata_, 0, sizeof(hdr_metadata_)); |
| hdr_metadata_.hdr_supported = 1; |
| hdr_metadata_.hdr_state = HDR_DISABLE; |
| reset_hdr_flag_ = false; |
| |
| drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, |
| &hdr_metadata_); |
| } |
| } |
| } |
| |
| return error; |
| } |
| |
| void HWTVDRM::DumpHDRMetaData(HWHDRLayerInfo::HDROperation operation) { |
| DLOGI("Operation = %d, HDR Metadata: MaxDisplayLuminance = %d MinDisplayLuminance = %d\n" |
| "MaxContentLightLevel = %d MaxAverageLightLevel = %d Red_x = %d Red_y = %d Green_x = %d\n" |
| "Green_y = %d Blue_x = %d Blue_y = %d WhitePoint_x = %d WhitePoint_y = %d EOTF = %d\n" |
| "HDR10+ payload size = %u\n", |
| operation, hdr_metadata_.max_luminance, hdr_metadata_.min_luminance, |
| hdr_metadata_.max_content_light_level, hdr_metadata_.max_average_light_level, |
| hdr_metadata_.display_primaries_x[0], hdr_metadata_.display_primaries_y[0], |
| hdr_metadata_.display_primaries_x[1], hdr_metadata_.display_primaries_y[1], |
| hdr_metadata_.display_primaries_x[2], hdr_metadata_.display_primaries_y[2], |
| hdr_metadata_.white_point_x, hdr_metadata_.white_point_y, hdr_metadata_.eotf, |
| hdr_metadata_.hdr_plus_payload_size); |
| } |
| |
| void HWTVDRM::InitMaxHDRMetaData() { |
| memset(&hdr_metadata_, 0, sizeof(hdr_metadata_)); |
| hdr_metadata_.hdr_supported = 1; |
| hdr_metadata_.hdr_state = HDR_ENABLE; |
| hdr_metadata_.eotf = UINT32(GetEOTF(Transfer_SMPTE_ST2084)); |
| // Rec. 2020 (ITU-R Recommendation BT.2020) RGB color space parameters |
| // +---------------+-----------------+-----------------------------------------------+ |
| // | | White point | Primary colors | |
| // | Color space +--------+--------+-------+-------+-------+-------+-------+-------+ |
| // | | xW | yW | xR | yR | xG | yG | xB | yB | |
| // +---------------+--------+--------+-------+-------+-------+-------+-------+-------+ |
| // | ITU-R BT.2020 | 0.3127 | 0.3290 | 0.708 | 0.292 | 0.170 | 0.797 | 0.131 | 0.046 | |
| // +---------------+--------+--------+-------+-------+-------+-------+-------+-------+ |
| // Rec. 2020 D65 'CIE Standard Illuminant'. |
| hdr_metadata_.white_point_x = 15635; // 0.31271 x 50000 |
| hdr_metadata_.white_point_y = 16451; // 0.32902 x 50000 |
| // Rec. 2020 primaries. |
| hdr_metadata_.display_primaries_x[0] = 35400; // 0.708 x 50000 |
| hdr_metadata_.display_primaries_y[0] = 14600; // 0.292 x 50000 |
| hdr_metadata_.display_primaries_x[1] = 8500; // 0.170 x 50000 |
| hdr_metadata_.display_primaries_y[1] = 39850; // 0.797 x 50000 |
| hdr_metadata_.display_primaries_x[2] = 6550; // 0.131 x 50000 |
| hdr_metadata_.display_primaries_y[2] = 2300; // 0.046 x 50000 |
| hdr_metadata_.min_luminance = 0; // 0 nits |
| hdr_metadata_.max_luminance = 100000000; // 10000 nits |
| hdr_metadata_.max_content_light_level = 100000000; // 10000 nits brightest pixel in content |
| hdr_metadata_.max_average_light_level = 100000000; // 10000 nits brightest frame in content |
| } |
| |
| DisplayError HWTVDRM::PowerOn(const HWQosData &qos_data, SyncPoints *sync_points) { |
| DTRACE_SCOPED(); |
| if (!drm_atomic_intf_) { |
| DLOGE("DRM Atomic Interface is null!"); |
| return kErrorUndefined; |
| } |
| |
| if (first_cycle_) { |
| drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_CRTC, token_.conn_id, token_.crtc_id); |
| drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_].mode; |
| drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, ¤t_mode); |
| if (hw_panel_info_.hdr_enabled) { |
| hdr_metadata_.hdr_supported = 1; |
| hdr_metadata_.hdr_state = HDR_DISABLE; |
| drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, |
| &hdr_metadata_); |
| } |
| } |
| |
| return HWDeviceDRM::PowerOn(qos_data, sync_points); |
| } |
| |
| } // namespace sdm |
| |