美文网首页
minigui 4.0 源代码分析(二)

minigui 4.0 源代码分析(二)

作者: RonZheng2010 | 来源:发表于2020-11-22 20:10 被阅读0次

    1. Video Device与Video Surface

    1.1 GAL_VideoDevice

    GAL_VideoDevice定义Video Device,它是GAL(Graphics Abstract Layer)层设备的抽象。

    • 成员name是设备名。
    • 成员screen是设备的Surface,视频数据渲染在Surface的表面。这是一个GAL_Surface结构。
    • 成员hidden是设备的平台特有的数据。这是一个GAL_PrivaeVideoData结构。
    • 成员info是与一般的视频设备属性,如capability等。这是一个GAL_VideoInfo结构。
    • 成员函数VideoInit()初始化Video Device。
    • 成员函数SetVideoMode()设置视频模式。它还创建GAL_Surface实例,并连接到设备的数据缓存上。

    全局变量__mg_current_video保存全局唯一的的GAL_VideoDevice实例。

    GAL_VideoDevice *__mg_current_video = NULL;
    

    1.2 VideoBootStrap

    VideoBootStrap负责创建GAL_VideoDevice实例。

    • 成员name是设备名。
    • 成员desc是设备描述信息
    • 成员函数available()检查是否支持指定的Video Device。
    • 成员函数create()创建指定平台类型的设备,也就是GAL_VideoDevice实例。

    不同平台提供了自己的VideoBootStrap实例。全局数组 bootstrap[]中保存了这些实例。这里使用基于开源软件gvfb的模拟环境,使用的实例是PCXVFB_bootstrap。

      VideoBootStrap *bootstrap[] = {
        &DUMMY_bootstrap,
        &PCXVFB_bootstrap,
        &X11_bootstrap,
        ...
      };
    
      VideoBootStrap PCXVFB_bootstrap = {                                                                  
        "pc_xvfb", 
        "PCX Virtual FrameBuffer",                                                            
        PCXVFB_Available, 
        PCXVFB_CreateDevice                                                            
      };    
    

    1.3 GAL_Surface

    GAL_Surface是GAL_VideoDevice的绘制表面。

    • 成员flags是Surface的标志,其中部分bit指定Surface的类型。类型是如下值。

      #define GAL_SWSURFACE  0  /* Surface is in system memory */
      #define GAL_HWSURFACE  1  /* Surface is in video memory */
      
    • 成员pixels指向数据缓存。对于硬件Video Device,就是显存。

    • 成员format是数据格式,这是个GAL_PixelFormat结构。

    • 成员w、h分别是Surface的宽、高,pitch是字节对齐后的宽度。

    • 成员clip_rect是剪裁区域。

    1.4 PCXVFB

    PCXVFB_bootstrap创建基于开源软件gvfb的GAL_VideoDevice实例。

    • minigui进程在子进程中启动gvfb进程。
    • 在minigui的进程和gvfb的进程之间创建基于unix socket的通信通道。
    • gvfb进程创建一块共享内存,并且把共享内存的ID,通过unix socket传给minigui进程。这样建立起minigui与gvfb之间的连接。

    共享内存的布局如下:

    共享内存包括包括两部分,一是映射的数据显存,二是显存宽、高、颜色深度等信息的数据头。数据头hdr在前,显存video data紧随其后。

    • gvfb进程更新数据头,告知显存信息。
    • minigui向显存中写入数据,让gvfb显示它。

    XVFBHeader定义数据头。

    • 成员width、height/pitch、depth是显存的位置、大小、颜色深度信息。
    • 成员fb_offset是显存在共享内存中的偏移。

    GAL_PrivateVideoData的成员shmrgn指向共享内存起始地址。因为数据头在内存头部,所以成员hdr与shmrgn指向同一地址。

    除了视频相关的 功能,gvfb还负责捕捉输入事件,通过Unix socket通道,将输入消息传给minigui进程。这部分在“用户输入系统INPUT”中说明。

    1.5 PCXVFB_CreateDevice()

    PCXVFB_CreateDevice()基于gvfb创建GAL_VideoDevice实例。

    • 调用malloc(),创建GAL_VideoDevice实例。
    • 调用malloc(),创建实例的成员hidden,也就是GAL_PrivateVideoData。
    • 设置GAL_VideoDevice的成员函数,如VideoInit()、SetVideoMode()等。
      • 对于PCXVFB,对应的成员函数是PCXVFB_VideInit()、PCXVFB_SetVideoMode()。

    1.6 PCXVFB_VideoInit()

    PCXVFB_VideoInit()初始化GAL_VideoDevice实例。

    • 调用GetMgEtcValue(),从配置文件中依次读取

      • gvfb的可执行文件路径 /use/local/bin/gvfb
      • 窗口名 XVFB-for-MiniGUI-3.0-(Gtk-Version)
      • 希望的显存模式 360x480-32bpp。调用函数GAL_ParseVideoMode()将这个字符串分解成宽360、高480、颜色深度32。
    • 调用socket(),创建一个UNIX socket,保存在全局变量__mg_pcxvfb_server_sockfd中。

      int __mg_pcxvfb_server_sockfd;
      
    • 调用bind(),将socket绑定在地址/tmp/pcxvfb_socketXXX,XXX为进程ID号。

    • 调用listen()将socket置于监听状态。

    • 调用shm_init_lock(),创建和初始化以进程ID为key的semaphore。其中,semget()创建semaphore,semctl()将semaphore的值设置为1。

    • 调用fork()启动gvfb子进程。

    在gvfb子进程中,

    • 调用execl_pcxvfb()运行gvfb。其中,
      • 调用GetMgEtcValue(),与minigui进程一样,调用GetMgEtcValue(),从配置文件中依次读取gvfb的可执行文件路径、窗口名、 运行模式。
      • 用这些配置参数,调用execlp()运行gvfb。
      • gvfb进程应该创建共享内存,映射到显存,并通过unix socket连接minigui进程。

    在minigui进程中,

    • 调用my_select()在UNIX socket上等待gvfb子进程连接。成功返回后,调用accept()接收连接,得到新的数据socket,保存在全局变量__mg_pcxvfb_client_sockfd中。

      int __mg_pcxvfb_client_sockfd;
      
    • 调用my_select(),在数据socket __mg_pcxvfb_client_sockfd上等待。 成功返回后,调用read()读取gvfb进程写入的共享内存id。

    • 调用shmat(),得到共享内存的地址。将这个地址保存在GAL_PrivateVideoData的成员shmrgn中。同时让成员hdr也指向它。

    1.7 PCXVFB_SetVideoMode()

    PCXVFB_SetVideoMode()设置GAL_VideoDevice的模式。更重要的是,它还设置显存地址。

    • 将Video Device的类型设置为GAL_HWSURFACE,表示这是一个硬件显存
    • 将成员pixels设置为显存在共享内存中的偏移位置。如前所说,这是gvfb暴露给minigui进程的显存地址。
    // pcxvfb.c
    GAL_Surface *PCXVFB_SetVideoMode (_THIS, GAL_Surface *current,
            int width, int height, int bpp, Uint32 flags)
    {
        current->flags  = GAL_HWSURFACE | GAL_FULLSCREEN;
        current->w      = this->hidden->hdr->width;
        current->h      = this->hidden->hdr->height;
        current->pitch  = this->hidden->hdr->pitch;
        current->pixels = this->hidden->shmrgn + this->hidden->hdr->fb_offset;
        current->format->MSBLeft = this->hidden->hdr->MSBLeft;
        ...
    }
    

    1.8 GAL_VideoInit()

    GAL_VideoInit()创建GAL_VideoDevice设备并初始化。

    • 调用GAL_GetVideo()得到创建设备。其中,

      • 遍历全局数组bootstrap[],找到指定名字的VideoBootStrap实例。
      • 调用VideoBootStrap的成员函数available(),检查其是否可用。这里调用的是PCXVFB_Available()。
      • 如果可用,调用VideoBootStrap的成员函数create()创建实例。这里调用的是PCXVFB_CreateDevice()。
      • 最后设置实例的属性,如名字等。这里名字是”pc_xvfb”。
    • 将设备实例保存在全局变量__mg_current_video中。

    • 调用GAL_VideoDevice的成员函数VideoInit(),初始化设备。这里调用的是PCXVFB_VideoInit()。

    • 调用GAL_CreateRGBSurface()创建Surface,设置为GAL_VideoDevice的成员screen。

    1.9 GAL_CreateRGBSurface()

    GAL_CreateRGBSurface() 创建Surface。

    • 调用malloc(),创建GAL_Surface实例。
    • 调用GAL_AllocFormat(),创建GAL_PixelFormat结构。GAL_Surface实例的成员format设置成这个值。
    • 调用GAL_CalculatePitch(),计算surface每行的对齐宽度。
    • 调用GAL_SetClipRect(),将surface的剪裁区域置空。
    • 让GAL_Surface的成员pixels暂时指向本地静态内存。

    1.10 GAL_GetVideoMode()

    GAL_GetVideoMode()得到合适的模式,包括宽、高、颜色深度。

    • 调用GAL_VideoModeOK()检查希望的模式是否支持,得到实际支持的颜色深度。如果不支持,返回失败。如果支持,颜色深度与指定的颜色深度相同,则返回成功。

      • GAL_VideoModeOK()首先检查模式,包括宽、高、颜色深度,找到最近的颜色深度。如果不支持这个模式,则返回false;如果支持,则对比全局数组GAL_closest_depths[4][8]中预定义的模式,选择最接近的颜色深度。
    • 如果深度不同,则遍历GAL_closest_depths[4][8],得到接近的深度。

    • 调用GAL_ListModes()得到支持的长宽模式。

    • 根据指定的GAL_PixelFormat,调用GAL_VideoDevice的成员函数ListModes(),这里是PCXVFB_ListModes()。但PCXVFB_ListModes()什么都没做。

    1.11 GAL_SetVideoMode()

    GAL_SetVideoMode()设置模式,并连接设备的显存。

    • 调用GAL_GetVideoMode(),得到支持的模式。
    • 调用GAL_VideoDevice的成员函数SetVideoMode(),设置模式并连接设备显存。这里调用PCXVFB_SetVideoMode()。

    相关文章

      网友评论

          本文标题:minigui 4.0 源代码分析(二)

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