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.




53 comments:

Uros Trebec said...

As I said before... very very impressive! Rock on!

Cobo said...

Have you talked about using it within Cairo to their developers?

I expected something like you did after having the same feeling with Amanith and Arthur.

Cairo seems a little mess right now... and maybe isn't the moment to put something more in, but just in case...

This is pretty awesome. A well-defined standard implemented without depending on any toolkit. Glad you didn't use any GObject thing, did you?

Thanks for the hard work.

Ivan Leben said...

I don't know what you mean by GObject, but there is no such thing in ShivaVG. Just pure ANSI C and the OpenVG API.

Yeah, I was thinking about writing a Cairo backend using ShivaVG but right now I'm just so busy with all the uni projects that I really have no time.

Justin said...

This would be a fantastic library to have for Python! Currently vector drawing modules for python are lacking (or very restrictive in licensing).

Thanks for your hard work! This could truly be a groundbreaking project.

Дмитрий said...

Please could you tell will your implementation work on OpenGL with 1-bit stencil buffer?

pyro said...

yeah! finaly someone did it :)

i thought exactly the same when i read about the commercial openVG api or the one that depends on qt.

your project is exactly what we need regarding OpenVG.

keep up the good work. i really would find some use for your great library in my next game,
i hope you finish it :)

have a nice day

David said...

Hi Ivan

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....

Dave

OllieBrown said...

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.

Ollie

Austin said...

For some reason, when I do vguEllipse, I get a diamond rather than a circle. Is this something unimplemented in the lib, or am I doing something wrong?

Austin said...

Figured it out, it was an issue with the default viewport. It wasn't taking enough sample points because the default scale is small.

n008 said...

Does anyone know of a good, lightweight SVG parser? Save me a considerable bit of time if I could just use something akin to TinyXML to load up my SVG images.

I've looked around quite a bit on Krugle and Koders and there are some out there but they seem rather heavyweight, very integrated into their main apps.

n008 said...

Actually, I found one just now that's part of libxml++ (LGPL). Should do the trick.

Ivan Leben said...

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!

Skavenger said...

i would like to see a gnash/swfdec to OpenVG backend based on ShivaVG, soon or later !

yuneng said...

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.

VGfloat ang=15.0f; // simply change initial value of ang.

Please this helps.
If I was wrong please let me know.

Ivan Leben said...

Yes, yuneng, something is definitely wrong with that. Thanks for the feedback! I will have a look at it asap.

Ivan Leben said...

The bug report by yuneng has now been fixed. New source is in the repository as well as released for download.

Youare said...

Very impressive!
Any chance of factoring out the opengl dependency to allow hooking into a 3d engine?

Ivan Leben said...

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.

Youare said...

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 :)

Ivan Leben said...

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.

Steven said...

I am having some problems with shivavg-0.2.0.

Every example uses 100% of my cpu
and any code i write uses 100% of my cpu.

Here are my system specs.

1. MSI K9NBPM2-FID AM2 NVIDIA Quadro NVS 210S Micro ATX AMD Motherboard

2. AMD Athlon 64 X2 6000+ Windsor 3.0GHz Socket AM2 125W Dual-Core Processor

3. A-DATA 1GB 240-Pin DDR2 SDRAM DDR2 800 (PC2 6400)

My os is Crux Linux 2.4 http://crux.nu/
And my nvidia driver is NVIDIA-Linux-x86-169.12-pkg1

I am only see this issue with ShivaVG

Besides that you did a great job :)

Steven said...

Ok so i compiled & tested ShivaVG-0.2.0 against both nvidia and mesa libs and ran all examples.

Plus i did a complete system rebuild from source.

All examples use CPU 99.6% & Give or take 15.95Megs Memory

I then tested AmanithVG
and guess what...
All examples use CPU 97.4% & Give or take 20.09 Megs Memory

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 source
converted it from c to c++ and made it closed source and in the process took a
linux bug with them.

