Currently I'm using a C# OpenGL binding automatically generated from the Khronos .spec files found at the registry.
I'm quite satisfied by the bindings quality; here is a function example:
/// <summary>
/// Binding for glGenFramebuffers function.
/// </summary>
/// <remarks>
/// This function belongs to 'ARB_framebuffer_object'.
/// <para>
/// Depending on driver implementation, this routine could call the following (equivalent) routines:
/// - glGenFramebuffers
/// - glGenFramebuffersEXT
/// </para>
/// </remarks>
/// <param name="n">
/// A <see cref="Int32"/>.
/// </param>
/// <param name="framebuffers">
/// A <see cref="UInt32*"/>.
/// This parameter holds data returned from function.
/// </param>
public static void GenFramebuffer(Int32 n, [Out] UInt32[] framebuffers) {
unsafe {
fixed (UInt32* fp_framebuffers = framebuffers)
{
if (Delegates.pglGenFramebuffers != null)
Delegates.pglGenFramebuffers(n, fp_framebuffers);
else if (Delegates.pglGenFramebuffersEXT != null)
Delegates.pglGenFramebuffersEXT(n, fp_framebuffers);
else
throw new InvalidOperationException("binding point GenFramebuffer cannot be found");
}
}
LogProc("glGenFramebuffers("+n+", "+framebuffers+")");
}
As you can notice, the fixed block is trying to call two different delegates (Delegates.pglGenFramebuffers and Delegates.pglGenFramebuffersEXT).
This is possible since they have the same signature:
[System.Security.SuppressUnmanagedCodeSecurity()]
internal unsafe delegate void glGenFramebuffers(Int32 n, [Out] UInt32* framebuffers);
internal static glGenFramebuffers pglGenFramebuffers = null;
[System.Security.SuppressUnmanagedCodeSecurity()]
internal unsafe delegate void glGenFramebuffersEXT(Int32 n, [Out] UInt32* framebuffers);
internal static glGenFramebuffersEXT pglGenFramebuffersEXT = null;
The delegates have the same signature because the specification (.spec file) is the same for the two routines, introduced by difference extensions.
Previously, the bindings has support only for core, ARB and EXT extentions; the bindings generator simply avoid definition of those routine in the case exists another equivalent one with greater priority.
To increase extension support (stimulated by this SO question), I require to declare delegates and imports declaration also for those routine which have been promoted to ARB or to core implementation, and write a wrapper implementation which calls all equivalent routines (those which are defined).
In this way I got the source declared above.
The problems starts when dealing with 2K+ function declarations. I have a bindings generator since I can't write all the OpenGL bindings.
But how the binding generator can know whether a routine func is semantically equivalent to another routine funcARB or funcEXT (having the same signature)?
I think the only option I have is to write an external file (developer controlled) which lists the exception cases (i.e. two routines having the base same name and same signature are not semantically equivalent).
The final goal should be a mostly collapsed OpenGL binding wrapper library, in order to minize the effort required for managing OpenGL extensions.
After some experiments...
It is possible that two matching extensions are both implemented (i.e. ARB_framebuffer_object and EXT_framebuffer_object). Since entry points are different (different names), I need available all the functions of the both extensions.... but!
If I give a priority to the supported extensions (say ARB have higher priority than EXT, EXT have higher proprity than VENDOR), an implementation proposed in my question is acceptable for a wrapper framework, because the ARB extension is implemented, the framework implementation would prefer it than the EXT implementation (no matter what functionality).
This would work, but the side effect is that this policy is forced to the users of the OpenGL binding (no one, at the moment! So, nobody will complain with this! :) ).