<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>西瓜田 &#187; DirectX</title>
	<atom:link href="http://blog.thpiano.com/?feed=rss2&#038;tag=directx" rel="self" type="application/rss+xml" />
	<link>http://blog.thpiano.com</link>
	<description>无复洛城东</description>
	<lastBuildDate>Tue, 19 Jan 2021 03:54:37 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.4.2</generator>
		<item>
		<title>[转载]为DrawPrimitiveUP(DrawUserPrimitive)洗冤</title>
		<link>http://blog.thpiano.com/?p=133</link>
		<comments>http://blog.thpiano.com/?p=133#comments</comments>
		<pubDate>Thu, 27 Oct 2011 13:49:39 +0000</pubDate>
		<dc:creator>suika</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[DirectX]]></category>

		<guid isPermaLink="false">http://172.18.126.172/blog/?p=133</guid>
		<description><![CDATA[在做D3D画线时，处理顶点缓冲发现的问题！所以转一下 最初只因DXSDK文档里说了句推荐用Vertex Buffer而不要用DrawPrimitiveUP（C#里叫DrawUserPrimitive），DrawPrimitiveUP很快被描绘成传说 中的瘟疫，人人都在警告不要接近它。估计有人会想过，既然DrawPrimitiveUP这么不好，为什么还要提供它，难道只是为了显示DX也可以像 OpenGL一样简单地画三角形？ 记得当年我就是抱着这种想法在网上狂搜，功夫不负有心人，还真找到了。不过看了很不好意思，人家上来就批判不实际测试、以讹传讹的问题，我也比较懒，没动手测一下。那么为了和我一样的懒人，我把问题用中文解释一遍。 首 先，DrawPrimitiveUP内部其实就是一个dynamic vertex buffer（动态顶点缓冲），和我们自己实现一个动态顶点缓冲没区别。一般情况下，DrawPrimitiveUP和用动态顶点缓冲的效率也没多大区 别。也就是说DrawPrimitiveUP其实很高效的，而且简单易用。Irrlicht引擎几乎所有绘制都用的DrawPrimitiveUP，也很 快的。 那为什么不推荐用？ 原因一：DX8发布时显存容量已经有了很大提高，静态顶点缓冲可以缓存在显存或AGP内存里，从而节省带宽占用。所以推荐能用静态顶点缓冲的一定要用静态的。静态的可以比DrawPrimitiveUP和动态顶点缓冲都快很多。 原 因二：DrawPrimitiveUP相对动态顶点缓冲而言，需要将用户内存里的顶点数据复制到内部动态顶点缓冲，即多了一次复制，如果顶点数量较大，复 制开销也会加大。但很多程序里的动态缓冲设计并不太好，为了抽象或方便使用，也会复制一次数据。所以便丧失了这条优势。 原因三：这个比较 复杂，我们知道一帧内Batch（批）的数量直接影响CPU的占用率，1G处理器30FPS下每帧700Batch左右就会占用100%CPU。每个设置 设备状态到发出绘制命令的转换都将产生一个Batch。动态顶点缓冲的推荐使用模式是一个可以合并Batch的模式，即不断地填充顶点数据，但不立刻绘 制，在缓冲填满时才提交绘制一次，当然能合并的前提是各个batch都使用相同的设备状态，即纹理、材质、RenderStates、变换矩阵等。 原因四：DrawPrimitiveUP只支持一个顶点流。这其实是个不算是原因的原因。当然是只用一个顶点流时才用它。 综上所述，这其实是个优化问题，用动态顶点缓冲有可能做更多的优化，但如果做得不好，会比DrawPrimitiveUP差。如果正确使用了，但没有进一步的优化或者引擎的用法不具备可优化的特性，那么也就和DrawPrimitiveUP效率相当。 但 事实上用动态顶点缓冲做错了的也很多，最常见的就是没有正确使用Lock标志位，用锁定静态缓冲的方法锁定，根本得不到动态缓冲的效果。另外用C#和 MDX的，如果用返回数组的Lock方法重载，也完全没有意义，因为在内部整个缓冲被复制到数组，Unlock时再复制回去。即使用 GraphicsStream写顶点数据也很慢，因为会导致大量的Boxing，只有直接用指针写数据才能发挥动态缓冲的优势。 怎么才算做得好，DXSDK里有明确的样例，为了懒人，我帖出来： // 用法 1 // 每次绘制抛弃整个顶点缓冲内容并重新填充几千个顶点 // 可能包含多个物体，有可能需要按设备状态分几次DrawPrimitive // 计算需要填充的字节数 UINT nSizeOfData = nNumberOfVertices * m_nVertexStride; // 抛弃并重新填充 CONST DWORD dwLockFlags = D3DLOCK_DISCARD; // 锁定顶点缓冲内存 BYTE* pBytes; if( [...]]]></description>
			<content:encoded><![CDATA[<p>在做D3D画线时，处理顶点缓冲发现的问题！所以转一下</p>
<p>最初只因DXSDK文档里说了句推荐用Vertex Buffer而不要用DrawPrimitiveUP（C#里叫DrawUserPrimitive），DrawPrimitiveUP很快被描绘成传说 中的瘟疫，人人都在警告不要接近它。估计有人会想过，既然DrawPrimitiveUP这么不好，为什么还要提供它，难道只是为了显示DX也可以像 OpenGL一样简单地画三角形？<span id="more-133"></span></p>
<p>记得当年我就是抱着这种想法在网上狂搜，功夫不负有心人，还真找到了。不过看了很不好意思，人家上来就批判不实际测试、以讹传讹的问题，我也比较懒，没动手测一下。那么为了和我一样的懒人，我把问题用中文解释一遍。</p>
<p>首 先，DrawPrimitiveUP内部其实就是一个dynamic vertex buffer（动态顶点缓冲），和我们自己实现一个动态顶点缓冲没区别。一般情况下，DrawPrimitiveUP和用动态顶点缓冲的效率也没多大区 别。也就是说DrawPrimitiveUP其实很高效的，而且简单易用。Irrlicht引擎几乎所有绘制都用的DrawPrimitiveUP，也很 快的。</p>
<p>那为什么不推荐用？</p>
<p>原因一：DX8发布时显存容量已经有了很大提高，静态顶点缓冲可以缓存在显存或AGP内存里，从而节省带宽占用。所以推荐能用静态顶点缓冲的一定要用静态的。静态的可以比DrawPrimitiveUP和动态顶点缓冲都快很多。</p>
<p>原 因二：DrawPrimitiveUP相对动态顶点缓冲而言，需要将用户内存里的顶点数据复制到内部动态顶点缓冲，即多了一次复制，如果顶点数量较大，复 制开销也会加大。但很多程序里的动态缓冲设计并不太好，为了抽象或方便使用，也会复制一次数据。所以便丧失了这条优势。</p>
<p>原因三：这个比较 复杂，我们知道一帧内Batch（批）的数量直接影响CPU的占用率，1G处理器30FPS下每帧700Batch左右就会占用100%CPU。每个设置 设备状态到发出绘制命令的转换都将产生一个Batch。动态顶点缓冲的推荐使用模式是一个可以合并Batch的模式，即不断地填充顶点数据，但不立刻绘 制，在缓冲填满时才提交绘制一次，当然能合并的前提是各个batch都使用相同的设备状态，即纹理、材质、RenderStates、变换矩阵等。</p>
<p>原因四：DrawPrimitiveUP只支持一个顶点流。这其实是个不算是原因的原因。当然是只用一个顶点流时才用它。</p>
<p>综上所述，这其实是个优化问题，用动态顶点缓冲有可能做更多的优化，但如果做得不好，会比DrawPrimitiveUP差。如果正确使用了，但没有进一步的优化或者引擎的用法不具备可优化的特性，那么也就和DrawPrimitiveUP效率相当。</p>
<p>但 事实上用动态顶点缓冲做错了的也很多，最常见的就是没有正确使用Lock标志位，用锁定静态缓冲的方法锁定，根本得不到动态缓冲的效果。另外用C#和 MDX的，如果用返回数组的Lock方法重载，也完全没有意义，因为在内部整个缓冲被复制到数组，Unlock时再复制回去。即使用 GraphicsStream写顶点数据也很慢，因为会导致大量的Boxing，只有直接用指针写数据才能发挥动态缓冲的优势。</p>
<p>怎么才算做得好，DXSDK里有明确的样例，为了懒人，我帖出来：<br />
// 用法 1<br />
// 每次绘制抛弃整个顶点缓冲内容并重新填充几千个顶点<br />
// 可能包含多个物体，有可能需要按设备状态分几次DrawPrimitive</p>
<p>// 计算需要填充的字节数<br />
UINT nSizeOfData = nNumberOfVertices * m_nVertexStride;</p>
<p>// 抛弃并重新填充<br />
CONST DWORD dwLockFlags = D3DLOCK_DISCARD;</p>
<p>// 锁定顶点缓冲内存<br />
BYTE* pBytes;<br />
if( FAILED( m_pVertexBuffer-&gt;Lock( 0, 0, &amp;pBytes, dwLockFlags ) ) )<br />
return false;</p>
<p>// 将顶点数据复制到顶点缓冲<br />
memcpy( pBytes, pVertices, nSizeOfData );<br />
m_pVertexBuffer-&gt;Unlock();</p>
<p>// 绘制<br />
m_pDevice-&gt;DrawPrimitive( D3DPT_TRIANGLELIST, 0, nNumberOfVertices/3)</p>
<p>// 用法 2<br />
// 对多个物体复用一个顶点缓冲</p>
<p>// 计算需要填充的字节数<br />
UINT nSizeOfData = nNumberOfVertices * m_nVertexStride;</p>
<p>// 如果顶点缓冲内的剩余空间可以容纳要填充的顶点数量，则指定不覆盖原有数据<br />
DWORD dwLockFlags = D3DLOCK_NOOVERWRITE;</p>
<p>// 检查顶点缓冲空间是否用光<br />
if( m_nNextVertexData &gt; m_nSizeOfVB - nSizeOfData )<br />
{<br />
// 没有足够的空间，抛弃原有数据重新开始<br />
dwLockFlags = D3DLOCK_DISCARD;<br />
m_nNextVertexData = 0;<br />
}</p>
<p>// 锁定顶点缓冲内存<br />
BYTE* pBytes;<br />
if( FAILED( m_pVertexBuffer-&gt;Lock( (UINT)m_nNextVertexData, nSizeOfData,<br />
&amp;pBytes, dwLockFlags ) ) )<br />
return false;</p>
<p>// 将顶点数据复制到顶点缓冲<br />
memcpy( pBytes, pVertices, nSizeOfData );<br />
m_pVertexBuffer-&gt;Unlock();</p>
<p>// 绘制<br />
m_pDevice-&gt;DrawPrimitive( D3DPT_TRIANGLELIST,<br />
m_nNextVertexData/m_nVertexStride, nNumberOfVertices/3)</p>
<p>// 计算下一次的写入位置<br />
m_nNextVertexData += nSizeOfData;</p>
<p>当 然，这只是个正确用法样例，优化起来可还是会面目全非的。如果你的D3D功夫不够剑豪剑圣级别，大可安心地用DrawPrimitiveUP，对付一些杂 碎三角面，也大可不必杀鸡用牛刀，用DrawPrimitiveUP剁几下就行了。另外注意测试的时候一定要用硬件模式测，软件模式的结果是完全不同的。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.thpiano.com/?feed=rss2&#038;p=133</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Day 8235 生日快乐！</title>
		<link>http://blog.thpiano.com/?p=116</link>
		<comments>http://blog.thpiano.com/?p=116#comments</comments>
		<pubDate>Mon, 24 Oct 2011 16:55:34 +0000</pubDate>
		<dc:creator>suika</dc:creator>
				<category><![CDATA[日常流水账]]></category>
		<category><![CDATA[DirectX]]></category>
		<category><![CDATA[合唱]]></category>
		<category><![CDATA[图像]]></category>
		<category><![CDATA[生日]]></category>
		<category><![CDATA[舍友]]></category>

		<guid isPermaLink="false">http://localhost/blog/?p=116</guid>
		<description><![CDATA[今日是舍友强哥生日，强哥请我们晚上去川菜店小撮一顿； 到场的除了舍友、四位老男孩之外，还有一直收我作业的“课代表”、对门的超级低调牛人、以及一位担任学生会要职的女同学，共8人。 真好啊，即使是刚到异乡，过生日也不愁组不起人来。 刘同学还特地买了好看的蛋糕，意外地贵（88元），真是热心肠的好兄弟 饭桌上倒是没怎么喝酒，强哥更是一口气把蜡烛吹倒，大家的讨论也很火热。在饭桌上观察到了舍友的另一面，领略了其不凡之处；除去这顿饭不提，也已经很有收获了。 &#160; 回来的路上还兴起了给班里的大家都建个生日表的想法，但是一方面有些人可能觉得生日是秘密不想说，另一方面又不知道哪些同学过阴历生日，所以只好暂时作罢 至于我的生日……我是绝对不会让别人发觉我过生日的。 ================================================================== 今天班里组织了合唱练习，文体委员的职位由槟榔同学接替了。气场并不是特别出众，但是站在讲台上一直微笑着面对大家，效果意外地好！ 再加上专门租用教室，很安静，槟榔同学也有适当的提醒和调整，唱完之后观察到大家都情不自禁地为自己鼓掌（当然观察者没有这么做）。今天的这种程度，对比起原来的窘况，真是让人感叹“只要稍微有个人带领我们努力下就可以很像样了啊”。可惜这首曲子不适合钢琴演奏 ================================================================== 今天时间有些零碎，不知为何没有按照预定计划去做事情，反而是浪费在了无所谓的事情上。 其实就是各种方法画直线的效率比较，与上午相比，加入了directx（我总算对顶点有稍微一点了解了）。结果是： D3D画100000条（只更新一次顶点缓冲，重复部分只有DrawPrimitive）：0.125秒 D3D画100000条（每次都重新更新顶点缓冲）：0.685秒 GDI画100000条：0.875秒 SetPixel画1000条（这个实在太慢了所以只画1000条）：0.891秒 Bitmap画100000条：0.078秒 GDI+我就不用测试了，比GDI要龟得多，但是也不至于比SetPixel慢； SetPixel之所以龟到要命，因为每次调用都要入栈出栈 看上去Bitmap胜利啊，其实是因为这毫无比较可言。 因为不同的情况下，你的循环所加的地方不同。在测试里，Bitmap实际上的循环部分就是内存操作，当然快了； &#160; D3D的话则额外做了一次清屏，然后用3D里的DrawPrimitive来画的（虽然我已经调成RHW了保证模拟2D效率，但是估计还是用不上硬件加速，用不上的话自然比不过Bitmap咯） 于是又去翻DirectDraw，不过可惜太晚咯，只是稍微看了一下DirectDraw的写法。感觉和GDI几乎一模一样嘛！ 感觉主要是提供了硬件加速，直接操作显存，还有诸如blt方面的提升等等；但是如果开不了HAL，实际上就和GDI一模一样吧（本身也和GDI兼容的） 太晚了得去睡了。 &#160; 啊最重要的话一定要在睡前写下来： 像我这样每天漫无目的地碰碰dx、ddw之类无关事物的皮毛，又写些没人看的日志，真的适合我么？难道你们不觉得这应该是四年前的我做的事情么……]]></description>
			<content:encoded><![CDATA[<p>今日是舍友强哥生日，强哥请我们晚上去川菜店小撮一顿；</p>
<p>到场的除了舍友、四位老男孩之外，还有一直收我作业的“课代表”、对门的超级低调牛人、以及一位担任学生会要职的女同学，共8人。</p>
<p>真好啊，即使是刚到异乡，过生日也不愁组不起人来。</p>
<p>刘同学还特地买了好看的蛋糕，意外地贵（88元），真是热心肠的好兄弟</p>
<p>饭桌上倒是没怎么喝酒，强哥更是一口气把蜡烛吹倒，大家的讨论也很火热。在饭桌上观察到了舍友的另一面，领略了其不凡之处；除去这顿饭不提，也已经很有收获了。</p>
<p>&nbsp;</p>
<p>回来的路上还兴起了给班里的大家都建个生日表的想法，但是一方面有些人可能觉得生日是秘密不想说，另一方面又不知道哪些同学过阴历生日，所以只好暂时作罢</p>
<p>至于我的生日……我是绝对不会让别人发觉我过生日的。<span id="more-116"></span></p>
<p>==================================================================</p>
<p>今天班里组织了合唱练习，文体委员的职位由槟榔同学接替了。气场并不是特别出众，但是站在讲台上一直微笑着面对大家，效果意外地好！</p>
<p>再加上专门租用教室，很安静，槟榔同学也有适当的提醒和调整，唱完之后观察到大家都情不自禁地为自己鼓掌（当然观察者没有这么做）。今天的这种程度，对比起原来的窘况，真是让人感叹“只要稍微有个人带领我们努力下就可以很像样了啊”。可惜这首曲子不适合钢琴演奏</p>
<p>==================================================================</p>
<p>今天时间有些零碎，不知为何没有按照预定计划去做事情，反而是浪费在了无所谓的事情上。</p>
<p>其实就是各种方法画直线的效率比较，与上午相比，加入了directx（我总算对顶点有稍微一点了解了）。结果是：</p>
<p>D3D画100000条（只更新一次顶点缓冲，重复部分只有DrawPrimitive）：0.125秒</p>
<p>D3D画100000条（每次都重新更新顶点缓冲）：0.685秒</p>
<p>GDI画100000条：0.875秒</p>
<p>SetPixel画1000条（这个实在太慢了所以只画1000条）：0.891秒</p>
<p>Bitmap画100000条：0.078秒</p>
<p>GDI+我就不用测试了，比GDI要龟得多，但是也不至于比SetPixel慢；</p>
<p>SetPixel之所以龟到要命，因为每次调用都要入栈出栈</p>
<p>看上去Bitmap胜利啊，其实是因为这毫无比较可言。</p>
<p>因为不同的情况下，你的循环所加的地方不同。在测试里，Bitmap实际上的循环部分就是内存操作，当然快了；</p>
<p>&nbsp;</p>
<p>D3D的话则额外做了一次清屏，然后用3D里的DrawPrimitive来画的（虽然我已经调成RHW了保证模拟2D效率，但是估计还是用不上硬件加速，用不上的话自然比不过Bitmap咯）</p>
<p>于是又去翻DirectDraw，不过可惜太晚咯，只是稍微看了一下DirectDraw的写法。感觉和GDI几乎一模一样嘛！</p>
<p>感觉主要是提供了硬件加速，直接操作显存，还有诸如blt方面的提升等等；但是如果开不了HAL，实际上就和GDI一模一样吧（本身也和GDI兼容的）</p>
<p>太晚了得去睡了。</p>
<p>&nbsp;</p>
<p>啊最重要的话一定要在睡前写下来：</p>
<p>像我这样每天漫无目的地碰碰dx、ddw之类无关事物的皮毛，又写些没人看的日志，真的适合我么？难道你们不觉得这应该是四年前的我做的事情么……</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.thpiano.com/?feed=rss2&#038;p=116</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
