Toybrick

标题: RGA图像处理对比Opencv慢10倍,是什么问题? [打印本页]

作者: 萌虎龟来    时间: 2024-3-28 18:00
标题: RGA图像处理对比Opencv慢10倍,是什么问题?
硬件:RK3588
软件:RGA:/usr/lib/aarch64-linux-gnu/librga.so.2.1.0

对比测试crop + resize 操作,RGA平均用时2ms左右,OpenCV平均用时0.2ms,部分代码如下:
TransformData
  1. typedef struct _TransformData
  2. {
  3.     // 图像基本信息
  4.     int width, height, format;
  5.     int size;

  6.     // 对齐后的宽度
  7.     int stride;
  8.     int size_with_stride;

  9.     // 图像原始数据
  10.     char *data;

  11.     // DMA
  12.     int dma_fd;

  13.     // im2d
  14.     im_rect rect;

  15.     // RGA
  16.     rga_buffer_t buffer;
  17.     rga_buffer_handle_t handle;

  18. } TransformData;
复制代码
TransformData 实例化
  1. std::unique_ptr<TransformData> Transformer::wrapTransformData(cv::Mat cv_img, const im_rect &rect)
  2. {
  3.     m_timer.record(__func__);

  4.     std::unique_ptr<TransformData> td(new TransformData());

  5.     td->width = cv_img.cols;
  6.     td->height = cv_img.rows;
  7.     td->format = m_format;
  8.     td->size = td->width * td->height * get_bpp_from_format(td->format);

  9.     // 对齐后的宽度
  10.     td->stride = td->width;
  11.     td->size_with_stride = td->size;
  12.     if (td->width % m_align_bit)
  13.     {
  14.         td->stride = (td->width / m_align_bit + 1) * m_align_bit;
  15.         td->size_with_stride = td->size / td->width * td->stride;
  16.     }

  17.     // 使用dma_heap分配内存调用RGA
  18.     td->dma_fd = -1;
  19.     dma_buf_alloc(DMA_HEAP_PATH, td->size_with_stride, &(td->dma_fd), reinterpret_cast<void **>(&(td->data)));
  20.     assert(td->dma_fd != -1);

  21.     // 数据拷贝
  22.     if (td->width == td->stride)
  23.     {
  24.         std::memcpy(reinterpret_cast<uchar *>(td->data), cv_img.data, td->size);
  25.     }
  26.     else
  27.     {
  28.         size_t c = get_bpp_from_format(td->format);
  29.         size_t src_stride = td->width * c;
  30.         size_t dst_stride = td->stride * c;

  31.         uchar *src_ptr = cv_img.data;
  32.         uchar *dst_ptr = reinterpret_cast<uchar *>(td->data);

  33.         for (int i = 0; i < td->height; i++)
  34.         {
  35.             std::memcpy(dst_ptr, src_ptr, src_stride);
  36.             src_ptr += src_stride;
  37.             dst_ptr += dst_stride;
  38.         }
  39.     }

  40.     td->handle = importbuffer_fd(td->dma_fd, td->size_with_stride);
  41.     td->buffer = wrapbuffer_handle(td->handle, td->stride, td->height, td->format);

  42.     td->rect = rect;

  43.     m_timer.stop(__func__);
  44.     return td;
  45. }

  46. std::unique_ptr<TransformData> Transformer::wrapTransformData(const im_rect &rect)
  47. {
  48.     m_timer.record(__func__);

  49.     std::unique_ptr<TransformData> td(new TransformData());

  50.     td->width = rect.width;
  51.     td->height = rect.height;
  52.     td->format = m_format;
  53.     td->size = td->width * td->height * get_bpp_from_format(td->format);

  54.     // 对齐后的宽度
  55.     td->stride = td->width;
  56.     td->size_with_stride = td->size;
  57.     if (td->width % m_align_bit)
  58.     {
  59.         td->stride = (td->width / m_align_bit + 1) * m_align_bit;
  60.         td->size_with_stride = td->size / td->width * td->stride;
  61.     }

  62.     // 使用dma_heap分配内存调用RGA
  63.     td->dma_fd = -1;
  64.     dma_buf_alloc(DMA_HEAP_PATH, td->size_with_stride, &(td->dma_fd), reinterpret_cast<void **>(&(td->data)));
  65.     assert(td->dma_fd != -1);

  66.     td->handle = importbuffer_fd(td->dma_fd, td->size_with_stride);
  67.     td->buffer = wrapbuffer_handle(td->handle, td->stride, td->height, td->format);

  68.     td->rect = {};

  69.     m_timer.stop(__func__);
  70.     return td;
  71. }

  72. void Transformer::resetTransformData(std::unique_ptr<TransformData> &td)
  73. {
  74.     if (td)
  75.     {
  76.         m_timer.record(__func__);

  77.         // invalid CPU cache
  78.         dma_sync_device_to_cpu(td->dma_fd);
  79.         std::cout << "td->dma_fd: " << td->dma_fd << std::endl;
  80.         dma_buf_free(td->size_with_stride, &(td->dma_fd), reinterpret_cast<void **>(&(td->data)));

  81.         // release buffer
  82.         releasebuffer_handle(td->handle);

  83.         // reset
  84.         td.reset(nullptr);

  85.         m_timer.stop(__func__);
  86.     }
  87. }
