Providing graphics for BOINC applications
A BOINC application may provide graphics (e.g. visualizations) to volunteers. These graphics are shown in two contexts:
- As a screensaver, if selected by the user.
- In a window, opened using the Show Graphics button in the BOINC Manager.
Graphics are generated by a 'graphics app' program (separate from the main application). This graphics app must have the properties that:
- If invoked with
--fullscreen
, it opens a full-screen borderless window. It must exit on mouse or keyboard input (if you use the BOINC graphics API library this is handled automatically). - Otherwise it opens a standard window, and may handle mouse/keyboard input.
The logical name of the program must be 'graphics_app'. When you set up your application version directory, use an entry like
<file> <physical_name>uppercase_graphics_6.14_windows_intelx86.exe</physical_name> <logical_name>graphics_app</logical_name> </file>
in your version.xml file.
The graphics app is launched by the BOINC Manager and/or by the screensaver. It may be killed at any time. Multiple instances of the graphics app may run at the same time (e.g. if the user opens a graphics window via the Manager, and then the screensaver runs and launches another instance).
Communication between main and graphics apps
The graphics app may want to get information from the main app. This can be done using either shared memory or a file.
Shared memory
Communicating large amounts of data can be done efficiently using shared memory. The BOINC library supplies the following functions to facilitate this:
void* boinc_graphics_make_shmem(char* appname, int size);
Called from the main app. Creates a shared memory segment of the given size.
'appname' should be the name of this application (used to ensure uniqueness of the shared-memory segment name).
void* boinc_graphics_get_shmem(char* appname);
Called from the graphics app. Attaches to an existing segment. It must be called AFTER boinc_parse_init_data_file().
The contents of the shared memory segment are application-dependent; typically it contains numeric information describing the state of the computation.
You may want to include the following items:
struct UC_SHMEM { double update_time; double fraction_done; double cpu_time; BOINC_STATUS status; int countdown; };
These items should be updated by the main app once per second, using boinc_set_timer_handler(). The items are:
- update_time
- The current time (dtime()). The graphics app should exit if the current time exceeds this by 5 seconds or so, so that it exits if the main app exits.
- fraction_done
- The last fraction done reported by the main app.
- cpu_time
- The current CPU time, as returned by boinc_worker_thread_cpu_time().
- status
- The BOINC status, as returned by boinc_get_status(). If the 'suspended' flag is set, the graphics app should stop changing its display, and instead show an "application suspended" message.
- countdown
- See below.
Keep in mind that multiple instances of the graphics app may run simultaneously; avoid having the graphics app write to the shared memory. If you use shared memory to store a data structure, use a semaphore to synchronize access so that the graphics app doesn't see an inconsistent state.
Updating the shared memory structure uses CPU time, and it's desirable to avoid this overhead if no graphics app is running.
One way to do this is to include a countdown field in the shared memory structure, as above.
- The graphics sets this to 5 (say) in its app_graphics_render() function.
- The main app decrements this (if positive) once per second.
- The main app updates the application-specific data in shared memory only when countdown is nonzero.
See the example application for an example.
File
Alternatively, you can communicate data from main app to graphics app via a file. The BOINC library provides two functions for this purpose. The main program can call
int boinc_write_graphics_status( const char* filename, double cpu_time, double elapsed_time, double fraction_done );
to write a file containing its status in XML format. The graphics app can call
int boinc_parse_graphics_status( const char* filename, double* update_time, double* cpu_time, double* elapsed_time, double* fraction_done, BOINC_STATUS* status );
to read and parse this file.
Creating an icon for graphics applications
For Windows:
- make Icons (there's a tool for this in Visual Studio), say "boincAppIcon16x16.ico", "boincAppIcon32x32.ico" and "boincAppIcon48x48.ico".
- create a simple resource description file "boincAppIcon.rc" in the same directory
as the icon files pointing to the icon filenames,
the first entry is the resource name that is later passed to setWinIcon():
boinca16 ICON boincAppIcon16x16.ico boinca32 ICON boincAppIcon32x32.ico boinca48 ICON boincAppIcon48x48.ico
- compile the resource (I do this on a Visual Studio Command Prompt):
rc.exe boincAppIcon.rc
- when linking the App, add the resulting file boincAppIcon.RES to the objects
- we call setWinIcon("boinca16","boinca48") in app_graphics_init()