Detailed Explanation of the Allwinner V85x G2D Module Implementation Steps for Image Format

Overview of the G2D Module

Author: @chhjnavy

Original Article: https://bbs.aw-ol.com/topic/3291/

Main Functions of G2D: 1) Rotation: Supports 90, 180, 270 degrees; 2) Scale: Scaling;

3) Mirroring: Horizontal / Vertical;

4) Transparent Overlay: Achieves overlay of two RGB images;

5) Format Conversion: Various format conversions such as YUV to RGB;

6) Rectangle Filling, and many other functions;

Detailed Explanation of the Allwinner V85x G2D Module Implementation Steps for Image Format

G2D Configuration

Source Code Directory

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

Configure with make kernel_menuconfig

  • Device Drivers > Character devices > sunxi g2d driver

Detailed Explanation of the Allwinner V85x G2D Module Implementation Steps for Image Format

Device Tree Configuration

  • Path of 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";    };

Note: The status must be set to “okay”.

Recompile the Kernel

Use the flashing tool PhoenixSuit to flash the compiled img image onto the development board.

Open the control terminal with adb shell to check the device node G2D:

Detailed Explanation of the Allwinner V85x G2D Module Implementation Steps for Image Format

Operations via G2D Device Node

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

Detailed Explanation of the Allwinner V85x G2D Module Implementation Steps for Image Format

Specific Applications of G2D Sample

G2D Sample Directory

Detailed Explanation of the Allwinner V85x G2D Module Implementation Steps for Image Format

Performing Rotation, Scaling, and Format Conversion

Specific Implementation: Convert a 1920×1080 NV21 format image to RGB888 format and scale it down to 640×360 size. This involves two functions: format conversion and scaling.

First, allocate virtual address space based on the 1920×1080 NV21 format and the 640×360 RGB888 format, and convert to physical addresses (note: G2D conversion is performed in physical addresses).

Size of 1920×1080 NV21 Format Space (Input File):

  • Y occupies 1920*1080 = 2073600 bytes

  • UV occupies 1920*1080 / 2 = 1036800 bytes

Detailed Explanation of the Allwinner V85x G2D Module Implementation Steps for Image Format

Size of 640×360 RGB888 Format Space (Output File):

  • RGB occupies 640*360*3 = 691200 bytes

Additionally: Use the following function to convert virtual addresses to physical addresses:

g2d_getPhyAddrByVirAddr();

The complete function to allocate virtual space and convert to physical space is as follows:

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

Use fopen to pass two file handles, fd_in and fd_out, to operate on the input and output file resources.

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

Read the 1920×1080 NV21 image data into virtual space

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

Open G2D, initialize, and start conversion

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;    }// Specific conversion function: 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;}

After conversion, store the 640×360 RGB888 image data using the fd_out handle

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

Detailed Explanation of the Allwinner V85x G2D Module Implementation Steps for Image Format

Summary of Conversion Steps

Through the modular analysis in Step 3, it can be seen that G2D conversion is roughly divided into the following steps:

  1. Initialize to open I/O memory;

  2. Allocate virtual address space for src and dst image data and convert to physical address space;

  3. Place src image data into virtual address space, then automatically map to physical address space;

  4. Open the G2D device node for conversion (the most important step, specific conversion can be analyzed through the manual);

  5. Save the converted dst image data;

-End-

This article is reproduced from: https://bbs.aw-ol.com/topic/3291/

Detailed Explanation of the Allwinner V85x G2D Module Implementation Steps for Image Format

Leave a Comment