Skip to content

GL \ Common mistakes

Luca Piccioni edited this page Jan 31, 2018 · 3 revisions

Keep an eye on overloads: glOrtho and glOrthof

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:

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.

Out parameters of String type

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();

Pointer arguments

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.

String parameters copied only by reference

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.