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