MiniGUI之GAL启动流程

MiniGUI之GAL启动流程

mg_InitGAL()

  • 一些变量的含义
    w: GVFB窗口内部显示区域的宽度
    h: GVFB窗口内部显示区域的高度
    depth: bpp--bits per pixel
  • 调用GAL_VideoInit(engine, 0)
    调用GetMgEtcValue()从MiniGUI.cfg中获取gal_engine的值,从图中可以看到,虽然没有定义NOUNIX这个宏,但可能没有定义“MG_GAL_ENGINE”这个环境变量,所以走到上面那个if的时候,engine == NULL。


    MiniGUI之GAL启动流程_第1张图片

    打开/usr/local/etc/MiniGUI.cfg文件,system段如下:



    可以看到gal_engine定义为pc_xvfb。
  • 调用GAL_GetVideo(engine)
    这里介绍一个结构体VideoBootStrap:
typedef struct VideoBootStrap {
  const char *name; //Video Device的名称 
  const char *desc; //Video Device描述字符串
  int (*available)(void); //判断当前情况下Video Device是否可用
  GAL_VideoDevice *(*create)(int devindex); //创建Video Device
} VideoBootStrap;

再介绍一个全局数组bootstrap[]:

/* Available video drivers */
static VideoBootStrap *bootstrap[] = {
#ifdef _MGGAL_DUMMY
  &DUMMY_bootstrap,
#endif
#ifdef _MGGAL_FBCON
  &FBCON_bootstrap,
#endif
#ifdef _MGGAL_QVFB
  &QVFB_bootstrap,
#endif
#ifdef _MGGAL_PCXVFB
  &PCXVFB_bootstrap,
#endif
... ...
}

bootstrap[]定义了很多的可用的video drivers,适用于不同的设备环境。其中,在linux的情况下,FBCON和DUMMY这两个是默认提供的;PCXVFB或QVFB这两个需要在linux下装了GVFB或QVFB底层驱动后才有。


MiniGUI之GAL启动流程_第2张图片


因为笔者测试的MiniGUI使用的是pcxvfb引擎,所以这里介绍一下bootstrap中的成员PCXVFB_bootstrap:

VideoBootStrap PCXVFB_bootstrap = {
  "pc_xvfb", "PCX Virtual FrameBuffer",
  PCXVFB_Available, PCXVFB_CreateDevice
};
  • 调用PCXVFB_Available()
    该函数永远返回1。
  • 调用PCXVFB_CreateDevice(index)
    在GAL_GetVideo()调用PCXVFB_CreateDevice(index)时,index = 0。
    该函数主要干了两件事:申请内存,给结构体成员赋值。
    申请内存
    this = (GAL_VideoDevice *)malloc(sizeof(GAL_VideoDevice));
    this->hidden = (struct GAL_PrivateVideoData *) malloc ((sizeof *this->hidden));
    给结构体成员赋值
    MiniGUI之GAL启动流程_第3张图片

    这里要介绍几个个数据结构,struct GAL_VideoDevice,struct GAL_PrivateVideoData,XVFBHeader。
    1. struct GAL_VideoDevice
      因为该数据结构中的数据成员实在是太多,就删掉了注释,在此以图片的形式呈现:


      MiniGUI之GAL启动流程_第4张图片
    2. struct GAL_PrivateVideoData
      该数据结构和MiniGUI与GVFB共享内存相关。

/* Private display data /
struct GAL_PrivateVideoData {
unsigned char
shmrgn;
XVFBHeader* hdr;
};

     3. XVFBHeader
      用于控制显示,该数据结构也是MiniGUI同GVFB共享内存的一部分,下面介绍到的时候再细说。
![](http://upload-images.jianshu.io/upload_images/1352462-68420b9d10f518ca.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    回到GAL_GetVideo()中来,在创建了video之后,对video->name赋值(若底层引擎是PCXVFB,那name就等于pcxvfb),然后做一些初始化工作。这里简单介绍一下GAL_VideoInfo结构体:
![](http://upload-images.jianshu.io/upload_images/1352462-cb4df62c72de9e57.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
  回到GAL_VideoInit()中,初始化video子系统,先介绍一下GAL_PixelFormat数据结构:

typedef struct GAL_PixelFormat {
GAL_Palette *palette;

Uint8  BitsPerPixel; //一个像素占用的位数,可以选择的是1,2,4,8,16,24,32
Uint8  BytesPerPixel; //一个像素占用的字节数,可以是,1,2,4等
/* The flag indicating dithered palette */
Uint8  DitheredPalette;
/* The flag indicating the Most Significant Bits (MSB) 
 * is left when depth is less than 8. */
