显卡使用的内存分为两部分,一部分是显卡自带的显存称为VRAM内存,另外一部分是系统主存称为GTT内存(graphics translation table和后面的GART含义相同,都是指显卡的页表,GTT 内存可以就理解为需要建立GPU页表的显存)。在嵌入式系统或者集成显卡上,显卡通常是不自带显存的,而是完全使用系统内存。通常显卡上的显存访存速度数倍于系统内存,因而许多数据如果是放在显卡自带显存上,其速度将明显高于使用系统内存的情况(比如纹理,OpenGL中分普通纹理和常驻纹理)。
某些内容是必须放在vram中的,比如最终用于显示的“帧缓存”,以及后面说的页表GART (graphics addres remapping table),另外有一些比如后面将介绍的命令环缓冲区(ring buffer)是要放在GTT 内存中的。另一方面,VRAM内存是有限的,如果VRAM内存使用完了,则必须将一些数据放入GTT内存中。
通常GTT内存是按需分配的,而且是给设备使用的,比如radeon r600显卡最多可以使用512M系统内存(Linux内核中是这样设置的),一次性分配512M连续的给设备用的内存在linux系统中是不可能成功的,而且即使可以成功,有相当多的内存是会被浪费掉的。按照按需分配的原则,使用多少就从系统内存中分配多少,这样得到的GTT内存在内存中肯定是不连续的。GPU同时需要使用VRAM内存和GTT内存,最简单的方法就是将这两片内存统一编址(这类似RISC机器上IO和MEM统一编址),VRAM是显卡自带的内存,其地址一定是连续的,但是不连续的GTT内存如果要统一编址,就必须通过页表建立映射关系了,这个页表被称为GTT或者GART,这也是这些内存被称为GTT内存的原因。
和CPU端地址类似,我们将GPU使用的地址称为“GPU虚拟地址”,经过查页表之后的地址称为“GPU物理地址”,这些地址是GPU最终用于访存的地址,由于GPU挂接在设备总线上,因此这里的“GPU物理地址”就是“总线地址”,当然落在vram 区域的内存是不用建页表的,这一片内存区域的地址我们只关心其“GPU 虚拟地址”。
R600显卡核心存管理有关的寄存器如表1示,目前并没有找到完整的描述这些寄存器的手册,表中的数据根据阅读代码获取到。
寄存器名称
偏移地址
功能
R600_CONFIG_MEMSIZE
0x5428
VRAM大小
MC_VM_FB_LOCATION
0x2180
VRAM区域在GPU虚拟地址空间的起始地址和长度
MC_VM_SYSTEM_APERTURE_LOW_ADDR
0x2190
VRAM区域在GPU虚拟地址空间的起始地址
MC_VM_SYSTEM_APERTURE_HIGH_ADDR
0x2194
VRAM区域在GPU虚拟地址空间的结束地址
VM_L2_CNTL
GPU L2 Cache控制寄存器
MC_VM_L1_TLB_MCB
GPU TLB控制寄存器
VM_CONTEXT0_PAGE_TABLE_START_ADDR
0x1594
GTT内存的起始地址
VM_CONTEXT0_PAGE_TABLE_END_ADDR
0x15B4
GTT内存的结束地址
VM_CONTEXT0_PAGE_TABLE_BASE_ADDR
0x1547
GPU页表基地址
VM_CONTEXT0_CNTL
0x1440
GPU虚拟地址空间使能寄存器
VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR
0x1554