一、简介
AWTK是 ZLG 开发的开源 GUI 引擎,官网地址:https://www.zlg.cn/index/pub/awtk.html。
G2D 硬件加速是指将计算量较大的图像处理工作分配给专门的硬件外设来处理,减轻 CPU 的计算量,以此提高图像绘制的性能。
不同硬件平台的硬件加速外设不一样,其实现方法也有区别,在 AWTK 中,用户需要实现 awtk/src/base/g2d.h 文件中的相关接口,详见下表,然后开启宏 WITH_G2D 即可支持硬件加速,具体详见本文 2.21 章节。
函数名称 | 说明 | 备注 |
---|
g2d_fill_rect | 用颜色填充指定的区域 | | g2d_copy_image | 把图片指定的区域拷贝到 Framebuffer 中 | | g2d_rotate_image | 把图片指定的区域进行旋转并拷贝到 Framebuffer 的相应区域 | 本函数主要用于辅助实现横屏和竖屏的切换,一般支持90度旋转即可 | g2d_blend_image | 把图片指定的区域渲染到 Framebuffer 指定的区域,如果两个指定区域大小不一致则进行缩放 | 如果硬件设备不支持缩放或者不支持全局 Alpha 融合算法(绘制半透明图像),请返回 RET_NOT_IMPL,使用软件渲染 |
为方便读者理解,此处以绘制一张半透明的背景图为例,介绍 AWTK 是如何支持硬件加速的,绘制步骤如下:
- 在 AWTK 中通常会调用画布 canvas 中的 canvas_draw_image 函数绘制图像;
- 紧接着 canvas_draw_image 函数会调用 LCD 包装的 lcd_draw_image 函数;
- 在基于 Framebuffer 实现的 LCD 中实际上调用的是 lcd_mem_draw_image 函数;
- 由于此处绘制的是半透明图像,因此不能直接拷贝绘制,需要调用 image_blend 函数进行渲染;
- 如果开启宏 WITH_G2D 支持硬件加速,那么 image_blend 函数会调用 g2d_blend_image 函数进行绘制;
- 如果没有开启宏 WITH_G2D 或者 g2d_blend_image 函数绘制失败,那么就会调用 soft_blend_image 函数进行软件渲染。
备注:
- AWTK 中的画布 canvas 提供了基本的绘图功能和状态管理,其接口详见:awtk/src/base/canvas.h。
- AWTK 中的 LCD 的相关接口详见:awtk/src/base/lcd.h。
- AWTK 提供了基于 Framebuffer 的 LCD 缺省实现,代码详见:awtk/src/lcd/lcd_mem.inc。
- 基于 Framebuffer 实现的 LCD 通常会调用 awtk/src/blend/image_g2d.h 中的接口进行绘制。
绘制半透明背景的流程详见下图:
二、AWTK 默认自带的 STM32 的移植分析
目前,AWTK 内置了 STM32 系列平台 G2D 硬件加速的实现,代码详见:awtk/src/blend/stm32_g2d.c,只需定义下面的宏即可启用该功能:
#define WITH_STM32_G2D 1
备注:定义宏 WITH_STM32_G2D 后,AWTK 会自动定义宏 WITH_G2D 启用硬件加速,用户无需重复定义。
STM32 平台通过外设 DMA2D(Direct Memory Access 2D)支持硬件加速,此处以实现 g2d.h 文件中的 g2d_fill_rect 函数为例,介绍如何通过 DMA2D 实现硬件加速,其他接口的实现方法类似,详情可参考:awtk/src/blend/stm32_g2d.c。
备注:
- AWTK 针对 STM32f767igtx 的移植层 awtk-stm32f767igtx-raw 的下载地址:https://github.com/zlgopen/awtk-stm32f767igtx-raw。
- DMA2D 的相关说明可参考:awtk-stm32f767igtx-raw/HALLIB/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_dma2d。
- DMA2D 的使用方法可参考:awtk-stm32f767igtx-raw/HARDWARE/LCD/ltdc.c。
...
#define DMA2D_WORKING ((DMA2D->CR & DMA2D_CR_START))
#define DMA2D_WAIT \
do { \
while (DMA2D_WORKING) \
; \
DMA2D->IFCR = DMA2D_IFSR_CTCIF; \
} while (0);
#define PIXEL_FORMAT_BGRA8888 0X00
#define PIXEL_FORMAT_BGR565 0X02
ret_t g2d_fill_rect(bitmap_t* fb, const rect_t* dst, color_t c) {
...
uint16_t o_pixsize = 0;
uint16_t o_format = 0;
uint32_t color = 0;
if (fb->format == BITMAP_FMT_BGR565) {
o_pixsize = 2;
o_format = PIXEL_FORMAT_BGR565;
color = ((((c.rgba.r) >> 3) << 11) | (((c.rgba.g) >> 2) << 5) | ((c.rgba.b) >> 3));
} else {
o_pixsize = 4;
o_format = PIXEL_FORMAT_BGRA8888;
color = c.color;
}
uint8_t* fb_data = bitmap_lock_buffer_for_write(fb);
uint16_t o_offline = fb->w - dst->w;
uint32_t o_addr = ((uint32_t)fb_data + o_pixsize * (fb->w * dst->y + dst->x));
__HAL_RCC_DMA2D_CLK_ENABLE();
DMA2D->CR &= ~(DMA2D_CR_START);
DMA2D->CR = DMA2D_R2M;
DMA2D->OPFCCR = o_format;
DMA2D->OOR = o_offline;
DMA2D->OMAR = o_addr;
DMA2D->OCOLR = color;
DMA2D->NLR = dst->h | (dst->w << 16);
DMA2D->CR |= DMA2D_CR_START;
DMA2D_WAIT
bitmap_unlock_buffer(fb);
return RET_OK;
}
三、NXP 的 PXP 的硬件加速移植教程
除了 AWTK 内置的 STM32 平台的硬件加速移植外,在 AWTK 针对 AWorks (RT1052)平台的移植中,提供了 NXP PXP 硬件加速的实现文件,代码详见:awtk-aworks-rt1052/awtk-port/rt1052_g2d.c,只需定义下面的宏即可启用该功能:
#define WITH_PXP_G2D 1
备注:
- 移植层 awtk-aworks-rt1052 的下载地址:https://github.com/zlgopen/awtk-aworks-rt1052。
- 定义宏 WITH_PXP_G2D 后,AWTK 会自动定义宏 WITH_G2D 启用硬件加速,用户无需重复定义。
AWorks 平台通过外设 PXP(像素处理)支持硬件加速,此处同样以实现 g2d.h 文件中的 g2d_fill_rect 函数为例,介绍如何通过 PXP 实现硬件加速,其他接口的实现方法类似,详情可参考:awtk-aworks-rt1052/awtk-port/rt1052_g2d.c。
备注:如想了解 AWorks 平台 PXP 的详细说明以及使用方法可前往 ZLG 官网下载最新的 RT1052 光盘资料,其中包括文档《AWorks M105x 外设使用指南——PXP》,官网地址:https://www.zlg.cn。
...
ret_t g2d_fill_rect(bitmap_t* fb, const rect_t* dst, color_t c)
{
...
pxp_output_buffer_config_t pxp_output_config = {0};
pxp_ps_buffer_config_t ps_buffer_config = {0};
uint8_t out_pixsize = 2;
uint8_t* fb_data = bitmap_lock_buffer_for_write(fb);
uint32_t out_addr = (uint32_t)fb_data + (fb->w * dst->y + dst->x) * out_pixsize;
uint32_t fb_flush_size = ((dst->h - 1) * fb->w + dst->w) * out_pixsize;
aw_cache_flush((void *)out_addr, fb_flush_size);
pxp_hard_reset();
pxp_output_config.pixel_format = kPXP_OutputPixelFormatRGB565;
pxp_output_config.interlaced_mode = kPXP_OutputProgressive;
pxp_output_config.buffer0_addr = out_addr;
pxp_output_config.pitch_bytes = fb->w * out_pixsize;
pxp_output_config.width = dst->w;
pxp_output_config.height = dst->h;
pxp_set_output_buffer_config(&pxp_output_config);
ps_buffer_config.pixel_format = kPXP_PsPixelFormatRGB888;
ps_buffer_config.buffer_addr = out_addr;
ps_buffer_config.pitch_bytes = fb->w * out_pixsize;
pxp_set_process_surface_buffer_config(&ps_buffer_config);
pxp_set_process_surface_position(0, 0, dst->w - 1, dst->h - 1);
pxp_set_alpha_surface_position(1, 1, 0, 0);
pxp_set_process_surface_color_key(0, 0xFFFFFF);
pxp_set_process_surface_back_ground_color((uint32_t)c.color & (0xFFFFFF));
pxp_start();
pxp_complete_status_sync();
aw_cache_invalidate((void *)out_addr, fb_flush_size);
bitmap_unlock_buffer(fb);
return RET_OK;
}
|