#include "system/includes.h" #include "app_config.h" #include "jljpeg_decode.h" #include "res/resfile.h" #include "ui_core.h" #include "jlgpu_math.h" // matrix #include "jlgpu_driver.h" // gpu 驱动 #include "gpu_port.h" // GPU 接口,依赖于 jlgpu_driver.h #include "gpu_task.h" #include #include "ui/lcd/lcd_drive.h" // lcd 驱动 #define LOG_TAG_CONST JPEG #define LOG_TAG "[JPEG]" #define LOG_ERROR_ENABLE #define LOG_DEBUG_ENABLE #define LOG_INFO_ENABLE #define LOG_DUMP_ENABLE #define LOG_WARN_ENABLE #define LOG_CHAR_ENABLE #include "debug.h" struct jpeg_hd_manager { struct list_head entry; jdec_opj *opj; u32 check; u32 vaild; u32 task_id; u32 elm_id; u8 file_flag; }; struct jpeg_priv { u32 task_id; u32 elm_id; }; struct jpeg_hd_manager jpg_hd_manager_info; #define __this (&jpg_hd_manager_info) spinlock_t lock; #define ENTER_CRITICAL() spin_lock(&lock) #define EXIT_CRITICAL() spin_unlock(&lock) #define UI_IO_DEBUG_0(i,x) //{JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT &= ~BIT(x);} #define UI_IO_DEBUG_1(i,x) //{JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT |= BIT(x);} int jpeg_module_opj_free_file_hd(FILE *fp); int jlgpu_scheduler_async_free_jpeg_res(void *p); int jpeg_module_opj_release_async(void *jpg); void *psram_cache_2_nocache(void *p); u32 jlui_jpeg_infunc_bits_stream(struct _jdec_opj *opj, u8 *buf, u32 len); extern void psram_flush_cache(void *begin, u32 len); extern const u8 norflash_ext_sfc_en;//给gpu判断互斥 extern void norflash_espi_mutex_enter(); extern void norflash_espi_mutex_exit(); extern u32 ps_ram_size[]; static volatile const u32 psram_size = (u32)ps_ram_size; #define IS_SFC1_ADDR(addr) (!psram_size && (memory_in_flash(addr))) #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) //======================================================================// // jpeg链表管理 // 支持多jpeg显示,注意 // 1. 多jpeg水平方向无交叉时,效率不影响(即垂直排列) // 2. 需要全屏刷新 // 3. 不带psram时不支持变换 // 4. 注意ram消耗 //======================================================================// void *jpeg_hd_create_priv(u32 task_id, u32 elm_id) { struct jpeg_priv *priv = (struct jpeg_priv *)jpeg_malloc(sizeof(struct jpeg_priv)); priv->task_id = task_id; priv->elm_id = elm_id; return (void *)priv; } int jpeg_hd_get_priv_len() { return sizeof(struct jpeg_priv); } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_hd_manager_check 查询是否存在jpeg句柄 * * @param check * * @return */ /* ------------------------------------------------------------------------------------*/ static void *jpeg_hd_manager_check(u32 check) { struct jpeg_hd_manager *p; struct jpeg_hd_manager *rp = NULL; ENTER_CRITICAL(); list_for_each_entry(p, &__this->entry, entry) { if (p->check == check) { rp = p; break; } } EXIT_CRITICAL(); if (rp) { log_debug("%s hd:0x%x opj:0x%x check:0x%x", __func__, (u32)rp, (u32)rp->opj, check); } else { log_debug("%s check:0x%x", __func__, check); } return (void *)rp; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_hd_manager_find_by_opj 判断句柄是否存在 * * @param opj * * @return */ /* ------------------------------------------------------------------------------------*/ static void *jpeg_hd_manager_find_by_opj(void *opj) { struct jpeg_hd_manager *p; struct jpeg_hd_manager *rp = NULL; ENTER_CRITICAL(); list_for_each_entry(p, &__this->entry, entry) { if (p->opj == opj) { rp = p; break; } } EXIT_CRITICAL(); if (rp) { log_debug("%s hd:0x%x opj:0x%x check:0x%x", __func__, (u32)rp, (u32)rp->opj, (u32)opj); } else { log_debug("%s check:0x%x", __func__, (u32)opj); } return (void *)rp; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_hd_manager_find_by_id 通过id查找句柄 * * @param task_id * @param elm_id * * @return */ /* ------------------------------------------------------------------------------------*/ static void *jpeg_hd_manager_find_by_id(u32 task_id, u32 elm_id) { struct jpeg_hd_manager *p; struct jpeg_hd_manager *rp = NULL; ENTER_CRITICAL(); list_for_each_entry(p, &__this->entry, entry) { if ((p->task_id == task_id) && (p->elm_id == elm_id)) { rp = p; break; } } EXIT_CRITICAL(); if (rp) { log_debug("%s hd:0x%x opj:0x%x task_id:0x%x elm_id:0x%x \n", __func__, (u32)rp, (u32)rp->opj, task_id, elm_id); } else { log_debug("%s task_id:0x%x elm_id:0x%x \n", __func__, task_id, elm_id); } return (void *)rp; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_hd_manager_add 添加jpeg句柄记录 * * @param opj * @param check * * @return */ /* ------------------------------------------------------------------------------------*/ static struct jpeg_hd_manager *jpeg_hd_manager_add(void *opj, u32 check) { struct jpeg_hd_manager *p = jpeg_malloc(sizeof(struct jpeg_hd_manager)); memset(p, 0, sizeof(struct jpeg_hd_manager)); p->opj = (jdec_opj *)opj; p->check = check; p->vaild = 0; log_debug("%s hd:0x%x opj:0x%x check:0x%x", __func__, (u32)p, (u32)p->opj, check); ENTER_CRITICAL(); list_add_tail(&p->entry, &__this->entry); EXIT_CRITICAL(); return p; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_hd_manager_del 删除jpeg句柄记录 * * @param opj * * @return */ /* ------------------------------------------------------------------------------------*/ static int jpeg_hd_manager_del(void *opj) { log_debug("%s opj:0x%x ", __func__, (u32)opj); struct jpeg_hd_manager *p, *n; ENTER_CRITICAL(); list_for_each_entry_safe(p, n, &__this->entry, entry) { if (p->opj == opj) { list_del(&(p->entry)); if (p->file_flag) { FILE *fp = (FILE *)(((int *)p->opj->device)[0]); jpeg_module_opj_free_file_hd(fp); } jpeg_module_opj_release_async((void *)p->opj); jpeg_free(p); break; } } EXIT_CRITICAL(); return 0; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_hd_manager_clr 清空所有jpeg句柄记录 * * @return */ /* ------------------------------------------------------------------------------------*/ static int jpeg_hd_manager_clr() { log_debug("%s %d", __func__, __LINE__); struct jpeg_hd_manager *p, *n; ENTER_CRITICAL(); list_for_each_entry_safe(p, n, &__this->entry, entry) { list_del(&(p->entry)); if (p->file_flag) { FILE *fp = (FILE *)(((int *)p->opj->device)[0]); jpeg_module_opj_free_file_hd(fp); } jpeg_module_opj_release_async((void *)p->opj); jpeg_free(p); } EXIT_CRITICAL(); log_debug("%s %d", __func__, __LINE__); return 0; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_hd_manager_vaild_set 有效性设置 * * @param opj * @param vaild * * @return */ /* ------------------------------------------------------------------------------------*/ static int jpeg_hd_manager_vaild_set(void *opj, int vaild) { log_debug("%s opj:0x%x", __func__, (u32)opj); struct jpeg_hd_manager *p, *n; ENTER_CRITICAL(); list_for_each_entry_safe(p, n, &__this->entry, entry) { if (p->opj == opj) { p->vaild = vaild; log_debug("%s hd:0x%x opj:0x%x svaild:%d pvaild:0x%x", __func__, (u32)p, (u32)opj, vaild, p->vaild); break; } } EXIT_CRITICAL(); return 0; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_hd_manager_vaild_sub 有效性-- * * @param opj * @param vaild * * @return */ /* ------------------------------------------------------------------------------------*/ static int jpeg_hd_manager_vaild_sub(void *opj) { log_debug("%s opj:0x%x", __func__, (u32)opj); struct jpeg_hd_manager *p, *n; ENTER_CRITICAL(); list_for_each_entry_safe(p, n, &__this->entry, entry) { if (p->opj == opj) { if (p->vaild) { p->vaild --; } log_debug("%s hd:0x%x opj:0x%x pvaild:0x%x", __func__, (u32)p, (u32)opj, p->vaild); break; } } EXIT_CRITICAL(); return 0; } //======================================================================// // jpeg句柄管理 //======================================================================// /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_module_free_res_cb jpeg资源释放接口,gpu_task调用 * * @param p */ /* ------------------------------------------------------------------------------------*/ void jpeg_module_free_res_cb(void *p) { jdec_opj *opj = (jdec_opj *)p; if (opj) { /*释放图片资源*/ jpeg_free(opj->device); /*释放底层*/ jljpeg_decode_release(opj, 0); jpeg_hd_manager_del(p); /*释放句柄*/ jpeg_free(opj); /*如果全局句柄与当前一致,释放,如果不一致说明已经切换为新的句柄,就不需再清*/ if (jljpeg_get_decode_hd() == opj) { jljpeg_get_decode_hd_clr(); } } } int jpeg_module_opj_free_file_hd(FILE *fp) { u32 rets; __asm__ volatile("%0 = rets":"=r"(rets)); printf("%s 0x%x [FILE]fp:0x%x", __func__, rets, (u32)fp); int argv[3] = {0}; int retry = 3; argv[0] = (int)fclose; argv[1] = 1; argv[2] = (int)fp; __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; return 0; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_module_opj_release_async 异步释放接口,post到gpu_task执行 * * @param opj * * @return */ /* ------------------------------------------------------------------------------------*/ int jpeg_module_opj_release_async(void *opj) { u32 rets; __asm__ volatile("%0 = rets":"=r"(rets)); log_debug("%s 0x%x opj:%x", __func__, rets, opj); if (opj) { /*同步到gpu线程释放,避免gpu在使用jpeg资源*/ jlgpu_scheduler_async_free_jpeg_res(opj); } return 0; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_module_opj_init jpeg句柄初始化(初始化硬件、解析文件头) * * @param priv * * @return */ /* ------------------------------------------------------------------------------------*/ int jpeg_module_opj_init(void *priv) { jdec_opj *opj = (jdec_opj *)priv; void *dev = opj->device; int ret = jljpeg_decode_init(opj); if (!ret) { ret = jljpeg_img_info_get(opj, jlui_jpeg_infunc_bits_stream, dev); #if 0 wdt_clear(); FILE *fp = fopen("storage/sd0/C/debug/test****.jpg", "w+"); if (fp) { struct flash_file_info *image_info = (struct flash_file_info *)opj->device; printf("buf:0x%x len:%d", image_info->offset, image_info->last_tab_data_len); fwrite((u8 *)image_info->offset, 1, image_info->last_tab_data_len, fp); fclose(fp); os_time_dly(1); } ASSERT(!ret, "jpeg file notsupport err:%x", ret); #endif if (ret) { log_warn("%s err:%d", __func__, ret); } } log_debug("%s %d", __func__, ret); return ret; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_module_opj_create 创建jpeg句柄 * * @param dev * @param dev_len * @param check * @param index * * @return */ /* ------------------------------------------------------------------------------------*/ void *jpeg_module_opj_create(void *dev, int dev_len, u32 check, u32 index, u32 task_id, u32 elm_id) { int ret; struct jpeg_hd_manager *hd = jpeg_hd_manager_check(check); jdec_opj *opj = NULL; if (!hd) { opj = jpeg_malloc(sizeof(jdec_opj)); hd = jpeg_hd_manager_add(opj, check); opj->device = jpeg_malloc(dev_len); memcpy(opj->device, dev, dev_len); ret = jpeg_module_opj_init((void *)opj); if (ret) { log_debug("%s %d", __func__, __LINE__); jpeg_module_opj_release_async((void *)opj); opj = NULL; } hd->task_id = task_id; hd->elm_id = elm_id; } else { opj = hd->opj; } if (opj) { jpeg_hd_manager_vaild_set(opj, 1); } return (void *)opj; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_module_opj_set_invaild_by_index 将某个jpeg句柄设为无效 * * @param index * * @return */ /* ------------------------------------------------------------------------------------*/ int jpeg_module_opj_set_invaild_by_index(int index) { log_debug("%s %d", __func__, __LINE__); struct jpeg_hd_manager *p, *n; ENTER_CRITICAL(); list_for_each_entry_safe(p, n, &__this->entry, entry) { jpeg_hd_manager_vaild_sub(p->opj); } EXIT_CRITICAL(); return 0; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_module_opj_invaild_clr 将无效的句柄清除 * * @return */ /* ------------------------------------------------------------------------------------*/ int jpeg_module_opj_invaild_clr() { log_debug("%s %d", __func__, __LINE__); struct jpeg_hd_manager *p, *n; ENTER_CRITICAL(); list_for_each_entry_safe(p, n, &__this->entry, entry) { if (p->vaild) { continue; } list_del(&(p->entry)); if (p->file_flag) { FILE *fp = (FILE *)(((int *)p->opj->device)[0]); jpeg_module_opj_free_file_hd(fp); } jpeg_module_opj_release_async(p->opj); jpeg_free(p); } EXIT_CRITICAL(); return 0; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_module_opj_clr_all 清除所有句柄 * * @return */ /* ------------------------------------------------------------------------------------*/ int jpeg_module_opj_clr_all() { log_debug("%s %d", __func__, __LINE__); return jpeg_hd_manager_clr(); } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_module_init 模块初始化 * * @return */ /* ------------------------------------------------------------------------------------*/ int jpeg_module_init() { INIT_LIST_HEAD(&__this->entry); return 0; } //======================================================================// // jpeg数据输出输出 //======================================================================// /* ------------------------------------------------------------------------------------*/ /** * @brief jlui_jpeg_infunc_bits_stream jpeg数据流 * * @param opj jpeg句柄 * @param buf jpeg buf * @param len jpeg读取长度 * * @return */ /* ------------------------------------------------------------------------------------*/ u32 jlui_jpeg_infunc_bits_stream(struct _jdec_opj *opj, u8 *buf, u32 len) { u32 rets; __asm__ volatile("%0 = rets":"=r"(rets)); /* log_debug("%s jpeg_info:%x %x buf:%x rets:0x%x\n", __func__, (int)opj, (int)opj->device, (int)buf, rets); */ //dev句柄,可以是flash_info、ram地址、文件系统句柄等,只需要将 //偏移为opj->curr_offset长度为len数据,copy到buf,并返回实际的copy长度即可 struct flash_file_info *image_info = (struct flash_file_info *)opj->device; int start_addr, end_addr, curr_addr, read_len; if (image_info->tab) { //使用mmu_table int need_len = len; int poffset = opj->curr_offset; int curr_offset = 0; int mmu_idx = (poffset + image_info->offset) / 4096; //计算起始mmu_tab /* printf("%s offset %d end:%d tbsize:%d", __func__, image_info->offset, image_info->last_tab_data_len, image_info->tab_size / 4); */ do { //当前mmu块的最大长度 int block_end = (mmu_idx == ((image_info->tab_size / 4) - 1)) ? image_info->last_tab_data_len : 4096; //当前mmu块的起始偏移 int block_offset = (image_info->offset + poffset) % 4096; //当前mmu块的可读长度 int block_len = block_end - block_offset; //拷贝长度 read_len = (block_len < need_len) ? block_len : need_len; //拷贝地址 curr_addr = image_info->tab[mmu_idx] + block_offset; /* printf("%s mmu_idx:%d block_end:%d block_offset:%d block_len:%d read_len:%d need_len:%d,poffset:%d curr_offset%d\n", */ /* __func__, mmu_idx, block_end, block_offset, block_len, read_len, need_len, poffset, curr_offset); */ //分块拷贝 if (buf) { if (norflash_ext_sfc_en && IS_SFC1_ADDR(curr_addr)) { norflash_espi_mutex_enter(); } memcpy(buf + curr_offset, (const u8 *)curr_addr, read_len); if (norflash_ext_sfc_en && IS_SFC1_ADDR(curr_addr)) { norflash_espi_mutex_exit(); } } //计算下一块mmu poffset += read_len; curr_offset += read_len; need_len -= read_len; if (mmu_idx >= ((image_info->tab_size / 4) - 1)) {//读取完所有mmu break; } else { mmu_idx ++; } if (need_len <= 0) {//读取完数据 break; } } while (1); //返回实际读取总长度 read_len = curr_offset; } else { //资源起始地址 start_addr = image_info->offset; //结束地址 end_addr = image_info->offset + image_info->last_tab_data_len; //拷贝地址 curr_addr = start_addr + opj->curr_offset; //拷贝长度 read_len = (curr_addr + len > end_addr) ? end_addr - curr_addr : len; //拷贝 if (buf) { if (norflash_ext_sfc_en && IS_SFC1_ADDR(curr_addr)) { norflash_espi_mutex_enter(); } memcpy(buf, (const u8 *)curr_addr, read_len); if (norflash_ext_sfc_en && IS_SFC1_ADDR(curr_addr)) { norflash_espi_mutex_exit(); } } } /* log_debug("%s start_addr:0x%x end_addr:0x%x file_len:%d curr_addr:0x%x len:%d read_len:%d", */ /* __func__, start_addr, end_addr, end_addr - start_addr, curr_addr, len, read_len); */ return read_len; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg绘图回调 * * @param id 0 * @param dst_buf 屏显buffer * @param dst_r 屏显buffer rect * @param src_r 图片/控件尺寸 * @param bytes_per_pixel 格式 * @param priv jpeg句柄 * @param matrix 变换矩阵 */ /* ------------------------------------------------------------------------------------*/ static void jpeg_draw_cb(int id, u8 *dst_buf, struct rect *dst_r, struct rect *src_r, u8 bytes_per_pixel, void *priv, void *matrix) { jdec_opj *opj = (jdec_opj *)priv; //jpeg解码句柄 opj->matrix = matrix; //获取变换矩阵 //计算缩放系数 float ratio_w = 1.0; float ratio_h = 1.0; if (opj->matrix) { gpu_matrix_t *m = matrix; ratio_w = m->m[0][0];// ratio_h = m->m[1][1];// /* log_debug("ratio_w: %f, ratio_h: %f\n", ratio_w, ratio_h); */ } /* 计算变换后图片的输出区域 */ struct rect jpeg_draw_src; memcpy(&jpeg_draw_src, src_r, sizeof(struct rect)); //放大时为中心放大 int center_y = src_r->top + src_r->height / 2; jpeg_draw_src.height = opj->height / ratio_h; jpeg_draw_src.top = center_y - jpeg_draw_src.height / 2; int center_x = src_r->left + src_r->width / 2; jpeg_draw_src.width = opj->width / ratio_w; jpeg_draw_src.left = center_x - jpeg_draw_src.width / 2; /* DUMP_RECT(__func__, __LINE__, "dst_r", dst_r); //推屏buf */ /* DUMP_RECT(__func__, __LINE__, "src_r", src_r); //jpeg显示区域 */ /* DUMP_RECT(__func__, __LINE__, "jpeg_draw_src", &jpeg_draw_src); //jpeg缩放后区域 */ /* 计算图片输出和推屏Buf的重叠区域 */ struct rect cover_r_t; if (!get_rect_cover(dst_r, src_r, &cover_r_t)) { return; } if (jljpeg_get_decode_hd() && (opj != jljpeg_get_decode_hd())) { jljpeg_decode_hdl_reset(opj); /* jljpeg_decode_reset_curr(); */ } //计算缩放后的区域*以推屏区域、jpeg缩放区域、控件显示区域的交集作为最终输出,放大时受控件尺寸限制会变成中心放大 struct rect cover_r; get_rect_cover(&cover_r_t, &jpeg_draw_src, &cover_r); /* DUMP_RECT(__func__, __LINE__, "cover_r", &cover_r); //重叠区域 */ //计算jpeg解码的区域 int draw_top = cover_r.top - jpeg_draw_src.top; //绘制的top int draw_btm = cover_r.height + draw_top; //绘制的bottom int draw_h = cover_r.height; //绘制高度 /* int dec_top = draw_top * ratio_h; //需要解码的top */ /* int dec_btm = ceilf((float)draw_btm * ratio_h); //需要解码的高度,这里需要向上取 */ /* int dec_h = dec_btm - dec_top; //解码高度 */ int max_dec_height = (opj->msy << 3) / ratio_h; //一个mcu分块缩放后可以有效绘制的行数 int sub_top = 0; int sub_height = (draw_h > max_dec_height) ? max_dec_height : draw_h; //按mcu快缩放后的有效高度进行分行处理 while (sub_top + draw_top < draw_btm) { int dec_sub_top = (draw_top + sub_top) * ratio_h; int dec_sub_btm = ceilf((float)(draw_top + sub_top + sub_height) * ratio_h); int dec_sub_h = dec_sub_btm - dec_sub_top; /* log_debug("%s draw(%d %d) dec(%d %d)%d maxdec%d sub(%d %d) dec_sub(%d %d)", */ /* __func__, draw_top, draw_btm, dec_top, dec_btm, dec_h, max_dec_height, sub_top, sub_height, dec_sub_top, dec_sub_btm); */ struct rect jpeg_dec_r; /*jpeg解码区域*/ /* jpeg_dec_r.left = (cover_r.left - src_r->left) * ratio_w; */ jpeg_dec_r.left = (cover_r.left - jpeg_draw_src.left) * ratio_w; jpeg_dec_r.top = dec_sub_top; jpeg_dec_r.width = cover_r.width * ratio_w; jpeg_dec_r.height = dec_sub_h; struct rect block_r; /*缩放后显示的区域*/ block_r.top = cover_r.top + sub_top; block_r.height = sub_height; block_r.left = dst_r->left; block_r.width = dst_r->width; /* DUMP_RECT(__func__, __LINE__, "block_r", &block_r); */ /* DUMP_RECT(__func__, __LINE__, "jpeg_dec_r", &jpeg_dec_r); */ u8 *disp_buf = dst_buf + (block_r.top - dst_r->top) * 2 * dst_r->width; /*启动解码*/ jljpeg_decode_start(opj, &jpeg_draw_src, &jpeg_dec_r, &cover_r, &block_r, disp_buf); sub_top += sub_height; sub_height = (sub_top + sub_height + draw_top < draw_btm) ? max_dec_height : draw_btm - draw_top - sub_top; } } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_draw_cb_gpu gpu绘图回调 * * @param id * @param dst_buf * @param dst_r * @param src_r * @param bytes_per_pixel * @param priv * @param matrix */ /* ------------------------------------------------------------------------------------*/ void jpeg_draw_cb_gpu(int id, u8 *dst_buf, struct rect *dst_r, struct rect *src_r, u8 bytes_per_pixel, void *priv, void *matrix) { //先用过id获取句柄,如果获取不到就return struct jpeg_priv *__jpeg_priv = (struct jpeg_priv *) priv; struct jpeg_hd_manager *hd = jpeg_hd_manager_find_by_id(__jpeg_priv->task_id, __jpeg_priv->elm_id); if (!hd) { log_warn("%s elmid:%d task_id:%d", __func__, __jpeg_priv->elm_id, __jpeg_priv->task_id); return; } jpeg_draw_cb(id, dst_buf, dst_r, src_r, bytes_per_pixel, hd->opj, matrix); } /* ------------------------------------------------------------------------------------*/ /** * @brief jlui_draw_jpeg_cb_exit 任务销毁时调用,释放jpeg资源 * * @param priv jpeg句柄 * * @return */ /* ------------------------------------------------------------------------------------*/ int jpeg_draw_cb_exit(void *draw_info, void *priv) { pJLGPUTaskDraw_t __draw_info = (pJLGPUTaskDraw_t)draw_info; /*使用双任务链推屏时,在息屏前或更新资源句柄前释放jpeg句柄,避免双链表冲突*/ void *opj = __draw_info->priv; __draw_info->priv = NULL;//由应用层释放 __draw_info->priv_len = 0; return 0; } /* ------------------------------------------------------------------------------------*/ /** * @brief cache_gpu_input_jpeg_data_cb 将数据拷贝到psram * * @param priv jpeg句柄 * @param dst 解码后的输出buf * @param src NULL * @param len 0 */ /* ------------------------------------------------------------------------------------*/ void cache_gpu_input_jpeg_data_cb(void *priv, void *dst, void *src, int len) { jdec_opj *jpg_hd = (jdec_opj *)priv; //解码 struct rect jpeg_dec = { .left = 0, .top = 0, .width = jpg_hd->width, .height = jpg_hd->height, }; int bytes_per_pixel = 2; u32 jpeg_width_align = (jpeg_dec.width + 15) / 16 * 16; u32 jpeg_height_align = (jpg_hd->height + 15) / 16 * 16; u32 jpeg_stride = bytes_per_pixel * jpeg_width_align ; u8 *tmp_buf = malloc_psram(jpeg_stride * jpeg_height_align); jlgpu_scheduler_wait_sync(); extern int ui_disp_out_stride_set(u16 stride); ui_disp_out_stride_set(jpeg_stride); struct rect dst_r = { .left = 0, .top = 0, .width = jpeg_width_align, .height = jpeg_height_align, }; jpeg_draw_cb(0, tmp_buf, &dst_r, &jpeg_dec, bytes_per_pixel, jpg_hd, NULL); UI_IO_DEBUG_1(B, 6) texture_line_to_tile_base(dst, tmp_buf, jpeg_width_align, jpeg_height_align, GPU_FORMAT_RGB565); UI_IO_DEBUG_0(B, 6) free_psram(tmp_buf); } /* ------------------------------------------------------------------------------------*/ /** * @brief cache_gpu_input_jpeg_data 解码jpeg图片到psram * * @param head 预留 * @param task_param gpu任务参数 * @param fp jpeg文件指针 * @param index 任务链索引,一般为0、1 * * @return */ /* ------------------------------------------------------------------------------------*/ void *cache_gpu_input_jpeg_data(void *head, pJLGPUTaskParam_t task_param, void *fp, int index) { /* 检查是否已经有缓存,如果需要缓存jpg没在cache里,释放原来的,缓存新的 */ void *cache_addr = gpu_input_stream_cache_check(task_param->image.data_crc); //jpeg原始数据,nand使用 u8 *jpeg_src_data = NULL; int vaild_index = index; /* printf("@@@@@ cache_addr: 0x%x\n crc:%d", (u32)cache_addr,task_param->image.data_crc); */ if (!cache_addr) {//解码jpeg到psram jdec_opj *jpg_hd = jpeg_malloc(sizeof(jdec_opj)); //在任务销毁时释放 jpg_hd->device = jpeg_malloc(sizeof(struct flash_file_info));//设备句柄,这里可以是文件句柄等,搭配input_steam使用 #if TCFG_NANDFLASH_DEV_ENABLE if (fp) { //文件头解析的时候比较零散,这里直接将文件拷贝到psram,解完后free UI_IO_DEBUG_1(B, 2); jpeg_src_data = jpeg_malloc(task_param->image.len); res_fseek(fp, (u32)task_param->image.offset, SEEK_SET); res_fread(fp, jpeg_src_data, task_param->image.len); struct flash_file_info *p_info = (struct flash_file_info *)jpg_hd->device; p_info->offset = (u32)jpeg_src_data; p_info->tab = NULL; p_info->tab_size = 0; p_info->last_tab_data_len = task_param->image.len; UI_IO_DEBUG_0(B, 2); } else { ASSERT(0); } #else memcpy(jpg_hd->device, &task_param->info, sizeof(struct flash_file_info)); #endif UI_IO_DEBUG_1(B, 4); if (jpeg_module_opj_init(jpg_hd)) {//初始化jpeg头 //异常释放资源 jpeg_free(jpg_hd->device); jljpeg_decode_release(jpg_hd, 0); jpeg_free(jpg_hd); if (jpeg_src_data) { jpeg_free(jpeg_src_data); } return NULL; } //cache u32 jpeg_width_align = (jpg_hd->width + 15) / 16 * 16; u32 jpeg_stride = 2 * jpeg_width_align; u32 jpeg_height_align = (jpg_hd->height + 15) / 16 * 16; u32 jpeg_img_len = jpeg_stride * jpeg_height_align ; cache_addr = gpu_input_stream_cache_add_with_callback(jpg_hd, jpg_hd, jpeg_img_len, task_param->image.data_crc, NULL, 0, cache_gpu_input_jpeg_data_cb); //从cache同步到物理介质,后续用nocache直接访问 psram_flush_cache(cache_addr, jpeg_img_len); jpeg_free(jpg_hd->device); jljpeg_decode_release(jpg_hd, 1); jpeg_free(jpg_hd); if (jpeg_src_data) { jpeg_free(jpeg_src_data); } UI_IO_DEBUG_0(B, 4); } //使用nocache地址访问,提高读效率 task_param->texture.data = psram_cache_2_nocache(cache_addr); /* task_param->texture.data =(cache_addr); */ //更新任务配置 task_param->texture.mmu_tab_base = NULL; task_param->format = GPU_FORMAT_RGB565; task_param->texture.not_compress = 1; task_param->texture.adr_mode = 0; int width = task_param->image.width; int height = task_param->image.height; task_param->image.width = (width + 15) / 16 * 16; task_param->image.height = (height + 15) / 16 * 16; if (cache_addr) { gpu_input_stream_cache_vaild_value_set_by_index((u32)cache_addr, 3); gpu_input_stream_cache_set_index((u32)cache_addr, index); } return task_param->texture.data; } /* ------------------------------------------------------------------------------------*/ /** * @brief jlui_jpeg_infunc jpeg位流输入 * * @param opj 句柄 * @param buf 位流buf * @param len 预获取长度 * * @return 实际数据长度 */ /* ------------------------------------------------------------------------------------*/ static u32 jlui_jpeg_infunc(struct _jdec_opj *opj, u8 *buf, u32 len) { u32 rets; __asm__ volatile("%0 = rets":"=r"(rets)); if (buf) { FILE *fp = (FILE *)(((int *)opj->device)[0]); /* printf("%s fp:0x%x",__func__,(u32)fp); */ /* printf("%s offset:%d len:%d end:%d\n", __func__, opj->curr_offset,len,flen(fp)); */ fseek(fp, opj->curr_offset, SEEK_SET); return fread(buf, len, 1, fp); } else { return len; } } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_module_opj_init jpeg句柄初始化(初始化硬件、解析文件头) * * @param priv * * @return */ /* ------------------------------------------------------------------------------------*/ int jpeg_module_opj_init_file(void *priv) { jdec_opj *opj = (jdec_opj *)priv; void *dev = opj->device; int ret = jljpeg_decode_init(opj); if (!ret) { ret = jljpeg_img_info_get(opj, jlui_jpeg_infunc, dev); ASSERT(!ret, "jpeg file notsupport err:%x", ret); } log_debug("%s %d", __func__, ret); return ret; } /* ------------------------------------------------------------------------------------*/ /** * @brief jpeg_module_opj_create 创建jpeg句柄 * * @param dev * @param dev_len * @param check * @param index * * @return */ /* ------------------------------------------------------------------------------------*/ void *jpeg_module_opj_create_file(void *path, int path_len, u32 check, u32 index, u32 task_id, u32 elm_id) { int ret; struct jpeg_hd_manager *hd = jpeg_hd_manager_check(check); jdec_opj *opj = NULL; if (!hd) { opj = jpeg_malloc(sizeof(jdec_opj)); hd = jpeg_hd_manager_add(opj, check); void *dev = (void *)fopen(path, "r"); printf("%s [FILE] fp:0x%x ", __func__, (u32)dev); int dev_len = sizeof(FILE *); hd->file_flag = 1; opj->device = jpeg_malloc(dev_len); memcpy(opj->device, &dev, dev_len); ret = jpeg_module_opj_init_file((void *)opj); if (ret) { log_debug("%s %d", __func__, __LINE__); jpeg_module_opj_release_async((void *)opj); opj = NULL; } hd->task_id = task_id; hd->elm_id = elm_id; } else { opj = hd->opj; } if (opj) { jpeg_hd_manager_vaild_set(opj, 1); } return (void *)opj; }