Files
Android11_RK3568_Lubancat2/hardware/libhardware/modules/hw_output/hw_output.cpp
2023-05-14 11:44:44 +00:00

1108 lines
39 KiB
C++
Executable File

/*
* Copyright 2014 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 LOG_TAG "hw_output"
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <malloc.h>
#include <stdio.h>
#include <stdint.h>
#include <drm_fourcc.h>
#include <string>
#include <map>
#include <vector>
#include <iostream>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
#include <log/log.h>
#include <hardware/hw_output.h>
#include "baseparameter_api.h"
#include "hw_types.h"
#include "rkdisplay/drmresources.h"
#include "rkdisplay/drmmode.h"
#include "rkdisplay/drmconnector.h"
#include "rkdisplay/drmgamma.h"
#include "rockchip/baseparameter.h"
using namespace android;
#define LOG_LEVEL_ERROR 0
#define LOG_LEVEL_WARN 1
#define LOG_LEVEL_INFO 2
#define LOG_LEVEL_DEBUG 3
static int mHwcVersion = 0;
std::map<int,DrmConnector*> mGlobalConns;
static int dbgLevel = 3;
#define LOG_INFO(format, ...) \
do {\
if (dbgLevel < LOG_LEVEL_INFO)\
break;\
ALOGD("%s[%d]" format, __FUNCTION__, __LINE__, ##_VA_ARGS__); \
} while(0)
/*****************************************************************************/
typedef struct hw_output_private {
hw_output_device_t device;
// Callback related data
void* callback_data;
DrmResources *drm_;
DrmConnector* primary;
DrmConnector* extend;
BaseParameter* mBaseParmeter;
struct lut_info* mlut;
}hw_output_private_t;
static int hw_output_device_open(const struct hw_module_t* module,
const char* name, struct hw_device_t** device);
static struct hw_module_methods_t hw_output_module_methods = {
.open = hw_output_device_open
};
hw_output_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = HW_OUTPUT_HARDWARE_MODULE_ID,
.name = "Sample hw output module",
.author = "The Android Open Source Project",
.methods = &hw_output_module_methods,
.dso = NULL,
.reserved = {0},
}
};
static bool builtInHdmi(int type){
return type == DRM_MODE_CONNECTOR_HDMIA || type == DRM_MODE_CONNECTOR_HDMIB;
}
static void checkBcshInfo(uint32_t* mBcsh)
{
if (mBcsh[0] < 0)
mBcsh[0] = 0;
else if (mBcsh[0] > 100)
mBcsh[0] = 100;
if (mBcsh[1] < 0)
mBcsh[1] = 0;
else if (mBcsh[1] > 100)
mBcsh[1] = 100;
if (mBcsh[2] < 0)
mBcsh[2] = 0;
else if (mBcsh[2] > 100)
mBcsh[2] = 100;
if (mBcsh[3] < 0)
mBcsh[3] = 0;
else if (mBcsh[3] > 100)
mBcsh[3] = 100;
}
static void updateTimeline()
{
std::string strTimeline;
char property[100];
int timeline = property_get_int32("vendor.display.timeline", 1);
timeline++;
strTimeline = std::to_string(timeline);
property_set("vendor.display.timeline", strTimeline.c_str());
property_get("vendor.hw_output.debug", property, "3");
dbgLevel = atoi(property);
}
DrmConnector* getValidDrmConnector(hw_output_private_t *priv, int dpy)
{
std::map<int, DrmConnector*> mConns = mGlobalConns;
std::map<int, DrmConnector*>::iterator iter;
DrmConnector* mConnector = nullptr;
(void)priv;
iter = mConns.find(dpy);
if (iter != mConns.end()) {
mConnector = iter->second;
}
return mConnector;
}
static std::string getPropertySuffix(hw_output_private_t *priv, std::string header, int dpy)
{
DrmConnector* conn = getValidDrmConnector(priv, dpy);
std::string suffix;
suffix = header;
if (mHwcVersion == 2) {
if (conn != nullptr) {
const char* connTypeStr = priv->drm_->connector_type_str(conn->get_type());
int id = conn->connector_id();
suffix += connTypeStr;
suffix += '-';
ALOGD("id=%d", id);
suffix += std::to_string(id);
}
} else {
if (dpy == HWC_DISPLAY_PRIMARY)
suffix += "main";
else
suffix += "aux";
}
ALOGD("suffix=%s", suffix.c_str());
return suffix;
}
static int findSuitableInfoSlot(struct disp_info* info, int type, int id)
{
int found=0;
for (int i=0;i<4;i++) {
if (info->screen_info[i].type !=0 && info->screen_info[i].type == type &&
info->screen_info[i].id == id) {
found = i;
break;
} else if (info->screen_info[i].type !=0 && found == false){
found++;
}
}
if (found == -1) {
found = 0;
ALOGD("noting saved, used the first slot");
}
ALOGD("findSuitableInfoSlot: %d type=%d", found, type);
return found;
}
static bool getResolutionInfo(hw_output_private_t *priv, int dpy, char* resolution)
{
drmModePropertyBlobPtr blob;
drmModeObjectPropertiesPtr props;
DrmConnector* mCurConnector = NULL;
DrmCrtc *crtc = NULL;
struct drm_mode_modeinfo *drm_mode;
struct disp_info info;
BaseParameter* mBaseParmeter = priv->mBaseParmeter;
int value;
bool found = false;
mCurConnector = getValidDrmConnector(priv, dpy);
if (mCurConnector == nullptr) {
sprintf(resolution, "%s", "Auto");
return false;
}
if (mBaseParmeter && mBaseParmeter->have_baseparameter()) {
if (mCurConnector)
mBaseParmeter->get_disp_info(mCurConnector->get_type(), mCurConnector->connector_id(), &info);
int slot = findSuitableInfoSlot(&info, mCurConnector->get_type(), mCurConnector->connector_id());
if (!info.screen_info[slot].resolution.hdisplay ||
!info.screen_info[slot].resolution.clock ||
!info.screen_info[slot].resolution.vdisplay) {
sprintf(resolution, "%s", "Auto");
return false;
}
}
if (mCurConnector != NULL) {
crtc = priv->drm_->GetCrtcFromConnector(mCurConnector);
if (crtc == NULL) {
return false;
}
props = drmModeObjectGetProperties(priv->drm_->fd(), crtc->id(), DRM_MODE_OBJECT_CRTC);
for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
drmModePropertyPtr p = drmModeGetProperty(priv->drm_->fd(), props->props[i]);
if (!strcmp(p->name, "MODE_ID")) {
found = true;
if (!drm_property_type_is(p, DRM_MODE_PROP_BLOB)) {
ALOGE("%s:line=%d,is not blob",__FUNCTION__,__LINE__);
drmModeFreeProperty(p);
drmModeFreeObjectProperties(props);
return false;
}
if (!p->count_blobs)
value = props->prop_values[i];
else
value = p->blob_ids[0];
blob = drmModeGetPropertyBlob(priv->drm_->fd(), value);
if (!blob) {
ALOGE("%s:line=%d, blob is null",__FUNCTION__,__LINE__);
drmModeFreeProperty(p);
drmModeFreeObjectProperties(props);
return false;
}
float vfresh;
drm_mode = (struct drm_mode_modeinfo *)blob->data;
if (drm_mode->flags & DRM_MODE_FLAG_INTERLACE)
vfresh = drm_mode->clock *2/ (float)(drm_mode->vtotal * drm_mode->htotal) * 1000.0f;
else
vfresh = drm_mode->clock / (float)(drm_mode->vtotal * drm_mode->htotal) * 1000.0f;
ALOGD("nativeGetCurMode: crtc_id=%d clock=%d w=%d %d %d %d %d %d flag=0x%x vfresh %.2f drm.vrefresh=%.2f",
crtc->id(), drm_mode->clock, drm_mode->htotal, drm_mode->hsync_start,
drm_mode->hsync_end, drm_mode->vtotal, drm_mode->vsync_start, drm_mode->vsync_end, drm_mode->flags,
vfresh, (float)drm_mode->vrefresh);
sprintf(resolution, "%dx%d@%.2f-%d-%d-%d-%d-%d-%d-%x-%d", drm_mode->hdisplay, drm_mode->vdisplay, vfresh,
drm_mode->hsync_start, drm_mode->hsync_end, drm_mode->htotal,
drm_mode->vsync_start, drm_mode->vsync_end, drm_mode->vtotal,
(drm_mode->flags&0xFFFF), drm_mode->clock);
drmModeFreePropertyBlob(blob);
}
drmModeFreeProperty(p);
}
drmModeFreeObjectProperties(props);
} else {
return false;
}
return true;
}
static void updateConnectors(hw_output_private_t *priv){
if (priv->drm_->connectors().size() == 2) {
bool foundHdmi=false;
int cnt=0,crtcId1=0,crtcId2=0;
for (auto &conn : priv->drm_->connectors()) {
if (cnt == 0 && priv->drm_->GetCrtcFromConnector(conn.get())) {
ALOGD("encoderId1: %d", conn->encoder()->id());
crtcId1 = priv->drm_->GetCrtcFromConnector(conn.get())->id();
} else if (priv->drm_->GetCrtcFromConnector(conn.get())){
ALOGD("encoderId2: %d", conn->encoder()->id());
crtcId2 = priv->drm_->GetCrtcFromConnector(conn.get())->id();
}
if (builtInHdmi(conn->get_type()))
foundHdmi=true;
cnt++;
}
ALOGD("crtc: %d %d foundHdmi %d 2222", crtcId1, crtcId2, foundHdmi);
char property[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.device.primary", property, "null");
if (crtcId1 == crtcId2 && foundHdmi && strstr(property, "HDMI-A") == NULL) {
for (auto &conn : priv->drm_->connectors()) {
if (builtInHdmi(conn->get_type()) && conn->state() == DRM_MODE_CONNECTED) {
priv->extend = conn.get();
conn->set_display(1);
} else if(!builtInHdmi(conn->get_type()) && conn->state() == DRM_MODE_CONNECTED) {
priv->primary = conn.get();
conn->set_display(0);
}
}
}
}
}
/*****************************************************************************/
static void hw_output_save_config(struct hw_output_device* dev){
hw_output_private_t* priv = (hw_output_private_t*)dev;
if (priv->mBaseParmeter)
priv->mBaseParmeter->saveConfig();
}
static void hw_output_hotplug_update(struct hw_output_device* dev){
hw_output_private_t* priv = (hw_output_private_t*)dev;
DrmConnector *mextend = NULL;
DrmConnector *mprimary = NULL;
int dpy = 0;
for (auto &conn : priv->drm_->connectors()) {
drmModeConnection old_state = conn->state();
conn->UpdateModes();
drmModeConnection cur_state = conn->state();
ALOGD("old_state %d cur_state %d conn->get_type() %d", old_state, cur_state, conn->get_type());
if (cur_state == old_state)
continue;
ALOGI("%s event for connector %u\n",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id());
if (cur_state == DRM_MODE_CONNECTED) {
if (conn->possible_displays() & HWC_DISPLAY_EXTERNAL_BIT) {
mextend = conn.get();
} else if (conn->possible_displays() & HWC_DISPLAY_PRIMARY_BIT) {
mprimary = conn.get();
}
}
}
/*
* status changed?
*/
priv->drm_->DisplayChanged();
dpy = mGlobalConns.size();
DrmConnector *old_primary = priv->drm_->GetConnectorFromType(HWC_DISPLAY_PRIMARY);
mprimary = mprimary ? mprimary : old_primary;
if (!mprimary || mprimary->state() != DRM_MODE_CONNECTED) {
mprimary = NULL;
for (auto &conn : priv->drm_->connectors()) {
if (!(conn->possible_displays() & HWC_DISPLAY_PRIMARY_BIT))
continue;
if (conn->state() == DRM_MODE_CONNECTED) {
mprimary = conn.get();
//mGlobalConns[HWC_DISPLAY_PRIMARY] = conn.get();
break;
}
}
}
if (!mprimary) {
ALOGE("%s %d Failed to find primary display\n", __FUNCTION__, __LINE__);
//return;
}
if (mprimary && mprimary != old_primary) {
priv->drm_->SetPrimaryDisplay(mprimary);
}
DrmConnector *old_extend = priv->drm_->GetConnectorFromType(HWC_DISPLAY_EXTERNAL);
mextend = mextend ? mextend : old_extend;
dpy = 1;
if (!mextend || mextend->state() != DRM_MODE_CONNECTED) {
mextend = NULL;
for (auto &conn : priv->drm_->connectors()) {
if (!(conn->possible_displays() & HWC_DISPLAY_EXTERNAL_BIT))
continue;
if (mprimary && conn->id() == mprimary->id())
continue;
if (conn->state() == DRM_MODE_CONNECTED) {
mextend = conn.get();
//mGlobalConns[dpy] = conn.get();
break;
}
}
}
priv->drm_->SetExtendDisplay(mextend);
priv->drm_->DisplayChanged();
priv->drm_->UpdateDisplayRoute();
priv->drm_->ClearDisplay();
updateConnectors(priv);
}
static int hw_output_init_baseparameter(BaseParameter** mBaseParmeter)
{
char property[100];
property_get("vendor.ghwc.version", property, NULL);
if (strstr(property, "HWC2") != NULL) {
*mBaseParmeter = new BaseParameterV2();
mHwcVersion = 2;
} else {
*mBaseParmeter = new BaseParameterV1();
mHwcVersion = 1;
}
return 0;
}
static int hw_output_initialize(struct hw_output_device* dev, void* data)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
priv->drm_ = NULL;
priv->primary = NULL;
priv->extend = NULL;
priv->mlut = NULL;
priv->callback_data = data;
hw_output_init_baseparameter(&priv->mBaseParmeter);
if (priv->drm_ == NULL) {
priv->drm_ = new DrmResources();
priv->drm_->Init();
ALOGD("nativeInit: ");
if (mHwcVersion >= 2) {
int id=0;
for (auto &conn : priv->drm_->connectors())
mGlobalConns.insert(std::make_pair(id++, conn.get()));
} else {
int id=1;
for (auto &conn : priv->drm_->connectors()) {
if (conn->possible_displays() & HWC_DISPLAY_PRIMARY_BIT)
mGlobalConns.insert(std::make_pair(HWC_DISPLAY_PRIMARY, conn.get()));
else
mGlobalConns.insert(std::make_pair(id++, conn.get()));
}
}
priv->mBaseParmeter->set_drm_connectors(mGlobalConns);
hw_output_hotplug_update(dev);
if (priv->primary == NULL) {
for (auto &conn : priv->drm_->connectors()) {
if ((conn->possible_displays() & HWC_DISPLAY_PRIMARY_BIT)) {
//mGlobalConns[HWC_DISPLAY_PRIMARY] = conn.get();
}
if ((conn->possible_displays() & HWC_DISPLAY_EXTERNAL_BIT) && conn->state() == DRM_MODE_CONNECTED) {
priv->drm_->SetExtendDisplay(conn.get());
priv->extend = conn.get();
}
}
}
ALOGD("primary: %p extend: %p ", priv->primary, priv->extend);
}
return 0;
}
/*****************************************************************************/
static int hw_output_set_mode(struct hw_output_device* dev, int dpy, const char* mode)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
DrmConnector* conn = getValidDrmConnector(priv, dpy);
BaseParameter* mBaseParameter = priv->mBaseParmeter;
char property[PROPERTY_VALUE_MAX];
std::string propertyStr;
propertyStr = getPropertySuffix(priv, "persist.vendor.resolution.", dpy);
ALOGD("nativeSetMode %s display %d", mode, dpy);
if (strcmp(mode, property) !=0) {
property_set(propertyStr.c_str(), mode);
updateTimeline();
struct disp_info info;
float vfresh=0.0f;
int slot = 0;
mBaseParameter->get_disp_info(conn->get_type(), conn->connector_id(), &info);
slot = findSuitableInfoSlot(&info, conn->get_type(), conn->connector_id());
info.screen_info[slot].type = conn->get_type();
info.screen_info[slot].id = conn->connector_id();
if (strncmp(mode, "Auto", 4) != 0 && strncmp(mode, "0x0p0-0", 7) !=0) {
sscanf(mode,"%dx%d@%f-%d-%d-%d-%d-%d-%d-%x-%d",
&info.screen_info[slot].resolution.hdisplay, &info.screen_info[slot].resolution.vdisplay,
&vfresh, &info.screen_info[slot].resolution.hsync_start,&info.screen_info[slot].resolution.hsync_end,
&info.screen_info[slot].resolution.htotal,&info.screen_info[slot].resolution.vsync_start,
&info.screen_info[slot].resolution.vsync_end, &info.screen_info[slot].resolution.vtotal,
&info.screen_info[slot].resolution.flags, &info.screen_info[slot].resolution.clock);
info.screen_info[slot].resolution.vrefresh = (int)vfresh;
} else {
info.screen_info[slot].feature|= RESOLUTION_AUTO;
memset(&info.screen_info[slot].resolution, 0, sizeof(info.screen_info[slot].resolution));
}
mBaseParameter->set_disp_info(conn->get_type(), conn->connector_id(), &info);
}
return 0;
}
static int hw_output_set_3d_mode(struct hw_output_device*, const char* mode)
{
char property[PROPERTY_VALUE_MAX];
property_get("vendor.3d_resolution.main", property, "null");
if (strcmp(mode, property) !=0) {
property_set("vendor.3d_resolution.main", mode);
updateTimeline();
}
return 0;
}
static int hw_output_set_gamma(struct hw_output_device* dev, int dpy, uint32_t size, uint16_t* r, uint16_t* g, uint16_t* b)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
BaseParameter* mBaseParameter = priv->mBaseParmeter;
DrmConnector* mConnector = getValidDrmConnector(priv, dpy);
int ret = -1;
int crtc_id = 0;
if (mConnector)
crtc_id = priv->drm_->GetCrtcFromConnector(mConnector)->id();
ret = DrmGamma::set_3x1d_gamma(priv->drm_->fd(), crtc_id, size, r, g, b);
if (ret < 0)
ALOGE("fail to SetGamma %d(%s)", ret, strerror(errno));
if(ret == 0){
struct gamma_lut_data data;
data.size = size;
for(int i = 0; i< size; i++){
data.lred[i] = r[i];
data.lgreen[i] = g[i];
data.lblue[i] = b[i];
}
mBaseParameter->set_gamma_lut_data(mConnector->get_type(), mConnector->connector_id(), &data);
}
return ret;
}
static int hw_output_set_3d_lut(struct hw_output_device* dev, int dpy, uint32_t size, uint16_t* r, uint16_t* g, uint16_t* b)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
BaseParameter* mBaseParameter = priv->mBaseParmeter;
DrmConnector* mConnector = getValidDrmConnector(priv, dpy);
int ret = -1;
int crtc_id = 0;
if (mConnector)
crtc_id = priv->drm_->GetCrtcFromConnector(mConnector)->id();
ret = DrmGamma::set_cubic_lut(priv->drm_->fd(), crtc_id, size, r, g, b);
if (ret < 0)
ALOGE("fail to set 3d lut %d(%s)", ret, strerror(errno));
if(ret == 0){
struct cubic_lut_data data;
for(int i = 0; i< size; i++){
data.lred[i] = r[i];
data.lgreen[i] = g[i];
data.lblue[i] = b[i];
}
mBaseParameter->set_cubic_lut_data(mConnector->get_type(), mConnector->connector_id(), &data);
}
return ret;
}
static int hw_output_set_brightness(struct hw_output_device* dev, int dpy, int brightness)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
BaseParameter* mBaseParameter = priv->mBaseParmeter;
DrmConnector* conn = getValidDrmConnector(priv, dpy);
char property[PROPERTY_VALUE_MAX];
char tmp[128];
std::string propertyStr;
propertyStr = getPropertySuffix(priv, "persist.vendor.brightness.", dpy);
sprintf(tmp, "%d", brightness);
property_get(propertyStr.c_str(), property, "50");
if (atoi(property) != brightness) {
property_set(propertyStr.c_str(), tmp);
updateTimeline();
mBaseParameter->set_brightness(conn->get_type(), conn->connector_id(), brightness);
}
return 0;
}
static int hw_output_set_contrast(struct hw_output_device* dev, int dpy, int contrast)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
BaseParameter* mBaseParameter = priv->mBaseParmeter;
DrmConnector* conn = getValidDrmConnector(priv, dpy);
char property[PROPERTY_VALUE_MAX];
char tmp[128];
std::string propertyStr;
sprintf(tmp, "%d", contrast);
propertyStr = getPropertySuffix(priv, "persist.vendor.contrast.", dpy);
property_get(propertyStr.c_str(), property, "50");
if (atoi(property) != contrast) {
property_set(propertyStr.c_str(), tmp);
updateTimeline();
mBaseParameter->set_contrast(conn->get_type(), conn->connector_id(), contrast);
}
return 0;
}
static int hw_output_set_sat(struct hw_output_device* dev, int dpy, int sat)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
BaseParameter* mBaseParameter = priv->mBaseParmeter;
DrmConnector* conn = getValidDrmConnector(priv, dpy);
char property[PROPERTY_VALUE_MAX];
char tmp[128];
std::string propertyStr;
sprintf(tmp, "%d", sat);
propertyStr = getPropertySuffix(priv, "persist.vendor.saturation.", dpy);
property_get(propertyStr.c_str(), property, "50");
if (atoi(property) != sat) {
property_set(propertyStr.c_str(), tmp);
updateTimeline();
mBaseParameter->set_saturation(conn->get_type(), conn->connector_id(), sat);
}
return 0;
}
static int hw_output_set_hue(struct hw_output_device* dev, int dpy, int hue)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
BaseParameter* mBaseParameter = priv->mBaseParmeter;
DrmConnector* conn = getValidDrmConnector(priv, dpy);
char property[PROPERTY_VALUE_MAX];
char tmp[128];
std::string propertyStr;
sprintf(tmp, "%d", hue);
propertyStr = getPropertySuffix(priv, "persist.vendor.hue.", dpy);
property_get(propertyStr.c_str(), property, "50");
if (atoi(property) != hue) {
property_set(propertyStr.c_str(), tmp);
updateTimeline();
mBaseParameter->set_hue(conn->get_type(), conn->connector_id(), hue);
}
return 0;
}
static int hw_output_set_screen_scale(struct hw_output_device* dev, int dpy, int direction, int value)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
BaseParameter* mBaseParameter = priv->mBaseParmeter;
DrmConnector* conn = getValidDrmConnector(priv, dpy);
std::string propertyStr;
char property[PROPERTY_VALUE_MAX];
char overscan[128];
int left,top,right,bottom;
propertyStr = getPropertySuffix(priv, "persist.vendor.overscan.", dpy);
property_get(propertyStr.c_str(), property, "overscan 100,100,100,100");
sscanf(property, "overscan %d,%d,%d,%d", &left, &top, &right, &bottom);
if (direction == OVERSCAN_LEFT)
left = value;
else if (direction == OVERSCAN_TOP)
top = value;
else if (direction == OVERSCAN_RIGHT)
right = value;
else if (direction == OVERSCAN_BOTTOM)
bottom = value;
sprintf(overscan, "overscan %d,%d,%d,%d", left, top, right, bottom);
if (strcmp(property, overscan) != 0) {
property_set(propertyStr.c_str(), overscan);
updateTimeline();
struct overscan_info overscan;
overscan.maxvalue = 100;
overscan.leftscale = left;
overscan.topscale = top;
overscan.rightscale = right;
overscan.bottomscale = bottom;
mBaseParameter->set_overscan_info(conn->get_type(), conn->id(), &overscan);
}
return 0;
}
static int hw_output_set_hdr_mode(struct hw_output_device* dev, int dpy, int hdr_mode)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
std::string propertyStr, hdrStr;
char property[PROPERTY_VALUE_MAX];
char tmp[128];
sprintf(tmp, "%d", hdr_mode);
propertyStr = getPropertySuffix(priv, "persist.vendor.hdr_mode.", dpy);
property_get(propertyStr.c_str(), property, "50");
if (atoi(property) != hdr_mode) {
property_set(propertyStr.c_str(), tmp);
updateTimeline();
}
return 0;
}
static int hw_output_set_color_mode(struct hw_output_device* dev, int dpy, const char* color_mode)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
BaseParameter* mBaseParameter = priv->mBaseParmeter;
DrmConnector* conn = getValidDrmConnector(priv, dpy);
std::string propertyStr;
struct disp_info info;
char property[PROPERTY_VALUE_MAX];
propertyStr = getPropertySuffix(priv, "persist.vendor.color.", dpy);
property_get(propertyStr.c_str(), property, NULL);
ALOGD("hw_output_set_color_mode %s display %d property=%s", color_mode, dpy, property);
if (strcmp(color_mode, property) !=0) {
property_set(propertyStr.c_str(), color_mode);
property_get(propertyStr.c_str(), property, NULL);
updateTimeline();
}
if (conn) {
mBaseParameter->get_disp_info(conn->get_type(), conn->connector_id(), &info);
int slot = findSuitableInfoSlot(&info, conn->get_type(), conn->connector_id());
if (strncmp(property, "Auto", 4) != 0){
if (strstr(property, "RGB") != 0)
info.screen_info[slot].format = output_rgb;
else if (strstr(property, "YCBCR444") != 0)
info.screen_info[slot].format = output_ycbcr444;
else if (strstr(property, "YCBCR422") != 0)
info.screen_info[slot].format = output_ycbcr422;
else if (strstr(property, "YCBCR420") != 0)
info.screen_info[slot].format = output_ycbcr420;
else {
info.screen_info[slot].feature |= COLOR_AUTO;
info.screen_info[slot].format = output_ycbcr_high_subsampling;
}
if (strstr(property, "8bit") != NULL)
info.screen_info[slot].depthc = depth_24bit;
else if (strstr(property, "10bit") != NULL)
info.screen_info[slot].depthc = depth_30bit;
else
info.screen_info[slot].depthc = Automatic;
} else {
info.screen_info[slot].depthc = Automatic;
info.screen_info[slot].format = output_ycbcr_high_subsampling;
info.screen_info[slot].feature |= COLOR_AUTO;
}
ALOGD("saveConfig: color=%d-%d", info.screen_info[slot].format, info.screen_info[slot].depthc);
mBaseParameter->set_disp_info(conn->get_type(), conn->connector_id(), &info);
}
return 0;
}
static int hw_output_get_cur_mode(struct hw_output_device* dev, int dpy, char* curMode)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
bool found=false;
if (curMode != NULL)
found = getResolutionInfo(priv, dpy, curMode);
else
return -1;
if (!found) {
sprintf(curMode, "%s", "Auto");
}
return 0;
}
static int hw_output_get_cur_color_mode(struct hw_output_device* dev, int dpy, char* curColorMode)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
DrmConnector* mCurConnector = getValidDrmConnector(priv, dpy);
BaseParameter* mBaseParmeter = priv->mBaseParmeter;
struct disp_info dispInfo;
std::string propertyStr;
char colorMode[PROPERTY_VALUE_MAX];
int len=0;
propertyStr = getPropertySuffix(priv, "persist.vendor.color.", dpy);
len = property_get(propertyStr.c_str(), colorMode, NULL);
ALOGD("nativeGetCurCorlorMode: property=%s", colorMode);
if (!len && mBaseParmeter && mBaseParmeter->have_baseparameter()) {
mBaseParmeter->get_disp_info(mCurConnector->get_type(), mCurConnector->connector_id(), &dispInfo);
int slot = findSuitableInfoSlot(&dispInfo, mCurConnector->get_type(), mCurConnector->connector_id());
if (dispInfo.screen_info[slot].depthc == Automatic &&
dispInfo.screen_info[slot].format == output_ycbcr_high_subsampling)
sprintf(colorMode, "%s", "Auto");
}
sprintf(curColorMode, "%s", colorMode);
ALOGD("nativeGetCurCorlorMode: colorMode=%s", colorMode);
return 0;
}
static int hw_output_get_num_connectors(struct hw_output_device* dev, int, int* numConnectors)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
(void)priv;
*numConnectors = mGlobalConns.size();//priv->drm_->connectors().size();
return 0;
}
static int hw_output_get_connector_state(struct hw_output_device* dev, int dpy, int* state)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
int ret = 0;
DrmConnector* mConn = getValidDrmConnector(priv, dpy);
if (mConn != nullptr) {
*state = mConn->state();
} else {
ret = -1;
}
return ret;
}
static int hw_output_get_color_configs(struct hw_output_device* dev, int dpy, int* configs)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
DrmConnector* mCurConnector = getValidDrmConnector(priv, dpy);;
uint64_t color_capacity=0;
uint64_t depth_capacity=0;
if (mCurConnector != NULL) {
if (mCurConnector->hdmi_output_mode_capacity_property().id())
mCurConnector->hdmi_output_mode_capacity_property().value( &color_capacity);
if (mCurConnector->hdmi_output_depth_capacity_property().id())
mCurConnector->hdmi_output_depth_capacity_property().value(&depth_capacity);
configs[0] = (int)color_capacity;
configs[1] = (int)depth_capacity;
ALOGD("nativeGetCorlorModeConfigs: corlor=%d depth=%d configs:%d %d",(int)color_capacity,(int)depth_capacity, configs[0], configs[1]);
}
return 0;
}
static int hw_output_get_overscan(struct hw_output_device* dev, int dpy, uint32_t* overscans)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
char property[PROPERTY_VALUE_MAX];
std::string propertyStr;
int left,top,right,bottom;
propertyStr = getPropertySuffix(priv, "persist.vendor.overscan.", dpy);
property_get(propertyStr.c_str(), property, "overscan 100,100,100,100");
sscanf(property, "overscan %d,%d,%d,%d", &left, &top, &right, &bottom);
overscans[0] = left;
overscans[1] = top;
overscans[2] = right;
overscans[3] = bottom;
return 0;
}
static int hw_output_get_bcsh(struct hw_output_device* dev, int dpy, uint32_t* bcshs)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
BaseParameter* mBaseParmeter = priv->mBaseParmeter;
DrmConnector* conn = getValidDrmConnector(priv, dpy);
char mBcshProperty[PROPERTY_VALUE_MAX];
std::string propertyStr;
propertyStr = getPropertySuffix(priv, "persist.vendor.brightness.", dpy);
if (property_get(propertyStr.c_str(), mBcshProperty, NULL) > 0) {
bcshs[0] = atoi(mBcshProperty);
} else if (mBaseParmeter&&mBaseParmeter->have_baseparameter()) {
bcshs[0] = mBaseParmeter->get_brightness(conn->get_type(), conn->connector_id());
} else {
bcshs[0] = DEFAULT_BRIGHTNESS;
}
memset(mBcshProperty, 0, sizeof(mBcshProperty));
propertyStr = getPropertySuffix(priv, "persist.vendor.contrast.", dpy);
if (property_get(propertyStr.c_str(), mBcshProperty, NULL) > 0) {
bcshs[1] = atoi(mBcshProperty);
} else if (mBaseParmeter&&mBaseParmeter->have_baseparameter()) {
bcshs[1] = mBaseParmeter->get_contrast(conn->get_type(), conn->connector_id());
} else {
bcshs[1] = DEFAULT_CONTRAST;
}
memset(mBcshProperty, 0, sizeof(mBcshProperty));
propertyStr = getPropertySuffix(priv, "persist.vendor.saturation.", dpy);
if (property_get(propertyStr.c_str(), mBcshProperty, NULL) > 0) {
bcshs[2] = atoi(mBcshProperty);
} else if (mBaseParmeter&&mBaseParmeter->have_baseparameter()) {
bcshs[2] = mBaseParmeter->get_contrast(conn->get_type(), conn->connector_id());
} else {
bcshs[2] = DEFAULT_SATURATION;
}
memset(mBcshProperty, 0, sizeof(mBcshProperty));
propertyStr = getPropertySuffix(priv, "persist.vendor.hue.", dpy);
if (property_get(propertyStr.c_str(), mBcshProperty, NULL) > 0) {
bcshs[3] = atoi(mBcshProperty);
} else if (mBaseParmeter&&mBaseParmeter->have_baseparameter()) {
bcshs[3] = mBaseParmeter->get_hue(conn->get_type(), conn->connector_id());
} else {
bcshs[3] = DEFAULT_SATURATION;
}
checkBcshInfo(bcshs);
ALOGD("Bcsh: %d %d %d %d ", bcshs[0], bcshs[1], bcshs[2], bcshs[3]);
return 0;
}
static int hw_output_get_builtin(struct hw_output_device* dev, int dpy, int* builtin)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
DrmConnector* mConnector = getValidDrmConnector(priv, dpy);
if (mConnector) {
*builtin = mConnector->get_type();
} else {
*builtin = 0;
}
return 0;
}
static drm_mode_t* hw_output_get_display_modes(struct hw_output_device* dev, int dpy, uint32_t* size)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
std::vector<DrmMode> mModes;
DrmConnector* mCurConnector;
drm_mode_t* drm_modes = NULL;
int idx=0;
*size = 0;
mCurConnector = getValidDrmConnector(priv, dpy);
if (mCurConnector) {
mModes = mCurConnector->modes();
} else {
return NULL;
}
if (mModes.size() == 0)
return NULL;
drm_modes = (drm_mode_t*)malloc(sizeof(drm_mode_t) * mModes.size());
for (size_t c = 0; c < mModes.size(); ++c) {
const DrmMode& info = mModes[c];
float vfresh;
if (info.flags() & DRM_MODE_FLAG_INTERLACE)
vfresh = info.clock()*2 / (float)(info.v_total()* info.h_total()) * 1000.0f;
else
vfresh = info.clock()/ (float)(info.v_total()* info.h_total()) * 1000.0f;
drm_modes[c].width = info.h_display();
drm_modes[c].height = info.v_display();
drm_modes[c].refreshRate = vfresh;
drm_modes[c].clock = info.clock();
drm_modes[c].flags = info.flags();
drm_modes[c].interlaceFlag = info.flags()&(1<<4);
drm_modes[c].yuvFlag = (info.flags()&(1<<24) || info.flags()&(1<<23));
drm_modes[c].connectorId = mCurConnector->id();
drm_modes[c].mode_type = info.type();
drm_modes[c].idx = idx;
drm_modes[c].hsync_start = info.h_sync_start();
drm_modes[c].hsync_end = info.h_sync_end();
drm_modes[c].htotal = info.h_total();
drm_modes[c].hskew = info.h_skew();
drm_modes[c].vsync_start = info.v_sync_start();
drm_modes[c].vsync_end = info.v_sync_end();
drm_modes[c].vtotal = info.v_total();
drm_modes[c].vscan = info.v_scan();
idx++;
ALOGV("display%d mode[%d] %dx%d fps %f clk %d h_start %d h_enc %d htotal %d hskew %d",
dpy,(int)c, info.h_display(), info.v_display(), info.v_refresh(),
info.clock(), info.h_sync_start(),info.h_sync_end(),
info.h_total(), info.h_skew());
ALOGV("vsync_start %d vsync_end %d vtotal %d vscan %d flags 0x%x",
info.v_sync_start(), info.v_sync_end(), info.v_total(), info.v_scan(),
info.flags());
}
*size = idx;
return drm_modes;
}
/*****************************************************************************/
static int hw_output_device_close(struct hw_device_t *dev)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
if (priv->mBaseParmeter) {
delete priv->mBaseParmeter;
}
if (priv) {
free(priv);
}
return 0;
}
static connector_info_t* hw_output_get_connector_info(struct hw_output_device* dev, uint32_t* size)
{
hw_output_private_t* priv = (hw_output_private_t*)dev;
*size = 0;
connector_info_t* connector_info = NULL;
connector_info = (connector_info_t*)malloc(sizeof(connector_info_t) * priv->drm_->connectors().size());
int i = 0;
for (auto &conn : mGlobalConns) {
DrmConnector* mConn = conn.second;
connector_info[i].type = mConn->get_type();
connector_info[i].id = (uint32_t)mConn->connector_id();
connector_info[i].state = (uint32_t)mConn->state();
i++;
}
*size = i;
ALOGE("%s:%d i=%d", __FUNCTION__, __LINE__, i);
return connector_info;
}
static int hw_output_update_disp_header(struct hw_output_device *dev)
{
bool found = false;
int ret = 0, firstEmptyHeader = -1;
hw_output_private_t* priv = (hw_output_private_t*)dev;
BaseParameter* mBaseParmeter = priv->mBaseParmeter;
struct disp_header * headers = (disp_header *)malloc(sizeof(disp_header) * 8);
for (auto &conn : priv->drm_->connectors()) {
if(conn->state() == DRM_MODE_CONNECTED){
found = false;
firstEmptyHeader = -1;
mBaseParmeter->get_all_disp_header(headers);
for(int i = 0; i < 8; i++){
if(headers[i].connector_type == conn->get_type() && headers[i].connector_id == conn->connector_id()){
found = true;
}
if(firstEmptyHeader == -1 && headers[i].connector_type == 0 && headers[i].connector_id == 0){
firstEmptyHeader = i;
}
}
if(!found){
ret = mBaseParmeter->set_disp_header(firstEmptyHeader, conn->get_type(), conn->connector_id());
}
}
}
free(headers);
return ret;
}
static int hw_output_device_open(const struct hw_module_t* module,
const char* name, struct hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, HW_OUTPUT_DEFAULT_DEVICE)) {
hw_output_private_t* dev = (hw_output_private_t*)malloc(sizeof(*dev));
/* initialize our state here */
//memset(dev, 0, sizeof(*dev));
/* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = HW_OUTPUT_DEVICE_API_VERSION_0_1;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = hw_output_device_close;
dev->device.initialize = hw_output_initialize;
dev->device.setMode = hw_output_set_mode;
dev->device.set3DMode = hw_output_set_3d_mode;
dev->device.setBrightness = hw_output_set_brightness;
dev->device.setContrast = hw_output_set_contrast;
dev->device.setSat = hw_output_set_sat;
dev->device.setHue = hw_output_set_hue;
dev->device.setColorMode = hw_output_set_color_mode;
dev->device.setHdrMode = hw_output_set_hdr_mode;
dev->device.setGamma = hw_output_set_gamma;
dev->device.setScreenScale = hw_output_set_screen_scale;
dev->device.getCurColorMode = hw_output_get_cur_color_mode;
dev->device.getBcsh = hw_output_get_bcsh;
dev->device.getBuiltIn = hw_output_get_builtin;
dev->device.getColorConfigs = hw_output_get_color_configs;
dev->device.getConnectorState = hw_output_get_connector_state;
dev->device.getCurMode = hw_output_get_cur_mode;
dev->device.getDisplayModes = hw_output_get_display_modes;
dev->device.getNumConnectors = hw_output_get_num_connectors;
dev->device.getOverscan = hw_output_get_overscan;
dev->device.hotplug = hw_output_hotplug_update;
dev->device.saveConfig = hw_output_save_config;
dev->device.set3DLut = hw_output_set_3d_lut;
dev->device.getConnectorInfo = hw_output_get_connector_info;
dev->device.updateDispHeader = hw_output_update_disp_header;
*device = &dev->device.common;
status = 0;
}
return status;
}