主题 : Tiny210v2( S5PV210 )平台下FIMG对应的G2D驱动中,关于graphic data的理解 复制链接 | 浏览器收藏 | 打印
级别: 骑士
UID: 5844
精华: 9
发帖: 64
金钱: 770 两
威望: 154 点
贡献值: 9 点
综合积分: 308 分
注册时间: 2009-05-11
最后登录: 2019-05-14
楼主  发表于: 2012-12-14 20:09

 Tiny210v2( S5PV210 )平台下FIMG对应的G2D驱动中,关于graphic data的理解

管理提醒: 本帖被 xoom 执行加亮操作(2012-12-15)

    1. G2D功能大概
    2. G2D内部处理流程
    3. 驱动实现-预留内存
    4. 驱动实现-控制寄存器IOMEM 和 IRQ
    5. 驱动实现-probe
    6. 驱动实现-ioctl
    7. 驱动实现-ioctl的参数
    8. 用户空间的测试程序
    9. 结论


    G2D驱动的源代码比较少,功能也比较单一,看起来比较容易,因此先理解了一下G2D的驱动,重点不是理解G2D的每一个机能应该如何使用,而是G2D从哪里获取原始数据,处理完后会将数据放到哪里,这些数据和fb设备文件的framebuffer数据有没有关系。

1. G2D功能大概

    G2D主要是2D图形加速器,用于对已有图形数据的处理,比如拷贝,拉伸,旋转,翻转,alpha透过等处理。这和我以前理解的图形加速稍微有一些不一样。以前理解DirectFB的时候,好像要求还会有画点,画线,画矩形等加速功能。
    所以我理解G2D的定义是针对贴图应用程序的加强吧,而不是针对描画等程序进行增强的。贴图应用程序是指那些将背景图或者素材以图片形式保留起来,画图的时候,将这些素材直接贴到相应的位置上。


2. G2D内部处理流程

    在S5PV210的用户文档中,专门提到了G2D的处理流程,参考下面的图:
        


    需要留意的是,G2D驱动程序差不多也是按照这个图去设置的控制寄存器,具体参考后面的内容。

3. 驱动实现-预留内存
    
    开发板在启动过程中,为G2D预留了8M的内存。

复制代码
  1.         arch/arm/plat-s5pv210/mach-mini210.c
  2.         ----------------------------------------------------------
  3.         #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_G2D        ( 8192 * SZ_1K)
  4.         
  5.         static struct s5p_media_device mini210_media_devs[] = {
  6.             ......
  7.             #if defined(CONFIG_VIDEO_G2D)
  8.             {
  9.                 .id            = S5P_MDEV_G2D,
  10.                 .name        = "g2d",
  11.                 .bank        = 0,
  12.                 .memsize    = S5PV210_VIDEO_SAMSUNG_MEMSIZE_G2D,
  13.                 .paddr        = 0,
  14.             },
  15.             #endif
  16.             ......
  17.         }


4. 驱动实现-控制寄存器IOMEM 和 IRQ

    G2D 使用的系统资源主要是:
    * IOMEM -> G2D 的控制寄存器
    * IRQ   -> G2D 的中断号

    控制寄存器的地址和S5PV210用户手册上的寄存器地址能对应上,而中断主要是在处理结束的时候,通知系统,用于开始下一次操作。


复制代码
  1.         arch/arm/plat-s5pv210/include/mach/map.h
  2.         ----------------------------------------------------------
  3.         /* fimg2d */
  4.         #define S5PV210_PA_FIMG2D       (0xFA000000)
  5.         #define S5P_PA_FIMG2D           S5PV210_PA_FIMG2D
  6.         #define S5P_SZ_FIMG2D           SZ_1M
  7.         
  8.         arch/arm/plat-s5p/devs.c
  9.         ----------------------------------------------------------
  10.         static struct resource s3c_g2d_resources[] = {
  11.             [0] = {
  12.                 .start    = S5P_PA_FIMG2D,
  13.                 .end    = S5P_PA_FIMG2D + S5P_SZ_FIMG2D - 1,
  14.                 .flags    = IORESOURCE_MEM,
  15.             },
  16.             [1] = {
  17.                 .start    = IRQ_2D,
  18.                 .end    = IRQ_2D,
  19.                 .flags    = IORESOURCE_IRQ,
  20.             }
  21.         };
  22.         
  23.         struct platform_device s3c_device_g2d = {
  24.             .name        = "s3c-g2d",
  25.             .id            = -1,
  26.             .num_resources    = ARRAY_SIZE(s3c_g2d_resources),
  27.             .resource    = s3c_g2d_resources,
  28.         };


    下面是控制寄存器的截图:
        


