美文网首页
MiniGUI之GAL启动流程

MiniGUI之GAL启动流程

作者: 蓝雪冬荷 | 来源:发表于2016-05-26 21:59 被阅读786次

    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共享内存的一部分,下面介绍到的时候再细说。
    ![](https://img.haomeiwen.com/i1352462/68420b9d10f518ca.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
        回到GAL_GetVideo()中来,在创建了video之后,对video->name赋值(若底层引擎是PCXVFB,那name就等于pcxvfb),然后做一些初始化工作。这里简单介绍一下GAL_VideoInfo结构体:
    ![](https://img.haomeiwen.com/i1352462/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的算法与此类似。
    ![](https://img.haomeiwen.com/i1352462/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中。
    ![](https://img.haomeiwen.com/i1352462/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进程。
    ![](https://img.haomeiwen.com/i1352462/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的连接
    ![](https://img.haomeiwen.com/i1352462/bc1b663aea4c3da8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
       4. 读取GVFB发来的数据
    ![](https://img.haomeiwen.com/i1352462/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)
    

    相关文章

      网友评论

          本文标题:MiniGUI之GAL启动流程

          本文链接:https://www.haomeiwen.com/subject/fhuxdttx.html