Saturday, 7 July 2007

ShivaVG: open-source ANSI C OpenVG

Vector graphic algorithms on CPU are more or less reaching their limits and the only hope to get software like Adobe Illustrator speeded up is probably by installing a faster processor into your PC. I've started an open-source project for a vector-graphics drawing library that would use hardware acceleration already a year ago under the name libShiva. However, it never took up really well and recently I realized why.

Basically, it's the same problem as with other current open-source vector-graphics APIs that utilize graphic card. They are usually a part of a very large toolkit or framework and it's hard to use the sole drawing API without having to link your project against and make it dependent on the whole framework. This goes for projects like Qt (and it's OpenGL drawing widget) as well as Amanith, which itself depends on Qt for creaton of a window and initialization of an OpenGL context.

It was the same problem with libShiva - I tried to implement a HW accelerated renderer and a whole GUI toolkit together with event management like Flash offers in its ActionScript in one single library. That made the lib very heavy for use, but on the other hand, what we really need is a lightweight API that just renders the graphics, possibly written in ANSI C to be as portable as possible.

And here's where OpenVG came into play. It is a royalty free API developed by Khronos Group (http://www.khronos.org/openvg). Originally it targets smaller, portable devices (e.g. mobile phones, PDA's) but the specification itself encourages PC implementations as well. What is pretty obvious is that on hand-held devices the API will be implemented in hardware and there are already plans by nVidia and other companies to design chips to handle OpenVG.

Since such hardware is not available for PCs yet, I decided to implement the API on top of OpenGL which is basically the same approach that Qt's OpenGL painter and Amanith use. Actually, there is already a project named AmanithVG which is another implementation of the OpenVG API, but it's commercial and closed source. Usually, when I see good projects made closed-source and commercialized, I get really pissed off, and I feel the urge to start a similar open-source project. Besides, after having a look at the API it felt like this is exactly what FOSS community would need. Moreover, as a response to a blog entry by Zack Rusin regarding the implementation of the OpenVG API on top of Qt (link), there was already a request for an ANSI C version of it.

So, I took the rendering code from libShiva project, translated it from C++ to ANSI C and wrapped into OpenVG API, to create a new implementation called ShivaVG. So far, most of the code for creating, transforming, interpolating and drawing paths is done. The imaging support is currently very poor (just RGBA_8888 format supported), but both linear and radial gradients work and full porter-duff blending is being developed. The source code is accessible via subversion at SourceForge:

$ svn co https://shivavg.svn.sourceforge.net/svnroot/shivavg/trunk

After optimizing the code a little bit the performance is even much better than the old libShiva implementation. Check the lower-left corner of the example program screenshots to see the number of frames per second - that's on Core 2 Duo 2.16 with GeForce 7600 GT. The EGL API for creating an OpenVG context is not implemented yet, but you can use any kind of technique to achieve that (GLUT, SDL, native). The only thing to do then is to call vgCreateContextSH prior to any other VG call and vgDestroyContextSH when you are done. The example programs use GLUT, so you will need that to compile them. There are even Visual Studio projects provided for those of you who use Windows.

Great Work I have to say with ShivaVG. I have been developing with OpenVG for a few years, and this has been the best implementation Ive seen of this great API. Now the time has come with you developing a Desktop, hardware friendly and Open Sourced alternative. Thank you very much my friend and keep up to date with your progress with your project and uni work. Hope all is good with your study....

I've been eager to develop a system that allows the creation of a scalable UI placed over an OpenGL application. I'd like the user to be able to interact with 3D objects using basic openGL picking and that part I have well in hand. What I need now is a good, robust system to place an interface (buttons, boxes, etc) on top of this existing 3D application.

While OpenVG would be great for a scalable user interface it seems to me to lack built in picking like OpenGL provides. But, perhaps we can bridge this gap with your library? In fact, since you have it using OpenGL in the background there is the potential to use OpenGL Picking to handle user interaction.

Any thoughts on this? Is there perhaps a better way to handle picking in general with OpenVG that I'm not aware of?

