Semantic OpenGL Extension Support

I am currently using the CG OpenGL binding automatically generated from Khrosos.spec files found in the registry .

I am quite satisfied with the quality of the bindings; here is an example function:

/// <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 see, the fixed block is trying to call two different delegates (Delegates.pglGenFramebuffers and Delegates.pglGenFramebuffersEXT).

This is possible because 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; 

Delegates have the same signature because the specification (.spec file) is the same for the two routines introduced by the difference extensions.


Previously, bindings supported only kernel extensions, ARB, and EXT; the binding generator simply avoids defining this procedure in case there is another equivalent with high priority.

In order to increase support for the extension (stimulated by this SO question ), I need to declare delegates and import the declaration also for the procedure that was promoted to ARB or to the kernel implementation and write a shell implementation that calls all equivalent procedures (those that are defined).

So I got the source declared above.


Problems arise when working with 2K + ads. I have a binding generator as I cannot write all OpenGL bindings.

But how can the binding generator know if the func subroutine is semantically equivalent to another funcARB or funcEXT subroutine (with the same signature)?

I think the only option I have is to write an external file (controlled by the developer) that lists the exception cases (i.e. two routines that have the same base name and the same signature, are not are semantically equivalent).

The ultimate goal should be basically a collapsible OpenGL wrapper library to minimize the effort required to manage OpenGL extensions.


After some experimentation ...

It is possible that both suitable extensions are implemented (i.e. ARB_framebuffer_object and EXT_framebuffer_object). Since the entry points are different (different names), I need all the functions of both extensions .... but!

If I give priority to supported extensions (let's say that ARB has a higher priority than EXT, EXT has a higher privilege than VENDOR), the implementation proposed in my question is acceptable for the shell framework, since the ARB extension is implemented, the infrastructure implementation is preferable, than an EXT implementation (no matter what functionality).

This will work, but a side effect is that this policy is forced to use the OpenGL binding (no one at the moment! So no one will complain about it! :)).

+1
source share
1 answer

You will have to do some work, but it is not as bad as you might think. Instead of working at the function level, you need to work at the extension level.

Either the extension was transferred to the kernel with exactly the same functionality, or it was not. If this is not so, then it is inappropriate to substitute one for the other. So, you need a list of extensions that advance along the kernel with modifications.

For example, EXT_FBO has not been translated to ARB_FBO / kernel unchanged. There were some significant changes, and it would be wrong to just use an application that uses the EXT functions, using the ARB equivalents without changes.

Creating a list of extensions changed through advertising is not easy. This will require going through the actual specifications and looking at what has actually changed from one version to another.

One of the positive things is that recently ARB has been in the habit of making so-called "core extensions". These are ARB extensions that perfectly reflect the behavior of the kernel, down to function names. Thus, the ARB_FBO functions and counters do not have the suffix "ARB". Most of the new ARB extensions fall into this category.

Alternatively, you can use the alias field in the gl.spec file. This field is supposedly an alternate version of the function. For example, if you look at "GenFramebuffersEXT" in gl.spec, you will find that it has an alias value for "GenFramebuffers". It seems that the alias always points to an extension function to the kernel equivalent. I absolutely do not understand how relevant or accurate this information is, but this is what you could use. It would not be too difficult to change the code generator to use this information and see what you choose.

From a quick gl.spec study, it seems that aliases do not follow the rules outlined above. There are some aliases (e.g. NV_transform_feedback for feedback on kernel conversion) that are actually not a good idea. NV_transform_feedback allows you to set feedback parameters after linking the program. And although, of course, it is possible that this functionality, the kernel does not allow this. Therefore, if you allow them an alias, a person may accidentally use the NV functions on the NVIDIA card, and suddenly their code stops working with cards other than NVIDIA.

+1
source

Source: https://habr.com/ru/post/894108/


All Articles