目前我正在使用从registry找到的Khronos .spec文件自动生成的C#OpenGL绑定。
我对装订质量非常满意;这是一个功能示例:
/// <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+")");
}
您可以注意到,固定块正在尝试调用两个不同的代理( Delegates.pglGenFramebuffers 和 Delegates.pglGenFramebuffersEXT )。
这是可能的,因为它们具有相同的签名:
[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;
委托具有相同的签名,因为规范(.spec文件)对于由差异扩展引入的两个例程是相同的。
以前,绑定仅支持核心,ARB和EXT扩展;绑定生成器只是避免定义那些例程,在这种情况下存在另一个具有更高优先级的等效例程。
为了增加扩展支持(由此SO question激发),我还要为那些已经提升为ARB或核心实现的例程声明委托和导入声明,并编写一个调用所有等效的包装器实现例程(已定义的例程)。
通过这种方式,我得到了上面声明的来源。
在处理2K +函数声明时会出现问题。我有一个绑定生成器,因为我无法编写所有的OpenGL绑定。
但是绑定生成器如何知道例程 func 在语义上是否等同于另一个例程 funcARB 或 funcEXT (具有相同的签名)?
我认为我唯一的选择就是编写一个外部文件(开发者控制),列出异常情况(即两个具有相同名称和相同签名的例程在语义上不相同)。
最终目标应该是一个主要是折叠的OpenGL绑定包装器库,以便最大限度地减少管理OpenGL扩展所需的工作量。
经过一些实验......
有可能实现两个匹配的扩展(即ARB_framebuffer_object和EXT_framebuffer_object)。由于入口点不同(不同的名称),我需要两个扩展的所有功能....但是!
如果我优先考虑支持的扩展(比如说ARB的优先级高于EXT,EXT比VENDOR更高),我的问题中提出的实现对于包装器框架是可以接受的,因为实现了ARB扩展,框架实现比EXT实现更喜欢它(无论什么功能)。
这样可行,但副作用是这个策略被强制用于OpenGL绑定的用户(目前没有人!所以,没有人会抱怨这个!:)。
答案 0 :(得分:1)
你将不得不做一些腿部工作,但这并不像你想象的那么糟糕。您需要在扩展级别工作,而不是在功能级别工作。
使用完全相同的功能将扩展程序提升为核心,或者不是。如果不是,那么用一个替换另一个是不合适的。所以你需要的是一个扩展列表,其中包括升级到核心的扩展。
例如,EXT_FBO 未提升为ARB_FBO / core而没有任何更改。有一些重大的变化,只是让一个使用EXT函数的应用程序使用ARB等价物而不做任何改变是错误的。
生成通过促销更改的扩展名列表并不容易。它需要通过实际的规范,看看从一个版本到另一个版本的实际变化。
一个积极的一点是,ARB最近习惯于制造所谓的“核心扩展”。这些是ARB扩展,完美地反映了核心行为,直到功能名称。因此ARB_FBO函数和枚举器没有“ARB”后缀。大多数新的ARB扩展都属于这一类。
作为替代方案,您可以使用gl.spec文件中的alias
字段。该字段据称表示该函数的替代版本。例如,如果你在gl.spec中查找“GenFramebuffersEXT”,你会发现它的alias
值为“GenFramebuffers”。别名似乎总是从扩展函数指向核心等价物。我完全不知道这些信息是最新的或准确的,但是你可以使用它。修改代码生成器以使用信息并查看从中获得的信息并不会太难。
从gl.spec的粗略检查中,似乎别名不符合我上面概述的规则。有一些别名(比如核心变换反馈的NV_transform_feedback)真的不是一个好主意。 NV_transform_feedback允许您在链接程序后设置反馈参数。虽然人们可能肯定想要这种功能,但核心不允许这样做。因此,如果你允许这些别名,一个人可能会意外地使用NVIDIA卡上的NV功能,突然他们的代码停止在非NVIDIA卡上工作。