Rich's picture

OpenTK instead of Tao

Hello there!

I'm currently using Tao & Mono for my Project to rebuild a 10 year old 2D game.
I came to your side once in a while and I think that OpenTK is much more serious than Tao.

My question is now:

Is OpenTK a good choice for that? Are there more advantages than less cryptic code (which is a present from heaven for me)?

thx rich


Comments

objarni's picture

* OpenTK has linear algebra types which integrate nicely with the OpenGL API (vector, matrix, quaternion)
* OpenTK allows usage of .NET Color (a minor thing but sweet anyway)
* OpenTK feels a lot more .NETish than Tao
* OpenTK has some enum-separation allowing easier-to-write code (via IntelliSense), compared to Tao's "one enum to rule them all". (last time I checked at least - which was two years ago but anyway ...)

Rich's picture

Fair enough! So you would say OpenTK + Mono/.Net is fast enough for a 10 year old 2D Game?

thx rich

the Fiddler's picture

Absolutely.

Since you are aiming for 2d, take a look at AgateLib. It uses OpenTK and is easier/simpler than raw OpenGL.

Rich's picture

thx for the fast replies and hopefully i can announce my new project soon :)

BlueMonkMN's picture

I'm using OpenTK for Scrolling Game Development Kit 2, converted from Managed DirectX, and it runs significantly faster. It can also handle more sprites faster than the original Scrolling Game development Kit based on DirectX 5, which I assume is partly due to the fact sprite behavior is based on compiled rather than interpreted code now, thanks to .NET's ability to compile code at runtime. I haven't tested under mono as much, but I have run games compiled by both Visual Studio in Windows and Mono in Linux, and the performance of the projects compiled by Mono seems about the same; I just don't know how hard I could push the Mono/Linux version before I start seeing performance degradation. With Visual Studio, I believe I got at least a hundred sprites before I noticed anything (it's been a while since I ran the test). And I've done multiple layers of parallax scrolling tiles without any problem, of course (tiles are easier on the CPU than sprites).

the Fiddler's picture

The only place where I've seen Mono perform significantly worse than .Net is GC performance, but even this is being worked on (a new, generational GC is planned for Mono 2.8 IIRC). There are other differences, but few of these actually impact games (e.g. string/xml processing or things like that).

Interestingly, my current project runs significantly faster on Mono/Linux compared to .Net/Vista. I get ~72 fps on Linux vs ~60 fps on Vista, which is a tremendous difference for the amount of processing involved (relief mapping with multisampled self-shadows, SSAO, bloom filter on floating point buffers and quad-buffered stereo). I haven't tried to trace the cause yet - I doubt it's the runtime - but the difference is there and it's significant.

Even more curious is the fact that this is on Ati hardware, which is notorious for its Linux drivers.

In any case, performance is pretty good on both runtimes. Absolutely no problems on that front.

Kamujin's picture

I have to disagree slightly. The mono run time consistently under performs the .NET run time in many areas. They have made improvements in mono 2.2 targeted at improving performance, but quite frankly, Microsoft has out spent them by orders of magnitude in optimizing the .NET run time.

Having said this, I feel that the mono run time's performance is without question good enough for many projects. I think the performance variation you will experience in the underlying hardware will have far more impact than the difference between the run times.

objarni's picture

Is there a difference between "numerical program" (not using so much of the .NET standard libraries) and API-heavy programs (eg. WinForms/db/other standard lib stuff..)?

What I'm trying to get at, is if there is a difference between the byte-code/jit-compiler in .NET and mono, and if there are differences in the implementations of library routines.

the Fiddler's picture

The .Net C# and jit tend to create better code than the ones used in Mono. From benchmarks posted to the Mono mailing lists, the Mono BCL is slower more often than not, which is understandable if you take the platform abstraction layers into account.

However, there are two things that make Mono equally (or more) suitable to .Net for games: faster pinvokes and Mono.Simd. Most games make heavy use of unmanaged APIs and numeric computations and (bugs aside) Mono shines on these.

docflabby's picture

Hey rich,

As someone who is also remaking a 2D game (except in my case im making it 3d) i would highly recommend OpenTK

Why use OpenTK instead of Tao?
- OpenTK has ALL the functionality of Tao with alot less typing. the time you save in typing is amazing.
- You can use Tao and OpenTK side by side. Thus if there is something you need in Tao you can still use it
I still use Tao.devil to load textures and images.
- OpenTK has an amazing text writing utility which makes writing text to the screen easy. In Tao you have to do this all manually.

I started with Tao but as soon as i found OpenTK i switched. Its just so much easier to develop with.

This is why i use OpenTK :)

