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。



    打开/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使用的是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));
    给结构体成员赋值

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


    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()中,下面这段代码应该适合硬件有关,如果显卡有加速功能的话,才会切入到这块代码。


  • 调用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)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容