详解全志V85x内G2D模块实现图片格式步骤方法

全志在线 2023-04-18 17:17

G2D模块概述

作者@chhjnavy

原文:https://bbs.aw-ol.com/topic/3291/


G2D主要功能:
1)旋转:支持90、180、270旋转;
2)scale:放缩;

3)镜像反转:H / V;

4)透明叠加:实现两个rgb图片叠加;

5)格式转换:yuv转rgb等多种格式相互间转换;

6)矩形填充,等诸多功能;



G2D配置


源码目录

  • tina-v853-docker/kernel/linux-4.9/drivers/char/sunxi_g2d


make kernel_menuconfig 配置

  • Device Drivers > Character devices > sunxi g2d driver


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 = 89 IRQ_TYPE_LEVEL_HIGH>;      clocks = <&clk_g2d>;      iommus = <&mmu_aw 3 1>;      status = "okay";    };


注:status 要设定为“okay” 状态。


重新编译内核

使用烧录工具PhoenixSuit 将编译打包好的img镜像烧录到开发板。


adb shell 打开控制终端查看设备节点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;}


G2D sample具体应用


G2D sample目录


进行rotation,scale,格式转换

具体实现:将 nv21 格式的1920x1080图转换成rgb888 格式并放缩为640x360 大小。具体用到两个功能,格式转换和放缩。


首先根据1920x1080 nv21 格式以及 640x360 rgb888 格式申请虚拟地址空间以及转换成物理地址(注意:g2d 转换是在物理地址中完成的)


1920x1080 nv21 格式空间大小(输入文件):

  • Y 占 19201080 = 2073600 字节

  • UV 占 19201080 / 2 = 1036800 字节


640x360 rgb888 格式空间大小(输出文件):

  • RGB 占 6403603 = 691200 字节


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

g2d_getPhyAddrByVirAddr()


申请虚拟空间并转换成物理空间完整函数如下:

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; }


通过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);


读出 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);        }


打开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;}


转化完成后将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);        }


转化步骤总结


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

  1. 为打开 iomen 初始化;

  2. 为src以及dst图资申请虚拟地址空间并转换成物理地址空间;

  3. 将src图资放入虚拟地址空间,然后自动映射到物理地址空间;

  4. 打开g2d 设备节点进行转换(最重要的一环,可以通过手册分析具体怎么转换的);

  5. 将转换好的dst图资保存起来;


-End-

本文转载自:https://bbs.aw-ol.com/topic/3291/