Rich's picture

k thx for support. Another question came up to me yesterday. I read the short guide on the site and i saw that because of compability time from .net/mono to c there shouldn't be more than 600 GL.X calls for every frame.
My game has a tile terrain which means i have about 600 quads (basically 44x44) building up just my terrain (i can upload a image if you want to tomorrow). I'm having serious problem with performance because the game seems to eat all power of the CPU. Is there a workaround that i use something like a vertex buffer or indexbuffer like in DirectX and not to call more than 600 times my render statement GL.Begin(BeginContex.Quads); .... GL.End() ?

thx rich

objarni's picture

VertexBufferObjects, or VBOs for short. See this tutorial:

http://www.opentk.com/doc/chapter/2/opengl/geometry/vbo

Note: VertexArrays are a good and easy way to draw things a lot faster in C/C++. But it is neither easy nor fast in C#/.NET! VBOs is what you are looking for!

the Fiddler's picture

The 600 calls is not a hard limit, just a rule of thumb. You will get a nice speed boost if you switch to Vertex Buffer Objects, but I don't think the GL.Begin() - GL.End() is the cause of the high CPU usage here (each OpenGL call has an additional overhead in the order of 8-15ns compared to C code, so it's not that bad).

Are you using the debug or the release version of OpenTK? The debug version hits the cpu hard: it calls GL.GetError() automatically, which causes the OpenGL command-queue to flush.

It's also normal to see 100% CPU usage if you don't enable vsync, because then you are drawing as fast as possible. Enable vsync and CPU usage should drop significantly.

Rich's picture

Ok i now have a constant low CPU usage without any VBO... I do not really know how to write my data into the VBO and at the same time use the index buffer. (Picture in attachments)

1,2,3 and 4 are the vertices i'm using on each drawn tile.

How would you use the index buffer?

thx rich

AttachmentSize
Bildschirmfoto.png416.16 KB
the Fiddler's picture

You'll have to use the index buffer to connect the 4 vertices so that they form two triangles. Assuming the vertices are like this:

34
12

You can connect them like this:

1, 2, 3
3, 2, 4

Make sure that you preserve the normal between the two triangles (123 and 324 have normals that face the same way. 123 and 342 have normals that face in opposite ways).

If performance is adequate, I wouldn't worry about using VBOs just yet. When building a 2d game, you'll probably want to keep hardware requirements as low as possible, which usually translates in an OpenGL 1.1 code path (i.e. immediate-mode and display lists). OpenGL 1.1 won't go away any time soon and even plain old immediate-mode can be fast enough for old-school 2d games with a little care.

If possible, just try to decouple the data structures for your map (tiles, layers, regions) from their rendering method. This way you'll be able to add a VBO render path later on, if you decide it's necessary.

Inertia's picture

http://www.opentk.com/doc/chapter/2/opengl/geometry

Is there anything we can do to make these kinds of articles easier to find? I still intend to add custom Vertex attribs and VAO explanation to these pages, but there shouldn't be a single person visiting this website who does not know about VBO. Or spell it VOB. ;-)

If you want my 2c why OpenTK is superior to Tao: (Besides what was mentioned above, which is all true) OpenTK saves you alot of time looking up function parameters in manuals. OpenTK does not spare you reading the red book or a similar introduction to GL, but if you are familiar with the usage patterns it is very helpful to have the enums. The enums take away your little "Woot! I wrote 10 lines of GL code without using the manual and it produces no GLError!" victory, but that's something one can live without.

Rich's picture

