/******************************************************************************************* # Copyright (c) 2023~2024 Quaming Intelligent Technology Co., Ltd. # All Rights Reserved. # Confidential and Proprietary - Quaming Intelligent Technology Co., Ltd. #*******************************************************************************************/ #ifndef CONFIG_XOS_USE_DLMPI #include #include #include #include #include #include #include #include #include #include #include #include "display/fbdev.h" #include "display/qua_mm_display.h" #include "system/qua_mm_system.h" #include "common/qua_sys_platform.h" #include "filter/qua_mm_filter.h" #include "utils/qua_display_parser.h" #include "bootanimation/qua_bootanimation.h" #define DISPLAY_ID "id:display0" #define BK_IMAGE_PATH "/usrdata/pic/bk.rgba" #define TAG_IMAGE_PATH "/usrdata/pic/tag.rgba" #define TAG_Y_OFFSET 640 static QUA_CHAR *pShowScreen; static QUA_U32 u32PhyAddrScreen; static qua_fb_fix_screeninfo_t finfo; static qua_fb_var_screeninfo_t vinfo; static qua_mm_module_t *g_display_module = NULL; static qua_mm_vo_device_t *g_vo_device = NULL; qua_mm_fb_device_t *g_fb_device = NULL; static QUA_S32 vo_num, fb_num; static QUA_CONST_CHAR *vo_id = NULL; static QUA_CONST_CHAR *fb_id = NULL; static QUA_S32 enable_vo_device(QUA_VO_DEV dev) { QUA_S32 ret = QUA_SUCCESS; qua_mm_module_t *display_module = NULL; ret = qua_mm_load_module(QUA_MM_MODULE_DISPLAY, &display_module); if (ret != QUA_SUCCESS || display_module == NULL) { printf("Error: load display module failed\n"); return ret; } g_display_module = display_module; qua_mm_device_t *mm_device = NULL; ret = display_module->open_device(display_module, vo_id, dev, &mm_device); if (ret != QUA_SUCCESS || mm_device == NULL) { printf("Error: open vo dev failed\n"); return ret; } qua_mm_vo_device_t *vo_device = (qua_mm_vo_device_t *)mm_device; printf("Device %s, number %d\n", vo_device->parent.id, vo_device->dev_num); g_vo_device = vo_device; return ret; } static QUA_S32 disable_vo_device(QUA_VO_DEV dev) { qua_mm_vo_device_t *vo_device = g_vo_device; vo_device->disable(dev); return vo_device->parent.close((qua_mm_device_t *)vo_device); } static QUA_S32 init_fyfb() { QUA_S32 ret = QUA_SUCCESS; qua_mm_device_t *mm_device = NULL; ret = g_display_module->open_device(g_display_module, fb_id, fb_num, &mm_device); if (ret != QUA_SUCCESS || mm_device == NULL) { printf("open fb dev failed\n"); return ret; } qua_mm_fb_device_t *fb_device = (qua_mm_fb_device_t *)mm_device; printf("Device %s, number %d fd=%d\n", fb_device->parent.id, fb_device->dev_num, fb_device->fd); g_fb_device = fb_device; qua_fb_bitfield_t stR = {16, 8, 0}; qua_fb_bitfield_t stG = {8, 8, 0}; qua_fb_bitfield_t stB = {0, 8, 0}; qua_fb_bitfield_t stA = {24, 8, 0}; fb_device->show(fb_device, QUA_FALSE); qua_point_t position = {0, 0}; if (fb_device->put_origin != NULL) fb_device->put_origin(fb_device, &position); qua_size_t screen_size; screen_size.width = LV_USE_HOR_SIZE; screen_size.height = LV_USE_VER_SIZE; if (fb_device->put_size != NULL) fb_device->put_size(fb_device, &screen_size); if (fb_device->get_var_info(fb_device, &vinfo) != QUA_SUCCESS) { printf("get var info failed\n"); return QUA_FAILURE; } vinfo.xres_virtual = vinfo.xres = LV_USE_HOR_SIZE; vinfo.yres_virtual = vinfo.yres = LV_USE_VER_SIZE; #ifdef CONFIG_XOS_FB_ROTATION vinfo.yres_virtual *= 2; #endif vinfo.activate = QUA_FB_ACTIVATE_NOW; vinfo.bits_per_pixel = 32; vinfo.xoffset = 0; vinfo.yoffset = 0; vinfo.red = stR; vinfo.green = stG; vinfo.blue = stB; vinfo.transp = stA; if (fb_device->put_var_info(fb_device, &vinfo) != QUA_SUCCESS) { printf("put var info failed\n"); return QUA_FAILURE; } /* Re-read vinfo to get actual values from driver */ fb_device->get_var_info(fb_device, &vinfo); if (fb_device->get_fix_info(fb_device, &finfo) != QUA_SUCCESS) { printf("get fix info failed\n"); return QUA_FAILURE; } printf("FB actual: %ux%u, smem_len=%u, line_length=%u\n", vinfo.xres, vinfo.yres, finfo.smem_len, finfo.line_length); qua_fb_alpha_t alpha; alpha.alpha_enable = QUA_TRUE; alpha.alpha_channel = QUA_TRUE; alpha.alpha0 = 0; alpha.alpha1 = 128; alpha.global_alpha = 128; alpha.reserved = 0; if (fb_device->put_alpha(fb_device, &alpha) != QUA_SUCCESS) { printf("put alpha failed\n"); return QUA_FAILURE; } pShowScreen = fb_device->map(fb_device, finfo.smem_len, 0); if (pShowScreen == QUA_NULL) { printf("map failed\n"); goto map_failed; } memset(pShowScreen, 0x00, finfo.smem_len); /* Step 1: load bk.rgba as full-screen background */ { int fb_stride = finfo.line_length; int row_bytes = vinfo.xres * 4; FILE *fp = fopen(BK_IMAGE_PATH, "rb"); if (fp) { for (unsigned int y = 0; y < vinfo.yres; y++) { if (fread(pShowScreen + y * fb_stride, 1, row_bytes, fp) <= 0) break; } fclose(fp); printf("[init_fyfb] loaded %s full screen\n", BK_IMAGE_PATH); } else { printf("[init_fyfb] %s not found\n", BK_IMAGE_PATH); } /* Step 2: overlay tag.rgba at bottom (y=TAG_Y_OFFSET ~ yres) with alpha blend */ fp = fopen(TAG_IMAGE_PATH, "rb"); if (fp) { unsigned int tag_h = vinfo.yres - TAG_Y_OFFSET; uint8_t *row_buf = (uint8_t *)malloc(row_bytes); if (row_buf) { /* skip top TAG_Y_OFFSET rows of tag image */ for (unsigned int y = 0; y < (unsigned int)TAG_Y_OFFSET; y++) if (fread(row_buf, 1, row_bytes, fp) <= 0) break; /* blend bottom rows */ for (unsigned int y = 0; y < tag_h; y++) { if (fread(row_buf, 1, row_bytes, fp) <= 0) break; uint8_t *dst = (uint8_t *)(pShowScreen + (TAG_Y_OFFSET + y) * fb_stride); uint8_t *src = row_buf; for (unsigned int x = 0; x < vinfo.xres; x++) { uint8_t sb = src[0], sg = src[1], sr = src[2], sa = src[3]; if (sa == 255) { dst[0] = sb; dst[1] = sg; dst[2] = sr; dst[3] = 255; } else if (sa > 0) { dst[0] = (sb * sa + dst[0] * (255 - sa)) / 255; dst[1] = (sg * sa + dst[1] * (255 - sa)) / 255; dst[2] = (sr * sa + dst[2] * (255 - sa)) / 255; dst[3] = 255; } src += 4; dst += 4; } } free(row_buf); } fclose(fp); printf("[init_fyfb] overlaid %s at y=%d\n", TAG_IMAGE_PATH, TAG_Y_OFFSET); } else { printf("[init_fyfb] %s not found\n", TAG_IMAGE_PATH); } } fb_device->compress(fb_device, QUA_TRUE); return QUA_SUCCESS; map_failed: fb_device->unmap(fb_device, pShowScreen, finfo.smem_len); return QUA_FAILURE; } static QUA_S32 deinit_fyfb() { qua_mm_fb_device_t *fb_device = (qua_mm_fb_device_t *)g_fb_device; if (pShowScreen != NULL) fb_device->unmap(fb_device, pShowScreen, finfo.smem_len); fb_device->parent.close((qua_mm_device_t *)fb_device); return QUA_SUCCESS; } char *fbdev_get_fbp(void) { return pShowScreen; } void fbdev_get_info(struct fb_var_screeninfo *pOutScreenInfo, struct fb_fix_screeninfo *pOutFixInfo) { memcpy(pOutScreenInfo, &vinfo, sizeof(qua_fb_var_screeninfo_t)); memcpy(pOutFixInfo, &finfo, sizeof(qua_fb_fix_screeninfo_t)); } int fbdev_init_xd(void) { QUA_S32 ret; // qua_init_display_parser(); ret = qua_parse_display_id(DISPLAY_ID, &vo_id, &vo_num, &fb_id, &fb_num); printf("vo_id=%s vo_num= %d fb_id=%s fb_num=%d\n", vo_id, vo_num, fb_id, fb_num); if (ret != QUA_SUCCESS) { printf("%s, qua_parse_display_id error!\n", __func__); return ret; } ret = enable_vo_device(vo_num); if (ret != QUA_SUCCESS) { printf("enable_vo_device failed\n"); // return -1; } ret = init_fyfb(); if (ret != QUA_SUCCESS) { printf("init_fyfb failed\n"); return -1; } return 0; } int fbdev_exit_xd(void) { deinit_fyfb(); disable_vo_device(vo_num); return 0; } int fbdev_pan_disp(void) { qua_mm_fb_device_t *fb_dev = (qua_mm_fb_device_t *)g_fb_device; static int is_first_frame = 1; static int pan_cnt = 0; if (pan_cnt < 3) { printf("[fbdev_pan_disp] called #%d first=%d fb_dev=%p\n", pan_cnt, is_first_frame, fb_dev); fflush(stdout); pan_cnt++; } if (fb_dev == NULL) return -1; if (is_first_frame) { #ifdef CONFIG_XOS_PLAY_BOOTANIMATION int status = qua_request_bootanimation(QUA_BOOTANIMAION_CMD_QUERY_STATUS); if (status >= QUA_BOOTANIMAION_STATUS_UNKNOWN && status < QUA_BOOTANIMAION_STATUS_BOOT_FINISH) { return -1; } #else if (g_vo_device == NULL) return -1; qua_vo_pub_attr_t dev_attr = { .bg_color = 0, .intf_type = QUA_VO_INTF_LCD, // #ifdef CONFIG_XOS_LCM_800x1280 .intf_sync = QUA_VO_OUTPUT_800x1280_60, // #else // .intf_sync = QUA_VO_OUTPUT_1024x600_60, // #endif .intf_type = QUA_VO_INTF_LCD, }; QUA_S32 ret = g_vo_device->set_public_attr(vo_num, &dev_attr); if (ret != QUA_SUCCESS) { return ret; } ret = g_vo_device->enable(vo_num); if (ret != QUA_SUCCESS) { return ret; } #endif if (fb_dev->show(fb_dev, QUA_TRUE) != QUA_SUCCESS) { printf("show failed\n"); return -1; } is_first_frame = 0; } if (fb_dev->render == NULL) return -1; QUA_S32 render_ret = fb_dev->render(fb_dev, &vinfo); return render_ret; } #endif