You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

509 lines
18 KiB

/*
* Copyright (c) Hisilicon Technologies Co., Ltd.. 2019-2020. All rights reserved.
* Description: overlay create win/queue buffer by VO
* Author: Original Media Software Group
* Create: 2019-07-15
*/
#include "dft/HwgraphicsDft.h"
#include "UnifiedWindowImpl.h"
#include <cinttypes>
#include <log/log.h>
#include <cutils/properties.h>
#include <utils/KeyedVector.h>
#include <utils/Timers.h>
#include <sys/mman.h>
#include <cutils/properties.h>
#include <android/data_space.h>
#include <queue>
/* for MPI temp */
#include "mpi_win_ext.h"
#include "drv_video_ext.h"
#include "drv_color_ext.h"
/* for UAPI */
#include "uapi_video.h"
using namespace android;
using namespace dft;
static std::queue<WindowManager*> destroyedWindow;
static uapi_disp ConvertDisplayID(int displayID)
{
ALOGD("IN %s:%d displayID:%d", __func__, __LINE__, displayID);
char value[PROPERTY_VALUE_MAX];
if ((property_get("persist.vendor.display.master", value, nullptr) != 0) &&
(strcasecmp("1", value) == 0)) {
ALOGD("primary disp is disp1");
switch (displayID) {
case HWC_DISPLAY_PRIMARY:
return UAPI_DISPLAY1;
case HWC_DISPLAY_EXTERNAL:
return UAPI_DISPLAY0;
default:
ALOGE("Unkown display ID, just return PRIMARY");
return UAPI_DISPLAY1;
}
} else {
switch (displayID) {
case HWC_DISPLAY_PRIMARY:
return UAPI_DISPLAY0;
case HWC_DISPLAY_EXTERNAL:
return UAPI_DISPLAY1;
default:
ALOGE("Unkown display ID, just return PRIMARY");
return UAPI_DISPLAY0;
}
}
}
static td_s32 DestroyWindowInternal(WindowManager &winLocal)
{
ALOGV("IN %s window 0x%x", __func__, winLocal.window);
if (winLocal.window == 0) {
ALOGE("window has been destroyed");
return TD_SUCCESS;
}
ALOGD("DestroyWindow window 0x%x", winLocal.window);
nsecs_t timeStampDestroyWin = systemTime(SYSTEM_TIME_MONOTONIC);
pthread_mutex_lock(&winLocal.mutex);
int ret = uapi_win_set_enable(winLocal.window, TD_FALSE);
if (ret != TD_SUCCESS) {
pthread_mutex_unlock(&winLocal.mutex);
ALOGE("disable window failed, ret:0x%x", ret);
return ret;
}
ret = uapi_win_destroy(winLocal.window);
if (ret != TD_SUCCESS) {
pthread_mutex_unlock(&winLocal.mutex);
ALOGE("destroy window failed,ret:0x%x", ret);
return ret;
}
winLocal.window = 0;
winLocal.sequence = -1;
pthread_mutex_unlock(&winLocal.mutex);
ALOGD("%s OUT cost:%" PRId64 "", __func__, systemTime(SYSTEM_TIME_MONOTONIC) - timeStampDestroyWin);
return TD_SUCCESS;
}
static td_s32 UnifiedRMEventCB(td_void *client, uapi_rm_event event, td_u32 eventPara)
{
TD_UNUSED(eventPara);
WindowManager* winLocal = static_cast<WindowManager *>(client);
ALOGI("RMEventCB IN,enEvent:%d", event);
if (!winLocal) {
ALOGE("RMEventCB pWin is null");
return TD_FAILURE;
}
switch (event) {
case UAPI_RM_EVENT_WIN_LACK: {
pthread_mutex_lock(&winLocal->mutex);
pthread_mutex_lock(&winLocal->rmMutex);
bool isValidWindow = static_cast<bool>(winLocal->window) && winLocal->rmState == RmState::RM_NOT_DESTROY;
if (!isValidWindow) {
ALOGE("RMEventCB pWin window is null or destroyed");
pthread_mutex_unlock(&winLocal->rmMutex);
pthread_mutex_unlock(&winLocal->mutex);
return TD_FAILURE;
}
winLocal->rmState = RmState::RM_DESTROYING;
pthread_mutex_unlock(&winLocal->rmMutex);
pthread_mutex_unlock(&winLocal->mutex);
return DestroyWindowInternal(*winLocal);
}
case UAPI_RM_EVENT_WIN_DESTROYED: {
pthread_mutex_lock(&winLocal->rmMutex);
switch (winLocal->rmState) {
case RmState::RM_DESTROYING:
winLocal->rmState = RmState::RM_DESTROYED;
/* clear rm state if other vo window was destroed */
destroyedWindow.emplace(winLocal);
ALOGI("switch rm state from RM_DESTROYING to RM_DESTROYED");
break;
case RmState::RM_DESTROYED:
ALOGI("switch rm state from RM_DESTROYED to RM_NOT_DESTROY");
winLocal->rmState = RmState::RM_NOT_DESTROY;
break;
default:
ALOGE("Ignore RM Win destroyed event when in wrong state:%d", winLocal->rmState);
}
pthread_mutex_unlock(&winLocal->rmMutex);
break;
}
default:
ALOGE("RMEventCB receive not registered event:%d", event);
}
ALOGI("RMEventCB END");
return TD_SUCCESS;
}
static void OverlayCheckPrint(void* dest, int destsz, int ch, int count, std::string printstr)
{
errno_t retValue = memset_s(dest, destsz, ch, count);
if (retValue != EOK) {
ALOGE("[%s:%d] %s failed:0x%x\n", __FUNCTION__, __LINE__, printstr.c_str(), retValue);
}
}
void UnifiedWindowImpl::UnRegistRmcCallback(WindowManager& winManager)
{
if (winManager.isRmRegister) {
int ret = uapi_rm_unregister_callback(&winManager, UnifiedRMEventCB);
if (ret != TD_SUCCESS) {
ALOGE("UAPI_RM_UnRegisterCallback failed:0x%x", ret);
} else {
pthread_mutex_lock(&winManager.rmMutex);
winManager.isRmRegister = false;
pthread_mutex_unlock(&winManager.rmMutex);
ALOGI("UAPI_RM_UnRegisterCallback SUCCESS");
}
}
}
void UnifiedWindowImpl::ClearWindowCallback()
{
while (!destroyedWindow.empty()) {
WindowManager* winManager = destroyedWindow.front();
UnRegistRmcCallback(*winManager);
destroyedWindow.pop();
}
}
int UnifiedWindowImpl::CreateWindow(const LayerInfo &info)
{
nsecs_t timeStampCreateWin = systemTime(SYSTEM_TIME_MONOTONIC);
if (!IsNeededToCreatWindow(info)) {
return TD_SUCCESS;
}
ALOGD("begin CreateWindow");
destroyedWindow.emplace(&winManager);
ClearWindowCallback();
td_s32 ret = uapi_win_init();
if (ret != TD_SUCCESS) {
ALOGE("init window failed, ret:0x%x", ret);
return ret;
}
uapi_win_attr winAttr;
OverlayCheckPrint(&winAttr, sizeof(winAttr), 0, sizeof(winAttr), "memset_s");
winAttr.disp_id = ConvertDisplayID(info.displayId);
winAttr.is_virtual = TD_FALSE;
winAttr.asp_convert_mode = UAPI_WIN_ASPECT_CONVERT_FULL;
OverlayCheckPrint(&winAttr.video_rect, sizeof(uapi_video_rect), 0x0, sizeof(uapi_video_rect), "memset_s");
ret = uapi_win_create(&winAttr, &winManager.window);
FaultInfo mFaultInfo = {"uapi_win_create", "disp_id", winAttr.disp_id};
HwgraphicsDft::GetInstance()->ReportFaultIfNecessary(ret != TD_SUCCESS, OVERLAYPLAY_FAIL, mFaultInfo);
if (ret != TD_SUCCESS) {
ALOGE("create window failed, ret:0x%x", ret);
return ret;
}
(void)SetWindowQuickOutput(info);
ret = uapi_win_set_enable(winManager.window, TD_TRUE);
if (ret != TD_SUCCESS) {
ALOGE("enable window failed, ret:0x%x", ret);
return ret;
}
winManager.sequence = info.sequence;
pthread_mutex_init(&winManager.rmMutex, nullptr);
pthread_mutex_init(&winManager.mutex, nullptr);
int registResult = RegistRMCallback();
if (registResult != TD_SUCCESS) {
DestroyWindow();
ALOGE("Register rm callback failed, destroy the created window!!!");
return TD_FAILURE;
}
OverlayCheckPrint(&lastPosition, sizeof(lastPosition), 0, sizeof(OverlayRect), "memset_s");
OverlayCheckPrint(&lastSourceCrop, sizeof(lastSourceCrop), 0, sizeof(OverlayRect), "memset_s");
ALOGD("Create window:0x%x, cost:%" PRId64 "",\
winManager.window, systemTime(SYSTEM_TIME_MONOTONIC) - timeStampCreateWin);
return TD_SUCCESS;
}
int UnifiedWindowImpl::SetWindowPosition(const OverlayRect &displayFrame)
{
if (static_cast<bool>(RectIsEqual(lastPosition, displayFrame))) {
return TD_SUCCESS;
}
uapi_video_rect videoRect;
OverlayCheckPrint(&videoRect, sizeof(videoRect), 0, sizeof(videoRect), "memset_s");
int ret = uapi_win_get_outrect(winManager.window, &videoRect);
if (ret != TD_SUCCESS) {
ALOGE("uapi_win_get_outrect 0x%x failed,ret:0x%x", winManager.window, ret);
return ret;
}
ALOGD("get videoRect,x:%d, y:%d, w:%d,h:%d", videoRect.x, videoRect.y,
videoRect.width, videoRect.height);
int width = displayFrame.right - displayFrame.left;
int height = displayFrame.bottom - displayFrame.top;
ALOGD("window position, x:%d, y:%d, w:%d, h:%d", displayFrame.left, displayFrame.top,
width, height);
if (width < MIN_WINDOW_WIDTH || height < MIN_WINDOW_HEIGHT) {
ALOGE("check position failed, videoRect [%d, %d] is smaller than [%d, %d]",
width, height, MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT);
return TD_FAILURE;
}
uapi_video_rect setRect = {displayFrame.left, displayFrame.top, static_cast<td_u32>(width),
static_cast<td_u32>(height)};
ret = uapi_win_set_outrect(&winManager.window, &setRect, 1);
FaultInfo mFaultInfo = {"uapi_win_set_outrect"};
HwgraphicsDft::GetInstance()->ReportFaultIfNecessary(ret != TD_SUCCESS, OVERLAYPLAY_FAIL, mFaultInfo);
if (ret != TD_SUCCESS) {
ALOGE("set window 0x%x attr failed,ret:%d", winManager.window, ret);
return ret;
}
lastPosition = displayFrame;
return TD_SUCCESS;
}
int UnifiedWindowImpl::SetWindowCrop(const OverlayRect &sourceCrop)
{
if (static_cast<bool>(RectIsEqual(lastSourceCrop, sourceCrop))) {
return TD_SUCCESS;
}
uapi_video_crop_rect cropRect;
OverlayCheckPrint(&cropRect, sizeof(cropRect), 0, sizeof(cropRect), "memset_s");
cropRect.left_offset = (td_u32)sourceCrop.left;
cropRect.top_offset = (td_u32)sourceCrop.top;
cropRect.right_offset = (td_u32)sourceCrop.right;
cropRect.bottom_offset = (td_u32)sourceCrop.bottom;
ALOGD("window CropRect, l:%u, r:%u, t:%u, b:%u", cropRect.left_offset, cropRect.right_offset,
cropRect.top_offset, cropRect.bottom_offset);
int ret = uapi_win_set_crop_rect(&winManager.window, &cropRect, 1);
if (ret != TD_SUCCESS) {
ALOGE("set window 0x%x crop rect failed, ret:0x%x", winManager.window, ret);
return ret;
}
lastSourceCrop = sourceCrop;
return TD_SUCCESS;
}
int UnifiedWindowImpl::SetWindowTransform(const uint32_t transform)
{
uapi_win_rotation rotation;
switch (transform) {
case static_cast<int>(OvTransform::OV_TRANSFORM_ROT_90): {
rotation = UAPI_WIN_ROTATION_90;
break;
}
case static_cast<int>(OvTransform::OV_TRANSFORM_ROT_180): {
rotation = UAPI_WIN_ROTATION_180;
break;
}
case static_cast<int>(OvTransform::OV_TRANSFORM_ROT_270): {
rotation = UAPI_WIN_ROTATION_270;
break;
}
default:
rotation = UAPI_WIN_ROTATION_0;
break;
}
if (rotation == lastRotation) {
return TD_SUCCESS;
}
ALOGD("set transform , rotation=%d ", rotation);
td_s32 ret = uapi_win_set_rotation(winManager.window, rotation);
if (ret != TD_SUCCESS) {
ALOGE("uapi_win_set_rotation failed, ret=0x%x", ret);
} else {
lastRotation = rotation;
}
return ret;
}
int UnifiedWindowImpl::SetWindowZorder(const int32_t zorder)
{
ALOGD("SetWindowZorder %d", zorder);
td_s32 ret = uapi_win_set_abs_zorder(winManager.window, zorder);
FaultInfo mFaultInfo = {"uapi_win_set_abs_zorder", "zorder", zorder};
HwgraphicsDft::GetInstance()->ReportFaultIfNecessary(ret != TD_SUCCESS, OVERLAYPLAY_FAIL, mFaultInfo);
if (ret != TD_SUCCESS) {
ALOGE("uapi_win_set_abs_zorder failed, ret=0x%x", ret);
return ret;
}
return TD_SUCCESS;
}
void UnifiedWindowImpl::FillFrameInfo(const Frame &frame, ext_drv_video_frame &frameInfo, const int &dataSpace) const
{
if (frame.hnd == nullptr) {
ALOGE("frame.hnd is nullptr");
return;
}
frameInfo.buf_addr[0].start_addr = frame.hnd->fd;
frameInfo.buf_addr_lb[0].start_addr = frame.hnd->fd;
if (frameInfo.hdr_type == EXT_DRV_HDR_TYPE_CUVA &&
frameInfo.hdr_info.cuva_info.dynamic_metadata_available == TD_TRUE) {
frameInfo.hdr_info.cuva_info.dynamic_metadata.mem_addr.mem_handle = frame.hnd->attr_fd;
} else if (frameInfo.hdr_type == EXT_DRV_HDR_TYPE_DOLBYVISION &&
frameInfo.hdr_info.dolby_info.metadata_valid == TD_TRUE) {
frameInfo.hdr_info.dolby_info.metadata.mem_addr.mem_handle = frame.hnd->attr_fd;
}
if (dataSpace == ADATASPACE_DISPLAY_P3) {
frameInfo.color_space.color_primary = EXT_DRV_COLOR_PRIMARY_DISPLAY_P3;
}
}
void UnifiedWindowImpl::DisplayFrameInfo(const Frame &frame, ext_drv_video_frame &frameInfo, const int &sinkFenceFd)
{
if (debug) {
uapi_win_play_info winInfo;
if (frame.hnd == nullptr) {
ALOGE("frame.hnd is nullptr");
return;
}
OverlayCheckPrint(&winInfo, sizeof(uapi_win_play_info), 0, sizeof(uapi_win_play_info), "memset_s");
(void) uapi_win_get_play_info(winManager.window, &winInfo);
ALOGI("overlay queue frame, handle:0x%x, win_handle:0x%x, queue_idx:%d, sink_fence:%d, delay= %d ms,\
dispRate= %d, bufCount= %d, CurrentDispFramePTS = %lld underload_cnt= %d", frame.hnd->addr,
winManager.window, frameInfo.frame_index, sinkFenceFd, winInfo.delay_time_ms, winInfo.disp_rate,
winInfo.frame_num, winInfo.current_disp_frame_pts_us, winInfo.underload_cnt);
}
}
int UnifiedWindowImpl::DisplayFrame(const Frame &frame, int &releaseFence, const int &dataSpace)
{
int ret = TD_FAILURE;
int sinkFenceFd = -1;
struct attr_private_buffer mediaPrivateBuffer;
pthread_mutex_lock(&winManager.mutex);
if (frame.hnd && frame.hnd->attr_fd != -1) {
ret = gralloc_buffer_attr_read(frame.hnd, GRALLOC_BUFFER_ATTR_MEDIA, &mediaPrivateBuffer);
}
if (ret != GRALLOC_SUCCESS) {
pthread_mutex_unlock(&winManager.mutex);
ALOGE("gralloc_buffer_attr_read failed :%d", ret);
return ret;
}
ext_drv_video_frame *frameInfo = static_cast<ext_drv_video_frame *>(mediaPrivateBuffer.ptr);
if (frameInfo == nullptr) {
pthread_mutex_unlock(&winManager.mutex);
ALOGE("frameInfo is null");
return TD_FAILURE;
}
FillFrameInfo(frame, *frameInfo, dataSpace);
ret = ext_mpi_win_queue_frame(winManager.window, frameInfo, reinterpret_cast<td_u32 *>(&sinkFenceFd));
FaultInfo mFaultInfo = {"ext_mpi_win_queue_frame", "sinkFenceFd", sinkFenceFd};
HwgraphicsDft::GetInstance()->ReportFaultIfNecessary(ret != TD_SUCCESS, OVERLAYPLAY_FAIL, mFaultInfo);
if (ret != TD_SUCCESS) {
pthread_mutex_unlock(&winManager.mutex);
ALOGE("queue frame failed, ret:0x%x", ret);
return ret;
}
DisplayFrameInfo(frame, *frameInfo, sinkFenceFd);
releaseFence = sinkFenceFd;
winManager.isReset = false;
pthread_mutex_unlock(&winManager.mutex);
return TD_SUCCESS;
}
int UnifiedWindowImpl::ResetWindow()
{
ALOGD("IN %s window 0x%x", __func__, winManager.window);
if (winManager.window == 0 || winManager.isReset) {
return TD_SUCCESS;
}
uapi_win_freeze_mode resetType = UAPI_WIN_FREEZE_MODE_BLACK;
/* release all buffer in window */
int ret = uapi_win_set_freeze_mode(winManager.window, resetType);
if (ret != TD_SUCCESS) {
ALOGE("reset window 0x%x failed,ret:0x%x", winManager.window, ret);
return ret;
}
winManager.isReset = true;
return TD_SUCCESS;
}
int UnifiedWindowImpl::DestroyWindow()
{
ALOGD("IN %s window 0x%x", __func__, winManager.window);
if (static_cast<bool>(DestroyWindowInternal(winManager))) {
ALOGE("RMDestroyWindow 0x%x failed", winManager.window);
return TD_FAILURE;
}
ClearWindowParams();
return TD_SUCCESS;
}
int UnifiedWindowImpl::SetWindowQuickOutput(const LayerInfo &info)
{
const private_handle_t *hnd = static_cast<const private_handle_t *>(info.handle);;
if (hnd == nullptr) {
ALOGE("invalid parameter hnd");
return TD_FAILURE;
}
int ret;
int isFastOutput = static_cast<bool>(((hnd->producer_usage | hnd->consumer_usage) &
static_cast<unsigned long long>(GRALLOC_USAGE_PRI_FASTOUTPUT))) ? 1 : 0;
td_bool quickOutputEnable = (isFastOutput != 0) ? TD_TRUE : TD_FALSE;
if (quickOutputEnable == TD_TRUE) {
ret = uapi_win_set_quickout_mode(winManager.window, UAPI_WIN_QUICKOUT_SUPER_LOW_DELAY);
} else {
ret = uapi_win_set_quickout_mode(winManager.window, UAPI_WIN_QUICKOUT_DISABLE);
}
if (ret != TD_SUCCESS) {
ALOGE("set quickout mode failed, bEnable:%d, ret=%#x", quickOutputEnable, ret);
return ret;
}
return ret;
}
int UnifiedWindowImpl::RegistRMCallback()
{
int ret = uapi_rm_init();
if (ret != TD_SUCCESS) {
ALOGE("UAPI_RM_Init failed, ret:0x%x", ret);
return TD_FALSE;
}
ret = uapi_rm_register_callback(&winManager, UnifiedRMEventCB,
static_cast<td_u32>(UAPI_RM_EVENT_WIN_LACK) | static_cast<td_u32>(UAPI_RM_EVENT_WIN_DESTROYED));
if (ret != TD_SUCCESS) {
ALOGE("UAPI_RM_RegisterCallback failed, ret:0x%x", ret);
return TD_FALSE;
} else {
pthread_mutex_lock(&winManager.rmMutex);
winManager.isRmRegister = true;
winManager.rmState = RmState::RM_NOT_DESTROY;
pthread_mutex_unlock(&winManager.rmMutex);
ALOGI("UAPI_RM_RegisterCallback SUCCESS");
return TD_SUCCESS;
}
}
void UnifiedWindowImpl::UnRegistRMCallback()
{
UnRegistRmcCallback(winManager);
}
UnifiedWindowImpl::~UnifiedWindowImpl()
{
ALOGD("IN %s:%d ", __func__, __LINE__);
UnRegistRmcCallback(winManager);
pthread_mutex_destroy(&winManager.mutex);
pthread_mutex_destroy(&winManager.rmMutex);
}
UnifiedWindowImpl::UnifiedWindowImpl()
:lastRotation(UAPI_WIN_ROTATION_MAX)
{
ALOGD("IN %s:%d ", __func__, __LINE__);
ClearWindowParams();
}