DirectFB 源码解读之初始化-5

来源:互联网 发布:qq飞鸟升级数据 编辑:程序博客网 时间:2024/06/08 10:41
转载时请表明原文出处(http://blog.sina.com.cn/wyw1976)及作者邮箱(wyw1976@gmail.com)
 
我们先看graphics_core 这个核心部件的初始化。graphics_core是一个与画图息息相关的一个核心部件,每个画图调用都会进入这个部件,并在此决定调用软件实现或是硬件实现。这个核心部件与gfx driver 的关系如下:
 

DirectFB <wbr>源码解读之初始化-9
 
有关上面的图, 有以下几点说明:
(1) graphics driver 分为内核态和用户态,为了区分我们称用户态为gfx driver 而内核态的为gfx module, 内核态的module也就是传统意义上的设备驱动,负责直接操作graphics硬件,它的接口和实现与DFB无关。
(2)用户态的gfx driver是DFB的一部分,它向上的接口是统一的,而向下的接口则可能不同。每个gfx driver都是以动态链接库的形式存在。
(3)DFB本身包含了一些gfx driver的实现,支持一些硬件,如果这些不能满足你的需求,你可以实现自己的gfx driver但是必须符合DFB的要求,即实现特定的一些接口。
(4)上图中出现多个gfx driver 和 gfx module,是指在DFB编译时可以有多个gfx driver, 即多个gfx driver 的动态链接库,但运行时系统一般只有一个其作用,因为一般只有一个图形加速卡。
 
而这个部件的初始化,总结起来分为几个工作:
(1)找到与当前系统硬件匹配的gfx driver
(2)调用gfx driver中的函数初始化该driver,设置硬件绘图函数
(3)调用gfx driver中的函数初始化该gfx硬件
 
上面三个工作的核心是第一步,只要找到了正确的driver,后面两步就水到渠成了。
 
static DFBResult
dfb_graphics_core_initialize( CoreDFB               *core,
                              DFBGraphicsCore       *data,
                              DFBGraphicsCoreShared *shared )
{
 .....
//card是一个全局变量,代表系统的graphics card, 如果下面找到了合适的gfx driver,那么card中就记录了它的所有信息, 包括最重要的函数表。
 card = data;  
 ......
//下面的这个函数我们在dfb_system_lookup()的时候遇到过,它的作用是搜索并打开 
//dfb_graphics_drivers 指定的目录中的所有动态链接库,并建立一个modules链表
//在打开动态库时,自动调用一个统一的注册函数,与system类似的是,DFB通过宏定义
//DFB_GRAPHICS_DRIVER统一了各种不同的gfx driver,具体细节与之前相同,略过。
 direct_modules_explore_directory( &dfb_graphics_drivers );
 .....
//dfb_system_caps()等到当前系统的caps信息,其中的值表示系统是否支持硬件加速。
//dfb_gfxcard_find_driver()遍历上面的链表中的每一个gfx driver, 调用它们的probe函
//数,即driver_probe(),  而它最终调用的system_funcs->GetAccelerator(),也就是当前
//系统的GetAccelerator函数,以fbdev为例,它返回的就是dfb_fbdev->shared->fix.accel,
//这就是fbdev在初始化时,通过ioctl得到的fbdev的固定信息。
//至此我们得到了当前系统中存在的graphics硬件信息(实际就是一个整数值),每个gfx driver
//将自己支持的硬件信息与当前系统的硬件信息比较,如果相同,则匹配成功。
 
 if (dfb_system_caps() & CSCAPS_ACCELERATION)
  dfb_gfxcard_find_driver( core );
 if (data->driver_funcs)
 {
 
   ...  
         //进入这里,表示找到了匹配的gfx driver
        //card->driver_funcs指向的是gfx driver 的统一接口,每个driver都是一样,如
InitDriver(),InitDevice()等。
       //card->funcs指向的是各个gfx driver 的内部接口,每个driver是不同。
        //调用该driver的初始化函数完成driver的初始化,其中重要的步骤就是为card->funcs中的各个函数指针赋值,使其指向gfx driver自己的函数,以后上层用户需要画图时,DFB就会通过这些函数指针,调用相应的硬件实现,完成硬件加速功能。 
         ret = funcs->InitDriver( card, &card->funcs,
                                   card->driver_data, card->device_data, core );
   ....
       //调用InitDevice,一般是设置gfx硬件的寄存器,为正式的作图做好准备。
          ret = funcs->InitDevice( data, &shared->device_info,
                                   data->driver_data, data->device_data );
      }
 
   //即使系统存在硬件加速,DFB仍然提供了上层用户绕过硬件加速而只使用纯软件的画图。这在调试硬件或比较软硬件性能时很有帮助。这是通过directfbrc中的'hardware'指定的。
 if (dfb_config->software_only)
 {
 
  if (data->funcs.CheckState)
  {
            //在每个做图函数中都会查看CheckState, 如果这个变量是 NULL, 则直接调用DFB自带的软件画图
                data->funcs.CheckState = NULL;
                 D_INFO( "DirectFB/Graphics: Acceleration disabled (by 'no-hardware')\n" );
  }
 }
 .....
 return DFB_OK;

}


现在我们看看input_core的初始化。
     在进入具体的代码之前,我们先总结一下input_core这个核心部件的主要功能。我们知道计算机系统的外设有很多,不同的外设,接口不同,功能不同,提供的数据类型也不尽相同。例如键盘的事件是KEY_RELEASE 或KEY_PRESS, 而鼠标的事件是BUTTON_PRESS或BUTTON_RELEAASE,还有触摸屏,游戏杆等等。所以input_core的功能之一就是统一不同输入设备的差异。第二,上层可能有多个进程在等待某个输入,而下层的输入设备并不知道,这种向多个进程分发事件的功能也是input core完成的。第三,系统中可能有多个设备对应同一个driver,DFB需要建立设备与driver的对应关系。
 
      根据以前的解读,我们可以直接跳到dfb_input_core_initialize()开始input_core 的初始化。这个函数做两件事:
(1)direct_modules_explore_directory():这个函数又出现了,它就是在指定的目录中搜索所有的动态链接库,依次打开这些库,将这些库的信息(主要是函数表)记录在一个结构中,并挂在一个链表里。
(2)init_devices():初始化input device。init_devices()的主体代码如下:
 
static void init_devices( CoreDFB *core )
{
    //遍历每一个module,一个modeule对应一个input driver
      direct_list_foreach_safe (module, next, dfb_input_modules.entries)
      {
           //得到该module的函数表
             funcs = direct_module_ref( module );
                 if (!funcs)
                     continue;
 
             driver = D_CALLOC( 1, sizeof(InputDriver) );
           //得到当前系统中,该driver支持的设备总数,不同的设备driver实现自己的GetAvailabe
           //GetAvailabe的实现分两类,一是调用access看节点是否存在,而是调用open看是否打开成功。
          //同一driver可能对应多个设备。
                driver->nr_devices = funcs->GetAvailable();


                driver->module = module;
                driver->funcs  = funcs;
          //所有有效的input driver会记录在全局变量core_local的drivers链表中。
           direct_list_prepend( &core_local->drivers, &driver->link );


              for (n=0; n<driver->nr_devices; n++)
              {
                 device = D_CALLOC( 1, sizeof(CoreInputDevice) );
                     shared = SHCALLOC( pool, 1, sizeof(InputDeviceShared) );
                     device->core = core;
 
             //打开设备,在成功打开设备后调用direct_thread_create(),为每个设备指定一个事件处理线程, 这个线程负责读取设备的事件,完成初次转发。
                  funcs->OpenDevice( device, n, &device_info, &driver_data );
             //为每个设备创建一个reactor的结构,其中有一个reactions的链表将来会记录所有关心该设备事件的对象,事件的转发会最终在此完成。
                   shared->reactor = fusion_reactor_new( sizeof(DFBInputEvent), buf, dfb_core_world(core) );
             //下面这一步与当前分析没有太多联系,略过。
                   fusion_call_init( &shared->call, input_device_call_handler,  device, dfb_core_world(core) );
                   //device 与driver,device与share(即reactor)联系起来
                       device->shared      = shared;
                       device->driver      = driver;
                   //所有的device都会记录在全局变量core_local的devices链表中。
                      input_add_device( device );
          }
     }
}
 
上面有关fusion和reactor时,我们仍然只考虑单进程的情况。
在input_core_part初始化完成后,我们最终得到一个数据结构core_local, 将input drivers, input devices, reactors联系起来。其结构图如下:
 
DirectFB <wbr>源码解读之初始化-10

 
 
有关上面的图, 有几点说明:
(1)DFB中的input driver 与gfx driver 类似,只是DFB中的一个概念,不是真正意义的设备驱动。而上图中的input driver和input device只是对真正设备和驱动的一个抽象,在DFB中也数据结构的形式,将它们串联起来。
 (2) 每一个设备对应一个EventThread, 一经创建,即开始工作,不断从设备中读取事件,并开始处理
分发这些事件。
(3)图中的reactor指向的是一个reactions链表,虚线表示这时并没有实际的reactions接入,也就是没有对这些设备及其事件感兴趣的应用。所以在上一步中,即使读到数据,在分发时都扔掉了。
(4)上图中的driver与device是一一对应的,但也可以是一对多的关系(一个driver,多个device)
(5)DFB中自带了各种input driver, 在实际运行时,只有系统中存在的设备的driver才会挂到上面的结构中。
(6)DFB中定义了一个DFBInputEvent的数据结构,各种输入设备的事件都需要mapping到这个结构中。因此EventThread在开始分发事件前,需要做mapping的工作。
(7) 上图只针对单进程的情况。
 
下节我们看看输入设备事件传送的流程。