/* * 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 #include #include #include #include #include #include #include #include /* 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 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(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(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(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(width), static_cast(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(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(OvTransform::OV_TRANSFORM_ROT_90): { rotation = UAPI_WIN_ROTATION_90; break; } case static_cast(OvTransform::OV_TRANSFORM_ROT_180): { rotation = UAPI_WIN_ROTATION_180; break; } case static_cast(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(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(&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(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(info.handle);; if (hnd == nullptr) { ALOGE("invalid parameter hnd"); return TD_FAILURE; } int ret; int isFastOutput = static_cast(((hnd->producer_usage | hnd->consumer_usage) & static_cast(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(UAPI_RM_EVENT_WIN_LACK) | static_cast(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(); }