作者:Sam(甄峰) sam_code@hotmail.com
Sam有一个计划,将SDL video driver底层适配到dfb和framebuffer上。之前做过一些工作,虽然编译通过了,但SDL例子程序跑起来却会有问题。这次决定重新作一次。
SDL简介:
SDL(Simple DirectMedia Layer),一个简单的游戏开发库。SDL是一个跨平台的多媒体函数库,被用来设计成在低层访问音频,键盘,鼠标,游戏杆,基于OPENGL(一个3D图象开发函数库)的3D 硬件,和2D图象帧缓冲区。Sam:这个图像帧缓冲区是否就是framebuffer??
1.下载SDL:
http://www.libsdl.org/download-1.2.php
2. SDL代码结构粗浅理解:
Sam看过SDL/src目录后,对代码结构有个粗浅的理解。
以下以audio和video目录为例谈一谈。
2.1 audio目录:
audio目录中包括一些.c文件和一些目录,如alsa,dsp,dummy等。
Sam的理解是:audio目录中的.c文件是上层程序使用audio的统一接口。而这些目录如alsa,dsp,dummy等中的代码则是SDL对具体使用何种audio device的适配。alsa就是audio统一接口对alsa的适配,dsp则为对OSS的适配等等。
2.2 video目录:
同上video目录下的.c文件为上层程序显示的统一接口。目录内的程序则为各种显示方法的适配,
如fbcon为framebuffer. directfb为dfb。
3.编译尝试:
3.1: SDL提供了一个最小化的Makefile:Makefile.minimal,所有的实现都是dummy,就是一个空的实现,编译能通过,但运行时什么都不能做.
我们先研究一下这个Makefile:
INCLUDE = -I./include
CFLAGS = -g -O2 $(INCLUDE)
AR = ar
RANLIB = ranlib
CONFIG_H = include/SDL_config.h
TARGET = libSDL.a
SOURCES = \
src/*.c \
src/audio/*.c \
src/cdrom/*.c \
src/cpuinfo/*.c \
src/events/*.c \
src/file/*.c \
src/joystick/*.c \
src/stdlib/*.c \
src/thread/*.c \
src/timer/*.c \
src/video/*.c \
src/audio/dummy/*.c \
src/video/dummy/*.c \
src/joystick/dummy/*.c \
src/cdrom/dummy/*.c \
src/thread/generic/*.c \
src/timer/dummy/*.c \
src/loadso/dummy/*.c \
OBJECTS = $(shell echo $(SOURCES) sed -e 's,\.c,\.o,g')
all: $(TARGET)
$(TARGET): $(CONFIG_H) $(OBJECTS)
$(AR) crv $@ $^ $(RANLIB) $@
$(CONFIG_H):
cp $(CONFIG_H).default $(CONFIG_H)
clean:
rm -f $(TARGET) $(OBJECTS)
这个Makefile很简单:
#make all 会生成libSDL.a
libSDL.a是所有.o ar成的一个库。
注意:OBJECTS= SOURCES的.c 变.o
#make clean 会删除libSDL.a和所有.o
3.2 正式编译
那怎样把想要的实现加上去呢?
比如:
3.2.1
Sam想在Video上选择framebuffer,在audio上选择alsa. 该怎么做呢?
则可以在Makefile中添加:
src/video/fbcon/*.c
src/audio/alsa/*.c
直接编译,发现编译成功。生成了libSDL.a
3.2.2
Sam想要把底层适配为如下模式:
Video: directfb
audio: alsa
则Sam如下添加:
src/video/directfb/*.c
src/audio/alsa/*.c
编译后会报错。显示缺乏directfb头文件。
于是Sam在Makefile中添加了:
-I/home/sam/work/current/Intel_CE_3110/Intel_CE3110_Dev/Canmore-1.1078/i686-linux-elf/usr/local/include/directfb
但发现为跨平台准备的类型定义重定义了。
这其实是因为SDL和Directfb都为跨平台考虑,tyedef了类型。
但directfb中是:typedef unsigned long uintptr_t;
SDL中为:typedef unsigned int uintptr_t;
所以Sam修改了SDL中的typedef
则可以编译成功。
注意:虽然编译成功,但其实bootstrap中并未加入fbcon或者directfb.
所以Sam又在include/SDL_config_minimal.h中添加了:
/* Sam add it for fb*/
#define SDL_VIDEO_DRIVER_FBCON 1
则fb被加入了。
SDL Video架构:
基于SDL的程序初始化时,会调用 SDL_Init()。
SDL_Init(flags)通过调用SDL_InitSubSystem(flags)来初始化各个子系统。具体哪个子系统,通过flags指定。
如果flags指定为video. 则调用SDL_VideoInit()
在SDL_VideoInit() 中,通过bootstrap去分别指向video底层的各个实现。
SDL设计的很精巧,bootstrap中只有2个接口:available,create。
其中available用来查询设备是否可用。 create用来对上层提供所有接口。
所以,如果有人想要在嵌入式系统中移植SDL,则要么支持fb或dfb.要么提供一套新的接口。并利用available和create将他们提供给上层。
SDL中有个结构:
SDL_PixelFormat:
这个结构是用来表示每个Pixel的格式的。因为SDL适配于多种显示设备上。所以用这个结构体来抽象每个Pixel。
这个结构中类似BitsPerPixel这样的含义很简单。
还有一下这些项目:
//每个色彩的精确度损失
Uint8 Rloss;
Uint8 Gloss;
Uint8 Bloss;
Uint8 Aloss;
//每个piexl中各个颜色的偏移
Uint8 Rshift;
Uint8 Gshift;
Uint8 Bshift;
Uint8 Ashift;
//每个piexl中对应色彩的Mask。
Uint32 Rmask;
Uint32 Gmask;
Uint32 Bmask;
Uint32 Amask;
这些数值可以和framebuffer中的fb_bitfield 结构对应起来看。
例如:
从Framebuffer中,读到的fb_var_screeninfo 中:
red:offset=10,length=5
Blue: offset=5, length=5
green:offset=0, length=5
transp:offset=15,length=1
这说明一个pixel结构如下:
GBRA
5551 =16bit
那么:
Rshift=Red.offset=10
Bshift = Blue.offset=5
Gshift = Green。offset=0
Ashift=transp.offset=15
Rmask=111110000000000B
Bmask=000001111100000B
Gmask=000000000111110B
Amask=00000000000001B
1 条评论:
很好,谢谢楼主分享~
发表评论