-
Notifications
You must be signed in to change notification settings - Fork 111
GL \ Common mistakes
There are some OpenGL command that have similar names, and because the suffix removal they seems a simple overload utility: they are not!
Take as example the two functions:
The corresponding OpenGL.Net methods are:
-
Gl.Ortho(double, ..., double) for
glOrtho
-
Gl.Ortho(float, ..., float) for
glOrthof
They seems the same function, but the former is specified by the OpenGL 1.0 specification and the latter is specified by OpenGL ES 1.0 specification (that is another different implementation). Probably the latter will be not found on your system, causing a NullReferenceException
.
Certain methods returns back a string
, but you can notice that the underlying OpenGL.Net method accept a StringBuilder
parameter. For example:
void GetActiveAttrib(UInt32 program, UInt32 index, Int32 bufSize, out Int32 length, out Int32 size, out Int32 type, [Out] StringBuilder name)
In this case, you must allocate a StringBuilder
big enough to hold the data returned. In this case, the correct way to code GetActiveAttrib
is
int attributeBufferSize;
// Get inputs maximum length for name
Gl.GetProgram(obj, Gl.ACTIVE_ATTRIBUTE_MAX_LENGTH, out attributeBufferSize);
// Allocate the StringBuilder
StringBuilder nameBuffer = new StringBuilder(attributeBufferSize);
// Some version of Mono has strange StringBuilder implementation
nameBuffer.EnsureCapacity(attributeBufferSize);
// Obtain active input informations
Gl.GetActiveAttrib(obj, i, attributeBufferSize, out nameLength, out size, out type, nameBuffer);
// Obtain active input location
string name = nameBuffer.ToString();
If a method accept a pointer argument, there is the risk that the actual method implementation store the pointer temporarily to use it later. This may cause a memory access problem, since the GC collector is free to move the managed objects memory.
The solution is pin the memory of the managed object (informing the GC) till is necessary for the driver. An example is found the Examples directory.
using (MemoryLock vertexArrayLock = new MemoryLock(_ArrayPosition))
{
Gl.VertexPointer(2, VertexPointerType.Float, 0, vertexArrayLock.Address);
Gl.EnableClientState(EnableCap.VertexArray);
Gl.DrawArrays(PrimitiveType.Triangles, 0, 3);
}
The MemoryLock
is an IDisposable
utility class that pins the memory passed to the constructor.
AFAIK the GL functions affected by the GC are only the ones that modify the GL client state (such as glVertexPointer
). For modern GL versions, this issue does not exist because it has no more client memory management.
I had problems in setting the transform varyings on a shader. Attributes names reach the shader state in a damaged state, just like the memory was reused. Investigating on it I've understood that the OpenGL call stores of the string argument pointer instead of copying the string.
This caused the problem; I've resolved it by allocating manually the string arguments of Gl.TransformFeedbackVaryings
, till the program linkage.
if (Gl.CurrentExtensions.TransformFeedback2_ARB || Gl.CurrentExtensions.TransformFeedback_EXT) {
string[] feedbackVaryings = _FeedbackVaryings.ToArray();
// Bug in NVIDIA drivers? Not exactly, but the NVIDIA driver hold the 'feedbackVaryings' pointer until
// glLinkProgram is executed, causing linker errors like 'duplicate varying names are not allowed' or garbaging
// part of the returned strings via glGetTransformFeedbackVarying
feedbackVaryingsPtrs = feedbackVaryings.AllocHGlobal();
// Specify feedback varyings
Gl.TransformFeedbackVaryings(ObjectName, feedbackVaryingsPtrs, (int)cctx.FeedbackVaryingsFormat);
}
The magic is performed in AllocHGlobal
:
public static IntPtr[] AllocHGlobal(this String[] array)
{
IntPtr[] unmanagedArray = new IntPtr[array.Length];
for (int i = 0; i < array.Length; i++)
unmanagedArray[i] = Marshal.StringToHGlobalAnsi(array[i]);
return (unmanagedArray);
}
Probably in un-managed languages the problem is minimized because the string array is statically initialized or scoped on the stack of the method calling glLinkProgram
.