android_mt6572_jiabo/hardware/cyanogen/livedisplay/impl/SDM.cpp
2025-09-05 16:56:03 +08:00

560 lines
17 KiB
C++

/*
** Copyright 2016, The CyanogenMod Project
** 2017, The LineageOS 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.
*/
#include <dlfcn.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <cutils/properties.h>
//#define LOG_NDEBUG 0
#define LOG_TAG "LiveDisplay-SDM"
#include <utils/Log.h>
#include "SDM.h"
#include "Utils.h"
namespace android {
status_t SDM::loadVendorLibrary() {
if (mLibHandle != NULL) {
return OK;
}
mLibHandle = dlopen(SDM_DISP_LIB, RTLD_NOW);
if (mLibHandle == NULL) {
ALOGE("DLOPEN failed for %s (%s)", SDM_DISP_LIB, dlerror());
return NO_INIT;
}
disp_api_init = (int32_t(*)(int64_t*, uint32_t))dlsym(mLibHandle, "disp_api_init");
if (disp_api_init == NULL) {
ALOGE("dlsym failed for disp_api_init");
goto fail;
}
disp_api_deinit = (int32_t(*)(int64_t, uint32_t))dlsym(mLibHandle, "disp_api_deinit");
if (disp_api_deinit == NULL) {
ALOGE("dlsym failed for disp_api_deinit");
goto fail;
}
disp_api_get_global_color_balance_range = (int32_t(*)(int64_t, uint32_t, void*))dlsym(
mLibHandle, "disp_api_get_global_color_balance_range");
if (disp_api_get_global_color_balance_range == NULL) {
ALOGE("dlsym failed for disp_api_get_global_color_balance_range");
goto fail;
}
disp_api_set_global_color_balance = (int32_t(*)(int64_t, uint32_t, int32_t, uint32_t))dlsym(
mLibHandle, "disp_api_set_global_color_balance");
if (disp_api_set_global_color_balance == NULL) {
ALOGE("dlsym failed for disp_api_set_global_color_balance");
goto fail;
}
disp_api_get_global_color_balance = (int32_t(*)(int64_t, uint32_t, int32_t*, uint32_t*))dlsym(
mLibHandle, "disp_api_get_global_color_balance");
if (disp_api_get_global_color_balance == NULL) {
ALOGE("dlsym failed for disp_api_get_global_color_balance");
goto fail;
}
disp_api_get_num_display_modes =
(int32_t(*)(int64_t, uint32_t, int32_t, int32_t*, uint32_t*))dlsym(
mLibHandle, "disp_api_get_num_display_modes");
if (disp_api_get_num_display_modes == NULL) {
ALOGE("dlsym failed for disp_api_get_num_display_modes");
goto fail;
}
disp_api_get_display_modes =
(int32_t(*)(int64_t, uint32_t, int32_t, void*, int32_t, uint32_t*))dlsym(
mLibHandle, "disp_api_get_display_modes");
if (disp_api_get_display_modes == NULL) {
ALOGE("dlsym failed for disp_api_get_display_modes");
goto fail;
}
disp_api_get_active_display_mode =
(int32_t(*)(int64_t, uint32_t, int32_t*, uint32_t*, uint32_t*))dlsym(
mLibHandle, "disp_api_get_active_display_mode");
if (disp_api_get_active_display_mode == NULL) {
ALOGE("dlsym failed for disp_api_get_active_display_mode");
goto fail;
}
disp_api_set_active_display_mode = (int32_t(*)(int64_t, uint32_t, int32_t, uint32_t))dlsym(
mLibHandle, "disp_api_set_active_display_mode");
if (disp_api_set_active_display_mode == NULL) {
ALOGE("dlsym failed for disp_api_set_active_display_mode");
goto fail;
}
disp_api_set_default_display_mode = (int32_t(*)(int64_t, uint32_t, int32_t, uint32_t))dlsym(
mLibHandle, "disp_api_set_default_display_mode");
if (disp_api_set_default_display_mode == NULL) {
ALOGE("dlsym failed for disp_api_set_default_display_mode");
goto fail;
}
disp_api_get_default_display_mode = (int32_t(*)(int64_t, uint32_t, int32_t*, uint32_t*))dlsym(
mLibHandle, "disp_api_get_default_display_mode");
if (disp_api_get_default_display_mode == NULL) {
ALOGE("dlsym failed for disp_api_get_default_display_mode");
goto fail;
}
disp_api_get_global_pa_range =
(int32_t(*)(int64_t, uint32_t, void*))dlsym(mLibHandle, "disp_api_get_global_pa_range");
if (disp_api_get_global_pa_range == NULL) {
ALOGE("dlsym failed for disp_api_get_global_pa_range");
goto fail;
}
disp_api_get_global_pa_config = (int32_t(*)(int64_t, uint32_t, uint32_t*, void*))dlsym(
mLibHandle, "disp_api_get_global_pa_config");
if (disp_api_get_global_pa_config == NULL) {
ALOGE("dlsym failed for disp_api_get_global_pa_config");
goto fail;
}
disp_api_set_global_pa_config = (int32_t(*)(int64_t, uint32_t, uint32_t, void*))dlsym(
mLibHandle, "disp_api_set_global_pa_config");
if (disp_api_set_global_pa_config == NULL) {
ALOGE("dlsym failed for disp_api_set_global_pa_config");
goto fail;
}
disp_api_get_feature_version = (int32_t(*)(int64_t, uint32_t, void*, uint32_t*))dlsym(
mLibHandle, "disp_api_get_feature_version");
if (disp_api_get_feature_version == NULL) {
ALOGE("dlsym failed for disp_api_get_feature_version");
goto fail;
}
return OK;
fail:
ALOGE("Failed to link vendor library: %s", dlerror());
dlclose(mLibHandle);
mLibHandle = NULL;
return NO_INIT;
}
status_t SDM::initialize() {
status_t rc = loadVendorLibrary();
if (rc != OK) {
return rc;
}
rc = disp_api_init(&mHandle, 0);
if (rc != OK) {
return rc;
}
mActiveModeId = -1;
if (hasFeature(Feature::DISPLAY_MODES)) {
rc = saveInitialDisplayMode();
if (rc != OK) {
ALOGE("Failed to save initial display mode! err=%d", rc);
return rc;
}
sp<DisplayMode> defMode = getDefaultDisplayMode();
if (defMode != nullptr) {
setDisplayMode(defMode->id, false);
}
}
return OK;
}
SDM::~SDM() {
if (mLibHandle != NULL) {
dlclose(mLibHandle);
}
}
status_t SDM::deinitialize() {
if (mLibHandle != NULL) {
disp_api_deinit(mHandle, 0);
mHandle = -1;
}
return OK;
}
status_t SDM::setAdaptiveBacklightEnabled(bool enabled) {
status_t rc = NO_INIT;
if (enabled == mCachedFOSSStatus) {
return OK;
}
char* buf = new char[DPPS_BUF_SIZE];
sprintf(buf, "%s", enabled ? FOSS_ON : FOSS_OFF);
if (Utils::sendDPPSCommand(buf, DPPS_BUF_SIZE) == OK) {
if (strncmp(buf, "Success", 7) == 0) {
rc = OK;
mCachedFOSSStatus = enabled;
}
}
delete[] buf;
return rc;
}
bool SDM::isAdaptiveBacklightEnabled() {
return mCachedFOSSStatus;
}
status_t SDM::getColorBalanceRange(Range& range) {
status_t rc = disp_api_get_global_color_balance_range(mHandle, 0, &range);
ALOGV("getColorBalanceRange: min=%d max=%d step=%d", range.min, range.max, range.step);
return rc;
}
status_t SDM::setColorBalance(int32_t balance) {
return disp_api_set_global_color_balance(mHandle, 0, balance, 0);
}
int32_t SDM::getColorBalance() {
int32_t value = -1;
uint32_t flags = 0;
if (disp_api_get_global_color_balance(mHandle, 0, &value, &flags) != 0) {
value = 0;
}
return value;
}
uint32_t SDM::getNumDisplayModes() {
uint32_t flags = 0;
int32_t count = 0;
if (disp_api_get_num_display_modes(mHandle, 0, 0, &count, &flags)) {
count = 0;
}
if (getLocalSRGBMode() != nullptr) {
count++;
}
if (getLocalDCIP3Mode() != nullptr) {
count++;
}
return count;
}
status_t SDM::getDisplayModes(List<sp<DisplayMode>>& profiles) {
status_t rc = OK;
uint32_t flags = 0, i = 0;
uint32_t count = getNumDisplayModes();
if (!count) return rc;
sp<DisplayMode> srgb = getLocalSRGBMode();
sp<DisplayMode> dci_p3 = getLocalDCIP3Mode();
uint32_t sdm_count = count;
if (srgb != nullptr) {
sdm_count--;
}
if (dci_p3 != nullptr) {
sdm_count--;
}
struct sdm_mode {
int32_t id;
int32_t type;
int32_t len;
char* name;
};
sdm_mode* tmp = new sdm_mode[sdm_count];
memset(tmp, 0, sizeof(sdm_mode) * sdm_count);
for (i = 0; i < sdm_count; i++) {
tmp[i].id = -1;
tmp[i].name = new char[128];
tmp[i].len = 128;
}
rc = disp_api_get_display_modes(mHandle, 0, 0, tmp, sdm_count, &flags);
if (rc == 0) {
for (i = 0; i < sdm_count; i++) {
const sp<DisplayMode> m = new DisplayMode(tmp[i].id, tmp[i].name, tmp[i].len);
m->privFlags = PRIV_MODE_FLAG_SDM;
profiles.push_back(m);
delete tmp[i].name;
}
}
delete[] tmp;
if (srgb != nullptr) {
profiles.push_back(srgb);
}
if (dci_p3 != nullptr) {
profiles.push_back(dci_p3);
}
return rc;
}
status_t SDM::setDisplayMode(int32_t modeID, bool makeDefault) {
status_t rc = OK;
if (modeID == mActiveModeId) {
return OK;
}
sp<DisplayMode> mode = getDisplayModeById(modeID);
if (mode == nullptr) {
return BAD_VALUE;
}
ALOGV("setDisplayMode: current mode=%d", mActiveModeId);
if (mActiveModeId >= 0) {
sp<DisplayMode> oldMode = getCurrentDisplayMode();
ALOGV("setDisplayMode: oldMode=%d flags=%d", oldMode->id, oldMode->privFlags);
if (oldMode->privFlags == PRIV_MODE_FLAG_SYSFS ||
mode->privFlags == PRIV_MODE_FLAG_SYSFS) {
ALOGV("disabling old mode");
rc = setModeState(oldMode, false);
if (rc != OK) {
ALOGE("Failed to disable previous mode! err=%d", rc);
return rc;
}
}
}
rc = setModeState(mode, true);
if (rc == OK) {
mActiveModeId = mode->id;
if (makeDefault) {
rc = Utils::writeLocalModeId(mode->id);
if (rc != OK) {
ALOGE("failed to save mode! %d", rc);
return rc;
}
if (mode->privFlags == PRIV_MODE_FLAG_SDM) {
rc = disp_api_set_default_display_mode(mHandle, 0, mode->id, 0);
if (rc != OK) {
ALOGE("failed to save mode! %d", rc);
return rc;
}
}
}
HSIC tmp;
rc = getPictureAdjustment(tmp);
if (rc != OK) {
ALOGE("failed to retrieve picture adjustment after mode setting!");
} else {
ALOGV("new default PA: %d %f %f %f %f", tmp.hue, tmp.saturation,
tmp.intensity, tmp.contrast, tmp.saturationThreshold);
mDefaultPictureAdjustment.setTo(tmp);
}
} else {
ALOGE("Failed to setModeState! err=%d", rc);
return rc;
}
ALOGV("setDisplayMode: %d default: %d flags: %d", modeID, makeDefault, mode->privFlags);
return OK;
}
sp<DisplayMode> SDM::getDisplayModeById(int32_t id) {
List<sp<DisplayMode>> profiles;
status_t rc = getDisplayModes(profiles);
if (rc == OK) {
for (List<sp<DisplayMode>>::iterator it = profiles.begin(); it != profiles.end(); ++it) {
const sp<DisplayMode> mode = *it;
if (id == mode->id) {
return mode;
}
}
}
return nullptr;
}
sp<DisplayMode> SDM::getCurrentDisplayMode() {
return getDisplayModeById(mActiveModeId);
}
sp<DisplayMode> SDM::getDefaultDisplayMode() {
int32_t id = 0;
if (Utils::readLocalModeId(&id) == OK && id >= 0) {
return getDisplayModeById(id);
}
if (Utils::readInitialModeId(&id) == OK && id >= 0) {
return getDisplayModeById(id);
}
return nullptr;
}
status_t SDM::setModeState(sp<DisplayMode> mode, bool state) {
int32_t id = 0;
if (mode->privFlags == PRIV_MODE_FLAG_SYSFS) {
ALOGV("sysfs node: %s state=%d", mode->privData.string(), state);
return Utils::writeInt(mode->privData.string(), state ? 1 : 0);
} else if (mode->privFlags == PRIV_MODE_FLAG_SDM) {
if (state) {
return disp_api_set_active_display_mode(mHandle, 0, mode->id, 0);
} else {
if (Utils::readInitialModeId(&id) == OK) {
ALOGV("set sdm mode to default: id=%d", id);
return disp_api_set_active_display_mode(mHandle, 0, id, 0);
}
}
}
return BAD_VALUE;
}
sp<DisplayMode> SDM::getLocalSRGBMode() {
char path[PATH_MAX];
sprintf(path, "%s", SRGB_NODE);
if (access(path, W_OK) != 0) {
return nullptr;
}
sp<DisplayMode> m = new DisplayMode(SRGB_NODE_ID, "srgb", 4);
m->privFlags = PRIV_MODE_FLAG_SYSFS;
m->privData.setTo(path);
return m;
}
sp<DisplayMode> SDM::getLocalDCIP3Mode() {
char path[PATH_MAX];
sprintf(path, "%s", DCI_P3_NODE);
if (access(path, W_OK) != 0) {
return nullptr;
}
sp<DisplayMode> m = new DisplayMode(DCI_P3_NODE_ID, "dci_p3", 6);
m->privFlags = PRIV_MODE_FLAG_SYSFS;
m->privData.setTo(path);
return m;
}
status_t SDM::getPictureAdjustmentRanges(HSICRanges& ranges) {
hsic_ranges r;
memset(&r, 0, sizeof(struct hsic_ranges));
status_t rc = disp_api_get_global_pa_range(mHandle, 0, &r);
if (rc == OK) {
ranges.hue.min = r.hue.min;
ranges.hue.max = r.hue.max;
ranges.hue.step - r.hue.step;
ranges.saturation.min = r.saturation.min;
ranges.saturation.max = r.saturation.max;
ranges.saturation.step = r.saturation.step;
ranges.intensity.min = r.intensity.min;
ranges.intensity.max = r.intensity.max;
ranges.intensity.step = r.intensity.step;
ranges.contrast.min = r.contrast.min;
ranges.contrast.max = r.contrast.max;
ranges.contrast.step = r.contrast.step;
ranges.saturationThreshold.min = r.saturationThreshold.min;
ranges.saturationThreshold.max = r.saturationThreshold.max;
ranges.saturationThreshold.step = r.saturationThreshold.step;
}
return rc;
}
status_t SDM::getPictureAdjustment(HSIC& hsic) {
uint32_t enable = 0;
hsic_config config;
memset(&config, 0, sizeof(struct hsic_config));
status_t rc = disp_api_get_global_pa_config(mHandle, 0, &enable, &config);
if (rc == OK) {
hsic.hue = config.data.hue;
hsic.saturation = config.data.saturation;
hsic.intensity = config.data.intensity;
hsic.contrast = config.data.contrast;
hsic.saturationThreshold = config.data.saturationThreshold;
}
return rc;
}
status_t SDM::getDefaultPictureAdjustment(HSIC& hsic) {
hsic.setTo(mDefaultPictureAdjustment);
return OK;
}
status_t SDM::setPictureAdjustment(HSIC hsic) {
hsic_config config;
memset(&config, 0, sizeof(struct hsic_config));
config.data.hue = hsic.hue;
config.data.saturation = hsic.saturation;
config.data.intensity = hsic.intensity;
config.data.contrast = hsic.contrast;
config.data.saturationThreshold = hsic.saturationThreshold;
return disp_api_set_global_pa_config(mHandle, 0, 1, &config);
}
bool SDM::hasFeature(Feature feature) {
uint32_t id = 0, flags = 0;
struct version {
uint8_t x, y;
uint16_t z;
};
version v;
switch (feature) {
case Feature::DISPLAY_MODES:
id = 4;
break;
case Feature::COLOR_TEMPERATURE:
id = 3;
break;
case Feature::PICTURE_ADJUSTMENT:
id = 1;
case Feature::ADAPTIVE_BACKLIGHT:
if (property_get_int32("ro.qualcomm.foss", 0) > 0) {
return true;
}
break;
default:
return false;
}
if (disp_api_get_feature_version(mHandle, id, &v, &flags) == 0) {
if (v.x > 0 || v.y > 0 || v.z > 0) {
// Color balance depends on calibration data in SDM
if (feature == Feature::DISPLAY_MODES ||
feature == Feature::COLOR_TEMPERATURE) {
if (getNumDisplayModes() > 0) {
// make sure the range isn't zero
if (feature == Feature::COLOR_TEMPERATURE) {
Range r;
if (getColorBalanceRange(r) == OK && r.isNonZero()) {
return true;
}
return false;
}
return true;
}
} else if (feature == Feature::PICTURE_ADJUSTMENT) {
HSICRanges r;
if (getPictureAdjustmentRanges(r) == OK && r.isValid()) {
return true;
}
}
}
}
return false;
}
status_t SDM::saveInitialDisplayMode() {
int32_t id = 0;
uint32_t flags = 0;
if (Utils::readInitialModeId(&id) != OK || id < 0) {
if (disp_api_get_default_display_mode(mHandle, 0, &id, &flags) == OK && id >= 0) {
return Utils::writeInitialModeId(id);
} else {
return Utils::writeInitialModeId(id = 0);
}
}
return OK;
}
};