语义OpenGL扩展支持

时间:2011-08-26 08:42:23

标签: c# opengl binding

目前我正在使用从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绑定的用户(目前没有人!所以,没有人会抱怨这个!:)。

1 个答案:

答案 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卡上工作。