blob: d08ee3df1737e55d8be7714cbf66c51b4327983c [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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.
*/
#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
#include "ExynosPrimaryDisplayModule.h"
#include <android-base/file.h>
#include <json/reader.h>
#include <json/value.h>
#include <cmath>
#include "BrightnessController.h"
#include "ExynosDisplayDrmInterfaceModule.h"
#include "ExynosHWCDebug.h"
#ifdef FORCE_GPU_COMPOSITION
extern exynos_hwc_control exynosHWCControl;
#endif
using namespace gs101;
mpp_phycal_type_t getMPPTypeFromDPPChannel(uint32_t channel) {
for (int i=0; i < MAX_DECON_DMA_TYPE; i++){
if(idma_channel_map[i].channel == channel)
return idma_channel_map[i].type;
}
return MPP_P_TYPE_MAX;
}
ExynosPrimaryDisplayModule::ExynosPrimaryDisplayModule(uint32_t index, ExynosDevice* device,
const std::string& displayName)
: ExynosPrimaryDisplay(index, device, displayName), mAtcInit(false) {
#ifdef FORCE_GPU_COMPOSITION
exynosHWCControl.forceGpu = true;
#endif
mColorManager = std::make_unique<ColorManager>(this, static_cast<ExynosDeviceModule*>(device));
}
ExynosPrimaryDisplayModule::~ExynosPrimaryDisplayModule () {
}
void ExynosPrimaryDisplayModule::usePreDefinedWindow(bool use)
{
#ifdef FIX_BASE_WINDOW_INDEX
/* Use fixed base window index */
mBaseWindowIndex = FIX_BASE_WINDOW_INDEX;
return;
#endif
if (use) {
mBaseWindowIndex = PRIMARY_DISP_BASE_WIN[mDevice->mDisplayMode];
mMaxWindowNum = mDisplayInterface->getMaxWindowNum() - PRIMARY_DISP_BASE_WIN[mDevice->mDisplayMode];
} else {
mBaseWindowIndex = 0;
mMaxWindowNum = mDisplayInterface->getMaxWindowNum();
}
}
int32_t ExynosPrimaryDisplayModule::validateWinConfigData()
{
bool flagValidConfig = true;
if (ExynosDisplay::validateWinConfigData() != NO_ERROR)
flagValidConfig = false;
for (size_t i = 0; i < mDpuData.configs.size(); i++) {
struct exynos_win_config_data &config = mDpuData.configs[i];
if (config.state == config.WIN_STATE_BUFFER) {
bool configInvalid = false;
uint32_t mppType = config.assignedMPP->mPhysicalType;
if ((config.src.w != config.dst.w) ||
(config.src.h != config.dst.h)) {
if ((mppType == MPP_DPP_GF) ||
(mppType == MPP_DPP_VG) ||
(mppType == MPP_DPP_VGF)) {
DISPLAY_LOGE("WIN_CONFIG error: invalid assign id : "
"%zu, s_w : %d, d_w : %d, s_h : %d, d_h : %d, mppType : %d",
i, config.src.w, config.dst.w, config.src.h, config.dst.h, mppType);
configInvalid = true;
}
}
if (configInvalid) {
config.state = config.WIN_STATE_DISABLED;
flagValidConfig = false;
}
}
}
if (flagValidConfig)
return NO_ERROR;
else
return -EINVAL;
}
void ExynosPrimaryDisplayModule::doPreProcessing() {
ExynosDisplay::doPreProcessing();
if (mDevice->checkNonInternalConnection()) {
mDisplayControl.adjustDisplayFrame = true;
} else {
mDisplayControl.adjustDisplayFrame = false;
}
}
int32_t ExynosPrimaryDisplayModule::getColorModes(
uint32_t* outNumModes, int32_t* outModes)
{
return mColorManager->getColorModes(outNumModes, outModes);
}
int32_t ExynosPrimaryDisplayModule::setColorMode(int32_t mode)
{
return mColorManager->setColorMode(mode);
}
int32_t ExynosPrimaryDisplayModule::getRenderIntents(int32_t mode,
uint32_t* outNumIntents, int32_t* outIntents)
{
return mColorManager->getRenderIntents(mode, outNumIntents, outIntents);
}
int32_t ExynosPrimaryDisplayModule::setColorModeWithRenderIntent(int32_t mode,
int32_t intent)
{
return mColorManager->setColorModeWithRenderIntent(mode, intent);
}
int32_t ExynosPrimaryDisplayModule::setColorTransform(
const float* matrix, int32_t hint)
{
return mColorManager->setColorTransform(matrix, hint);
}
int32_t ExynosPrimaryDisplayModule::getClientTargetProperty(
hwc_client_target_property_t* outClientTargetProperty,
HwcDimmingStage *outDimmingStage) {
GsInterfaceType* displayColorInterface = getDisplayColorInterface();
if (displayColorInterface == nullptr) {
ALOGI("%s dc interface not created", __func__);
return ExynosDisplay::getClientTargetProperty(outClientTargetProperty);
}
const DisplayType display = getDcDisplayType();
hwc::PixelFormat pixelFormat;
hwc::Dataspace dataspace;
bool dimming_linear;
if (!displayColorInterface->GetBlendingProperty(display, pixelFormat, dataspace,
dimming_linear)) {
outClientTargetProperty->pixelFormat = toUnderlying(pixelFormat);
outClientTargetProperty->dataspace = toUnderlying(dataspace);
if (outDimmingStage != nullptr)
*outDimmingStage = dimming_linear
? HwcDimmingStage::DIMMING_LINEAR
: HwcDimmingStage::DIMMING_OETF;
return HWC2_ERROR_NONE;
}
ALOGW("%s failed to get property of blending stage", __func__);
return ExynosDisplay::getClientTargetProperty(outClientTargetProperty);
}
int32_t ExynosPrimaryDisplayModule::updateBrightnessTable() {
std::unique_ptr<const IBrightnessTable> table;
auto displayColorInterface = getDisplayColorInterface();
if (displayColorInterface == nullptr) {
ALOGE("%s displaycolor interface not available!", __func__);
return HWC2_ERROR_NO_RESOURCES;
}
auto displayType = getDcDisplayType();
auto ret = displayColorInterface->GetBrightnessTable(displayType, table);
if (ret != android::OK) {
ALOGE("%s brightness table not available!", __func__);
return HWC2_ERROR_NO_RESOURCES;
}
// BrightnessController is not ready until this step
mBrightnessController->updateBrightnessTable(table);
return HWC2_ERROR_NONE;
}
int ExynosPrimaryDisplayModule::deliverWinConfigData()
{
int ret = 0;
ExynosDisplayDrmInterfaceModule *moduleDisplayInterface =
(ExynosDisplayDrmInterfaceModule*)(mDisplayInterface.get());
GsInterfaceType* displayColorInterface = getDisplayColorInterface();
bool forceDisplayColorSetting = false;
if (!getDisplaySceneInfo().displaySettingDelivered || isForceColorUpdate())
forceDisplayColorSetting = true;
setForceColorUpdate(false);
if (displayColorInterface != nullptr) {
moduleDisplayInterface
->setColorSettingChanged(getDisplaySceneInfo().needDisplayColorSetting(),
forceDisplayColorSetting);
}
checkAtcHdrMode();
ret = ExynosDisplay::deliverWinConfigData();
checkAtcAnimation();
if (mDpuData.enable_readback &&
!mDpuData.readback_info.requested_from_service)
getDisplaySceneInfo().displaySettingDelivered = false;
else
getDisplaySceneInfo().displaySettingDelivered = true;
return ret;
}
int32_t ExynosPrimaryDisplayModule::updateColorConversionInfo()
{
return mColorManager->updateColorConversionInfo();
}
int32_t ExynosPrimaryDisplayModule::resetColorMappingInfo(ExynosMPPSource* mppSrc) {
return mColorManager->resetColorMappingInfo(mppSrc);
}
int32_t ExynosPrimaryDisplayModule::updatePresentColorConversionInfo()
{
int ret = NO_ERROR;
GsInterfaceType* displayColorInterface = getDisplayColorInterface();
if (displayColorInterface == nullptr) {
return ret;
}
ExynosDisplayDrmInterfaceModule *moduleDisplayInterface =
(ExynosDisplayDrmInterfaceModule*)(mDisplayInterface.get());
auto refresh_rate = moduleDisplayInterface->getDesiredRefreshRate();
if (refresh_rate > 0) {
getDisplaySceneInfo().displayScene.refresh_rate = refresh_rate;
}
auto operation_rate = moduleDisplayInterface->getOperationRate();
if (operation_rate > 0) {
getDisplaySceneInfo().displayScene.operation_rate = static_cast<uint32_t>(operation_rate);
}
getDisplaySceneInfo().displayScene.lhbm_on = mBrightnessController->isLhbmOn();
getDisplaySceneInfo().displayScene.dbv = mBrightnessController->getBrightnessLevel();
const DisplayType display = getDcDisplayType();
if ((ret = displayColorInterface->UpdatePresent(display, getDisplaySceneInfo().displayScene)) !=
0) {
DISPLAY_LOGE("Display Scene update error (%d)", ret);
return ret;
}
return ret;
}
int32_t ExynosPrimaryDisplayModule::getColorAdjustedDbv(uint32_t &dbv_adj) {
GsInterfaceType* displayColorInterface = getDisplayColorInterface();
if (displayColorInterface == nullptr) {
return NO_ERROR;
}
const DisplayType display = getDcDisplayType();
dbv_adj = displayColorInterface->GetPipelineData(display)->Panel().GetAdjustedBrightnessLevel();
return NO_ERROR;
}
bool ExynosPrimaryDisplayModule::parseAtcProfile() {
Json::Value root;
Json::CharReaderBuilder reader_builder;
std::unique_ptr<Json::CharReader> reader(reader_builder.newCharReader());
std::string atc_profile;
if (!android::base::ReadFileToString(kAtcProfilePath, &atc_profile)) {
atc_profile = kAtcJsonRaw;
ALOGI("Use default atc profile file");
}
if (!reader->parse(atc_profile.c_str(), atc_profile.c_str() + atc_profile.size(), &root,
nullptr)) {
ALOGE("Failed to parse atc profile file");
return false;
}
ALOGI("Atc Profile version = %s", root[kAtcProfileVersionStr].asString().c_str());
Json::Value nodes = root[kAtcProfileModesStr];
atc_mode mode;
for (Json::Value::ArrayIndex i = 0; i < nodes.size(); ++i) {
std::string name = nodes[i][kAtcProfileModeNameStr].asString();
if (nodes[i][kAtcProfileLuxMapStr].size() != nodes[i][kAtcProfileAlMapStr].size() &&
nodes[i][kAtcProfileAlMapStr].size() != nodes[i][kAtcProfileStMapStr].size()) {
ALOGE("Atc profile is unavailable !");
return false;
}
uint32_t map_cnt = nodes[i][kAtcProfileLuxMapStr].size();
mode.lux_map.clear();
for (uint32_t index = 0; index < map_cnt; ++index) {
mode.lux_map.emplace_back(atc_lux_map{nodes[i][kAtcProfileLuxMapStr][index].asUInt(),
nodes[i][kAtcProfileAlMapStr][index].asUInt(),
nodes[i][kAtcProfileStMapStr][index].asUInt()});
}
if (!nodes[i][kAtcProfileStUpStepStr].empty())
mode.st_up_step = nodes[i][kAtcProfileStUpStepStr].asUInt();
else
mode.st_up_step = kAtcStStep;
if (!nodes[i][kAtcProfileStDownStepStr].empty())
mode.st_down_step = nodes[i][kAtcProfileStDownStepStr].asUInt();
else
mode.st_down_step = kAtcStStep;
if (nodes[i][kAtcProfileSubSettingStr].size() != kAtcSubSetting.size()) return false;
for (auto it = kAtcSubSetting.begin(); it != kAtcSubSetting.end(); it++) {
mode.sub_setting[it->first.c_str()] =
nodes[i][kAtcProfileSubSettingStr][it->first.c_str()].asUInt();
}
auto ret = mAtcModeSetting.insert(std::make_pair(name.c_str(), mode));
if (ret.second == false) {
ALOGE("Atc mode %s is already existed!", ret.first->first.c_str());
return false;
}
}
if (mAtcModeSetting.find(kAtcModeNormalStr) == mAtcModeSetting.end()) {
ALOGW("Failed to find atc normal mode");
return false;
}
return true;
}
bool ExynosPrimaryDisplayModule::isLbeSupported() {
return mLbeSupported;
}
void ExynosPrimaryDisplayModule::initLbe() {
if (!parseAtcProfile()) {
ALOGD("Failed to parseAtcMode");
mAtcInit = false;
return;
}
mAtcInit = true;
mAtcAmbientLight.node = String8::format(ATC_AMBIENT_LIGHT_FILE_NAME, mIndex);
mAtcAmbientLight.value.set_dirty();
mAtcStrength.node = String8::format(ATC_ST_FILE_NAME, mIndex);
mAtcStrength.value.set_dirty();
mAtcEnable.node = String8::format(ATC_ENABLE_FILE_NAME, mIndex);
mAtcEnable.value.set_dirty();
for (auto it = kAtcSubSetting.begin(); it != kAtcSubSetting.end(); it++) {
mAtcSubSetting[it->first.c_str()].node = String8::format(it->second.c_str(), mIndex);
mAtcSubSetting[it->first.c_str()].value.set_dirty();
}
mLbeSupported = true;
}
uint32_t ExynosPrimaryDisplayModule::getAtcLuxMapIndex(std::vector<atc_lux_map> map, uint32_t lux) {
uint32_t index = 0;
for (uint32_t i = 0; i < map.size(); i++) {
if (lux < map[i].lux) {
break;
}
index = i;
}
return index;
}
int32_t ExynosPrimaryDisplayModule::setAtcStrength(uint32_t strength) {
mAtcStrength.value.store(strength);
if (mAtcStrength.value.is_dirty()) {
if (writeIntToFile(mAtcStrength.node.c_str(), mAtcStrength.value.get()) != NO_ERROR) {
return -EPERM;
}
mAtcStrength.value.clear_dirty();
}
return NO_ERROR;
}
int32_t ExynosPrimaryDisplayModule::setAtcAmbientLight(uint32_t ambient_light) {
mAtcAmbientLight.value.store(ambient_light);
if (mAtcAmbientLight.value.is_dirty()) {
if (writeIntToFile(mAtcAmbientLight.node.c_str(), mAtcAmbientLight.value.get()) != NO_ERROR)
return -EPERM;
mAtcAmbientLight.value.clear_dirty();
}
return NO_ERROR;
}
int32_t ExynosPrimaryDisplayModule::setAtcMode(std::string mode_name) {
ATRACE_CALL();
auto mode_data = mAtcModeSetting.find(mode_name);
uint32_t ambient_light = 0;
uint32_t strength = 0;
bool enable = (!mode_name.empty()) && (mode_data != mAtcModeSetting.end());
if (enable) {
atc_mode mode = mode_data->second;
for (auto it = kAtcSubSetting.begin(); it != kAtcSubSetting.end(); it++) {
mAtcSubSetting[it->first.c_str()].value.store(mode.sub_setting[it->first.c_str()]);
if (mAtcSubSetting[it->first.c_str()].value.is_dirty()) {
if (writeIntToFile(mAtcSubSetting[it->first.c_str()].node.c_str(),
mAtcSubSetting[it->first.c_str()].value.get()) != NO_ERROR)
return -EPERM;
mAtcSubSetting[it->first.c_str()].value.clear_dirty();
}
}
mAtcStUpStep = mode.st_up_step;
mAtcStDownStep = mode.st_down_step;
uint32_t index = getAtcLuxMapIndex(mode.lux_map, mCurrentLux);
ambient_light = mode.lux_map[index].al;
strength = mode.lux_map[index].st;
}
if (setAtcAmbientLight(ambient_light) != NO_ERROR) {
ALOGE("Fail to set atc ambient light for %s mode", mode_name.c_str());
return -EPERM;
}
if (setAtcStDimming(strength) != NO_ERROR) {
ALOGE("Fail to set atc st dimming for %s mode", mode_name.c_str());
return -EPERM;
}
if (!enable && isInAtcAnimation()) {
mPendingAtcOff = true;
} else {
if (setAtcEnable(enable) != NO_ERROR) {
ALOGE("Fail to set atc enable = %d", enable);
return -EPERM;
}
mPendingAtcOff = false;
}
mCurrentAtcModeName = enable ? mode_name : "NULL";
ALOGI("atc enable=%d (mode=%s, pending off=%s)", enable, mCurrentAtcModeName.c_str(),
mPendingAtcOff ? "true" : "false");
return NO_ERROR;
}
void ExynosPrimaryDisplayModule::setLbeState(LbeState state) {
if (!mAtcInit) return;
std::string modeStr;
bool enhanced_hbm = false;
bool fullHdrLayer = isFullScreenHdrLayer();
switch (state) {
case LbeState::OFF:
mCurrentLux = 0;
break;
case LbeState::NORMAL:
modeStr = kAtcModeNormalStr;
break;
case LbeState::HIGH_BRIGHTNESS:
modeStr = kAtcModeHbmStr;
break;
case LbeState::POWER_SAVE:
modeStr = kAtcModePowerSaveStr;
break;
case LbeState::HIGH_BRIGHTNESS_ENHANCE:
modeStr = kAtcModeHbmStr;
enhanced_hbm = true;
break;
default:
ALOGE("Lbe state not support");
return;
}
if (fullHdrLayer && state != LbeState::OFF) checkAtcHdrMode();
else if (setAtcMode(modeStr) != NO_ERROR) return;
mBrightnessController->processEnhancedHbm(enhanced_hbm);
mBrightnessController->setOutdoorVisibility(state);
if (mCurrentLbeState != state) {
mCurrentLbeState = state;
mDevice->onRefresh(mDisplayId);
}
ALOGI("Lbe state %hhd", mCurrentLbeState);
}
void ExynosPrimaryDisplayModule::setLbeAmbientLight(int value) {
if (!mAtcInit) return;
auto it = mAtcModeSetting.find(mCurrentAtcModeName);
if (it == mAtcModeSetting.end()) {
ALOGE("Atc mode not found");
return;
}
atc_mode mode = it->second;
uint32_t index = getAtcLuxMapIndex(mode.lux_map, value);
if (setAtcAmbientLight(mode.lux_map[index].al) != NO_ERROR) {
ALOGE("Failed to set atc ambient light");
return;
}
if (setAtcStDimming(mode.lux_map[index].st) != NO_ERROR) {
ALOGE("Failed to set atc st dimming");
return;
}
if (mAtcLuxMapIndex != index) {
mAtcLuxMapIndex = index;
mDevice->onRefresh(mDisplayId);
}
mCurrentLux = value;
}
LbeState ExynosPrimaryDisplayModule::getLbeState() {
return mCurrentLbeState;
}
PanelCalibrationStatus ExynosPrimaryDisplayModule::getPanelCalibrationStatus() {
auto displayColorInterface = getDisplayColorInterface();
if (displayColorInterface == nullptr) {
return PanelCalibrationStatus::UNCALIBRATED;
}
auto displayType = getDcDisplayType();
auto calibrationInfo = displayColorInterface->GetCalibrationInfo(displayType);
if (calibrationInfo.factory_cal_loaded) {
return PanelCalibrationStatus::ORIGINAL;
} else if (calibrationInfo.golden_cal_loaded) {
return PanelCalibrationStatus::GOLDEN;
} else {
return PanelCalibrationStatus::UNCALIBRATED;
}
}
int32_t ExynosPrimaryDisplayModule::setAtcStDimming(uint32_t value) {
Mutex::Autolock lock(mAtcStMutex);
int32_t strength = mAtcStrength.value.get();
if (mAtcStTarget != value) {
mAtcStTarget = value;
uint32_t step = mAtcStTarget > strength ? mAtcStUpStep : mAtcStDownStep;
int diff = value - strength;
uint32_t count = (std::abs(diff) + step - 1) / step;
mAtcStStepCount = count;
ALOGI("setup atc st dimming=%d, count=%d, step=%d", value, count, step);
}
if (mAtcStStepCount == 0 && !mAtcStrength.value.is_dirty()) return NO_ERROR;
if ((strength + mAtcStUpStep) < mAtcStTarget) {
strength = strength + mAtcStUpStep;
} else if (strength > (mAtcStTarget + mAtcStDownStep)) {
strength = strength - mAtcStDownStep;
} else {
strength = mAtcStTarget;
}
if (setAtcStrength(strength) != NO_ERROR) {
ALOGE("Failed to set atc st");
return -EPERM;
}
if (mAtcStStepCount > 0) mAtcStStepCount--;
return NO_ERROR;
}
int32_t ExynosPrimaryDisplayModule::setAtcEnable(bool enable) {
mAtcEnable.value.store(enable);
if (mAtcEnable.value.is_dirty()) {
if (writeIntToFile(mAtcEnable.node.c_str(), enable) != NO_ERROR) return -EPERM;
mAtcEnable.value.clear_dirty();
}
return NO_ERROR;
}
void ExynosPrimaryDisplayModule::checkAtcAnimation() {
if (!isInAtcAnimation()) return;
if (setAtcStDimming(mAtcStTarget) != NO_ERROR) {
ALOGE("Failed to set atc st dimming");
return;
}
if (mPendingAtcOff && mAtcStStepCount == 0) {
if (setAtcEnable(false) != NO_ERROR) {
ALOGE("Failed to set atc enable to off");
return;
}
mPendingAtcOff = false;
ALOGI("atc enable is off (pending off=false)");
}
mDevice->onRefresh(mDisplayId);
}
int32_t ExynosPrimaryDisplayModule::setPowerMode(int32_t mode) {
hwc2_power_mode_t prevPowerModeState = mPowerModeState.value_or(HWC2_POWER_MODE_OFF);
int32_t ret;
ret = ExynosPrimaryDisplay::setPowerMode(mode);
if ((ret == HWC2_ERROR_NONE) && isDisplaySwitched(mode, prevPowerModeState)) {
ExynosDeviceModule* device = static_cast<ExynosDeviceModule*>(mDevice);
device->setActiveDisplay(mIndex);
setForceColorUpdate(true);
}
return ret;
}
bool ExynosPrimaryDisplayModule::isDisplaySwitched(int32_t mode, int32_t prevMode) {
ExynosDeviceModule* device = static_cast<ExynosDeviceModule*>(mDevice);
return (device->getActiveDisplay() != mIndex) && (prevMode == HWC_POWER_MODE_OFF) &&
(mode != HWC_POWER_MODE_OFF);
}
void ExynosPrimaryDisplayModule::checkAtcHdrMode() {
ATRACE_CALL();
if (!mAtcInit) return;
auto it = mAtcModeSetting.find(kAtcModeHdrStr);
if (it == mAtcModeSetting.end()) {
return;
}
bool hdrModeActive = (mCurrentAtcModeName == kAtcModeHdrStr);
bool fullHdrLayer = isFullScreenHdrLayer();
if (fullHdrLayer) {
if (!hdrModeActive && (mCurrentLbeState != LbeState::OFF)) {
setAtcMode(kAtcModeHdrStr);
ALOGI("HdrLayer on to set atc hdr mode");
}
} else {
if (hdrModeActive) {
setLbeState(mCurrentLbeState);
ALOGI("HdrLayer off to restore Lbe State");
}
}
}
bool ExynosPrimaryDisplayModule::isFullScreenHdrLayer() {
return mBrightnessController->getHdrLayerState() == HdrLayerState::kHdrLarge;
}