either way, very nice system. Your code is a breath of fresh air in this world of shoddy open source libraries. It has real potential to become a solid system used in industry. Keep up the good work.

Wow, I'm quite amazed by the response received on my blog despite not advertising my work much around the web. Well, to answer some of your questions:

Yes, the implementation should work also on a 1-bit stencil buffer, since the only place it is being used is to define the inner parts (the fill) of a shape before it is being filled with paint and so far it only needs a 0 or a 1 to tell the inner / outer area apart.

Also, regarding the picking. In the next iteration of the library I am going to add an extension to the API to provide a new function. This function will take a point in screen coordinates and test whether it lies inside a given path when it is transformed by the current path-user-to-surface matrix. The definition of "inside" here follows the current filling rule (even-odd etc.)

Hope this will allows even broader use of the library. Thanks to everyone interested in my work!

It seems like it has a tiny bug in your radial gradient paint code.It doesn't look right when I draw a radial gradient with paint to user matrix having a rotation.You can see this bug with code below in your TestRadial project.

why would you like to "factor out opengl dependency"? opengl is what makes this thing run fast! are you hinting that you are using d3d for you game engine? i'm writing my own in opengl and using shivavg with it is really simple ;) I think shivavg will never have a d3d backend for one simple reason: d3d is not open, opengl is.

Because 3d engines generally manage the APIs state. No matter if GL/DX or backends for both are available. The native API calls from shivavg alters/invalidate the API state the engine is tracking. And more generic/plugable backends would remove all the immediate mode calls since they arent available in both APIs :). Most middleware libraries in the games domain provide interfaces for the renderer instead of directly talking to it (e.g. SpeedTree, Scaleform..etc..). And it is even more open thant "just" opengl :)

Well, openvg was not really designed as a middleware, though. It primarily targets embedded devices with a direct hardware implementation. ShivaVG so far is actually more desktop oriented and that's why its written on top of OpenGL. There could in the future come another implementation / branch that would target OpenGL ES or maybe the whole thing would be abstracted even more to proved a d3d backend, but to be really efficient, there needs to be as little internal abstraction layers as possible. Which means one of the 3d graphics api's just has to be chosen, or a direct communication with a hardware implementation established.

And being that C++ would generally take up more memory than c they differences make sense.

So aether A. There is something seriously wrong with my system which wouldn't make sense being that i have thousands of opengl code examples written in c & c++ including OpenGL & Cairo examples and no application other than ShivaVG & AmanithVG has this issue with using up all of my memory.

Or B. AmanithVG took ShivaVG sourceconverted it from c to c++ and made it closed source and in the process took alinux bug with them.

Steven, this is far from being a bug. The example applications use GLUT library to construct a window with an OpenGL context. To be able to animate the scene, a functions callback is registered to be called whenever the application is idle which mean it's "doing nothing". Basically the glutMainLoop() function loops idefinitely as fast as it can and calls the callback functions to notify the application of certain events like mouse movement and keyboard clicks. When nothing is going on, the display function is called to redraw a new frame of animation.

An real-world application would probably block the execution for a few milliseconds in between the frames, just to keep the framerate acceptably high, but not to use 100% cpu time. The example applications are much simpler than that though.

I can confirm this performance problem with glutIdle functions. They do tend to bog down the system and understandably so.

