系列文章:
1.基于BLE SoC芯片GR5526开发GPU 3D图形效果(1) - 概览
2.基于BLE SoC芯片GR5526开发GPU 3D图形效果(2) - 先看Demo效果
3.基于BLE SoC芯片GR5526开发GPU 3D图形效果(3) - GPU知识概念梳理
4.基于BLE SoC芯片GR5526开发GPU 3D图形效果(4) - 解析第一个GPU工程
5.基于BLE SoC芯片GR5526开发GPU 3D图形效果(5) - 理解图形学中的矩阵变换
6.基于BLE SoC芯片GR5526开发GPU 3D图形效果(6) - 开发炫酷新动画
前言: 通过上一篇文章对GR5526 GPU知识基础和接口的梳理, 对基本原理有了一定认知, 可以阅读分析 SDK 提供的GPU示例工程了.
一、 GPU应用典型代码结构
GPU应用典型的代码结构主要分为四个部分:Graphics外设初始化、缓冲区配置、渲染任务与屏幕刷新、外设反初始化(可选)。
- Graphics外设初始化
- 初始化OSPI、PSRAM外设模块(默认使用OSPI访问内部PSRAM,若不使用内部PSRAM可不初始化相关外设)
- 初始化GPU模块
- 初始化DC模块
- 初始化QSPI模块
- 缓冲区配置
- Graphics内存管理初始化
- 根据需求,初始化合适的帧缓冲区
- 为GPU配置全局Framebuffer参数
- 为DC配置全局Framebuffer参数
- 根据需求,申请适当的Texture Memory存储纹理图案
- 初始化环形缓冲区,为命令列表提供缓冲空间
- 渲染任务与屏幕刷新
- 构建GPU的命令列表,并提交至GPU进行渲染
- 进入核心的渲染逻辑执行渲染任务,并实时将渲染结果刷新至屏幕上显示
- 根据GPU中断获取渲染结果
- 根据DC中断获取刷屏结果
- 外设反初始化(可选)
- 任务结束时反初始化Graphics相关外设模块
- 释放任务过程中申请的内存
Graphics 涉及几个重要的外设模块需要初始化, 分别是GPU、OSPI&PSRAM、DC和QSPI Flash, GPU 提供图形化渲染的算力,OSPI&PSRAM 提供足够的缓存运算空间, QSPI Flash是图片资源的持久化存储介质, DC模块要初始化好屏幕配置,同时负责将GPU渲染好的帧缓冲区, 刷新到屏幕进行显示.
二、基于 graphics_animation_effects 工程的说明
1. 宏配置graphics_defs.h
graphics_defs.h头文件属于工程配置文件,每个示例工程独立,其位于:SDK_Folder\projects\peripheral\graphics\示例工程名\Src\application
/* Set current screen configuration */ #define LCD_RES_CURRENT LCD_RES_454
/* Set display enable */ #define HAL_GDC_DISPLAY_ENABLE 1u
/* Set TSCx compressed format enable */ #define TSCx_ENABLE 1u
/* Set image show area */ #define SHOW_AREA_X 240u #define SHOW_AREA_Y 240u
/* Set pixel depth size in byte (Determined by color format) */ #define PIXEL_DEPTH_BYTES 4u
/* Set pixel show size in byte (Determined by color format) */ #define PIXEL_SHOW_BYTES 3u
/* Set screen display area */ #define DISPLAY_LCD_RES_X 454u #define DISPLAY_LCD_RES_Y 454u |
配置主要是配置显示屏幕参数, 显示区域参数和 Framebuffer参数. 注意屏幕分辨率和显示区域的区别,前者是屏幕物理上的分辨率尺寸,后者是实际显示区域, 小于等于前者, 意味着可能不会用所有区域进行显示
上述配置属于工程配置, 各个工程内容可能是不一致的
2. 宏配置 graphics_sys_defs.h
graphics_sys_defs.h头文件属于graphics系统配置文件,其位于:SDK_Folder\components\graphics\gfx\porting
/**< The GPU RING BUFFER SIZE. */ #define HAL_GFX_RING_BUFFER_SIZE 1024u /**< The same to Pool id */ #define HAL_GFX_MEM_POOL_ASSETS 0 /**< Pool id, only set to 0 currently */ #define HAL_GFX_MEM_POOL_FB 0 /**< the graphics (video) memory base address. */ #define VMEM_BASEADDR ((uint32_t)(&s_graphics_memory_buffer[0])) /**< The GPU max memory size for frame buffer. */ #ifndef VMEM_SIZE #define VMEM_SIZE (20*1024u) #endif /**< If enable, use the memory management of GPU. */ #ifndef USE_TSI_MALLOC #define USE_TSI_MALLOC #endif /**< if HAL_GFX_MULTI_MEM_POOLS is defined, use HAL_GFX_MULTI_MEM_POOLS_CNT pools must be equal or less than 4. */ #ifndef HAL_GFX_MULTI_MEM_POOLS_CNT #define HAL_GFX_MULTI_MEM_POOLS_CNT 1 #endif |
这些配置主要配置 命令列表缓冲区和GPU 库所引用的内存池等,一般不用修改
注释上述配置是公共路径的通用配置, 其修改会影响所有引用这个文件的工程
3. 工程目录
graphics_animation_effects示例的源代码和工程文件位于:SDK_Folder\projects\peripheral\graphics\graphics_animation_effects,其中工程文件位于Keil_5文件夹。
双击打开graphics_animation_effects.uvprojx工程文件,在Keil中查看示例graphics_animation_effects工程目录结构
4. 应用代码介绍
graphics_animation_effects示例工程主要展现GPU的图像过渡效果。
该工程已适配FreeRTOS,通过FreeRTOS的系统心跳可计算图像的FPS。开发者可以通过禁用ENV_USE_FREERTOS宏来禁用FreeRTOS,通过自定义函数来计算图像的FPS。
路径:工程目录下的Src\application\graphics_animation_effects.c
名称:int graphics_animation_effects_main(void)
该函数为graphics_animation_effects示例工程GPU应用程序的主体代码入口,该函数完成外设初始化、缓冲区配置、渲染任务与屏幕刷新等。
int graphics_animation_effects_main(void) { /* Peripheral Initialization and Buffer Configuration */ int ret = init(); if (ret) { app_graphics_mem_free(s_fb.bo.base_virt); return ret; } /* Rendering Tasks and Screen Refresh */ animation_effects_loop(); /* Destroy Command List and Memory Release */ hal_gfx_cl_destroy(&cl); app_graphics_mem_free(s_fb.bo.base_virt); return 0; } |
1. 外设初始化与缓冲区配置
路径:工程目录下的Src\application\graphics_animation_effects.c
名称:static int init(void)
该函数主要完成外设初始化与缓冲区配置,包括:
• 初始化OSPI、PSRAM外设模块(可选)
• 初始化GPU、DC外设模块
• 初始化帧缓冲区,申请合适的Texture Memory存储Texture Image(可选),并完成绑定工作
• 初始化CL所需的环形缓冲区
static int init(void) { /* Initialize OSPI, PSRAM Peripheral Modules */ app_graphics_ospi_params_t params = PSRAM_INIT_PARAMS_Default; app_graphics_ospi_init(¶ms); /* Initialize GPU, DC Peripheral Modules */ graphics_gpu_init(NULL); graphics_dc_rm69330_qspi_lcd_init(LCD_RES_CURRENT, LCD_PIXEL_mode_24bit,GDC_MIPICFG_QSPI_RGB888_OPT0); /* Initialize Graphics Memory Management */ app_graphics_mem_init((uint8_t*)GFX_MEM_BASE, GFX_MEM_SIZE); /* Buffer Configuration */ load_objects(); /* Create Command List */ cl = hal_gfx_cl_create(); /* Bind Command List */ hal_gfx_cl_bind(&cl); /* Set Clipping Rectangle */ hal_gfx_set_clip(0, 0, SHOW_AREA_X, SHOW_AREA_Y); /* Bind Texture to HAL_GFX_TEX1 Slot (Foreground) */ hal_gfx_bind_src_tex(screen0.bo.base_phys,screen0.w, screen0.h,(hal_gfx_tex_format_t)(screen0.format),screen0.stride,(hal_gfx_tex_mode_t)(HAL_GFX_FILTER_BL |HAL_GFX_TEX_BORDER)); /* Bind Texture to HAL_GFX_TEX2 Slot (Background) */ hal_gfx_bind_src2_tex(screen1.bo.base_phys,screen1.w, screen1.h,(hal_gfx_tex_format_t)(screen1.format),screen1.stride,(hal_gfx_tex_mode_t)(HAL_GFX_FILTER_BL |HAL_GFX_TEX_BORDER)); /* Set Texture Default Color */ hal_gfx_set_tex_color(0); /* Submit Current CL and Wait */ hal_gfx_cl_submit(&cl); hal_gfx_cl_wait(&cl); return 0; } |
名称:static void load_objects(void)
该函数主要完成缓冲区配置,包括初始化帧缓冲区,为GPU和DC配置全局Framebuffer参数,申请合适的Texture Memory存储Texture Image(可选)
static void load_objects(void) { /* Configure Framebuffer for GPU */ s_fb.bo = hal_gfx_fb_create(s_fb.w*s_fb.h*PIXEL_DEPTH_BYTES); hal_gfx_buffer_map(&s_fb.bo); /* Configure Framebuffer for DC */ #if HAL_GDC_DISPLAY_ENABLE >0u s_dc_layer.resolution_x = s_fb.w; s_dc_layer.resolution_y = s_fb.h; #if TSCx_ENABLE > 0u s_dc_layer.data_format = GDC_DATA_FORMAT_RGBA8888 ; #else s_dc_layer.data_format = GDC_DATA_FORMAT_RGBA8888 ; #endif s_dc_layer.row_stride = s_dc_layer.resolution_x*PIXEL_DEPTH_BYTES; s_dc_layer.blendmode = HAL_GDC_BL_SIMPLE; s_dc_layer.start_x = 0; s_dc_layer.start_y = 0; s_dc_layer.size_x = s_dc_layer.resolution_x; s_dc_layer.size_y = s_dc_layer.resolution_y; s_dc_layer.alpha = 0x80; s_dc_layer.frame_baseaddr = (void*)s_fb.bo.base_phys; #endif printf("FB: V:%p P:0x%08x\n", (void *)s_fb.bo.base_virt, (uint32_t)s_fb.bo.base_phys); } |
5. 渲染任务与屏幕刷新
路径:工程目录下的Src\application\graphics_animation_effects.c
名称:static void animation_effects_loop(void)
该函数主要构建GPU渲染任务的命令列表,包含GPU的各种图像过渡效果。最终通过DC外设模块,实时将图像刷新至屏幕。
static void animation_effects_loop(void) { float step = 0.f; float step_step = ANIMATION_STEP_0_1; float start_time = hal_gfx_get_time(); int frame = 0; while (1) { /* Build GPU Rendering Tasks and Refresh Screen */ display(step, HAL_GFX_BL_SRC); /* Realize Image Transition Effect of GPU */ if (step <= 0.f) { step = 0.f; step_step = ANIMATION_STEP_0_1; next_effect(); } else if (step >= 1.f) { step = 1.f; step_step = -ANIMATION_STEP_0_1; next_effect(); } step += step_step; frame++; /* Calculate FPS */ hal_gfx_calculate_fps_ext(start_time, frame); } } |
名称:static void display(float step, uint32_t blendmode)
该函数主要构建GPU渲染任务的命令列表和通过DC外设模块实时将图像刷新至屏幕
static void display(float step, uint32_t blendmode) { /* Reset Position of Next Command to be Written to the Beginning */ hal_gfx_cl_rewind(&cl); /* Bind Framebuffer to HAL_GFX_TEX0 Slot */ hal_gfx_bind_dst_tex((uint32_t)s_fb.bo.base_phys, s_fb.w, s_fb.h, (hal_gfx_tex_format_t)(s_fb.format), s_fb.stride); /* GPU Image Transition Effect */ hal_gfx_transition(s_effect, HAL_GFX_TEX1, HAL_GFX_TEX2, blendmode, step, s_fb.w, s_fb.h); /* Submit Current CL and Wait */ hal_gfx_cl_submit(&cl); (void)hal_gfx_cl_wait(&cl); /* Refresh Image to Screen via DC */ #if HAL_GDC_DISPLAY_ENABLE > 0u app_graphics_dc_set_power_state(GDC_POWER_STATE_ACTIVE); graphics_dc_rm69330_qspi_send_frame(s_dc_layer, DISPLAY_LCD_RES_X,DISPLAY_LCD_RES_Y); #endif } |
三、结语
本文通过 GR5526 SDK 提供的 graphics_animation_effects 工程解析了 GPU使用的基本流程, 涉及的外设模块, 对代码进行了初步的注解解释.可以比较简单的就把 GPU 效果先玩起来, 再看看这个工程的编译和烧录到SK的效果: