Skip to content

Performance considerations when calling OpenGL Extension Functions

Matthias Mailänder edited this page May 9, 2015 · 2 revisions

Static Invocation over dynamic Invocation

In version 2.4 we changed the way how SharpGL calls OpenGL extension functions. Thanks to @ftlPhysicsGuy for giving the feedback on this topic in issue #41!

The old way

The wglGetProcAddress function (MSDN Reference) was used to find a particular OpenGL extension function. The next step was to create a delegate to call the extension function by using Marshal.GetDelegateForFunctionPointer (MSDN Reference). This method converts an unmanaged function pointer to a delegate. The method Delegate.DynamicInvoke (MSDN Reference) was used to call the OpenGL extension function finally.

The Problem

The problem comes with the Delegate.DynamicInvoke method. This method calls the function dynamically, that means late-bound and involves reflection. This leads to an overhead that decreases performance.

The new way

Instead of using the Delegate.DynamicInvoke, we simply create the delegate for the OpenGL extension function and invoke the delegate statically. Here is the code to create the delegate:

private T GetDelegateFor<T>() where T : class
{
	//  Get the type of the extension function.
	Type delegateType = typeof(T);

	//  Get the name of the extension function.
	string name = delegateType.Name;

	// ftlPhysicsGuy - Better way
	Delegate del = null;
	if (extensionFunctions.TryGetValue(name, out del) == false)
	{
		IntPtr proc = Win32.wglGetProcAddress(name);
		if (proc == IntPtr.Zero)
			throw new Exception("Extension function " + name + " not supported");

		//  Get the delegate for the function pointer.
		del = Marshal.GetDelegateForFunctionPointer(proc, delegateType);

		//  Add to the dictionary.
		extensionFunctions.Add(name, del);
	}

	return del as T;
}

And so SharpGL invokes the delegate now:

// NOTE: JUST ONE EXAMPLE. MANY METHODS IN OpenGLExtensions.cs USE THIS PATTERN
public void BlendColor(float red, float green, float blue, float alpha)
{
	//InvokeExtensionFunction<glBlendColor>(red, green, blue, alpha);
	GetDelegateFor<glBlendColor>()(red, green, blue, alpha);
}

Results

By changing the function invocation process, we were able to increase the performance by 30%.