Using the BOINC Graphics API
From Unofficial BOINC Wiki
Contents |
[edit] General
BOINC applications can optionally provide graphics, which are displayed either in an application window or in a full-screen window (when acting as a screensaver).
General comments about graphics:
- The graphics often provide a visualization of what the application is doing scientifically. The graphics code must run concurrently with the science code, and must share data structures with it. This can be done using any of several process structures. For example, you can use separate threads in a single address space, or shared memory between separate programs. BOINC supports various process structures (see below).
- Whatever process structure is used, the application needs to handle 'graphics messages' from the core client, telling it when to open and close windows.
- You are encouraged to implement graphics using OpenGL. This makes it possible for your application to show graphics on all platforms.
- Graphics on Unix is tricky because hosts may not have the needed libraries (OpenGL, GLUT, X11). If an application is linked dynamically to these libraries, it will fail on startup if the libraries are not present. On the other hand, if an application is linked statically to these libraries, graphics will be done very inefficiently on most hosts.
BOINC supports process structures where graphics is done:
- In a Monolithic Structure type program. This works fine for Windows. Not recommended for Unix because of the dynamic linking problem described above.
- In a Shared-Library Structure that is dynamically linked by your main program. This works well on Unix.
- In a Separate-Program Structure. This works on all platforms and provides a nice factorization, but it introduces some complications that require work on your part.
You can use different structures for different Platforms. For example, SETI@home uses monolithic on Windows and shared library on other platforms. Climateprediction.net uses a separate program on all platforms.
[edit] Process Structures
[edit] Monolithic Structure
In this approach, graphics are generated by a thread within your main application. The application must call either
int boinc_init_graphics(WORKER_FUNC_PTR worker);
// for simple applications
int boinc_init_options_graphics(BOINC_OPTIONS&, WORKER_FUNC_PTR worker);
// for compound applications
where worker() is the main function of your Application. Do NOT call boinc_init() or boinc_init_options(). Your application must be linked with libboinc_graphics_api.a, and with your rendering and input-handling functions (see below). It should be linked dynamically with glut and opengl.
boinc_init_graphics() creates a worker thread that runs the main application function. The original thread becomes the graphics thread, which handles GUI events and does rendering. The two threads communicate through application-defined shared memory structures. Typically these structures contain information about the computation, which is used to generate graphics. You must initialize the shared data structure before calling boinc_init_graphics().
Unix/Linux applications that use graphics should compile all files with -D_REENTRANT, since graphics uses multiple threads.
[edit] Shared-Library Structure
In this structure your application consists of two parts: a main program and a shared library. The main program calls either
int boinc_init_graphics_lib(WORKER_FUNC_PTR worker, char* argv0);
// for simple apps
int boinc_init_options_graphics_lib(
BOINC_OPTIONS&, WORKER_FUNC_PTR worker, char* argv0
)
// for compound apps
where worker() is as above, and argv0 is the name of the executable as passed in the second argument of main() as argv[0]. The main program must be linked with libboinc_graphics_lib.a
The shared library must have the same name as the executable followed by '.so'. It must be linked with libboinc_graphics_impl.a, with your rendering and input-handling functions, and (dynamically) with glut and opengl.
You must bundle the main program and the shared library together as a multi-file Application Version (See Adding Application Versions).
A typical linking line in building the main program might look like this:
g++ -pthread -o einstein_4.01_i686-pc-linux-gnu app1.o app2.o -lboinc_zip -lboinc_api -lboinc -lboinc_graphics_lib -ldl -lm
where app1.o and app2.o contain the definitions of main() and worker().
A typical linking line in building the shared library might look like this:
g++ -pthread -o einstein_4.01_i686-pc-linux-gnu.so -shared -fPIC app_graphics1.o app_graphics2.o -lboinc_graphics_impl -lboinc -lglut -lGLU -lGL -lX11 -lXmu -ldl -lm
where app_graphics1.o and app_graphics2.o contain the definitions of app_graphics_init(), app_graphics_render(), etc.
In order to communicate data between the worker thread and the graphics thread, the worker() function can call functions from within the shared library. To do this, it makes use of the global variable graphics_lib_handle. If NULL, this means that the host lacks graphics capabilities. If not NULL, the worker can use
communications_function_hook = dlsym(graphics_lib_handle,"communications_function");
to resolve pointers to functions which are defined in the graphics code app_graphics.o. In turn, such functions can modify data used by the graphics code.
[edit] Separate-Program Structure
In this approach, an application bundles a 'main program' and a 'graphics program'. The main program executes the graphics program, and kills it when done. The main and graphics programs typically communicate using shared memory; you can use the functions in boinc/lib/shmem.C for this.
The graphics application can be implemented using the BOINC framework, in which case it must initialize with
int boinc_init_options_graphics(BOINC_OPTIONS&, NULL);
and supply rendering and input-handling functions.
Either the graphics or the main program can handle graphics messages from the core client. It's easiest to have the graphics program handle them; if the main program handles them, it must convey them to the graphics program.
[edit] Rendering and Input-Handling Functions
Programs that use BOINC graphics must supply the following functions:
bool app_graphics_render(int xs, ys, double time_of_day);
This will be called periodically in the graphics thread. It should generate the current graphic. xs and ys are the X and Y sizes of the window, and time_of_day is the relative time in seconds. The function should return true if it actually drew anything. It can refer to the user name, CPU time etc. obtained from boinc_get_init_data(). Applications that don't do graphics must also supply a dummy app_graphics_render() to link with the API.
void app_graphics_init();
This is called in the graphics thread when a window is created. It must make any calls needed to initialize graphics in the window.
void app_graphics_resize(int x, int y);
Called when the window size changes.
void app_graphics_reread_prefs();
This is called, in the graphics thread, whenever the user's project preferences change. It can call
boinc_parse_init_data_file();
boinc_get_init_data(APP_INIT_DATA&);
to get the new preferences.
The Application must supply the following input-handling functions:
void boinc_app_mouse_move(
int x, int y, // new coords of cursor
bool left, // whether left mouse button is down
bool middle,
bool right
);
void boinc_app_mouse_button(
int x, int y, // coords of cursor
int which, // which button (0/1/2)
bool is_down // true iff button is now down
);
void boinc_app_key_press(
int, int // system-specific key encodings
)
void boinc_app_key_release(
int, int // system-specific key encodings
)
Limiting frame rate
The following global variables control frame rate:
boinc_max_fps is an upper bound on the number of frames per second (default 30).
boinc_max_gfx_cpu_frac is an upper bound on the fraction of CPU time used for graphics (default 0.5).
[edit] Support Classes
Several graphics-related classes were developed for SETI@home. They may be of general utility.
- REDUCED_ARRAY
- Represents a two-dimensional array of data, which is reduced to a smaller dimension by averaging or taking extrema. Includes member functions for drawing the reduced data as a 3D graph in several ways (lines, rectangles, connected surface).
- PROGRESS and PROGRESS_2D
- Represent progress bars, depicted in 3 or 2 dimensions.
- RIBBON_GRAPH
- Represents of 3D graph of a function of 1 variable.
- MOVING_TEXT_PANEL
- Represents a flanged 3D panel, moving cyclically in 3 dimentions, on which text is displayed.
- STARFIELD
- Represents a set of randomly-generated stars that move forwards or backwards in 3 dimensions.
- TEXTURE_DESC
- Represents an image (JPEG, Targa, BMP or PNG) displayed in 3 dimensions.
[edit] Static Graphics
An application can display a pre-existing image file (JPEG, GIFF, BMP or Targa) as its graphic. This is the simplest approach since you don't need to develop any code. You must include the image file with each workunit. To do this, link the application with api/static_graphics.C (edit this file to use your filename). You can change the image over time, but you must change the (physical, not logical) name of the file each time.
[edit] UCB Source
[edit] Copyright ©
- 2005 University of California
- 2005 Paul D. Buck
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation.

