Navigation

    全志在线开发者论坛

    • Register
    • Login
    • Search
    • Categories
    • Tags
    • 在线文档
    • 社区主页

    v851s g2d 模块 sample 深究

    V Series
    2
    2
    2493
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • C
      chhjnavy LV 5 last edited by

      1. g2d 模块概述

      g2d 主要功能:
      1)旋转:支持90、180、270旋转;
      2)镜像反转:H / V;
      3) scale:放缩
      4)格式转换:yuv 转 rgb 等,多种格式相互间转换;
      5)透明叠加功能:实现两个rgb图片叠加;
      6)矩形填充,等诸多功能;

      2. g2d 配置
      1)源码目录:tina-v853-docker/kernel/linux-4.9/drivers/char/sunxi_g2d

      2)make kernel_menuconfig 配置

      Device Drivers > Character devices > sunxi g2d driver
      按空格键选中【*】
      309b3811-659e-4000-8634-7e867717ab87-image.png

      3)Device Tree 设备树配置
      sun8iw21p1.dtsi路径:
      tina-v853-docker/kernel/linux-4.9/arch/arm/boot/dts/sun8iw21p1.dtsi

      		g2d: g2d@05410000 {
      			compatible = "allwinner,sunxi-g2d";
      			reg = <0x0 0x05410000 0x0 0xbffff>;
      			interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
      			clocks = <&clk_g2d>;
      			iommus = <&mmu_aw 3 1>;
      			status = "okay";
      		};
      

      status 要设定为“okay” 状态。

      4)重新编译内核

      mkernel
      make -j1 V=s
      pack
      

      使用烧录工具PhoenixSuit 将路径:tina-v853-docker/out/v851s/lizard/openwrt/v851s_linux_lizard_uart0.img 下的img 镜像烧录到开发板。

      adb shell 打开控制终端查看设备节点G2D:
      483651d3-abc6-4e99-9a22-e5bac90a0194-image.png

      5)通过G2D 设备节点,对g2d 进行操作

      static int SampleG2d_G2dOpen(SAMPLE_G2D_CTX *p_g2d_ctx)
      {
          int ret = 0;
          p_g2d_ctx->mG2dFd = open("/dev/g2d", O_RDWR, 0);
          if (p_g2d_ctx->mG2dFd < 0)
          {
              aloge("fatal error! open /dev/g2d failed");
              ret = -1;
          }
          return ret;
      }
      

      3. 详解 eyesee-mpp 中g2d sample 具体应用
      1)eyesee-mpp 中 g2d sample 编译与执行请参考另一篇帖子
      链接文本

      2)g2d sample 目录
      3e6039cc-ec14-4724-942b-92852b697e74-image.png

      3)运用 g2d 进行rotation,scale,格式转换
      具体实现:将 nv21 格式的1920x1080图转换成rgb888 格式并放缩为640x360 大小。具体用到两个功能,格式转换和放缩。
      步骤如下:
      1))根据1920x1080 nv21 格式以及 640x360 rgb888 格式申请虚拟地址空间以及转换成物理地址(注意:g2d 转换是在物理地址中完成的)

      1920x1080 nv21 格式空间大小(输入文件):
      a804f646-d146-4e43-8f2f-9ee1352cfc8e-image.png
      Y 占 19201080 = 2073600 字节
      UV 占 1920
      1080 / 2 = 1036800 字节

      640x360 rgb888 格式空间大小(输出文件):
      RGB 占 6403603 = 691200 字节

      另外:虚拟地址转换成物理地址使用如下函数:

      g2d_getPhyAddrByVirAddr()
      

      申请虚拟空间并转换成物理空间完整函数如下:
      在文件 tina-v853-docker/platform/allwinner/eyesee-mpp/middleware/sun8iw21/sample/sample_g2d/sample_g2d.c/sample_g2d.c 中

      static int PrepareFrmBuff(SAMPLE_G2D_CTX *p_g2d_ctx)
      {
          SampleG2dConfig *pConfig = NULL;
          unsigned int size = 0;
      
          pConfig = &p_g2d_ctx->mConfigPara;
          
          p_g2d_ctx->src_frm_info.frm_width = pConfig->mSrcWidth;
          p_g2d_ctx->src_frm_info.frm_height =  pConfig->mSrcHeight;
      
          p_g2d_ctx->dst_frm_info.frm_width = pConfig->mDstWidth;
          p_g2d_ctx->dst_frm_info.frm_height = pConfig->mDstHeight;
      
          size = ALIGN(p_g2d_ctx->src_frm_info.frm_width, 16)*ALIGN(p_g2d_ctx->src_frm_info.frm_height, 16);
          if(pConfig->mPicFormat == MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420 || pConfig->mPicFormat == MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420)
          {
              p_g2d_ctx->src_frm_info.p_vir_addr[0] = (void *)g2d_allocMem(size);
              if(NULL == p_g2d_ctx->src_frm_info.p_vir_addr[0])
              {
                  aloge("malloc_src_frm_y_mem_failed");
                  return -1;
              }
      
              p_g2d_ctx->src_frm_info.p_vir_addr[1] = (void *)g2d_allocMem(size/2);
              if(NULL == p_g2d_ctx->src_frm_info.p_vir_addr[1])
              {
                  g2d_freeMem(p_g2d_ctx->src_frm_info.p_vir_addr[0]);
                  aloge("malloc_src_frm_c_mem_failed");    
                  return -1;
              }
      
              p_g2d_ctx->src_frm_info.p_phy_addr[0] = (void *)g2d_getPhyAddrByVirAddr(p_g2d_ctx->src_frm_info.p_vir_addr[0]); 
              p_g2d_ctx->src_frm_info.p_phy_addr[1] = (void *)g2d_getPhyAddrByVirAddr(p_g2d_ctx->src_frm_info.p_vir_addr[1]);
          }
      
      	if(pConfig->mDstPicFormat == MM_PIXEL_FORMAT_RGB_888)
      	{
      		size = p_g2d_ctx->dst_frm_info.frm_width * p_g2d_ctx->dst_frm_info.frm_height * 3;
      		p_g2d_ctx->dst_frm_info.p_vir_addr[0] = (void *)g2d_allocMem(size);
      		if(NULL == p_g2d_ctx->dst_frm_info.p_vir_addr[0])
      		{
      			if(p_g2d_ctx->src_frm_info.p_vir_addr[0] != NULL)
      			{
      				g2d_freeMem(p_g2d_ctx->src_frm_info.p_vir_addr[0]); 
      			}
      			if(p_g2d_ctx->src_frm_info.p_vir_addr[1] != NULL)
      			{
      				g2d_freeMem(p_g2d_ctx->src_frm_info.p_vir_addr[1]);
      			}
      			aloge("malloc_dst_frm_y_mem_failed");
      			return -1;
      		}
      		p_g2d_ctx->dst_frm_info.p_phy_addr[0] = (void *)g2d_getPhyAddrByVirAddr(p_g2d_ctx->dst_frm_info.p_vir_addr[0]); 
      	}
      
          return 0; 
      }
      

      2))通过fopen 传菜间两个文件句柄,fd_in fd_out 用来操作输入输出两个文件资源

              p_g2d_ctx->fd_in = fopen(p_g2d_ctx->mConfigPara.SrcFile,"r");
              if(NULL == p_g2d_ctx->fd_in)
              {
                  aloge("open src file failed");
                  ret = -1;
                  goto _err2;
              }
              fseek(p_g2d_ctx->fd_in, 0, SEEK_SET);
      
                  p_g2d_ctx->fd_out = fopen(p_g2d_ctx->mConfigPara.DstFile, "wb");
                  if (NULL == p_g2d_ctx->fd_out)
                  {
                      aloge("open out file failed");
                      ret = -1;
                      goto _err2;
                  }
                  fseek(p_g2d_ctx->fd_out, 0, SEEK_SET);
      

      3))读出 1920x1080 nv21 图资放入 虚拟空间

      read_len = p_g2d_ctx->src_frm_info.frm_width * p_g2d_ctx->src_frm_info.frm_height;
              if(pConfig->mPicFormat == MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420|| pConfig->mPicFormat == MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420)
              {
                  size1 = fread(p_g2d_ctx->src_frm_info.p_vir_addr[0] , 1, read_len, p_g2d_ctx->fd_in);
                  if(size1 != read_len)
                  {
                      aloge("read_y_data_frm_src_file_invalid");
                  }
                  size2 = fread(p_g2d_ctx->src_frm_info.p_vir_addr[1], 1, read_len /2, p_g2d_ctx->fd_in);
                  if(size2 != read_len/2)
                  {
                      aloge("read_c_data_frm_src_file_invalid");
                  }
      
                  fclose(p_g2d_ctx->fd_in);
      
                  g2d_flushCache((void *)p_g2d_ctx->src_frm_info.p_vir_addr[0], read_len);
                  g2d_flushCache((void *)p_g2d_ctx->src_frm_info.p_vir_addr[1], read_len/2);
              }
      

      4))打开g2d 初始化,并开始转换

      ret = SampleG2d_G2dOpen(p_g2d_ctx);
          if (ret < 0)
          {
              aloge("fatal error! open /dev/g2d fail!");
              goto _err2;
          }
          ret = SampleG2d_G2dConvert(p_g2d_ctx);
          if (ret < 0)
          {
              aloge("fatal error! g2d convert fail!");
              goto _close_g2d;
          }
      //具体转化函数:
      
      static int SampleG2d_G2dConvert_scale(SAMPLE_G2D_CTX *p_g2d_ctx)
      {
          int ret = 0;
          g2d_blt_h blit;
          g2d_fmt_enh eSrcFormat, eDstFormat; 
          SampleG2dConfig *pConfig = NULL;
      
          pConfig = &p_g2d_ctx->mConfigPara;
      
          ret = convert_PIXEL_FORMAT_E_to_g2d_fmt_enh(pConfig->mPicFormat, &eSrcFormat);
          if(ret!=SUCCESS)
          {
              aloge("fatal error! src pixel format[0x%x] is invalid!", pConfig->mPicFormat);
              return -1;
          }
          ret = convert_PIXEL_FORMAT_E_to_g2d_fmt_enh(pConfig->mDstPicFormat, &eDstFormat);
          if(ret!=SUCCESS)
          {
              aloge("fatal error! dst pixel format[0x%x] is invalid!", pConfig->mPicFormat);
              return -1;
          }
      
          //config blit
          memset(&blit, 0, sizeof(g2d_blt_h));
      
          if(0 != pConfig->mDstRotate)
          {
              aloge("fatal_err: rotation can't be performed when do scaling");
          }
      
          blit.flag_h = G2D_BLT_NONE_H;       // angle rotation used
      //    switch(pConfig->mDstRotate)
      //    {
      //        case 0:
      //            blit.flag_h = G2D_BLT_NONE_H;   //G2D_ROT_0, G2D_BLT_NONE_H
      //            break;
      //        case 90:
      //            blit.flag_h = G2D_ROT_90;
      //            break;
      //        case 180:
      //            blit.flag_h = G2D_ROT_180;
      //            break;
      //        case 270:
      //            blit.flag_h = G2D_ROT_270;
      //            break;
      //        default:
      //            aloge("fatal error! rotation[%d] is invalid!", pConfig->mDstRotate);
      //            blit.flag_h = G2D_BLT_NONE_H;
      //            break;
      //    }
          //blit.src_image_h.bbuff = 1;
          //blit.src_image_h.color = 0xff;
          blit.src_image_h.format = eSrcFormat;
          blit.src_image_h.laddr[0] = (unsigned int)p_g2d_ctx->src_frm_info.p_phy_addr[0];
          blit.src_image_h.laddr[1] = (unsigned int)p_g2d_ctx->src_frm_info.p_phy_addr[1];
          blit.src_image_h.laddr[2] = (unsigned int)p_g2d_ctx->src_frm_info.p_phy_addr[2];
          //blit.src_image_h.haddr[] = 
          blit.src_image_h.width = p_g2d_ctx->src_frm_info.frm_width;
          blit.src_image_h.height = p_g2d_ctx->src_frm_info.frm_height;
          blit.src_image_h.align[0] = 0;
          blit.src_image_h.align[1] = 0;
          blit.src_image_h.align[2] = 0;
          blit.src_image_h.clip_rect.x = pConfig->mSrcRectX;
          blit.src_image_h.clip_rect.y = pConfig->mSrcRectY;
          blit.src_image_h.clip_rect.w = pConfig->mSrcRectW;
          blit.src_image_h.clip_rect.h = pConfig->mSrcRectH;
          blit.src_image_h.gamut = G2D_BT601;
          blit.src_image_h.bpremul = 0;
          //blit.src_image_h.alpha = 0xff;
          blit.src_image_h.mode = G2D_PIXEL_ALPHA;   //G2D_PIXEL_ALPHA, G2D_GLOBAL_ALPHA
          blit.src_image_h.fd = -1;
          blit.src_image_h.use_phy_addr = 1;
      
          //blit.dst_image_h.bbuff = 1;
          //blit.dst_image_h.color = 0xff;
          blit.dst_image_h.format = eDstFormat;
          blit.dst_image_h.laddr[0] = (unsigned int)p_g2d_ctx->dst_frm_info.p_phy_addr[0];
          blit.dst_image_h.laddr[1] = (unsigned int)p_g2d_ctx->dst_frm_info.p_phy_addr[1];
          blit.dst_image_h.laddr[2] = (unsigned int)p_g2d_ctx->dst_frm_info.p_phy_addr[2];
          //blit.dst_image_h.haddr[] = 
          blit.dst_image_h.width = p_g2d_ctx->dst_frm_info.frm_width;
          blit.dst_image_h.height = p_g2d_ctx->dst_frm_info.frm_height;
          blit.dst_image_h.align[0] = 0;
          blit.dst_image_h.align[1] = 0;
          blit.dst_image_h.align[2] = 0;
          blit.dst_image_h.clip_rect.x = pConfig->mDstRectX;
          blit.dst_image_h.clip_rect.y = pConfig->mDstRectY;
          blit.dst_image_h.clip_rect.w = pConfig->mDstRectW;
          blit.dst_image_h.clip_rect.h = pConfig->mDstRectH;
          blit.dst_image_h.gamut = G2D_BT601;
          blit.dst_image_h.bpremul = 0;
          //blit.dst_image_h.alpha = 0xff;
          blit.dst_image_h.mode = G2D_PIXEL_ALPHA;   //G2D_PIXEL_ALPHA, G2D_GLOBAL_ALPHA
          blit.dst_image_h.fd = -1;
          blit.dst_image_h.use_phy_addr = 1;
      
          ret = ioctl(p_g2d_ctx->mG2dFd, G2D_CMD_BITBLT_H, (unsigned long)&blit);
          if(ret < 0)
          {
              aloge("fatal error! bit-block(image) transfer failed[%d]", ret);
              system("cd /sys/class/sunxi_dump;echo 0x14A8000,0x14A8100 > dump;cat dump");
          }
      
          return ret;
      } 
      
      

      5))转化完成后将640x360 rgb888 图资通过fd_out句柄存储起来

      if(pConfig->mDstPicFormat == MM_PIXEL_FORMAT_RGB_888)
              {
                  out_len = p_g2d_ctx->dst_frm_info.frm_width * p_g2d_ctx->dst_frm_info.frm_height *3;
                  g2d_flushCache((void *)p_g2d_ctx->dst_frm_info.p_vir_addr[0], out_len);
      
                  fwrite(p_g2d_ctx->dst_frm_info.p_vir_addr[0], 1, out_len, p_g2d_ctx->fd_out);
              }
      

      4. 总结转化步骤

      通过步骤3中的模块化分析,可以看出g2d 转化大概分为一下步骤:

      1)为打开 iomen 初始化;
      2)为src以及dst图资申请虚拟地址空间并转换成物理地址空间;
      3)将src图资放入虚拟地址空间,然后自动映射到物理地址空间;
      4)打开g2d 设备节点进行转换(最重要的一环,可以通过手册分析具体怎么转换的);
      5)将转换好的dst图资保存起来;

      1 Reply Last reply Reply Quote Share 7
      • P
        proc_c LV 3 last edited by

        你好,我目前有个疑问,这块的编译是跟系统绑在一起编译的,是一个大的makafile。现在需要将这块的编译的mackfile 单独弄出来一份,与我现有的代码做融合,这块的makefile怎样提取出来,比如有哪些这个编译得到依赖项怎样才能找到呢?

        1 Reply Last reply Reply Quote Share 0
        • 1 / 1
        • First post
          Last post

        Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号

        行为准则 | 用户协议 | 隐私权政策