1854 lines
69 KiB
C
1854 lines
69 KiB
C
/* 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 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)) {
|
||
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)) {
|
||
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
|
||
|
||
|