One thought (and something I've done to help alleviate this in the past) you can use a glutTimerFunc instead of a glutIdleFunc. The timer function will trigger after a set interval of time passes (or as soon as possible if the event loop is running too slow to accommodate the requested time). You can make this be every 1/15th or 1/30th of a second (or whatever interval you want) to achieve typical animation frame rates.

The nice thing is, if you are careful about when you set it then it will only trigger when you actually have some animation to be doing. So, when the scene is static the program is truly idle (0% cpu). Also, when it is animating you can potentially avoid the 'slam the processor' effect by re-drawing at a set framerate instead of every chance you get. On faster systems the idle function approach will be way faster than it needs to be and will bog down the processor unnecessarily.

I see people using the idle function a lot when I look at OpenGL tutorials and other OpenGL code on the net. In general I think it is always preferable to use the glutTimer function instead but it is more complicated to work with particularly since it cannot trigger more than once. Also, while many examples will have a timer function reset itself to achieve a periodic timer I find in practice this doesn't always work (particularly in GLUT for win32) so you often end up having to find creative ways to reset it. So in the end it's the old tradeoff between programming simplicity and performance.

Hello Ivan,I am new to OpenVG and trying to understand the spec and implementations available. I came across your page and was able to build the library.I also downloaded reference implementation from khronos site.I am a bit confused about what is the difference between ShivaVG and official reference implementation provide in khronos site?What are the advantages of ShivaVG over reference implementation?Sathya

Good news: successfully installed and built ShivaVG on 64 bit SUSE. First, I needed to obtain a newer compiler (gcc) which I did via YaST. Then I also needed OpenGL libraries so using YaST I downloaded freeglut. Finally, successfully ran ./configure, make all, make install. Many thanks!

Is it possible to use ShivaVG without using GLUT in my application code? Instead of GLUT, I plan to create an X window myself and create an EGL window surface using this X window. Would ShivaVG be able to render onto this EGL window surface?Would I need to make any modifications to achieve this?

I have been working with ShivaVG for quite a while now and it has even exceeded my expectations! Fast as Lightning =)

However, I have been asked by several people on how to set up the whole thing, when they compile it themselves. Its not exactly tricky, but it would be easier, if I could "embed" the ShivaVG source in my project files (we use MSVC and Code::Blocks).

Now this would not be a problem if the project would have been licensed under the GPL, but sadly this is not quite an opurtunity for us (partly because of user contributed code, where I cant get in contact with the original author anymore and ... I guess you know that kind of problem).

So I would just like to ask, if it is planned to switch to another license in future? Preferably one that allows static linking?

Is this project even alive any more? It seems like a lot of progress was made real quick then nothing...

There are some problems like in the README it says vgSetColor is implemented but the function is actually not anywhere in the source tree and you will get an undefined symbol if you try to use it.

I'm sad to see the utter lack of any available and complete open-source OpenVG API. A BSD-style license would be even better so we can statically link with other BSD-licensed (or compatible; non-*GPL) projects.

@Ivan, any chance of getting some proper SVG loading capability into the lib? Or giving some examples of using a good cross-platform SVG loading lib to do it? ShivaVG is really the only good option for game-quality SVG rendering that I've found, but unfortunately there don't seem to be any good cross-platform c/c++ libs for actually just loading SVG files (i.e., something that works on Windows as well, and doesn't require cygwin and tons of hacks (cairo, etc.)).

Hi, from varius sources your library for OpenVG seams to be one of the most usable. However I got (embarrassingly) stuck at make. My system is Mac OS X 10.5.6. Any clues to what might be wrong to this:

d-rll01:shivavg-0.2.0 rll01$ makemake all-recursiveMaking all in srcmake[2]: Nothing to be done for `all'.Making all in examplesmake[2]: Nothing to be done for `all'.d-rll01:shivavg-0.2.0 rll01$

I'm very interested in a design document. I'd like to recode it in C++ under a license that would be compatible with DirectX. I can't modify GPL-ed code or lgpled code but I could modify code under a different license and release it. (I haven't agreed to the GPL for legal reasons, it simplifies everything, and I'm not required to. A friend of mine said "that's so gnu" when I informed him about clause 9 in the GPL v3.

Also, TCL3d may have vector graphics code I plan to use if possible, under the BSD license.

I recently came across your blog and have been reading along. I thought I would leave my first comment. I don't know what to say except that I have enjoyed reading. Nice blog. I will keep visiting this blog very often.

I'm trying to use the image examples (TestImage & TestPattern), and I can not get them to work. After trying to use the jpeglib DLLs which did not work, I rebuilt jpeglib as a standalone lib. Now each program works without crashing, but the images do not display inside the designated boxes in the applications. What am I doing wrong?

Hi I need a help from yourwhile installing shivavg in meego i am getting this error why ?ShivaVG example programs will not be built because the GLUT headers are missingI know I miss somethingfrom where I will the packages