Uint8  MSBLeft;

Uint8  Rloss;
Uint8  Gloss;
Uint8  Bloss;
Uint8  Aloss;
Uint8  Rshift;
Uint8  Gshift;
Uint8  Bshift;
Uint8  Ashift;
Uint32 Rmask;
Uint32 Gmask;
Uint32 Bmask;
Uint32 Amask;

/* RGB color key information */
gal_pixel colorkey;
/* Alpha value information (per-surface alpha) */
gal_uint8 alpha;

} GAL_PixelFormat;

  其中,Xloss、Xshift、Xmask分别表示RGBA分量所丢失的位数、在像素中的偏移位数和掩码值。举例来说,假设一个像素值由16位来表示,某个像素点的RGB值为565,即R占5位,G占6位,B占5位。因为loss是相对于一个8位分量来说的,拿R来说,R bits=5,所以Rloss=8-5=3;shift是从bpp(或depth)的右边开始算,偏移了多少位,Rshift=16-5=11;mask是把相应颜色对应的位置1,其它位置0得到,Rmask=0x 1111 1000 0000 0000=0xF800。G和B的算法与此类似。
![](http://upload-images.jianshu.io/upload_images/1352462-950ac05fadd1d5e3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  回到GAL_VideoInit()中,下面这句video->VideoInit(video, &vformat)将会调用PCXVFB_VideoInit()函数。
 - 调用PCXVFB_VideoInit() 
  从MiniGUI.cfg中读取[pc_xvfb]字段下的key的值到execl_file、window_caption和mode中。
![](http://upload-images.jianshu.io/upload_images/1352462-bca5850e75c36308.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  接下来就跳转到针对linux的代码中。这一段代码功能就是本地socket通信,通过sprintf(socket_file, "/tmp/pcxvfb_socket%d", getpid())和strcpy(server_address.sun_path, socket_file)将把本地套接字的名字设为/tmp/pcxvfb_socket+getpid(),而GVFB也通过这两句获取本地套接字,使其与MiniGUI通信。
   1. unlink(socket_file);
    是在没有进程打开或使用socket_file的时候,删除本地套接字对应的文件。
   2. 开启GVFB子进程
    通过调用execl_pcxvfb()开启gvfb进程。
![](http://upload-images.jianshu.io/upload_images/1352462-159f65b1f231543a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
     * 调用execl_pcxvfb()
      通过MiniGUI.cfg和getpid(),获取“ch_pid, window_caption, mode, skin”,其中skin为null,最后再调用execlp()开启gvfb进程。
      `execlp(execl_file, "pcxvfb", ch_pid, window_caption, mode, skin, NULL)`
   3. 接受来自GVFB的连接
![](http://upload-images.jianshu.io/upload_images/1352462-bc1b663aea4c3da8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
   4. 读取GVFB发来的数据
![](http://upload-images.jianshu.io/upload_images/1352462-061412c5b7fd026c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    注意:这两段代码中有个FD_ZERO()和FD_SET(),虽然从字面上能看懂意思,但总感觉不踏实,用SourceInsight定位也没有找到。后来到网上查资料才知道,这两句是socket编程里面用来操作fd_set的,具体含义请自行查找。
    GVFB发给MiniGUI的正是共享内存的shmid,这块共享内存主要包含两部分(或者说三部分,另一部分是PalEntry,这应该是在bpp=8或者以下时才会用到):
     1. GFVBHeader结构
      用于控制显示,和XVFBHeader结构体相同,只是在不同层有不同的名字。
     2. 屏幕显示区域
      这块区域的大小是pitch*height,也就是一行像素的总大小乘以高度,这就是整个像素区域的大小。
      
     所以MiniGUI需要将这块内存空间映射到自己的进程空间中,才能使用。
    ```
data->shmrgn = (unsigned char *)shmat (shmid, 0, 0);
    data->hdr = (XVFBHeader *) data->shmrgn;
接下来就是根据这块共享内存中已经设置好的bpp的值(在GVFB创建这块共享内存的时候,会指定),对vformat的成员赋值。

再回到GAL_VideoInit()中,下面这段代码应该适合硬件有关,如果显卡有加速功能的话,才会切入到这块代码。


MiniGUI之GAL启动流程_第5张图片
  • 调用GAL_CreateRGBSurface()
    接下来就会根据刚才GVFB传过来的共享内存中bpp的值设置的vformat的格式来创建Surface。

Surface是管理显存的一个重要对象。它负责管理显存的大小、色深等信息。而且,可以把一块普通的内存看做一个显存,这样,我们就可以在内存中首先构造出该对象。

该函数创建一个GAL_Surface结构体对象,并初始化了其成员。这其中,我们需要重点注意对format成员和map成员的初始化。对format成员,它调用了GAL_AllocFormat函数。 --doon的专栏

format的创建由GAL_AllocFormat()函数完成,现在看一下GAL_AllocFormat()这个函数。
+ 调用GAL_AllocFormat()
该函数中,主要看default分支代码,功能主要是根据mask的值完成对loss和shift值的计算。PCXVFB_VideoInit()主要是对format的mask值计算,GAL_AllocFormat()时根据mask值计算loss和shift值。

接下来是对surface的一些成员赋值。

surface->w = width;
surface->h = height;
surface->pitch = GAL_CalculatePitch(surface);
surface->pixels = NULL;
surface->offset = 0;
surface->hwdata = NULL;
surface->map = NULL;
surface->format_version = 0;
GAL_SetClipRect(surface, NULL);

再接下来申请一块屏幕大小的内存,和GVFB返回的共享内存的一部分大小相同,都是pitch*height。==这一块可能和显示有关,等以后验证。==
+ 调用GAL_AllocBlitMap()
首先,看一下GAL_BlitMap结构体的定义:
```
typedef struct GAL_BlitMap {
GAL_Surface *dst;
int identity;
Uint8 *table;
GAL_blit hw_blit;
GAL_blit sw_blit;
struct private_hwaccel *hw_data;
struct private_swaccel *sw_data;

 /* the version count matches the destination; mismatch indicates an invalid mapping */
 unsigned int format_version;
} GAL_BlitMap;
     >这里需要关注的重点是hw_blit和sw_blit变量,它们是主要指向blit的操作的回调。GAL_blit的定义是:
     ```
typedef int (*GAL_blit)(struct GAL_Surface *src, GAL_Rect *srcrect, struct GAL_Surface *dst, GAL_Rect *dstrect);
 hw_blit是用硬件加速实现的函数,所以,它是由GAL层实现和设置的。每种不同的开发板有字节的实现方法,所以,这不是我们讨论的重点。sw_blit只软件实现的混合函数,由MiniGUI自己提供,它的确定,是在GAL_MapSurface函数中确定。
 
 接下来看一下GAL_AllocBlitMap函数,该函数主要做了两个分配工作:
 `map = (GAL_BlitMap *)calloc(1, sizeof(*map));//malloc(sizeof(*map));`
 `map->sw_data = (struct private_swaccel *)calloc(1, sizeof(*map->sw_data));`
 现在介绍一下struct private_swaccel结构体:
 ```

/* This is the private info structure for software accelerated blits */
struct private_swaccel {
GAL_loblit blit;
void *aux_data;
};

     GAL_loblit函数指针的类型宏定义:
     ```
/* The type definition for the low level blit functions */
typedef void (*GAL_loblit)(GAL_BlitInfo *info);
 以及GAL_BlitInfo结构体:
 ```

/* The structure passed to the low level blit functions */
typedef struct {
Uint8 *s_pixels;
int s_width;
int s_height;
int s_skip;
Uint8 *d_pixels;
int d_width;
int d_height;
int d_skip;
void *aux_data;
GAL_PixelFormat *src;
Uint8 *table;
GAL_PixelFormat *dst;
} GAL_BlitInfo;

     现在还不知道这些结构体和函数是做什么的,先注意一下。
     
   回到GAL_CreateRGBSurface()中,在对surface的引用计数置1之后,就返回surface了。
   
  回到GAL_VideoInit()中,剩下的代码也没干什么(将video赋值为current_video,对vformat赋值),但也没理解具体这样做的用处。
  至此,GAL_VideoInit()函数的整体调用流程就分析完了,下一步是分析GVFB,以及它和MiniGUI是怎么通信的。

##参考链接
1. [MiniGUI源码分析:GDI(1)-- GDI概览及Surface](http://blog.csdn.net/doon/article/details/7091379)

你可能感兴趣的:(MiniGUI之GAL启动流程)