﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Richard He-文章分类-D3D</title><link>http://www.cppblog.com/richardhe/category/8497.html</link><description>学无止境!永远学下去!</description><language>zh-cn</language><lastBuildDate>Thu, 11 Dec 2008 11:18:23 GMT</lastBuildDate><pubDate>Thu, 11 Dec 2008 11:18:23 GMT</pubDate><ttl>60</ttl><item><title>D3D资源管理</title><link>http://www.cppblog.com/richardhe/articles/69204.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Thu, 11 Dec 2008 10:58:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/69204.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/69204.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/69204.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/69204.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/69204.html</trackback:ping><description><![CDATA[<div class="PostContent">
<p class="MsoNormal"><strong><span style="font-family: 宋体;">摘要</span><span lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal"><span style="font-family: 宋体;">受管贴图（</span><span lang="EN-US">Managed textures</span><span style="font-family: 宋体;">，也就是我们通常所谓的&#8220;自动管理贴图&#8221;），在</span><span lang="EN-US">DX6</span><span style="font-family: 宋体;">中首次被引入，经过一系列的改进和增强，在</span><span lang="EN-US">DX9</span><span style="font-family: 宋体;">中自动管理的资源类型增加到贴图，顶点缓冲，顶点索引缓冲，所有这些资源使用统一的公共接口。通过使用</span><span lang="EN-US">D3D</span><span style="font-family: 宋体;">资源管理器，应用程序可以轻松的处理设备丢失、处理稍微过量的显存使用。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">有时开发者在使用受管资源会遇到一些困难，这部分归咎与系统的抽象特性。在大多数情况下使用受<span class="GramE">管对象</span>是不错的选择，但有时出于性能考虑也会使用非托管资源。这篇文章将讨论一般情况下如何处理资源，受管与非受管资源的行为差别。</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><strong><span style="font-family: 宋体;">内容</span><span lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt;"><span style="font-family: wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;">显示内存</span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt;"><span style="font-family: wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;">受管资源</span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt;"><span style="font-family: wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;">驱动管制资源</span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt;"><span style="font-family: wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;">默认资源</span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt;"><span style="font-family: wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;">系统内存资源</span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt;"><span style="font-family: wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;">一般性的建议</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><strong><span style="font-family: 宋体;">显示内存</span><span lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal"><span style="font-family: 宋体;">为了使得资源可以利用显存，</span><span lang="EN-US">GPU</span><span style="font-family: 宋体;">需要通过内存访问定位他。</span><span lang="EN-US">GPU</span><span style="font-family: 宋体;">访问（</span><span lang="EN-US">Local video memory</span><span style="font-family: 宋体;">）显存是非常高效的，并且某些资源（例如</span><span lang="EN-US">RenderTarget</span><span style="font-family: 宋体;">，深度、模板缓冲）必须在本地显存（</span><span lang="EN-US">Local video memory</span><span style="font-family: 宋体;">）定位。由于</span><span lang="EN-US">AGP</span><span style="font-family: 宋体;">的出现，</span><span lang="EN-US">GPU</span><span style="font-family: 宋体;">可以直接访问部分系统内存，而这部分系统内存区域就是所谓的非本地显存（</span><span lang="EN-US">non-local video memory</span><span style="font-family: 宋体;">），当然这部分内存（显存）也是不能挪做它用的。非本地<span class="GramE">显存仅能</span>被</span><span lang="EN-US">GPU</span><span style="font-family: 宋体;">访问，与访问本地显存相比，其效率低一些。需要明确的是，所有</span><span lang="EN-US">AGP</span><span style="font-family: 宋体;">内存在设备丢失时都会失效，都需要在恢复他们。</span></p>
<p class="MsoNormal" style="text-align: center;" align="center"><span lang="EN-US"><img  src="http://www.sineysoft.com/article/imgs/d3d_rm1.jpg" v:shapes="_x0000_i1025" alt="" width="330" height="305"> </span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">一些集成显卡使用统一内存结构（</span><span lang="EN-US">Unified Memory Architecture</span><span style="font-family: 宋体;">），这样主内存可以被系统任何一个设备寻址。</span><span lang="EN-US">D3D</span><span style="font-family: 宋体;">支持</span><span lang="EN-US">UMA</span><span style="font-family: 宋体;">而不需要修改任何代码，这样我们把系统内存配置为本地显存，硬件确保资源的定位就像传统的结构一样进行工作。</span></p>
<p class="MsoNormal" style="text-align: center;" align="center"><span lang="EN-US"><img  src="http://www.sineysoft.com/article/imgs/d3d_rm2.jpg" v:shapes="_x0000_i1026" alt="" width="296" height="254"> </span></p>
<p class="MsoNormal"><strong><span style="font-family: 宋体;">受管资源</span><span lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal"><span style="font-family: 宋体;">大部分资源应该使用</span><span lang="EN-US">POOL_MANAGED</span><span style="font-family: 宋体;">方式创建，即受管资源。所有受管资源将被创建在系统内存，在需要的时候复制到显存。当发生设备丢失时会自动</span><span lang="EN-US">copy</span><span style="font-family: 宋体;">系统内存到显存。既然不是所有受管资源都需要一次送入显存，这样你可以提交超过渲染每帧所必须使用的最小内存容量，但是这样会使得<span class="GramE">大量显存内容</span>因为分<span class="GramE">页操作</span>而写到磁盘上，这是非常耗时的。这也是为什么恢复设备如此耗时，因为需要将大量磁盘数据复制到显存。</span></p>
<p class="MsoNormal"><span lang="EN-US">DX</span><span style="font-family: 宋体;">会为每份资源在最后一次使用时加上时间戳，这样<span class="GramE">当显存分配</span>失败时，它会释放那些最近最少使用的资源（</span><span lang="EN-US">LRU</span><span style="font-family: 宋体;">算法）。使用</span><strong><span lang="EN-US">SetPriority</span></strong><span style="font-family: 宋体;">函数可以标记资源的重要程度，重要的资源优于时间戳的判断，所以那些比较常用的资源应该设置高优先级，而不用担心因为时间戳过期而导致资源被释放。在</span><span lang="EN-US">DX9</span><span style="font-family: 宋体;">中，驱动程序提供的显存管理信息是非常有限的，运行时可能不得不清除大量资源用于分配足够的内存。设置适合的优先级是非常有用的，这样</span><span lang="EN-US">D3D</span><span style="font-family: 宋体;">不会清除那些马上又需要使用的资源。应用程序可以强制调用</span><strong><span lang="EN-US">EvictManagedResources</span></strong><span style="font-family: 宋体;">清除所有受管资源，但是如果下一帧又需要重新加载这些资源，这将是非常耗时的，不过这个函数在那些场景明显需要改变（比如进入下一个关卡）的情况下，还是非常有用的。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">如果&#8220;当前帧&#8221;内需要非常多资源用于渲染，这将是件麻烦的事情，用前面的</span><span lang="EN-US">LRU</span><span style="font-family: 宋体;">方式调度资源效率就不太理想了，这个时候使用</span><span lang="EN-US">MRU</span><span style="font-family: 宋体;">资源调度方式取代，即优先清理那些比较活跃的资源。注意，这里&#8220;当前帧&#8221;的概念是指</span><span lang="EN-US">BeginScene</span><span style="font-family: 宋体;">和</span><span lang="EN-US">EndScene</span><span style="font-family: 宋体;">之间的需要渲染的帧。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">开发人员如果想得到关于受管资源的更多信息，可以通过</span><strong><span lang="EN-US">IDirect3DQuery9</span></strong><span style="font-family: 宋体;">接口查询，但是这个接口仅能用于调试模式（</span><span lang="EN-US">debug runtimes</span><span style="font-family: 宋体;">），在发布版本中，应用程序不能依靠改接口的信息做任何假定。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">了解资源管理如何工作可以帮助我们调试、调整程序，重要的是应用程序不要太过依赖当前的运行库（或者驱动程序）的资源管理方式，驱动更新有可能导致其行为发生变化，将来的</span><span lang="EN-US">D3D</span><span style="font-family: 宋体;">将会有套久经考验的资源管理方式。</span></p>
<p class="MsoNormal"><strong><span style="font-family: 宋体;">驱动程序管理的资源</span><span lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal"><span lang="EN-US">D3D</span><span style="font-family: 宋体;">驱动可以自由的实现&#8220;由驱动管理贴图&#8221;的特性，通过</span><span lang="EN-US">D3DCAPS2_CANMANAGERESOURCE</span><span class="GramE"><span style="font-family: 宋体;">段可以</span></span><span style="font-family: 宋体;">查询硬件驱动是否支持这个特性，这样驱动将代替</span><span lang="EN-US">D3D</span><span style="font-family: 宋体;">运行库管理资源。<span class="GramE">对于级少数</span>的硬件是支持这个特性的，对于大多数硬件则不尽相同，你可以咨询你的产品提供商获得这方面信息。一般情况下，你可是使用</span><span lang="EN-US">D3DCREATE_DISABLE_DRIVER_MANAGEMENT</span><span style="font-family: 宋体;">方式创建设备，这样将由</span><span lang="EN-US">D3D</span><span style="font-family: 宋体;">运行库来管理资源。</span></p>
<p class="MsoNormal"><strong><span style="font-family: 宋体;">缺省资源管理（非受管资源）</span><span lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal"><span style="font-family: 宋体;">虽然受管资源非常简单，容易使用，高效，但是有时我们希望直接<span class="GramE">往显存里</span>写东西，这种情况下我们需要使用</span><span lang="EN-US">POOL_DEFAULT</span><span style="font-family: 宋体;">方式创建资源。使用这种方式会增加程序的复杂性，代码需要应付所有设备丢失的情况，并需要谨慎考虑何时复制数据到显存。错误的指定</span><span lang="EN-US">USAGE_WRITEONLY</span><span style="font-family: 宋体;">标记或者锁定渲染目标（</span><span lang="EN-US">Render Target</span><span style="font-family: 宋体;">）将严重影响性能。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">锁定</span><span lang="EN-US">POOL_DEFAULT</span><span style="font-family: 宋体;">类型的资源很可能导致</span><span lang="EN-US">GPU</span><span style="font-family: 宋体;">停止运转，这与</span><span lang="EN-US">POOL_MANAGED</span><span style="font-family: 宋体;">类型的资源是不同的，除非使用一些特性的指示标记。根据资源当前的位置不同，锁定后得到的指针也不相同，可能是一块临时的系统内存，也可能直接指向</span><span lang="EN-US">AGP</span><span style="font-family: 宋体;">内存。如果是临时的系统内存，</span><span lang="EN-US">Unlock</span><span style="font-family: 宋体;">后将把这段数据送入显存，这是因为如果显<span class="GramE">卡资源</span>不是只写的（</span><span lang="EN-US">write-only</span><span style="font-family: 宋体;">），</span><span lang="EN-US">Lock</span><span style="font-family: 宋体;">的时候数据将不得不被送入一段临时的内存；如果指向的</span><span lang="EN-US">AGP</span><span style="font-family: 宋体;">内存区域，临时的拷贝是可以避免的，但是</span><span lang="EN-US">cache</span><span style="font-family: 宋体;">的行为将会降低性能。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">为了避免在写入一整行数据（</span><span lang="EN-US">a full cache line of data</span><span style="font-family: 宋体;">）进入</span><span lang="EN-US">AGP</span><span style="font-family: 宋体;">内存<span class="GramE">区导致</span></span><span lang="EN-US">write-combing</span><span style="font-family: 宋体;">性能下降（一般是由于发生了一次读写周期），顺序的访问</span><span lang="EN-US">AGP</span><span style="font-family: 宋体;">内存是推荐的做法，如果你的程序需要随机的访问</span><span lang="EN-US">AGP</span><span style="font-family: 宋体;">内存，而你又不希望使用受管资源，那么你可以使用系统内存作为替代方案，这样当你生成了数据之后，可以</span><span lang="EN-US">lock</span><span style="font-family: 宋体;">后拷贝，这样不会带来太大的性能损失，这里的性能损失一般是由缓冲的&#8220;写搜索&#8221;操作引起。</span><span lang="EN-US">(</span><span style="font-family: 宋体;">注，这里关于词汇</span><span lang="EN-US">cache write-combing</span><span style="font-family: 宋体;">译者也不知道对应的中文含义，只能按照字面意思翻译，见谅</span><span lang="EN-US">)</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">对于某些类型的资源，使用</span><span lang="EN-US">LOCK_NOOVERWRITE</span><span style="font-family: 宋体;">标记会使添加数据比较有效率，但是多次的</span><span lang="EN-US">Lock</span><span style="font-family: 宋体;">，</span><span lang="EN-US">Unlock</span><span style="font-family: 宋体;">同一资源还是需要尽量避免的，适当的利用多种不同的锁定标记对于效率优化使非常重要的，就像填充锁定内存区域最好使用</span><span lang="EN-US">cache</span><span style="font-family: 宋体;">友好的（</span><span lang="EN-US">cache-friendly</span><span style="font-family: 宋体;">）数据访问方式一样。</span></p>
<p class="MsoNormal"><strong><span style="font-family: 宋体;">受管资源和缺省资源混合使用</span><span lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal"><span style="font-family: 宋体;">受管资源与非受管资源的混合分配使用可能导致显存碎块，并且扰乱受管资源使用的内存区域。最好在使用受管资源前使用非受管资源，或者使用受管资源后使用</span><span lang="EN-US">EvictManagedResources</span><span style="font-family: 宋体;">函数清除那些受管资源再使用非受管资源。记住，所有非受管资源都会常驻显存，这样其他内存需求就不能使用了。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">注意，与以往的</span><span lang="EN-US">DX</span><span style="font-family: 宋体;">版本不同，在显<span class="GramE">存缺乏</span>时，如果分配非受管资源失败，</span><span lang="EN-US">DX9</span><span style="font-family: 宋体;">会自动<span class="GramE">清除受</span>管资源，这有可能导致潜在的显存碎块，甚至把资源放入不适当的地方（比如非本地内存的静态贴图区）。所以，最好在使用受管资源之前分配全部的非受管资源。</span></p>
<p class="MsoNormal"><strong><span style="font-family: 宋体;">动态缺省资源</span><span lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal"><span style="font-family: 宋体;">如果数据需要很高频率更新，那最好使用非受管资源，并使用</span><span lang="EN-US">USAGE_DYNAMIC</span><span style="font-family: 宋体;">标记，这样驱动会决定最适合的地方放置这些需要经常更新的数据。这通常意味着放置在非本地显存中，这样对于</span><span lang="EN-US">GPU</span><span style="font-family: 宋体;">来说，访问速度可能相对要慢一些。而对于</span><span lang="EN-US">UMA</span><span style="font-family: 宋体;">架构，驱动将会选择</span><span lang="EN-US">CPU</span><span style="font-family: 宋体;">访问效率较高的特殊地方放置这些数据。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">这种用法（动态缺省资源类型）一般用于软蒙皮和基于</span><span lang="EN-US">CPU</span><span style="font-family: 宋体;">计算的粒子系统的顶点</span><span lang="EN-US">/</span><span style="font-family: 宋体;">顶点索引的</span><span lang="EN-US">Buffer</span><span style="font-family: 宋体;">填充，</span><span lang="EN-US">LOCK_DISCARD</span><span style="font-family: 宋体;">标记可以保证资源仍被使用的时候，锁定操作不会导致系统停止暂停工作。在这种情况下，使用受管资源会更新系统内存，然后拷贝到显存。对于系统的非本地内存，多余拷贝是不需要的。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">标准的贴图是不允许锁定的，仅仅可以通过</span><span lang="EN-US">UpdateSurface</span><span style="font-family: 宋体;">和</span><span lang="EN-US">UpdateTexture</span><span style="font-family: 宋体;">函数更新。一些系统支持动态贴图，它可以通过配合使用</span><span lang="EN-US">LOCK_DISCARD</span><span style="font-family: 宋体;">标记进行锁定，但这需要检查</span><span lang="EN-US">D3DCAPS2_DYNAMICTEXTURES</span><span style="font-family: 宋体;">硬件能力。对于高动态贴图（如视频、程序生成贴图），最好使用非受管资源和系统内存资源，并且通过</span><span lang="EN-US">UpdateTexture</span><span style="font-family: 宋体;">函数更新贴图。对于高频度的粒子更新，</span><span lang="EN-US">UpdateTexture</span><span style="font-family: 宋体;">函数可能是最好的选择。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">在有限的总线－内存带宽下，静态贴图资源应该使用</span><span lang="EN-US">POOL_MANAGED</span><span style="font-family: 宋体;">方式，这样可以确保它最好的利用本地显存，并有较好的效率。对于&#8220;半静态&#8221;资源，使用动态类型资源有时会获得更好的效率。</span></p>
<p class="MsoNormal"><strong><span style="font-family: 宋体;">系统内存资源</span><span lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal"><span style="font-family: 宋体;">资源可以使用</span><span lang="EN-US">POOL_SYSTEMMEM</span><span style="font-family: 宋体;">方式创建。但他们不能用于图形管线，他们仅能<span class="GramE">做为源数据</span>用于更新</span><span lang="EN-US">POOL_DEFAULT</span><span style="font-family: 宋体;">类型的资源，这是通过</span><span lang="EN-US">UpdateSurface</span><span style="font-family: 宋体;">和</span><span lang="EN-US">UpdateTexture</span><span style="font-family: 宋体;">函数完成的。他们的锁定操作也非常简单，尽管他们同样可能因为前面提到的原因导致系统停止运转。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">虽然是在系统内存中创建资源，但</span><span lang="EN-US">POOL_SYSTEMMEM</span><span style="font-family: 宋体;">所支持的资源格式和能力（比如最大尺寸）是受硬件、驱动限制的。同样是在系统内存中创建资源的</span><span lang="EN-US">POOL_SCRATCH</span><span style="font-family: 宋体;">则没有这方面限制，它支持所有格式和能力，但设备却不能直接访问它。</span><span lang="EN-US">SCRATCH</span><span style="font-family: 宋体;">类型资源一般用于内容创建工具。</span></p>
<p class="MsoNormal" style="text-align: center;" align="center"><span lang="EN-US"><img  src="http://www.sineysoft.com/article/imgs/d3d_rm3.jpg" v:shapes="_x0000_i1027" alt="" width="398" height="363"> </span></p>
<p class="MsoNormal"><strong><span style="font-family: 宋体;">一般性的建议</span><span lang="EN-US"><o:p></o:p></span></strong></p>
<p class="MsoNormal"><span style="font-family: 宋体;">了解资源管理的技术实现细节对达成你的程序的性能目标是有非常大的帮助的，规划你的资源如何交给</span><span lang="EN-US">D3D</span><span style="font-family: 宋体;">并设计好的结构以便能及时加载必要的数据是一件非常复杂的工作，为此我们给出一些好的实践经验<span class="GramE">做为</span>一般性的原则：</span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt;"><span style="font-family: wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;">预处理你的资源。不要将耗时的加载资源、资源转换、资源优化丢给用户去做，虽然这样便于开发，但确让用户无法忍受。预处理这些资源可以加快加载，更快使用，你的用户也会发现你的程序跑的更快了。</span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt;"><span style="font-family: wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;">避免在每帧创建过多的资源。对于过多的资源加载，可以把他们分到<span class="GramE">多帧里完成</span>或者不要急于释放那些暂时不用的资源。</span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt;"><span style="font-family: wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;">确保在一帧结束时已经断开了所有资源通道。（比如，顶点流，</span><span lang="EN-US">texture stages</span><span style="font-family: 宋体;">，顶点索引）。</span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt;"><span style="font-family: wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;">对于贴图，建议使用压缩贴图（</span><span lang="EN-US">DXTn</span><span style="font-family: 宋体;">）格式，建议使用</span><span lang="EN-US">mip-map</span><span style="font-family: 宋体;">或者将小贴图拼接为大贴图使用。</span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt;"><span style="font-family: wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;">建议使用顶点索引，这将减少数据传输量。</span></p>
<p class="MsoNormal" style="margin-left: 21pt; text-indent: -21pt;"><span style="font-family: wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;">对于过渡的优化资源管理是需要谨慎的。如果你的程序过分依赖驱动、硬件和操作系统的某些特征，那么这些程序、硬件的修改将会导致潜在的性能问题。</span></p>
</div><img src ="http://www.cppblog.com/richardhe/aggbug/69204.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-12-11 18:58 <a href="http://www.cppblog.com/richardhe/articles/69204.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>D3D中的渲染到纹理</title><link>http://www.cppblog.com/richardhe/articles/63853.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Mon, 13 Oct 2008 01:15:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/63853.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/63853.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/63853.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/63853.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/63853.html</trackback:ping><description><![CDATA[渲染到纹理是D3D中的一项高级技术。一方面，它很简单，另一方面它很强大并能产生很多特殊效果。
比如说发光效果，环境映射，阴影映射，都可以通过它来实现。渲染到纹理只是渲染到表面的一个延伸。我们只需再加些东西就可以了。首先，我们要创造一个纹
理，并且做好一些防范措施。第二步我们就可以把适当的场景渲染到我们创建的纹理上了。然后，我们把这个纹理用在最后的渲染上。<br>　　?main.cpp<br>　　首先我们得声明所需要的对象。当然我们需要一张用来渲染的纹理。此外，我们还需要两个Surface对象。一个是用来存储后台缓冲区，一个用来当纹理的渲染对象。后面我再详细介绍它们。另外我们还需要两个矩阵，一个是用来当纹理的投影矩阵，另一个是存储原来的矩阵。<br>　　LPDIRECT3DTEXTURE9 pRenderTexture = NULL;<br>　　LPDIRECT3DSURFACE9 pRenderSurface = NULL,pBackBuffer = NULL;<br>　　D3DXMATRIX matProjection,matOldProjection;<br>
现在我们来创建纹理。前两个参数是纹理的宽度和高度，第三个参数是纹理的多级渐进纹理序列参数，在这里是设为1，第四个参数非常重要而且必须设为
D3DUSAGE_RENDERTARGET，表明我们所创建的纹理是用来渲染的。剩下的参数就是指纹理格式，顶点缓冲区的内存位置，和一个指向纹理的指
针。当纹理是用来当渲染对象时，顶点缓冲区的内存位置必须设为D3D_DEFAILT。<br>　　g_App.GetDevice()-&gt;CreateTexture(256,256,1,D3DUSAGE_RENDERTARGET,D3DFMT_R5G6B5,D3DPOOL_DEFAULT,&amp;pRenderTexture,NULL);<br>
为了访问纹理内存对象，我们需要一个Surface对象，因为D3D中的纹理是用这样的一个Surface来存储纹理数据的。为了得到纹理表面的
Surface,我们需要调用方法GetSurfaceLevel() 。第一个参数我们设为0，第二个参数为一个指向surface对象的指针。<br>　　pRenderTexture-&gt;GetSurfaceLevel(0,&amp;pRenderSurface);<br>　　下一步就是创建一个适合纹理维数的投影矩阵，因为纹理的横纵比和后台缓冲区的不一样。<br>　　D3DXMatrixPerspectiveFovLH(&amp;matProjection,D3DX_PI / 4.0f,1,1,100);<br>　　在我们的循环渲染之前，我们必须保存后台缓冲区和它的投影矩阵。<br>　　g_App.GetDevice()-&gt;GetTransform(D3DTS_PROJECTION,&amp;matOldProjection);<br>　　g_App.GetDevice()-&gt;GetRenderTarget(0,&amp;pBackBuffer);<br>
渲染循环函数可以分为两个部分。第一部分是渲染到纹理的过程。因此，渲染对象必须设为纹理表面。然后我们就可以把东西渲染到这个对象上了。渲染到另一个
表面上和正常地渲染到后台缓冲区差不多。只有一点不同，那就是先不调用Prensent（）函数，因为纹理上的内容并不需要显示在屏幕上。象平时一样，我
们先要重置表面颜色缓冲区，并且调用BeginSence()和EndSence()方法。为了能够适当的渲染，我们必须设置和纹理表面相符的投影矩阵。
否则最后的图象可能被扭曲<br>　　//render-to-texture<br>　　g_App.GetDevice()-&gt;SetRenderTarget(0,pRenderSurface); //set new render target<br>　　g_App.GetDevice()-&gt;Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_X#646464,1.0f,0); //clear texture<br>　　g_App.GetDevice()-&gt;BeginScene();<br>　　g_App.GetDevice()-&gt;SetTexture(0,pPyramideTexture);<br>　　D3DXMatrixRotationY(&amp;matRotationY,fRotation);<br>　　D3DXMatrixTranslation(&amp;matTranslation,0.0f,0.0f,5.0f);<br>　　g_App.GetDevice()-&gt;SetTransform(D3DTS_WORLD,&amp;(matRotationY * matTranslation));<br>　　g_App.GetDevice()-&gt;SetTransform(D3DTS_PROJECTION,&amp;matProjection); //set projection matrix<br>　　g_App.GetDevice()-&gt;SetStreamSource(0,pTriangleVB,0,sizeof(D3DVERTEX));<br>　　g_App.GetDevice()-&gt;DrawPrimitive(D3DPT_TRIANGLELIST,0,4);<br>　　g_App.GetDevice()-&gt;EndScene();<br>　　渲染循环的第二部分就是渲染最后场景的过程（也就是显示到屏幕上的过程）。渲染对象重新设为后台缓冲区，投影矩阵重新设为原来的投影矩阵。由于纹理已经准备好了，所以它和纹理层0相关联。<br>　　//render scene with texture<br>　　g_App.GetDevice()-&gt;SetRenderTarget(0,pBackBuffer); //set back buffer<br>　　g_App.GetDevice()-&gt;Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_X#000000,1.0f,0);<br>　　g_App.GetDevice()-&gt;BeginScene();<br>　　g_App.GetDevice()-&gt;SetTexture(0,pRenderTexture); //set rendered texture<br>　　g_App.GetDevice()-&gt;SetTransform(D3DTS_WORLD,&amp;matTranslation);<br>　　g_App.GetDevice()-&gt;SetTransform(D3DTS_PROJECTION,&amp;matOldProjection); //restore projection matrix<br>　　g_App.GetDevice()-&gt;SetStreamSource(0,pQuadVB,0,sizeof(D3DVERTEX));<br>　　g_App.GetDevice()-&gt;DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);<br>　　g_App.GetDevice()-&gt;EndScene();<br>　　g_App.GetDevice()-&gt;Present(NULL,NULL,NULL,NULL);<br>　　最后我们通过调用Release()方法释放Surface对象。<br>　　pRenderSurface-&gt;Release();<br>　　pRenderSurface = NULL;<br>　　pBackBuffer-&gt;Release();<br>　　pBackBuffer = NULL;<br>　　渲染到纹理能让你做很多事情，但是你必须注意一些限制。首先深度缓冲区必须总是大于或等于渲染对象的大小。此外，渲染对象和深度缓冲区的格式必须一致。<img src ="http://www.cppblog.com/richardhe/aggbug/63853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-10-13 09:15 <a href="http://www.cppblog.com/richardhe/articles/63853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏中汉字显示的实现与技巧</title><link>http://www.cppblog.com/richardhe/articles/63851.html</link><dc:creator>RichardHe</dc:creator><author>RichardHe</author><pubDate>Mon, 13 Oct 2008 01:12:00 GMT</pubDate><guid>http://www.cppblog.com/richardhe/articles/63851.html</guid><wfw:comment>http://www.cppblog.com/richardhe/comments/63851.html</wfw:comment><comments>http://www.cppblog.com/richardhe/articles/63851.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/richardhe/comments/commentRss/63851.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/richardhe/services/trackbacks/63851.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 游戏中汉字显示的实现与技巧[ZZ]作者：炎龙工作室 千里马肝版本：v1.0最后更新日期：2002-3-30绪言在游戏中，因为我们是中国人麻，通常都需要显示汉字，比方说交待剧情。而对于文字的显示，英文的显示要较其简单得多，因为只有26个字母，就算再加一些标点、符号什么的，用一张位图，就可以足以显示所有的单词了，而相关实现技巧，也比较轻松。而中文的显示方法，要复杂得...&nbsp;&nbsp;<a href='http://www.cppblog.com/richardhe/articles/63851.html'>阅读全文</a><img src ="http://www.cppblog.com/richardhe/aggbug/63851.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/richardhe/" target="_blank">RichardHe</a> 2008-10-13 09:12 <a href="http://www.cppblog.com/richardhe/articles/63851.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>