关于 D3D 的资源管理的那点事

        引擎中的异步资源管理,其中重要部分是涉及到 D3D 设备资源的管理。在 CreateX Engine 中,大部分 D3D 资源,除了必须以 Default 方式创建的之外,基本都是 Managed Pool 管理的。以 Texture 为例,当申请一个纹理资源时,除了创建引擎逻辑上的纹理对象外,最终还要创建 D3D 的设备对象,很显然,在不开启 D3D 设备多线程安全的模式下,设备资源的创建必然是在渲染线程中完成的,若要不希望渲染线程被阻塞,关键在于填充数据这一步。我采取的做法是:1.在渲染线程 Lock,将 Lock 返回指针和要填充的内存数据投递给资源上传线程;2.资源上传线程 memcpy,通知渲染线程;3.渲染线程 Unlock。我曾经把这个方案介绍给腾讯的同事,有人提出疑问:即使将 copy 数据的过程放在了另一个线程,但是调用在 Unlock API 时 Driver 还是要把数据再 upload 到显存中,这个过程是在渲染线程中完成的,所以本质上还是阻塞了渲染线程。对此我的回答是这样的:Managed 的方式创建的资源,在 Unlock 之后并不是立刻 Upload 到显存中,众所周知,Default 资源是常驻本地显存(On-chip Memory)中的,当一个 Default 资源被创建时,立即在本地显存中分配出一段内存留给这个资源。而 Managed  资源在创建时并不立即分配显存,而是在非本地显存(AGP 内存)中保存一份相同的数据,当渲染需要用到这个资源时,Driver 会判断资源是否在本地显存中,如果不在才会从非本地显存中 Upload 到本地显存中。用一个 D3D API 也可以佐证我的观点:IDirect3DDevice9::EvictManagedResources,这个函数的作用是清除本地显存中的所有 Managed 资源,经常做为当显存不足无法创建 D3D 资源对象时的处理手段。如果这一事实成立,上述异步创建 D3D 资源的流程就是有效的。但不幸的是这个观点无法得到官方文档的证实,在 D3D SDK 文档中没有任何说明 Unlock 后发生了什么,也许只有 GPU 厂商知道。直到今天 ATI 的技术人员来公司做技术演示,在交流过程中总算是对之前的这个疑惑有了官方的解答:

        对于 Managed 资源,在 Unlock 后并不是立即提交到本地显存,而是延迟提交,也就是渲染时用到即时提交;对于 Default 资源,有2种情况:1.Lock 返回的是本地 Visible 显存地址。这里解释一下,ATI GPU Driver 内部会把本地显存分为两种:一种是 Visible,一种是 Invisible,这里所谓的 visible 是指对 CPU 而言,也就是说 Visible 的本地显存地址可以映射到 CPU 可见得的系统地址空间中,这样当 Lock 时,根据资源创建的标志和 Lock 标志,返回的有可能是 Visible 的本地显存的映射地址,这时向 Lock 返回的地址 copy 数据实际上就是向本地显存直接 upload 数据,也就同时发生了总线数据传输。2.Lock 返回的是非本地显存的地址,由于非本地显存对 CPU 也是可见的(可映射的),这时的 copy 操作实际上是将数据 copy 到临时的非本地显存中,当 Unlock 时就是把非本地显存的临时数据再 copy 到本地显存中。

        当我把我的多线程 D3D 设备资源管理方案和 ATI 技术人员介绍了之后,他认为这样做没有问题,确实可以提高加载性能,而不阻塞渲染线程。当然,这还只是 ATI 的驱动的实现方式,我计划下次跟 Nvidia 技术交流时再提相同问题,看看 Nvidia Driver 又是如何处理的。不过我相信大同小异。

Advertisements
此条目发表在Uncategorized分类目录。将固定链接加入收藏夹。

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  更改 )

Google+ photo

You are commenting using your Google+ account. Log Out /  更改 )

Twitter picture

You are commenting using your Twitter account. Log Out /  更改 )

Facebook photo

You are commenting using your Facebook account. Log Out /  更改 )

w

Connecting to %s