5. 驱动实现-probe

    G2D的probe函数主要进行了IOMEM的申请和映射,预留内存的使用,中断的申请,misc设备的注册,以及驱动程序内部几个关键变量的初始化。

复制代码
  1.         drivers/media/video/samsung/g2d/fimg2d_3x.c
  2.         ----------------------------------------------------------
  3.         static int sec_g2d_probe(struct platform_device *pdev)
  4.         {
  5.             struct resource *res;
  6.             int ret = 0;
  7.         
  8.             pr_debug("g2d: start probe : name=%s num=%d res[0].start=0x%x res[1].start=0x%x\n",
  9.                     pdev->name, pdev->num_resources,
  10.                     pdev->resource[0].start, pdev->resource[1].start);
  11.         
  12.             /* get the memory region */
  13.             res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  14.             if (res == NULL) {
  15.                 pr_err("g2d: failed to get memory region resouce\n");
  16.                 ret = -ENOENT;
  17.                 goto probe_out;
  18.             }
  19.         
  20.             g_g2d_mem = request_mem_region(res->start,
  21.                     res->end - res->start + 1,
  22.                     pdev->name);
  23.             if (g_g2d_mem == NULL) {
  24.                 pr_err("g2d: failed to reserve memory region\n");
  25.                 ret = -ENOENT;
  26.                 goto err_mem_req;
  27.             }
  28.         
  29.             /* ioremap */
  30.             g_g2d_base = ioremap(g_g2d_mem->start, g_g2d_mem->end - res->start + 1);
  31.             if (g_g2d_base == NULL) {
  32.                 pr_err("g2d: failed ioremap\n");
  33.                 ret = -ENOENT;
  34.                 goto err_mem_map;
  35.             }
  36.         
  37.             /* irq */
  38.             g_g2d_irq_num = platform_get_irq(pdev, 0);
  39.             if (g_g2d_irq_num <= 0) {
  40.                 pr_err("g2d: failed to get irq resouce\n");
  41.                 ret = -ENOENT;
  42.                 goto err_irq_req;
  43.             }
  44.         
  45.             ret = request_irq(g_g2d_irq_num, sec_g2d_irq,
  46.                     IRQF_DISABLED, pdev->name, NULL);
  47.             if (ret) {
  48.                 pr_err("g2d: request_irq(g2d) failed.\n");
  49.                 goto err_irq_req;
  50.             }
  51.         
  52.             /* Get g2d power domain regulator */
  53.             g_g2d_pd_regulator = regulator_get(&pdev->dev, "pd");
  54.             if (IS_ERR(g_g2d_pd_regulator)) {
  55.                 printk(KERN_ERR "g2d: failed to get resource %s\n", "g2d");
  56.                 ret = -ENOENT;
  57.                 goto err_regulator_get;
  58.             }
  59.         
  60.             g_g2d_clk = clk_get(&pdev->dev, "g2d");
  61.             if (g_g2d_clk == NULL) {
  62.                 pr_err("g2d: failed to find g2d clock source\n");
  63.                 ret = -ENOENT;
  64.                 goto err_clk_get;
  65.             }
  66.         
  67.             /* blocking I/O */
  68.             init_waitqueue_head(&g_g2d_waitq);
  69.         
  70.             /* atomic init */
  71.             g_in_use = 0;
  72.         
  73.             /* misc register */
  74.             ret = misc_register(&sec_g2d_dev);
  75.             if (ret) {
  76.                 pr_err("g2d: cannot register miscdev on minor=%d (%d)\n",
  77.                         G2D_MINOR, ret);
  78.                 goto err_misc_reg;
  79.             }
  80.         
  81.             g_g2d_reserved_phys_addr = s5p_get_media_memory_bank(S5P_MDEV_G2D, 0);
  82.             if (g_g2d_reserved_phys_addr == 0) {
  83.                 pr_err("g2d: failed to s3c_get_media_memory_bank !!!\n");
  84.                 ret = -ENOENT;
  85.                 goto err_req_fw;
  86.             }
  87.         
  88.             g_g2d_reserved_size = s5p_get_media_memsize_bank(S5P_MDEV_G2D, 0);
  89.         
  90.             g_g2d_src_phys_addr = g_g2d_reserved_phys_addr;
  91.             g_g2d_src_virt_addr = (u32)phys_to_virt(g_g2d_src_phys_addr);
  92.             g_g2d_src_size      = PAGE_ALIGN(g_g2d_reserved_size >> 1);
  93.         
  94.             g_g2d_dst_phys_addr = g_g2d_src_phys_addr + g_g2d_src_size;
  95.             g_g2d_dst_virt_addr = g_g2d_src_virt_addr + g_g2d_src_size;
  96.             g_g2d_dst_size      = PAGE_ALIGN(g_g2d_reserved_size - g_g2d_src_size);
  97.         
  98.             pr_debug("g2d: sec_g2d_probe ok!\n");
  99.         
  100.             return 0;
  101.         
  102.         err_req_fw:
  103.             misc_deregister(&sec_g2d_dev);
  104.         err_misc_reg:
  105.             clk_put(g_g2d_clk);
  106.             g_g2d_clk = NULL;
  107.         err_clk_get:
  108.             regulator_put(g_g2d_pd_regulator);
  109.         err_regulator_get:
  110.             free_irq(g_g2d_irq_num, NULL);
  111.         err_irq_req:
  112.             iounmap(g_g2d_base);
  113.         err_mem_map:
  114.             release_resource(g_g2d_mem);
  115.             kfree(g_g2d_mem);
  116.         err_mem_req:
  117.         probe_out:
  118.             pr_err("g2d: sec_g2d_probe fail!\n");
  119.             return ret;
  120.         }

    
    我们需要注意一下 g_g2d_dst_* 这几个变量,搜索内核代码,没有发现使用他们的地方,因此这几个变量也就是没有用。
    而g_g2d_src_virt_addr 也没有使用过,因此我理解G2D操作的数据全部使用的是物理地址,这在后来的测试程序中会进行确认。
    g_g2d_src_phys_addr 指向预留内存的物理地址,这个变量在 mmap 的时候会使用,也就是说应用程序可以将这块内存映射到应用程序的内存空间。具体是用来干啥的我没有关注。


