Avoiding pitfalls in the managed world

This text is intended for someone with a C/OpenGL background.

Even though OpenTK automatically translates GL/AL calls from C# to C, some things work slightly differently in the managed world, when compared to plain C. This page describes a few rules you need to keep in mind:

Rules of thumb

  1. Use server storage rather than client storage.
    A few legacy OpenGL functions use pointers to memory managed by the user. The most popular example is Vertex Arrays, with the GL.***Pointer family of functions.

    This approach cannot be used in a Garbage Collected environment (as .NET), as the garbage collector (GC) may move the contents of the buffer in memory. It is strongly recommended that you replace legacy Vertex Arrays with Vertex Buffer Objects, which do not suffer from this problem.

    Unlike OpenGL 2.1, OpenGL 3.0 will not contain any functions with client storage.

  2. Try to minimize the number of OpenGL calls per frame.
    This is true for any programming environment utilizing OpenGL, but a little more important in the OpenTK case; while the OpenGL/OpenAL bindings are quite optimized, the transition from managed into unmanaged code incurs a small, but measurable, overhead.

    To minimize the impact of this overhead, try to minimize the number of OpenGL/OpenAL calls. A good rule of thumb is to make no more than a few thousand OpenGL calls per frame, which can be achieved by avoiding Immediate Mode, in favour of Display Lists and VBO's.

  3. For optimal math routine performance, use the ref and out overloads.
    This is because Vector3, Matrix4 etc. are structures, not classes. Classes are passed by reference by default in C#.

    Vector3 v1 = Vector3.UnitX;
    Vector3 v2 = Vector3.UnitZ;
    Vector3 v3 = Vector3.Zero;
    v3 = v1 + v2;                        // requires three copies; slow.
    Vector3.Add(ref v1, ref v2, out v3); // nothing is copied; fast!

    The same holds true when calling OpenGL functions:

    GL.Vertex3(ref v1.X);  // pass a pointer to v1; fast!
    GL.Vertex3(v1);        // copy the whole v1 structure; slower!

Measuring performance

  1. GameWindow provides built-in frames-per-second counters [Someone with confidence in the details please fill in here] However, GLControl does not.
  2. A simple and convenient way to measure the performance of your code, is via the .NET 2.0 / Mono 1.2.4 Stopwatch class. Use it like this:
    Stopwatch sw = new Stopwatch();
    // Your code goes here.
    double ms = sw.Elapsed.TotalMilliseconds;

    Note: Avoid using DateTime.Now or other DateTime-based method on any periods shorter than a couple of seconds, since its granularity is 10 ms or worse. (rumour has it, it may even go backwards on occasion!) Using DateTime to measure very long operations (several seconds) is OK.

  3. If you are on Windows, you can download Fraps to measure how many frames per second are rendered in your application. For linux (and Windows), you can use the commercial tool gDEBugger [anyone: any similar tools for Mac? Any free tool for Linux?]



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

No such tools that I'm aware of, *but* GameWindow provides methods to measure frame time (and how much time passed in the UpdateFrame and RenderFrame events). The code's a bit untested, but should work. For the GLControl, you'll have to do this manually.

In general, I think it's better to provide this functionality in your own code, than rely on external tools (which may incur an additional speed hit).

objarni's picture

I agree, but to someone new to the OpenTK/C# environment of development, it might be simpler to use such a tool. Also to make sure the timing mechanisms are fairly accurate, such a tool is great.

georgwaechter's picture

there is another quite cool program that (among other things) displays the FPS: gDEBugger (an opengl profiler) ... but sadly it is a commercial tool

advantage: it works under linux and windows (i think mac version is planned)

AdrianPi's picture

glIntercept is a good non-commercial alternative to gDEBugger and is free as in freedom, although is Windows-only


fdncred's picture

gDEBugger is now free for PC, Mac, and Linux. http://www.gremedy.com/

DreaminD's picture

Hmm, the bit about "300-500 OpenGL calls per frame" is quite misleading/confusing. The discussion here explains the actual situation, but I believe it would be better to clarify that in the official documentation :)

On a side note, could there be any overhead reduction if a bunch of calls to unmanaged code are placed into unsafe {} block? Perhaps that won't help with OpenGL-like API, but still :J

the Fiddler's picture

Updated to mention several thousand rather than 300. Unsafe blocks won't help, the bindings are already using them internally wherever possible.

I'm testing out a new p/invoke system that will hopefully improve both runtime and startup performance. Once it stops crashing, that is :)

DreaminD's picture

A new p/invoke system... I didn't know there were several of them =3 Would you mind to somewhat explain the outline of your idea?

I've just tried to do a quick search on that topic, but currently only found a mention that doing wrappers in managed C++ might give less overhead than p/invoke: http://stackoverflow.com/questions/1433334/performance-differences-betwe... Are you by chance planning to use this?