语义 OpenGL 扩展支持

Posted

技术标签:

【中文标题】语义 OpenGL 扩展支持【英文标题】:Semantic OpenGL extension support 【发布时间】:2011-08-26 08:42:22 【问题描述】:

目前我正在使用从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.pglGenFramebuffersDelegates.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 在语义上是否等同于另一个例程 funcARBfuncEXT(具有相同的签名)?

我认为我唯一的选择是编写一个列出异常情况的外部文件(开发人员控制)(即两个具有相同名称和相同签名的例程在语义上不等效)。

最终目标应该是一个大部分折叠的 OpenGL 绑定包装库,以最大限度地减少管理 OpenGL 扩展所需的工作量。


经过一些实验……

可能同时实现了两个匹配的扩展(即 ARB_framebuffer_object 和 EXT_framebuffer_object)。由于入口点不同(不同的名称),我需要两个扩展的所有功能......但是!

如果我优先考虑支持的扩展(比如 ARB 的优先级高于 EXT,EXT 的优先级高于 VENDOR),我的问题中提出的实现对于包装框架是可以接受的,因为实现了 ARB 扩展,框架实现比 EXT 实现更喜欢它(不管是什么功能)。

这可行,但副作用是该策略被强制用于 OpenGL 绑定的用户(目前没有人!所以,没有人会抱怨这个!:))。

【问题讨论】:

【参考方案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 卡上工作。

【讨论】:

别名的好主意。遗憾的是“据说”(我想要规范的规范!)。但是,该框架带来了声明支持或不支持哪个扩展的结构;这些标志可用于更改语义,而无需每次调用​​不同的函数。 是的,它是一个比唯一的函数名更稳定的信息,但是存在别名之间函数签名不匹配的情况,因此需要仔细检查;稍后我会更深入地探讨这个问题。

以上是关于语义 OpenGL 扩展支持的主要内容,如果未能解决你的问题,请参考以下文章

Blender源码分析之OpenGL基本例子

Blender源码分析之OpenGL基本例子

检查是不是支持 DirectX 或 OpenGL

OpenGL 实践——在没有核心版本的情况下运行 OpenGL

需要带有 FBO 扩展的 OpenGL 2.0 或更高版本 - LibGDX 错误

OpenGL版本与OpenGL扩展机制