我应该多久调用一次和/ glEnable()或glEnableClientState()相应的OpenGL函数glDisable?它们是否应该在应用程序开始时调用一次,还是应该禁用它们并且仅启用我立即需要绘制某些内容的那些功能?有性能差异吗?
Mar*_*arc 15
如果你发现你经常检查状态变量的值,然后调用glEnable/glDisable您可以通过使用属性堆栈(glPushAttrib/glPopAttrib)清理了一点东西.
属性堆栈允许您隔离代码区域,以便在一个部分中对属性的更改不会影响其他部分中的属性状态.
void drawObject1(){
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
/* Isolated Region 1 */
glPopAttrib();
}
void drawObject2(){
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_FOG);
glEnable(GL_GL_POINT_SMOOTH);
/* Isolated Region 2 */
glPopAttrib();
}
void drawScene(){
drawObject1();
drawObject2();
}
Run Code Online (Sandbox Code Playgroud)
虽然GL_LIGHTING和GL_DEPTH_TEST在drawObject1设置他们的状态不会保留到drawObject2.在没有glPushAttrib的情况下,情况并非如此.另外 - 请注意,在函数调用结束时无需调用glDisable,glPopAttrib可以完成这项工作.
就性能而言,单个函数调用glEnable/glDisable所产生的开销很小.如果你需要处理许多状态,你可能需要创建自己的状态管理器或对glGetInteger进行多次调用......然后相应地采取行动.增加的机械和控制流程可能使代码更不透明,更难调试,更难以维护.这些问题可能会使其他更有成效的优化变得更加困难.
归因堆栈可以帮助维护抽象层并创建隔离区域.
unw*_*ind 12
"那要看".
如果您的整个应用程序仅使用启用/禁用状态的一种组合,那么无论如何只需在开头设置它就可以了.
大多数真实世界的应用程序需要混合,然后你被迫调用glEnable()以启用某些特定状态,进行绘制调用,然后glDisable()当你完成"清除阶段"时再次调用它们.
状态排序,状态跟踪和许多优化方案源于此,因为状态切换有时很昂贵.
小智 8
首先,您使用哪个OpenGL版本?您的目标群体拥有哪一代图形硬件?了解这一点可以更容易地给出更正确的答案.我的回答是假设OpenGL 2.1.
OpenGL是一个状态机,意味着每当状态发生变化时,该状态就会变为"当前",直到程序员使用新的OpenGL API调用再次明确地更改状态.存在此规则的例外情况,例如客户端状态数组调用使当前顶点颜色未定义.但这些是定义规则的例外.
" 一旦在应用程序的开头 "没有多大意义,因为有时你需要在应用程序仍在运行时销毁你的OpenGL上下文.我假设你的意思是在每个窗口创建之后.这适用于您不需要稍后更改的状态.示例:如果所有绘制调用都使用相同的顶点数组数据,则不需要在之后使用glDisableClientState禁用它们.
有许多与旧的固定功能管道相关的启用/禁用状态.对此的轻松兑换是:使用着色器!如果您定位的是最近五年的一代卡片,那么无论如何它都可能模仿着色器的固定功能管道.通过使用着色器,您可以或多或少地完全控制在变换和光栅化阶段发生的事情,并且您可以使用制服制作自己的"状态",这些制服的更改/更新非常便宜.
知道OpenGL就像我上面所说的状态机一样,应该清楚地表明,只要有可能,就应该努力将状态变化保持在最低限度.但是,最有可能的其他因素会影响性能,而不仅仅是启用/禁用状态调用.如果您想了解它们,请阅读.
国家出资不与旧的固定功能状态呼叫相关的,并且不是简单的启用/禁用状态可在成本相差很大.值得注意的是,链接着色器和绑定名称(纹理,程序,缓冲区对象的"名称")通常相当昂贵.这就是为什么许多游戏和应用程序用于根据纹理对其网格的绘制顺序进行排序的原因.这样,他们就不必两次绑定相同的纹理.然而,现在,这同样适用于着色器程序.如果不必要,您不希望将相同的着色器程序绑定两次.此外,并非特定OpenGL版本中的所有功能都是在所有卡上加速硬件,即使这些卡的供应商声称它们符合OpenGL标准.合规意味着他们遵循规范,而不是他们必须有效地运行所有的功能.在这方面应该记住GL_ ARB __imaging中的一些函数,如glHistogram和glMinMax.
结论:除非有明显的理由不使用着色器!它可以帮助您避免许多不必要的状态调用,因为您可以使用制服.你知道,OpenGL着色器已经存在了大约六年.此外,启用/禁用状态更改的开销可能是一个问题,但通常还可以从优化其他更昂贵的状态更改中获得更多,例如glUseProgram,glCompileShader,glLinkprogram,glBindBuffer和glBindTexture.
PS:OpenGL 3.0删除了客户端状态启用/禁用调用.它们是隐式启用的,因为绘制数组是在此版本中绘制的唯一方法.立即模式已被删除.gl..Pointer调用也被删除了,因为一个人真的只需要glVertexAttribPointer.