D3D资源管理

摘要

受管贴图(Managed textures,也就是咱们一般所谓的“自动管理贴图”),在DX6中首次被引入,通过一系列的改进和加强,在DX9中自动管理的资源类型增长到贴图,顶点缓冲,顶点索引缓冲,全部这些资源使用统一的公共接口。经过使用D3D资源管理器,应用程序能够轻松的处理设备丢失、处理稍微过量的显存使用。

有时开发者在使用受管资源会遇到一些困难,这部分归咎与系统的抽象特性。在大多数状况下使用受管对象是不错的选择,但有时出于性能考虑也会使用非托管资源。这篇文章将讨论通常状况下如何处理资源,受管与非受管资源的行为差异。


内容

l 显示内存

l 受管资源

l 驱动管制资源

l 默认资源

l 系统内存资源

l 通常性的建议


显示内存

为 了使得资源能够利用显存,GPU须要经过内存访问定位他。GPU访问(Local video memory)显存是很是高效的,而且某些资源(例如RenderTarget,深度、模板缓冲)必须在本地显存(Local video memory)定位。因为AGP的出现,GPU能够直接访问部分系统内存,而这部分系统内存区域就是所谓的非本地显存(non-local video memory),固然这部份内存(显存)也是不能挪作它用的。非本地显存仅能被GPU访问,与访问本地显存相比,其效率低一些。须要明确的是,全部AGP 内存在设备丢失时都会失效,都须要在恢复他们。

一些集成显卡使用统一内存结构(Unified Memory Architecture),这样主内存能够被系统任何一个设备寻址。D3D支持UMA而不须要修改任何代码,这样咱们把系统内存配置为本地显存,硬件确保资源的定位就像传统的结构同样进行工做。


受管资源

大部分资源应该使用POOL_MANAGED方式建立,即受管资源。全部受管资源将被建立在系统内存,在须要的时候复制到显存。当发生设备丢失时会自动 copy系统内存到显存。既然不是全部受管资源都须要一次送入显存,这样你能够提交超过渲染每帧所必须使用的最小内存容量,可是这样会使得大量显存内容由于分页操做而写到磁盘上,这是很是耗时的。这也是为何恢复设备如此耗时,由于须要将大量磁盘数据复制到显存。

DX会为每份资源在最后一次使用时加上时间戳,这样当显存分配失败时,它会释放那些最近最少使用的资源(LRU算法)。使用SetPriority函数能够标记资源的重要程度,重要的资源优于时间戳的判断,因此那些比较经常使用的资源应该设置高优先级,而不用担忧由于时间戳过时而致使资源被释放。在DX9中,驱动程序提供的显存管理信息是很是有限的,运行时可能不得不清除大量资源用于分配足够的内存。设置适合的优先级是很是有用的,这样D3D不会清除那些立刻又须要使用的资源。应用程序能够强制调用EvictManagedResources清除全部受管资源,可是若是下一帧又须要从新加载这些资源,这将是很是耗时的,不过这个函数在那些场景明显须要改变(好比进入下一个关卡)的状况下,仍是很是有用的。

若是“当前帧”内须要很是多资源用于渲染,这将是件麻烦的事情,用前面的LRU方式调度资源效率就不太理想了,这个时候使用MRU资源调度方式取代,即优先清理那些比较活跃的资源。注意,这里“当前帧”的概念是指 BeginScene和EndScene之间的须要渲染的帧。

开发人员若是想获得关于受管资源的更多信息,能够经过IDirect3DQuery9接口查询,可是这个接口仅能用于调试模式(debug runtimes),在发布版本中,应用程序不能依靠改接口的信息作任何假定。

了解资源管理如何工做能够帮助咱们调试、调整程序,重要的是应用程序不要太过依赖当前的运行库(或者驱动程序)的资源管理方式,驱动更新有可能致使其行为发生变化,未来的D3D将会有套久经考验的资源管理方式。


驱动程序管理的资源

D3D 驱动能够自由的实现“由驱动管理贴图”的特性,经过D3DCAPS2_CANMANAGERESOURCE段能够查询硬件驱动是否支持这个特性,这样驱动将代替D3D运行库管理资源。对于级少数的硬件是支持这个特性的,对于大多数硬件则不尽相同,你能够咨询你的产品提供商得到这方面信息。通常状况下,你但是使用D3DCREATE_DISABLE_DRIVER_MANAGEMENT方式建立设备,这样将由D3D运行库来管理资源。


缺省资源管理(非受管资源)

虽然受管资源很是简单,容易使用,高效,可是有时咱们但愿直接往显存里写东西,这种状况下咱们须要使用POOL_DEFAULT方式建立资源。使用这种方式会增长程序的复杂性,代码须要应付全部设备丢失的状况,并须要谨慎考虑什么时候复制数据到显存。错误的指定USAGE_WRITEONLY标记或者锁定渲染目标(Render Target)将严重影响性能。

锁定POOL_DEFAULT类型的资源极可能致使GPU中止运转,这与 POOL_MANAGED类型的资源是不一样的,除非使用一些特性的指示标记。根据资源当前的位置不一样,锁定后获得的指针也不相同,多是一块临时的系统内存,也可能直接指向AGP内存。若是是临时的系统内存,Unlock后将把这段数据送入显存,这是由于若是显卡资源不是只写的(write- only),Lock的时候数据将不得不被送入一段临时的内存;若是指向的AGP内存区域,临时的拷贝是能够避免的,可是cache的行为将会下降性能。

