Electronic Joint Business

Solution for E-Business

Linux环境下的图形系统和AMD R600显卡编程(5)——AMD显卡显命令处理机制

  通常通过读写设备寄存器对设备进行编程,在X86系统上,有专门的IO指令进行编程,在其他诸如MIPS、SPARC这类系统上,通过将设备的寄存器映射到内存地址空间直接使用读写内存的方式对设备进行编程。   Radeon显卡提供两种方式对硬件进行编程,一种称为“推模式”(push mode)即直接写寄存器的方式,另一种称为拉模式,这篇blog讨论拉模式,这也是驱动中使用的模式。   在拉模式下,驱动使用命令流(Command Stream)的形式进行对显卡编程:驱动程序将需要对显卡进行配置的一连串命令写入命令缓冲区,写完之后进入让出处理器,显卡按照命令写入的顺序执行这些命令,执行完成后触发中断通知驱动。CPU将这些命令放入一个称为命令环的环形缓冲区中,命令环是GTT内存中分出来的一片内存,驱动程序往命令环中填充命令,填充完后通知GPU命令已经写入命令,GPU的命令处理器CP(Command Processor)。上一篇博客即是通过ring环内存的使用来说明如何在系统中分配内存以及建立映射关系的。   驱动写入的命令流由命令处理器CP进行解析,具体来说,CP完成以下工作: •接收驱动程序的命令流。驱动程序将命令流先写入系统内存,然后由CP通过总线主设备访问方式进行获取,当前支持三种命令流,除了前面说的环形缓冲命令流,还有间接缓冲1命令流和间接缓冲2命令流; •解析命令流,将解析后的数据传输给图形控制器的其他模块,包括3D图形处理器、2D图形处理器、视频处理器。 命令环缓冲区   在拉模式下,驱动程序在系统内存中为命令流申请一块缓冲区。GPU会根据这些命令流去执行屏幕绘图等操作。这种命令缓冲区按照环形方式进行管理,是CPU和GPU 共享的一片系统主存,CPU负责写入命令包,GPU负责读取和解析命令包。因为CPU和GPU 看到的环形缓冲区状态必须是一致性,所以CPU和GPU都要共同维护和管理环形缓冲区的状态:基地址、长度、写指针和读指针。为了使Ring Buffer能够正常工作,CPU和GPU 必须维护这种状态的一致性。Ring Buffer基地址和大小是在系统第一次启动时已经初始化好的,之后一般也不会改变。当操作Ring Buffer时, 读指针和写指针的修改非常频繁。为了维护环形缓冲区的状态一致性,当写操作者(CPU)更新写指针时,它必须将写指针告诉GPU。同样的,当读操作者(GPU)更新读指针时,它必须将读指针告知CPU。无论是CPU还是GPU都是从低地址开始进行填写或抽取操作的,一旦到了环形缓冲区的结束处,又从环形缓冲区起始处继续。  整个过程如图1示,左边的Host(CPU)和右边的GPU各自记录了命令环的起始地址,并各自保存了一份读写指针,CPU写之前首先查询读指针,确认有空闲空间之后写入内容并更新写指针,GPU读取了命令之后更新读指针。 间接缓冲   在系统主存中,除了环形缓冲区之外,CP还可以从间接缓冲1和间接缓冲2中获取命令包。这个过程是这样完成的:在主命令流中(ring buffer)有一个设置CP的间接缓冲1地址和大小的寄存器。写间接缓冲1的寄存器触发CP从提供的地址处取间接缓冲区1的命令流。主命令的最后一个命令包设置间接缓冲1地址和大小;然后CP开始从间接缓冲1中取数据。间接缓冲1的数命令流可能使用间接缓冲区2。和之前的过程一样,写间接缓冲1的寄存器触发CP从间接缓冲区2中获取新的命令流。间接缓冲1流中的最后一个包设置间接缓冲2的地址和大小。CP从间接缓冲2取命令直到全部去完;执行完间接缓冲区2的命令后返回到间接缓冲1的命令流。CP从间接缓冲1中取剩余的命令一直到间接缓冲1的末尾,返回到主命令流中。   这个过程有点类似函数调用。程序在运行过程中遇到函数调用,则会使用跳转指令跳到被调用函数入口,执行完函数后跳回到原来的程序位置继续执行。这的最大调用“深度”为2。      在Linux内核radeon驱动中有一个ring test过程用于验证ring buffer是否工作正常,如果ring test通过,那么GPU和CPU交互的部分已经配置正确,可以正常工作了。   Ring buffer机制几乎在所有类型的芯片上都是一样的,区别只是r600以后的芯片ring buffer GPU端读写指针的寄存器地址发生了变化。Linux内核驱动针对不同GPU核实现ring buffer机制以及ring test过程的代码几乎是完全相同的。   从内核中拿出ring test过程的代码: 2287 int r600_ring_test(struct radeon_device *rdev) 2288 { 2289 uint32_t scratch; 2290 uint32_t tmp = 0; 2291 unsigned i; 2292 […]

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.