是否有任何计划或现有项目将OpenGL API移植到C++

Are there any plans or existing projects to port OpenGL API to C++?

本文关键字:API C++ OpenGL 项目 计划 任何 是否      更新时间:2023-10-16

OpenGL标准页面规定OpenGL可从C和C++调用。然而,API当然是纯C。例如,由于OpenGL使用了大量枚举,因此使用enum-classes(来自C++11)可以大大减少错误数量,并使API对初学者更可行。可以看出,创建了许多像OpenTK(针对C#)这样的绑定;创建一个好的C++API并不难。

我找不到任何东西,只是一个晦涩的包装,因此我提出了问题:

  1. 是否有一个著名的C++包装器使用OpenGL的C++11工具?如果不是
  2. 像这样的事情是由知名人士策划的吗

OpenGL的整个工作方式并不能很好地映射到OOP:http://www.opengl.org/wiki/Common_Mistakes#The_Object_Oriented_Language_Problem

本文中没有说明的是上下文亲和性问题。在OpenGL中,所有的事情都发生在上下文中,所以一个类"Texture",正确地说,只不过是一个与上下文一起使用的光荣句柄。

这是错误

class Texture {
/* ... */
public:
void bind();
}

只有当纹理是当前活动上下文的一部分时,它才会起作用。

这也不好:

class Texture {
/* ... */
public:
void bind(Context &ctx);
}

纹理仍然必须是上下文ctx的一部分,并且只有当ctx此时处于活动状态时,它才会起作用。

那么这个呢:

class Context {
/* ... */
public:
void bindTextureToUnit(TextureUnit &tu, Texture &t);
};

更好,但仍然不正确,因为上下文必须是当前线程中当前活动的上下文。您可能会想"哦,如果上下文不活动,我就抛出一个异常"。请不要这样做。

那么这个呢

class ActiveContext : Context {
/* ... */
public:
void bindTextureToUnit(TextureUnit &tu, Texture &t);
}

现在,您已经确保每个线程只能有一个ActiveContext实例。这会让你陷入各种奇怪的线程单例混乱。

事实上,我曾多次尝试实现从OpenGL状态和对象到一组C++类的干净、合理的映射,但总有一些情况下,它根本不起作用,或者最终陷入可怕的代码混乱。

IMHO最好不要尝试将OpenGL API映射到一组C++类中(这不能很好地完成),而是使用专门类中的常规OpenGL API。任何OpenGL上下文管理都依赖于所讨论的程序,因此必须专门针对所述程序进行定制。

封装OpenGL和OpenGL对象模型是两个不同的概念。OpenGL实体可以很容易地被制作成对象来包装它们的功能,事实上,如果你想编写一个可以用OpenGL或D3D实例化的渲染器,这是非常必要的。

我有这样的课程:

class Device
class State
class Buffer
class BufferUniform
class BufferVertices
class BufferIndices
class BufferArray
class Texture
class Texture1d
class Texture2d
class Texture3d
class TextureCubeMap
class TextureArray
class TextureRender
class TextureFrame          
class Shader
class ShaderPixel
class ShaderVertex
class ShaderGeometry
class ShaderEvaluator
class ShaderTessellator
class ShaderProgram
class ShaderGenerator
class ShaderGeneratorParser
class ShaderGeneratorNode
class ShaderGeneratorCondition

以及各自的D3D或OpenGL版本。渲染器<…>在编译时用一个或另一个集合实例化,这取决于我是想要D3D还是OpenGL来完成这项工作。

是否有一个众所周知的C++包装器使用OpenGL的C++11工具?如果没有,

否。已经有一些尝试了。

这样的事情是由任何知名人士策划的吗?

Khronos ARB并没有真正尝试直接与我们沟通即将推出的产品。然而,我非常怀疑他们是否关心这类事情。

至于其他人,同样,也有一些独立的项目。但一般来说,使用OpenGL的人对做这类事情不太感兴趣。

基本事实是:OpenGL对象与一些全局概念直接相关。即OpenGL上下文。只有当这些对象所在的上下文(因为对象可以在上下文之间共享)处于活动状态时,才能对其进行操作。

因此,任何C++面向对象系统都必须决定其容错程度,也就是说,它希望提供什么样的保证。如果您调用一个对对象进行操作的函数,那么您对该调用成功的把握有多大?

以下是可以合理提供的保证级别列表:

完全分析

在这种情况下,您可以确保每个函数调用都成功或正确地检测到错误条件并正确地失败。

为了实现这一点,您需要一个显式OpenGL上下文对象。每个OpenGL对象都必须与上下文之间的共享组相关联(如果对象类型不可共享,则必须与特定上下文本身相关联)。

所有对象成员函数都必须采用上下文对象,该对象必须是它们所属的上下文或该上下文的共享组的成员。必须有上下文的每线程缓存,这样他们才能检查当前上下文是否是给定的上下文,如果不是,则使其成为当前上下文。

当一个上下文被破坏时,依赖于该上下文存在的每个对象都必须立即变得不起作用。因此,每个这样的对象都需要访问某个标记(例如通过std::weak_ptr),让它们知道所有的函数调用都将失败。

如果对象要正确地RAII'd,那么每个对象都必须能够确保它们可以在其中销毁的上下文(即:glDelete*函数)是最新的。如果不是,他们需要使成为一个电流。因此,基本上,每个对象都需要持有对有效上下文的引用,或者需要能够创建一个引用。

就我个人而言,我觉得这一切都很愚蠢。没有API是这种容错的,也不需要。有很多毫无意义的保姆和信息共享。C++不是一种安全的语言,因此它不应该仅仅为了提供这种级别的安全性而浪费良好的内存和/或性能。

Sane

在这里,我们取消了基于上下文的安全检查。用户在尝试以任何方式使用任何对象之前,应确保正确的上下文是最新的。C++也是如此。这个API的主要特性就是比原始的C API好。

OpenGL对象将是RAII样式,但它们也有一个"dispose"函数,如果您希望它们在不删除相应对象的情况下清除自身,则可以调用该函数。如果您正在关闭一个上下文,并且不想遍历和销毁所有对象,这将非常有用。

这个系统基本上假设您想要这些类的纯直接状态访问。因此,没有一个修改成员函数实际将对象绑定到上下文。他们可以通过以下几种方式之一实现这一点:

  1. 使用EXT_DSA或同等产品(如有)
  2. 如果EXT_DSA或等效程序不可用,则存储修改后的状态,并在下次绑定此对象时发送修改
  3. 或者只是绑定它,进行修改,然后解除绑定

某些类型的修改不能使用#2。例如,glBufferDataglBufferSubDataglTexSubImage*D调用。用户真的希望它们现在就发生。这些函数的命名方式应使其与保证的非绑定函数区分开来。

任何这样的绑定函数都不应试图恢复对象以前的绑定状态。

许可

基本上,C++成员函数和C函数之间存在1:1的对应关系。当然,您将使用C++运算符重载等来减少不必要的函数变化。但归根结底,你几乎是在像写C代码一样写C++代码。

对象可能会使用RAII,但除此之外,它们不会提供任何真正的便利。成员函数将绑定对象本身,或者希望您已经绑定了它们。或者,如果DSA不可用,他们将使用DSA并失败。

为什么要麻烦

归根结底,拥有OpenGL的C++接口对来说并没有什么好处。当然,你有RAII。好吧,您可以通过使用带有特殊deleter函子的std::unique_ptr来获得RAII(是的,真的,这是非常可能的)。但是,除了API的一些轻微便利之外,您还获得了以前没有的真正的表达能力

如果你真的想使用OpenGL来开发应用程序,那么你可能会构建一个渲染系统,相对于代码的其余部分,它可以抽象OpenGL的概念。因此,除了你的渲染器之外,没有人会看到你花哨的C++接口。您的渲染器也可以很容易地使用OpenGL的C API。如果你的渲染器什么都不买,为什么要用抽象来构建它呢。

如果你只是在玩OpenGL。。。这有什么关系?只需使用您的界面即可。