基于DirectFB的framebuffer底层驱动及应用程序架构原理分析

来源:互联网 发布:平面效果图设计软件 编辑:程序博客网 时间:2024/05/16 15:31

本文作者为:铁匠Smith 先生

转载请在显著位置注明出处和链接,否则保留追究相关事务之权利。

一、DirecfFB架构下应用层fbdev系统的初始化

    对任何一个dfb应用程序,它在初始化时一定会调用下面两句:
      /* DirectFB init */
     DirectFBInit( &argc, &argv);
     DirectFBCreate(&dfb);

        第一步,DirectFBInit主要完成directFB配置的一些初始化。主要包括读取环境变量DIRECTFBPATH,读取directfbrc文件,获取系统配置和用户配置、处理命令行等。
读取到的配置信息保存在dfb_config全局变量中。这样,后面的程序可以通过dfb_config,获取配置信息,不需要自己去读取。

   第二步,DirectFBCreate主要是在配置已经读取的基础上,完成一系列初始化,并将各种需要的信息保存在IDirectFB指向的数据结构中.

     其中,对fbdev的初始化流程为:调用dfb_core_create-------->dfb_system_lookup.

dfb_system_lookup函数主要是根据系统库目录,读取和加载系统信息。这里的系统,指的是图形系统,一般frame buffer设备(fbdev)、x11等。

系统库目录是以如下这种宏的形式指定的:
   
  DEFINE_MODULE_DIRECTORY( dfb_core_systems, "systems", DFB_CORE_SYSTEM_ABI_VERSION );

 例如:

root@Danny:/opt/WorkDir/SHLib/directfb-1.4-0# ls
gfxdrivers  inputdrivers  interfaces  systems  wm

root@Danny:/opt/WorkDir/SHLib/directfb-1.4-0/systems# ls
libdirectfb_fbdev.so

系统目录为:/opt/WorkDir/SHLib/directfb-1.4-0/systems.

要加载的系统插件为:libdirectfb_fbdev.so

DFB图形系统相关的大致软件架构如下图所示:


二、DirecfFB架构下应用层图形系统fbdev与帧缓冲驱动通信及内存映射的建立

     在上节的dfb_system_lookup函数里会调用direct_modules_explore_directory( &dfb_graphics_drivers ),最后会调用dlopen( )函数。

    根据dlopen的性质,在dlopen函数返回前,它会调用被__attribute__((constructor))修饰的函数。

在core_system.h里我们可以看到如下定义:

 

 

     前面我们已经分析知道,要加载的系统插件为:libdirectfb_fbdev.so

在fbdev.c文件的开始,可以找到如下宏:
DFB_CORE_SYSTEM( fbdev )

可按上面的代码定义进行展开。

在上图的代码调用在dlopen返回前完成后,实际上完成了注册fbdev的systemfuncs.

在dfb核心初始化时, 会调用dfb_core_part_initialize,遍历各个core part,完成各个core的初始化,fbdev属于system 核心组件。

(core part是通过DFB_CORE_PART( )宏来注册的), 如DFB_CORE_PART( system_core, SystemCore );

对于system核心组件来说,DFB初始化时会调用到dfb_system_core_initialize:

 system_funcs->Initialize( core, &system_data );

fbdev属于core system, 会调用自己的system_initialize函数。

本节主要是介绍system_initialize函数所做的工作,主要可概括为以下几个部分:。

(1)调用dfb_fbdev_open()打开framebuffer设备(如:“/dev/fb0”)。

(2)调用ioctl( dfb_fbdev->fd, FBIOGET_FSCREENINFO, &shared->fix)获取显卡内存和类型等固定信息;

(3) 把framebuffer设备文件映射进虚拟内存,并保存内存基址:

dfb_fbdev->framebuffer_base = mmap( NULL, shared->fix.smem_len,
                                         PROT_READ | PROT_WRITE, MAP_SHARED,
                                         dfb_fbdev->fd, 0 );

(4)调用dfb_surface_pool_initialize初始化平面内存池。

(4)通过ioctl获取屏幕可变信息和调色板等信息。

 

