Files
AC707N/SDK/cpu/br35/ui_driver/interface/gpu_task.c
T
huxi 36e62db3a4 1、摄像头添加SD卡录满处理;
2、修复摄像头、科大讯飞等相关问题;
2026-01-08 11:29:46 +08:00

1859 lines
69 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Copyright(C) 2010- , JIELI TECHNOLOGY, Inc.
* All right reserved.
*/
/* ------------------------------------------------------------------------------------*/
/**
* @file gpu_task.c
*
* @brief GPU 任务调度模块
*
* @author zhuhaifang@zh-jieli.com
*
* @version V1.0.0
*
* @date 2024-08-01
*/
/* ------------------------------------------------------------------------------------*/
#include "app_config.h"
#include "product_test.h"
#include "jlui/ui_core.h"
#include "gpu_port.h"
#include "gpu_task.h"
#include "includes.h"
#include "dbi.h"
#include "jlui/ui_measure.h"
#include "ui_expand/buffer_manager.h"
#include "ui_expand/ui_addr.h"
#include "ui_page_switch.h"
#include "jlui_effect/jlui_effect.h" //特效相关
#include "ui_core.h"
#include "jljpeg_decode.h"
#include "jlui_app/ui_style.h"
#include "jlui_app/ui_app_effect.h"
#include "ui_multi_page_manager.h"
#if (defined(CONFIG_UI_STYLE_JL_PUBLIC_MODLS_ENABLE) || defined(CONFIG_UI_STYLE_JL_CSC_PUBLIC_MODLS_ENABLE))
#include "ui_expand/time_count.h"
/* debug 打印配置 */
#define LOG_TAG_CONST JL_GPU
#define LOG_TAG "[JL GPU]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
#define DUMP_RECT(func, line, name, rect) \
printf("[RECT] %s() %d, %s [%d, %d, %d, %d]\n", func, line, name, (rect)->left, (rect)->top, (rect)->width, (rect)->height)
/* DMA模块和PSRAM相关 */
#if (defined TCFG_PSRAM_DEV_ENABLE && TCFG_PSRAM_DEV_ENABLE)
#include "asm/dma_copy.h"
#include "lcd_task.h"
#endif
#define CONFIG_LCD_BUF_DYNAMIC_MIN_LINE (4) //若剩余空间换算的行数低于此值,则丢帧或断言
#define CONFIG_LCD_BUF_LEFT_SPACE (40*1024) //动态申请buf后,留下的剩余空间
/* 私有参数 */
struct gpu_task_private_def {
struct draw_context dc; // DC数据备份,在GPU合成时使用,防止GPU合成时,DC内容被UI框架修改
void *buffer_hdl; // buf管理句柄,用于设置buf状态、获取空闲buf等
void *buffer_adr; // buf指针,用于记录当前使用的buf地址
#if TCFG_LCD_BUF_DYNAMIC_LINE_ENABLE
void *disp_adr; //gpu task申请的显存buf
void *disp_hdl; //gpu task申请的显存管理
#endif
#if (defined TCFG_PSRAM_DEV_ENABLE && TCFG_PSRAM_DEV_ENABLE)
void *psram_addr;
void *psram_buf_hdl;
void *psram_buf_adr;
void *psram_lcd_buf;
void *psram_last_buf;
#endif
OS_SEM buf_idle_sem; // buf 设置为空闲时信号量,防止GPU获取空闲buf时进入循环死等
/* GPU空闲信号量,等待GPU同步时会pend住,DBI模块推完最后一个分块时会post,允许GPU合成下一帧 */
OS_SEM gpu_sem; // GPU空闲信号量
/* TE同步信号量,等待TE时会pend住,TE中断过来时会post,释放TE等待 */
OS_SEM lcd_te_sem; // TE同步信号量
/* 推屏buf使用信号量,DBI启动推屏前需pend住等上一个buf推完,DBI推完buf后会post允许下一次推屏 */
OS_SEM buffer_sem; // BUF使用信号量
pJLGPUMultTaskList_t mult_list;
pJLGPUMultTaskList_t last_mult_list;
u8 has_init; // 模块初始化标志,防止信号量未初始化就使用,导致系统异常
u8 gpu_line_end_flag : 1; // 最后一块推屏标志,仅当合成最后一个分块时为1,其它时候为0,仅仅表示gpu,不代表lcd已经推完
u8 lcd_draw_line_end_flag: 1; // 最后一块推屏标志,仅当合成最后一个分块时为1,其它时候为0,表示lcd
u8 redraw_mode; // 同步或异步刷新标志
u8 wait_gpu_sem; // 是否需等GPU信号量标志
u8 gpu_is_busy; // GPU繁忙标志,GPU正在合成任务链时为真
u8 draw_task_list; // 绘制GPU任务链标志
u8 release_frame_buf; // 释放PSRAM帧buf
int lcd_width;
int lcd_height;
};
static struct gpu_task_private_def gpu_task_priv ALIGNED(4) = {0};
#define __this (&gpu_task_priv)
extern int jljpeg_stream_src_data_unlock();
extern volatile int64_t dc_te_absolute_us;
extern volatile int64_t dc_start_absolute_us;
extern volatile int lcd_spi_last_us;
extern int64_t get_system_us(void);
extern u32 lcd_get_te_frame_period_us(void);
extern u32 lcd_get_spi_frame_period_us(void);
extern u32 lcd_get_te_phase_us();
extern void gpu_free_frame_buf(void *p);
extern void jpeg_module_free_res_cb(void *p);
extern struct element *ui_core_get_root();
extern u8 buf_is_heap_addr(void *p);
extern int ui_buf_is_psram(void *buf);
extern const int JLUI_GPU_DMA_TO_PSRAM;
extern void *jlgpu_unit_to_instruction(pJLGPUTaskUnit_t taskp);
extern const int config_gpu_cache_psram_jpeg_en ;
extern const int config_gpu_cache_psram_file_res_en;
extern int jpeg_module_opj_invaild_clr();
extern int jpeg_module_opj_set_invaild_by_index(int index);
extern size_t xPortGetPhysiceMemorySize(void);
void *jlui_malloc(int size, u32 ram_type, u32 module_type);
void jlui_free(void *buf, u32 ram_type, u32 module_type);
void jlui_argb8565_to_rgb565(u8 *out_buf, struct rect *out_r, u8 *in_buf, struct rect *in_r);
extern uint32_t gpu_task_get_format_bpp(uint32_t format);
extern void psram_flush_cache(void *begin, u32 len);
extern int async_buffer_clr();
#if TCFG_VIDEO_DIAL_ENABLE
extern void avi_gpu_scheduler_kick_start(void *priv);
#endif
extern const int JLUI_LCD_RAMLESS_ENABLE;
extern const int JLUI_MULTI_PAGE_OVERLAY_SUPPORT;
extern const int GPU_INPUT_TO_NOCACHE;
extern const int JLJPEG_STREAM_ENABLE;
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_lcd_buf_line_get 计算可用行数
*
* @param left_space 剩余ram空间
* @param stride 一行大小
* @param buf_num buf数量(一般为双buf
* @param max_line 最大行数,-1时不设上限
*
* @return 行数
*/
/* ------------------------------------------------------------------------------------*/
static int jlgpu_lcd_buf_line_get(int left_space, int stride, int buf_num, int max_line, int total_line)
{
if (left_space < CONFIG_LCD_BUF_LEFT_SPACE) { //预留一部分空间
return 0;
}
left_space -= CONFIG_LCD_BUF_LEFT_SPACE;
int check_line = left_space / stride / buf_num;
/* printf("%s left_space:%d check_line:%d total:%d max:%d",__func__,left_space,check_line,total_line,max_line); */
if (max_line != -1) { //上限
check_line = (check_line > max_line) ? max_line : check_line;
}
if (check_line < CONFIG_LCD_BUF_DYNAMIC_MIN_LINE) { //下限
return 0;
}
check_line = (check_line > total_line) ? total_line : check_line;
/* printf("%s left_space:%d check_line:%d total:%d max:%d",__func__,left_space,check_line,total_line,max_line); */
return check_line;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_scheduler_aysnc_free_buf_cb 异步释放buf回调
*
* @param p
*/
/* ------------------------------------------------------------------------------------*/
static void jlgpu_scheduler_aysnc_free_buf_cb(void *p)
{
if (buf_is_heap_addr(p) || ui_buf_is_psram(p)) {
gpu_free_frame_buf(p);
} else {
ASSERT(0, "p:%x", (int)p);
}
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_scheduler_async_free_buf post buf到gpu task释放
*
* @param p
*
* @return
*
* @notes: buf可能被gpu异步使用时,post到gpu中释放,避免出现硬件访问异常
*/
/* ------------------------------------------------------------------------------------*/
int jlgpu_scheduler_async_free_buf(void *p)
{
int ret = 0;
if (strcmp(os_current_task(), GPU_TASK_NAME)) {
int argv[3] = {0};
int retry = 3;
argv[0] = (int) jlgpu_scheduler_aysnc_free_buf_cb;
argv[1] = 1;
argv[2] = (int)p;
__try_again:
ret = os_taskq_post_type(GPU_TASK_NAME, Q_CALLBACK, 3, argv);
if (ret) {
if (retry) {
os_time_dly(1);
retry--;
goto __try_again;
}
printf("%s post ret:%d retry:%d\n", __func__, ret, retry);
}
} else {
jlgpu_scheduler_aysnc_free_buf_cb(p);
}
return ret;
}
int jlgpu_scheduler_async_gpu_cache_free()
{
int ret = 0;
int argv[3] = {0};
int retry = 3;
argv[0] = (int)gpu_input_stream_cache_clr_all_invaild;
argv[1] = 0;
__try_again:
ret = os_taskq_post_type(GPU_TASK_NAME, Q_CALLBACK, 2, argv);
if (ret) {
if (retry) {
os_time_dly(1);
retry--;
goto __try_again;
}
printf("%s post ret:%d retry:%d\n", __func__, ret, retry);
}
return ret;
}
int jlgpu_scheduler_async_gpu_cache_free_resident()
{
int ret = 0;
int argv[3] = {0};
int retry = 3;
argv[0] = (int) gpu_input_stream_cache_clr_resident;
argv[1] = 0;
__try_again:
ret = os_taskq_post_type(GPU_TASK_NAME, Q_CALLBACK, 2, argv);
if (ret) {
if (retry) {
os_time_dly(1);
retry--;
goto __try_again;
}
printf("%s post ret:%d retry:%d\n", __func__, ret, retry);
}
return ret;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_scheduler_async_free_buf post buf到gpu task释放
*
* @param p
*
* @return
*
* @notes: buf可能被gpu异步使用时,post到gpu中释放,避免出现硬件访问异常
*/
/* ------------------------------------------------------------------------------------*/
int jlgpu_scheduler_async_free_jpeg_res(void *p)
{
int argv[3] = {0};
int retry = 3;
argv[0] = (int) jpeg_module_free_res_cb;
argv[1] = 1;
argv[2] = (int)p;
__try_again:
int ret = os_taskq_post_type(GPU_TASK_NAME, Q_CALLBACK, 3, argv);
if (ret) {
if (retry) {
os_time_dly(1);
retry--;
goto __try_again;
}
printf("%s post ret:%d retry:%d\n", __func__, ret, retry);
}
return ret;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief lcd_flush_finish_cb DBI模块中断回调,每推完一帧数据起一次
*
* @Params err 错误标志
*/
/* ------------------------------------------------------------------------------------*/
static int lcd_flush_finish_cb(void *priv)
{
IO_DBI_LOW();
if (JLUI_GPU_DMA_TO_PSRAM) {
#if (defined TCFG_PSRAM_DEV_ENABLE && TCFG_PSRAM_DEV_ENABLE)
if (JLUI_LCD_RAMLESS_ENABLE) {
if (priv) {
struct dbi_ramless_callback_param *param = (struct dbi_ramless_callback_param *)priv;
if (param->lcd_buff_update) {
if (param->lcd_buff_new == (u32)__this->psram_lcd_buf) {
set_buffer_used(__this->psram_buf_hdl, __this->psram_lcd_buf);
}
if (param->lcd_buff_old == (u32)__this->psram_last_buf) {
set_buffer_idle(__this->psram_buf_hdl, __this->psram_last_buf);
os_sem_post(&__this->buf_idle_sem);
}
}
}
} else {
if (priv) {
set_buffer_idle(__this->psram_buf_hdl, priv);
os_sem_post(&__this->buf_idle_sem);
}
}
/* LCD推屏结束,buf才空闲,可以进行buf释放 */
if (__this->release_frame_buf && !__this->gpu_is_busy) {
#if (defined TCFG_PSRAM_DEV_ENABLE && TCFG_PSRAM_DEV_ENABLE)
os_taskq_del_type(LCD_TASK_NAME, LCD_MSG_FLUSH); // 清空lcd_task消息
#endif
if (__this->psram_buf_hdl) {
buffer_manager_free(__this->psram_buf_hdl);
__this->psram_buf_hdl = NULL;
__this->psram_buf_adr = NULL;
__this->psram_lcd_buf = NULL;
}
if (__this->psram_addr) {
free_psram(__this->psram_addr);
__this->psram_addr = NULL;
}
}
#if (defined TCFG_LCD_TE_USED_PEND && TCFG_LCD_TE_USED_PEND)
lcd_spi_last_us = get_system_us() - dc_start_absolute_us;
#endif
#endif
} else {
if (__this->buffer_hdl) {
/* 推屏完成,设置推完屏的buf为空闲状态,允许GPU获取这块buf进行合成 */
set_buffer_idle(__this->buffer_hdl, __this->buffer_adr);
if (!__this->lcd_draw_line_end_flag) {
__this->buffer_hdl = NULL;
__this->buffer_adr = NULL;
}
os_sem_post(&__this->buf_idle_sem);
/* 当line_end_flag为真时,说明当前推完的是最后一个分块,此时已经完成一帧的合成和推屏 */
if (__this->lcd_draw_line_end_flag) {
__this->lcd_draw_line_end_flag = 0;
#if (defined TCFG_LCD_TE_USED_PEND && TCFG_LCD_TE_USED_PEND)
lcd_spi_last_us = get_system_us() - dc_start_absolute_us;
#endif
if (__this->draw_task_list) {
buffer_manager_free(__this->buffer_hdl);
__this->draw_task_list = 0;
}
#if TCFG_LCD_BUF_DYNAMIC_LINE_ENABLE
//free_buf
if (__this->disp_adr) {
jlui_free(__this->disp_adr, UI_RAM_SRAM, UI_MODULE_BUFFER);
__this->disp_adr = NULL;
}
//buffer_manager_free
if (__this->disp_hdl) {
buffer_manager_free(__this->disp_hdl);
__this->disp_hdl = NULL;
}
#endif// TCFG_LCD_BUF_DYNAMIC_LINE_ENABLE
__this->buffer_hdl = NULL;
__this->buffer_adr = NULL;
__this->wait_gpu_sem = false;
os_sem_post(&__this->gpu_sem); // 最后一个分块推完,发送GPU信号量
__this->wait_gpu_sem = true;
}
os_sem_post(&__this->buffer_sem); // 每推完一个分块,发送一个buf信号量
}
}
return 0;
}
#define APP_IO_DEBUG_0(i,x) {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT &= ~BIT(x);}
#define APP_IO_DEBUG_1(i,x) {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT |= BIT(x);}
/* ------------------------------------------------------------------------------------*/
/**
* @brief lcd_te_sync_int_handler TE中断同步回调,在TE中断中调用,用于TE等待同步
*/
/* ------------------------------------------------------------------------------------*/
void lcd_te_sync_int_handler(void)
{
/* APP_IO_DEBUG_1(B,5); */
if (__this->has_init) {
dc_te_absolute_us = get_system_us();
os_sem_post(&__this->lcd_te_sem);
}
/* APP_IO_DEBUG_0(B,5); */
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief lcd_wait_te TE等待同步函数
*/
/* ------------------------------------------------------------------------------------*/
static void lcd_wait_te()
{
#if TCFG_LCD_PIN_TE == NO_CONFIG_PORT
return;
#else
os_sem_set(&__this->lcd_te_sem, 0);
while (1) {
/* pend住等待TE信号量,释放CPU */
int err = os_sem_pend(&__this->lcd_te_sem, 10);
if (err != OS_NO_ERR) {
if (err == OS_TIMEOUT) {
printf("lcd wait te timeout.\n");
break;
} else {
printf("lcd wait te error.\n");
}
} else {
break;
}
}
#endif
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief lcd_wait_te_sync TE自适应同步
*/
/* ------------------------------------------------------------------------------------*/
void lcd_wait_te_sync()
{
#if (PRODUCT_TEST_ENABLE && (!PT_LCD_TP_ENABLE))
if (product_test_check_run()) {
return ;
}
#endif /* #if (PRODUCT_TEST_ENABLE && (!PT_LCD_TP_ENABLE)) */
#if (defined TCFG_LCD_TE_USED_PEND && TCFG_LCD_TE_USED_PEND)
#if (defined TCFG_LCD_TE_QUICK_SYNC && TCFG_LCD_TE_QUICK_SYNC)
/* 自适应TE同步逻辑,仅在推第一个分块时需要判断是否进行TE同步 */
u32 period_us = lcd_get_te_frame_period_us();//tft屏幕刷新一帧时间
u32 spi_period_us = lcd_get_spi_frame_period_us();//spi推屏一帧时间
u32 rela_us = get_system_us() - dc_te_absolute_us;
//当前时间距离te中断的时间
int lcd_need_wait_te = 0;
//判断时间差是否大于2倍te,要么是中途停止刷屏要么是推屏超时2te,无论哪个情况都要等te
if ((get_system_us() - dc_start_absolute_us) >= 2 * period_us) {
lcd_need_wait_te = 1;
goto __end;//结束计算
}
//判断时间差是否<1 te,1e 能推完的下次繼續等
if (lcd_spi_last_us <= period_us) {
lcd_need_wait_te = 1;
goto __end;//结束计算
}
//转换为距离te点相对时间,解决te中断压力情况中断延后导致的计数器溢出问题
if (rela_us >= period_us) {
rela_us = rela_us - period_us;
}
//rela_us 在这里是标识超过当前te线的时间,不代表距离上次一次te的时间,考虑溢出问题
//把te 触发点 转换,te 距离刷屏0点的距离
int te_offset = (period_us - lcd_get_te_phase_us() % period_us);//或者理解为触发中断到屏幕刷新0行的时间
int remain_render_flush_time_min;//
int remain_render_flush_time_max;//
if (rela_us > te_offset) {//证明当前刷新点已经越过了0行了
//当前rela_us - te_offset 代表越过0行的刷新时间
remain_render_flush_time_min = period_us - (rela_us - te_offset); //1 te 周期内完成的时间剩余
remain_render_flush_time_max = 2 * period_us - (rela_us - te_offset); //2 te 周期内完成的时间剩余
} else {
//lcd_get_te_phase_us() + rela_us代表当前点在越过0行的刷新行时间
remain_render_flush_time_min = period_us - (lcd_get_te_phase_us() + rela_us);//1 te 周期内完成的时间剩余
remain_render_flush_time_max = 2 * period_us - (lcd_get_te_phase_us() + rela_us);//2 te 周期内完成的时间剩余
}
if (lcd_spi_last_us < spi_period_us) {
lcd_spi_last_us = spi_period_us; //正常是要小于spi 周期的,除非局部刷新
}
//1.15 只是一个系数
if (lcd_spi_last_us * 1.15f > remain_render_flush_time_max) { //上次刷新时间加上系数比剩余最大时间还大,需要等te
lcd_need_wait_te = 1;
} //need wait te
if (spi_period_us < remain_render_flush_time_min) {
//spi 速度快过了,本来要求最快17ms推完,但是spi是16ms推完,瞬时速度过度,需要分块的策略或者等te了
/* printf("%d %d,%d %d,%d %d %d %d\n", remain_render_flush_time_min, remain_render_flush_time_max, spi_period_us , rela_us, lcd_spi_last_us, period_us,lcd_get_spi_frame_period_us(),lcd_get_te_phase_us()); */
lcd_need_wait_te = 1;
} //need wait te
__end:
if (lcd_need_wait_te) {
lcd_wait_te();
}
dc_start_absolute_us = get_system_us();
#else
lcd_wait_te();
#endif
#endif
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief get_idle_buf_by_handler 通过显存buf管理句柄获取空闲buf,会释放CPU放置阻塞
*
* @Params hdl buf管理句柄
*
* @return 空闲buf指针
*/
/* ------------------------------------------------------------------------------------*/
static inline u8 *get_idle_buf_by_handler(void *hdl)
{
u8 *idle_buf = NULL;
u32 time_msec1 = jiffies_msec();
do {
/* 等待获取空闲显出buf,给GPU模块作为输出buf */
idle_buf = get_idle_buffer_to_lock(hdl);
if (!idle_buf) {
os_sem_pend(&__this->buf_idle_sem, 1); // 挂起一下任务,空出CPU
}
u32 time_msec2 = jiffies_msec();
if ((time_msec2 - time_msec1) > 500) {
buffer_manager_status_dump(hdl);
time_msec1 = time_msec2;
}
} while (!idle_buf);
return idle_buf;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief wait_buf_to_idle 等待指定buf状态转变为空闲
*
* @Params hdl buf管理句柄
* @Params buf 需要等待转为空闲的buf
*/
/* ------------------------------------------------------------------------------------*/
static inline void wait_buf_to_idle(void *hdl, void *buf)
{
u32 time_msec1 = jiffies_msec();
do {
/* 等待获取空闲显出buf,给GPU模块作为输出buf */
if (get_buffer_status(hdl, buf) != BUFFER_STATUS_IDLE) {
os_sem_pend(&__this->buf_idle_sem, 1); // 挂起一下任务,空出CPU
}
u32 time_msec2 = jiffies_msec();
if ((time_msec2 - time_msec1) > 500) {
buffer_manager_status_dump(hdl);
time_msec1 = time_msec2;
}
} while (get_buffer_status(hdl, buf) != BUFFER_STATUS_IDLE);
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief lcd_flush_buffer_start 启动DBI模块推屏
*
* @Params buf_hdl buffer管理句柄
* @Params buf_adr buffer地址/待推屏的buf地址
* @Params rect 推屏的区域,与buf_adr指向的地址大小相同
* @Params is_continue 是否续传,每次推屏第一个分块为0,其它分块为1,直到本次推屏结束
*/
/* ------------------------------------------------------------------------------------*/
static void lcd_flush_buffer_start(void *buf_hdl, void *buf_adr, struct rect *rect, int is_continue)
{
int x_start = rect->left;
int x_end = x_start + rect->width - 1;
int y_start = rect->top;
int y_end = y_start + rect->height - 1;
IO_DBI_HIGH();
/* 等待上一个buf推完 */
int os_err = os_sem_pend(&__this->buffer_sem, 100);
if (os_err) {
ASSERT(0, "%s os_err:%d\n", __func__, os_err);
}
/* put_buf(buf_adr, (x_end - x_start) * 2); */
//设置是否lcd最后一块,注意这里的位置要在同步之后,防止中断还没有起来
if (__this->gpu_line_end_flag) {
__this->lcd_draw_line_end_flag = 1;
}
/* 设置buf为使用状态,避免被其它地方使用 */
set_buffer_used(buf_hdl, buf_adr);
__this->buffer_hdl = buf_hdl;
__this->buffer_adr = buf_adr;
if (!is_continue) {
lcd_wait_te_sync();
/* 第一个分块启动DBI模块推屏 */
lcd_draw_kistart(buf_adr, x_start, x_end, y_start, y_end); // DBI kistart
} else {
/* 其它分块启动DBI模块续传 */
lcd_draw_continue(buf_adr, x_start, x_end, y_start, y_end); // DBI 续传
}
}
#if (defined TCFG_PSRAM_DEV_ENABLE && TCFG_PSRAM_DEV_ENABLE)
/* ------------------------------------------------------------------------------------*/
/**
* @brief dma_copy_callback dma拷贝到PSRAM回调
*
* @Params priv dma异步拷贝回调参数
*/
/* ------------------------------------------------------------------------------------*/
static void dma_copy_callback(void *priv)
{
if (__this->buffer_hdl) {
set_buffer_idle(__this->buffer_hdl, __this->buffer_adr);
/* __this->buffer_hdl = NULL; */
/* __this->buffer_adr = NULL; */
os_sem_post(&__this->buf_idle_sem);
if (__this->lcd_draw_line_end_flag) {
__this->lcd_draw_line_end_flag = 0;
/* lcd_spi_last_us = get_system_us() - dc_start_absolute_us; */
__this->wait_gpu_sem = false;
os_sem_post(&__this->gpu_sem); // 最后一个分块推完,发送GPU信号量
__this->wait_gpu_sem = true;
if (__this->draw_task_list) {
buffer_manager_free(__this->buffer_hdl);
__this->draw_task_list = 0;
}
/* 最后一个分块DMA拷贝完成,启动DBI推屏 */
__this->psram_last_buf = __this->psram_lcd_buf;
__this->psram_lcd_buf = __this->psram_buf_adr;
set_buffer_pend(__this->psram_buf_hdl, __this->psram_lcd_buf);
int err = 0;
int msg[32];
msg[0] = LCD_MSG_FLUSH;
msg[1] = LCD_FLUSH_KISTART;
msg[2] = 0;
msg[3] = __this->lcd_width - 1;
msg[4] = 0;
msg[5] = __this->lcd_height - 1;
msg[6] = (u32)__this->psram_buf_adr;
msg[7] = (u32)__this->psram_buf_hdl;
if (JLUI_LCD_RAMLESS_ENABLE == 0) {
set_buffer_used(__this->psram_buf_hdl, __this->psram_lcd_buf);
}
/* 启动推屏 */
err = os_taskq_post_type(LCD_TASK_NAME, msg[0], 8, &msg[1]);
if (err != OS_NO_ERR) {
printf("Error, post lcd flush msg failed!\n");
}
}
os_sem_post(&__this->buffer_sem); // 每推完一个分块,发送一个buf信号量
__this->buffer_hdl = NULL;
__this->buffer_adr = NULL;
}
}
static void psram_flush_buffer_start(void *buf_hdl, void *buf_adr, struct rect *rect, int is_continue)
{
/* 等待上一个buf推完 */
int os_err = os_sem_pend(&__this->buffer_sem, 100);
if (os_err) {
ASSERT(0, "%s os_err:%d\n", __func__, os_err);
}
/* put_buf(buf_adr, (x_end - x_start) * 2); */
//设置是否lcd最后一块,注意这里的位置要在同步之后,防止中断还没有起来
if (__this->gpu_line_end_flag) {
__this->lcd_draw_line_end_flag = 1;
}
/* 设置buf为使用状态,避免被其它地方使用 */
set_buffer_used(buf_hdl, buf_adr);
__this->buffer_hdl = buf_hdl;
__this->buffer_adr = buf_adr;
if (rect->width < __this->lcd_width) {
// 局部刷新
int length = rect->width * 2;
for (int line = 0; line < rect->height; line++) {
int offset = (line + rect->top) * __this->lcd_width * 2 + rect->left * 2;
u8 *psram_addr = (u8 *)((u32)__this->psram_buf_adr + offset);
u8 *input_addr = (u8 *)((u32)buf_adr + line * length);
/* printf("dst: 0x%x, src: 0x%x\n", (u32)psram_addr, (u32)input_addr); */
memcpy(psram_addr, input_addr, length);
/* dma_memcpy_sync(psram_addr, input_addr, length); */
}
dma_copy_callback(NULL);
} else {
// 全局刷新
int offset = rect->width * rect->top * 2;
int length = rect->width * rect->height * 2;
u8 *psram_addr = (u8 *)UI_PSRAM_CACHE_TO_NOCACHE((u32)__this->psram_buf_adr + offset);
dma_memcpy_async_with_callback(psram_addr, buf_adr, length, dma_copy_callback, NULL);
}
}
/* 释放PSRAM缓存,在LCD进入休眠时调用 */
void psram_frame_buf_release()
{
__this->release_frame_buf = true;
#if 0
if (__this->psram_buf_hdl) {
buffer_manager_free(__this->psram_buf_hdl);
__this->psram_buf_hdl = NULL;
__this->psram_buf_adr = NULL;
__this->psram_lcd_buf = NULL;
}
if (__this->psram_addr) {
free_psram(__this->psram_addr);
__this->psram_addr = NULL;
}
#endif
}
#endif
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_scheduler_wait_sync 等待GPU合成完毕
*
* @return 0 正常,-OS_TIMEOUT 等待超时
*/
/* ------------------------------------------------------------------------------------*/
int jlgpu_scheduler_wait_sync()
{
u32 rets;
__asm__ volatile("%0 = rets":"=r"(rets));
while (__this->gpu_is_busy && __this->wait_gpu_sem) {
/* printf("%s %d value:%d rets:%x", __func__, __LINE__, __this->gpu_sem.value, rets); */
if (os_sem_pend(&__this->gpu_sem, 50) == OS_TIMEOUT) {
__this->wait_gpu_sem = false;
log_error("%s(), wait GPU task run timeout!\n", __func__);
ASSERT(0);
return -OS_TIMEOUT;
}
}
return 0;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_scheduler_reset_dc_gpu_task_head 重置所有dc的任务链
*/
/* ------------------------------------------------------------------------------------*/
void jlgpu_scheduler_reset_dc_gpu_task_head()
{
if (JLUI_MULTI_PAGE_OVERLAY_SUPPORT) {
return;
}
pJLGPUMultTaskList_t gpu_mult_list_common = jlgpu_mult_task_list_get_common_root();
pJLGPUMultTaskList_t gpu_mult_list_shadow = jlgpu_mult_task_list_switch_root(gpu_mult_list_common);
struct element *root = ui_core_get_root();
struct element *elm;
list_for_each_child_element(elm, root) {
if (elm && elm->dc) {
u8 index = elm->dc->index;
pJLGPUTaskHead_t head_common = jlgpu_mult_task_head_by_index(gpu_mult_list_common, index);
pJLGPUTaskHead_t head_shadow = jlgpu_mult_task_head_by_index(gpu_mult_list_shadow, index);
if (elm->dc->gpu_task_head != head_common && head_shadow) {
elm->dc->gpu_task_head = head_shadow;
}
/* ASSERT(elm->dc->gpu_task_head); */
}
}
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_scheduler_set_redraw_mode 设置GPU任务的刷新模式
*
* @Params dc UI框架DC结构体
* @Params mode 刷新模式
*/
/* ------------------------------------------------------------------------------------*/
void jlgpu_scheduler_set_redraw_mode(struct draw_context *dc, gpu_redraw_mode_t mode)
{
if (mode != __this->redraw_mode) {
jlgpu_scheduler_wait_sync();
if (__this->redraw_mode == GPU_ASYN_REDRAW) {
/* 原先是异步刷新,现在要切换到同步刷新 */
dc->gpu_mult_list = __this->last_mult_list;
dc->gpu_task_head = jlgpu_mult_task_head_by_index(dc->gpu_mult_list, dc->index);
/* 由异步切换到同步模式时,清空影子组多任务链管理,减少RAM占用 */
jlgpu_mult_task_list_clr(jlgpu_mult_task_list_switch_root(dc->gpu_mult_list));
/* 更新dc指向的任务链 */
jlgpu_scheduler_reset_dc_gpu_task_head();
} else {
/* 原先是同步刷新,现在要切换到异步刷新 */
/* dc->gpu_mult_list = __this->mult_list; */
dc->gpu_mult_list = __this->last_mult_list;
dc->gpu_task_head = jlgpu_mult_task_head_by_index(dc->gpu_mult_list, dc->index);
/* 由同步切换到异步模式时,同步影子组多任务链管理,UI和GPU并行 */
jlgpu_mult_task_list_sync_shadow(dc->gpu_mult_list);
/* 更新dc指向的任务链 */
jlgpu_scheduler_reset_dc_gpu_task_head();
}
/* 设置当前刷新方式 */
__this->redraw_mode = mode;
}
}
int jlgpu_scheduler_get_redraw_mode()
{
return __this->redraw_mode;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_scheduler_create_mult_task_list 创建多任务链管理句柄
*
* @Params dc UI框架DC指针
*
* @return 多任务链管理句柄
*/
/* ------------------------------------------------------------------------------------*/
void *jlgpu_scheduler_create_mult_task_list(struct draw_context *dc)
{
/* 创建多任务链管理句柄 */
if (!__this->mult_list) {
__this->mult_list = jlgpu_mult_task_list_get_common_root();
}
/* 如果是同步刷新,则不需要创建多任务链管理句柄 */
if (__this->redraw_mode == GPU_SYNC_REDRAW) {
/* ASSERT(0); */
return __this->mult_list;
}
/* 等待GPU空闲,防止改到GPU正在使用的内容 */
jlgpu_scheduler_wait_sync();
/* 将GPU任务链添加到多任务链管理句柄 */
jlgpu_mult_task_list_add(__this->mult_list, dc->gpu_task_head, dc->index);
/* 同步影子多任务链管理句柄 */
jlgpu_mult_task_list_sync_shadow(__this->mult_list);
/* 更新dc指向的任务链 */
jlgpu_scheduler_reset_dc_gpu_task_head();
return (void *)__this->mult_list;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_scheduler_delete_mult_task_list 删除多任务链管理句柄
*
* @Params dc UI框架DC指针
*/
/* ------------------------------------------------------------------------------------*/
void jlgpu_scheduler_delete_mult_task_list(struct draw_context *dc)
{
/* 如果是同步刷新模式,只需删除当前的GPU任务链即可 */
if (__this->redraw_mode == GPU_SYNC_REDRAW) {
jlgpu_delete_task_list_head(dc->gpu_task_head);
return;
}
/* 清空GPU任务的队列消息 */
os_taskq_del_type(GPU_TASK_NAME, GPU_MSG_DRAW);
/* 等待GPU合成完成 */
jlgpu_scheduler_wait_sync();
if (JLUI_MULTI_PAGE_OVERLAY_SUPPORT) {
jlgpu_mult_task_list_del_by_index(__this->mult_list, dc->index);
} else {
/* 找到当前DC使用的GPU任务链 */
void *gpu_task_head;
gpu_task_head = jlgpu_mult_task_head_by_index(__this->mult_list, dc->index);
/* 从多任务链管理句柄删除当前的任务链 */
jlgpu_mult_task_list_del(__this->mult_list, gpu_task_head);
/* 删除当前的GPU任务链 */
jlgpu_delete_task_list_head(gpu_task_head);
}
/* 同步影子多任务链管理句柄 */
jlgpu_mult_task_list_sync_shadow(__this->mult_list);
/* 更新dc指向的任务链 */
jlgpu_scheduler_reset_dc_gpu_task_head();
}
#if (defined TCFG_PSRAM_DEV_ENABLE && TCFG_PSRAM_DEV_ENABLE)
void psram_double_buffer_init()
{
if (!__this->psram_addr) {
int psram_buf_size = __this->lcd_width * __this->lcd_height * 2 * 2; // 申请PSRAM两个帧缓存buf
__this->psram_addr = malloc_psram(psram_buf_size);
if (!__this->psram_buf_hdl) {
buffer_manager_init(__this->psram_buf_hdl, __this->psram_addr, psram_buf_size, 2); // 创建buf管理句柄
}
}
__this->release_frame_buf = false;
}
#endif
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_scheduler_kick_start 启动GPU合成并调用DBI刷新
*
* @Params mult_list 需合成的多任务链管理句柄
* @Params dc UI框架的DC指针
*
* @return 0 正常合成,其它 合成失败
*/
/* ------------------------------------------------------------------------------------*/
static int jlgpu_scheduler_kick_start(pJLGPUMultTaskList_t mult_list, struct draw_context *dc)
{
//释放无效的gpu_cache_ram
jlgpu_scheduler_async_gpu_cache_free();
/* gpu_input_stream_cache_clr_all_invaild(); */
//合成前需要重置jpeg
jpeg_module_opj_invaild_clr();
/* jljpeg_decode_reset_curr(); */
/* 防止出现野指针进入 */
if (!jlgpu_mult_task_list_check(mult_list)) {
log_error("%s(), unknow mult GPU task list: 0x%p, not run!\n", __func__, mult_list);
return -1;
}
/* 记录当前GPU合成的多任务链管理句柄 */
__this->last_mult_list = mult_list;
/* 获取当前需要刷新的GPU任务链 */
void *gpu_task_head = jlgpu_mult_task_head_by_index(mult_list, dc->index);
/* 如果没找到任务链,则退出 */
if (!gpu_task_head) {
return -1;
}
#if TCFG_VIDEO_DIAL_ENABLE
avi_gpu_scheduler_kick_start(gpu_task_head);
#endif
__this->gpu_is_busy = true;
__this->wait_gpu_sem = true;
/* printf("@@@@@ draw mult_list: 0x%p, task_head: 0x%p, index: %d\n", mult_list, gpu_task_head, dc->index); */
/* printf("@@@@@ draw_state: %d\n", dc->draw_state); */
/* jlgpu_dump_all_task(gpu_task_head, __func__, __LINE__); */
/* Get draw area. */
struct rect refresh_rect;
if (JLUI_LCD_RAMLESS_ENABLE) {
refresh_rect.left = 0;
refresh_rect.top = 0;
refresh_rect.width = __this->lcd_width;
refresh_rect.height = __this->lcd_height;
} else {
struct rect lcd_rect;
lcd_rect.left = 0;
lcd_rect.top = 0;
lcd_rect.width = __this->lcd_width;
lcd_rect.height = __this->lcd_height;
if (!get_rect_cover(&dc->rect_orig, &lcd_rect, &refresh_rect)) {
ASSERT(0);
}
}
/* 如果是左右划屏时,刷新区域强制从0坐标开始 */
if (dc->draw_state == GPU_SYNTHESIS) {
refresh_rect.left = 0;
refresh_rect.top = 0;
}
/* 是否对GPU任务链进行重新排序 */
if (!dc->gpu_task_dont_sort) {
jlgpu_task_list_reorder(gpu_task_head);
}
/* DUMP_RECT(__func__, __LINE__, "refresh_rect", &refresh_rect); */
int width = refresh_rect.width; // 刷新宽度
int height = refresh_rect.height; // 刷新高度
int block_height = dc->lines; // 分块高度
/* If refresh dirty block, adjust block height. */
#if 0 //局部刷新暂不动态调整高度
if (width < dc->width) {
log_debug("%s(), Dirty block refresh, adjust block height!\n", __func__);
block_height = (dc->width * dc->lines) / width;
}
log_info("%s(), block_height: %d\n", __func__, block_height);
#endif
/* Calculation block number. */
int block_number = (height % block_height) ? ((height / block_height) + 1) : (height / block_height);
log_info("%s(), block_number: %d\n", __func__, block_number);
#if TCFG_LCD_BUF_DYNAMIC_LINE_ENABLE
int buf_num = 2;
int refresh_stride = (width * gpu_get_format_bpp(GPU_OUT_FORMAT_RGB565) + 7) / 8;
int check_line = jlgpu_lcd_buf_line_get(xPortGetPhysiceMemorySize(), refresh_stride, buf_num, block_height, height);
if (!check_line) {
log_error("not enough disp_buf ,pass this frame!!!\n");
__this->gpu_is_busy = false;
__this->wait_gpu_sem = false;
return -1;
}
#endif
if (JLUI_GPU_DMA_TO_PSRAM) {
#if (defined TCFG_PSRAM_DEV_ENABLE && TCFG_PSRAM_DEV_ENABLE)
psram_double_buffer_init();
if (width < __this->lcd_width || height < __this->lcd_height) {
if (__this->psram_buf_adr) {
wait_buf_to_idle(__this->psram_buf_hdl, __this->psram_buf_adr); // 局部刷新,已经有buf,等待buf空闲
} else {
__this->psram_buf_adr = get_idle_buf_by_handler(__this->psram_buf_hdl); // 局部刷新,还没有buf,获取空闲buf
}
} else {
__this->psram_buf_adr = get_idle_buf_by_handler(__this->psram_buf_hdl); // 全屏刷新,直接获取空闲buf实现乒乓
}
#endif
} else {
/* Set lcd draw area. */
lcd_set_draw_area(refresh_rect.left, (refresh_rect.left + width - 1), refresh_rect.top, (refresh_rect.top + height - 1));
}
#if TCFG_LCD_BUF_DYNAMIC_LINE_ENABLE
ASSERT(!__this->disp_hdl);
int buffer_alloc_adr_len = buf_num * check_line * refresh_stride;
__this->disp_adr = jlui_malloc(buffer_alloc_adr_len, UI_RAM_SRAM, UI_MODULE_BUFFER);
ASSERT(__this->disp_adr);
buffer_manager_init(__this->disp_hdl, __this->disp_adr, buffer_alloc_adr_len, buf_num);
block_height = check_line;
block_number = (height % block_height) ? ((height / block_height) + 1) : (height / block_height);
void *buffer_hdl = __this->disp_hdl;
#else
void *buffer_hdl = dc->buffer_hdl;
#endif
int draw_height;
struct rect draw_rect = {0};
__this->gpu_line_end_flag = 0; // 最后一块标志初始为0
//特效准备
struct ui_page_priv *page_ctrl = ui_page_get_param();
struct ui_page_draw page_draw = {0};
if ((dc->draw_state == GPU_SYNTHESIS) && (dc->index == 0)) {
struct ui_effect_module *effmod_hd = ui_effect_get_handle_by_style(page_ctrl->mode);
if (effmod_hd && effmod_hd->effect_draw) {
effmod_hd->effect_draw(mult_list, &page_draw);
}
}
u8 *argb8565_buf = NULL; //子链缓存buf
pJLGPUTaskHead_t sub_head = NULL; //子任务链头
u32 *addr_buf = NULL; //group任务地址信息
int group_num = 0; //group数量
if (dc->draw_state == GPU_DRAW_EACH_GROUP) {
//创建子任务链头
sub_head = jlgpu_create_task_list_head();
jlgpu_set_task_list_out_format(sub_head, GPU_OUT_FORMAT_ARGB8565);
//申请子任务链输出空间
int out_stride = (width * gpu_get_format_bpp(GPU_OUT_FORMAT_ARGB8565) + 7) / 8;
int argb8565_buf_len = out_stride * block_height;
argb8565_buf = zalloc(argb8565_buf_len);
//遍历group数量
pJLGPUTaskUnit_t sub_taskp_curr = jlgpu_task_find_first_task(gpu_task_head);
pJLGPUTaskUnit_t sub_taskp_last = sub_taskp_curr;
while (sub_taskp_curr) {
if ((sub_taskp_curr->info.group != sub_taskp_last->info.group) || (jlgpu_find_next_task(sub_taskp_curr) == NULL)) {
group_num ++;
}
sub_taskp_last = sub_taskp_curr;
sub_taskp_curr = jlgpu_find_next_task(sub_taskp_curr);
}
//记录每个group的第一个和最后一个任务的地址
addr_buf = zalloc(2 * group_num * sizeof(int));
int addr_offset = 0;
sub_taskp_curr = jlgpu_task_find_first_task(gpu_task_head);
sub_taskp_last = sub_taskp_curr;
while (sub_taskp_curr) {
if ((sub_taskp_curr->info.group != sub_taskp_last->info.group) || (jlgpu_find_next_task(sub_taskp_curr) == NULL)) {
//前个group的尾
void *task_addr_last = jlgpu_unit_to_instruction(sub_taskp_last);
//后个group的头
void *task_addr_curr = jlgpu_unit_to_instruction(sub_taskp_curr);
addr_buf[addr_offset] = (u32)task_addr_last;
addr_buf[addr_offset + 1] = (u32)task_addr_curr;
addr_offset += 2;
}
sub_taskp_last = sub_taskp_curr;
sub_taskp_curr = jlgpu_find_next_task(sub_taskp_curr);
}
}
/* printf("@@@@@ list_total: %d\n", list_total); */
/* 开始分块合成并推屏 */
for (int i = 0; i < block_number; i++) {
/* 刷新最后一个分块时,最后一块标志为1 */
if (i == (block_number - 1)) {
__this->gpu_line_end_flag = 1;
}
/* Calculation current draw block height. */
if ((i + 1) * block_height < height) {
draw_height = block_height;
} else {
draw_height = height - (i * block_height);
}
/* Move to dirty block area. */
draw_rect.left = refresh_rect.left + 0;
draw_rect.top = refresh_rect.top + i * block_height;
draw_rect.width = width;
draw_rect.height = draw_height;
/* DUMP_RECT(__func__, __LINE__, "draw_rect", &draw_rect); */
if (dc->draw_state == GPU_SYNTHESIS_AND_DRAW) {
/* 普通页面合成并刷新 */
u8 *idle_buf = get_idle_buf_by_handler(buffer_hdl);
/* 清空缓存buf */
memset(idle_buf, 0, draw_rect.width * draw_rect.height * 2);
if (JLUI_MULTI_PAGE_OVERLAY_SUPPORT) {
int n;
int bottom_page_exist = 0;
int num = jlgpu_mult_task_list_get(mult_list, NULL);
int *index_tab = (int *)malloc(num * sizeof(int));
jlgpu_mult_task_list_get(mult_list, index_tab);
int bottom_page_num = ui_multi_page_get_index_by_prio(PAGE_PRIO_BOTTOM, NULL);
if (bottom_page_num > 0) {
int *bottom_page_tab = (int *)malloc(bottom_page_num * sizeof(int));
ASSERT(bottom_page_tab);
ui_multi_page_get_index_by_prio(PAGE_PRIO_BOTTOM, bottom_page_tab);
for (n = 0; n < bottom_page_num; n++) {
pJLGPUTaskHead_t task_head = jlgpu_mult_task_head_by_index(mult_list, bottom_page_tab[n]);
if (task_head) {
bottom_page_exist = 1;
jlgpu_set_task_list_out_buf(task_head, idle_buf, &draw_rect, 0, 0);
jlgpu_task_list_run(task_head);
}
}
free(bottom_page_tab);
}
for (n = 0; n < num; n++) {
if (!ui_multi_page_check_index(index_tab[n])) {
pJLGPUTaskHead_t task_head = jlgpu_mult_task_head_by_index(mult_list, index_tab[n]);
if (task_head) {
if (bottom_page_exist) {
jlgpu_task_enable_by_id(task_head, 0, 0, 0);
jlgpu_task_layer_enable(task_head, 0);
}
/* 设置GPU任务链合成区域和输出buf */
jlgpu_set_task_list_out_buf(task_head, idle_buf, &draw_rect, 0, 0);
/* 启动GPU合成 */
jlgpu_task_list_run(task_head);
}
}
}
int top_page_num = ui_multi_page_get_index_by_prio(PAGE_PRIO_TOP, NULL);
if (top_page_num > 0) {
int *top_page_tab = (int *)malloc(top_page_num * sizeof(int));
ASSERT(top_page_tab);
ui_multi_page_get_index_by_prio(PAGE_PRIO_TOP, top_page_tab);
for (n = 0; n < top_page_num; n++) {
pJLGPUTaskHead_t task_head = jlgpu_mult_task_head_by_index(mult_list, top_page_tab[n]);
if (task_head) {
jlgpu_task_enable_by_id(task_head, 0, 0, 0);
jlgpu_task_layer_enable(task_head, 0);
jlgpu_set_task_list_out_buf(task_head, idle_buf, &draw_rect, 0, 0);
jlgpu_task_list_run(task_head);
}
}
free(top_page_tab);
}
free(index_tab);
} else {
/* 设置GPU任务链合成区域和输出buf */
jlgpu_set_task_list_out_buf(gpu_task_head, idle_buf, &draw_rect, 0, 0);
/* 启动GPU合成 */
jlgpu_task_list_run(gpu_task_head);
}
/* 设置缓存buf为等待状态,等待DBI模块推屏 */
set_buffer_pend(buffer_hdl, idle_buf);
/* 启动DBI模块推屏 */
if (JLUI_GPU_DMA_TO_PSRAM) {
#if (defined TCFG_PSRAM_DEV_ENABLE && TCFG_PSRAM_DEV_ENABLE)
psram_flush_buffer_start(buffer_hdl, idle_buf, &draw_rect, i);
#endif
} else {
lcd_flush_buffer_start(buffer_hdl, idle_buf, &draw_rect, i);
}
} else if (dc->draw_state == GPU_SYNTHESIS) {
/* 划屏时合成并刷新 */
u8 *idle_buf = get_idle_buf_by_handler(buffer_hdl);
memset(idle_buf, 0, draw_rect.width * draw_rect.height * 2);
pJLGPUTaskHead_t dc_head = gpu_task_head;
int out_bpp = gpu_get_format_bpp(dc_head->out_param.format) / 8;
int out_stride = width * out_bpp;
if (page_draw.new_task_list) { //重排链表
int bottom_page_exist = 0;
int n;
if (JLUI_MULTI_PAGE_OVERLAY_SUPPORT) {
int bottom_page_num = ui_multi_page_get_index_by_prio(PAGE_PRIO_BOTTOM, NULL);
if (bottom_page_num > 0) {
int *bottom_page_tab = (int *)malloc(bottom_page_num * sizeof(int));
ASSERT(bottom_page_tab);
ui_multi_page_get_index_by_prio(PAGE_PRIO_BOTTOM, bottom_page_tab);
for (n = 0; n < bottom_page_num; n++) {
pJLGPUTaskHead_t task_head = jlgpu_mult_task_head_by_index(mult_list, bottom_page_tab[n]);
if (task_head) {
bottom_page_exist = 1;
jlgpu_set_task_list_out_buf(task_head, idle_buf, &draw_rect, 0, 0);
jlgpu_task_list_run(task_head);
}
}
free(bottom_page_tab);
}
}
for (int idx = 0; idx < page_draw.list_total; idx++) {
pJLGPUTaskHead_t head = (pJLGPUTaskHead_t)page_draw.new_task_list[idx];
page_draw.rec_gpu_rect[idx].top = draw_rect.top;
page_draw.rec_gpu_rect[idx].height = draw_rect.height;
if (page_ctrl->mode > 2) {
if (page_draw.new_list_create & BIT(idx)) {
jlgpu_set_task_list_out_buf(head, idle_buf, &page_draw.rec_gpu_rect[idx], page_draw.rec_gpu_rect[idx].left, out_stride);
} else {
jlgpu_set_task_list_out_buf(head, idle_buf, &page_draw.rec_gpu_rect[idx], page_draw.rec_lcd_rect[idx].left, out_stride);
}
} else {
struct rect block_r;
block_r.top = draw_rect.top;
block_r.width = page_draw.rec_gpu_rect[idx].width;
block_r.height = draw_rect.height;
block_r.left = page_draw.rec_gpu_rect[idx].left + draw_rect.left - page_draw.rec_lcd_rect[idx].left;
if (block_r.left < 0) {
block_r.width = draw_rect.width;
}
jlgpu_set_task_list_out_buf(head, idle_buf, &block_r, 0, out_stride);
}
if (bottom_page_exist) {
jlgpu_task_enable_by_id(head, 0, 0, 0);
jlgpu_task_layer_enable(head, 0);
}
jlgpu_task_list_run(head);
}
if (JLUI_MULTI_PAGE_OVERLAY_SUPPORT) {
int top_page_num = ui_multi_page_get_index_by_prio(PAGE_PRIO_TOP, NULL);
if (top_page_num) {
int *top_page_tab = (int *)malloc(top_page_num * sizeof(int));
ASSERT(top_page_tab);
ui_multi_page_get_index_by_prio(PAGE_PRIO_TOP, top_page_tab);
for (n = 0; n < top_page_num; n++) {
pJLGPUTaskHead_t task_head = jlgpu_mult_task_head_by_index(mult_list, top_page_tab[n]);
if (task_head) {
jlgpu_task_enable_by_id(task_head, 0, 0, 0);
jlgpu_task_layer_enable(task_head, 0);
jlgpu_set_task_list_out_buf(task_head, idle_buf, &draw_rect, 0, 0);
jlgpu_task_list_run(task_head);
}
}
free(top_page_tab);
}
}
}
set_buffer_pend(buffer_hdl, idle_buf);
if (JLUI_GPU_DMA_TO_PSRAM) {
#if (defined TCFG_PSRAM_DEV_ENABLE && TCFG_PSRAM_DEV_ENABLE)
psram_flush_buffer_start(buffer_hdl, idle_buf, &draw_rect, i);
#endif
} else {
lcd_flush_buffer_start(buffer_hdl, idle_buf, &draw_rect, i);
}
} else if (dc->draw_state == GPU_DRAW_EACH_GROUP) {
//获取分块buf
u8 *idle_buf = get_idle_buf_by_handler(buffer_hdl);
sub_head->gpu_task_base_adr = ((pJLGPUTaskHead_t)gpu_task_head)->gpu_task_base_adr;
jlgpu_set_task_list_out_buf(sub_head, argb8565_buf, &draw_rect, 0, 0);
for (int group_i = 0; group_i < group_num; group_i++) {
void *task_addr_last = (void *)addr_buf[2 * group_i];
void *task_addr_curr = (void *)addr_buf[2 * group_i + 1];
//断开任务链
gpu_task_add_to_next(task_addr_last, NULL);
//合成当前group
jlgpu_task_list_run(sub_head);
//blend
jlui_argb8565_to_rgb565(idle_buf, &draw_rect, argb8565_buf, &draw_rect);
//断链重连
gpu_task_add_to_next(task_addr_last, task_addr_curr);
//指向下一个group
sub_head->gpu_task_base_adr = task_addr_curr;
}
//输出
/* 设置缓存buf为等待状态,等待DBI模块推屏 */
set_buffer_pend(buffer_hdl, idle_buf);
/* 启动DBI模块推屏 */
lcd_flush_buffer_start(buffer_hdl, idle_buf, &draw_rect, i);
}
}
if (argb8565_buf) {
free(argb8565_buf);
}
if (sub_head) {
sub_head->gpu_task_base_adr = NULL;//只释放表头
jlgpu_delete_task_list_head(sub_head);
}
if (addr_buf) {
free(addr_buf);
}
for (int i = 0; i < page_draw.list_total; i++) {
if (page_draw.new_list_create & BIT(i)) {
if (page_draw.normal_list_flag & BIT(i)) {
jlgpu_delete_task_list_head(page_draw.new_task_list[i]);
} else {
jlgpu_task_list_copy_destroy(page_draw.new_task_list[i]);
}
}
}
if (page_draw.new_task_list) {
free(page_draw.new_task_list);
}
if (page_draw.rec_gpu_rect) {
free(page_draw.rec_gpu_rect);
}
if (page_draw.rec_lcd_rect) {
free(page_draw.rec_lcd_rect);
}
if (page_draw.rec_page_rect) {
free(page_draw.rec_page_rect);
}
if ((__this->redraw_mode == GPU_ASYN_REDRAW) && (dc->draw_state == GPU_SYNTHESIS_AND_DRAW)) { //同步刷新不释放
/* gpu_input_stream_cache_vaild_sub(); */
if (dc->index >= 2) {
/*
若top层设计复杂,请使用全局刷新
*/
gpu_input_stream_cache_vaild_sub_by_index(dc->index);
} else {
if ((__this->lcd_height == refresh_rect.height) && (__this->lcd_width == refresh_rect.width)) {
gpu_input_stream_cache_vaild_sub_by_index(dc->index);
} else {
/*
局部刷新不释放资源
主要针对一些通用数字更新场景。比如时间自刷新、更新心率、步数数值等。
若有个别图片需要切换的内容过多、且资源较大时,请刷新全屏
否则psram缓存不下触发异常。
*/
}
}
}
jpeg_module_opj_set_invaild_by_index(dc->index);
if (JLJPEG_STREAM_ENABLE) {
jljpeg_stream_src_data_unlock();
}
__this->gpu_is_busy = false;
/* os_sem_post(&__this->gpu_sem); */
if (JLUI_MULTI_PAGE_OVERLAY_SUPPORT) {
async_buffer_clr();
}
return 0;
}
void *jlgpu_scheduler_draw_mult_task_list(struct draw_context *dc)
{
pJLGPUMultTaskList_t mult_list = dc->gpu_mult_list;
pJLGPUMultTaskList_t next_mult = NULL;
if (__this->redraw_mode == GPU_ASYN_REDRAW) {
/* 获取多任务链管理影子组句柄,并将DC指针的多任务链管理、GPU任务链替换为影子组 */
if (JLUI_MULTI_PAGE_OVERLAY_SUPPORT) {
jlgpu_scheduler_wait_sync();
next_mult = jlgpu_mult_task_list_switch_root(mult_list);
dc->gpu_task_head = jlgpu_mult_task_head_idle_by_index(next_mult, dc->index, dc->gpu_task_head);
dc->gpu_mult_list = next_mult;
__this->mult_list = next_mult;
if ((dc->draw_state == GPU_SYNTHESIS) && (dc->index)) {
return next_mult;
}
} else {
next_mult = jlgpu_mult_task_list_switch_root(mult_list);
dc->gpu_task_head = jlgpu_mult_task_head_by_index(next_mult, dc->index);
dc->gpu_mult_list = next_mult;
__this->mult_list = next_mult;
if ((dc->draw_state == GPU_SYNTHESIS) && (dc->index)) {
return next_mult;
}
jlgpu_scheduler_wait_sync();
}
int err;
int msg[32];
msg[0] = GPU_MSG_DRAW;
msg[1] = (int)dc->index;
msg[2] = (int)mult_list;
msg[3] = 0;
/* 同步DC指针内容 */
memcpy(&__this->dc, dc, sizeof(struct draw_context));
/* 发送队列消息到GPU系统任务,由GPU系统任务调度GPU启动合成 */
err = os_taskq_post_type(GPU_TASK_NAME, msg[0], 2, &msg[1]);
if (err != OS_NO_ERR) {
ASSERT(0);
return NULL;
}
return next_mult;
} else {
if ((dc->draw_state == GPU_SYNTHESIS) && (dc->index)) {
return dc->gpu_mult_list;
}
/* 串行刷新时,直接调用GPU合成接口 */
jlgpu_scheduler_kick_start(dc->gpu_mult_list, dc);
return dc->gpu_mult_list;
}
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief gpu_status 获取GPU当前状态,判断GPU是否空闲
*
*/
/* ------------------------------------------------------------------------------------*/
int gpu_status()
{
return __this->gpu_is_busy;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_scheduler_draw_task_list 绘制指定GPU任务链并推屏
*
* @Params head 待绘制的GPU任务链
* @Params disp_buf 显存buf
* @Params disp_buf_size 显存buf大小
*/
/* ------------------------------------------------------------------------------------*/
static void jlgpu_scheduler_draw_task_list(pJLGPUTaskHead_t head, void *disp_buf, int disp_buf_size)
{
/* printf("%s(), head: 0x%x, disp_buf: 0x%x, buf_size: %d\n", __func__, (u32)head, (u32)disp_buf, disp_buf_size); */
/* jlgpu_dump_all_task(head, __func__, __LINE__); */
/* GPU 任务链绘制区域 */
struct rect *win_rect = &head->win_rect;
/* printf("draw rect[%d, %d, %d, %d]\n", win_rect->left, win_rect->top, win_rect->width, win_rect->height); */
int out_format = head->out_param.format;
int bpp_byte = gpu_task_get_format_bpp(out_format) >> 3;
/* 计算分块高度 */
int block_buf_size = disp_buf_size >> 1;
int block_height = block_buf_size / (win_rect->width * bpp_byte);
/* printf("block_height: %d\n", block_height); */
/* 计算分块数量 */
int block_number = (win_rect->height % block_height) ? ((win_rect->height / block_height) + 1) : (win_rect->height / block_height);
/* printf("block_number: %d\n", block_number); */
/* 等待GPU空闲 */
jlgpu_scheduler_wait_sync();
/* 准备buf管理句柄,推屏结束后释放 */
void *buf_hdl = NULL;
#if TCFG_LCD_BUF_DYNAMIC_LINE_ENABLE
if (!disp_buf) {
__this->disp_adr = jlui_malloc(disp_buf_size, UI_RAM_SRAM, UI_MODULE_BUFFER);
disp_buf = __this->disp_adr;
}
#endif
buffer_manager_init(buf_hdl, disp_buf, disp_buf_size, 2);
/* 配置GPU渲染参数 */
int draw_height;
struct rect draw_rect = {0};
#if (defined TCFG_PSRAM_DEV_ENABLE && TCFG_PSRAM_DEV_ENABLE)
if (JLUI_GPU_DMA_TO_PSRAM) {
psram_double_buffer_init();
if (win_rect->width < __this->lcd_width || win_rect->height < __this->lcd_height) {
if (__this->psram_buf_adr) {
wait_buf_to_idle(__this->psram_buf_hdl, __this->psram_buf_adr); // 局部刷新,已经有buf,等待buf空闲
} else {
__this->psram_buf_adr = get_idle_buf_by_handler(__this->psram_buf_hdl); // 局部刷新,还没有buf,获取空闲buf
}
} else {
__this->psram_buf_adr = get_idle_buf_by_handler(__this->psram_buf_hdl); // 全屏刷新,直接获取空闲buf实现乒乓
}
#else
if (0) {
#endif
} else {
lcd_set_draw_area(win_rect->left, (win_rect->left + win_rect->width - 1), win_rect->top, (win_rect->top + win_rect->height - 1));
}
//等待dbi空闲再赋值,避免和推屏回调冲突
__this->gpu_is_busy = true;
__this->wait_gpu_sem = true;
__this->gpu_line_end_flag = false;
__this->draw_task_list = true; // 绘制GPU任务链标志,用于释放buf管理句柄判断
for (int i = 0; i < block_number; i++) {
if ((i + 1) * block_height < win_rect->height) {
draw_height = block_height;
} else {
draw_height = win_rect->height - (i * block_height);
__this->gpu_line_end_flag = true;
}
draw_rect.left = win_rect->left + 0;
draw_rect.top = win_rect->top + i * block_height;
draw_rect.width = win_rect->width;
draw_rect.height = draw_height;
/* printf("draw rect [%d, %d, %d, %d]\n", draw_rect.left, draw_rect.top, draw_rect.width, draw_rect.height); */
u8 *idle_buf = get_idle_buf_by_handler(buf_hdl);
memset(idle_buf, 0x00, block_buf_size);
jlgpu_set_task_list_out_buf(head, idle_buf, &draw_rect, 0, 0);
jlgpu_task_list_run(head);
set_buffer_pend(buf_hdl, idle_buf);
#if (defined TCFG_PSRAM_DEV_ENABLE && TCFG_PSRAM_DEV_ENABLE)
if (JLUI_GPU_DMA_TO_PSRAM) {
psram_flush_buffer_start(buf_hdl, idle_buf, &draw_rect, i);
#else
if (0) {
#endif
} else {
lcd_flush_buffer_start(buf_hdl, idle_buf, &draw_rect, i);
}
}
__this->gpu_is_busy = false;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_task GPU 异步合成任务
*
* @Params p
*/
/* ------------------------------------------------------------------------------------*/
static void jlgpu_task(void *p)
{
int ret;
int msg[32] = {0};
while (1) {
/* 等待消息队列 */
ret = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
if (ret != OS_TASKQ) {
continue;
}
switch (msg[0]) {
case GPU_MSG_DRAW:
/* 如果接收到绘制消息,启动GPU合成 */
IO_GPU_HIGH();
pJLGPUMultTaskList_t mult_list = (pJLGPUMultTaskList_t)msg[2];
jlgpu_scheduler_kick_start(mult_list, &__this->dc);
break;
case GPU_MSG_DUMP:
/* 将SRAM的数据转储到PSRAM,并将行排列转换为块排列 */
/* 参数顺序:dst, src, w, h, format, buf_hdl */
/* printf("dump data dst: 0x%x, src: 0x%x, w: %d, h: %d, fmt: %d\n", msg[1], msg[2], msg[3], msg[4], msg[5]); */
texture_line_to_tile_base((void *)msg[1], (void *)msg[2], msg[3], msg[4], msg[5]);
set_buffer_idle((void *)msg[6], (void *)msg[2]);
break;
case GPU_MSG_DRAW_LIST:
pJLGPUTaskHead_t head = (pJLGPUTaskHead_t)msg[1];
void *disp_buf = (void *)msg[2];
int disp_buf_size = msg[3];
jlgpu_scheduler_draw_task_list(head, disp_buf, disp_buf_size);
break;
case GPU_MSG_OTHER:
break;
default:
break;
}
}
}
static void gpu_load_data_cb(void *priv, void *dst, void *src, int len)
{
/* printf("%s(), priv: 0x%x, dst: 0x%x, src: 0x%x, len: %d\n", __func__, (u32)priv, (u32)dst, (u32)src, len); */
UI_RESFILE *fp = (UI_RESFILE *)priv;
res_fseek(fp, (u32)src, SEEK_SET);
res_fread(fp, dst, len);
if (GPU_INPUT_TO_NOCACHE) {
if (UI_ADDR_IN_PSRAM_CACHE(dst)) {
psram_flush_cache(dst, len);
}
}
}
void jlgpu_scheduler_init(
void *(*malloc)(int, u32, u32),
void (*free)(void *, u32, u32),
u16 lcd_width, u16 lcd_height)
{
__this->lcd_width = lcd_width;
__this->lcd_height = lcd_height;
lcd_draw_set_callback(lcd_flush_finish_cb); // 设置lcd推屏结束回调
/* 初始化GPU模块 */
jlgpu_module_init(malloc, free, __this->lcd_width, __this->lcd_height);
int jpeg_module_init();
jpeg_module_init();
if (config_gpu_cache_psram_jpeg_en || config_gpu_cache_psram_file_res_en) {
gpu_input_stream_cache_set_alloc_cb(malloc, free);
gpu_input_stream_cache_init(gpu_load_data_cb, jlgpu_scheduler_async_free_buf);
} else {
gpu_input_stream_cache_set_alloc_cb(malloc, free);
gpu_input_stream_cache_init(NULL, jlgpu_scheduler_async_free_buf);
}
/* 默认使用的多任务链管理句柄 */
__this->mult_list = jlgpu_mult_task_list_get_common_root();
/* 创建GPU任务 */
task_create(jlgpu_task, NULL, GPU_TASK_NAME);
#if (defined TCFG_PSRAM_DEV_ENABLE && TCFG_PSRAM_DEV_ENABLE)
task_create(jllcd_task, NULL, LCD_TASK_NAME);
#endif
/* 创建同步信号量 */
os_sem_create(&__this->gpu_sem, 1);
os_sem_create(&__this->lcd_te_sem, 1);
os_sem_create(&__this->buffer_sem, 1);
os_sem_create(&__this->buf_idle_sem, 1);
/* 初始化标志 */
__this->has_init = true;
/* 默认开异步刷新 */
__this->redraw_mode = GPU_ASYN_REDRAW;
__this->gpu_is_busy = false;
}
void jlgpu_scheduler_free()
{
jlgpu_module_free();
if (config_gpu_cache_psram_jpeg_en || config_gpu_cache_psram_file_res_en) {
gpu_input_stream_cache_free();
}
__this->has_init = false;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_create_task_list_by_psram_img 将PSRAM中缓存的帧buf作为图片创建GPU指令链表
*
* @Params psram_img PSRAM中缓存的图片地址
* @Params format PSRAM中缓存的图片数据格式,一般为RGB565格式
* @Params img_w PSRAM中缓存的帧数据宽度(页面原来的宽度)
* @Params img_h PSRAM中欢度的帧数据高度(页面原来的高度)
*
* @return GPU任务链
*/
/* ------------------------------------------------------------------------------------*/
pJLGPUTaskHead_t jlgpu_create_task_list_by_psram_img(void *psram_img, int format, int img_w, int img_h)
{
pJLGPUTaskHead_t head = jlgpu_create_task_list_head();
jlgpu_set_task_list_out_format(head, format);
jlgpu_task_texture_param_init(1, 1);
task_param.format = GPU_FORMAT_RGB565;
task_param.image.width = (img_w + 7) / 8 * 8;
task_param.image.height = (img_h + 7) / 8 * 8;
task_param.draw.left = 0;
task_param.draw.top = 0;
task_param.draw.width = task_param.image.width;
task_param.draw.height = task_param.image.height;
jlgpu_get_win_rect(&task_param.area);
task_param.texture.not_compress = true;
task_param.texture.data = (u8 *)((u32)psram_img - 0x04000000); // 转为nocache地址
task_param.texture.adr_mode = 0; // 使用块排列
/* 计算裁剪参数 */
if ((task_param.image.width != img_w) || (task_param.image.height != img_h)) {
task_param.crop_en = true;
task_param.texture.crop.left = 0;
task_param.texture.crop.top = 0;
task_param.texture.crop.width = img_w;
task_param.texture.crop.height = img_h;
}
jlgpu_update_task_by_id(head, 1, 1, &task_param);
return head;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlgpu_task_list_dump_to_psram GPU任务链合成并转储到PSRAM块排列缓存
*
* @Params head 待合成的GPU任务链
* @Params w 页面宽度
* @Params h 页面高度
* @Params disp_buf LCD配置的显存buf,用显存作为GPU合成输出缓存,加快合成速度
* @Params disp_buf_size LCD配置的显存buf大小
*
* @return 转储到PSRAM后的帧buf地址
*/
/* ------------------------------------------------------------------------------------*/
void *jlgpu_task_list_dump_to_psram(pJLGPUTaskHead_t head, int w, int h, void *disp_buf, int disp_buf_size)
{
/* 获取GPU任务链输出格式 */
int out_format = head->out_param.format;
/* 宽高做8对齐 */
int out_w = ((w + 7) >> 3) << 3;
int out_h = ((h + 7) >> 3) << 3;
/* 计算需要使用的PSRAM缓存大小 */
int out_size = (gpu_task_get_format_bpp(out_format) * out_w * out_h) >> 3;
/* 申请PSRAM输出缓存 */
void *out_addr = malloc_psram(out_size);
ASSERT(out_addr, "Error, malloc psram block stroge faild! size: %d\n", out_size);
/* return NULL; // 申请内存失败,说明内存不够缓存一帧了 */
/* 准备buf管理句柄 */
void *buf_hdl;
#if TCFG_LCD_BUF_DYNAMIC_LINE_ENABLE
if (!disp_buf) {
__this->disp_adr = jlui_malloc(disp_buf_size, UI_RAM_SRAM, UI_MODULE_BUFFER);
disp_buf = __this->disp_adr;
}
#endif
buffer_manager_init(buf_hdl, disp_buf, disp_buf_size, 2);
/* 根据显存大小,重新计算分块高度,并将高度调整到向下8对齐 */
// 注意,这里直接将输出设定为RGB565
int block_h = disp_buf_size / 2 / 2 / w / 8 * 8;
int draw_h = block_h;
/* 计算分块数量,向上取整 */
int block_num = (h + block_h - 1) / block_h;
int msg[32];
msg[0] = GPU_MSG_DUMP;
struct rect draw_rect = {0};
/* time_count_start(3); */
/* 分块合成,并分块将输出转储到PSRAM块排列方式 */
for (int i = 0; i < block_num; i++) {
if (i == (block_num - 1)) {
draw_h = h - (i * block_h); // 最后一个分块调整高度
}
draw_rect.left = 0;
draw_rect.top = i * block_h;
draw_rect.width = w;
draw_rect.height = draw_h;
/* 获取空闲buf */
u8 *idle_buf = get_idle_buf_by_handler(buf_hdl);
memset(idle_buf, 0, draw_rect.width * draw_rect.height * 2);
jlgpu_set_task_list_out_buf(head, idle_buf, &draw_rect, 0, 0);
jlgpu_task_list_run(head);
/* 将合成好的分块post到GPU任务转储到PSRAM */
msg[1] = (u32)out_addr + i * out_w * block_h * 2;
msg[2] = (u32)idle_buf;
msg[3] = draw_rect.width;
msg[4] = draw_rect.height;
msg[5] = out_format;
msg[6] = (int)buf_hdl;
msg[7] = 0;
set_buffer_used(buf_hdl, idle_buf);
int err = os_taskq_post_type(GPU_TASK_NAME, msg[0], 7, &msg[1]);
if (err != OS_NO_ERR) {
ASSERT(0);
return NULL;
}
}
buffer_manager_free(buf_hdl);
/* time_count_end(3); */
return out_addr;
}
#endif