作者:Sam(甄峰)
sam_code@hotmail.comSam有一个计划,将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.php2. 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./includeCFLAGS = -g -O2 $(INCLUDE)AR = arRANLIB = ranlib
CONFIG_H = include/SDL_config.hTARGET = libSDL.aSOURCES = \ 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/*.csrc/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