6. 驱动实现-ioctl

    sec_g2d_ioctl是G2D的核心函数。sec可能是Samsung Electronics Company的缩写。通过下面的ioctl函数可以得知,G2D提供的操作命令听少的,当然这和它实现的机能单一有关系。其中关于图像处理的,最主要通过 G2D_BLIT 这个cmd实现的。
    G2D_BLIT首先从用户空间获取到参数,并依据这个参数进行控制寄存器的设定;然后让G2D进行运算处理;最后通过中断得到的通知告诉应用程序处理完成了。
    如果在一定时间内等不到G2D完成的信息,驱动程序会认为G2D内部出错了,会将G2D进行RESET。


复制代码
  1.         drivers/media/video/samsung/g2d/fimg2d_3x.c
  2.         ----------------------------------------------------------
  3.         static long sec_g2d_ioctl(struct file *file,
  4.                 unsigned int cmd,
  5.                 unsigned long arg)
  6.         {
  7.             int                  ret    = 0;
  8.             struct g2d_params   *params = NULL;
  9.             struct g2d_dma_info  dma_info;
  10.             void                *vaddr;
  11.         
  12.             switch (cmd) {
  13.                 case G2D_GET_MEMORY:
  14.                     ret = copy_to_user((unsigned int *)arg, &g_g2d_reserved_phys_addr,
  15.                             sizeof(unsigned int));
  16.                     break;
  17.                 case G2D_GET_MEMORY_SIZE:
  18.                     ret = copy_to_user((unsigned int *)arg, &g_g2d_reserved_size,
  19.                             sizeof(unsigned int));
  20.                     break;
  21.                 case G2D_DMA_CACHE_INVAL:
  22.                     ret = copy_from_user(&dma_info, (struct g2d_dma_info *)arg,
  23.                             sizeof(dma_info));
  24.                     vaddr = phys_to_virt(dma_info.addr);
  25.                     dmac_map_area(vaddr, (unsigned long)vaddr + dma_info.size,
  26.                             DMA_FROM_DEVICE);
  27.                     break;
  28.                 case G2D_DMA_CACHE_CLEAN:
  29.                     ret = copy_from_user(&dma_info, (struct g2d_dma_info *)arg,
  30.                             sizeof(dma_info));
  31.                     vaddr = phys_to_virt(dma_info.addr);
  32.                     dmac_map_area(vaddr, (unsigned long)vaddr + dma_info.size,
  33.                             DMA_TO_DEVICE);
  34.                     break;
  35.                 case G2D_DMA_CACHE_FLUSH:
  36.                     ret = copy_from_user(&dma_info, (struct g2d_dma_info *)arg,
  37.                             sizeof(dma_info));
  38.                     vaddr = phys_to_virt(dma_info.addr);
  39.                     dmac_flush_range(vaddr, vaddr + dma_info.size);
  40.                     break;
  41.                 case G2D_SET_MEMORY:
  42.                     ret = copy_from_user(&dma_info, (struct g2d_dma_info *)arg,
  43.                             sizeof(dma_info));
  44.                     vaddr = phys_to_virt(dma_info.addr);
  45.                     memset(vaddr, 0x00000000, dma_info.size);
  46.                     break;
  47.                 default:
  48.                     ret = -1;
  49.                     break;
  50.             }
  51.         
  52.             if (ret == 0)
  53.                 return 0;
  54.         
  55.             mutex_lock(&g_g2d_rot_mutex);
  56.         
  57.             if (file->f_flags & O_NONBLOCK) {
  58.                 if (g_in_use == 1) {
  59.                     if (wait_event_interruptible_timeout(g_g2d_waitq,
  60.                                 (g_in_use == 0),
  61.                                 msecs_to_jiffies(G2D_TIMEOUT)) == 0) {
  62.                         __raw_writel(G2D_SWRESET_R_RESET, g_g2d_base + SOFT_RESET_REG);
  63.                         pr_err("g2d:%s: waiting for interrupt is timeout\n", __func__);
  64.                     }
  65.                 }
  66.             }
  67.         
  68.             g_in_use = 1;
  69.         
  70.             params = (struct g2d_params *)arg;
  71.         
  72.             if (cmd == G2D_BLIT) {
  73.                 /* initialize */
  74.                 sec_g2d_init_regs(params);
  75.         
  76.                 /* bitblit */
  77.                 sec_g2d_rotate_with_bitblt(params);
  78.             } else {
  79.                 pr_err("g2d: unmatched command (%d)\n", cmd);
  80.                 goto sec_g2d_ioctl_done;
  81.             }
  82.         
  83.             if (!(file->f_flags & O_NONBLOCK)) {
  84.                 if (g_in_use == 1) {
  85.                     if (wait_event_interruptible_timeout(g_g2d_waitq,
  86.                                 (g_in_use == 0),
  87.                                 msecs_to_jiffies(G2D_TIMEOUT)) == 0) {
  88.                         __raw_writel(G2D_SWRESET_R_RESET, g_g2d_base + SOFT_RESET_REG);
  89.                         pr_err("g2d:%s:    waiting for interrupt is timeout\n", __func__);
  90.                     }
  91.         
  92.                     g_in_use = 0;
  93.                 }
  94.             }
  95.         
  96.             ret = 0;
  97.         
  98.         sec_g2d_ioctl_done:
  99.         
  100.             mutex_unlock(&g_g2d_rot_mutex);
  101.             return ret;
  102.         }

    
    sec_g2d_init_regs是通过参数进行控制寄存器的设定处理,这些寄存器的设定过程和S5PV210的用户手册提到的G2D的处理流程基本是一致的。

