android13/hardware/rockchip/tv_input/sideband/DrmVopRender.cpp

1010 lines
36 KiB
C++
Executable File

#include <fcntl.h>
#include <errno.h>
#include "DrmVopRender.h"
#include "log/log.h"
#include <unistd.h>
#include <sys/mman.h>
#include <cutils/properties.h>
#include "common/TvInput_Buffer_Manager.h"
#include "common/Utils.h"
#define HAS_ATOMIC 1
#define PROPERTY_TYPE "vendor"
#ifdef LOG_TAG
#undef LOG_TAG
#define LOG_TAG "tv_input_VopRender"
#endif
namespace android {
#define ALIGN_DOWN( value, base) (value & (~(base-1)) )
#define ALIGN(x, a) (((x) + (a)-1) & ~((a)-1))
DrmVopRender::DrmVopRender()
: mDrmFd(0),
mSidebandPlaneId(0)
{
memset(&mOutputs, 0, sizeof(mOutputs));
ALOGE("DrmVopRender");
}
DrmVopRender::~DrmVopRender()
{
// WARN_IF_NOT_DEINIT();
ALOGE("DrmVopRender delete ");
}
DrmVopRender* DrmVopRender::GetInstance() {
static DrmVopRender instance;
return &instance;
}
bool DrmVopRender::initialize()
{
Mutex::Autolock autoLock(mVopPlaneLock);
ALOGE("initialize in");
/*if (mInitialized) {
ALOGE(">>Drm object has been initialized");
return true;
}*/
const char *path = "/dev/dri/card0";
mDrmFd = open(path, O_RDWR);
if (mDrmFd < 0) {
ALOGD("failed to open Drm, error: %s", strerror(errno));
return false;
}
ALOGE("mDrmFd = %d", mDrmFd);
for (const auto &fbidMap : mFbidMap) {
int fbid = fbidMap.second;
ALOGE("%s find last fbid=%d", __FUNCTION__, fbid);
if (drmModeRmFB(mDrmFd, fbid))
ALOGE("Failed to rm fb %d", fbid);
}
mFbidMap.clear();
memset(&mOutputs, 0, sizeof(mOutputs));
mInitialized = true;
int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
(const hw_module_t **)&gralloc_);
if (ret) {
ALOGE("Failed to open gralloc module");
return ret;
} else {
ALOGD("open gralloc module successful !");
}
return true;
}
void DrmVopRender::deinitialize()
{
ALOGE("deinitialize in");
if(!mInitialized) return;
Mutex::Autolock autoLock(mVopPlaneLock);
for (int i = 0; i < OUTPUT_MAX; i++) {
resetOutput(i);
}
if (mDrmFd) {
close(mDrmFd);
mDrmFd = 0;
}
for (const auto &fbidMap : mFbidMap) {
int fbid = fbidMap.second;
if (drmModeRmFB(mDrmFd, fbid))
ALOGE("Failed to rm fb");
}
mInitialized = false;
}
void DrmVopRender::DestoryFB() {
Mutex::Autolock autoLock(mVopPlaneLock);
for (const auto &fbidMap : mFbidMap) {
int fbid = fbidMap.second;
ALOGV("%s fbid=%d", __FUNCTION__, fbid);
if (drmModeRmFB(mDrmFd, fbid))
ALOGE("Failed to rm fb");
}
mFbidMap.clear();
}
bool DrmVopRender::detect() {
Mutex::Autolock autoLock(mVopPlaneLock);
detect(HWC_DISPLAY_PRIMARY);
mEnableSkipFrame = false;
return true;
}
bool DrmVopRender::detect(int device)
{
if (!mInitialized) {
return false;
}
ALOGE("detect device=%d", device);
int outputIndex = getOutputIndex(device);
if (outputIndex < 0 ) {
return false;
}
char prop_name[PROPERTY_VALUE_MAX] = {0};
char prop_value[PROPERTY_VALUE_MAX] = {0};
for (int i=0; i< MAX_DISPLAY_NUM; i++) {
sprintf(prop_name, "vendor.hwc.device.display-%d", i);
property_get(prop_name, prop_value, "0:0:0");
ALOGE("%s=%s", prop_name, prop_value);
/*if (strcmp(prop_value, "0") == 0) {
break;
}*/
bool connected = strstr(prop_value, ":connected");
if (mDisplayInfos.empty() || i > mDisplayInfos.size()-1) {
DisplayInfo info;
memset(&info, 0, sizeof(info));
info.display_id = i;
info.connected = connected;
if (mEnableOverScan) {
char *saveptr;
int num_tokens = 0;
char* token = strtok_r(prop_value, ":", &saveptr);
while (token != NULL){
if (num_tokens == 0) {
strcpy(info.connector_name, token);
} else if (num_tokens == 1) {
info.crtc_id = (int)atoi(token);
}
num_tokens++;
token = strtok_r(NULL, ":", &saveptr);
}
saveptr = NULL;
}
ALOGE("=====push display info %d %d %s=====", i, info.crtc_id, info.connector_name);
mDisplayInfos.push_back(info);
} else {
mDisplayInfos[i].connected = connected;
if (mEnableOverScan && mDisplayInfos[i].crtc_id == 0 && strcmp(prop_value, "0:0:0") != 0) {
char *saveptr;
int num_tokens = 0;
char* token = strtok_r(prop_value, ":", &saveptr);
while (token != NULL) {
if (num_tokens == 0) {
strcpy(mDisplayInfos[i].connector_name, token);
} else if (num_tokens == 1) {
mDisplayInfos[i].crtc_id = (int)atoi(token);
}
num_tokens++;
token = strtok_r(NULL, ":", &saveptr);
}
saveptr = NULL;
ALOGE("=====update display info %d %d %s=====", i, mDisplayInfos[i].crtc_id, mDisplayInfos[i].connector_name);
}
}
}
resetOutput(outputIndex);
drmModeConnectorPtr connector = NULL;
DrmOutput *output = &mOutputs[outputIndex];
bool ret = false;
// get drm resources
drmModeResPtr resources = drmModeGetResources(mDrmFd);
if (!resources) {
ALOGE("fail to get drm resources, error: %s", strerror(errno));
return false;
}
ret = drmSetClientCap(mDrmFd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
if (ret) {
ALOGE("Failed to set atomic cap %s", strerror(errno));
return ret;
}
ret = drmSetClientCap(mDrmFd, DRM_CLIENT_CAP_ATOMIC, 1);
if (ret) {
ALOGE("Failed to set atomic cap %s", strerror(errno));
return ret;
}
output->res = resources;
ALOGD("resources->count_connectors=%d",resources->count_connectors);
// find connector for the given device
for (int i = 0; i < resources->count_connectors; i++) {
if (!resources->connectors || !resources->connectors[i]) {
ALOGE("fail to get drm resources connectors, error: %s", strerror(errno));
continue;
}
nsecs_t startTime = systemTime();
connector = drmModeGetConnector(mDrmFd, resources->connectors[i]);
long usedTime = (long)((systemTime() - startTime)/1000000);
if (usedTime > 2000) {
ALOGD("%s ===========timeout===========%ld", __FUNCTION__, usedTime);
}
if (!connector) {
ALOGE("drmModeGetConnector failed");
continue;
}
if (connector->connection != DRM_MODE_CONNECTED) {
ALOGE("+++device %d is not connected", device);
if (i == resources->count_connectors -1) {
drmModeFreeConnector(connector);
ret = true;
break;
}
continue;
}
DrmModeInfo drmModeInfo;
memset(&drmModeInfo, 0, sizeof(drmModeInfo));
drmModeInfo.connector = connector;
output->connected = true;
ALOGD("connector %d connected",outputIndex);
// get proper encoder for the given connector
if (connector->encoder_id) {
ALOGD("Drm connector has encoder attached on device %d", device);
drmModeInfo.encoder = drmModeGetEncoder(mDrmFd, connector->encoder_id);
if (!drmModeInfo.encoder) {
ALOGD("failed to get encoder from a known encoder id");
// fall through to get an encoder
}
}
if (!drmModeInfo.encoder) {
ALOGD("getting encoder for device %d", device);
drmModeEncoderPtr encoder;
for (int j = 0; j < resources->count_encoders; j++) {
if (!resources->encoders || !resources->encoders[j]) {
ALOGE("fail to get drm resources encoders, error: %s", strerror(errno));
continue;
}
encoder = drmModeGetEncoder(mDrmFd, resources->encoders[i]);
if (!encoder) {
ALOGE("drmModeGetEncoder failed");
continue;
}
ALOGD("++++encoder_type=%d,device=%d",encoder->encoder_type,getDrmEncoder(device));
if (encoder->encoder_type == getDrmEncoder(device)) {
drmModeInfo.encoder = encoder;
break;
}
drmModeFreeEncoder(encoder);
encoder = NULL;
}
}
if (!drmModeInfo.encoder) {
ALOGE("failed to get drm encoder");
break;
}
// get an attached crtc or spare crtc
if (drmModeInfo.encoder->crtc_id) {
ALOGD("Drm encoder has crtc attached on device %d", device);
drmModeInfo.crtc = drmModeGetCrtc(mDrmFd, drmModeInfo.encoder->crtc_id);
if (!drmModeInfo.crtc) {
ALOGE("failed to get crtc from a known crtc id");
// fall through to get a spare crtc
}
}
if (!drmModeInfo.crtc) {
ALOGE("getting crtc for device %d %d", device, i);
drmModeCrtcPtr crtc;
for (int j = 0; j < resources->count_crtcs; j++) {
if (!resources->crtcs || !resources->crtcs[j]) {
ALOGE("fail to get drm resources crtcs, error: %s", strerror(errno));
continue;
}
crtc = drmModeGetCrtc(mDrmFd, resources->crtcs[j]);
if (!crtc) {
ALOGE("drmModeGetCrtc failed");
continue;
}
// check if legal crtc to the encoder
if (drmModeInfo.encoder->possible_crtcs & (1<<j)) {
drmModeInfo.crtc = crtc;
}
drmModeObjectPropertiesPtr props;
drmModePropertyPtr prop;
props = drmModeObjectGetProperties(mDrmFd, crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
if (!props) {
ALOGD("Failed to found props crtc[%d] %s\n",
crtc->crtc_id, strerror(errno));
continue;
}
for (uint32_t i = 0; i < props->count_props; i++) {
prop = drmModeGetProperty(mDrmFd, props->props[i]);
if (!strcmp(prop->name, "ACTIVE")) {
ALOGD("Crtc id=%d is ACTIVE.", crtc->crtc_id);
if (props->prop_values[i]) {
drmModeInfo.crtc = crtc;
ALOGD("Crtc id=%d is active",crtc->crtc_id);
break;
}
}
}
}
}
if (!drmModeInfo.crtc) {
ALOGE("failed to get drm crtc");
break;
} else {
drmModeObjectPropertiesPtr props;
drmModePropertyPtr prop;
props = drmModeObjectGetProperties(mDrmFd, drmModeInfo.crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
if (props) {
for (uint32_t i = 0; i < props->count_props; i++) {
prop = drmModeGetProperty(mDrmFd, props->props[i]);
if (!strcmp(prop->name, "PLANE_MASK")) {
uint64_t plane_mask_value = props->prop_values[i];
//ALOGD("PLANE_MASK=%d", (int)plane_mask_value);
for (i = 0; i < prop->count_enums; i++) {
uint64_t enums_value = 1LL << prop->enums[i].value;
if ((plane_mask_value & enums_value) == enums_value) {
strcpy(drmModeInfo.crtc_plane_mask+strlen(drmModeInfo.crtc_plane_mask), prop->enums[i].name);
}
}
}
drmModeFreeProperty(prop);
}
drmModeFreeObjectProperties(props);
}
}
output->plane_res = drmModeGetPlaneResources(mDrmFd);
ALOGD("drmModeGetPlaneResources successful. index=%d", i);
output->mDrmModeInfos.push_back(drmModeInfo);
//break;
}
if (output->mDrmModeInfos.empty()) {
ALOGD("final mDrmModeInfos is empty");
for (int i = 0; i < mDisplayInfos.size(); i++) {
ALOGE("empty drmmodeinfo force set connected false");
mDisplayInfos[i].connected = false;
}
} else {
int last_crtc_id = -1;
int total_crtc_id_num = 0;
for (int i=0; i<output->mDrmModeInfos.size(); i++) {
if (output->mDrmModeInfos[i].crtc) {
int crtc_id = output->mDrmModeInfos[i].crtc->crtc_id;
total_crtc_id_num++;
ALOGD("final crtc->crtc_id %d %s", crtc_id, output->mDrmModeInfos[i].crtc_plane_mask);
nsecs_t startTime = systemTime();
output->mDrmModeInfos[i].props = drmModeObjectGetProperties(mDrmFd, output->mDrmModeInfos[i].crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
long usedTime = (long)((systemTime() - startTime)/1000000);
if (usedTime > 2000) {
ALOGD("%s ===========timeout===========%ld", __FUNCTION__, usedTime);
}
if (!output->mDrmModeInfos[i].props) {
ALOGE("Failed to found props crtc[%d] %s\n", output->mDrmModeInfos[i].crtc->crtc_id, strerror(errno));
}
if (last_crtc_id == crtc_id) {
ALOGE("same crtc_id need reconnect");
for (int j =0; j < mDisplayInfos.size(); j++) {
mDisplayInfos[j].connected = false;
}
} else {
last_crtc_id = crtc_id;
for (int j = 0; j < mDisplayInfos.size(); j++) {
if (crtc_id == mDisplayInfos[j].crtc_id) {
strcpy(output->mDrmModeInfos[i].connector_name, mDisplayInfos[j].connector_name);
ALOGE("index=%d, %d %s", i, crtc_id, output->mDrmModeInfos[i].connector_name);
}
}
}
}
}
for (int j = 0; j < mDisplayInfos.size(); j++) {
if (mDisplayInfos[j].connected) {
if (total_crtc_id_num > 0) {
total_crtc_id_num--;
} else {
ALOGE("find not crtcid display");
mDisplayInfos[j].connected = false;
}
}
}
}
drmModeFreeResources(resources);
return ret;
}
uint32_t DrmVopRender::getDrmEncoder(int device)
{
if (device == HWC_DISPLAY_PRIMARY)
return 2;
else if (device == HWC_DISPLAY_EXTERNAL)
return DRM_MODE_ENCODER_TMDS;
return DRM_MODE_ENCODER_NONE;
}
uint32_t DrmVopRender::ConvertHalFormatToDrm(uint32_t hal_format) {
switch (hal_format) {
case HAL_PIXEL_FORMAT_BGR_888:
return DRM_FORMAT_RGB888;
case HAL_PIXEL_FORMAT_RGB_888:
return DRM_FORMAT_BGR888;
case HAL_PIXEL_FORMAT_BGRA_8888:
return DRM_FORMAT_ARGB8888;
case HAL_PIXEL_FORMAT_RGBX_8888:
return DRM_FORMAT_XBGR8888;
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
return DRM_FORMAT_ABGR8888;
//Fix color error in NenaMark2.
case HAL_PIXEL_FORMAT_RGB_565:
return DRM_FORMAT_RGB565;
case HAL_PIXEL_FORMAT_YV12:
return DRM_FORMAT_YVU420;
case HAL_PIXEL_FORMAT_YCrCb_NV12:
return DRM_FORMAT_NV12;
case HAL_PIXEL_FORMAT_YCrCb_NV12_10:
return DRM_FORMAT_NV15;
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
return DRM_FORMAT_NV16;
case HAL_PIXEL_FORMAT_YCbCr_444_888:
return DRM_FORMAT_NV24;
default:
ALOGE("Cannot convert hal format to drm format %u", hal_format);
return -EINVAL;
}
}
int DrmVopRender::FindSidebandPlane(int device) {
Mutex::Autolock autoLock(mVopPlaneLock);
drmModePlanePtr plane;
drmModeObjectPropertiesPtr props;
drmModePropertyPtr prop;
int find_plan_id = 0;
int outputIndex = getOutputIndex(device);
if (outputIndex < 0 ) {
ALOGE("invalid device");
return false;
}
DrmOutput *output= &mOutputs[outputIndex];
if (!output->connected) {
ALOGE("device is not connected,outputIndex=%d",outputIndex);
return false;
}
//ALOGD("output->plane_res->count_planes %d", output->plane_res->count_planes);
if (output->plane_res == NULL) {
ALOGE("%s output->plane_res is NULL", __FUNCTION__);
return false;
}
int plandIdCount = 0;
if (!output->mDrmModeInfos.empty()) {
for (int i=0; i<output->mDrmModeInfos.size(); i++) {
output->mDrmModeInfos[i].plane_id = -1;
plandIdCount++;
}
}
if (mDebugLevel == 3) {
ALOGE("start to find ASYNC_COMMIT output->plane_res->count_planes=%d", output->plane_res->count_planes);
}
for(uint32_t i = 0; i < output->plane_res->count_planes; i++) {
if (plandIdCount == 0) {
break;
}
plane = drmModeGetPlane(mDrmFd, output->plane_res->planes[i]);
props = drmModeObjectGetProperties(mDrmFd, plane->plane_id, DRM_MODE_OBJECT_PLANE);
if (!props) {
ALOGE("Failed to found props plane[%d] %s\n",plane->plane_id, strerror(errno));
return -ENODEV;
}
int plane_id;
for (uint32_t j = 0; j < props->count_props; j++) {
prop = drmModeGetProperty(mDrmFd, props->props[j]);
if (!strcmp(prop->name, "ASYNC_COMMIT")) {
if (mDebugLevel == 3) {
ALOGE("find ASYNC_COMMIT plane id=%d value=%lld====%d-%d", plane->plane_id, (long long)props->prop_values[j], i, j);
}
if (props->prop_values[j] != 0) {
plane_id = plane->plane_id;
}
} else if (plane_id > 0 && !strcmp(prop->name, "NAME")) {
if (prop->count_enums > 0) {
char* win_name = strstr(prop->enums[0].name, "-");
if (win_name && !output->mDrmModeInfos.empty()) {
char plane_name[10] = {""};
strncpy(plane_name, prop->enums[0].name, strlen(prop->enums[0].name)-strlen(win_name));
for (int k=0; k<output->mDrmModeInfos.size(); k++) {
ALOGV("crtc_plane_mask=%s plane_name=%s", output->mDrmModeInfos[k].crtc_plane_mask, plane_name);
if (strstr(output->mDrmModeInfos[k].crtc_plane_mask, plane_name)) {
output->mDrmModeInfos[k].plane_id = plane_id;
ALOGV("set plan_id=%d crtc_id=%d to pos=%d", plane_id, output->mDrmModeInfos[k].crtc->crtc_id, k);
find_plan_id = plane_id;
plandIdCount--;
break;
}
}
}
}
if (prop) {
drmModeFreeProperty(prop);
}
break;
}
if (prop)
drmModeFreeProperty(prop);
}
if(props)
drmModeFreeObjectProperties(props);
if(plane)
drmModeFreePlane(plane);
}
return find_plan_id;
}
int DrmVopRender::getFbLength(buffer_handle_t handle) {
if (!handle) {
ALOGE("%s buffer_handle_t is NULL.", __FUNCTION__);
return -1;
} else {
ALOGE("%s %p", __FUNCTION__, handle);
}
common::TvInputBufferManager* tvBufferMgr = common::TvInputBufferManager::GetInstance();
return tvBufferMgr->GetHandleBufferSize(handle);
}
int DrmVopRender::getFbid(buffer_handle_t handle, int hdmiInType) {
Mutex::Autolock autoLock(mVopPlaneLock);
if (!handle) {
ALOGE("%s buffer_handle_t is NULL.", __FUNCTION__);
return -1;
}
common::TvInputBufferManager* tvBufferMgr = common::TvInputBufferManager::GetInstance();
hwc_drm_bo_t bo;
int fd = 0;
int ret = 0;
int src_w = 0;
int src_h = 0;
int src_format = 0;
int src_stride = 0;
fd = (int)tvBufferMgr->GetHandleFd(handle);
std::map<int, int>::iterator it = mFbidMap.find(fd);
int fbid = 0;
if (it == mFbidMap.end()) {
memset(&bo, 0, sizeof(hwc_drm_bo_t));
uint32_t gem_handle;
size_t plane_size;
fd = (int)tvBufferMgr->GetHandleFd(handle);
ret = drmPrimeFDToHandle(mDrmFd, fd, &gem_handle);
src_w = tvBufferMgr->GetWidth(handle);
src_h = tvBufferMgr->GetHeight(handle);
src_format = tvBufferMgr->GetHalPixelFormat(handle);
plane_size = tvBufferMgr->GetNumPlanes(handle);
ALOGV("format=%d, plane_size = %zu", src_format, plane_size);
if (hdmiInType == HDMIIN_TYPE_MIPICSI) {
if (src_format == HAL_PIXEL_FORMAT_BGR_888) {
src_stride = src_w * 3;
} else if (src_format != HAL_PIXEL_FORMAT_YCrCb_NV12_10) {
src_stride = src_w;
} else {
src_stride = (int)tvBufferMgr->GetPlaneStride(handle, 0);
}
} else {
src_stride = (int)tvBufferMgr->GetPlaneStride(handle, 0);
}
//gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_GET_HADNLE_WIDTH, handle, &src_w);
//gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_GET_HADNLE_HEIGHT, handle, &src_h);
//gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_GET_HADNLE_FORMAT, handle, &src_format);
//gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_GET_HADNLE_BYTE_STRIDE, handle, &src_stride);
bo.width = src_w;
bo.height = src_h;
//bo.format = ConvertHalFormatToDrm(HAL_PIXEL_FORMAT_YCrCb_NV12);
bo.format = ConvertHalFormatToDrm(src_format);
if (src_format == HAL_PIXEL_FORMAT_YCrCb_NV12_10) {
bo.pitches[0] = ALIGN(src_stride / 4 * 5, 64);
} else {
bo.pitches[0] = src_stride;
}
bo.gem_handles[0] = gem_handle;
bo.offsets[0] = 0;
if(src_format == HAL_PIXEL_FORMAT_YCrCb_NV12
|| src_format == HAL_PIXEL_FORMAT_YCrCb_NV12_10
|| src_format == HAL_PIXEL_FORMAT_YCbCr_422_SP)
{
bo.pitches[1] = bo.pitches[0];
bo.gem_handles[1] = gem_handle;
bo.offsets[1] = bo.pitches[1] * bo.height;
} else if (src_format == HAL_PIXEL_FORMAT_YCbCr_444_888) {
if (src_w == src_stride) {
bo.pitches[1] = bo.pitches[0] * 2;
} else {
bo.pitches[1] = ALIGN(src_w * 2, 64);
}
bo.gem_handles[1] = gem_handle;
bo.offsets[1] = bo.pitches[0] * bo.height;
}
//if (src_format == HAL_PIXEL_FORMAT_YCrCb_NV12_10) {
// bo.width = src_w / 1.25;
// bo.width = ALIGN_DOWN(bo.width, 2);
//}
ALOGD("width=%d,height=%d,format=%x,fd=%d,src_stride=%d, pitched=%d-%d",
bo.width, bo.height, bo.format, fd, src_stride, bo.pitches[0], bo.pitches[1]);
ret = drmModeAddFB2(mDrmFd, bo.width, bo.height, bo.format, bo.gem_handles,\
bo.pitches, bo.offsets, &bo.fb_id, 0);
fbid = bo.fb_id;
ALOGD("drmModeAddFB2 ret = %s fbid=%d", strerror(ret), fbid);
mFbidMap.insert(std::make_pair(fd, fbid));
} else {
fbid = it->second;
}
if (fbid <= 0) {
ALOGD("fbid is error.");
return -1;
}
return fbid;
}
void DrmVopRender::resetOutput(int index)
{
ALOGE("resetOutput index=%d", index);
DrmOutput *output = &mOutputs[index];
output->connected = false;
memset(&output->mode, 0, sizeof(drmModeModeInfo));
if (!output->mDrmModeInfos.empty()) {
for (int i=0; i<output->mDrmModeInfos.size(); i++) {
if (output->mDrmModeInfos[i].connector) {
drmModeFreeConnector(output->mDrmModeInfos[i].connector);
output->mDrmModeInfos[i].connector = 0;
}
if (output->mDrmModeInfos[i].encoder) {
drmModeFreeEncoder(output->mDrmModeInfos[i].encoder);
output->mDrmModeInfos[i].encoder = 0;
}
if (output->mDrmModeInfos[i].crtc) {
drmModeFreeCrtc(output->mDrmModeInfos[i].crtc);
output->mDrmModeInfos[i].crtc = 0;
}
}
output->mDrmModeInfos.clear();
}
if (output->fbId) {
drmModeRmFB(mDrmFd, output->fbId);
output->fbId = 0;
}
if (output->fbHandle) {
output->fbHandle = 0;
}
}
bool DrmVopRender::needRedetect() {
char prop_name[PROPERTY_VALUE_MAX] = {0};
char prop_value[PROPERTY_VALUE_MAX] = {0};
for (int i=0; i<mDisplayInfos.size(); i++) {
sprintf(prop_name, "vendor.hwc.device.display-%d", i);
property_get(prop_name, prop_value, "0");
if (strstr(prop_value, ":connected")) {
if(!mDisplayInfos[i].connected) {
return true;
}
} else {
if(mDisplayInfos[i].connected) {
return true;
}
}
}
return false;
}
void DrmVopRender::setDebugLevel(int debugLevel) {
if (mDebugLevel != debugLevel) {
mDebugLevel = debugLevel;
}
}
bool DrmVopRender::SetDrmPlane(int device, int32_t width, int32_t height,
buffer_handle_t handle, int displayRatio, int hdmiInType) {
if (mDebugLevel == 3) {
ALOGE("%s come in, device=%d, handle=%p", __FUNCTION__, device, handle);
}
if (mEnableSkipFrame) {
nsecs_t now = systemTime();
if (now - mSkipFrameStartTime < SKIP_FRAME_TIME) {
if (mDebugLevel == 3) {
ALOGE("%s come in, skip frame", __FUNCTION__);
}
return false;
}
mEnableSkipFrame = false;
}
if (needRedetect() && mInitialized) {
ALOGE("=================needRedetect===================");
DestoryFB();
ClearDrmPlaneContent(device, 0, 0);
detect(HWC_DISPLAY_PRIMARY);
mSkipFrameStartTime = systemTime();
mEnableSkipFrame = true;
return false;
}
int ret = 0;
int find_plan_id = FindSidebandPlane(device);
mSidebandPlaneId = find_plan_id;
bool findAvailedPlane = find_plan_id > 0;
int fb_id = findAvailedPlane?getFbid(handle, hdmiInType):-1;
int flags = 0;
int src_left = 0;
int src_top = 0;
int src_right = 0;
int src_bottom = 0;
int dst_left = 0;
int dst_top = 0;
int dst_right = 0;
int dst_bottom = 0;
int src_w = 0;
int src_h = 0;
int dst_w = 0;
int dst_h = 0;
char sideband_crop[PROPERTY_VALUE_MAX];
memset(sideband_crop, 0, sizeof(sideband_crop));
DrmOutput *output= &mOutputs[device];
int length = 0;//property_get("vendor.hwc.sideband.crop", sideband_crop, NULL);
if (length > 0) {
sscanf(sideband_crop, "%d-%d-%d-%d-%d-%d-%d-%d",\
&src_left, &src_top, &src_right, &src_bottom,\
&dst_left, &dst_top, &dst_right, &dst_bottom);
dst_w = dst_right - dst_left;
dst_h = dst_bottom - dst_top;
/*} else {
dst_w = output->crtc->width;
dst_h = output->crtc->height;*/
}
src_w = width;
src_h = height;
if (!mInitialized || !findAvailedPlane || fb_id < 0) {
if (mDebugLevel == 3) {
ALOGE("%s come in %d, %d, %d", __FUNCTION__, mInitialized, findAvailedPlane, fb_id);
}
return false;
}
//gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_GET_HADNLE_FORMAT, handle, &src_format);
//ALOGV("dst_w %d dst_h %d src_w %d src_h %d in", dst_w, dst_h, src_w, src_h);
//ALOGV("mDrmFd=%d plane_id=%d, output->crtc->crtc_id=%d fb_id=%d flags=%d", mDrmFd, plane_id, output->crtc->crtc_id, fb_id, flags);
if (!output->mDrmModeInfos.empty()) {
for (int i=0; i<output->mDrmModeInfos.size(); i++) {
DrmModeInfo_t drmModeInfo = output->mDrmModeInfos[i];
int plane_id = drmModeInfo.plane_id;
if (plane_id > 0) {
int overscan[] = {100, 100, 100, 100};
if (mEnableOverScan) {
int connector_name_len = strlen(drmModeInfo.connector_name);
if (connector_name_len > 0) {
char overscan_prop[PROPERTY_VALUE_MAX] = {0};
char overscan_name[PROPERTY_VALUE_MAX] = {0};
std::string temp1(drmModeInfo.connector_name, connector_name_len - 1);
std::string temp2(1, drmModeInfo.connector_name[connector_name_len - 1]);
sprintf(overscan_name, "%s%s%d", TV_INPUT_OVERSCAN_PREF, temp1.c_str(), atoi(temp2.c_str()) - 1);
property_get(overscan_name, overscan_prop, "0");
if (strcmp(overscan_prop, "0") != 0) {
const char split[] = ",";
char* res = strtok(overscan_prop + 8, split);
int overscan_index = 0;
while (res != NULL) {
overscan[overscan_index++] = (int)atoi(res);
res = strtok(NULL, split);
}
}
}
}
dst_w = drmModeInfo.crtc->width;
dst_h = drmModeInfo.crtc->height;
int ratio_w = dst_w;
int ratio_h = dst_h;
if (displayRatio == SCREEN_16_9) {
ratio_h = dst_w * 9 /16;
} else if (displayRatio == SCREEN_4_3) {
ratio_h = dst_w * 3 /4;
}
if (dst_h < ratio_h) {
ratio_h = dst_h;
if (displayRatio == SCREEN_16_9) {
ratio_w = dst_h * 16 /9;
} else if (displayRatio == SCREEN_4_3) {
ratio_w = dst_h * 4 /3;
}
}
if (dst_w < ratio_w) {
ratio_w = dst_w;
}
int offset_l = 0;
int offset_t = 0;
int offset_r = 0;
int offset_b = 0;
if (mEnableOverScan) {
offset_l = dst_w * (100 - overscan[0]) / 200;
offset_t = dst_h * (100 - overscan[1]) / 200;
offset_r = dst_w * (100 - overscan[2]) / 200;
offset_b = dst_h * (100 - overscan[3]) / 200;
}
int32_t crtc_x = dst_left + (dst_w - ratio_w) / 2 + offset_l;
int32_t crtc_y = dst_top + (dst_h - ratio_h) / 2 + offset_t;
uint32_t crtc_w = ALIGN_DOWN(ratio_w - offset_l - offset_r, 2);
uint32_t crtc_h = ALIGN_DOWN(ratio_h - offset_t - offset_b, 2);
ret = drmModeSetPlane(mDrmFd, plane_id,
drmModeInfo.crtc->crtc_id, fb_id, flags,
crtc_x, crtc_y, crtc_w, crtc_h,
0, 0,
src_w << 16, src_h << 16);
if (mDebugLevel == 3) {
ALOGE("drmModeSetPlane ret=%s mDrmFd=%d plane_id=%d, crtc_id=%d, fb_id=%d, flags=%d, %d %d, %d %d %d %d",
strerror(ret), mDrmFd, plane_id, drmModeInfo.crtc->crtc_id, fb_id, flags, dst_w, dst_h, crtc_x, crtc_y, crtc_w, crtc_h);
}
}
}
}
ALOGV("%s end.", __FUNCTION__);
return true;
}
bool DrmVopRender::ClearDrmPlaneContent(int device, int32_t width, int32_t height)
{
Mutex::Autolock autoLock(mVopPlaneLock);
ALOGD("%s come in, device=%d", __FUNCTION__, device);
bool ret = true;
int plane_id = 0;//FindSidebandPlane(device);
// drmModeAtomicReqPtr reqPtr = drmModeAtomicAlloc();
DrmOutput *output= &mOutputs[device];
drmModePlanePtr plane;
drmModeObjectPropertiesPtr props;
drmModePropertyPtr prop;
//props = drmModeObjectGetProperties(mDrmFd, output->crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
if (output->plane_res == NULL) {
ALOGE("%s output->plane_res is NULL", __FUNCTION__);
prop = NULL;
return -1;
}
for(uint32_t i = 0; i < output->plane_res->count_planes; i++) {
plane = drmModeGetPlane(mDrmFd, output->plane_res->planes[i]);
props = drmModeObjectGetProperties(mDrmFd, plane->plane_id, DRM_MODE_OBJECT_PLANE);
if (!props) {
ALOGE("Failed to found props plane[%d] %s\n",plane->plane_id, strerror(errno));
return -ENODEV;
}
for (uint32_t j = 0; j < props->count_props; j++) {
prop = drmModeGetProperty(mDrmFd, props->props[j]);
if (!strcmp(prop->name, "ASYNC_COMMIT")) {
if (props->prop_values[j] != 0) {
plane_id = plane->plane_id;
// ret = drmModeAtomicAddProperty(reqPtr, plane_id, prop->prop_id, 0) < 0;
ret = drmModeObjectSetProperty(mDrmFd, plane_id, 0, prop->prop_id, 0) < 0;
if (ret) {
ALOGE("drmModeObjectSetProperty failed");
drmModeFreeProperty(prop);
// drmModeAtomicFree(reqPtr);
return false;
} else {
ALOGD("drmModeObjectSetProperty successful.");
}
break;
}
}
if (prop)
drmModeFreeProperty(prop);
}
if(props)
drmModeFreeObjectProperties(props);
if(plane)
drmModeFreePlane(plane);
}
prop = NULL;
/*
for (uint32_t i = 0; i < props->count_props; i++) {
prop = drmModeGetProperty(mDrmFd, props->props[i]);
ALOGD("%s prop->name=%s", __FUNCTION__, prop->name);
if (!strcmp(prop->name, "CRTC_ID")) {
// ret = drmModeAtomicAddProperty(reqPtr, plane_id, prop->prop_id, 0) < 0;
ret = drmModeObjectSetProperty(mDrmFd, plane_id, 0, prop->prop_id, 0) < 0;
if (ret) {
ALOGE("drmModeAtomicAddProperty failed");
drmModeFreeProperty(prop);
// drmModeAtomicFree(reqPtr);
return false;
}
}
if (!strcmp(prop->name, "FB_ID")) {
// ret = drmModeAtomicAddProperty(reqPtr, plane_id, prop->prop_id, 0) < 0;
ret = drmModeObjectSetProperty(mDrmFd, plane_id, 0, prop->prop_id, 0) < 0;
if (ret) {
ALOGE("drmModeAtomicAddProperty failed");
drmModeFreeProperty(prop);
// drmModeAtomicFree(reqPtr);
return false;
}
}
}
drmModeFreeProperty(prop);
drmModeAtomicFree(reqPtr);
prop = NULL;
*/
/*int ret = 0;
int plane_id = FindSidebandPlane(device);
int flags = 0;
int src_left = 0;
int src_top = 0;
int src_right = 0;
int src_bottom = 0;
int dst_left = 0;
int dst_top = 0;
int dst_right = 0;
int dst_bottom = 0;
int src_w = 0;
int src_h = 0;
int dst_w = 0;
int dst_h = 0;
char sideband_crop[PROPERTY_VALUE_MAX];
memset(sideband_crop, 0, sizeof(sideband_crop));
DrmOutput *output= &mOutputs[device];
int length = property_get("vendor.hwc.sideband.crop", sideband_crop, NULL);
if (length > 0) {
sscanf(sideband_crop, "%d-%d-%d-%d-%d-%d-%d-%d",\
&src_left, &src_top, &src_right, &src_bottom,\
&dst_left, &dst_top, &dst_right, &dst_bottom);
dst_w = dst_right - dst_left;
dst_h = dst_bottom - dst_top;
} else {
dst_w = output->crtc->width;
dst_h = output->crtc->height;
}
src_w = width;
src_h = height;
if (plane_id > 0) {
ret = drmModeSetPlane(mDrmFd, plane_id,
0, 0, flags,
dst_left, dst_top,
dst_w, dst_h,
0, 0,
src_w << 16, src_h << 16);
ALOGV("drmModeSetPlane ret=%s", strerror(ret));
}*/
return ret;
}
int DrmVopRender::getOutputIndex(int device)
{
switch (device) {
case HWC_DISPLAY_PRIMARY:
return OUTPUT_PRIMARY;
case HWC_DISPLAY_EXTERNAL:
return OUTPUT_EXTERNAL;
default:
ALOGD("invalid display device");
break;
}
return -1;
}
int DrmVopRender::getSidebandPlaneId() {
return mSidebandPlaneId;
}
} // namespace android