在我的OpenGL体验期间,我经常忘记设置一些状态。所以我认为状态机今天可能不是一个好的设计。但现在必须兼容。而且我也知道DirectX在早期也是一台状态机。我想知道为什么OpenGL和DirectX最初被设计为状态机?
答案 0 :(得分:24)
当人们提到“国家机器”时,人们的意思并不清楚,因为他们从不解释相反的情况。因此,我将在OpenGL“状态机”与当前D3D“非状态机”方面进行一般性和特别性的讨论。
OpenGL和Direct3D都使用全局状态。每个渲染命令都要求您设置一堆状态。
为了在两个API中呈现,您必须设置一堆全局状态。您必须设置要使用的着色器。您必须设置要使用这些制服的当前参数。如果你正在使用纹理,你需要设置它们。您需要设置当前视口参数。等等。
这种种“状态机”的原因很简单:这就是硬件通常的工作方式。
每个状态位代表GPU中的一些寄存器。那些寄存器是状态。需要加载着色器才能渲染。您需要设置视口寄存器。您需要设置正在使用的纹理寻址寄存器。等等。因此,API是状态机,因为 GPU 是状态机。
你可以想象这样做会由渲染命令完成。但是看看你需要传递多少个物体。您必须传递一组着色器,一组纹理,顶点数据,帧缓冲,视口设置,混合设置等。
相反,API让你做GPU所做的事情。你事先设置了所有这些东西。
另外,这会使API 更快。为什么?因为现在API知道你正在使用什么状态。如果你想渲染一个具有不同纹理的网格的不同部分,你可以保持帧缓冲,视口,顶点数据等都是一样的。你在它们之间唯一改变的是你使用的纹理。
如果您使用某种带有许多参数的巨型Draw调用,那么现在API必须查看每个参数以查看它是否与您上次的绘制调用相同。如果不是,则必须更新GPU寄存器。
现在,关于OpenGL和D3D之间的差异。在这种情况下,问题的不同之处在于它们如何对待对象。
D3D是基于对象的,因为修改对象的函数将对象作为参数。此外,大多数D3D对象是不可变的;创建它们后,您无法更改其大部分设置。一旦你创建了一定大小,格式等的纹理,它就完成了。如果不删除对象并创建新对象,则无法使用不同的大小/格式/等重新分配它。
OpenGL是基于状态的。这意味着修改对象的OpenGL函数(大多数情况下)不会将它们操作的对象作为参数。
这不仅仅是“设计”,而是简单的OpenGL严格遵守向后兼容性。 OpenGL中的对象只是全局状态的片段;这就是他们的定义方式。为什么呢?
因为最初,在OpenGL 1.0中,没有对象(除了显示列表)。是的,甚至不是纹理对象。当他们认为这是愚蠢的并且他们需要对象时,他们决定以向后兼容的方式实现它们。每个人都在使用在全球状态下运作的功能。所以他们只是说通过绑定一个对象,你覆盖了全局状态。那些用于改变全局状态的函数现在改变了对象的状态。
通过这种方式,他们可以将对象引入API,而不会引入一堆只能与对象一起使用的新函数。因此,以前工作的代码可以处理只有非常小的调整的对象,而不是强制重写代码。这也意味着如果他们需要引入可以在纹理上进行操作的新功能,那么它们可以在没有对象的情况下使用和。因此,它既可以向后兼容也可以。
Most OpenGL objects work this way:如果你想改变它们,你必须绑定它们,然后修改“全局”状态。
答案 1 :(得分:9)
来自http://www.cs.tufts.edu/research/graphics/resources/OpenGL/OpenGL.htm:
OpenGL像状态机一样运行的原因是为了避免在每次函数调用时都传递许多参数。
最小参数段落
应用程序和OpenGL之间的通信最终必须通过工作站数据总线传递到图形硬件。数据总线通常比工作站CPU和图形硬件慢得多,因此通常可能成为高速图形的瓶颈。为了保持尽可能高的速度,OpenGL在函数调用中尽可能少地传递参数,这可以通过查看OpenGL文档来看出。所有调用都假设许多内部变量先前已设置为您想要的值。