优秀网站建设方案,百度没有投放的网站点击,wordpress打赏赞插件,西安网站建设制作原文:http://www.arm9home.net/read.php?tid-25938.html 管理提醒#xff1a; 本帖被 xoom 执行加亮操作(2012-12-13)如之前所说#xff0c;一直想知道显示数据都在哪个地方#xff0c;通常的数据#xff0c;比如 framebuffer 中的显示数据#xff0c;和OpenGL 处理的数据… 原文:http://www.arm9home.net/read.php?tid-25938.html 管理提醒 本帖被 xoom 执行加亮操作(2012-12-13) 如之前所说一直想知道显示数据都在哪个地方通常的数据比如 framebuffer 中的显示数据和OpenGL 处理的数据有啥关系。目前为止我还没有弄明白 OpenGL 这块但是 framebuffer 这部分差不多了。这篇文章记录了 framebuffer 的显示数据相关内容。1. 关于FIMD Tiny210v2 开发板属于 s5pv210 的一种在这块开发板上显示部分又被叫做 FIMD我不知道FIMD是什么的缩写但D应该和Display Controller有关系吧。 FIMD 的主要功能就是获取显示数据并将数据输出到显示屏。当然期间会对显示数据进行处理 FIMD一共支持5个layer在SoC用户手册中将layer成为window源代码中也叫做window。 FIMD可以通过AXI总线从内存或者Camera哪里获取到显示数据并进行合成。 2. 内核配置 framebuffer 通过 make menuconfig 可以配置 framebuffer 相关的内容。 保存以后在 .config 文件中可以找到相关配置内容。 .config -------------------------------------------------- 复制代码 CONFIG_FB_S3C_DEFAULT_WINDOW2 CONFIG_FB_S3C_NR_BUFFERS3 CONFIG_FB_S3C_NUM_OVLY_WIN1 CONFIG_FB_S3C_NUM_BUF_OVLY_WIN3 同样也会在头文件中生成宏定义 include/generated/autoconf.h -------------------------------------------------- 复制代码 #define CONFIG_FB_S3C_DEFAULT_WINDOW 2 #define CONFIG_FB_S3C_NR_BUFFERS 3 #define CONFIG_FB_S3C_NUM_OVLY_WIN 1 #define CONFIG_FB_S3C_NUM_BUF_OVLY_WIN 3 CONFIG_FB_S3C_DEFAULT_WINDOW 是指 默认的 window 0-4。 CONFIG_FB_S3C_NR_BUFFERS 是指 window 的buffer数3个就是 trebble-buffer2个就是double-buffer。 其中第一个是正在显示的数据又叫onscreen其他几个是后台描画的数据又叫offscreen通过 flip 操作可以将 onscreen 数据和offscreen 数据交换。 CONFIG_FB_S3C_NUM_OVLY_WIN 是 OVERLAY window 0-4。 CONFIG_FB_S3C_NUM_BUF_OVLY_WIN 是指 OVERLAY window 的buffer数和 CONFIG_FB_S3C_NR_BUFFERS 一个意思。 3. 显示数据buffer 内核初始话过程中为这些window 的 buffer 预留了一部分内存。 具体看下面的代码 初始化函数会首先映射内存空间 复制代码 MACHINE_START(MINI210, MINI210) /* Maintainer: Kukjin Kim kgene.kimsamsung.com */ .boot_params S5P_PA_SDRAM 0x100, .fixup mini210_fixup, .init_irq s5pv210_init_irq, .map_io mini210_map_io, .init_machine mini210_machine_init, #ifdef CONFIG_S5P_HIGH_RES_TIMERS .timer s5p_systimer, #else .timer s5p_timer, #endif MACHINE_END 在映射内存空间中保留了一部分内存保留的大小就和window 以及 buffer数有关系 大小是 800 x 480 x 2个window x 3个buffer x RGBA的4字节,这是给通常显示数据的 除此之外还预留了 YUV 的数据区域1280 x 720 x 3个buffer x Y的一个字节数据 1280 x 720 x 3个buffer x UV的一个字节数据。 另外还有一个 4096 字节大小的 数据。 这些数据我只理解了 RGBA 数据 YUV 的数据不知道是干啥的 难道是给 HDMI 输出用的 arch/arm/mach-sp5v210/Mach-mini210.c -------------------------------------------------- 复制代码 /* Multimedia support */ #define LCD_WIDTH 800 #define LCD_HEIGHT 480 #define BYTES_PER_PIXEL 4 #define NUM_BUFFER_OVLY (CONFIG_FB_S3C_NUM_OVLY_WIN * CONFIG_FB_S3C_NUM_BUF_OVLY_WIN) #define NUM_BUFFER (CONFIG_FB_S3C_NR_BUFFERS NUM_BUFFER_OVLY) #define PXL2FIMD(pixels) ((pixels) * BYTES_PER_PIXEL * NUM_BUFFER) #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD PXL2FIMD(LCD_WIDTH * LCD_HEIGHT) static struct s5p_media_device mini210_media_devs[] { ......, { .id S5P_MDEV_FIMD, .name fimd, .bank 1, .memsize S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD, .paddr 0, }, ......, } static void __init mini210_map_io(void) { ...... frame_size lcd-width * lcd-height * BYTES_PER_PIXEL; fimd_size ALIGN(frame_size, PAGE_SIZE) * NUM_BUFFER; if (frame_size 0x200000) { fimd_size ALIGN(frame_size, PAGE_SIZE) * 2; // Not used } /* Reserve 0x003f6000 bytes for PVR YUV video, and 1 page */ fimd_size ALIGN(1280*720, PAGE_SIZE) * 3; fimd_size ALIGN(1280*360, PAGE_SIZE) * 3 PAGE_SIZE; if (fimd_size ! S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD) { mini210_fixup_bootmem(S5P_MDEV_FIMD, fimd_size); } ...... s5p_reserve_bootmem(mini210_media_devs, ARRAY_SIZE(mini210_media_devs), S5P_RANGE_MFC); ...... } 这些内存是PAGE对齐的对齐的部分参考下面的算法。 PAGE_SIZE 大小是 4096。 include/linux/Const.h -------------------------------------------------- 复制代码 #ifdef __ASSEMBLY__ #define _AC(X,Y) X #define _AT(T,X) X #else #define __AC(X,Y) (X##Y) #define _AC(X,Y) __AC(X,Y) #define _AT(T,X) ((T)(X)) #endif arch/arm/include/asm/Page.h -------------------------------------------------- 复制代码 #define PAGE_SHIFT 12 #define PAGE_SIZE (_AC(1,UL) PAGE_SHIFT) include/linux/Kernel.h -------------------------------------------------- 复制代码 #define __ALIGN_KERNEL_MASK(x, mask) (((x) (mask)) ~(mask)) #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) #define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) 4. 内核关于FIMD内存预留的相关debug log 在内核的 boot log 中我们可以找到关于内存预留的log dmesg log : -------------------------------------------------- [ 0.000000] s5p: 13060 kbytes system memory reserved for fimd at 0x3c330000, 1-bank base(0x3c330000) [ 0.648804] fimd at 0x3c3300005. 物理内存视图 画了一个简单的物理内存布局图可以看到 RGBA 部分的数据其实一共给 2 个 window 预留了。 | | |--------------| | |0x3CFF0000 -- 0x3CFF0FFF || ???? |--------------| | |0x3CF7F000 -- 0x3CFEFFFF || |--------------| || | |0x3CF0E000 -- 0x3CF7EFFF || treble-buffer YUV( UV ) framebuffer : 1280 x 360 x 1 byte |--------------| || | |0x3CE9D000 -- 0x3CF0DFFF || |--------------| | |0x3CDBC000 -- 0x3CE9EFFF || |--------------| || | |0x3CCDB000 -- 0x3CDBBFFF || treble-buffer YUV( Y ) framebuffer : 1280 x 720 x 1 byte |--------------| || | |0x3CBFA000 -- 0x3CCDAFFF || |--------------| | |0x3CA83000 -- 0x3CBF9FFF || |--------------| || | |0x3C90C000 -- 0x3CA82FFF || treble-buffer RGBA framebuffer : 800 x 480 x 4 bytes |--------------| || | |0x3C795000 -- 0x3C90BFFF || |--------------| | |0x3C61E000 -- 0x3C794FFF || |--------------| || | |0x3C4A7000 -- 0x3C61DFFF || treble-buffer RGBA framebuffer : 800 x 480 x 4 byte |--------------| || | |0x3C330000 -- 0x3C4A6FFF || |--------------| | |6. 将预留的物理内存记录到platform信息中 这些预留的物理内存在 platform 初始化过程中会映射到内存空间。 在开发板初始化过程中会进行 machine init, 而 machine init 过程中会调用 s3c_fb_set_platdata 初始化 platform 信息。 arch/arm/mach-sp5v210/Mach-mini210.c -------------------------------------------------- 复制代码 static struct s3c_platform_fb mini210_fb_data __initdata { .hw_ver 0x62, .clk_name sclk_fimd, .nr_wins 5, .default_win CONFIG_FB_S3C_DEFAULT_WINDOW, .swap FB_SWAP_WORD | FB_SWAP_HWORD, .cfg_gpio lcd_cfg_gpio, .backlight_on lcd_backlight_on, .backlight_onoff lcd_backlight_off, .reset_lcd lcd_reset_lcd, }; static void __init mini210_machine_init(void) { ...... #ifdef CONFIG_FB_S3C_MINI210 { struct s3cfb_lcd *mlcd mini210_get_lcd(); if (!(mlcd-args 0x0f)) { if (readl(S5PV210_GPF0_BASE 0x184) 0x10) mlcd-args | (1 7); } mini210_fb_data.lcd mlcd; s3c_fb_set_platdata(mini210_fb_data); } #endif ...... } MACHINE_START(MINI210, MINI210) /* Maintainer: Kukjin Kim kgene.kimsamsung.com */ .boot_params S5P_PA_SDRAM 0x100, .fixup mini210_fixup, .init_irq s5pv210_init_irq, .map_io mini210_map_io, .init_machine mini210_machine_init, #ifdef CONFIG_S5P_HIGH_RES_TIMERS .timer s5p_systimer, #else .timer s5p_timer, #endif MACHINE_END 在platform初始化过程中就会通过 pmem_start 和 pmem_size 分别记录这5个window 的物理内存地址和大小。 注意的是 platform 初始化相当于是记录系统都有哪些资源。而设备驱动初始化过程中比如s3cfb这个fb驱动则会来使用这些资源。 arch/arm/plat-s5p/include/plat/Fb.h -------------------------------------------------- 复制代码 struct s3c_platform_fb { int hw_ver; char clk_name[16]; int nr_wins; int nr_buffers[5]; int default_win; int swap; phys_addr_t pmem_start[5]; /* starting physical address of memory region */ size_t pmem_size[5]; /* size of memory region */ void *lcd; void (*cfg_gpio)(struct platform_device *dev); int (*backlight_on)(struct platform_device *dev); int (*backlight_onoff)(struct platform_device *dev, int onoff); int (*reset_lcd)(struct platform_device *dev); int (*clk_on)(struct platform_device *pdev, struct clk **s3cfb_clk); int (*clk_off)(struct platform_device *pdev, struct clk **clk); }; arch/arm/plat-samsung/Dev-fb.c -------------------------------------------------- 复制代码 void __init s3c_fb_set_platdata(struct s3c_platform_fb *pd) { struct s3c_platform_fb *npd; struct s3cfb_lcd *lcd; phys_addr_t pmem_start; int i, default_win, num_overlay_win; int frame_size; if (!pd) pd default_fb_data; npd kmemdup(pd, sizeof(struct s3c_platform_fb), GFP_KERNEL); if (!npd) { printk(KERN_ERR %s: no memory for platform data\n, __func__); } else { for (i 0; i npd-nr_wins i NR_BUFFERS; i) { npd-nr_buffers?? 1; } default_win npd-default_win; num_overlay_win CONFIG_FB_S3C_NUM_OVLY_WIN; if (num_overlay_win default_win) { printk(KERN_WARNING %s: NUM_OVLY_WIN should be less than default \ window number. set to 0.\n, __func__); num_overlay_win 0; } ...... /* set starting physical address size of memory region for * overlay window and default window */ pmem_start s5p_get_media_memory_bank(S5P_MDEV_FIMD, 1); printk(fimd at 0x%08x\n, pmem_start); for (i 0; i num_overlay_win; i) { *(npd-nr_buffersi) CONFIG_FB_S3C_NUM_BUF_OVLY_WIN; *(npd-pmem_starti) pmem_start; *(npd-pmem_sizei) frame_size * *(npd-nr_buffersi); pmem_start *(npd-pmem_sizei); } npd-nr_buffers[default_win] CONFIG_FB_S3C_NR_BUFFERS; npd-pmem_start[default_win] pmem_start; npd-pmem_size[default_win] frame_size * npd-nr_buffers[default_win]; #if defined(CONFIG_MACH_MINI210) npd-pmem_size[default_win] ALIGN(1280*720, PAGE_SIZE) * 3; npd-pmem_size[default_win] ALIGN(1280*360, PAGE_SIZE) * 3 PAGE_SIZE; if (frame_size 0x200000) { // Not Used : frame_size 0x200000 pmem_start npd-pmem_size[default_win]; for (; i npd-nr_wins; i) { if (i ! default_win) { npd-nr_buffers[i] 2; npd-pmem_start[i] pmem_start; npd-pmem_size[i] frame_size * npd-nr_buffers[i]; break; } } } #endif s3c_device_fb.dev.platform_data npd; } } 我们需要留意一下上面这段代码 因为 num_overlay_win 是 CONFIG_FB_S3C_NUM_OVLY_WIN1,所以 for 循环只执行了一次那么 window 0 的物理内存地址初始化了。 然后又手工为 default_win 也就是 CONFIG_FB_S3C_DEFAULT_WINDOW2 进行了初始化。 也就是说 window 0 和 window 2 在platform初始化中记录了数据buffer的物理内存地址。 虽然是 for 循环做的我认为这个for循环写得不好。7. 在s3cfb初始化过程中,为window 关联这些内存 在初始化过程中会分配fb设备相关数据结构并注册fb设备。 drivers/video/samsung/s3cfb.c -------------------------------------------------- 复制代码 static int __devinit s3cfb_probe(struct platform_device *pdev) { ...... if (s3cfb_alloc_framebuffer(fbdev)) { ret -ENOMEM; goto err_alloc; } if (s3cfb_register_framebuffer(fbdev)) { ret -EINVAL; goto err_register; } ...... } 但是我们发现只有当 fb 设备对应的 window 是 default window 也就是 window 2 的时候 才会将 window 2 对应的内存映射到内存空间。 虽然预留的物理内存是 window 0 和 window 2 的但这个时候 window 0 的物理内存是没有被映射的。 drivers/video/samsung/s3cfb.c -------------------------------------------------- 复制代码 static int s3cfb_alloc_framebuffer(struct s3cfb_global *ctrl) { ...... for (i 0; i pdata-nr_wins; i) { ctrl-fb[i] framebuffer_alloc(sizeof(*ctrl-fb), ctrl-dev); if (!ctrl-fb[i]) { dev_err(ctrl-dev, not enough memory\n); ret -ENOMEM; goto err_alloc_fb; } ...... if (i pdata-default_win) { if (s3cfb_map_video_memory(ctrl-fb[i])) { dev_err(ctrl-dev, failed to map video memory for default window (%d)\n, i); ret -ENOMEM; goto err_map_video_mem; } } } ...... } 这是注册 fb 设备的地方只要注册成功/dev 目录下就会有一个 fb 文件。 虽然只给 window 2 映射了显示数据的内存但是 for 循环还是将所有的 window 都注册设备文件了。 这就是为什么 /dev 目录下有 fb0 - fb4 5个fb设备。其实每一个 fb 设备对应一个 window。 另外需要注意的是第一个注册的 fb 是 fb0然后依次 。 下面的代码在注册的时候 首先注册的是 default window 2然后是 3, 4, 0, 1。 也就是说 fb0 - window 2 fb1 - window 3 fb2 - window 4 fb3 - window 0 fb4 - window 1 另外还需要注意的是如果你直接去 cat /dev/fbX 只有 fb0 是成功的其他全部失败 因为到目前位置只有 fb0 也就是 default window 2映射了显示数据的内存。 drivers/video/samsung/s3cfb.c -------------------------------------------------- 复制代码 static int s3cfb_register_framebuffer(struct s3cfb_global *ctrl) { ...... k 0; for (i pdata-default_win; i pdata-nr_wins pdata-default_win; i) { j i % pdata-nr_wins; ret register_framebuffer(ctrl-fb[j]); if (ret) { dev_err(ctrl-dev, failed to register framebuffer device\n); ret -EINVAL; goto err_register_fb; } pdata-fb_file_minor[ j ] k; k; #ifndef CONFIG_FRAMEBUFFER_CONSOLE if (j pdata-default_win) { s3cfb_check_var(ctrl-fb[j]-var, ctrl-fb[j]); s3cfb_set_par(ctrl-fb[j]); s3cfb_draw_logo(ctrl-fb[j]); } #endif } ...... } 8. 内核关于显示内存映射的相关debug log 需要注意一下部分log中写的是fb2但这个log是boot阶段的真正有效的是fb0 代码中log写错了fb 很多应该是 window。fb0 - window 2 dmesg log : -------------------------------------------------- [ 507.316250] [s3cfb]win 2: pmem_start0x3c795000 [ 507.316292] [s3cfb][fb2] dma: 0x3c795000, cpu: 0xe1000000, size: 0x0085c000 [ 507.333888] PA FB 0x3C795000, bits per pixel 32 [ 507.333933] screen width800 height480 va0xdc795000 pa0x3c795000 [ 507.333987] xres_virtual 800, yres_virtual 1440, xoffset 0, yoffset 0 [ 507.336543] fb_size8765440 [ 507.339351] Back frameBuffer[0].VAddrdc90c000 PAddr3c90c000 size1536000 [ 507.346146] Back frameBuffer[1].VAddrdca83000 PAddr3ca83000 size1536000 [ 507.353014] Video Y Buffer[0].VAddrdcbfa000 PAddr3cbfa000 size921600 [ 507.359576] Video Y Buffer[1].VAddrdccdb000 PAddr3ccdb000 size921600 [ 507.366161] Video Y Buffer[2].VAddrdcdbc000 PAddr3cdbc000 size921600 [ 507.372750] Video UV Buffer[0].VAddrdce9d000 PAddr3ce9d000 size462848 [ 507.379418] Video UV Buffer[1].VAddrdcf0e000 PAddr3cf0e000 size462848 [ 507.386093] Video UV Buffer[2].VAddrdcf7f000 PAddr3cf7f000 size4628489. 显示数据使用内存映射的一些细节 s3cfb_map_video_memory 这个函数用于映射显示数据的内存地址 如果是 platform 初始化过程中预留过物理内存则会使用这个物理内存。 否则就会临时申请一块内存。 也就是说 window 0 和 window 2 会使用预留的物理内存。 window 1 / window 3 / window 4 会使用新申请的内存。 drivers/video/samsung/s3cfb.c -------------------------------------------------- 复制代码 static int s3cfb_map_video_memory(struct fb_info *fb) { ...... if (win-owner DMA_MEM_OTHER) { fix-smem_start win-other_mem_addr; fix-smem_len win-other_mem_size; return 0; } if (fb-screen_base) return 0; if (pdata pdata-pmem_start[win-id] (pdata-pmem_size[win-id] fix-smem_len)) { fix-smem_start pdata-pmem_start[win-id]; fix-smem_len pdata-pmem_size[win-id]; fb-screen_base ioremap_wc(fix-smem_start, pdata-pmem_size[win-id]); dev_err(fbdev-dev, [fb%d][win%d]: pmem_start0x%x\n, pdata-fb_file_minor[win-id],win-id, pdata-pmem_start[win-id]); } else { fb-screen_base dma_alloc_writecombine(fbdev-dev, PAGE_ALIGN(fix-smem_len), (unsigned int *)fix-smem_start, GFP_KERNEL); } ...... } 除了在初始化的时候会映射以外 还可一通过 ioctl 来调用 s3cfb_map_video_memory。 传递的参数是 FBIOPUT_VSCREENINFO。 drivers/video/samsung/s3cfb.c -------------------------------------------------- 复制代码 static int s3cfb_set_par(struct fb_info *fb) { ...... if (win-id ! pdata-default_win) { fb-fix.line_length fb-var.xres_virtual * fb-var.bits_per_pixel / 8; fb-fix.smem_len fb-fix.line_length * fb-var.yres_virtual; s3cfb_map_video_memory(fb); } ...... } struct fb_ops s3cfb_ops { .fb_set_par s3cfb_set_par, }; drivers/video/fbmem.c -------------------------------------------------- int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) { ...... if (info-fbops-fb_set_par) { ret info-fbops-fb_set_par(info); ...... } ...... } static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg) { case FBIOPUT_VSCREENINFO: ...... ret fb_set_var(info, var); ..... break; } static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { ...... return do_fb_ioctl(info, cmd, arg); ...... } static const struct file_operations fb_fops { ...... .unlocked_ioctl fb_ioctl, ...... }; 10. 在s3cfb初始化过程中映射FIMD的控制寄存器用于控制硬件 FIMD的控制寄存器和内存是统一编址的因此可以像使用内存一样访问他们但前提是需要将他们映射到内存空间。 内核代码中的寄存器地址定义都能和 SoC 用户手册对应上我们看看下面的截图很一致吧。 但是在看代码的过程中我发现代码使用的寄存器的一些信息Soc 用户手册没有是不是用户手册比较老了 在 s3cfb 模块初始化的过程中就会将控制寄存器映射到内存中。 arch/arm/mach-sp5v210/include/mach/map.h -------------------------------------------------- 复制代码 #define S5PV210_PA_LCD (0xF8000000) #define S5P_PA_LCD S5PV210_PA_LCD #define S5PV210_SZ_LCD SZ_1M #define S5P_SZ_LCD S5PV210_SZ_LCD arch/arm/plat-samsung/dev-fb.c -------------------------------------------------- 复制代码 static struct resource s3cfb_resource[] { [0] { .start S5P_PA_LCD, .end S5P_PA_LCD S5P_SZ_LCD - 1, .flags IORESOURCE_MEM, }, [1] { .start IRQ_LCD1, .end IRQ_LCD1, .flags IORESOURCE_IRQ, }, [2] { .start IRQ_LCD0, .end IRQ_LCD0, .flags IORESOURCE_IRQ, }, }; static u64 fb_dma_mask 0xffffffffUL; struct platform_device s3c_device_fb { .name s3cfb, .id -1, .num_resources ARRAY_SIZE(s3cfb_resource), .resource s3cfb_resource, .dev { .dma_mask fb_dma_mask, .coherent_dma_mask 0xffffffffUL } }; drivers/video/samsung/s3cfb.c -------------------------------------------------- static int __devinit s3cfb_probe(struct platform_device *pdev) { ...... res platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(fbdev-dev, failed to get io memory region\n); ret -EINVAL; goto err_io; } res request_mem_region(res-start, res-end - res-start 1, pdev-name); if (!res) { dev_err(fbdev-dev, failed to request io memory region\n); ret -EINVAL; goto err_io; } fbdev-regs ioremap(res-start, res-end - res-start 1); if (!fbdev-regs) { dev_err(fbdev-dev, failed to remap io region\n); ret -EINVAL; goto err_mem; } ...... } s3cfb_fimd6x.c这个文件将读写 FIMD 的控制寄存器相关功能都集中在这里了。 我理解 6x 可能是对应硬件版本号因为印象中看到硬件版本号好象是 0x62。 通过设定这些控制寄存器就能控制比如 window 是否显示啊显示数据格式是啥啊显示数据地址在哪里啊等等。 drivers/video/samsung/s3cfb_fimd6x.c -------------------------------------------------- 复制代码 int s3cfb_display_on(struct s3cfb_global *ctrl) { u32 cfg; cfg readl(ctrl-regs S3C_VIDCON0); cfg | (S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE); writel(cfg, ctrl-regs S3C_VIDCON0); dev_dbg(ctrl-dev, global display is on\n); return 0; } 11. 用户空间的测试用例 这个用例其实是用来确认 /dev 目录下的 fb0 - fb4 是否好用的以及 window 之间的alpha透过是否正确。 关于 window 之间的层次关系可以参考 下面的代码大概意思是 * 打开 window 0 - window 4 对应的 fb 设备文件。 * 设置这些 window 都是 800 x 480 x RGBA * 设置这些 window 内部的显示数据是从 window 0 - window 4 开始的分别画 500x480, 400x480, 300x480, 200x480, 100x480 这么大块数据。 * 让window 的显示数据显示出来。 s3cfb_test.c -------------------------------------------------- 复制代码 #include sys/types.h #include sys/stat.h #include sys/ioctl.h #include sys/mman.h #include fcntl.h #include stdio.h #include string.h #include linux/fb.h #define WIN0 0 #define WIN1 1 #define WIN2 2 #define WIN3 3 #define WIN4 4 #define WIN_MAX 5 const char * fb_file_path[ WIN_MAX ] { /* WIN0 *//dev/fb3, /* WIN1 *//dev/fb4, /* WIN2 *//dev/fb0, /* WIN3 *//dev/fb1, /* WIN4 *//dev/fb2 }; const int fb_x[ WIN_MAX ] { /* WIN0 */500, /* WIN1 */400, /* WIN2 */300, /* WIN3 */200, /* WIN4 */100 }; const int fb_color[ WIN_MAX ] { /* WIN0 */0x10FFFFFF, /* WIN1 */0x10FF0000, /* WIN2 */0x1000FF00, /* WIN3 */0x100000FF, /* WIN4 */0x10000000, }; void draw_framebuffer( int win, int fd, int xres, int yres ) { int i, j; int *p; int color; p mmap( NULL, xres*yres*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ); if( !p ){ printf( mmap failed\n ); return; } /* draw default color with alpha : all pass through*/ for( j 0; j yres; j ){ for( i 0; i xres ; i ){ *( p j * xres i ) 0x00FFFFFF; } } /* draw color */ for( j 0; j yres; j ){ for( i 0; i fb_x[win] ; i ){ *( p j * xres i ) fb_color[win]; } } munmap( p, xres*yres*4 ); } int main( int argc, char *argv[] ) { int i; int ret; struct fb_var_screeninfo var; int blank; int fd[ WIN_MAX ]; /* initial */ memset( fd, -1, sizeof( fd ) ); /* open framebuffer */ for( i0; iWIN_MAX; i ){ fd[i] open( fb_file_path[i], O_RDWR ); if( fd[i] 0 ){ printf( open %s failed\n, fb_file_path[i] ); goto end; } } printf( open framebuffer ok\n ); /* set screen info */ ret ioctl( fd[WIN2], FBIOGET_VSCREENINFO, var ); if( ret 0 ){ printf( ioctl %s FBIOGET_VSCREENINFO failed\n, fb_file_path[WIN2] ); goto end; } var.activate FB_ACTIVATE_FORCE; var.yres_virtual var.yres; for( i0; iWIN_MAX; i ){ ret ioctl( fd[i], FBIOPUT_VSCREENINFO, var ); if( ret 0 ){ printf( ioctl %s FBIOPUT_VSCREENINFO failed\n, fb_file_path[i] ); goto end; } } printf( set screeninfo ok\n ); /* draw some color */ for( i0; iWIN_MAX; i ){ draw_framebuffer( i, fd[i], var.xres, var.yres ); } printf( draw color ok\n ); /* show window */ blank FB_BLANK_UNBLANK; for( i0; iWIN_MAX; i ){ ret ioctl( fd[i], FBIOBLANK, blank ); if( ret 0 ){ printf( ioctl %s FBIOBLANK failed\n, fb_file_path[i] ); goto end; } } printf( show window ok\n ); /* wait input */ getchar(); end: return 0; } 下面是屏幕截图其实我对 RGB 不太了解不知到什么值应该是什么颜色但 只描画了红/绿/蓝 三种颜色而屏幕上不是这三种颜色。 说明 alpha blending 应该是正常工作了的。 END