复制代码
  1.         drivers/media/video/samsung/g2d/fimg2d_3x.c
  2.         ----------------------------------------------------------
  3.         static void sec_g2d_init_regs(struct g2d_params *params)
  4.         {
  5.             u32 blt_cmd = 0;
  6.         
  7.             struct g2d_rect *src_rect = params->src_rect;
  8.             struct g2d_rect *dst_rect = params->dst_rect;
  9.             struct g2d_flag *flag     = params->flag;
  10.         
  11.             /* source image */
  12.             blt_cmd |= sec_g2d_set_src_img(src_rect, dst_rect, flag);
  13.         
  14.             /* destination image */
  15.             blt_cmd |= sec_g2d_set_dst_img(dst_rect);
  16.         
  17.             /* rotation */
  18.             blt_cmd |= sec_g2d_set_rotation(flag);
  19.         
  20.             /* color key */
  21.             blt_cmd |= sec_g2d_set_color_key(flag);
  22.         
  23.             /* pattern */
  24.             blt_cmd |= sec_g2d_set_pattern(src_rect, flag);
  25.         
  26.             /* rop & alpha blending */
  27.             blt_cmd |= sec_g2d_set_alpha(src_rect, dst_rect, flag);
  28.         
  29.             /* command */
  30.             sec_g2d_set_bitblt_cmd(src_rect, dst_rect, blt_cmd);
  31.         }


