Rendering SVG with OpenGL (and OpenGL ES)

AndroidOpenglOpengl EsSvgVector Graphics

Android Problem Overview


I am currently investigating the possibility of rendering vector graphics from an SVG file using OpenGL and OpenGL ES. I intend to target Windows and Android. My ideal solution would be to have a minimal C library that generates a polygon triangulation from a given SVG file. This would then generate standard OpenGL or OpenGL ES calls, and use a display list or vbo for optimization when redrawing. I would simply draw a display list to draw the vector image after translating and rotating, allowing me to mix this with other OpenGL calls.

So far I see that the suggestions are to firstly use QT or Cairo. - This is not an option given that I wish to manage my own OpenGL context without bloated libraries (in the context of what I am trying to achieve). Nor is this suitable for Android.

Second option is to use libraries that render to a texture. While this might be ok for static vector graphics, it's not an efficient or feasible option for games where scaling and rotations occur frequently.

Thirdly there is the possibility of using OpenVG. There are some opensource implementations of the OpenVG specification (ShivaVG etc), but I am yet to find a library that is capable of generating the appropriate OpenVG calls from a given SVG file at runtime, and I can't see how to optimize this as we might wish to with a display list or vbo.

All three methods suffer limitations. I think the most promising option is using an OpenVG implementation if no other solution exists. So my question is, are there any libraries out there that do what I want, or close to what I want? If not, is there a good reason why not? And would it be better to attempt to do this from the ground up instead?

Android Solutions


Solution 1 - Android

My answer is going to about displaying vector graphics wtih OpenGL in general, because all solutions for this problem can support rather trivially SVG in particular, although none support animated SVGs (SMIL). Since there was nothing said about animation, I assume the question implied static SVGs only.

First, I would not bother with anything OpenVG, not even with MonkVG, which is probably the most modern, albeit incomplete implementation. The OpenVG committee has folded in 2011 and most if not all implementations are abandonware or at best legacy software.

Since 2011, the state of the art is Mark Kilgard's baby, NV_path_rendering, which is currently only a vendor (Nvidia) extension as you might have guessed already from its name. There are a lot of materials on that:

You can of course load SVGs and such https://www.youtube.com/watch?v=bCrohG6PJQE. They also support the PostScript syntax for paths. You can also mix path rendering with other OpenGL (3D) stuff, as demoed at:

NV_path_rendering is now used by Google's Skia library behind the scenes, when available. (Nvidia contributed the code in late 2013 and 2014.) One of the cairo devs (who is an Intel employee as well) seems to like it too http://lists.cairographics.org/archives/cairo/2013-March/024134.html, although I'm not [yet] aware of any concrete efforts for cairo to use NV_path_rendering.

NV_path_rendering has some minor dependencies on the fixed pipeline, so it can a bit of nuisance to use in OpenGL ES. This issue documented in the official extension doc linked above. For a workaround see for example what Skia/Chromium has done: https://code.google.com/p/chromium/issues/detail?id=344330