复制代码
crop + resize 实际就是把原始图像中某一个区域进行resize操作
  1. void *Transformer::process(cv::Mat &cv_src, const im_rect &crop_rect, const im_rect &dst_info)
  2. {
  3.     m_timer.record(__func__);

  4.     // init src TransformData
  5.     resetTransformData(m_src);
  6.     m_src = wrapTransformData(cv_src, crop_rect);

  7.     // init dst TransformData
  8.     resetTransformData(m_dst);
  9.     m_dst = wrapTransformData(dst_info);

  10.     // rga process
  11.     IM_STATUS ret = imcheck(m_src->buffer, m_dst->buffer, m_src->rect, m_dst->rect);
  12.     assert(ret == IM_STATUS_NOERROR);

  13.     ret = improcess(m_src->buffer, m_dst->buffer, {}, m_src->rect, m_dst->rect, {}, IM_SYNC);
  14.     assert(ret == IM_STATUS_SUCCESS);

  15.     m_timer.stop(__func__);
  16.     return reinterpret_cast<void *>(m_dst->data);
  17. }
复制代码
请问是代码中的哪些地方影响了处理速度?有什么不合理的地方?


作者: jefferyzhang    时间: 2024-3-29 09:15
硬件算法仅对Non-Cache的物理连续Buffer友好。
这种CPU从MMU申请的非连续还带Cache的buffer,同步cache以及频繁的mmu访问都是速度低下的原因。
作者: 萌虎龟来    时间: 2024-3-29 10:34
你好,针对你的建议,我的理解是:
1. 带Cache的buffer,意思是需要将DMA_HEAP_PATH修改为DMA_HEAP_UNCACHE_PATH ?
2. 同步cache,意思是取消dma_sync_device_to_cpu ?
3. 频繁的mmu访问,意思是dma_buf_alloc在外部调用一次,在后续批处理过程中重复使用同一个dma_fd ?
这样理解对吗?

问题还有:
1. 要求输出结果为127,那么RK_FORMAT_RGB_888 RGA3要求16对齐,那么我需要将wstride设置为128,这样循环拷贝依然存在,耗时存在,但是在RGA处理中对齐后格式可以直接作为rknn zero-copy的输入,所以这一步有没有更好的处理方案;
2. 如何保证buffer是连续的?在sample中提到了rga_allocator_dma32_demo.cpp不保证物理连续,其他方式并没有提及?
2.
作者: jefferyzhang    时间: 2024-3-29 16:34
萌虎龟来 发表于 2024-3-29 10:34
你好,针对你的建议,我的理解是:
1. 带Cache的buffer,意思是需要将DMA_HEAP_PATH修改为DMA_HEAP_UNCACHE ...

1. 改用CMA
2. 不用cache就不存在同步
3. CMA物理连续,使用物理地址不需要访问mmu
4. 对其可以用RGA Crop
5. 代码里存在memcpy就是有问题的写法,要从架构设计上进出buf就得是dma/cma ,如果你想cpu读一个图再用rga,那是无意义的。




欢迎光临 Toybrick (https://t.rock-chips.com/) Powered by Discuz! X3.3