Graphics library (libgraph)#
libgraph is a graphics library that allows for scheduling and (possibly hardware accelerated) execution of 2D
graphics operations.
Source code: https://github.com/phoenix-rtos/phoenix-rtos-corelibs/tree/master/libgraph
Contents#
Graphics adapters#
The library supports the following graphics adapters:
virtio-gpu- virtualized graphics adapter compatible with VirtIO specification (available on QEMU or VirtualBox)vga- VGA compatible graphics adaptercirrus- Cirrus Logic GD5446 SuperVGA adapter
libgraph apps#
Examples of applications, which use graphics library (ia32-generic-qemu target architecture).
voxeldemo
Source code can be found in the
_userdirectory in phoenix-rtos-project repository.The app can be run using the following command:
/usr/bin/voxeldemorotrectangle
Source code can be also found in the
_userdirectory in phoenix-rtos-project repository.The app can be run using the following command:
/usr/bin/rotrectangletest_graph
Source code is available in the
gfxdirectory in phoenix-rtos-tests repository.The test can be run using the following command:
/bin/test_graph
libgraph interface#
libgraph functions take graph argument which is a pointer to graph_t structure initialized by
graph_open(). graph_adapter_t is an enum used to distinguish between different graphics adapters.
graph_init- Initializes the graphics library and all required drivers.int graph_init(void)
graph_open- Initializes thegraph_tstructure and opens a context for the specified graphics adapter.int graph_open(graph_t *graph, graph_adapter_t adapter, unsigned int mem)
The uninitialized
graph_tstructure should be passed in thegraphargument and the graphicsadaptershould be chosen from the following list:GRAPH_NONE- the graphics adapter isn’t specified, in this case, the function returns-ENODEVGRAPH_VIRTIOGPU- generic VirtIO GPU graphics adapterGRAPH_VGA- generic VGA graphics adapterGRAPH_CIRRUS- Cirrus Logic graphics adapterGRAPH_ANY- an available graphics adapter is chosen
The
memargument specifies the total graphics tasks queue size. The bigger thememthe more graphics tasks we can queue up.The return value is set to
EOK, or an error number, for example:-EINVAL- specified memory value is too low-ENOMEM- memory allocation for graphics context failed-ENODEV- incorrect graphics adapter passed inadapter
graph_mode- Sets graphics mode with specified screen refresh rate frequency.int graph_mode(graph_t *graph, graph_mode_t mode, graph_freq_t freq)
The initialized
graphstructure should be passed, andmodeshould be chosen from thegraph_mode_tenum, and placed in thegraph.hheader.The common graphics modes are presented below:
GRAPH_DEFMODE- default graphics modeGRAPH_ON- display enabled modeGRAPH_OFF- display disabled modeGRAPH_STANDBY- display standby modeGRAPH_SUSPEND- display suspend modeGRAPH_800x600x8- 800x600 resolution, 8-bit indexed color modeGRAPH_320x200x16- 320x200 resolution, 16-bit color modeGRAPH_1920x1080x32- 1920x1080 resolution, 32-bit color mode
There should also be specified the
freqargument (graph_freq_tenum). The common screen refresh rates are presented below:GRAPH_DEFFREQ- default refresh rateGRAPH_24Hz- 24Hz refresh rateGRAPH_60Hz- 60Hz refresh rateGRAPH_120Hz- 120Hz refresh rateGRAPH_360Hz- 360Hz refresh rate
graph_line- Draws a line for the specified graphics adapter context.int graph_line(graph_t *graph, unsigned int x, unsigned int y, int dx, int dy, unsigned int stroke, unsigned int color, graph_queue_t queue)
The following arguments should be passed:
graph- initializedgraph_tstructurex- start point x position, where 0 is the left edge of the screeny- start point y position, where 0 is the upper edge of the screendx- line length in x-axis in pixelsdy- line length in y-axis in pixelsstroke- line thickness in pixelscolor- line colorFor
8-bitindexed color default VGA color palette is presented below (e.g.0x0Brepresents cyan).
Source: https://www.fountainware.com/EXPL/vga_color_palettes.htm
For
16-bitcolor depth - it’s the following format in bits:RRRRRGGGGGGBBBBB(e.g.0x07E0represents green)For
24-bitcolor depth - it’s represented by0xRRGGBB(e.g.0x0000FFrepresents blue)For
32-bitcolor depth - it’s the following format in hex:0xAARRGGBB, whereArepresents alpha. WithAAset to0xFFopacity equals 100%, but by default transparency isn’t enabled, so there can be any value.
queue- graphics task queue, should be chosen from thegraph_queue_tenum, where are following options:GRAPH_QUEUE_HIGH- high priority queueGRAPH_QUEUE_LOW- low priority queueGRAPH_QUEUE_BOTH- any queueGRAPH_QUEUE_DEFAULT- default queue
graph_rect- Draws a rectangle. Arguments are similar to those ingraph_line()function. A drawn rectangle will be filled with a specified color.int graph_rect(graph_t *graph, unsigned int x, unsigned int y, unsigned int dx, unsigned int dy, unsigned int color, graph_queue_t queue)
graph_fill- Fills a closed figure with the color specified in thecolorargument ((x,y) should be any point inside the figure to fill).int graph_fill(graph_t *graph, unsigned int x, unsigned int y, unsigned int color, graph_fill_t type, graph_queue_t queue)
The following
graph_fill_tcolor fill methods are supported:GRAPH_FILL_FLOOD- works like Windows paint bucket tool (floods homogeneous area, all pixels inside the polygon with color values same as the one at (x,y) flood origin point)GRAPH_FILL_BOUND- fills the polygon until an edge of the same color as the fill color is found. It can’t fill the figure with a color different from the figure boundary
graph_print- Prints text pointed by thetextargument. Font data should be passed tograph_font_tstructure. The example is stored ingfxdirectory in phoenix-rtos-tests repository (font.hfile). The remaining arguments are similar to those from the functions above.int graph_print(graph_t *graph, const graph_font_t *font, const char *text, unsigned int x, unsigned int y, unsigned char dx, unsigned char dy, unsigned int color, graph_queue_t queue)
graph_move- Moves data in the range specified byx,y,dx,dyarguments to the following point: (x+mx,y+my).int graph_move(graph_t *graph, unsigned int x, unsigned int y, unsigned int dx, unsigned int dy, int mx, int my, graph_queue_t queue)
graph_copy- Copies a bitmap pointed by thesrcargument into bitmap pointed by thedstargument. The area which is copied is limited by a rectangle withdxanddydimensions. There should also be specified span arguments, which represent the total width of a source/destination bitmap multiplied by its color depth. When copying some part of a bitmap,srcshould point to the proper element, and the same applies to the destination buffer.int graph_copy(graph_t *graph, const void *src, void *dst, unsigned int dx, unsigned int dy, unsigned int srcspan, unsigned int dstspan, graph_queue_t queue)
graph_colorset- Sets a color palette used for 8-bit indexed color mode. A color map should be passed incmapargument. The range of changing colors is set by passingfirstandlastarguments. If a set color palette’s size is lower than a default one, the remaining colors are the same.int graph_colorset(graph_t *graph, const unsigned char *colors, unsigned char first, unsigned char last)
graph_colorget- Retrieves a color palette used in 8-bit indexed color mode. The retrieved color map fromfirsttolastelement is passed to a buffer pointed by thecolorsargument.int graph_colorget(graph_t *graph, unsigned char *colors, unsigned char first, unsigned char last)
graph_cursorset- Sets cursor icon,amask(ANDmask) andxmask(XORmask) arguments determine the shape of the cursor. Default cursor shape is defined incursor.hheader file placed ingfxdirectory inphoenix-rtos-testsrepository. There is a possibility to pass cursor colors - outline color (bgargument) and main color (fgargument). The following color format should be applied:0xAARRGGBB, whereArepresents alpha, so when it’s set to0xff100% opacity is provided. Opacity isn’t supported for cirrus graphics adapter (default foria32-generic-qemutarget)int graph_cursorset(graph_t *graph, const unsigned char *amask, const unsigned char *xmask, unsigned int bg, unsigned int fg)
graph_cursorpos- Sets cursor position.int graph_cursorpos(graph_t *graph, unsigned int x, unsigned int y)
graph_cursorshow- Displays cursor.int graph_cursorshow(graph_t *graph)
graph_cursorhide- Hides cursor.int graph_cursorhide(graph_t *graph)
graph_commit- Commits frame buffer changes (flushes frame buffer) in the specified graphics adapter context.int graph_commit(graph_t *graph)
graph_trigger- Triggers next task from queue execution.int graph_trigger(graph_t *graph)
graph_stop- Disable adding new tasks to specified queue, for agraphcontext.int graph_stop(graph_t *graph, graph_queue_t queue)
graph_tasks- Returns number of tasks in queue.int graph_tasks(graph_t *graph, graph_queue_t queue)
graph_reset- Resets task queue.int graph_reset(graph_t *graph, graph_queue_t queue)
graph_vsync- Returns number of vertical synchronizations since the last callint graph_vsync(graph_t *graph)
graph_close- Closes a graph context, pointed bygraph.void graph_close(graph_t *graph)
graph_done- Closes the graphics library.void graph_done(void
How to use the graphics library#
Few simple examples of libgraph functions usage. Default graphics adapter (cirrus) for ia32-generic-qemu running
script is used, the default color depth is 4 bytes. Before calling mentioned functions the following initialization
was applied:
#include <graph.h>
#include <time.h>
int main(void)
{
graph_t graph;
graph_init();
graph_open(&graph, GRAPH_ANY, 0x2000);
graph_mode(&graph, GRAPH_DEFMODE, GRAPH_DEFFREQ)
/* clear screen */
graph_rect(&graph, 0, 0, graph.width, graph.height, 0, GRAPH_QUEUE_HIGH)
}
Purple line
graph_line(&graph, 0, 0, graph.width-50, graph.height/2-50, 2, 0x8282FF, GRAPH_QUEUE_HIGH);

Cyan filled rectangle
graph_rect(&graph, 200, graph.height/4, graph.width/2, graph.height/2, 0x00FFFF, GRAPH_QUEUE_HIGH);

Examples of
graph_fill()usage, both forGRAPH_FILL_FLOODandGRAPH_FILL_BOUNDoptionfor (int i = 0; i < 2; i++) { graph_line(&graph, 50+i*350, 50, 0, 300, 2, 0x00000FF, GRAPH_QUEUE_HIGH); graph_line(&graph, 50+i*350, 50, 300, 0, 2, 0x00000FF, GRAPH_QUEUE_HIGH); graph_line(&graph, 350+i*350, 50, -300, 300, 2, 0x00000FF, GRAPH_QUEUE_HIGH); graph_line(&graph, 52+i*350, 52, 146, 146, 3, 0xFFFFFF, GRAPH_QUEUE_HIGH); } sleep(2); graph_fill(&graph, 52, 55, 0x00000FF, GRAPH_FILL_FLOOD, GRAPH_QUEUE_HIGH); graph_fill(&graph, 402, 55, 0x00000FF, GRAPH_FILL_BOUND, GRAPH_QUEUE_HIGH);

Printing text using libgraph
Header file with font data in
graph_font_tstructure has to be included. The example offont.his placed ingfxdirectory in phoenix-rtos-tests repository.graph_print(&graph, &font, "lorem ipsum", 300, 300, font.height, font.height, 0x00FF00, GRAPH_QUEUE_HIGH);

graph_moveexamplegraph_rect(&graph, 100, 100, 200, 200, 0xFFFF00, GRAPH_QUEUE_HIGH); sleep(3); graph_move(&graph, 100, 100, 100, 100, 300, 300, GRAPH_QUEUE_HIGH);

Copying raw bitmap into a screen
Note that bitmaps are stored in memory in little endian format. So for 32-bit color depth first byte represents the blue color, next green, red, alpha, and so on.
static const unsigned char greenSquareBitMap32[50][8] = { { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, }; graph_copy(&graph, greenSquareBitMap32, (void *)(uintptr_t)graph.data, 10, 10, graph.depth * 10, graph.depth * graph.width, GRAPH_QUEUE_HIGH);

Setting and getting a color palette
The 8-bit color depth has to be applied, so for cirrus graphics adapter please use
GRAPH_800x600x8instead ofGRAPH_DEFMODE. Note that in a default color palette when using the 8-bit mode,0x01refers to blue and for passed color map (cmap) it’s{ 0xff, 0x00, 0x00}- red.unsigned char buff[2][3]; static const unsigned char cmap[2][3] = { { 0xff, 0xff, 0xff}, { 0xff, 0x00, 0x00} }; graph_colorget(&graph, buff[0], 0, 1); graph_colorset(&graph, cmap[0], 0, 1); graph_rect(&graph, 200, 200, 200, 100, 0x01, GRAPH_QUEUE_HIGH); sleep(1); graph_colorset(&graph, buff[0], 0, 1);

Moving a cursor The
cursor.hheader file with cursor shape data (amask,xmask) has to be included.graph_cursorset(&graph, amask[0], xmask[0], 0xff0000ff, 0xffffffff); graph_cursorshow(&graph); for (int i = 0; i < 300; i++) { graph_cursorpos(&graph, i, i); usleep(10000); } graph_cursorhide(&graph);

Generating an image bitmap and displaying it using libgraph#
To create a raw bitmap, which can be displayed on the screen, it’s needed to use some graphic program,
for example Gimp.
There are few steps to follow:
Open
Gimpand paste the imageSet the desired resolution (image → scale image)
Depending on the desired format:
for 8-bit indexed color - change the file mode (image → mode → indexed) and export the file as raw binary data (file → export and choose raw image data format)
for other color depths - export the file to C source/header format (a dialog window pops up with additional options for color conversion)
At this point image binary data should be available (either as an array in
.cor.hfile or raw hex dump)Custom image data formatting might be required
If the image bitmap is ready, there is a possibility to display it using graph_copy(). Please see the proper example
in How to use libgraph chapter.