OpenGL的直接状态访问机制的优点是什么?


11

我一直在opengl.org上阅读有关OpenGL 4.5直接状态访问(DSA)的信息,但不确定是否正确。

似乎暗示着,旧方法的效率较低:

glBind(something)
glSetA(..)
glSetB(..)
glSetC(..)

比新方法:

glSetA(something, ..)
glSetB(something, ..)
glSetC(something, ..)

从外观上看,每个组件glSet都必须包含glBind(something)在其中,并且如果OpenGL仍然是状态机,则无法利用应用于单个对象的流式更改something

请说明新DSA的原因和优势。

Answers:


21

从外观上来看,每个glSet都必须在其中包含glBind(something)

不完全是。正如下面几段所述,这是另一种方式。

即使是事实,请记住,与常规函数调用相比,从客户端应用程序到GL服务器(又称为驱动程序)的GL命令具有大量的调度开销。即使我们假设DSA函数只是现有函数的包装器,它们还是位于GL服务器内部的包装器,因此可以(少)减少开销。

如果OpenGL仍然是状态机,则无法利用流式处理应用于单个对象的更改。

GPU不是状态机。GL状态机接口是一种模拟,它包装了类似DSA的驱动程序内部组件,而不是相反。

清除一层包装(即需要大量调用GL服务器的一层)显然是一个胜利,即使只有很小的一层。

在处理多个线程时,状态机方法也没有多大意义。在这种用例中,GL仍然很糟糕,但是驱动程序经常在后台使用线程,并且状态机需要大量线程同步或真正花哨的并行算法/构造才能使事情可靠地工作。

DSA扩展继续以状态更改来表达其操作,因为毕竟它是对现有基于状态的文档的扩展,而不是全新的API,因此必须准备好插入现有GL规范文档的语言和术语。即使该现有语言非常适合作为现代图形硬件API的工作。

请说明新DSA的原因和优势。

最大的理由是,旧方法很痛苦。很难将可能会各自修改或依赖GL状态的库组合在一起。由于其深深的过程状态管理根源,难以以面向对象或功能形式有效包装GL API,这使得以各种非C语言包装API变得困难,也使得提供高效的图形设备包装程序变得困难从Direct3D抽象OpenGL。

第二是程序状态机API开销,如前所述。

第三,DSA函数从旧的API适当地更改了语义,从而提高了效率。例如,以前可变的东西变成不可变的,这从GL服务器中删除了很多记帐代码。当GL服务器不必处理可变对象时,可以将应用程序的调用分派到硬件或更快(或以更多并行方式)进行验证。

-

EXT_direct_state_access扩展规范中提供了其他理由和解释。

-

与API设计相关的硬件更改相当多。

记住OpenGL可以追溯到1991年。目标硬件不是消费级图形卡(不存在),而是大型CAD工作站等。那个时代的硬件与今天的性能有很大不同。多线程的情况比较少见,内存总线和CPU的速度差距较小,GPU的功能仅比固定功能三角形渲染多。

增加了越来越多的固定功能。各种照明模型,纹理模式等都已添加,每种都需要自己的状态。当您具有少数状态时,基于状态的简单方法就可以工作。随着越来越多的状态被添加,API开始在接缝处爆发。该API变得更加笨拙,但与硬件模式的区别并不大,因为它们确实基于许多状态开关。

然后,可编程硬件随之出现。硬件已经变得越来越可编程,到现在为止,硬件支持一点状态,一些用户提供的程序以及很多缓冲区。必须模仿以前时代的所有状态,就像那个时代的所有固定功能功能都被驾驶员模仿一样。

硬件也变得越来越并行。这需要其他硬件重新设计,这使得图形状态更改非常昂贵。硬件在不可变状态的大块中工作。由于这些更改,驱动程序不能简单地应用用户立即设置的状态的每一个点,而是必须自动批量处理更改并在需要时隐式应用它们。

现代硬件的运行距离经典OpenGL模型还要远。DSA是大约10年前需要的一个小更改(最初承诺是OpenGL 3.0的一部分),类似于D3D10所做的。要保持OpenGL的相关性,上述许多硬件更改所需的不仅仅是DSA,这就是为什么还可以使用更多可大大改变OpenGL模型的大型扩展的原因。然后是全新的GLnext API以及D3D12,Mantle,Metal等。其中没有一个可以保留过时的状态机抽象。


感谢你的回答。因此,似乎在某种程度上赢得了状态机(非DSA),但在某些方面已经发生了变化,现在DSA更具优势。您能否阐明发生了什么变化?
Kromster

@KromStern:尽我所能。如果您需要更多详细信息,那么比我有更多知识的人将不得不提供它。
肖恩·米德迪奇

@KromStern我已经看到(从对历史的有限研究中),openGL越来越少地每帧在CPU端调用调用;显示列表(价值),glDrawArrays(一次调用即可绘制),VBO(一次上传到GPU),VAO(一次将缓冲区绑定到属性),统一缓冲区对象(一次性设置统一)。我敢肯定,还有更多我想念的东西。
棘轮怪胎

@ratchetfreak:有趣的是,我们现在正采取另一种方式。现代的API /扩展专注于增加每帧的绘制调用,主要是通过删除每个绘制调用必须设置/调度的所有状态,并使绘制调用只不过是针对较大的“将绘制命令插入命令队列”静态和无绑定资源集。噢,无边无际,我什至忘了在回答中提到这一部分。
肖恩·米德迪奇

@SeanMiddleditch我应该每帧设置呼叫。
棘手怪胎2015年

1

概述通过以下方式证明其合理性:

此扩展的目的是使库更有效地避免干扰选择器和锁存状态。通过消除对选择器更新命令的需求,该扩展还可以更有效地使用命令。

我认为这里的“效率更高”既指图书馆作者减少簿记开销,又指性能更高。使用当前的API,要“表现良好”,您需要查询状态,隐藏状态,更改状态以执行所需的操作,然后恢复原始状态。

喜欢

oldState = glGet()
glBind()
glDoThings...
glSet(oldState)  // restore, in case anyone needs it just as they left it

据推测,可以通过显式的状态更改API使旧硬件的性能更高。否则这是一个很奇怪的仪式。此扩展意味着(并且仅查看作者列表!)避免使用fetch,set,restore舞现在在当前硬件上更能赢得性能,即使每次调用都带有附加参数也是如此。


“需要查询/存储/更改/恢复”-使用DSA会更好吗?
Kromster

..添加伪代码以显示。使用DSA,不需要任何操作。大概当前的硬件实际上并不需要“绑定”状态,可以根据需要访问所有状态。
大卫范布林克2015年

该链get/bind/do/set很少使用,因为“获取”非常慢。通常,应用程序无论如何都必须维护变量的副本,因此将其缩减为just bind/do。我明白了这一点。
Kromster

2
@krom从驱动程序状态获取可以很快,某些可获取状态在GPU上没有任何作用,因此可以从快速获取的RAM中获取。
棘轮怪胎
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.