评论
  • 智能汽车可替换LED前照灯控制运行的原理涉及多个方面,包括自适应前照灯系统(AFS)的工作原理、传感器的应用、步进电机的控制以及模糊控制策略等。当下时代的智能汽车灯光控制系统通过车载网关控制单元集中控制,表现特殊点的有特斯拉,仅通过前车身控制器,整个系统就包括了灯光旋转开关、车灯变光开关、左LED前照灯总成、右LED前照灯总成、转向柱电子控制单元、CAN数据总线接口、组合仪表控制单元、车载网关控制单元等器件。变光开关、转向开关和辅助操作系统一般连为一体,开关之间通过内部线束和转向柱装置连接为多,
    lauguo2013 2024-12-10 15:53 81浏览
  • 【萤火工场CEM5826-M11测评】OLED显示雷达数据本文结合之前关于串口打印雷达监测数据的研究,进一步扩展至 OLED 屏幕显示。该项目整体分为两部分: 一、框架显示; 二、数据采集与填充显示。为了减小 MCU 负担,采用 局部刷新 的方案。1. 显示框架所需库函数 Wire.h 、Adafruit_GFX.h 、Adafruit_SSD1306.h . 代码#include #include #include #include "logo_128x64.h"#include "logo_
    无垠的广袤 2024-12-10 14:03 69浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-10 16:13 105浏览
  • RK3506 是瑞芯微推出的MPU产品,芯片制程为22nm,定位于轻量级、低成本解决方案。该MPU具有低功耗、外设接口丰富、实时性高的特点,适合用多种工商业场景。本文将基于RK3506的设计特点,为大家分析其应用场景。RK3506核心板主要分为三个型号,各型号间的区别如下图:​图 1  RK3506核心板处理器型号场景1:显示HMIRK3506核心板显示接口支持RGB、MIPI、QSPI输出,且支持2D图形加速,轻松运行QT、LVGL等GUI,最快3S内开
    万象奥科 2024-12-11 15:42 68浏览
  • 近日,搭载紫光展锐W517芯片平台的INMO GO2由影目科技正式推出。作为全球首款专为商务场景设计的智能翻译眼镜,INMO GO2 以“快、准、稳”三大核心优势,突破传统翻译产品局限,为全球商务人士带来高效、自然、稳定的跨语言交流体验。 INMO GO2内置的W517芯片,是紫光展锐4G旗舰级智能穿戴平台,采用四核处理器,具有高性能、低功耗的优势,内置超微高集成技术,采用先进工艺,计算能力相比同档位竞品提升4倍,强大的性能提供更加多样化的应用场景。【视频见P盘链接】 依托“
    紫光展锐 2024-12-11 11:50 47浏览
  •         在有电流流过的导线周围会感生出磁场,再用霍尔器件检测由电流感生的磁场,即可测出产生这个磁场的电流的量值。由此就可以构成霍尔电流、电压传感器。因为霍尔器件的输出电压与加在它上面的磁感应强度以及流过其中的工作电流的乘积成比例,是一个具有乘法器功能的器件,并且可与各种逻辑电路直接接口,还可以直接驱动各种性质的负载。因为霍尔器件的应用原理简单,信号处理方便,器件本身又具有一系列的du特优点,所以在变频器中也发挥了非常重要的作用。  &nb
    锦正茂科技 2024-12-10 12:57 76浏览
  •         霍尔传感器是根据霍尔效应制作的一种磁场传感器。霍尔效应是磁电效应的一种,这一现象是霍尔(A.H.Hall,1855—1938)于1879年在研究金属的导电机构时发现的。后来发现半导体、导电流体等也有这种效应,而半导体的霍尔效应比金属强得多,利用这现象制成的各种霍尔元件,广泛地应用于工业自动化技术、检测技术及信息处理等方面。霍尔效应是研究半导体材料性能的基本方法。通过霍尔效应实验测定的霍尔系数,能够判断半导体材料的导电类型、载流子浓度及载流子
    锦正茂科技 2024-12-10 11:07 64浏览
  • 概述 通过前面的研究学习,已经可以在CycloneVGX器件中成功实现完整的TDC(或者说完整的TDL,即延时线),测试结果也比较满足,解决了超大BIN尺寸以及大量0尺寸BIN的问题,但是还是存在一些之前系列器件还未遇到的问题,这些问题将在本文中进行详细描述介绍。 在五代Cyclone器件内部系统时钟受限的情况下,意味着大量逻辑资源将被浪费在于实现较大长度的TDL上面。是否可以找到方法可以对此前TDL的长度进行优化呢?本文还将探讨这个问题。TDC前段BIN颗粒堵塞问题分析 将延时链在逻辑中实现后
    coyoo 2024-12-10 13:28 101浏览
  • 一、SAE J1939协议概述SAE J1939协议是由美国汽车工程师协会(SAE,Society of Automotive Engineers)定义的一种用于重型车辆和工业设备中的通信协议,主要应用于车辆和设备之间的实时数据交换。J1939基于CAN(Controller Area Network)总线技术,使用29bit的扩展标识符和扩展数据帧,CAN通信速率为250Kbps,用于车载电子控制单元(ECU)之间的通信和控制。小北同学在之前也对J1939协议做过扫盲科普【科普系列】SAE J
    北汇信息 2024-12-11 15:45 77浏览
  • 时源芯微——RE超标整机定位与解决详细流程一、 初步测量与问题确认使用专业的电磁辐射测量设备,对整机的辐射发射进行精确测量。确认是否存在RE超标问题,并记录超标频段和幅度。二、电缆检查与处理若存在信号电缆:步骤一:拔掉所有信号电缆,仅保留电源线,再次测量整机的辐射发射。若测量合格:判定问题出在信号电缆上,可能是电缆的共模电流导致。逐一连接信号电缆,每次连接后测量,定位具体哪根电缆或接口导致超标。对问题电缆进行处理,如加共模扼流圈、滤波器,或优化电缆布局和屏蔽。重新连接所有电缆,再次测量
    时源芯微 2024-12-11 17:11 74浏览
  • 我的一台很多年前人家不要了的九十年代SONY台式组合音响,接手时只有CD功能不行了,因为不需要,也就没修,只使用收音机、磁带机和外接信号功能就够了。最近五年在外地,就断电闲置,没使用了。今年9月回到家里,就一个劲儿地忙着收拾家当,忙了一个多月,太多事啦!修了电气,清理了闲置不用了的电器和电子,就是一个劲儿地扔扔扔!几十年的“工匠式”收留收藏,只能断舍离,拆解不过来的了。一天,忽然感觉室内有股臭味,用鼻子的嗅觉功能朝着臭味重的方向寻找,觉得应该就是这台组合音响?怎么会呢?这无机物的东西不会腐臭吧?
    自做自受 2024-12-10 16:34 136浏览
  • 全球知名半导体制造商ROHM Co., Ltd.(以下简称“罗姆”)宣布与Taiwan Semiconductor Manufacturing Company Limited(以下简称“台积公司”)就车载氮化镓功率器件的开发和量产事宜建立战略合作伙伴关系。通过该合作关系,双方将致力于将罗姆的氮化镓器件开发技术与台积公司业界先进的GaN-on-Silicon工艺技术优势结合起来,满足市场对高耐压和高频特性优异的功率元器件日益增长的需求。氮化镓功率器件目前主要被用于AC适配器和服务器电源等消费电子和
    电子资讯报 2024-12-10 17:09 87浏览
  • 天问Block和Mixly是两个不同的编程工具,分别在单片机开发和教育编程领域有各自的应用。以下是对它们的详细比较: 基本定义 天问Block:天问Block是一个基于区块链技术的数字身份验证和数据交换平台。它的目标是为用户提供一个安全、去中心化、可信任的数字身份验证和数据交换解决方案。 Mixly:Mixly是一款由北京师范大学教育学部创客教育实验室开发的图形化编程软件,旨在为初学者提供一个易于学习和使用的Arduino编程环境。 主要功能 天问Block:支持STC全系列8位单片机,32位
    丙丁先生 2024-12-11 13:15 49浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