7. 驱动实现-ioctl的参数

    ioctl参数对于理解G2D的实现还是挺有意义的。
    参数包含3个主要部分,原始图形数据的信息,目标图形数据的信息,以及图形处理的FLAG。
    因为图形数据可能是一屏幕数据中的一部分,所以必须告诉G2D整个数据的大小,否则G2D不知到第二行开始的数据在一个连续内存中从哪个地方开始。
    color_format用于数据转化,比如 RGBA -> RGB565。
    FLAG就是额外处理信息了,比如是否需要旋转,是否进行拉伸等。

    特别需要注意的地方是,图形数据的地址是物理地址。


复制代码
  1.         drivers/media/video/samsung/g2d/fimg2d_3x.h
  2.         ----------------------------------------------------------
  3.         struct g2d_rect {
  4.             unsigned int   x;
  5.             unsigned int   y;
  6.             unsigned int   w;
  7.             unsigned int   h;
  8.             unsigned int   full_w;
  9.             unsigned int   full_h;
  10.             int            color_format;
  11.             unsigned int   phys_addr;
  12.             unsigned char *virt_addr;
  13.         };
  14.         struct g2d_params {
  15.             struct g2d_rect *src_rect;
  16.             struct g2d_rect *dst_rect;
  17.             struct g2d_flag *flag;
  18.         };


8. 用户空间的测试程序

    我不太清楚如何在应用程序中,将逻辑地址转化为物理地址,因此写了一个程序来确认一下是不是真的用的是物理地址。
    在之前的 FIMD 程序中分析过,fb0 和 fb3 系统预留了物理内存,他们的关系如下所示:
        ---top---
        fb0 -> win2 : 0x3C795000
        fb3 -> win0 : 0x3C330000
        ---bottom---
    因此在测试程序中,对于图形数据的位置,是直接传递的物理地址。
        * fb0 上画800x100的红条,800x100的绿条,800x100的蓝条。
        * 设置原始数据为fb0的( 0,0 )位置的480x300区域,从0x3C795000开始。
        * 设置目标数据为fb3的( 0,0 )位置的300x480区域,从0x3C330000开始。
        * 设置图形处理FLAG为旋转90度,也就是横条变成竖条。
    因为颜色设置了alpha透过,如果一切顺利,就能够看到6个颜色条互相垂直。


