
1.Overview
DirectFB is a thin library that provides hardware graphics acceleration, input device handling and abstraction, integrated windowing system with support for translucent windows and multiple display layers, not only on top of the linux frame buffer device. It’s a complete hardware abstraction layer with software fallbacks for every graphics operation that is not supported by the underlying hardware.
a. architecture
DirectFB works on a frame buffer device (/dev/fb) and provides the mechanism to use the hardware acceleration effectively.
DirectFB consists of the followings:
Core API Module
Generic GFX driver
GFX drivers for specific hardware.
Generic GFX driver checks whether the hardware acceleration by a GFX driver is available:
If yes, it handovers to the GFX driver
If not, it uses software rendering engine.
b. core modules
| ClipBoard | |
| ColorHash | |
| Surface | Surface interface and management |
| System | Display backend , tipically fb driver |
| Input | Input device handle |
| Graphics | Graphics rendering |
| Screen | |
| Layer | |
| WM | Window manager |
2.Surface interface
1.surface format
| DSPF_ARGB1555 | 16 bits 1@a 5@r 5@g 5@b |
| DSPF_RGB16 | 16 bits 5@r 6@g 5@b |
| DSPF_RGB24 | 24 bits 8@r 8@g 8@b |
| DSPF_RGB32 | 32 bits 8@r 8@g 8@b |
| DSPF_ARGB | 32 bits 8@a 8@r 8@g 8@b |
| DSPF_A8 | 8 bits 8@a |
| DSPF_YUY2 | 16 bits |
| DSPF_RGB332 | 8 bits 3@r 3@g 2@b |
| DSPF_UYVY | 32 bits |
| DSPF_I420 | |
| DSPF_YV12 | |
| DSPF_LUT8 | |
| DSPF_ALUT44 | |
| DSPF_AiRGB | |
| DSPF_A1 | |
| DSPF_NV12 | |
| DSPF_NV16 | |
| DSPF_ARGB2554 | |
| DSPF_ARGB4444 | |
| DSPF_RGBA4444 | |
| DSPF_NV21 | |
| DSPF_AYUV | |
| DSPF_A4 | |
| DSPF_ARGB1666 | |
| DSPF_ARGB6666 | |
| DSPF_RGB18 | |
| DSPF_LUT2 | |
| DSPF_RGB444 | |
| DSPF_RGB555 | |
| DSPF_RGBA5551 | |
| DSPF_YUV444P | |
| DSPF_ARGB8565 | |
| DSPF_AVYU | |
| DSPF_VYU | |
GetCapabilities(IDirectFBSurface *thiz, DFBSurfaceCapabilities)
This will get some capabilites from directfb.
| DSCAPS_PRIMARY | It’s a primary surface |
| DSCAPS_SYSTEMONLY | Surface data is permanently stored in system memory |
| DSCAPS_VIDEOONLY | Surface data is permanently stored in video memory |
| DSCAPS_DOUBLE | Surface is double buffered |
| DSCAPS_SUBSURFACE | Surface is just a sub area of another one sharing the surface data |
| DSCAPS_INTERLACED | |
| DSCAPS_SEPARATED | |
| DSCAPS_STATIC_ALLOC | The amount of video or system memory allocated for the surface is never less than its initial value |
| DSCAPS_TRIPLE | Surface is tripple buffered. |
| DSCAPS_PREMULTIPLIED | Surface stores data with premultiplied alpha |
| DSCAPS_DEPTH | A depth buffer is allocated |
| DSCAPS_SHARED | The surface will be accessible among processes |
| DSCAPS_ROTATED | The back buffers are allocated with swapped width/height |
FillRectangle()
Fill the specified rectangle with the given color following the specified flags.
DrawRectangle()
Draw an outline of the specified rectangle with the given color following the specified flags.
DrawLine()
DrawLines()
FillTriangle()
Fill a non-textured tirangle.
FillRectangles()
Fill a bunch of rectangles with a single call
FillSpans()
Fill spans specified by x and width
FillTriangles()
Fill a bunch of triangles with single call
4.Blit functions
Blit()
Blit an area from the source to this surface.
TileBlit()
Blit and area from the source tiled to this surface
BatchBlit()
Blit a bunch of areas at once
StretchBlit()
Blit an area scaled from the source to the destination rectangle
TextureTriangles(thiz, texture, vertices, indices, num, formation)
Draw triangles with the specified vertices and type (triangle list, triangle fan and triangle strip) and map the texture onto tirangles.
It looks like that the software rendering path is not impelemented.
5.drawing flags
DFBSurfaceDrawingFlags:
It will affect the effect of the draw.
| DSDRAW_BLEND | Enable blend |
| DSDRAW_DST_COLORKEY | Write to destination only if the destination pixel matches the destination color key |
| DSDRAW_SRC_PREMULTIPLY | Mulitplies the color’s rgb channels by the alpha channel before drawing |
| DSDRAW_DST_PREMULTIPLY | Modulates the destination color with the destination alpha |
| DSDRAW_DEMULTIPLY | Divides the color by the alpha before writing the data to the destination |
| DSDRAW_XOR | Bitwise xor the destination pixels with the specified color after premultiplication |
blitting flags will affect the effort of blit.
| DSBLIT_BLEND_ALPHACHANNEL | Enables blending and uses alpha channel from source |
| DSTBLIT_BLEND_COLORALPHA | Enables blending and uses alpha value from color |
| DSTBLIT_COLORIZE | Modulates source color with the color’s r/g/b values |
| DSTBLIT_SRC_COLORKEY | Don’t blit pixels matching the source color key |
| DSTBLIT_DST_COLORKEY | Write to destination only if the destination pixel matches the destination color key |
| DSTBLIT_SRC_PREMULTIPLY | Modulates the source color with the (modulated) source alpha |
| DSTBLIT_DST_PREMULTIPLY | Modulates the destination color with the destination alpha |
| DSTBLIT_DEMULTIPLY | Divides the color by the alpha before writing the data to the destination |
| DSTBLIT_DEINTERLACE | Deinterlaces the source during blitting by reading only one field, scaling it vertially by factor two. |
| DSBLIT_SRC_PREMULTCOLOR | Modulates the source color with the color alpha |
| DSTBLIT_XOR | Bitwise xor the destination pixels with the source pixels after premultiplication |
| DSTBLIT_INDEX_TRANSLATION | Do fast indexed to indexed translation, this flag is mutual exclusive with all others |
| DSTBLIT_ROTATE90 | Rotate the image by 90 degree |
| DSTBLIT_ROTATE180 | Roate the image by 180 degree |
| DSTBLIT_ROTATE270 | Rotate the image by 270 degree |
| DSTBLIT_COLORKEY_PROTECT | Make usre written pixels don’t match color key |
| DSTBLIT_SRC_MASK_ALPHA | Modulate source alpha channel with alpha channel from source mask |
| DSTBLIT_SRC_MASK_COLOR | Modulate source color channels with color channels from source mask. |
| DSTBLIT_SOURCE2 | Use secondary source instead of destination for reading |
| DSTBLIT_FLIP_HORIZONTAL | Flip the image horizontally |
| DSTBLIT_FLIP_VERTICAL | Flip the image vertically |
Porter-Duff rule:
IDirectFBSurface_SetPorterDuff()
Pixel = (source * fs + destination * fd)
sa = source alpha
da = destination alpha
| DSPD_NONE | fs = sa fd = 1.0 – sa |
| DSPD_CLEAR | fs = 0.0 fd = 0.0 |
| DSPD_SRC | fs = 1.0 fd = 0.0 |
| DSPD_SRC_OVER | fs = 1.0 fd = 1.0 – sa |
| DSPD_DST_OVER | fs = 1.0 – da fd = 1.0 |
| DSPD_SRC_IN | fs = da fd = 0 |
| DSPD_DST_IN | fs = 0.0 fd = sa |
| DSPD_SRC_OUT | fs = 1.0 – da fd = 0.0 |
| DSPD_DST_OUT | fs = 0.0 fd = 1.0 –sa |
| DSPD_SRC_ATOP | fs = da fd = 1.0 - sa |
| DSPD_DST_ATOP | fs = 1.0 – da fd = sa |
| DSPD_ADD | fs = 1.0 fd = 1.0 |
| DSPD_XOR | fs = 1.0 – da fd = 1.0 - sa |
| DSPD_DST | Fs = 0.0 fd = 1.0 |
Pixel color = sc * cf[sf] + dc * cf[df]
Pxiel alpha = sa * af(sf) + da * af[df]
sc = source color
sa = source alpha
dc = destination color
da = destination alpha
sf = source blend function
df = destination blend function
cf [x] = color factor for blend function x
af[x] = alpha factor for blend function x
| DSBF_ZERO | Cf = 0 af = 0 |
| DSBF_ONE | Cf = 1 af = 1 |
| DSBF_SRCCOLOR | Cf = sc af = sa |
| DSBF_INVSRCCOLOR | Cf = 1-sc af = 1-sa |
| DSBF_SRCALPHA | Cf = sa af = sa |
| DSBF_INVSRCALPHA | Cf = 1-sa af = 1 – sa |
| DSBF_DESTALPHA | Cf = da af = da |
| DSBF_INVDESTALPHA | Cf = 1-da af = 1 – da |
| DSBF_DESTCOLOR | Cf = dc af = da |
| DSBF_INVDESTCOLOR | Cf = 1- dc af = 1 – da |
| DSBF_SRCALPHASAT | Cf = min(sa, 1-da) af = 1 |
(Detail code in src/gfx/generic/generic.c: gAcquire())
The software rendering flow diagram for blitting:
8.Surface render options
Options for drawing and blitting operations, not mandatory for acceleration.
| DSRO_SMOOTH_UPSCALE | Use interpolation for upscale stretchBlit |
| DSRO_SMOOTH_DOWNSCALE | Use interpolation for downscale stretchBlit |
| DSRO_MATRIX | Use the transformation matrix |
| DSRO_ANTIALIAS | Enable anti-aliasing for edges(alpha blend must be enable) |
DSRO_MATRIX: when this flag is set, directfb will translate the original primitive to triangles and then send them to driver.
9.2d driver implementation
a.driver functions we need to hook
/* check if it’s s3’s card */
int (*Probe) (CoreGraphicsDevice *device);
/* get some driver info such as name and vendor */
void (*GetDriverInfo) (CoreGraphicsDevice *device,
GraphicsDriverInfo *driver_info);
/* export device hook functions and device caps */
DFBResult (*InitDriver) (CoreGraphicsDevice *device,
GraphicsDeviceFuncs *funcs,
void *driver_data,
void *device_data,
CoreDFB *core);
/* initilize the hw device */
DFBResult (*InitDevice) (CoreGraphicsDevice *device,
GraphicsDeviceInfo *device_info,
void *driver_data,
void *device_data);
/* deinitialize the hw device */
void (*CloseDevice) (CoreGraphicsDevice *device,
void *driver_data,
void *device_data);
/* deinitialize the driver */
void (*CloseDriver) (CoreGraphicsDevice *device,
void *driver_data);
b.device functions we need to hook
/*
* function that is called after variable screeninfo is changed
* (used for buggy fbdev drivers, that reinitialize something when
* calling FBIO_PUT_VSCREENINFO)
*/
void (*AfterSetVar)( void *driver_data, void *device_data );
/*
* Called after driver->InitDevice() and during dfb_gfxcard_unlock( true ).
* The driver should do the one time initialization of the engine,
* e.g. writing some registers that are supposed to have a fixed value.
*
* This happens after mode switching or after returning from
* OpenGL state (e.g. DRI driver).
*/
void (*EngineReset)( void *driver_data, void *device_data );
/*
* Makes sure that graphics hardware has finished all operations.
*
* This method is called before the CPU accesses a surface' buffer
* that had been written to by the hardware after this method has been
* called the last time.
*
* It's also called before entering the OpenGL state (e.g. DRI driver).
*/
DFBResult (*EngineSync)( void *driver_data, void *device_data );
/*
* Called during dfb_gfxcard_lock() to notify the driver that
* the current rendering state is no longer valid.
*/
void (*InvalidateState)( void *driver_data, void *device_data );
/*
* after the video memory has been written to by the CPU (e.g. modification
* of a texture) make sure the accelerator won't use cached texture data
*/
void (*FlushTextureCache)( void *driver_data, void *device_data );
/*
* After the video memory has been written to by the accelerator
* make sure the CPU won't read back cached data.
*/
void (*FlushReadCache)( void *driver_data, void *device_data );
/*
* Called before a software access to a video surface buffer.
*/
void (*SurfaceEnter)( void *driver_data, void *device_data,
CoreSurfaceBuffer *buffer, DFBSurfaceLockFlags flags );
/*
* Called after a software access to a video surface buffer.
*/
void (*SurfaceLeave)( void *driver_data, void *device_data, CoreSurfaceBuffer *buffer );
/*
* Return the serial of the last (queued) operation.
*
* The serial is used to wait for finishing a specific graphics
* operation instead of the whole engine being idle.
*/
void (*GetSerial)( void *driver_data, void *device_data, CoreGraphicsSerial *serial );
/*
* Makes sure that graphics hardware has finished the specified operation.
*/
DFBResult (*WaitSerial)( void *driver_data, void *device_data, const CoreGraphicsSerial *serial );
/*
* emit any buffered commands, i.e. trigger processing
*/
void (*EmitCommands) ( void *driver_data, void *device_data );
/*
* 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 );
/*
* 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 );
/*
* drawing functions
*/
bool (*FillRectangle) ( void *driver_data, void *device_data,
DFBRectangle *rect );
bool (*DrawRectangle) ( void *driver_data, void *device_data,
DFBRectangle *rect );
bool (*DrawLine) ( void *driver_data, void *device_data,
DFBRegion *line );
bool (*FillTriangle) ( void *driver_data, void *device_data,
DFBTriangle *tri );
/*
* blitting functions
*/
bool (*Blit) ( void *driver_data, void *device_data,
DFBRectangle *rect, int dx, int dy );
bool (*Blit2) ( void *driver_data, void *device_data,
DFBRectangle *rect, int dx, int dy, int sx2, int sy2 );
bool (*StretchBlit) ( void *driver_data, void *device_data,
DFBRectangle *srect, DFBRectangle *drect );
bool (*TextureTriangles)( void *driver_data, void *device_data,
DFBVertex *vertices, int num,
DFBTriangleFormation formation );
/*
* Signal beginning of a sequence of operations using this state.
* Any number of states can be 'drawing'.
*/
void (*StartDrawing)( void *driver_data, void *device_data, CardState *state );
/*
* Signal end of sequence, i.e. destination surface is consistent again.
*/
void (*StopDrawing)( void *driver_data, void *device_data, CardState *state );
10.Surface allocation
DirectFB has a surface pool to allocate buffer from it.
The pool is intialized when intialize the fb driver.
Video memory size is get from fb driver.
In /systems/fbdev/fbdev.c
system_initialize:
dfb_surface_pool_initialize( core, &fbdevSurfacePoolFuncs, &dfb_fbdev->shared->pool )
11.DirectFBGL
OpenGL implementation on top of the direct FB, opengl driver is loaded by directfb in IDirectFBSurface_GetGL.
Here is the sample code:
DFBCHECK(DirectFBInit( &argc, &argv ));
/* create the super interface */
DFBCHECK(DirectFBCreate( &dfb ));
/* create an event buffer for all devices with these caps */
DFBCHECK(dfb->CreateInputEventBuffer( dfb, DICAPS_KEYS | DICAPS_AXES,
DFB_FALSE, &events ));
/* set our cooperative level to DFSCL_FULLSCREEN
for exclusive access to the primary layer */
dfb->SetCooperativeLevel( dfb, DFSCL_FULLSCREEN );
/* get the primary surface, i.e. the surface of the
primary layer we have exclusive access to */
dsc.flags = DSDESC_CAPS;
dsc.caps = DSCAPS_PRIMARY | DSCAPS_DOUBLE;
DFBCHECK(dfb->CreateSurface( dfb, &dsc, &primary ));
/* get the size of the surface and fill it */
DFBCHECK(primary->GetSize( primary, &screen_width, &screen_height ));
DFBCHECK(primary->FillRectangle( primary, 0, 0,
screen_width, screen_height ));
primary->Flip( primary, NULL, 0 );
/* create the default font and set it */
DFBCHECK(dfb->CreateFont( dfb, NULL, NULL, &font ));
DFBCHECK(primary->SetFont( primary, font ));
/* get the GL context */
DFBCHECK(primary->GetGL( primary, &primary_gl ));
DFBCHECK(primary_gl->Lock( primary_gl ));
init(argc, argv);
reshape(screen_width, screen_height);
DFBCHECK(primary_gl->Unlock( primary_gl ));
While(1)
{
DFBCHECK(primary_gl->Lock( primary_gl ));
draw();
DFBCHECK(primary_gl->Unlock( primary_gl ));
primary->Flip( primary, NULL, 0 );
}
12.hardware acceleration consideration
To fully support 2d acceleration , we have to use the 3d pipleline, look at the alpha
blending and stretch blit and texture triangles.