I finally gave VBOs a try and the performance is much more adequat.

But still some questions :) :
I have about 600 "maptiles" every frame.... (see picture above from previous post).
Now with the VBO i have to bind for every tile a the texture id.
Isn't there faster way? Can't i just store the texture ids for each quad in GL and
destroy this loop with mean about ~1200 GL calls?

for (int i=0;i < 600;i++)
{
  Textures.BindTexture(todraw[i]); //todraw[i] is the texture id i want to bind
  GL.DrawArrays(BeginMode.Quads,i*4,4); //here i draw one of the 600 quads
}

EDIT:
Another question came up to me. I read about the PBO (Pixel Buffer Object). I didn't
really understand why to use it. I can use it to store texture via the DMA (Direct Memory Access).
This procedure relieves the CPU usage.
But when i bind my texture the bytes are already stored in GL? why should i use the PBO?

thx rich

the Fiddler's picture

The best solution way is to use tile sheets, were multiple tiles are stored in a single texture. This way you can change a tile by simply changing the texture coordinates of its quad.

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct VertexPositionTexture
{
    Vector2 Position;
    Vector2 TexCoords;
}
 
// Load 'tiles' into the VBO afterwards.
var tiles = new VertexPositionTexture[MapWidth, MapHeight, 4];
for (int x = 0; x < Map.Width; x++)
{
    for (int y = 0; y < Map.Height; y++)
    {
        tiles[x, y, 0] = new VertexPositionTexture()
        {
            Position = { X = x * TileWidth, Y = y * TileHeight },
            TexCoords = { X = tile_coordinates_in_texture.X, tile_coordinates_in_texture.Y }
        };
 
        tiles[x, y, 1] = new VertexPositionTexture()
        {
            Position = { X = (x + 1) * TileWidth, Y = y * TileHeight },
            TexCoords = { X = tile_coordinates_in_texture.X + TileWidth / TextureWidth, tile_coordinates_in_texture.Y }
        };
 
        // Likewise for the other two vertices of the quad.
    }
}

This way, assuming that all your textures fit inside a single tile sheet, you'll be able to draw all 600 tiles with a single draw call:

Textures.BindTexture(tile_sheet);
GL.DrawArrays(BeginMode.Quads, 0, 600*4);

If they don't fit in a single tile sheet, you can use as many draw calls as the number of tile sheets you have. It's slightly more complicated (not much), but it is going to be *much* faster than 600 texture binds & draw calls.

Edit: PBOs can help you write or read textures from GL memory asynchronously. They also have other uses that aren't really relevant here.

Rich's picture

Hey there,

I'm still having some problems with performance (or i think i can code it much faster).
First look at picture in attachments pls!

What about if i make for each 8x8 block on the map a drawing list and move arround with GL.Translate(x,y,z); ? would that be faster?
what you think

thx rich

AttachmentSize
8x8.png464.51 KB
objarni's picture

Display lists are a good option to speed up non-dynamic rendering, as your grass tiles (they look the same all the time).

During the load of your level, create a display list by "recording" the rendering of 8x8 block of grass tiles. The display list (DL for short) will get an integer "name" just like texture objects do.

Note: DO NOT re-create the display list at every paint! That is a common beginners-mistake. Re-creating the display list every paint is likely to be slower than using ordinary immediate mode.

In your paint method:
1. clear the color buffer (this step might be skipped if your grass block covers 100%, but your image says otherwise - there is some pixel row between each tile shining through whatever is behind the grass)
2. blit the DL all over the background, with as few CallList as possible.
3. draw images of the tree, mushroom ontop of this.

Here's a random tutorial I found to get you started:

http://www.songho.ca/opengl/gl_displaylist.html

the Fiddler's picture

Yes, display lists should be faster in this case. The best ways to improve performance are to:

  1. Draw more stuff with less calls. Modern hardware performs best when you draw at least (IIRC) 4096 vertices per draw call - anything less and it starts to stall.
  2. Minimize state changes. Sorting everything by shader / texture will be much faster than binding a different shader / texture every time you issue a draw call.