复制代码
  1.         #include <sys/types.h>
  2.         #include <sys/stat.h>
  3.         #include <sys/ioctl.h>
  4.         #include <sys/mman.h>
  5.         #include <fcntl.h>
  6.         #include <stdio.h>
  7.         #include <string.h>
  8.         #include <linux/fb.h>
  9.         
  10.         /*
  11.          * ---top---
  12.          * fb0 -> win2
  13.          * fb3 -> win0
  14.          * ---bottom---
  15.          */
  16.         #define    FBDEV_0        "/dev/fb0"
  17.         #define    FBDEV_3        "/dev/fb3"
  18.         #define G2DDEV        "/dev/sec-g2d"
  19.         
  20.         /* copy from drivers/media/samsung/g2d/fimg2d_3x.h start */
  21.         #define G2D_MINOR  240
  22.         #define G2D_IOCTL_MAGIC 'G'
  23.         #define G2D_BLIT             _IO(G2D_IOCTL_MAGIC, 0)
  24.         
  25.         enum G2D_ROT_DEG {
  26.             G2D_ROT_0 = 0,
  27.             G2D_ROT_90,
  28.             G2D_ROT_180,
  29.             G2D_ROT_270,
  30.             G2D_ROT_X_FLIP,
  31.             G2D_ROT_Y_FLIP
  32.         };
  33.         
  34.         enum G2D_ALPHA_BLENDING_MODE {
  35.             G2D_ALPHA_BLENDING_MIN    = 0,   /* wholly transparent */
  36.             G2D_ALPHA_BLENDING_MAX    = 255, /* 255 */
  37.             G2D_ALPHA_BLENDING_OPAQUE = 256, /* opaque */
  38.         };
  39.         
  40.         enum G2D_COLORKEY_MODE {
  41.             G2D_COLORKEY_NONE = 0,
  42.             G2D_COLORKEY_SRC_ON,
  43.             G2D_COLORKEY_DST_ON,
  44.             G2D_COLORKEY_SRC_DST_ON,
  45.         };
  46.         
  47.         enum G2D_BLUE_SCREEN_MODE {
  48.             G2D_BLUE_SCREEN_NONE = 0,
  49.             G2D_BLUE_SCREEN_TRANSPARENT,
  50.             G2D_BLUE_SCREEN_WITH_COLOR,
  51.         };
  52.         
  53.         enum G2D_ROP_TYPE {
  54.             G2D_ROP_SRC = 0,
  55.             G2D_ROP_DST,
  56.             G2D_ROP_SRC_AND_DST,
  57.             G2D_ROP_SRC_OR_DST,
  58.             G2D_ROP_3RD_OPRND,
  59.             G2D_ROP_SRC_AND_3RD_OPRND,
  60.             G2D_ROP_SRC_OR_3RD_OPRND,
  61.             G2D_ROP_SRC_XOR_3RD_OPRND,
  62.             G2D_ROP_DST_OR_3RD,
  63.         };
  64.         enum G2D_THIRD_OP_MODE {
  65.             G2D_THIRD_OP_NONE = 0,
  66.             G2D_THIRD_OP_PATTERN,
  67.             G2D_THIRD_OP_FG,
  68.             G2D_THIRD_OP_BG
  69.         };
  70.         enum G2D_COLOR_SPACE {
  71.             G2D_RGB_565 = 0,
  72.             G2D_RGBA_8888,
  73.             G2D_ARGB_8888,
  74.             G2D_BGRA_8888,
  75.             G2D_ABGR_8888,
  76.         };
  77.         struct g2d_rect {
  78.             unsigned int   x;
  79.             unsigned int   y;
  80.             unsigned int   w;
  81.             unsigned int   h;
  82.             unsigned int   full_w;
  83.             unsigned int   full_h;
  84.             int            color_format;
  85.             unsigned int   phys_addr;
  86.             unsigned char *virt_addr;
  87.         };
  88.         
  89.         struct g2d_flag {
  90.             unsigned int   rotate_val;
  91.             unsigned int   alpha_val;
  92.             unsigned int   blue_screen_mode;
  93.             unsigned int   color_key_val;
  94.             unsigned int   color_val;
  95.             unsigned int   third_op_mode;
  96.             unsigned int   rop_mode;
  97.             unsigned int   mask_mode;
  98.         };
  99.         
  100.         struct g2d_params {
  101.             struct g2d_rect *src_rect;
  102.             struct g2d_rect *dst_rect;
  103.             struct g2d_flag *flag;
  104.         };
  105.         /* copy from drivers/media/samsung/g2d/fimg2d_3x.h end */
  106.         
  107.         int main( int argc, char *argv[] )
  108.         {
  109.             int fd;
  110.             struct fb_var_screeninfo var;
  111.             int blank;
  112.             int x,y;
  113.             int *p;
  114.             int ret;
  115.             struct g2d_rect src_rect;
  116.             struct g2d_rect dst_rect;
  117.             struct g2d_flag flag;
  118.             struct g2d_params params;
  119.         
  120.             
  121.             /* initial */
  122.             blank = FB_BLANK_UNBLANK;
  123.             memset( &params, 0, sizeof( params ) );
  124.             
  125.             /********************************************************
  126.              *  Operation on /dev/fb0
  127.              *******************************************************/
  128.             /* open fb0 */
  129.             fd = open( FBDEV_0, O_RDWR );
  130.             if( fd < 0 ){
  131.                 printf( "open %s failed\n", FBDEV_0 );
  132.                 return;
  133.             }
  134.             
  135.             /* get var-screen-info from fb0 */
  136.             ret = ioctl( fd, FBIOGET_VSCREENINFO, &var );
  137.             if( ret < 0 ){
  138.                 printf( "ioctl %s FBIOGET_VSCREENINFO failed\n", FBDEV_0 );
  139.             }
  140.             
  141.             /* set no back-buffer */
  142.             var.activate = FB_ACTIVATE_FORCE;
  143.             var.yres_virtual = var.yres;
  144.             
  145.             /* set fb0 no back-buffer */
  146.             ret = ioctl( fd, FBIOPUT_VSCREENINFO, &var );
  147.             if( ret < 0 ){
  148.                 printf( "ioctl %s FBIOPUT_VSCREENINFO failed\n", FBDEV_0 );
  149.                 return;
  150.             }
  151.             
  152.             /* map fb0's video buffer */
  153.             p = mmap( NULL, var.xres*var.yres*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 );
  154.             if( !p ){
  155.                 printf( "mmap %s video buffer failed\n", FBDEV_0 );
  156.                 return;
  157.             }
  158.             
  159.             /* draw white screen */
  160.             for( y = 0; y < var.yres; y++ ){
  161.                 for( x = 0; x < var.xres; x++ ){
  162.                     *( p + y * var.xres + x ) = 0x00FFFFFF; /* alpha: all pass , FFFFFF: white */
  163.                 }
  164.             }
  165.         
  166.             /* draw red line 800x100 fb0 */
  167.             for( y = 0; y < 100; y++ ){
  168.                 for( x = 0; x < var.xres; x++ ){
  169.                     *( p + y * var.xres + x ) = 0x80FF0000; /* alpha : 128 */
  170.                 }
  171.             }
  172.             /* draw green line 800x100 fb0 */
  173.             for( y = 100; y < 200; y++ ){
  174.                 for( x = 0; x < var.xres; x++ ){
  175.                     *( p + y * var.xres + x ) = 0x8000FF00;
  176.                 }
  177.             }
  178.             /* draw blue line 800x100 fb0 */
  179.             for( y = 200; y < 300; y++ ){
  180.                 for( x = 0; x < var.xres; x++ ){
  181.                     *( p + y * var.xres + x ) = 0x800000FF;
  182.                 }
  183.             }
  184.             
  185.             /* munmap fb0's video buffer */
  186.             munmap( p, var.xres*var.yres*4 );
  187.             
  188.             /* enable fb0 */
  189.             ret = ioctl( fd, FBIOBLANK, blank );
  190.             if( ret < 0 ){
  191.                 printf( "ioctl %s FBIOBLANK failed\n", FBDEV_0 );
  192.                 return;
  193.             }
  194.             
  195.             /********************************************************
  196.              *  Operation on /dev/fb3
  197.              *******************************************************/
  198.             /* open fb3 */
  199.             fd = open( FBDEV_3, O_RDWR );
  200.             if( fd < 0 ){
  201.                 printf( "open %s failed\n", FBDEV_3 );
  202.                 return;
  203.             }
  204.             
  205.             /* set fb3 no back-buffer */
  206.             ret = ioctl( fd, FBIOPUT_VSCREENINFO, &var );
  207.             if( ret < 0 ){
  208.                 printf( "ioctl %s FBIOPUT_VSCREENINFO failed\n", FBDEV_3 );
  209.                 return;
  210.             }
  211.             
  212.             /* map fb3's video buffer */
  213.             p = mmap( NULL, var.xres*var.yres*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 );
  214.             if( !p ){
  215.                 printf( "mmap %s video buffer failed\n", FBDEV_3 );
  216.                 return;
  217.             }
  218.             
  219.             /* draw white screen */
  220.             for( y = 0; y < var.yres; y++ ){
  221.                 for( x = 0; x < var.xres; x++ ){
  222.                     *( p + y * var.xres + x ) = 0x00FFFFFF;
  223.                 }
  224.             }
  225.             
  226.             /* munmap fb0's video buffer */
  227.             munmap( p, var.xres*var.yres*4 );
  228.             
  229.             /* enable fb3 */
  230.             ret = ioctl( fd, FBIOBLANK, blank );
  231.             if( ret < 0 ){
  232.                 printf( "ioctl %s FBIOBLANK failed\n", FBDEV_3 );
  233.                 return;
  234.             }
  235.             
  236.             /********************************************************
  237.              *  Operation on /dev/sec-g2d
  238.              *******************************************************/
  239.             /* open sec-g2d */
  240.             fd = open( G2DDEV, O_RDWR );
  241.             if( fd < 0 ){
  242.                 printf( "open %s failed\n", G2DDEV );
  243.                 return;
  244.             }
  245.             
  246.             params.src_rect                    = &src_rect;
  247.             params.dst_rect                    = &dst_rect;
  248.             params.flag                        = &flag;
  249.             /* ( 0,0 ) - 480 x 300 */
  250.             params.src_rect->x                = 0;
  251.             params.src_rect->y                = 0;
  252.             params.src_rect->w                = 480;
  253.             params.src_rect->h                = 300;
  254.             params.src_rect->full_w            = var.xres;
  255.             params.src_rect->full_h            = var.yres;
  256.             params.src_rect->color_format    = G2D_ARGB_8888;
  257.             params.src_rect->phys_addr        = 0x3C795000;
  258.             params.src_rect->virt_addr        = NULL;
  259.             /* ( 0,0 ) - 300 x 480 */
  260.             params.dst_rect->x                = 0;
  261.             params.dst_rect->y                = 0;
  262.             params.dst_rect->w                = 300;
  263.             params.dst_rect->h                = 480;
  264.             params.dst_rect->full_w            = var.xres;
  265.             params.dst_rect->full_h            = var.yres;
  266.             params.dst_rect->color_format    = G2D_ARGB_8888;
  267.             params.dst_rect->phys_addr        = 0x3C330000;
  268.             params.dst_rect->virt_addr        = NULL;
  269.             /* rotete 90 degree */
  270.             params.flag->rotate_val            = G2D_ROT_90;
  271.             params.flag->alpha_val            = G2D_ALPHA_BLENDING_OPAQUE;
  272.             params.flag->blue_screen_mode    = G2D_BLUE_SCREEN_NONE;
  273.             params.flag->color_key_val        = 0;
  274.             params.flag->color_val            = 0;
  275.             params.flag->third_op_mode        = G2D_THIRD_OP_NONE;
  276.             params.flag->rop_mode            = G2D_ROP_SRC;
  277.             params.flag->mask_mode            = 0;
  278.             
  279.             /* 2D hardware blit */
  280.             ret = ioctl( fd, G2D_BLIT, &params );
  281.             if( ret < 0 ){
  282.                 printf( "ioctl %s G2D_BLIT failed\n", G2DDEV );
  283.                 return;
  284.             }
  285.             
  286.             getchar();
  287.             
  288.             /* all opened fd will be close when process exit */
  289.             return 0;
  290.         }


    结果如下图所示:
        


9. 结论
    
    看来G2D处理的数据,真的是物理地址啊,但是应用程序如何将逻辑地址转化为物理地址呢,目前还没有确认。
    虽然目前还没能够确认OpenGL的数据是如何处理的,但应该能够从G2D的理解中看到一些信息:
    因为 S5PV210 没有独立显存,因此无论是 CPU 还是 GPU,应该都是通过高速总线从 DDR2 内存中获取的数据,对于CPU而言可能需要纠结物理内存和虚拟内存,以及图形数据互相拷贝的开销对系统性能的影响。但对于GPU而言,都是一样的,就是从一个地方拷贝到另外一个地方,中间再处理一下。
    因此,对于整个系统图形性能的设计,就集中在系统框架的设计上了。