OpenGL如何在最低级别工作?
我知道如何编写OpenGL / DirectX程序,并且我知道背后的math和概念性的东西,但是我很好奇GPU-CPU通信是如何在低级别上工作的。
假设我有一个用C语言编写的OpenGL程序,它显示一个三angular形并将摄像头旋转45度。 当我编译这个程序的时候,它会变成一系列的ioctl调用,然后GPU驱动程序将相应的命令发送到GPU,在那里旋转三angular形和设置合适的颜色的适当的像素的所有逻辑是有线在? 或者将程序编译成一个加载到GPU上的“gpu程序”并计算旋转等。 或者完全不同的东西?
编辑 :几天后,我发现这个文章系列,基本上回答了这个问题: http : //fgiesen.wordpress.com/2011/07/01/a-trip-through-the-graphics-pipeline-2011-part- 1 /
这个问题几乎是不可能回答的,因为OpenGL本身就是一个前端API,只要一个实现符合规范,并且结果符合这个要求,就可以以任何你喜欢的方式完成。
问题可能是:OpenGL驱动程序如何在最低级别上工作。 现在再也不可能一般地回答了,因为一个驱动程序与一些硬件密切相关,然而开发人员devise这个硬件可能会再次发生。
所以问题应该是:“OpenGL和graphics系统背后的平均水平如何?”。 我们从下往上看这个:
-
在最底层有一些graphics设备。 现在,这些GPU是提供一组寄存器来控制它们的操作(哪些寄存器完全取决于器件)有一些用于着色器的程序存储器,用于input数据(顶点,纹理等)的大容量存储器以及其余的I / O通道它接收/发送数据和命令stream的系统。
-
graphics驱动程序会跟踪GPU的状态以及所有使用GPU的资源应用程序。 它还负责转换或处理应用程序发送的数据(将纹理转换为GPU支持的像素格式,在GPU的机器代码中编译着色器)。 此外,它提供了一些抽象的,依赖于驱动程序的应用程序接口
-
然后是驱动程序依赖的OpenGL客户端库/驱动程序。 在Windows上,这是通过代理通过opengl32.dll加载,在Unix系统上,这个驻留在两个地方:
- X11 GLX模块和驱动程序相关的GLX驱动程序
- 和/usr/lib/libGL.so可能包含一些驱动程序相关的东西,用于直接渲染
在MacOS X上,这恰好是“OpenGL框架”。
(2)中所描述的驱动程序部分中的驱动程序特定function的调用是这样的。
-
最后是实际的OpenGL API库,Windows中的opengl32.dll,以及Unix上的/usr/lib/libGL.so; 这大多只是将命令传递给OpenGL实现。
实际交stream如何发生不能一概而论:
在Unix中,3→4连接可能发生在套接字上(如果你愿意的话,可能会,也可能会通过networking)或通过共享内存。 在Windows中,接口库和驱动程序客户端都被加载到进程地址空间中,所以没有太多的通信,而是简单的函数调用和variables/指针传递。 在MacOS X中,这与Windows相似,只是OpenGL接口和驱动程序客户端之间没有分离(这就是为什么MacOS X跟上新的OpenGL版本太慢的原因,它总是需要完整的操作系统升级来提供新的框架)。
3 < – > 2之间的通信可以通过ioctl,读/写或者通过将某些存储器映射到进程地址空间,并且configurationMMU以在对该存储器进行改变时触发一些驱动程序代码。 这在任何操作系统上都是非常相似的,因为你总是要跨越内核/用户空间的界限:最终你要经过一些系统调用。
系统与GPU之间的通信是通过外设总线及其定义的访问方式实现的,所以PCI,AGP,PCI-E等通过Port-I / O,Memory Mapped I / O,DMA,IRQ工作。
当我编译这个程序的时候,它会变成一系列的ioctl调用,然后GPU驱动程序将相应的命令发送到GPU,在那里旋转三angular形和设置合适的颜色的适当的像素的所有逻辑是有线在? 或者将程序编译成一个加载到GPU上的“gpu程序”并计算旋转等。
你离我们不远 你的程序调用可安装的客户端驱动程序(这不是一个真正的驱动程序,它是一个用户空间共享库)。 这将使用ioctl或类似的机制将数据传递给内核驱动程序。
对于下一部分,这取决于硬件。 较旧的video卡具有所谓的“固定functionstream水线”。 在显卡的matrix中有专门的存储空间,还有用于纹理查找,混合等的专用硬件。video驱动程序会为每个单元加载正确的数据和标志,然后设置DMA来传输顶点数据(位置,颜色,纹理坐标等)。
较新的硬件在显卡内部具有处理器内核(“着色器”),与CPU不同,它们的运行速度要慢得多,但还有更多的并行工作。 对于这些显卡,驱动程序准备程序二进制文件在GPU着色器上运行。
您的程序不是针对任何特定的GPU编译的; 它只是dynamic链接到一个库,将实现OpenGL。 实际的实现可能涉及向GPU发送OpenGL命令,运行软件回退,编译着色器并将其发送到GPU,甚至使用着色器回退到OpenGL命令。 graphics景观相当复杂。 幸运的是,链接将绝大多数驱动程序的复杂性隔离开来,使驱动程序实施者可以自由使用任何他们认为合适的技术。
C / C ++编译器/链接器完成一件事情:将文本文件转换为CPU上运行的一系列特定于计算机的操作码。 OpenGL和Direct3D只是C / C ++ API; 他们不能神奇地将你的C / C ++编译器/链接器转换成GPU的编译器/链接器。
你写的每一行C / C ++代码都将在CPU上执行。 调用OpenGL / Direct3D将调用C / C ++库,静态或dynamic视情况而定。
当一个“gpu程序”发挥作用时,唯一的地方就是你的代码明确地创build了着色器。 也就是说,如果您将API调用导入OpenGL / D3D,导致着色器的编译和链接。 为此,您(在运行时,而不是C / C ++编译时)可以生成或加载以某种着色器语言表示着色器的string。 然后,您通过着色器编译器推送它们,并在该API中获取代表该着色器的对象。 然后,您将一个或多个着色器应用于特定的渲染命令。 这些步骤中的每一个都是在C / C ++代码的指导下明确进行的,如前所述,这些代码在CPU上运行。
许多着色器语言使用C / C ++语法。 但是这并不能使它们等同于C / C ++。