16 August 2010
My name is Antonio Patriarca. The aim of my Shader Engine project is to implement a new visualization engine in Gephi based on modern graphics card capabilities. The current one is in fact designed to be very portable and only uses legacy features which are not optimal on modern hardware.
The OpenGL API, which Gephi uses, has changed a lot in the last years to follows the evolution of the hardware. Several parts of the first versions are now considered deprecated and they are difficult to implement efficiently in the drivers. For this reason, it is often necessary to redesign the graphics engines based on old versions to get the best from modern hardware.
In the old days, graphics primitives were rendered using a fixed pipeline implemented in hardware. The programmers had to set several states in order to control the rendering logic. Several tricks has to be invented to achieve not supported effects. At each new OpenGL version, several new states were introduced to give more freedom and power to the users and the pipeline soon became very complex and difficult to manage. This is how the current Gephi visualization engine is still implemented.
Inspired by the success of the RenderMan Shading Language, graphics card manufactures finally introduced some programmable stages to the graphics pipeline. These stages give the ability to precisely and easily define the rendering logic without taking care of a large number of states. At first, the only way to implement the programs, called shaders, running in these programmable stages was using an assembly language. But the GLSL language was soon designed to simplify shader implementation in OpenGL and other similar high level languages were introduced in the other APIs as well. The number of the programmable stages of the graphics pipeline are increased since their first introduction and modern GPUs are now often used as general purpose stream processors. The new visualization engine will use the shaders to render the nodes and edges of the graph in a more efficient way, while achieving an higher quality image.
Current Gephi Visualization Module issues
It is useful to discuss the problems of the current architecture to better understand the new engine design. The current Gephi Visualization Module was designed to be very portable and only use features available in the first OpenGL version. It is therefore based on the fixed pipeline and it sends the geometry to the GPU using the immediate mode or display lists. The new engine will still support legacy hardware, but it will also includes a more modern pipeline. Some issue will be only solved in the new pipeline.
Each renderable object (nodes, edges and labels) implements a common interface which take care of how it is rendered and responds to changes in the graph. In the rendering loop, the engine iterates over each edge, node and label and calls the corresponding method to render it. This is not optimal on modern graphics cards for several reasons.
A modern GPU is composed by several cores which runs the same program (they may execute different parts of it though) in parallel. Each time a state change, the GPU may stall waiting for each core to terminate before updating the state. In the current design, several states change between consecutive renderable objects causing the GPU to be idle most of the time. Moreover, each renderable object is composed by a small number of polygons and it is unable to use all the available cores. The best way to render objects using a modern graphics card is to sort them by state change and render them in batches. This is the strategy which will be implemented in the new visualization engine.
The OpenGL API is optimized to render 3D polygonal meshes. Therefore, the only ways to draw vector objects were to approximate them using polygons or textures. They both have issues when the objects are bigger enough which can be solved using additional memory. The current engine draw circles and spheres using a polygonal approximation. Shaders gives to the programmers a lot of additional freedom and it is now possible to draw general objects rendering a single polygon. The shapes generated using shaders looks good regardless of the size of the objects. The engine will use this method where possible.
New Visualization Module design
The new visualization engine will be composed by three parts: the viewer, the controller and the data manager. The viewer controls the drawable object and the main rendering loop. The controller updates both the camera and the selection area and handles all the window and mouse events. The data manager updates the graph information in the engine and decides what to draw each frame. Each part of the engine runs in a different thread. Therefore, it shouldn’t freeze when the graph is modified as it sometimes happen in current engine.
The rendering system of the new visualization engine will use concrete and immutable representations of the renderable objects. Each data manager frame, after the graph has been updated, each node, edge and label data is inserted in a render batch which is then inserted in the specific render queue. All the render queues (one for each renderable object type) are sent with the current camera to the Viewer for rendering. The Viewer then updates the current render queues and wait the following display method call.
The rendering logic for each renderable object will be defined in the renderers. Each renderer will be only able to render a specific type of object and it will render the entire render queue. There will be no way to directly render a single renderable object in the new visualization engine. The viewer will maintain a single renderer for each object type and it will then use them to render the current render queues. Two renderers will be implemented for each renderable object (one using the OpenGL 2.0 version and one using the OpenGL 1.2 version) and the viewer will decide what renderer to use based on the installed graphics card and user preferences. A detailed description of all the renderers will be soon published in the specification.
The majority of the changes in the new visualization engine will be invisible to the user, but there will be also some new features. The most important ones are the following (some of them will also requires some works in the other Gephi modules):
- Different node shapes for each node. It will be possible to define a different shape for each node and therefore use node shapes to distinguish between the different groups of nodes.
- Images as node shape. It will be possible to load images to use instead of the predefined node shapes.
- Wider choice of 2D node shape. Several node shapes will be supported in addition to circles and rectangles.
- Starting and ending color for edges. It will be possible to define a different color for the starting and ending part of the edges and use gradients to define edge directions.
- Clusters implemented as halos or depth-aware borders around nodes. Clusters will be supported rendering additional halos or borders of increasing depth of the cluster color around each node in the cluster.
- Per primitive anti aliasing (PPAA). Shaders allows the implementation of an anti aliasing strategy independent to multisampling. The new engine will implement these strategies to achieve a better image quality. In the figure above it is possible to observe the PPAA technique applied to the transition between the inner part and the border of a node in an old prototype without multisampling. The effect is slightly exaggerated.
Current status and future work
The engine is currently implemented as a standalone application independent of the rest of Gephi. The engine has been implemented in this way to be able to focus on the most important parts of the engine from the start. Gephi wasn’t in fact independent enough from the current visualization engine to immediately substitutes it with the new one. When the project will terminate, the standalone application will not have all the desired features and it will not be ready to be included in Gephi. The basic rendering system logic and the general engine architecture will be probably implemented in time though.
When the GSoC project will terminate the interaction layer with Gephi will be implemented and some parts of the code will be adapted to work with it. The project will be rewritten as a Gephi module and the required interfaces with the rest of the application will be implemented.