Tile resources
对于Tile资源,依靠运行设备分页队列的异步VMM服务是不够的。特别是对于Tile资源想让页表刷新操作和渲染操作一起排队,这样确保了更新操作能够在绘制渲染操作之间同步应用。
例如,被一个应用程序调用的下面的API序列
1.Draw #42
2.Update tile mapping
3.Draw #43
我们想确保Draw #42在旧的页表状态下执行,而Draw #43在新的页表状态下执行。对于更新tile映射操作被设置了非写入标志,同步的操作可以放松一点,但是对于高性能更新操作必须被支持。为了支持高性能排队更新,我们需要提前进行换页操作的能力,并将这些操作排队到上下文中以及一旦依赖的渲染上下文达到一个固定时间点时就要执行这些操作。
意味着换页操作需要被排队在GPU等待到指定的渲染上下文被触发。因为这点,这些操作不能被直接的被排队到共享系统上下文中,因为这样作意味着一个应用程序将被系统中的每一个换页执行操作阻塞。
理论上,现在我们基于包的调度能够实现等待设备换页队列中的一部分操作,并监视这些等待,直到等待条件被满足之后就提交换页操作到共享系统上下文。但是,因为我们的移动操作超越了基于包的调度达到了硬件调度层次,所以我们希望确保能够使用CPU到GPU的同步原语来互锁,就保证了尽可能的高性能。
为了解决这个问题,我们引入了每个上下文的换页compaion上下文(per-context paging companion context)的概念。这个换页companion上下文是延迟创建的,在第一次调用UpdateGpuVirtualAddress方法的才被创建。这个Compaion上下文被用于所有需要互锁同步的的页表更新操作。UpdateGpuVIrtualAddress将GPU监视Fence对象和一个指定的Fence值作为参数。Companion上下文在等待这个做更新页表操作关联的监视Fence对象,之后会自增这个监视fence对象,并触发这个fence对象的信号。这样就允许了渲染上下文与Companion上下文能够紧密同步。
使用companion上下文更新的过程如图所示:
Companion上下文被VMM延迟地创建,这一行为依赖于KMD在上下文创建时选择的引擎。(DXGKARG_CREATECONTEXT.PagingCompanionNodeId)。
Companion上下文运行在每个进程的特权地址空间中。之所以这个地址空间有特权是因为它被内核所管理并且仅能够被内核生成的DMA buffer被允许在其中执行。除此以外,这就是普通的GPU VA空间,并不需要任何特殊的硬件虚拟地址特权来支持。
我们选择每个进程的特权GPU VA空间而不是为了简单而使用系统换页进程的GPU VA空间。考虑到Tile资源映射和解除映射是很普遍的,我们需要应用程序的页表被永久的映射到地址空间中而避免平凡的映射和解除映射。此外,我们稍后会详细说明这点,我们也需要永远的映射Tile资源池。如果将这些永久性的映射移到系统地址空间中,将引入不必要的复杂性。
每个进程的特权GPU VA空间会被初始化,这样使得进程的GPU页表通过这个被初始化的地址空间变得可见,更新命令就能够使用GPU来更新不同的页表项。另外,进程创建的额Tile资源池也被映射到了这个地址空间中。
页表项被Companion上下文更新的方式有一些特殊,这里再解释一下。当映射操作在排队等在共享系统上下文里执行时,VMM知道物理地址被映射到并且能直接主线在相关的页缓存中。UpdatePageTable 换页操作就被用在这种情况下,VMM会确保在指定页上的换页操作会在这些页面被用于其他目的之前执行完成。
但是,对于在Companion上下文中的页表的同步更新,情况就有一点复杂了。VMM知道在更新操作被创建时被引用的tile池的物理页面,但是这些操作会被排队等待GPU一段任意长的时间之后才会被执行(甚至应用程序会死锁而永远不会被触发信号)。VMM不知道幻夜操作实际得到执行时被用到的tile池的物理页面,VMM也就不能保持Tile池在一个位置存在任意长的一段时间。
为了解决这个问题,我们需要排队换页操作并且当物理地址改变时重新Patch换页地址,或者我们给更新操作使用到的实际地址进行晚绑定,VMM负责晚绑定的行为。
为了解决这个问题VMM要完成两件事。第一,VMM会映射GPU VA到进程所有的Tile池,这个Tile池属于进程内部的进程特权地址空间。当tile池在内存中移动时,VMM自动的保持这些GPUVA指向正确地址,对于tile池使用的这种简单的机制,也适用于其他类型的allocation.
为了更新Tile资源的页表项,VMM引入了CopyPageTableEntry这个新的换页操作,它可以将页表项从tile池的虚拟地址拷贝到Tile资源的虚拟地址上。因为VMM在tile池在内从中移动时,一直保持Tile池的虚拟地址是最新的,这样就确保拷贝操作能够在当前正确的tile池物理地址上执行,而不用关心这个操作的命令从生成到实际执行之间过了多少时间。
注意 只要队列中的页表更新操作引用了tile池,VMM就将保持tile池在residency,应用程序的前提条件无论UMD或者应用程序怎样,都保证了Tile池虚拟地址在执行更新操作的时候是有效的。
这个机制如下图所示:
Update GPU virtual address on GPUs with CPU_VIRTUAL page table update mode
在GPU支持DXGK_PAGETABLEUPDATE_CPU_VIRTUAL 页表更新模式的GPU中,CopyPageTableEntries 操作将不会被使用。这些都是集成GPU,不使用换页buffers。VMM将推迟更新操作合适的时间,并使用 UpdatePageTable操作来建立页表。
这种方法的弊端在于UpdatePageTable 操作和渲染操作不是并行的。而优点在于驱动不需要实现对换页Buffer的支持以及实现UpdatePageTable为一个立即操作。