我如何支持不同的OpenGL版本?

jos*_*efx 10 opengl

我有两个不同的系统,一个是OpenGL 1.4,一个是3.我的程序使用Shaders,它是OpenGL 3的一部分,仅在1.4实现中作为ARB扩展支持.

由于我无法在OpenGL 1.4中使用OpenGL 3功能,有没有一种方法可以支持两种OpenGL版本而无需编写两次相同的OpenGL代码(ARB/EXT和v3)?

Dam*_*mon 10

除非你真的因为某些原因需要支持10年历史的显卡,否则我强烈建议使用OpenGL 2.0而不是1.4(事实上,我甚至可以达到目标版本2.1).

由于使用"3.0中核心的着色器"必然意味着图形卡必须至少具有某种版本的GLSL,因此排除了任何无法提供至少OpenGL 2.0的硬件.这意味着,如果有人拥有OpenGL 1.4 并且可以运行着色器,那么他正在使用8-10岁的驱动程序.除此之外几乎没有什么可以获得(除了支持梦魇).

目标OpenGL 2.1是合理的,现在几乎没有任何系统不支持它(即使假设最小的OpenGL 3.2可能是一个完全合理的选择).

入门级OpenGL 3.3兼容卡的市场价格大约是两年前的高端OpenGL 1.4卡的1000倍,大约是25美元.如果您打算出售您的应用程序,您必须问自己,无法负担(或者不想负担)的人是否是您合理期望为您的软件付费的人.

话虽如此,同时支持OpenGL 2.x和OpenGL> 3.1是一场噩梦,因为阴影语言中有非平凡的变化,这些变化远远超出#define in varying并且会经常咬你.

因此,我个人选择永远不再使用实例化数组和着色器对象来定位低于3.2版的任何东西.这适用于可以合理预期具有运行现代应用程序的处理能力的所有硬件,并且它包括懒得将其驱动程序升级到3.3的用户,在单个代码路径中提供相同的功能.如果可用,OpenGL 4.x功能可作为扩展加载,这很好.
但是,当然,每个人都必须自己决定哪种鞋最合适.

够了我的等等,回到实际问题:
关于不复制扩展/核心的代码,在很多情况下你可以使用相同的名称,函数指针和常量.但是,请注意:作为一揽子声明,这是非法的,未定义的和危险的.
实际上,大多数(并非所有!)扩展都与相应的核心功能相同,并且工作方式相同.但是如何知道哪些可以使用,哪些会吃掉你的猫?查看gl.spec - 一个函数,其alias条目相同且与别名无法区分.您可以安全地互换使用它们.
有问题的扩展通常在某处也有解释性注释(例如"这不是PrimitiveRestartIndexNV的别名,因为它设置服务器而不是客户端状态."),但不依赖于这些,依赖于alias字段.


dat*_*olf 5

就像@Nicol Bolas已经告诉过你的那样,为OpenGL-3核心和OpenGL-2创建两个代码路径是不可避免的.OpenGL-3核心故意破坏兼容性.然而,赌注并不像看起来那么糟糕,因为大多数情况下代码只会在细微差别上有所不同,而且两个代码路径都可以写在单个源文件中并使用条件编译方法.

例如

#ifdef OPENGL3_CORE
    glVertexAttribPointer(Attribute::Index[Position], 3, GL_FLOAT, GL_FALSE, attribute.position.stride(), attribute.position.data());
    glVertexAttribPointer(Attribute::Index[Normal], 3, GL_FLOAT, GL_FALSE, attribute.position.stride(), attribute.position.data());

#else
    glVertexPointer(3, GL_FLOAT, attribute.position.stride(), attribute.position.data());
    glNormalPointer(GL_FLOAT, attribute.normal.stride(), attribute.normal.data());
#endif
Run Code Online (Sandbox Code Playgroud)

GLSL着色器可以类似地重复使用.使用宏来改变预定义但已被删除的标识符或引入更高版本关键字的例子

#ifdef USE_CORE
#define gl_Position position
#else
#define in varying
#define out varying
#define inout varying

vec4f gl_Position;
#endif
Run Code Online (Sandbox Code Playgroud)

通常,程序的着色器管理代码中将有一组标准头文件来构建最终源代码,然后传递给OpenGL,当然这取决于使用的代码路径.