rga模块介绍
rk系列的rga模块硬件版本、驱动版本和动态库版本都比较多,说实话一款芯片能把其中的一个硬核做成这么多差异版本出来,也是不容易。以下是sdk文档《Rockchip_Developer_Guide_RGA_CN》中的介绍。
除此之外,在接口层的重载设计,也是五花八门,第一眼看去都不知道该用哪个接口了。
rga问题分析
问题描述:RGA_MMU unsupported memory larger than 4G!
[ 6653.664110] rga_mm: RGA_MMU unsupported memory larger than 4G!
[ 6653.664189] rga_mm: scheduler core[4] unsupported mm_flag[0x8]!
[ 6653.664290] rga_mm: rga_mm_map_buffer map virtual address error!
[ 6653.664306] rga: buffer[0] mm import buffer failed! memory = 0x7f87539010, type = virt_addr(0x1)
[ 6653.664955] rga_mm: RGA_MMU unsupported memory larger than 4G!
[ 6653.664973] rga_mm: scheduler core[4] unsupported mm_flag[0x8]!
[ 6653.665071] rga_mm: rga_mm_map_buffer map virtual address error!
[ 6653.665082] rga: buffer[0] mm import buffer failed! memory = 0x7f86d4f010, type = virt_addr(0x1)
出现上述这个表现的根本原因是,rk3568的rga硬核的iommu范围是32bit,不能寻址到大于4GB的内存空间。再简单点说,就是rk这里兼容性设计的不好,在程序使用上,不能随意分配内存的起始地址,所以使用上有2点约束。
1、使用32bit寻址空间内的地址,而且最好是dma映射的空间,因为dma的效率更高;
那么低32bit的dma-buf空间怎么映射的呢?
参考内核源码drivers/dma-buf/heaps/rk_system_heap.c,已经做好了几个空间的dma_heap,下图是注册的几个字符设备节点,“system-uncached-dma32” 映射的就是低32bit的地址空间,如下图是文件系统查看到的节点。
所以在编程使用上,只需要去申请“system-uncached-dma32”节点的映射空间即可,这个节点在头文件linux-rga/samples/utils/allocator/include/dma_alloc.h中被申明为宏DMA_HEAP_DMA32_UNCACHE_PATCH。
2、必须importbuffer_virtualaddr,不能跳过而直接wrapbuffer_xxx,意思是告诉rga模块这个已经分配好的共享地址;
rga编程demo
以linux-rga中的一个例程做简单的demo。
以接口dma_buf_alloc(DMA_HEAP_DMA32_UNCACHE_PATCH, src_buf_size, &src_dma_fd, (void **)&src_buf)去申请共享地址空间。
#if USE_DMA_HEAPret = dma_buf_alloc(DMA_HEAP_DMA32_UNCACHE_PATCH, src_buf_size, &src_dma_fd, (void **)&src_buf);if (ret < 0) {printf("alloc src dma32_heap buffer failed!\n");return -1;}ret = dma_buf_alloc(DMA_HEAP_DMA32_UNCACHE_PATCH, dst_buf_size, &dst_dma_fd, (void **)&dst_buf);if (ret < 0) {printf("alloc dst dma32_heap buffer failed!\n");return -1;}
#else(void)(src_dma_fd);(void)(dst_dma_fd);src_buf = (char *)malloc(src_buf_size);dst_buf = (char *)malloc(dst_buf_size);if (src_buf == NULL || dst_buf == NULL) {printf("malloc failed!\n");return -1;}
#endif/* fill image data */if (0 != read_image_from_file(src_buf, LOCAL_FILE_PATH, src_width, src_height, src_format, 0)) {printf("src image read err\n");memset(src_buf, 0xaa, src_buf_size);}memset(dst_buf, 0x80, dst_buf_size);src_handle = importbuffer_virtualaddr(src_buf, src_buf_size);dst_handle = importbuffer_virtualaddr(dst_buf, dst_buf_size);if (src_handle == 0 || dst_handle == 0) {printf("importbuffer failed!\n");goto release_buffer;}src_img = wrapbuffer_handle(src_handle, src_width, src_height, src_format);dst_img = wrapbuffer_handle(dst_handle, dst_width, dst_height, dst_format);ret = imcheck(src_img, dst_img, {}, {});if (IM_STATUS_NOERROR != ret) {printf("%d, check error! %s", __LINE__, imStrError((IM_STATUS)ret));return -1;}