摘要
受管贴图Q?/span>Managed texturesQ也是我们通常所谓的“自动理贴图”Q,?/span>DX6中首ơ被引入Q经q一pd的改q和增强Q在DX9中自动管理的资源cd增加到脓(chung)图,点~冲Q顶点烦引缓Ԍ所有这些资源用统一的公共接口。通过使用D3D资源理器,应用E序可以L的处理设备丢失、处理稍微过量的昑֭使用?/span>
有时开发者在使用受管资源会遇C些困难,q部分归咎与pȝ的抽象特性。在大多数情况下使用?span class="GramE">对?/span>是不错的选择Q但有时Z性能考虑也会使用非托资源。这文章将讨论一般情况下如何处理资源Q受与非受资源的行ؓ差别?/span>
内容
l 昄内存
l 受管资源
l 驱动制资源
l 默认资源
l pȝ内存资源
l 一般性的
昄内存
Z使得资源可以利用昑֭Q?/span>GPU需要通过内存讉K定位他?/span>GPU讉KQ?/span>Local video memoryQ显存是非常高效的,q且某些资源Q例?/span>RenderTargetQ深度、模板缓Ԍ必须在本地显存(Local video memoryQ定位。由?/span>AGP的出玎ͼGPU可以直接讉K部分pȝ内存Q而这部分pȝ内存区域是所谓的非本地显存(non-local video memoryQ,当然q部分内存(昑֭Q也是不能挪做它用的。非本地昑֭仅能?/span>GPU讉KQ与讉K本地昑֭相比Q其效率低一些。需要明的是,所?/span>AGP内存在设备丢失时都会失效Q都需要在恢复他们?/span>
一些集成显卡用统一内存l构Q?/span>Unified Memory ArchitectureQ,q样d存可以被pȝM一个设备寻址?/span>D3D支持UMA而不需要修改Q何代码,q样我们把系l内存配|ؓ本地昑֭Q硬件确保资源的定位像传统的结构一栯行工作?/span>
受管资源
大部分资源应该?/span>POOL_MANAGED方式创徏Q即受管资源。所有受资源将被创建在pȝ内存Q在需要的时候复制到昑֭。当发生讑֤丢失时会自动copypȝ内存到显存。既然不是所有受资源都需要一ơ送入昑֭Q这样你可以提交过渲染每所必须使用的最内存容量,但是q样会?span class="GramE">大量昑֭内容因ؓ?span class="GramE">|?/span>而写到磁盘上Q这是非常耗时的。这也是Z么恢复设备如此耗时Q因为需要将大量盘数据复制到显存?/span>
DX会ؓ每䆾资源在最后一ơ用时加上旉戻Iq样当显存分?/span>p|Ӟ它会释放那些最q最用的资源Q?/span>LRU法Q。?/span>SetPriority函数可以标记资源的重要程度,重要的资源优于时间戳的判断,所以那些比较常用的资源应该讄高优先Q而不用担心因为时间戳q期而导致资源被释放。在DX9中,驱动E序提供的显存管理信息是非常有限的,q行时可能不得不清除大量资源用于分配_的内存。设|适合的优先是非常有用的Q这?/span>D3D不会清除那些马上又需要用的资源。应用程序可以强制调?/span>EvictManagedResources清除所有受资源,但是如果下一帧又需要重新加载这些资源,q将是非常耗时的,不过q个函数在那些场景明N要改变(比如q入下一个关卡)的情况下Q还是非常有用的?/span>
如果“当前?#8221;内需要非常多资源用于渲染Q这是仉烦的事情Q用前面?/span>LRU方式调度资源效率׃太理想了Q这个时候?/span>MRU资源调度方式取代Q即优先清理那些比较z跃的资源。注意,q里“当前?#8221;的概忉|?/span>BeginScene?/span>EndScene之间的需要渲染的帧?/span>
开发h员如果想得到关于受管资源的更多信息,可以通过IDirect3DQuery9接口查询Q但是这个接口仅能用于调试模式(debug runtimesQ,在发布版本中Q应用程序不能依靠改接口的信息做M假定?/span>
了解资源理如何工作可以帮助我们调试、调整程序,重要的是应用E序不要太过依赖当前的运行库Q或者驱动程序)的资源管理方式,驱动更新有可能导致其行ؓ发生变化Q将来的D3D会有套久经考验的资源管理方式?/span>
驱动E序理的资?/span>
D3D驱动可以自由的实?#8220;由驱动管理脓(chung)?#8221;的特性,通过D3DCAPS2_CANMANAGERESOURCED可?/span>查询g驱动是否支持q个Ҏ(gu),q样驱动代?/span>D3Dq行库管理资源?span class="GramE">对于U少?/span>的硬件是支持q个Ҏ(gu)的Q对于大多数g则不相同,你可以咨询你的品提供商获得q方面信息。一般情况下Q你可是使用D3DCREATE_DISABLE_DRIVER_MANAGEMENT方式创徏讑֤Q这样将?/span>D3Dq行库来理资源?/span>
~省资源理Q非受管资源Q?/span>
虽然受管资源非常单,Ҏ(gu)使用Q高效,但是有时我们希望直接往昑֭?/span>写东西,q种情况下我们需要?/span>POOL_DEFAULT方式创徏资源。用这U方式会增加E序的复杂性,代码需要应付所有设备丢q情况Qƈ需要}慎考虑何时复制数据到显存。错误的指定USAGE_WRITEONLY标记或者锁定渲染目标(Render TargetQ将严重影响性能?/span>
锁定POOL_DEFAULTcd的资源很可能DGPU停止q{Q这?/span>POOL_MANAGEDcd的资源是不同的,除非使用一些特性的指示标记。根据资源当前的位置不同Q锁定后得到的指针也不相同,可能是一块时的pȝ内存Q也可能直接指向AGP内存。如果是临时的系l内存,Unlock后将把这D|据送入昑֭Q这是因为如果显卡资?/span>不是只写的(write-onlyQ,Lock的时候数据将不得不被送入一D时的内存Q如果指向的AGP内存区域Q时的拯是可以避免的Q但?/span>cache的行为将会降低性能?/span>
Z避免在写入一整行数据Q?/span>a full cache line of dataQ进?/span>AGP内存区导?/span>write-combing性能下降Q一般是׃发生了一ơ读写周期)Q顺序的讉KAGP内存是推荐的做法Q如果你的程序需要随机的讉KAGP内存Q而你又不希望使用受管资源Q那么你可以使用pȝ内存作ؓ替代Ҏ(gu)Q这样当你生成了数据之后Q可?/span>lock后拷贝,q样不会带来太大的性能损失Q这里的性能损失一般是q冲的“写搜?#8221;操作引v?/span>(注,q里关于词汇cache write-combing译者也不知道对应的中文含义Q只能按照字面意思翻译,见谅)
对于某些cd的资源,使用LOCK_NOOVERWRITE标记会d数据比较有效率,但是多次?/span>LockQ?/span>Unlock同一资源q是需要尽量避免的Q适当的利用多U不同的锁定标记对于效率优化佉K帔R要的Q就像填充锁定内存区域最好?/span>cache友好的(cache-friendlyQ数据访问方式一栗?/span>
受管资源和缺省资源合?/span>
受管资源与非受管资源的合分配用可能导致显存碎块,q且Cؕ受管资源使用的内存区域。最好在使用受管资源前用非受管资源Q或者用受资源后使用EvictManagedResources函数清除那些受管资源再用非受管资源。记住,所有非受管资源都会帔R昑֭Q这样其他内存需求就不能使用了?/span>
注意Q与以往?/span>DX版本不同Q在?span class="GramE">存缺?/span>Ӟ如果分配非受资源失败,DX9会自?span class="GramE">清除?/span>资源,q有可能D潜在的显存碎块,甚至把资源放入不适当的地方(比如非本地内存的静态脓(chung)囑Q。所以,最好在使用受管资源之前分配全部的非受管资源?/span>
动态缺省资?/span>
如果数据需要很高频率更斎ͼ那最好用非受管资源Qƈ使用USAGE_DYNAMIC标记Q这样驱动会军_最适合的地Ҏ(gu)|这些需要经常更新的数据。这通常意味着攄在非本地昑֭中,q样对于GPU来说Q访问速度可能相对要慢一些。而对?/span>UMA架构Q驱动将会选择CPU讉K效率较高的特D地Ҏ(gu)|这些数据?/span>
q种用法Q动态缺省资源类型)一般用于Y蒙皮和基?/span>CPU计算的粒子系l的点/点索引?/span>Buffer填充Q?/span>LOCK_DISCARD标记可以保证资源仍被使用的时候,锁定操作不会Dpȝ停止暂停工作。在q种情况下,使用受管资源会更新系l内存,然后拯到显存。对于系l的非本地内存,多余拯是不需要的?/span>
标准的脓(chung)图是不允讔R定的Q仅仅可以通过UpdateSurface?/span>UpdateTexture函数更新。一些系l支持动态脓(chung)图,它可以通过配合使用LOCK_DISCARD标记q行锁定Q但q需要检?/span>D3DCAPS2_DYNAMICTEXTURESg能力。对于高动态脓(chung)图(如视频、程序生成脓(chung)图)Q最好用非受管资源和系l内存资源,q且通过UpdateTexture函数更新贴图。对于高频度的粒子更斎ͼUpdateTexture函数可能是最好的选择?/span>
在有限的ȝQ内存带宽下Q静态脓(chung)图资源应该?/span>POOL_MANAGED方式Q这样可以确保它最好的利用本地昑֭Qƈ有较好的效率。对?#8220;半静?#8221;资源Q用动态类型资源有时会获得更好的效率?/span>
pȝ内存资源
资源可以使用POOL_SYSTEMMEM方式创徏。但他们不能用于囑Ş线Q他们仅?span class="GramE">做ؓ源数?/span>用于更新POOL_DEFAULTcd的资源,q是通过UpdateSurface?/span>UpdateTexture函数完成的。他们的锁定操作也非常简单,管他们同样可能因ؓ前面提到的原因导致系l停止运转?/span>
虽然是在pȝ内存中创源,?/span>POOL_SYSTEMMEM所支持的资源格式和能力Q比如最大尺寸)是受g、驱动限制的。同h在系l内存中创徏资源?/span>POOL_SCRATCH则没有这斚w限制Q它支持所有格式和能力Q但讑֤却不能直接访问它?/span>SCRATCHcd资源一般用于内容创建工兗?/span>
一般性的
了解资源理的技术实现细节对达成你的E序的性能目标是有非常大的帮助的,规划你的资源如何交给D3Dq设计好的结构以便能及时加蝲必要的数据是一仉常复杂的工作Qؓ此我们给Z些好的实늻?span class="GramE">做ؓ一般性的原则Q?/span>
l 预处理你的资源。不要将耗时的加载资源、资源{换、资源优化丢l用户去做,虽然q样便于开发,但确让用h法忍受。预处理q些资源可以加快加蝲Q更快用,你的用户也会发现你的E序跑的更快了?/span>
l 避免在每帧创多的资源。对于过多的资源加蝲Q可以把他们分到多里完?/span>或者不要急于释放那些暂时不用的资源?/span>
l 保在一帧结束时已经断开了所有资源通道。(比如Q顶Ҏ(gu)Q?/span>texture stagesQ顶点烦引)?/span>
l 对于贴图Q徏议用压~脓(chung)图(DXTnQ格式,使用mip-map或者将脓(chung)图拼接ؓ大脓(chung)图用?/span>
l 使用点索引Q这减数据传输量?/span>
l 对于q渡的优化资源管理是需要}慎的。如果你的程序过分依赖驱动、硬件和操作pȝ的某些特征,那么q些E序、硬件的修改会D潜在的性能问题?/span>