Display lists help in both regards: you draw more stuff in one call and they driver may be able to minimize state changes.

However, before you go in and make any large changes, make sure you are benchmarking a release build (this includes OpenTK) ran outside of the IDE. It is a good idea to try a profiler, too - you wouldn't want to optimize something that isn't a bottleneck!

Rich's picture

@the Fiddler: what you mean with your seconde statement (2.)? how can i sort everything by shader / texture? can you give me a tutorial, because i do not really understand what you mean with it!

ok thx for your advice... I'll give those display lists a try, and i hope that i'll get a huge performance boost :).
I also think i put the mushrooms and stuff into the lists because they will never change or vanish during game play.

But first i will run everything outside the IDE...

thx rich

the Fiddler's picture

If you keep a different texture per tile, you can improve performance a lot by drawing all grass tiles first, all water tiles next, etc.

Instead of this (pseudo-code):

for (int y = 0; y < map.Height; y++)
{
    for (int x = 0; x < map.Width; x++)
    {
        // Bind texture
        // Draw tile map[x, y]
    }
}

you can do this:

// When you load your map, sort the tiles by texture:
Dictionary<Texture, List<Point>> sorted_tiles = new Dictionary<Texture, List<Point>>();
for (int y = 0; y < map.Height; y++)
{
    for (int x = 0; x < map.Width; x++)
    {
        if (!sorted_tiles.Contains(map[x, y].Texture))
            sorted_tiles.Add(map[x, y].Texture, new List<Point>());
 
       sorted_tiles[map[x, y].Texture].Add(new Point(x, y));
    }
}
 
// In your draw function
foreach (var texture in sorted_tiles.Keys)
{
    // Bind texture, then
    foreach (var point in sorted_tiles[texture])
    {
        // Draw tile map[point.X, point.Y]
    }
}

This way you reduce the number of times you need to call GL.BindTexture, which can give a nice performance boost. How nice? Try commenting out your BindTexture calls and see if your fps improve.

Rich's picture

Hello there,

after a long break, i sorted the BindTexture calls and reduced them to a minimum. It turns out that the map now needs 0 milliseconds which is a huge improvement!
But still an annoying problem: the frame flickers black. With the old implementation the frame is constantly drawn without any flickering. Any suggestions? (I cannot remove the clear - colorbit call because my game does not cover the hole frame)

thx

the Fiddler's picture

This shouldn't happen. Are you, by any chance, drawing to the front buffer? (This is no longer supported in OpenGL).

As long as you don't call GL.DrawBuffer(DrawBufferMode.Front) and call SwapBuffers at the end of the RenderFrame event, there shouldn't be any flickering at all.

Rich's picture

This is my code: (I use VBOs)

//1 ms + no flickering
/*for (int i=0;i<600;i++)
{
	Textures.BindTexture(todraw[i]);
	GL.DrawArrays(BeginMode.Quads,i*4,4);
}*/
 
//0 ms + flickering
for (int i=0;i < 600;i++)
{
	if (todraw[i] != -1)
	{
		Textures.BindTexture(todraw[i]);
		int bound = todraw[i];
		for (int j=0;j < 600;j++)
		{
			if (bound == todraw[j])
			{	
				GL.DrawArrays(BeginMode.Quads,j*4,4);
				todraw[j] = -1;
			}
		}
	}
}
the Fiddler's picture

What does the flickering look like? Does the whole screen flash between black and color? Only the tiles? Can you capture it in a screenshot?

Rich's picture

Like this:

AttachmentSize
Bildschirmfoto.png238.47 KB
Rich's picture

Finally i found the error:

I do not update the mapdata every frame. So if i set the todraw[i] = -1; -> the nextframe do not do anything and just clears the map...

This works fine:

List<int> list = new List<int>();
foreach (int i in todraw)
{
	if (!list.Contains(i))
	list.Add(i);
}
 
foreach (int i in list)
{
	Textures.BindTexture(i);
	for (int j=0;j < 600;j++)
	{
		if (i == todraw[j])
		{	
			GL.DrawArrays(BeginMode.Quads,j*4,4);
		}
	}
}