前面介绍了如何移植dfb到nuc972平台,但未对硬件2D部分的gfx驱动做较详细的说明,这里先简单介绍下如何为dfb写gfx驱动。
(本文描述的nuc972平台的dfb的gfx驱动可以在github上获取)
由前面文章《DirectFB学习之面对对象设计》我们应该可以理解一个具体的gfx驱动将被视为是gfx驱动接口的一个实现,所以让我们先来看看在dfb中gfx驱动的接口是咋样的呢。
如下,其详细代码位于src/core/graphics_driver.h中。
static int driver_probe( ... );
static void driver_get_info( ... );
static DFBResult driver_init_driver( ... );
static DFBResult driver_init_device( ... );
static void driver_close_device( ... );
static void driver_close_driver( ... );
static GraphicsDriverFuncs driver_funcs = {
.Probe = driver_probe,
.GetDriverInfo = driver_get_info,
.InitDriver = driver_init_driver,
.InitDevice = driver_init_device,
.CloseDevice = driver_close_device,
.CloseDriver = driver_close_driver
};
#define DFB_GRAPHICS_DRIVER(shortname) \
__attribute__((constructor)) void directfb_##shortname##_ctor( void ); \
__attribute__((destructor)) void directfb_##shortname##_dtor( void ); \
\
void \
directfb_##shortname##_ctor( void ) \
{ \
direct_modules_register( &dfb_graphics_drivers, \
DFB_GRAPHICS_DRIVER_ABI_VERSION, \
#shortname, &driver_funcs ); \
} \
\
void \
directfb_##shortname##_dtor( void ) \
{ \
direct_modules_unregister( &dfb_graphics_drivers, \
#shortname ); \
}
这个文件主要做了两个事情:
所以在dfb下所有的gfx驱动多会包含这个头文件然后实现上面的声明的六个接口,并利用宏DFB_GRAPHICS_DRIVER定义自己的gfx器件使之能被注册到,如下是在nuc972平台的示例:
#include <core/graphics_driver.h>
DFB_GRAPHICS_DRIVER( NUC970 )
接下来我们依次来简单介绍下这六个接口里面我要具体做些什么事情。
static int
driver_probe( CoreGraphicsDevice *device );
此函数是用来匹配gfx驱动的,即当这个gfx被加载后首先调用的即是这个函数,只有它成功了才有后面的故事,否则该gfx驱动将不会被使用,而gfx匹配是通过一个ID来实现的,即好比一个器件固有的device ID,这个ID我们通过函数dfbgfxcardget_accelerator来得到,它的具体实现来着于不同的system,如下在nuc972平台的示例:
static int
driver_probe( CoreGraphicsDevice *device )
{
return dfb_gfxcard_get_accelerator( device ) == 998;
}
如上我们把nuc972的ID假设为998,这个值如果是从fb中拿的则通过fb驱动写进去,如果是从devmem从得则是写在配置文件中的,如果你实在不知道或你不想给自己定义一个ID也可以欺骗下它直接返回1也可。
static void
driver_get_info( CoreGraphicsDevice *device,
GraphicsDriverInfo *info );
此函数主要要来设定一些驱动信息,比如name、vendor等,然后通过info返回。
static DFBResult
driver_init_driver( CoreGraphicsDevice *device,
GraphicsDeviceFuncs *funcs,
void *driver_data,
void *device_data,
CoreDFB *core );
初始化驱动,主要完成funcs里的callback函数指针的赋值,把图形硬件支持的操作接口函数填充进去,如果dfb的system选择的是devmem则还需要在这个函数里完成screens和layers的注册。
static DFBResult
driver_init_device( CoreGraphicsDevice *device,
GraphicsDeviceInfo *device_info,
void *driver_data,
void *device_data );
器件相关的初始化,主要完成一些和硬件相关的初始化动作,如完成2D图像设备的初始化,完成了硬件相关的初始化后还需通过device_info来告诉dfb本图形设备支持的具体功能等一些硬件设备相关的信息。
与driver_init_driver对应做一些对应的释放操作。
与driver_init_device对应做一些对应的释放操作。
如前所述,dfb主要从一个器件的驱动接口里面了解该设备支持何种加速操作和拿到对应加速操作的callback函数指针,即是GraphicsDeviceFuncs的内容,之后的所有对图形器件的操作多是通过callback来完成的。
所以GraphicsDeviceFuncs则可被视为一个图形器件功能接口抽象,根据各图像器件的不同,并不是该结构体内的所有函数多得实现,我们只去实现那些必要的和我们器件所支持的即可。
其中必要的操作有:
其中Blitting/Drawing functions我们根据我们具体图形硬件支持的功能进行实现,这里主要说明Check/Set state的作用。
/*
* Check if the function 'accel' can be accelerated with the 'state'.
* If that's true, the function sets the 'accel' bit in 'state->accel'.
* Otherwise the function just returns, no need to clear the bit.
*/
void (*CheckState)( void *driver_data, void *device_data,
CardState *state, DFBAccelerationMask accel );
当你调试一个图形驱动发现加速操作不被调用,大多数情况就是在CheckState函数里面失败了,这个函数会在每次图形操作时调用来确认当前器件是否支持当前操作,我们从它传入的参数得知此次图形操作的具体内容和参数信息来判断我们的图形器件是否能完成来回答dfb的调用,如果支持则它下一步即调用SetState否则调用软件方法来实现本次操作。
/*
* Program card for execution of the function 'accel' with the 'state'.
* 'state->modified' contains information about changed entries.
* This function has to set at least 'accel' in 'state->set'.
* The driver should remember 'state->modified' and clear it.
* The driver may modify 'funcs' depending on 'state' settings.
*/
void (*SetState) ( void *driver_data, void *device_data,
struct _GraphicsDeviceFuncs *funcs,
CardState *state, DFBAccelerationMask accel );
在SetState中我们将得到此次图形操作的参数信息位于入口参数的CardState中,我们把它保存起来等调用具体的图形操作时传递给硬件设备或者直接在此时传递给硬件设备,比如要完成一个矩形的填充,我需要知道填充的颜色、位置、大小信息,这些是dfb此时告诉我们的。
如上一次dfb调用硬件加速的流程是:
如上,要完成一个gfx驱动主要的工作是在完成两个结构体(GraphicsDriverFuncs和GraphicsDeviceFuncs)内容的实现,即接口的实现。
在GraphicsDriverFuncs中除了完成一些初始动作外,dfb主要想了解到本驱动的基本信息和支持哪些加速操作并拿到其callback接口;
在GraphicsDeviceFuncs中则是具体的操作实现,根据硬件设备的具体情况进行实现即可。