三、DirecfFB架构下应用层图形gfxdriver架构及其与应用层图形系统fbdev的映射以及gfxdriver

      gfxdriver架构如下图所示:

       gfxdriver初始化时,也就是调用driver_init_driver card, &card->funcs, card->driver_data, card->device_data, core )函数时,会初始化driverdata

      在初始化driverdata时,会去调用dfb_gfxcard_map_mmiodfb_gfxcard_memory_physical等函数。
      在dfb_gfxcard_map_mmio等函数中,会调用dfb_system_xx之类的函数,如dfb_system_map_mmio。
       这样就完成了gfxdriver与systems的映射。具体细节读者可参阅代码。

     

四、DirecfFB架构下应用层图形系统fbdev与帧缓冲驱动通信:内存分配的时机和执行

     前面说过,对任何一个dfb应用程序,它在初始化时一定会调用下面这句:DirectFBCreate(&dfb)---IDirectFB_Construct------》完成一系列函数指针的安装,如:IDirectFBSurface_DrawRectangle----》dfb_gfxcard_drawrectangle。在dfb_gfxcard_drawrectangle函数里,会对显卡的状态进行检查并获取当前状态:

if (rect->w <= card->limits.dst_max.w && rect->h <= card->limits.dst_max.h &&              dfb_gfxcard_state_check( state, DFXL_DRAWRECTANGLE ) &&              dfb_gfxcard_state_acquire( state, DFXL_DRAWRECTANGLE ))          {               hw = card->funcs.DrawRectangle( card->driver_data,                                               card->device_data, rect );               dfb_gfxcard_state_release( state );          }


接着会触发如下的函数调用

dfb_gfxcard_state_acquire

---》dfb_surface_buffer_lock

----》dfb_surface_pools_allocate

--->dfb_surface_pools_negotiate(  /* Build a list of possible pools being free or out of memory */TestConfig ---))-

该函数会调用TestConfig检查是否有足够的显存

----》然后进行内存的分配调用:

/* Try to do the allocation in one of the pools */     for (i=0; i<num_pools; i++) {          CoreSurfacePool *pool = pools[i];          D_MAGIC_ASSERT( pool, CoreSurfacePool );          ret = dfb_surface_pool_allocate( pool, buffer, &allocation );          if (ret == DFB_OK)               break;          /* When an error other than out of memory happens... */          if (ret != DFB_NOVIDEOMEMORY) {               D_INFO( "%s( -> Allocation in '%s' failed for %s!)\n", __func__, pool->desc.name, DirectFBErrorString(ret) );               /* ...forget about the pool for now */               pools[i] = NULL;          }


 

------》AllocateBuffer

------》fbdevAllocateBuffer

      fbAlloc.flags = FBMAN_ALLOCATE_SURFACE | FBMAN_COMMON_SURFACE;          fbAlloc.pid = dfb_fbdev->shared->master_pid;          if (ioctl( dfb_fbdev->fd, FBIO_ALLOCFB, &fbAlloc) < 0){   //D_INFO("%s([Frame Buffer Memory] out of memory (size %d)!)\n", __func__, fbAlloc.size);               ret = DFB_NOVIDEOMEMORY;          }else{               ret = DFB_OK;          }


      在ioctl后,帧缓冲内存的分配就交给驱动层内核去实现了,并最终映射到物理内存。

 

 

五、DirecfFB架构下帧缓冲驱动层内存管理的实现:内存分配实例分析。

      接到用户层的内存分配请求:

 case FBIO_ALLOCFB:        {T_fb_allocate allocFB;            int ret;if ( copy_from_user(&allocFB, (void *)arg, sizeof(allocFB)) ) {retval = -EFAULT;break;}ret = AllocateFB(&allocFB);            retval = (copy_to_user( (void *)arg, &allocFB, sizeof(allocFB) ) ? -EFAULT : 0 );            retval = (ret ? -EFAULT : retval);        }        break;


于是去调用AllocateFB函数。

详细内容请参考下一篇文章: 基于Linux伙伴算法和DirecfFB架构的帧缓冲驱动层内存管理的一个实现。

 

原创粉丝点击