An upstart having even less (or downright no) vendor support or academic glitz is NanoVG, which is currently developed and maintained. (https://github.com/memononen/nanovg) Given the number of 2D libraries over OpenGL that have come and gone over time, you're taking a big bet using something not supported by a major vendor, in my humble opinion.

Solution 2 - Android

Check out MonkVG an OpenVG like API implementation on top of OpenGL ES.

Also, for SVG rendering on top of OpenVG (MonkVG) checkout MonkSVG.

MonkVG has been built for iOS, OSX, and Android platforms.

I'm the author of both libraries and would be happy to answer any questions.

Solution 3 - Android

It needs to be said that rendering SVG or OpenVG with OpenGL or OpenGL ES is fundamentally a bad idea. There are reasons the OpenVG implementations are all so slow and largely abandoned. The process of tessellating paths (the foundation of all SVG/OpenVG rendering) into triangle lists as required by OpenGL is fundamentally slow and inefficient. It basically requires inserting a sort/search algorithm into the 3D rendering pipeline, which cripples performance. There is also the problem that a dynamic memory allocation scheme is required because the size of the data set is unknown since SVG places no limits on the complexity of the path geometry. A really poor design.

SVG and OpenVG were created by developers who had little understanding of how modern 3D graphics hardware engines actually work (triangle lists). They were created to be an open alternative to Adobe Flash, which also has the same flawed architecture that has made Flash reviled in the industry for unpredictable performance.

My advice is to rethink your design and use OpenGL triangle lists directly. You may have to write more code, but your app will perform about a thousand times better and you can more easily debug your code than someone elses.

Solution 4 - Android

> I am currently investigating the possibility of rendering vector graphics from an SVG file > using OpenGL and OpenGL ES. I intend to target Windows and Android. My ideal solution > would be to have a minimal C library that generates a polygon triangulation from a given > SVG file. This would then generate standard OpenGL or OpenGL ES calls, and use a display > list or vbo for optimization when redrawing. I would simply draw a display list to draw > the vector image after translating and rotating, allowing me to mix this with other OpenGL > calls.

If you only want to transform SVG vector shapes into OpenGL|ES, then I suggest to do the parser and the logic yourself. Note that SVG is a huge spec, with different features like paint servers (gradients, patterns ...), references, filters, clipping, font handling, animations, scripting, linking, etc, etc.

If you want full svg support, then there's a library on http://code.google.com/p/enesim called egueb (and particularly esvg) which uses enesim (a rendering library that has software and opengl backends) for the drawing. In most cases it uses shaders and everything is rendered into a texture, the library is very flexible allowing you to adapt to your particular needs like modifying the rendered scene, transform it, etc. Because the gl drawing is done always into a texture.

> So far I see that the suggestions are to firstly use QT or Cairo. - This is not an option > given that I wish to manage my own OpenGL context without bloated libraries (in the > context of what I am trying to achieve). Nor is this suitable for Android. > > Second option is to use libraries that render to a texture. While this might be ok for > static vector graphics, it's not an efficient or feasible option for games where scaling > and rotations occur frequently.

In the particular case of the gl backend, enesim does not create a GLX (or any other window dependent context), you have to provide it, so it adapts perfectly to your situation as it only uses GL calls.

The only drawback is that the library is not complete yet in terms of gl support or full SVG spec support, but depending on your needs, seems to me like a good option.

Solution 5 - Android

From http://shivavg.svn.sourceforge.net/viewvc/shivavg/trunk/src/shPipeline.c?revision=14&view=markup :

static void shDrawVertices(SHPath *p, GLenum mode)
{
int start = 0;
int size = 0;

/* We separate vertex arrays by contours to properly
handle the fill modes */
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, sizeof(SHVertex), p->vertices.items);

while (start < p->vertices.size) {
size = p->vertices.items[start].flags;
glDrawArrays(mode, start, size);
start += size;
}

glDisableClientState(GL_VERTEX_ARRAY);
}

So it does use a VBO. So I'd suggest making your own SVG parser / use a pre-made one, and forward the calls to ShivaVG.

You still have the problem that ShivaVG is in C (and not in Java) and creates an opengl context (and not opengles, if I read the code correctly). So even if you compile it using Android's NDK, you'll have to modify the code ( for instance, I've seen a few glVertex3f around, but they don't seem to be much needed... hope for the best). The other option, of course, it to port the code from C to Java. Maybe not as painful as you could imagine.

Good luck !

Solution 6 - Android

You can have a look at AmanithVG, they seem to have implemented a good paths -> triangles pipeline. I've tried the iOS GL tiger example, and it seems that triangulation is not a real bottleneck.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatt EschView Question on Stackoverflow
Solution 1 - AndroidFizzView Answer on Stackoverflow
Solution 2 - AndroidzerodogView Answer on Stackoverflow
Solution 3 - AndroidClayMontgomeryView Answer on Stackoverflow
Solution 4 - AndroidturranView Answer on Stackoverflow
Solution 5 - AndroidCalvin1602View Answer on Stackoverflow
Solution 6 - AndroidmirknacView Answer on Stackoverflow