是否有一个著名的 C++ 包装器使用 C++11 设施来支持 OpenGL?如果不,
不,已经有一些尝试了。
这样的事情是由任何知名人士(尤其是 Khronos)策划的吗?
Khronos ARB 并没有真正尝试直接与我们交流即将发生的事情。但是,我非常怀疑他们是否关心这种事情。
至于其他人,同样,那里有一些独立的项目。但一般来说,使用 OpenGL 的人对做这类事情并没有那么感兴趣。
基本事实如下: OpenGL 对象直接与一些全局概念相关联。即,OpenGL 上下文。这些对象只有在它们所在的上下文(因为对象可以在上下文之间共享)处于活动状态时才能被操作。
因此,任何 C++ 面向对象的系统都必须决定它想要的容错程度。也就是说,它想提供什么样的保证。如果你调用一个对一个对象进行操作的函数,你能确定这个调用成功吗?
以下是可以合理提供的保证级别列表:
完全肛门
在这种情况下,您可以确保每个函数调用要么成功,要么正确检测到错误条件并正确失败。
为了实现这一点,您需要一个显式的OpenGL 上下文对象。每个 OpenGL 对象都必须与上下文(或特定上下文本身,如果对象类型不可共享)之间的共享组相关联。
所有对象成员函数都必须采用上下文对象,该对象必须是它们所属的上下文或该上下文的共享组的成员。必须有一个上下文的每个线程缓存,以便他们可以检查当前上下文是否是给定的上下文,如果不是,则使其成为当前上下文。
当一个上下文被销毁时,依赖于该上下文存在的每个对象都必须立即失去功能。因此,每个这样的对象都需要访问某个标签(例如通过 a std::weak_ptr
),让他们知道他们所有的函数调用都会失败。
如果要对对象进行适当的 RAII,则每个对象都必须能够确保它们可以在其中销毁的上下文(即:glDelete*
函数)是当前的。如果不是,他们需要制作一个电流。所以基本上,每个对象都需要持有对有效上下文的引用,否则需要能够创建一个。
就个人而言,我觉得这一切都非常愚蠢。没有 API 具有这种容错能力,也不需要如此。有很多毫无意义的保姆和信息共享。C++ 不是一种安全语言,因此它不应该仅仅为了提供这种安全级别而浪费良好的内存和/或性能。
萨内
在这里,我们摆脱了基于上下文的安全检查。在尝试以任何方式使用任何对象之前,用户应确保正确的上下文是最新的。这与 C++ 一样。这个 API 的主要特点就是比原始的 C API 更好。
OpenGL 对象将是 RAII 样式,但它们也将具有“处理”函数,如果您希望它们清除自身而不删除其相应对象,则可以调用该函数。如果您要关闭上下文并且不想运行并破坏所有对象,这很有用。
该系统基本上会假设您想要这些类的纯直接状态访问。因此,没有一个修改成员函数实际上将对象绑定到上下文。他们可以通过以下几种方式之一来实现:
- 使用 EXT_DSA 或等效的(如果有)。
- 如果 EXT_DSA 或等效项不可用,则存储修改后的状态并在下次绑定此对象时发送修改。
- 或者只是绑定它,进行修改,然后取消绑定。
某些类型的修改不能使用#2。例如glBufferData
,glBufferSubData
和glTexSubImage*D
调用。用户真的希望它们现在发生。这些函数的命名方式应使它们与保证的非绑定函数区分开来。
任何此类绑定函数都不应努力恢复对象的先前绑定状态。
宽容的
基本上,C++ 成员函数和 C 函数之间存在 1:1 的对应关系。当然,您将使用 C++ 运算符重载等来减少不必要的函数变化。但归根结底,您几乎是在以编写 C 代码的方式编写 C++ 代码。
对象可能会使用 RAII,但除此之外它们不会提供任何真正的便利。成员函数要么绑定对象本身,要么期望你绑定它们。或者,如果 DSA 不可用,他们将使用 DSA 并失败。
何苦?
归根结底,从 C++ 接口到 OpenGL 并没有什么好处。当然,你会得到 RAII。好吧,您可以通过使用std::unique_ptr
带有特殊删除器函子的 a 来获得 RAII(是的,真的,这是非常可能的)。但除了 API 带来的一些轻微便利之外,您还获得了哪些以前没有的真正表达能力?
如果您对使用 OpenGL 开发应用程序很认真,那么您可能会构建一个渲染系统,相对于您的其余代码,它将 OpenGL 的概念抽象出来。因此,除了您的渲染器之外,没有人会看到您花哨的 C++ 界面。您的渲染器也可以轻松使用 OpenGL 的 C API。如果它几乎没有给您带来任何好处,为什么还要从抽象中构建您的渲染器。
如果你只是在玩 OpenGL……那有什么关系呢?只需使用您拥有的界面即可。