Vertex Array example
Posted Friday, 25 January, 2008 - 15:14 by Anonymous in
The Vertex array example (T02_Vertex_Arrays.cs) is missing the "Main" method in the example class file. I added it based one of the other examples, but the example does not display things.
Is this example in flux due to 0.9.1 development?
The reason I was looking at the Vertex array example is that while researching the share context issues I came accross several message boards indicating that OpenGL 3 will drop display lists from the spec and further indicated thet VA and VBO were both described as mechanisms to use in place of display lists.
djk




Comments
Jan 25
15:58:09This example was disabled on
posted by the FiddlerThis example was disabled on purpose because it suffers from a serious flaw: the vertex arrays are stored in managed memory and may be moved by the Garbage Collector. While this can be worked around (either by allocating unmanaged memory, or by pinning the objects in question), doing this will cause a performance hit.
Vertex Buffer Objects do not suffer from this problem, as they are stored in server memory. OpenGL 3 will not use client memory anyway, so VBO's are a safer bet.
Jan 25
16:15:33The vertex array shows up in
posted by AnonymousThe vertex array shows up in the example launcher under debug. I have been looking at the VBO example this morning.
Jan 25
16:24:00Just a small note that the
posted by the FiddlerJust a small note that the examples have grown a little stale (some major restructuring is underway for 0.9.2). Better check the VBO functionality in the GLSL example, as this is a little more up-to-date.
Jan 31
02:01:41Is it better to avoid arrays
posted by darxusIs it better to avoid arrays in sake of speed? I think that opengl superbible talks about this issue.
Feb 01
09:13:19Speedwise, from slowest to
posted by the FiddlerSpeedwise, from slowest to fastest:
While Display Lists can be faster than VBO's, they are only suitable for static geometry, which means VBO's are the best all-around solution. Both are (or can be) stored in video memory, so they are *very* fast to draw.
VA's on the other hand are stored in client memory, and have to travel through the AGP/PCI-E bus every time before rendering. Not only does this make them quite slow, but it also places the burden of memory management to the user (hence the problem with Garbage Collectors).
For general usage VBO's are the best solution.
Mar 08
23:59:42Re: Vertex Array example
posted by haymoSince I am rendering large mathematical objects and do not want to rely on large enough video memory, I'm still using vertex arrays. I came across the problem with index lists, which produce problems while switching to unmanaged context. However, by carefully designing the vertex array in stripes, one can most the time get around this issue. The way I figured out by now, does actually seems to be relatively ok. Thats why I'd like to share it here.
// populate vertex array to GL
GL.InterleavedArrays(OpenTK.OpenGL.Enums.InterleavedArrayFormat.C4fN3fV3f
,0,(IntPtr)pVertices);
// do some other stuff here, than
// DrawElements will be called in a loop.
// We give a pointer to the only index array existing,
// what will prevent from using index list array.
fixed (UInt32* pGridIndWalk = m_indices)
for ([number of stripes]) {
GL.DrawElements(OpenTK.OpenGL.Enums.BeginMode.Lines,
m_gridStripsLen,
OpenTK.OpenGL.Enums.DrawElementsType.UnsignedInt,
(IntPtr)(pGridIndWalk));
// increase the pointer to the next stripe
pGridIndWalk += m_gridStripsLen;
}
}
This will still be slower then using VBO, but may be useful for people needing to use indexed vertex arrays anyway.
Mar 09
07:52:14Re: Vertex Array example
posted by the FiddlerThanks, this should solve the problem (unless the driver decides to read the VA contents asynchronously).
One more thing to keep in mind is that the .Net GC will not move objects which are bigger than 80-90KB. Obviously this is not something to be relied on, as different versions of the runtime may have different limits, but it can affect behavior.
Mar 09
11:40:37Re: Vertex Array example
posted by Inertia.Net GC will not move objects which are bigger than 80-90KB.
Good to know! I couldn't find a variable to access this limit, is there any?
Mar 09
11:56:10Re: Vertex Array example
posted by the FiddlerThis is called the "large object heap".
I would be surprised if such a variable existed. This is an implementation detail (the specs don't dictate how to implement the GC), and I guess they want to be free to change it in the future. If they did provide this information, some programs would start depending on the exact limit and such a compatibility nightmare is the last they want :)
Mar 09
13:14:38Re: Vertex Array example
posted by InertiaFrom the link: ...implementation detail that could be changed in the future.
You are right, it would be nice though if this could be controlled. The ~83kb limit could also explain the VA related problems I had with PQ Torusknots in it's early stages (the Vertex[] had far less then 80kb back then), and why haymo's application does not require GL.Finish to run without random crashes at GL.Draw*
Mar 10
00:38:19Re: Vertex Array example
posted by haymo@Inertia: I hear "random crashes" and get the impression, I might have missed some mistake you have found? I dont think, it runs as smoothly as it does, just because of LOH (Is that, what you mean?) So if you see any potential danger, I would love to hear from it ! :)
Mar 10
00:57:00Re: Vertex Array example
posted by the FiddlerBoth Inertia and me have observed random crashes with unpinned arrays. The code sample above will work correctly as long as any of the following is true (ordered according to danger, with 1 being the least dangerous):
GL.DrawElementscalls finish within the fixed section.GL.DrawElementsspill outside the fixed section, but the GC does not touchm_verticesbecause it is placed in the LOH.GL.DrawElementsspill outside the fixed section,m_verticesare not in the LOH, but no GC happens whileGL.DrawElementsare executing.You can ensure that (1) will always happen, by placing a call to
GL.Finishjust before leaving the fixed statement, which will block until allGL.DrawElementscalls are complete. Without this, your graphics drivers will determine whether the calls will finish on the spot, or they will be queued up and executed later on. This is not something to be relied on - it may work ok on your system, but it may cause problems elsewhere.Now, if the
m_verticesarray is big enough, you may be able to get away with (2), without pinning and without callingGL.Finish. Obviously "big enough" is not something to be relied on either - it may change in future versions of .Net.If neither (1) or (2) apply, you start to tread into the dangerous waters of probabilistic programming and random crashes (i.e. "what are the chances it will work today?") :) Both Inertia and me fell into this trap on our first approach to VAs from .Net, and this is why we recommend taking care.
Just add a
GL.Finishto the code above and it will be 100% solid. There is a performance hit associated with this, but if the vertex arrays are very large (as they seem to be in this case), the hit won't be noticeable.Mar 11
10:43:49Re: Vertex Array example
posted by haymoAh, I see your point. I didn't know, the GL does process the vertices asynchronously. Are there any specs handling this topic? In the official OpenGL2.1 spec I found the following paragraph (chapter "Display Lists"):
When such a command is accumulated into the display list (that is, when
issued, not when executed), the client state in effect at that time applies to the command.
Only server state is affected when the command is executed. As always,
pointers which are passed as arguments to commands are dereferenced when the
command is issued. (Vertex array pointers are dereferenced when the commands
ArrayElement, DrawArrays, DrawElements, or DrawRangeElements are accumulated
into a display list.)
Thinking even a little longer about it, I wonder, if not all the other OpenTK delegates registering GCHandles (f.e. BufferData()) in order to send pointers to OpenGL also suffer from this issue? If the driver does not read the data immediately, the Handle will be disposed and the buffer might have moved away already?
Mar 11
11:03:00Re: Vertex Array example
posted by the FiddlerThis has been thoroughly discussed and tested in the past for both Tao.OpenGl and OpenTK. We haven't been able to reproduce a case where commands dealing with server-side may execute asynchronously and fail.
Makes sense, too. Imagine the following code in C:
{
float vertices[3 * number_of_vertices];
// Populate the array somehow - the details are not interesting.
glBufferData(..., (void*)vertices);
}
This is a fairly typical sample. The "vertices" array is allocated on the stack and will be deleted as soon as the function returns. Were glBufferData to execute asynchronously, this code would fail. But in practice this doesn't happen: BufferData copies the array internally and the driver handles the rest.
Vertex Arrays behave differently however, as the user is responsible for the buffer (client-side storage). Since you are expected to keep the pointer intact, VAs are free to execute asynchronously if the driver so chooses, and this certainly happens in display lists. :)
Mar 15
21:21:40Re: Vertex Array example
posted by haymoThanks for that excellent explanation :) !
May 07
19:32:15Re: Vertex Array example
posted by docflabbySomething thats works for me, that I thought I would share. Basically you can pin memory without going "unsafe" (.net 2.0)
1.0f, 0.0f, 0.0f,
-1.0f, -0.5f, -4.0f,
0.0f, 1.0f, 0.0f,
1.0f, -0.5f, -4.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.5f, -4.0f}
void load()
{
handle = GCHandle.Alloc(vertexArray, GCHandleType.Pinned);
}
void render()
{
GL.EnableClientState(EnableCap.VertexArray);
GL.InterleavedArrays(InterleavedArrayFormat.C3fV3f, 0, handle.AddrOfPinnedObject());
GL.DrawArrays(BeginMode.Triangles, 0, vertexArray.Length / 6);
GL.DisableClientState(EnableCap.VertexArray);
}
void unload()
{
handle.Free();
}
May 07
19:57:03Re: Vertex Array example
posted by the FiddlerYes, this works as long as you keep the pin intact.
Doing so, however, can be quite detrimental to performance and memory consumption (i.e. an object pinned at heap location 1000000 will ensure that 1000000 bytes will be always consumed - even if the object itself is smaller).
Also, pinning this way moves memory management back to you (taking care of resource allocation/deallocations, potential memory leaks, exception handling etc) - it hurts productivity.
Last, every call to GCHandle.Alloc, allocates memory and is quite slow in itself (about 200ns).
I'd really suggest avoiding this idiom whenever possible - but to each his own :-)
(OpenTK itself uses this quite extensively for OpenGL functions that take
objectparameters).May 07
20:05:42Re: Vertex Array example
posted by docflabbyI agree, its going to be a performance killer. I'm planning on doing the sensible thing and using VBOs :) I just noticed no one had posted up a stable managed solution to get vertex arrays to work. I couldn't get the unsafe/fixed code posted earlier to work, so thought I would post this.
May 07
20:25:41Re: Vertex Array example
posted by the FiddlerYep, this is the way to go if you want Vertex Arrays. Just wanted to discourage potential users from using this model on managed code (there are way too many tutorials on vertex arrays out there, and the potential pitfalls aren't readily visible).