为了不在写入一整行数据(a full cache line of data)进入AGP内存区致使write-combing性能降低(通常是因为发生了一次读写周期),顺序的访问AGP内存是推荐的作法,若是你的程序须要随机的访问AGP内存,而你又不但愿使用受管资源,那么你可使用系统内存做为替代方案,这样当你生成了数据以后,能够lock后拷贝,这样不会带来太大的性能损失,这里的性能损失通常是由缓冲的“写搜索”操做引发。(注,这里关于词汇cache write-combing译者也不知道对应的中文含义,只能按照字面意思翻译,见谅)

对于某些类型的资源,使用 LOCK_NOOVERWRITE标记会使添加数据比较有效率,可是屡次的Lock,Unlock同一资源仍是须要尽可能避免的,适当的利用多种不一样的锁定标记对于效率优化使很是重要的,就像填充锁定内存区域最好使用cache友好的(cache-friendly)数据访问方式同样。


受管资源和缺省资源混合使用

受管资源与非受管资源的混合分配使用可能致使显存碎块,而且扰乱受管资源使用的内存区域。最好在使用受管资源前使用非受管资源,或者使用受管资源后使用 EvictManagedResources函数清除那些受管资源再使用非受管资源。记住,全部非受管资源都会常驻显存,这样其余内存需求就不能使用了。

注意,与以往的DX版本不一样,在显存缺少时,若是分配非受管资源失败,DX9会自动清除受管资源,这有可能致使潜在的显存碎块,甚至把资源放入不适当的地方(好比非本地内存的静态贴图区)。因此,最好在使用受管资源以前分配所有的非受管资源。


动态缺省资源

若是数据须要很高频率更新,那最好使用非受管资源,并使用USAGE_DYNAMIC标记,这样驱动会决定最适合的地方放置这些须要常常更新的数据。这一般意味着放置在非本地显存中,这样对于GPU来讲,访问速度可能相对要慢一些。而对于UMA架构,驱动将会选择CPU访问效率较高的特殊地方放置这些数据。

这种用法(动态缺省资源类型)通常用于软蒙皮和基于CPU计算的粒子系统的顶点/顶点索引的Buffer填充,LOCK_DISCARD标记能够保证资源仍被使用的时候,锁定操做不会致使系统中止暂停工做。在这种状况下,使用受管资源会更新系统内存,而后拷贝到显存。对于系统的非本地内存,多余拷贝是不须要的。

标准的贴图是不容许锁定的,仅仅能够经过UpdateSurface和 UpdateTexture函数更新。一些系统支持动态贴图,它能够经过配合使用LOCK_DISCARD标记进行锁定,但这须要检查 D3DCAPS2_DYNAMICTEXTURES硬件能力。对于高动态贴图(如视频、程序生成贴图),最好使用非受管资源和系统内存资源,而且经过 UpdateTexture函数更新贴图。对于高频度的粒子更新,UpdateTexture函数多是最好的选择。

在有限的总线-内存带宽下,静态贴图资源应该使用POOL_MANAGED方式,这样能够确保它最好的利用本地显存,并有较好的效率。对于“半静态”资源,使用动态类型资源有时会得到更好的效率。


系统内存资源

资源可使用POOL_SYSTEMMEM方式建立。但他们不能用于图形管线,他们仅能作为源数据用于更新POOL_DEFAULT类型的资源,这是经过 UpdateSurface和UpdateTexture函数完成的。他们的锁定操做也很是简单,尽管他们一样可能由于前面提到的缘由致使系统中止运转。

虽然是在系统内存中建立资源,但POOL_SYSTEMMEM所支持的资源格式和能力(好比最大尺寸)是受硬件、驱动限制的。一样是在系统内存中建立资源的POOL_SCRATCH则没有这方面限制,它支持全部格式和能力,但设备却不能直接访问它。SCRATCH类型资源通常用于内容建立工具。


通常性的建议

了解资源管理的技术实现细节对达成你的程序的性能目标是有很是大的帮助的,规划你的资源如何交给D3D并设计好的结构以便能及时加载必要的数据是一件很是复杂的工做,为此咱们给出一些好的实践经验作为通常性的原则:

l 预处理你的资源。不要将耗时的加载资源、资源转换、资源优化丢给用户去作,虽然这样便于开发,但确让用户没法忍受。预处理这些资源能够加快加载,更快使用,你的用户也会发现你的程序跑的更快了。

l 避免在每帧建立过多的资源。对于过多的资源加载,能够把他们分到多帧里完成或者不要急于释放那些暂时不用的资源。

l 确保在一帧结束时已经断开了全部资源通道。(好比,顶点流,texture stages,顶点索引)。

l 对于贴图,建议使用压缩贴图(DXTn)格式,建议使用mip-map或者将小贴图拼接为大贴图使用。

l 建议使用顶点索引,这将减小数据传输量。

l 对于过渡的优化资源管理是须要谨慎的。若是你的程序过度依赖驱动、硬件和操做系统的某些特征,那么这些程序、硬件的修改将会致使潜在的性能问题。算法

相关文章
相关标签/搜索