How to use the kernel space acceleration in user mode ?


If you know how X works, you won't have any problems... You can look at some real code here.

Example :

fba_req_t req_buf[1000],*p;
struct fb_accel_list disp_list;

fd=fopen("/dev/fb0",O_RDWR);

/* ... */
/* initialize the graphic mode as usual, for example 640x480x16 */
/* ... */

/* now we build a display list which will be later executed */

p=req_buf;
FBA_SetFG(p,0);                             /* set black color */
FBA_FillRect(p,0,0,640,480,FBA_ROP_COPY);   /* draw a big rectangle */
FBA_SetFG(p,0xffff);                        /* set white color */
FBA_Point(p,320,240);                       /* draw a pixel a the center */

/* we set the display list */

disp_list.list_ptr=req_buf;
disp_list.list_size=p - req_buf;

/* now we execute the display list. The process is stopped until the display list is completed. The
frame buffer driver call schedule() to ensure that the other tasks are not freezed during long
requests */

ioctl(fd,FBIOACCEL_EXEC,&disp_list);

/* ... */

Request structure

Each user mode accelerated command (such as FBA_FillRect) puts its parameters in a display list. The code looks like:

#define FBA_FillRect(p,x,y,xsize,ysize,rop) \
{\
    p[0]=FBA_OP_FillRect;\
    p[1]=x;\
    p[2]=y;\
    p[3]=xsize;\
    p[4]=ysize;\
    p[5]=rop;\
    p+=6;\
}

XXX: using a structure may be better. Care must be taken with the structure definitions in case of a 64 bit architecture.

The graphic context :

Each accelerated command uses some information stored in the accelerated graphic context.

There is only one graphic context per frame buffer device. Its means that only one process at a time can use the acceleration safely. When a console switch occurs, the process must stop sending accelerated commands and store its graphic context itself to let another process (or the console) use the acceleration. The idea behind is that the kernel acceleration must be as simple as possible. There is no point in introducing extra complexity in the kernel to handle the console switches. This is coherent with the current approach where each graphic process must handle itself most of the console switch.

The graphic context must hold at least the following values :
 
fg_color Foreground color
bg_color Background color
clip_x1
clip_y1
clip_x2
clip_y2
Current clipping rectangle. Must be inside the rectangle (0,0,xres_virtual,yres_virtual).

The current clipping rectangle guaranties that no accelerated command can modify some memory outside the graphical memory. This is important with some badly designed graphic cards where there is no memory protection within the acceleration.
This current clipping rectangle makes it possible to use the hardware clippers available in some graphic cards. The X11 server can use this clipping rectangle to optimize the most common case where a primtive is drawn in a visible clipped window.

Acceleration ioctl : FBIOACCEL_EXEC :

It can be seen exactly as a call to the system call 'write'. In particular, this call can be interrupted by a signal. In this case, the user process must be able to restart it. Note that the interrupting signal can be a console switch. In this case, the user process should save its graphical context and do the console switch as usual.

XXX: another solution would be to use a new device : /dev/fbXaccel . Writes to this device would be the same as doing the FBIOACCEL_EXEC ioctl. This is not currently implemented.

Acceleration capabilities : FBIOACCEL_CAP

This ioctl is used to know whether a given accelerated command is implemented.

Example:

int tmp;

tmp=FBA_OP_FillRect;

ioctl(fd,FBIOACCEL_CAP,&tmp);

switch(tmp) {
case 0: /* this command is not implemented */
case 1: /* this command is software emulated in the kernel */
case 2: /* this command is hardware accelerated in the kenel */
}



Fabrice Bellard, Jan 11, 1999.