2026-02-12 05:17:55 +00:00
|
|
|
/*******************************************************************************************
|
|
|
|
|
# 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 <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <pthread.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <linux/fb.h>
|
|
|
|
|
|
|
|
|
|
#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"
|
2026-02-12 06:34:25 +00:00
|
|
|
#define BK_IMAGE_PATH "/usrdata/pic/bk.rgba"
|
|
|
|
|
#define TAG_IMAGE_PATH "/usrdata/pic/tag.rgba"
|
|
|
|
|
#define TAG_Y_OFFSET 640
|
2026-02-12 05:17:55 +00:00
|
|
|
|
|
|
|
|
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;
|
2026-02-12 05:22:07 +00:00
|
|
|
alpha.alpha_channel = QUA_TRUE;
|
2026-02-12 05:17:55 +00:00
|
|
|
alpha.alpha0 = 0;
|
2026-02-12 05:22:07 +00:00
|
|
|
alpha.alpha1 = 128;
|
2026-02-12 05:17:55 +00:00
|
|
|
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);
|
2026-02-12 06:34:25 +00:00
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-12 05:22:07 +00:00
|
|
|
fb_device->compress(fb_device, QUA_TRUE);
|
2026-02-12 05:17:55 +00:00
|
|
|
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;
|
2026-02-12 06:34:25 +00:00
|
|
|
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++; }
|
2026-02-12 05:17:55 +00:00
|
|
|
|
|
|
|
|
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;
|
2026-02-12 06:34:25 +00:00
|
|
|
|
|
|
|
|
QUA_S32 render_ret = fb_dev->render(fb_dev, &vinfo);
|
|
|
|
|
return render_ret;
|
2026-02-12 05:17:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|