Or C. Both your implementations are based on a flawed spec.

Anyone else want to verify this bug?

Ivan Leben said...

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.

OllieBrown said...

GLUTIdle func vs GLUTTimer

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.

Just my two cents. :-)

Seth

Ivan Leben said...

The ShivaVG example applications output FPS number for a reason and they *are* ment to try and draw as many frames as possible, instead of being locked at a certain framerate.

Sathya said...

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

dann said...

This is pretty cool. However having to chase all the dependencies is really a pain in the butt. Can't you please add the dependencies directly on the repository?

Do you plan on doing an OpenGL ES 2.x implementation? This would be the ideal HW accelerated backend.

dann said...

Hum i can get it to compile but i must be using the wrong libs, because it then crashes.

Can you please make the windows dependencies available. What libs are you using besides GLUT, libpng and libjpeg?

kohai said...

Hmm ... how can i say this ? ShivaVG is just godsend ! thx a bunch !

Mike Quentel said...

Thanks very much for this implementation of OpenVG. Has anyone tested ShivaVG successfully on Linux? I'm trying to build the source on a 64 bit SUSE Linux box, but running into problems.

Mike Quentel said...

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!

Glenn said...

A quick 5 minute patch to enable support for Screen blend mode:
--- shPipeline.c~ 2008-04-27 23:32:01.807318289 +0200
+++ shPipeline.c 2008-05-18 10:56:17.104178696 +0200
@@ -83,6 +83,11 @@
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (alphaIsOne) glDisable(GL_BLEND);
else glEnable(GL_BLEND); break;
+
+ case VG_BLEND_SCREEN:
+ /* src and dst are assumed premultiplied */
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
+ glEnable(GL_BLEND); break;
};
}

Christian said...

Could you please merge the latest cairo git version with your openvg version? I have some merge conflicts and didn't yet find the time to get to know cairo enough to fix them.

Please keep on maintaining and extending this project, it's a cool thing and could help accelerate the whole desktop.

Beoran said...

This is shaping up to be great!

Anyway, I just hacked together a completely untested SWIG based Ruby wrapper for your ShivaVG library. Ruby fans can download it here:

http://rubyforge.org/frs/?group_id=4924

I hope it's useful to someone. ^_^

Dave said...

Good stuff.

Any chance of seeing vgMask etc anytime soon? I'm writing a remake of an old BBC game and it would come in useful.

By the way - if anyone else is using SDL to set up the screen make sure you set the stencil size (SDL_GL_STENCIL_SIZE) - I didn't and was baffled for ages ....

Marcus said...

This is great!

Googie said...
This comment has been removed by the author.
Googie said...

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?

- Googie

Marcus Riemer said...

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?

CR said...

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.

n008 said...

@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.)).

rikardvilhelm said...

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$ make
make all-recursive
Making all in src
make[2]: Nothing to be done for `all'.
Making all in examples
make[2]: Nothing to be done for `all'.
d-rll01:shivavg-0.2.0 rll01$

Cheers
Rikard

Tener said...

It looks like a great project. Keep going!

Electro said...

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.

Donte said...

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.


Joannah

http://transcendmemory.net

new_to_vg said...

This library seems to be very helpful for the work what i want to do.

I have a couple of doubts

1. I want to have OpenVG implementation
over OpenGL ES.

2. The current implemantation is for
Desktop, i will like to port it to
ARM

How difficult/complex are above points assuming i start implementing on top of ShivaVG.

sunshine_uyl said...

I would like porting ShivaVG to Android platform. Could you tell me how to start it?
Thanks!

wstuart said...

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?

tmarbois said...

Has anyone tried porting this to OpenGL ES / IPhone OS yet?

Ross said...

Anyone interested in C# wrapper for ShivaVG?

hari said...

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

Dylan said...

Is it possible to use the NON_ZERO fill rule in your stencil buffer implementation of polygon drawing and still be able to draw concave polygons?