您的位置:首页 > 其它

【编撰】Directfb 深入 002 DirectFB内存分配与管理:surface pool

2016-10-14 15:52 801 查看
前言;如果我们打开过Diirectfb的调试选项,我们会发现很大一部分的信息都和DFB的缓存buffer的信息:dfb_surface_pool_lock()有关,例如:

(!) [Main Thread       4.120] (  430) *** Assumption [(lock)->offset == (lock)->allocation->offset || (lock)->offset == ~0] failed *** [surface_pool.c:855 in dfb_surface_pool_lock()]

本节转载Smith先生写的一篇博客,对DFB的平面池 surface pool 和 linux 内核frame buffer 的接口配置定义和surface pool本身的命中机制进行了深入的介绍。

文章有部分是自己的心得,用【】标示。原文地址:http://blog.csdn.net/acs713/article/details/7879545


 1.1版本之前,DFB只有基本的系统内存概念

即使用局部或共享内存;或者视频内存概念,即固定的物理地址和一定大小的连续的内存块,该内存直接由CPU映射或者由DFB内置的内存管理器Surface
Manager管理。Surface Manager是一个一维的内存管理器,它会踢出(kick-out)过时的(即不再需要的)内存。这些内存一般是本地备份的内存。只有很少的情况,系统或驱动模块可以控制或自己实现内存分配。通过调用显示层(Display Driver)驱动API: AllocateSurface(), ReallocateSurface()和DeallocateSurface().这些内存分配和释放通常不是由驱动实现的,因此通常使用video内存中的标准分配。【早期是标准的内存共享机制+
视频驱动API】


1.1版本以后,DFB引入了平面池surface pool的概念

因此程序员可以以自己的方式管理平面缓存(surface buffer)。Surface Pool最大的优势是将hardcoded【 Programmers may not have a dynamic user interface
solution for the end user worked out but must still deliver the feature or release the program】的system<->video堆(heap)逻辑(包括sync,transfer,locking等),转移到通用的机制。你可以创建任意多的heaps/pools。

     Surface Pool Negotiation【理解为buffer命中】是关键的一步,因为它把surface buffer内存分配请求路由到正确的pool.如果有多个pool满足条件,则从中选择一个最合适的。这些条件包括:支持必要的访问flag(access flags,如 CPU/GPU),surface类型标记(如Layer font)和其他必要的标准。

     当一个CoreSurface基于选定的CoreSurfaceConfiguration配置创建好以后,CoreSurfaceBuffer结构就分配和添加好了,然而其实并没有任何像素数据的分配发生。第一个lock或write操作会触发negotiation操作。



 

 


      例如,当用户需要进行画图操作时,

会在获取显卡状态时,首先对buffer进行lock.即调用dfb_surface_buffer_lock【注意这个在调试信息里面经常出来的函数】。该函数检查有没有合适内存分配对象allocation存在,如果没有则调用dfb_surface_pools_allocate( buffer, accessor, access, &allocation );去创建一个allocation对象。

     dfb_surface_pools_allocate会做些什么操作呢?关键的一步,是去作平面池协商Surface Pool Negotiation,调用: dfb_surface_pools_negotiate( buffer, accessor, access, pools, pool_count, &num_pools )。

      这个协商主要作什么呢?前面讲过,它把surface buffer内存分配请求路由到正确的pool。何为正确的pool?当然是那些能满足内存分配需求的pool.所以,我们会看到,在这个协商函数里,它会遍历各个pool, 来找到那个满足我们需求的pool.它会调用system module(如fbdev)的Testconfig.Testconfig会计算出我们需要分配的buffer大小并使用framebuffer驱动的ioctrl,查询我们是否能完成满足内存分配的能力。

    当pool找到了,下一步就是调用dfb_surface_pool_allocate( pool, buffer, &allocation )为这些pool创建allocation对象。这个allocation对象到底是什么个东东呢?请参考下图。

   


      我们假设system module采用fbdev。那么,在上面这个allocate函数里,会出现 funcs->AllocateBuffer( pool, pool->data, get_local(pool), buffer, allocation, allocation->data )【这应该是一个注册函数的调用】这样的代码,最终将调用fbdevAllocateBuffer分配内存。allocation的buffer、surface、pool、access、size和offset成员将得到赋值。其中size和offset是通过fbdev的AllocateBuffer
并通过ioctrl获取而赋值的
。接着我们调用dfb_surface_allocation_update对buffer的allocation进行更新,主要是written和read成员。



     在allocation创建和更新后,我们会对该allocation进行锁定,它的实现由dfb_surface_pool_lock( allocation->pool, allocation, lock )来完成。参数lock是CoreSurfaceBufferLock类型,是读、写锁的抽象,这个锁是显卡状态的一个成员变量。



    可见,先将lock的allocation成员与我们分配的allocation对象关联起来。然后,调用fbdevLock函数,完成其他成员的赋值。如下图:

 


 上面的alloc是在fbdevAllocateBuffer通过ioctrl从底层获取的。它通过allocation的成员变量data进行传递。

 


   


【小结:Directfb 向下的调用接口】

 1 funcs->AllocateBuffer( pool, pool->data, get_local(pool), buffer, allocation, allocation->data )

其中函数funcs->AllocateBuffer在使用fbdev设备时候,初始化应该会先注册fbdev的接口函数fbdevAllocateBuffer

 2 Surface Pool存储的是frame buffer的块的查询和访问信息而不是数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: