??xml version="1.0" encoding="utf-8" standalone="yes"?>久久精品中文无码资源站,精品久久久久久亚洲精品 ,精品国际久久久久999波多野http://www.shnenglu.com/lingjingqiu/archive/2014/01/14/205354.htmlI明{I明{Tue, 14 Jan 2014 02:07:00 GMThttp://www.shnenglu.com/lingjingqiu/archive/2014/01/14/205354.htmlhttp://www.shnenglu.com/lingjingqiu/comments/205354.htmlhttp://www.shnenglu.com/lingjingqiu/archive/2014/01/14/205354.html#Feedback6http://www.shnenglu.com/lingjingqiu/comments/commentRss/205354.htmlhttp://www.shnenglu.com/lingjingqiu/services/trackbacks/205354.html

I明{ 2014-01-14 10:07 发表评论
]]>
SALVIA 0.5.2优化?/title><link>http://www.shnenglu.com/lingjingqiu/archive/2013/02/11/197800.html</link><dc:creator>I明{</dc:creator><author>I明{</author><pubDate>Mon, 11 Feb 2013 12:09:00 GMT</pubDate><guid>http://www.shnenglu.com/lingjingqiu/archive/2013/02/11/197800.html</guid><wfw:comment>http://www.shnenglu.com/lingjingqiu/comments/197800.html</wfw:comment><comments>http://www.shnenglu.com/lingjingqiu/archive/2013/02/11/197800.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.shnenglu.com/lingjingqiu/comments/commentRss/197800.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lingjingqiu/services/trackbacks/197800.html</trackback:ping><description><![CDATA[<h1>梗概</h1> <p>SALVIA 0.5.2 的优化经历是一个“跌宕v伏”的q程。这个过E的l果很简单:(x)</p> <p>在Core 2 Duo T5800(2.0GHz x 2)上,Sponza的性能提升?0%QComplexMesh性能提升?6%?/p> <h1> </h1> <h1>背景</h1> <p>SALVIA的整个渲染流E主要是以下几部分:(x)</p> <ul> <li>Ҏ(gu)Index Buffer获得需要进行变换的点Q?/li> <li>顶点利用Vertex Shaderq行变换Q?/li> <li>变换后的顶点,输出成若q个float4Q?/li> <li>三角Ş光栅化。SALVIA的光栅化是将三角形拆分成4x4的像素块若干Q不满的块有掩码来处理;</li> <li>像素进行插|</li> <li>插完值后把像素送到Pixel Shader中处理一;</li> <li>处理完的l果用Blend Shader塞到Back buffer里面厅R?/li></ul> <p>用于试的场景:(x)</p> <ul> <li>Sponza 26万个面,20个左右的DiffuseU理Q?024x1024Q;</li> <li>PartOfSponza U?00个面Q?个DiffuseU理Q?024x1024Q;</li> <li>ComplexMesh 两万个面Q无U理Q有个能量保守的光照?/li></ul> <p>最初的版本QV1231Q中Q性能的主要瓶颈在插值阶D,各种耗时林林Ld?jin)一半以上(50% - 70%Q?/p> <p>相比之下其他阶段Ҏ(gu)能的媄(jing)响要么有限,要么没有多少优化I间。所以最q一周的优化Q就都集中在?jin)“插值”上?/p> <h1> </h1> <h1>插值算?/h1> <p><strong>U性的插值算?/strong>常见的实现有两种Q?/p> <p>W一U是拿UV插|W二U是用ddx和ddy累积?/p> <p>UV是先计算像素的u和vQ基本方法是用面U比Q不记得复?fn)一下中学几何吧Q,然后用插值公式:(x)</p> <p>pixel = v0 * u + v1 * v + v2 * (1-u-v)</p> <p>后者的步骤是选一个主点Q然后计这个顶点的ddx和ddyQ最后用</p> <p>pixel = v0 + ddx * offset_x + ddy * offset_y</p> <p>计算出相应顶炏V?/p> <p>但是在图形学中,我们q需要对插D行透视修正Q获得在3DI间中线性的插值结果?/p> <p>我们步骤修正到<strong>透视I间</strong>Q?/p> <p>先将v0Qv1Qv2弄到透视I间中,变成projected_v0, projected_v1, projected_v2</p> <p>对于UV的插值是</p> <p>pixel = ( projected_v0*u + projected_v1*v + projected_v2 * (1-u-v) ) / pixel_w</p> <p>对于用ddx和ddy的篏U公式是Q?/p> <p>pixel = ( projected_v0 + projected_ddx * offset_x + projected_ddy * offset_y ) / pixel_w</p> <h1> </h1> <h1>插值算法的选择</h1> <p>何咏QGraphixerQ大之前也写了(jin)一个渲染器Q比我快许多Q大概是4-6倍)(j)Q用的是UVQ?/p> <p>gameKnife大神两个C拜写成的渲染器Q速度比我用五q写出来的半成品要快7倍,用的办法是Lerp到Scanline上,再Lerp到像素?/p> <p>SALVIA采用?jin)篏U法Q?/p><pre class="brush: cpp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;">struct transformed_vertex { float4 attributes[MAX_ATTRIBUTE_COUNT]; };</pre><pre class="brush: cpp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;">transformed_vertex projected_corner; // 计算角点的坐? projected_scanline_start = projected_v0 + projected_ddx * offset_x + projected_ddy * offset_y; // 像素的透视修正? float inv_w; // 最l输出的4x4个像? pixel_input px_in[4][4]; for(int i = 0; i < 4; ++i) { projected_pixel = projected_scanline_start; for(int j = 0; j < 4; ++j) { // 透视I间转换到线性空间ƈ输出到px_in? px_in[i][j] = unproject( projected_pixel ); // 累加x方向上的|透视I间Q? projected_pixel += projected_ddx; } // 累加y方向上的|透视I间Q? projected_scanline_start += projected_ddy; }</pre> <h1> </h1> <h1>本轮优化之前Ҏ(gu)值算法的优化试</h1> <p>注意那个MAX_ATTRIBUTE_COUNTQ这个值通常比较大,在v1231中,它是32?/p> <p>不过Q显然我们不需要对所有的属性进行计。敏敏在q里q用?jin)一点小的技巧进行了(jin)优化Q只计算必要的属性。同ӞZ(jin)减少分支的用,他甚至用</p><pre class="brush: cpp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;">template <int N> void sub_n(out, v0, v1 ) { for(int i = 0; i < N; ++i) { out.attributes[i] = v0.attributes[i] ?v1.attributes[i]; } }</pre> <p>q合函数指针的Ҏ(gu)Q以?j)ɾ~译器展开循环Q减分支?/p> <p>不过从实际生成的汇编来看Q这个部分ƈ没有被展开到期望的形式Q可能是~译器认为x86的Branch Predication性能已经_高(sh)(jin)吧?/p> <p>q个“优化”在v1231中就已经具备?jin)?/p> <h1> </h1> <h1>首轮优化Qunproject函数Qoperator += ?operator =</h1> <p>W一个Profiling是用BenchmarkPartOfSponza和Sponza跑的QunprojectQoperator +=和operator = 加在一起大U占用了(jin)15-20%的时间。单独的unproject</p> <p>最初的实现是普通的标量。既不要求对齐,也没有用SIMD?/p> <p>所以当然会(x)以ؓ(f)用了(jin)SIMD后,优化效果?x)很好。于是在v1232中,中间点和像素输入的分配都以16字节寚wQunprojQ?=?也都使用?jin)SSEq行?jin)重写?/p> <p>从跑分来看,PartOfSponza性能提升?0%。但是,在测试ComplexMesh和SponzaӞq未发现帧率有显著提升?/p> <p>其实在进行优化之前,何咏告诫过我,因ؓ(f)CCPU的一些技术,比方说超标量啥的Q四个数据宽度的SSE和标量运相比,只?0%的性能差距?/p> <p>q且q些函数的指令已l极为简单,瓉也很明确的落在计指令上。例如Unproject优化后,性能焦点p在_mm_mul_ps上(3.7%Q,几无优化余地?/p> <p> </p> <h1>二轮优化Q插值算法的调整</h1> <p>在进行第二轮优化之前同样q行?jin)一ơProfiling。因为对PartOfSponza性能基本满意Q因此这ơ优化的目标主要在Sponza上?/p> <p>排名前几位的函敎ͼ分别是sub_nQunprojQ?= 和tex2D。对sub_n例行优化后,性能没什么变化。当?dng)q也是意料之中的事情?jin)?/p> <p>因此Q第二轮优化便着重考虑在插值算法本w上?/p> <p>在优化之前,我尝试对代码成本做个_略的评伎ͼ(x)</p> <p>在现有算法下Q假设每个像素有N个需要插值的属性,则^均每个像素有</p> <p>QcornerQ?N/16个读 + 2N/16个乘?+ 2N/16个加?+ N/16个写</p> <p>QxQ?=Q?N个读 + N个加?+ N个写</p> <p>QxQ?Q?nbsp; N个读 + 1个标量除?+ N个乘?+ N个写</p> <p>QyQ?=Q?N/4个读 + N/4个加?+ N/4个写</p> <p>QyQ?Q?N/4个读 + N/4个写</p> <p>因ؓ(f)每个都是函数指针Q所以这些都是优化不掉的。因此首先将一些操作合q了(jin)一下,比如?= ?合ƈ以减一下读写操作。只可惜效果也不是很明显?/p> <p> </p> <p>W二刀q到算法的头上。因为篏加本w是Z(jin)减少乘法的运用,但是q可能带来了(jin)多余的存取开销?/p> <p>因此直接套用公式Q?/p> <p>pixel = ( projected_v0 + projected_ddx * offset_x + projected_ddy * offset_y ) / pixel_w</p> <p>q样有Q?N读,2N乘法Q?N加法QN个乘法和N个写Q假讑֯存器够用的话Q。不Corner的计成本,q样比较一下,q于是3N/4个读QN/2+N个写QN/4个加法来换取2N个乘法的旉。本来以Z为IO瓉的应用,q样可以提高?sh)些性能。不q结果证实这个买卖实在是很不划算Q整体性能不增反减?/p> <p> </p> <h1>三轮优化Q减内存占用,x花明</h1> <p>虽然所有的操作只针对已使用的属性,但是I间上还是浪费了(jin)许多?/p> <p>考虑到内存占用较大也?x)导致一些性能损失Q于是将MAX_ATTRIBUTE_COUNT?2下调C(jin)8?/p> <p>l果令h大跌眼镜。性能瞬间提升?0-30%之多?/p> <p>再加上SSE也不知道Z么开始发力了(jin)Q用上之后性能大约又有?0-15%的提升?/p> <p>我猜可能是因ؓ(f)换页频率下降Q以?qing)Cache的命中率提升。不q手上没有VTuneq种工具Q所以也不太好验证?/p> <p> </p> <h1>四轮优化Q精度敏感性下降的额外U利</h1> <p>在这轮优化之后,PartOfSponza出现?jin)精度问题。因锥体的上下左叛_个面都没有ClipQ所以可能会(x)出现非常大的三角形。这L(fng)U的时候一旦v始点选择的不好,׃(x)出现比较大的误差。在之前版本中,使用/fp: precise来减这一问题出现的机?x)。但是因Z用了(jin)SSEQ也让这个问题再难解冟뀂因此我选用?jin)一些办法,来改善精度问题。在大问题都修正以后Q换?fp: fast来编译整个SALVIAQ最l也获得?-10%左右的性能收益?/p> <h1> </h1> <h1>l论</h1> <p>对于q算和IO都密集的E序来说Q优化真可能是牵一发而动全n的问题。比如在我的例子中,所有猜是性能瓉的地方,都没有得到预想中的改善?/p> <p>倒是在内存占用这个地Ҏ(gu)?j)插査I才得以柳暗花明,而且q让别的优化Ҏ(gu)体现?jin)h(hun)倹{所以如果你不像qiaojie大牛那样对x86?jin)如指掌Q还是要?fn)惯于从多方面猜,例如内存占用Q对齐或紧羃Q计强度,访存密度Qƈ行度{多个角度进行设惛_ƈ用实践去验证。尽可能会(x)遇到很多挫折Q但是,只要是直觉上有优化的余地Q一般都可以扑ֈ合适的Ҏ(gu)?/p><img src ="http://www.shnenglu.com/lingjingqiu/aggbug/197800.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lingjingqiu/" target="_blank">I明{</a> 2013-02-11 20:09 <a href="http://www.shnenglu.com/lingjingqiu/archive/2013/02/11/197800.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源光栅化渲染器SALVIA的O长五q_(d)?amp;middot;q货Q?/title><link>http://www.shnenglu.com/lingjingqiu/archive/2013/01/13/197224.html</link><dc:creator>I明{</dc:creator><author>I明{</author><pubDate>Sat, 12 Jan 2013 21:00:00 GMT</pubDate><guid>http://www.shnenglu.com/lingjingqiu/archive/2013/01/13/197224.html</guid><wfw:comment>http://www.shnenglu.com/lingjingqiu/comments/197224.html</wfw:comment><comments>http://www.shnenglu.com/lingjingqiu/archive/2013/01/13/197224.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.shnenglu.com/lingjingqiu/comments/commentRss/197224.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lingjingqiu/services/trackbacks/197224.html</trackback:ping><description><![CDATA[<p>SALVIA是从07q底开始开发的。历l五q_(d)无论是设计目标,q是使用到的一些方法,都和最初差别很大?<p>谨以此文Q纪忉|在五q中作出来的各种傻逼决定?<p>  <h1>1. 2007q??- 2007q?2月:(x)可笑的动机,可笑的雏?/h1> <h2>动机与原?/h2> <p>SALVIA出现的原因其实很可笑?7q底的时候我正在写一paperQ讲GP-GPU的。那个时候还没有CUDA一cȝ东西Q一切都要靠Shader来。本来我手上的显卡是一?550的SDRAM的简版。但是论文快l束的时候,H然q卡的风扇就|工?jin)。然后我降频用了(jin)大概一个多月,卡也废掉?jin)。因为没׃新显卡,我就打算写一个比D3D REF快的软g渲染器?/p> <p>07q底的时候,实现?jin)第一版的SALVIAQ当时还叫SoftArt。第一版的SALVIA其实q算不错Q流水线的完整程度到现在都还没超q,包括Cpp的Vertex Shader和Pixel Shader、纹理采栗光照什么的一应俱全。在开发过E中Q主要参考GL 2.0的SpecificationQ也阅读?jin)一些同cd软g的代码,例如Muli3D和Mesa?/p> <p>一些对线臛_重要的概念,例如透视修正、固定管U上U理采样的LoD Level、Clip都是借助于Spec和这些实现徏立的?/p> <h2>Z么要有Shader Compiler</h2> <p>如果是固定管U的话,那么SALVIA做到q些Ҏ(gu)也p够了(jin)。但是从SALVIA一开始,我就希望让它成ؓ(f)一个Pure Shader的管U,固定线的那些状态实在太?ch)h?jin)。本来Cpp实现的Shading language能满绝大部分的需要了(jin)Q但是有一个特性彻底难倒了(jin)我:(x)Pixel Shader的差分函数ddx/ddy?/p> <p>q个东西的工作原理是q样的:(x)</p> <p>比方说我有一Dshader函数Q?/p><pre class="brush: cpp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;">float shading_pixel( ... ): COLOR0 { float x; // Expression for calculating x return ddx(x); }</pre> <p>在Pixel Shaderq行的时候,它一ơ性执?x2的一个小块,所有的指o(h)对于整个块内都是同步执行的。遇到ddx(x)后,四个像素都正好执行到q里Q然后把x方向上的盔R两个像素的局部变量x求个差,可以得出ddx?jin)?/p> <p>q个要求在C++中很隑֮现?/p> <ol> <li>不好让C++的四个函数都在同一个地方JoinQ?/li> <li>我不好去获得盔R函数的栈上的倹{?/li></ol> <p>其实如果要较真,当然q是有办法的Q?/p> <ol> <li>对于Join问题Qv码有两种Ҏ(gu)Q?/li> <ul> <li>自己搞一个Fiber ManagerQ直接控制代码的栈的Switch。每个pixel都有一个FiberQ到?jin)DDX/DDY换C一个Fiber执行Q直到所有的Fiber都执行完毕后Q计ddxQ写入栈变量Q再l箋执行Q?/li> <li>直接用线E,JoinQ计,然后l箋执行?/li></ul> <li>对于栈变量的地址问题Q也有办法:(x)</li> <ul> <li>在切换线E的时候直接保存(sh)(f)时变量的地址?/li></ul></ol> <p>但是q些实现Q要么因为切换上下文而变得奇慢无比;要么是完全没有q_UL性。想来想去,q是要让代码按照g的方式SIMD执行?/p> <p>所以我最l横下一条心(j)Q要为它做Shading Language Compiler。然后开始了(jin)漫长的Compiler开发。后来我看团镉K个《O无止境的八月》的时候,直就是对着镜子照自q傻逹{所以我才更黑团ѝ?/p> <h1>2. 2008q初 - 2009q?2月:(x)黎明前的黑暗</h1> <h2>Shader的文?/h2> <p>08q到09q我都在外面实习(fn)Q一周上六天班,一天得q上十个多小时。从2008q初?月䆾Q我都一直在看编译原理和成熟的语法库。底子薄Q看h很吃力。到?月䆾开始设计Shader的EBNF。设计语aQ不外乎是三个方面:(x)应用场景、语法和库的支持。尽有现成的HLSL和GLSL作参考,但对于我?开始设计语a来说Q这些语a的语法和语义都过于复杂了(jin)。我需要让语言Ҏ(gu)慢慢的dq来?/p> <p>考虑到HLSL和C比较接近QC的文法参考资料又很多Q于是我选择?jin)从C开始裁剪语法。但是文法这个东西,q不单单是树(wi)状的l构Q树(wi)上的M一个语法节点,都可能会(x)引用到其它的文法规则。因此修改了(jin)一条规则后Q你?x)发现它可能会(x)和其它规则冲突了(jin),二义了(jin)。于是裁剪计划完蛋了(jin)?/p> <p>当然Q如果我现在来设计语法,肯定?x)和陈汉子一P直接从Use Casep把EBNF写出来,再稍微规范一下,一门不那么复杂的语a成?jin)。当然像C++q种变态语aQ这样做是做不出来的。但当时我显然不具备那样的能力。从七月份开始就磕l绊地裁剪了(jin)一些语法特性之后的语言Q到?jin)八月䆾才出了(jin)个千疮癑֭的方案?/p> <h2>:(x)Boost.Spirit</h2> <p>作ؓ(f)完全不懂~译器的矬货Q设计语a一定要和编译器的开发放在一h能有Ҏ(gu)莗我用过Flex/BisonQ用qANTLR。但是当时我对编译器特别的陌生,l织Build的能力也比较弱,因此它们在用上J琐和难于调试给我带来了(jin)很大的困扰。不q那时我Ҏ(gu)ѝ元~程和Boost已l相当熟(zhn)了(jin)Q无论是开发、阅M码还是Debug都能L应付Q所以我挑了(jin)半天Q选了(jin)Boost.Spirit?/p> <p>Boost.Spirit是个很奇葩的东西。它惛_C++里面提供一个类gEBNF、可以定义语法分析规则的方言。要让C++看v来像一个方aQ当然是要用神出鬼没的操作W重载。当?dng)即便是修饰后的语法,看v来也q是?x)有?gu)怪的。EBNF中的规则</p><pre class="brush: cpp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;">Rule ::= Token SubRule0 [OptionalSubRule1]</pre> <p>在Cpp中最单可以表C成</p><pre class="brush: cpp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;">rule = token >> subrule0 >> optional(OptionalSubRule1)</pre> <p>虽然看v来有点丑陋,但是它已l完全满一个DSL的要求了(jin)Q直观的面向解决Ҏ(gu)?/p> <p>不过如果牉|到实现细节,在C++里面要写一个又单、又可用Parser GeneratorQ那几乎是不可能完成的Q务。v码对于Combinator-based Parser来说Q它够简单,但是没有CPS的支持会(x)令错误恢复这一cȝ周遭设计变得极ؓ(f)可怕;如果Rule只是grammar definitionQ不牉|CQ何Parser的构造,那解析这个definition的复杂度和调试难度又不亚于ANTLR或者Yaccq样有单独脚本的工具。所以这工作,q是交给Haskellq样的语a来完成吧?/p> <p>通过使用Spirit、设计编译器、折腾文法,让我对Compiler和Cpp的理解都递进?jin)一大步。再加上08q全q都在做GUI相关的东西,也让我对~译器的理解有所加深?/p> <p>09q下半年我一直都比较动荡Q不q到q底ȝ是安定了(jin)下来?/p> <h1>3. 2009q?2月?010q?月:(x)长征的开?/h1> <h2>后端与前?/h2> <p>09q?2月䆾的时候,Boost升?jin),Spirit也到?jin)V2。到?月䆾Q我费了(jin)点功夫,把V2的Spirit折腾到SALVIA的前端上。Parser也有所变化Q前一版的Parserq比较草率,q一版的Parser我几乎是完全按照Spirit的Demo中的Ҏ(gu)q行的。此时我也开始尝试着撰写语义分析。怎么做函数重载都是在那个时候开始点的技能树(wi)Q虽然在现在看来都是歪的。ؓ(f)?jin)执行生成的代码Q我设计?jin)半个虚拟机Q然后还准备写点教程。但是我思前惛_Q对于Shaderq样一U钟要调?0Mơ的函数Q无论如何虚拟机都是不合适的?/p> <p>所以我开始筹备自q后端。要求就是一个字Q快。那个时候,陈汉子正在学怎么写x86的JIT。但是我的语a到x86有很长的路要走。怎么d配寄存器Q怎么把类型{换到x86的NativeQ怎么选择指o(h)Q我都是一知半解的。凭我当时的知识Q这一定是不可能完成的?/p> <p>于是在阅dIntel Architecture手册和优化指南后Q我军_L一个合用的后端。考虑q很多可选的办法Q例如生成C++的Code然后~译成DLLQ用Tiny CQTCCQ;或者是JIT。但是它们缺炚w是很明显的。编译成DLL必须要自p剪一个GCC出来QTiny C的效率ƈ不是很好QJIT很复杂(L(fng)在那个时候是q样Q。不q?月䆾的时候,敏敏q是谁指点了(jin)我一下,说你可以ȝ看LLVM。然后我M看,牛|是我要的东西!然后我就开始学LLVM。LLVM的IR很好学,一个下午就搞了(jin)个Hello world?/p> <p>q个时候,minmin也在SALVIA上实C(jin)Half-Space的光栅化法?/p> <p>那个时候我t躇满志Q意气风发,三月赶英Q五月超?/p> <p>可没想着p么掉坑里面去?jin)?/p> <h1>4. 2010q?月?011q新q_(d)(x)苦难的行?/h1> <h2>苦难Q复杂的问题</h2> <p>M大h真是,五个字就概括?jin)?010q一q的努力?/p> <ul> <li>minmin做的SALVIA的Half-Space法q不比我朴素的Top-Bottom的光栅化强;</li> <li>U理上的优化管使用?jin)SSE但是仍然改进有限Q?/li> <li>Shader~译器本w的~译旉׃Spirit的存在而实在O长;</li> <li>Shader~译器和Pipeline如何兌又无从下手;</li> <li>LLVM的集成也因ؓ(f)前端而有所耽搁Q另外因为各U错误层ZIP让整个开发进度变得龟速?/li></ul> <p>所以整个一q中QSALVIA的开发就是写写停停,停停写写。可以说08q初的锐气,已经消磨的差不多?jin)。到?月䆾的时候,我毕业了(jin)Q新工作也基本上定和熟(zhn)了(jin)Q我和minmin_(d)从现在开始我写半q报吧,讲述一下半q来的进展。于是便有了(jin)W一项目简报?/p> <h2>行军Q些微的q展</h2> <p>也正是从那个时候,我决定要把SALVIA作ؓ(f)一Ƒ֮验品来对待,用上所有我不会(x)的或者新学的东西。单元测试,CMake工具链,为Shader设计的PipelineQ语义分析和后端的原型都在那一q加入了(jin)SALVIA。虽然从实现上它们已l与现在相距甚远Q但是v码一切都q是往好的方向发展?/p> <p>另外Q?8q到09q期间在实习(fn)的时候积累的教训开始慢慢的酝酿和发酵,敏捷也逐渐成ؓ(f)?jin)我开发过E中的主要指南?/p> <p>基本上,那个时候积累了(jin)很多必要的经验和教训。当然绝大多数是教训?/p> <h1>5. 2011q?月?011q?月:(x)新Shader的v?/h1> <h2>坑神QBoost.Spirit的灭?/h2> <p>?1q的春节期间Q我l于无法忍受Spirit的麻?ch)?jin)Q?/p> <ul> <li>一D?00行不到的代码Q在我的机器上需要编?0分钟Q?/li> <li>Object File需要占?.9G的硬盘;</li> <li>Mangling nameL过4K字符的限Ӟ</li> <li>L撑爆obj文g的symbol tableQ需要用/bigobj才能够编译通过Q?/li> <li>甚至在编译的时候会(x)L的让32位的MSVC CL out of memory?/li></ul> <p>要知道,以上q些q是应用?jin)Spirit指南中的~译速度优化Ҏ(gu)之后的结果?/p> <p>q一切原因,都是因ؓ(f)Boost.Spirit对于Parser TreeQ是用了(jin)完全?rn)态的分析?wi)结构。每条规则的q回值都?x)是完全不同的类型。这直接Dcd数量极ؓ(f)庞大Q代码膨胀的厉実?/p> <p>于是11q的寒假我花?天的旉重新山寨?jin)一个文法分析器的生器Qƈ做到DSL几乎完全和Spirit一致。只不过Parser Tree不再是静(rn)态类型;模板的用量也减轻?jin)很多?/p> <h2>Shader的阶D|成?/h2> <p>C(jin)四月份的时候,Shading Language Semantic/System Value已经在语法上支持?jin),语义上也能分析出哪些变量是System ValueQ哪些变量是Uniform的。ƈ且通过生成Ҏ(gu)的函数签名,Shader满?jin)以下几个需求:(x)</p> <ol> <li>Shader要返回一个函敎ͼ</li> <li>q个函数是可重入的(因ؓ(f)要ƈ发)(j)Q?/li> <li>数据能正的从Pipeline传入到Shader的函CQ也能正的q回Q?/li> <li>Shader中对于Pipeline数据引用要能正确的生成地址?/li></ol> <p>C(jin)11q?月䆾的时候,l于把Shader全线贯通。虽然很多Operator和Instrinsicq(sh)支持Q但是v码有?jin)个可以看的Demo?/p> <h2>W一个版本与发布前的完善工作</h2> <p>LLVM用上?jin);VS完整?jin),PS也有?jin)个雏ŞQ预处理器什么的都有?jin)?/p> <p>Unit Test也有?jin)原型。我为每个Stage都做?jin)Unit testQParserQSemanticQCodeGen和JIT?/p> <p>某种意义上来_(d)q几个月来在后端上顺利进展,让我多少有点得意忘Ş。再加上梁ȝ帮助QSoftArtq个名字Ҏ(gu)SALVIAQLOGO也有?jin),我在部门内部做的一些Introduction也帮助我梳理?jin)思\。于是从4月䆾开始,我就{备着要把SALVIA正式发布出去?/p> <p>11q??PSALVIA Milestone 1.0 发布。有Change LogQ有Binary DemoQ有Snapshot?/p> <p>三周后,发布?jin)第一个有Vertex Shader的Demo</p> <h1>6. 2011q?月?012q?月:(x)坂道?.0</h1> <h2>Pixel ShaderQ需求与设计</h2> <p>在Milestone 1.0发布后,我开始做Pixel Shader的特性。本以ؓ(f)半年之内p搞定Q发?.0扬眉吐气一下。但是实践证明,我真是他妈的太盲目乐观了(jin)?/p> <p>我先来说一说Pixel Shader的特点和需求。比方说我有四个pixelQ每个pixel都是一个float?/p><pre class="brush: cpp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;">struct pixel_input { float data; }; pixel_input pixel_block[4];</pre> <p>然后我要计算一下,q个data加上1.0之后是多。我前面说过Q我要让指o(h)看v来是四个像素同一时刻执行的,那么昄我生成的代码׃(x)cM于这P(x)</p><pre class="brush: cpp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;">struct pixel_input { float data; }; struct pixel_output { float data; }; void shading_pixel(pixel_input* in_data, pixel_output* out_data) { // TMP = IN_DATA.DATA + 1.0 float tmp0 = in_data[0].data + 1.0; float tmp1 = in_data[1].data + 1.0; float tmp2 = in_data[2].data + 1.0; float tmp3 = in_data[3].data + 1.0; // OUT_DATA.DATA = TMP out_data[0].data = tmp0; out_data[1].data = tmp1; out_data[2].data = tmp2; out_data[3].data = tmp3; }</pre> <h2>Pixel ShaderQ优化与问题</h2> <p>昄q里是可以优化的Q将四条指o(h)q作一条SIMD指o(h)?/p> <p>那么q个时候,有两个需求是要满的Q?/p> <ol> <li>同样的struct member一定要是邻接在一赗?/li> <li>得根据SIMD的要求数据对齐?/li></ol> <p>只有一个域当然好办。如果struct很复杂呢Q比方说下面q样Q?/p><pre class="brush: cpp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;">struct { float; float2; int3; struct { float2[3]; float; }; };</pre> <p>那就?x)衍生出各种问题Q?/p> <ul> <li>那要不要把每个域都展q_Q?/li> <li>展^C么程度?</li> <li>让每个Builtin Type Member盔RQ还是让每个Float/Int盔RQ?/li> <li>那遇到动态寻址Q怎么办?</li> <li>展^后的代码Q与VS中的代码能通用吗?</li></ul> <p>每个Ҏ(gu)都一定能完成Q每个方案都有明昄~陷。最初我是想试四个像素完全独立的办法,q样实现h最方便。但是出于对性能的追求,我又惛_展^的。展q的Ҏ(gu)做到一半,发现太复杂了(jin)?/p> <h2>坑神IIQLLVM</h2> <p>此外Q还有几个非怸重的问题Q发生在LLVM上?/p> <p>一个是ABI。一个符合C Calling Convention的LLVM函数Q它对堆栈的理解与VS完全不同Q特别是参数传入或者返回Struct的时候。这P直接用LLVM的函数Export出来后,让VC去Call它就一定会(x)p|。ؓ(f)?jin)解军_Q我׃(jin)q两周的旉Q设计了(jin)一个ProxyQ让函数避免用Struct来传递,一切数据,除了(jin)和寄存器同样大小的float和intQ其余数据都通过指针来做。同Ӟ我需要将一些函数注入到LLVM中,比方说纹理采P此时ABI同样是个?zhn)。ؓ(f)?jin)让Code Gen正确的识别函数是LLVM的调用协议还是我自己定制的调用协议,q生正的代码。我做了(jin)各种奇葩和傻逼的Ҏ(gu)。有一些方案被废弃?jin),但是主要的IdeaQ仍然沿用到现在?/p> <p>一个是临时变量Q包括SpillerQ的寚w。在Linux/GCC上,栈顶和栈基指针一定是16字节寚w的。如果编译器需要分配一个(f)时变量,那么它只要通过ESP - 0x10*np获得一个对齐的地址。但是在VC中,x86下完全没有这L(fng)限制Q除非函C使用?jin)__m128Q这个时候在q入Frame之后?x)有一个SUB/AND的指令把栈顶搞到16字节寚w。)(j)。但LLVM生成的所有代码,又是ZGCC的假设。SALVIA生成的局部变量,q可以控制地址Q但是对于编译器临时生成的变量来_(d)完全不可控?jin)。在3.1之后因ؓ(f)引入?jin)AVXQ需?2字节寚wQ这个问题就更加变本加厉?jin)。在x86上,我还可以通过嵌入汇编Q来强制调整栈。但是在x64上,又启动了(jin)AVX的情况下Q我彻底没有办法了(jin)。这个问题(sh)直gl到现在Q如果我不动手去Debug LLVM的话Q就只能{他们什么时候想h修复q个问题?sh)(jin)?/p> <h2>SIMD执行模型下分支的处理</h2> <p>Pixel Shader的执行模型是SIMD的,q要求每个像素上同一时刻都执行相同的指o(h)。如果没有分支,那自然是单无比。一旦有?jin)分支就打破了(jin)这个约定。在DX9.0b?qing)之前,q当然没问题?/p> <p>但是Shader Model 3.0正式支持Dynamic Branch开始,q个问题凸现出来了(jin)Q分支要怎么处理Q?/p> <p>对于Pixel Shader来说Q会(x)面(f)三种分支Q静(rn)态分支,准静(rn)态分支(q个名字是我瞎v的)(j)和动态分支?/p><pre class="brush: cpp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;">float branches( uniform float udata, float vdata: POSITION): COLOR0 { const float zero = 0.0; if(zero < 1.0) { // Static branch } if(udata) { // Semi-Static Branch (我自己造的) } if(vdata) { // Dynamic Branch } } </pre> <p>我们来分情况讨论一下:(x)</p> <ul> <li>对于?rn)态分支来_(d)因ؓ(f)定分支的是一个常量,那么昄在编译阶D就能够知道分支执行与否Q直接生成对应的代码可以了(jin)?/li> <li>对于uniform作ؓ(f)判断条g的分支来_(d)在shader~译的时候,q不知道q个分支是否?x)执行。但是呢QUniform?x)在Shader执行前设|,和代码执行相比,Uniform讄的比例非怽。这个时候我们可以先讲代码编译成中间表达Q这个中间表达会(x)知道一个变量是不是Uniform的。在Uniform讄好后QShader真正执行前,把Uniform替换成那个|也就是把Uniform当做帔RQ对Shader再编译一ơ,得到真正的执行指令。所以在指o(h)执行的时候,准静(rn)态分支就和静(rn)态分支完全相同了(jin)?/li> <li>最后一个,动态分支。如果判断条件就是动态的Q那没办法,如果要支持SM3.0Q就必须要能支持它。同时对于不同的PixelQ都可能有不同的分支。这对于SIMD来说Q才是真正的N?/li></ul> <p>实际上,我们真正要解决的Q就是动态分支?/p> <p>对于SIMD模型来说Q动态分支有三种处理办法?/p> <ol> <li>跌{执行。像CUDA 2.0以上那样的指令集具备有一定的跌{执行能力。编译器可以把SIMD拆开Q按照标量执行。每个都执行完了(jin)后,再l按照SIMD执行其他的代码?/li> <li>条g执行。这也是囑Şg上最常见的执行模式。通过一个位Q就可以军_GPU中的执行单元是否执行一D代码。D个不准确的例子,如果是个4q发的执行器Q那么四个ƈ发执行器的执行条件可以设|ؓ(f)1100Q这样就只有前两个单元的数据执行Q后两个不执行了(jin)?/li> <li>写掩码。这个办法是没有办法的办法。它的基本理念就是:(x)只要不写到内存(sh)的执行结果,可以认为它没执行过。但是写掩码L费?jin)指令。不q好歹它q是避免?jin)蟩转的。所以对于早期的ARMq样没有分支预测的精体系来说Q一旦有分支执行h是ȝ。所以它有类gSelect-Storeq样的指令,可能的避免分支的出现?/li></ol> <p>对于SAVLIA来说Q蟩转执行和写掩码是两个可能的选择。因为写掩码的代码生成v来更加轻松一些,所以目前的SALVIA的实现是写掩码的。在x86/x64q_上,对于AVX以上的指令,q可以用blend。但是对于其他指令而言Q基本上只能是通过跌{实现写掩码。所以这部分的开销其实很大。等到造出?jin)自qSSA之后Q再来考虑分支执行的事情吧?/p> <p>对于写掩码的掩码要怎么计算Q一开始我?j)里挺没q。特别是有了(jin)QContinue和Break之后Q情况就?x)变得复杂v来。一开始我没法信自己的方案是正确的。后来看?jin)MESA的Gallinum以后Q看见了(jin)Continue Mask和Break Mask两个变量Q瞬间就明白?jin)?/p> <p>具体怎么思考的不多说了(jin)Q这里写下几个结论:(x)</p> <ol> <li>语言不能有GotoQ有Goto?x)让代码变得非常复杂Q甚至不可解Q;</li> <li>所需要的掩码的数量会(x)随着循环的嵌套层数的增加而增加;</li> <li>每个循环最多有三个掩码QBreakQContinue和MaskQ?/li> <li>E序是固定的话,掩码的数量就一定是个常量。(要不然硬件就没法做了(jin)Q?/li> <li>写掩码的位数只和执行单元的数量有养I和嵌套深度无兟?/li></ol> <h2>坂道のTest</h2> <p>管遇到?jin)各U难处,但是很多Ҏ(gu)q是利的做出来?jin)。方案和Ҏ(gu)之间差异很大Q要想顺利移植,必须要有Test?/p> <p>之前也说q,一开始我的Test是按照ParserQSemanticQCode GenQJIT分开做的。但是呢Q这样一来,不同Stage之间的Test复用性非帔R。而且因ؓ(f)Stagel常变化Q包括Stage的接口。这时候Test完蛋了(jin)。Test本n也很枯燥Q变量名都不好vQ,所以Test重写h难过的要歅R?/p> <p>于是我重新审视了(jin)一下需求。发现我最l只兛_(j)JIT~译出来的函数的q行l果Q其实ƈ不关?j)中间的q程。而且随着我对~译q程理解的逐步变化QCompiler Stages几乎每隔两个月就要进行比较大的修正。测试的量稍微大一点,没有办法维护Test Case?jin)。ƈ且,对于单条语句或者非常短的函数来_(d)从词法到最lJIT出来的函数所覆盖的编译器代码非常之少Q可?-4个函敎ͼ代码出来了(jin)。即便有问题Q对比过ȝ版本Lp分析出来。再加上大量的AssertionQ诊断v来更加容易?/p> <p>因此Q在q几个月中我完全重写?jin)Test CaseQ让JIT的测试粒度更低,试更丰富;取消所有的中间Level的测试。新的测试回归v来非常容易,Z(jin)问题?sh)很好找到。在Test Case写完后,正好看到Martin Fowler喯度TDD的问题,真是感同w受?/p> <p>试需要吗Q当焉要。但是选择合适的LevelQ做合适的试是非帔R要的。结合之前实?fn)的时候的Unit Testl验Q有以下几点感受Q?/p> <ol> <li>试一定要选择可能低的面Q这L(fng)涉的代码尽可能;</li> <li>在纵向上Q粒度要l。除?jin)单个API的TestQ还要有适度的交叉,不过太综合的试Q请让集成测试用例来完成Q?/li> <li>要重视代码覆盖率Q?/li> <li>试面向的API要稳定。天天变得API?x)让你彻底失dTest的信?j)。API稳定,在它上面出现问题的机?x)就多Q你写的试性h(hun)比也高?/li></ol> <h2>坡长路远Q小步快?/h2> <p>在完成了(jin)Test的改造后Q终于有?jin)一个合适的发布前评估。所以到?1q?1月后Q发布的速度明昑֏快了(jin)许多。快速的发布对于做一个长期项目来说非帔R要。这也和敏捷的想法不谋而合。不是从品质控制上、还是进度追t上Q或者是说对开发者自信心(j)的增强,都需要有短^快的开发周期?1q也正好是Autodesk推行敏捷的一q。同事里面有很多的h反应说敏捷会(x)D软g品质的下降,短期目标?x)导致过于追逐眼前利益?/p> <p>但是从我的经验来看,对于个hQ敏捯短^快。但对于团队Q敏捯从长计议。不是所有的iteration都需要开发新Ҏ(gu),必须要保留够的iteration来完成重构、整理、设计方案的反省和讨论。对于以qؓ(f)单位的长周期产品来说Q可以每个季度有3-5天的旉Q每个h都提出对框架的改q计划;每年有两周的旉Q完成框架的重构和修正。更的重构Q可以安排的更加短小的时间?/p> <h2>6. 2012q?月及(qing)以后Q现在与未来</h2> <h2>新特性,新思?/h2> <p>?1q?月䆾开始到现在Q就一直在做Demo、优化、特性的完善Q以?qing)一些新Ҏ(gu)的思考?/p> <p>ȝ来说Q这一q半的时间里面,很多工作已经不像早先几年做的那么吃力Q但是仍然在很多的点上有所斩获?/p> <ul> <li>整个~译器后端,包括基本的分析和优化都已l有所?jin)解QLLVM也熟(zhn)了(jin)许多Q?/li> <li>对Shader相关的API的了(jin)解也不再應|懂懂Q?/li> <li>对于语言机制的研IӞ加上陈汉子时不时抛来的一些思维发散题(sh)o(h)我对语言有了(jin)更深入的认识Q?/li> <li>认识?jin)RFXQ在短短几周帮助我在阅读V8和LLVM时积累的一些知识{化成?jin)有用的理解?/li></ul> <p>?012q底为SALVIAq行?jin)局部的重新设计Q也是“学”与“习(fn)”的C轮“习(fn)”。新的SSA?qing)Shader优化、JIT化的线、对性能有要求的新前端、瞄准DX11以上Shader Model Features、JIT的调试符Pq些一定会(x)l我带来许多l尽脑汁想不明白的问题,但同时我也会(x)学习(fn)到、实践到许多新的知识?/p> <p>我相信时间会(x)教给我们一切?/p><img src ="http://www.shnenglu.com/lingjingqiu/aggbug/197224.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lingjingqiu/" target="_blank">I明{</a> 2013-01-13 05:00 <a href="http://www.shnenglu.com/lingjingqiu/archive/2013/01/13/197224.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SASL~译器Diagnostic信息的管理、格式化与输?/title><link>http://www.shnenglu.com/lingjingqiu/archive/2012/03/08/167444.html</link><dc:creator>I明{</dc:creator><author>I明{</author><pubDate>Thu, 08 Mar 2012 13:25:00 GMT</pubDate><guid>http://www.shnenglu.com/lingjingqiu/archive/2012/03/08/167444.html</guid><wfw:comment>http://www.shnenglu.com/lingjingqiu/comments/167444.html</wfw:comment><comments>http://www.shnenglu.com/lingjingqiu/archive/2012/03/08/167444.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lingjingqiu/comments/commentRss/167444.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lingjingqiu/services/trackbacks/167444.html</trackback:ping><description><![CDATA[<p>1. Diagnostic需要提供哪些数?/p> <p>出错处理和错误提C,是编译器开发过E中重要而繁琐的部分?/p> <p>诊断信息的格式因~译器和IDE而不同?/p> <p>SALVIA采用Visual Studio的格式,?<u>文g + 行列 + cdQ等U)(j) + ~号 + 出错信息</u>。例如:(x)</p> <p>d:\programming\salvia\sasl\test\cgllvm_test\function_test_basic.cpp(16): error C2061: syntax error : identifier 'te'</p> <p>因此在出错分析的时候,也需要提供如上的一些信息?/p> <p><br>2. 诊断信息Diagnostic Item</p> <p>在以上信息中Q文件名和行列号可以在词法分析的时候获得,我们它作ؓ(f)属性附加在Token中?/p> <p>cd和编P对于同一个编译器而言是相对固定的Q尽我们可以用ID来表C,但是它ƈ不直观,~译器检查也较少。与参数匚wӞ也比较容易出错?/p> <p>SASL中的诊断信息每个错误都使用一个类型来表达Q?/p><pre class="code"><span style="background: white; color: #8000ff">class</span><span style="background: white"> </span><span style="background: white; color: black">diagnostic_item </span><span style="background: white"></span><span style="background: white; color: navy">{ </span><span style="background: white"></span><span style="background: white; color: navy">}; </span><span style="background: white"> </span><span style="background: white; color: #8000ff">class</span><span style="background: white"> </span><span style="background: white; color: black">unrecognized_identifier</span><span style="background: white; color: navy">:</span><span style="background: white"> </span><span style="background: white; color: #8000ff">public</span><span style="background: white"> </span><span style="background: white; color: black">diagnostic_item </span><span style="background: white"></span><span style="background: white; color: navy">{ </span><span style="background: white"></span><span style="background: white; color: #8000ff">public</span><span style="background: white; color: navy">: </span><span style="background: white"> </span><span style="background: white; color: black">unrecognized_identifier</span><span style="background: white; color: navy">&</span><span style="background: white"> </span><span style="background: white; color: black">token</span><span style="background: white; color: navy">(</span><span style="background: white"> </span><span style="background: white; color: black">token_t</span><span style="background: white"> </span><span style="background: white; color: black">tok</span><span style="background: white"> </span><span style="background: white; color: navy">); </span><span style="background: white"> </span><span style="background: white; color: #8000ff">private</span><span style="background: white; color: navy">: </span><span style="background: white"> </span><span style="background: white; color: #8000ff">static</span><span style="background: white"> </span><span style="background: white; color: #8000ff">int</span><span style="background: white"> </span><span style="background: white; color: black">level</span><span style="background: white; color: navy">; </span><span style="background: white"> </span><span style="background: white; color: #8000ff">static</span><span style="background: white"> </span><span style="background: white; color: #8000ff">int</span><span style="background: white"> </span><span style="background: white; color: black">id</span><span style="background: white; color: navy">;</span><span style="background: white; color: navy"> </span><span style="background: white"> </span><span style="background: white; color: #8000ff">static</span><span style="background: white"> </span><span style="background: white; color: black">std</span><span style="background: white; color: navy">::</span><span style="background: white; color: black">string</span><span style="background: white"> </span><span style="background: white; color: black">description_template</span><span style="background: white; color: navy">; </span><span style="background: white"> </span><span style="background: white; color: #8000ff">private</span><span style="background: white; color: navy">: </span><span style="background: white"> </span><span style="background: white; color: black">std</span><span style="background: white; color: navy">::</span><span style="background: white; color: black">string</span><span style="background: white"> </span><span style="background: white; color: black">ident</span><span style="background: white; color: navy">; </span><span style="background: white"> </span><span style="background: white; color: black">size_t</span><span style="background: white"> </span><span style="background: white; color: black">row</span><span style="background: white; color: navy">,</span><span style="background: white"> </span><span style="background: white; color: black">col</span><span style="background: white; color: navy">; </span><span style="background: white"> </span><span style="background: white; color: green">// Other properties </span><span style="background: white; color: navy">};</span></pre> <p>q样的好处在于可以用Combinator的风格来撰写错误信息。例如这P(x)</p> <p>diagnostic_chat.report<unrecognized_identifier>().token( err_tok ); <p>q且׃~译器的保证也比较不Ҏ(gu)写错? <p>  <p>但是q种写法也有一个很关键的问题,需要ؓ(f)每个错误都定义一个类Q工作量很大。SASL对这一问题的处理,自然是传l的大杀器:(x)q用脚本q行生成? <p>Clang使用?jin)它内置的代码生成工具td来完成生成的工作? <p>  <p>3. 诊断信息理器Diagnostic Chat <p>Chat是诊断信息的理工具。它主要要完成以下需求:(x)d和清理诊断信息,以及(qing)在诊断信息的d清理时提供回调操作? <p>后者是很有用的Q尤其是在调试编译器的时候。你得分清楚I竟是真正的E序错误呢,q是~译器出?jin)错? <p>Diagnostic Chat的原型如下:(x)<pre class="code"><span style="background: white; color: #8000ff">class</span><span style="background: white"> </span><span style="background: white; color: black">diagnostic_chat </span><span style="background: white"></span><span style="background: white; color: navy">{ </span><span style="background: white"></span><span style="background: white; color: #8000ff">public</span><span style="background: white; color: navy">: </span><span style="background: white"> </span><span style="background: white; color: #8000ff">template</span><span style="background: white"> </span><span style="background: white; color: navy"><</span><span style="background: white; color: #8000ff">typename</span><span style="background: white"> </span><span style="background: white; color: black">T</span><span style="background: white; color: navy">></span><span style="background: white"> </span><span style="background: white; color: black">T</span><span style="background: white; color: navy">&</span><span style="background: white"> </span><span style="background: white; color: black">report</span><span style="background: white; color: navy">(); </span><span style="background: white"> </span><span style="background: white; color: #8000ff">void</span><span style="background: white"> </span><span style="background: white; color: black">add_report_diagnostic_handler</span><span style="background: white; color: navy">(</span><span style="background: white"> </span><span style="background: white; color: black">DiagnosticHandlerT</span><span style="background: white"> </span><span style="background: white; color: black">handler</span><span style="background: white"> </span><span style="background: white; color: navy">); </span><span style="background: white"></span><span style="background: white; color: navy">};</span></pre> <p>同时Q我们也Treat Warning As ErrorQError CountQDisable WarningQStop compiling when error occurs{状态和功能所需要的支持d到Chat中? <p>所以,Chat除了(jin)提供理之外Q也要具有相应的诊断信息的统计功能? <p>  <p>4. qo(h)器Diagnostic Filter <p>Filter主要配合IDE使用Q从Chat中取出符合条件的诊断信息。Error Count和Disable Warnings{功能也可以通过它来完成? <p>  <p>5. Formatter <p>Formatter用于DiagnosticItems中的信息转换成h可读的字W串。目前SASL只打支持Visual Studio的格式,但是怿支持GCC的格式以更好的和Eclipse{第三方IDE集成q不困难? <p>在C#里面Q我们可以用“We need ‘{0}?not ‘{1}?”这L(fng)方式来分description templateqg期的产生格式化的字符丌Ӏ但是在C++中,q种做法q不Ҏ(gu)。C的sprintf很难h延期、渐增的l定模板的特定,对自定义cd的字W串化的支持也不Icd安全也比较差Q而stream的话Q也?x)面临着好端端的格式化字符串割裂的问题。SASL使用?jin)boost.formatQ从一定程度上搞定?jin)这两个问题Q从而像C#一P使用格式化字W串的功能?/p><img src ="http://www.shnenglu.com/lingjingqiu/aggbug/167444.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lingjingqiu/" target="_blank">I明{</a> 2012-03-08 21:25 <a href="http://www.shnenglu.com/lingjingqiu/archive/2012/03/08/167444.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SALVIA 0.3 发布QPixel Shaderd?jin)tex2D的支?/title><link>http://www.shnenglu.com/lingjingqiu/archive/2012/03/06/167256.html</link><dc:creator>I明{</dc:creator><author>I明{</author><pubDate>Tue, 06 Mar 2012 09:41:00 GMT</pubDate><guid>http://www.shnenglu.com/lingjingqiu/archive/2012/03/06/167256.html</guid><wfw:comment>http://www.shnenglu.com/lingjingqiu/comments/167256.html</wfw:comment><comments>http://www.shnenglu.com/lingjingqiu/archive/2012/03/06/167256.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lingjingqiu/comments/commentRss/167256.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lingjingqiu/services/trackbacks/167256.html</trackback:ping><description><![CDATA[<p>SALVIA 0.3 出炉?jin)?/p> <p><font color="#ff0000"><strong>q是?010q?月䆾以来Q?SALVIA Milestone 1.0之后最重要的发布!</strong></font></p> <p>0.3开始,SALVIA正式支持?jin)Pixel Shader?/p> <p>?008q中开始的Shader设计与实现工作基本完成?/p> <p>未来一q内QSALVIA的工作将集中以下几点Q?/p> <ol> <li>在Shader~译器的完善上,比如友善的语法和语义错误提示?/li> <li>提升与管U的集成度,q而充分提升性能?/li> <li>~译器和~译器生成代码的优化Q提高Shader的编译速度和运行速度?/li> <li>新的囑ŞҎ(gu),如各向异性过滤等?/li></ol> <p>随着SALVIA整体的逐渐成熟Q我们也希望有其他的朋友能来参与和支持这个项目,一同进步?/p> <p>如果(zhn)希望参与到q个目中,请mail联系我:(x)wuye9036 __at__ gmail dota com.</p> <p> </p> <p><a href="http://www.shnenglu.com/images/cppblog_com/lingjingqiu/Windows-Live-Writer/SALVIA-0.3-_BB28/tex2D_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="tex2D" border="0" alt="tex2D" src="http://www.shnenglu.com/images/cppblog_com/lingjingqiu/Windows-Live-Writer/SALVIA-0.3-_BB28/tex2D_thumb.png" width="680" height="264"></a></p><img src ="http://www.shnenglu.com/lingjingqiu/aggbug/167256.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lingjingqiu/" target="_blank">I明{</a> 2012-03-06 17:41 <a href="http://www.shnenglu.com/lingjingqiu/archive/2012/03/06/167256.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源Y件光栅化渲染器SALVIA 0.2.5发布Qؓ(f)Pixel Shaderd?jin)分支与循环的支?/title><link>http://www.shnenglu.com/lingjingqiu/archive/2012/02/24/166438.html</link><dc:creator>I明{</dc:creator><author>I明{</author><pubDate>Fri, 24 Feb 2012 08:56:00 GMT</pubDate><guid>http://www.shnenglu.com/lingjingqiu/archive/2012/02/24/166438.html</guid><wfw:comment>http://www.shnenglu.com/lingjingqiu/comments/166438.html</wfw:comment><comments>http://www.shnenglu.com/lingjingqiu/archive/2012/02/24/166438.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/lingjingqiu/comments/commentRss/166438.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lingjingqiu/services/trackbacks/166438.html</trackback:ping><description><![CDATA[<p>SALVIA 0.2.5 发布Q?br></p> <p>目主页Q?<a >http://code.google.com/p/softart/</a><br></p> <p>更新列表如下Q?/p> <p><br><strong>0.2.2 - 0.2.5 (Feb 24, 2012)</strong></p> <ul> <li>版本名称发生变化Q从原先的Milestone X fix Y的命名方式正式更Cؓ(f)与主版本相同的版本号序列? <li>取消?jin)对DirectX的强制依赖? <li>d?jin)对Visual C++ Express的支? <li>Pixel Shader q一步增强:(x)</li></ul>          1. 提供?jin)对分支语?<strong>if</strong> 的支?nbsp;  <br>          2. 支持 <strong>for, while, do-while</strong> 循环<br>          3. d?jin)新的内建函敎ͼ?x)<strong>ddx ddy dot cross sqrt</strong><br>          4. d?jin)纹理取样函?strong>tex2D</strong>的原? <ul> <li>对Rasterizerq行?jin)进一步的优化 <li>修正?jin)以下问题?x)</li></ul>          1. 在x86上执行vertex shader时可能会(x)Crash的问?br>          2. 不能再build配置文g中指定CMake路径的问?br>          3. 一些表辑ּ调用时报告函数重载错误的问题<img src ="http://www.shnenglu.com/lingjingqiu/aggbug/166438.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lingjingqiu/" target="_blank">I明{</a> 2012-02-24 16:56 <a href="http://www.shnenglu.com/lingjingqiu/archive/2012/02/24/166438.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SALVIA正式支持一站式~译http://www.shnenglu.com/lingjingqiu/archive/2011/12/26/162868.htmlI明{I明{Mon, 26 Dec 2011 13:09:00 GMThttp://www.shnenglu.com/lingjingqiu/archive/2011/12/26/162868.htmlhttp://www.shnenglu.com/lingjingqiu/comments/162868.htmlhttp://www.shnenglu.com/lingjingqiu/archive/2011/12/26/162868.html#Feedback5http://www.shnenglu.com/lingjingqiu/comments/commentRss/162868.htmlhttp://www.shnenglu.com/lingjingqiu/services/trackbacks/162868.htmlSALVIA在Milestone 1.2 Fix 2中,正式提供?jin)一站式~译脚本的支持?/p>

目主页Q?a title="http://code.google.com/p/softart/" >http://code.google.com/p/softart/

新的~译步骤如下Q?/p>

1. 下蝲最新的CMakeq安装?/p>

2. 下蝲Python 2.7q安装?/p>

3. 下蝲boost 1.44或更新的版本Q解压到某个目录下?/p>

4. Clone或下载SALVIA代码包,执行根目录下的build_all.py文g。第一ơ运行的时候会(x)生成一个project.pyQ编辑project.py讄相应属性,包括boost代码目录Q编译器Qconfiguration{?/p>

5. 再次q行build_all.pyQ编译程序?/p>

I明{ 2011-12-26 21:09 发表评论
]]>
LLVM随笔http://www.shnenglu.com/lingjingqiu/archive/2011/11/22/160736.htmlI明{I明{Tue, 22 Nov 2011 13:04:00 GMThttp://www.shnenglu.com/lingjingqiu/archive/2011/11/22/160736.htmlhttp://www.shnenglu.com/lingjingqiu/comments/160736.htmlhttp://www.shnenglu.com/lingjingqiu/archive/2011/11/22/160736.html#Feedback0http://www.shnenglu.com/lingjingqiu/comments/commentRss/160736.htmlhttp://www.shnenglu.com/lingjingqiu/services/trackbacks/160736.html 1. LLVM在x86和x64下都和Microsft C++ ABI的吻合程度不够。目前已知在以下情况下会(x)出错Q?br />
  • 参数为结构体?/li>
  • q回gؓ(f)l构?
以下情况我没有完整测试过Q?
  • q回gؓ(f)单个点
  • q回gؓ(f)向量Q_m128 / <4 x float>Q?
  • 参数为向量(_m128 / <4xfloat>Q?
所以徏议大家统一是l构体的q回值和参数以引?指针的Ş式传递?br /> 对于大小?个或?个字节的l构体如果希望按g递,那么需要在LLVM函数的签名上使用i32/i64作ؓ(f)参数cdQƈ使用bit cast在函C内强制{换成l构体?br />
2. LLVM提供?jin)很多的IntrinsicsQ例如SSE指o(h)集。它在Module上提供了(jin)一个getOrCreateTargetIntrinsicQ但实际上这个函数是坑爹的。有两个Ҏ(gu)可以正确的创建ƈ获取指o(h)集:(x)
  • 使用Module::getOrInsertFunction( intrinsic_name, intrinsic_function_type )。它?x)自动识别intrinsic的名Uƈ创徏function或者是intrinsic。指令需要用全名。例?llvm.x86.sse.sqrt.ps.
  • 或者用Ilvm::Intrinsic::getDeclaration( id ) 来创建。这个id可以在intrinsics.gen中找到?/li>
因ؓ(f)LLVM生成的Intrinsic是全q_的,所以可以在x86上指定ARM汇编的生成,反之亦然?br />
3. 默认情况下,LLVM的JIT是不?x)启用InliningPass的,Optimization Level指定为Aggressive也不?x)。这意味着inlinehint和alwaysinline都是失效的。如果需要inlining得自׃改JIT的源代码?br />
4. UndefValue是个好东ѝ这个常量可以生成的汇~少一条初始化指o(h)。比方说?初始化,可能对应的汇~就?xor reg, reg。如果用?jin)UndefQ那q条指o(h)没?jin)?br />
5.
TypeBuilder很好用,只是不能生成struct{复杂的cd。不q你可以对它做一些修改以让它支持struct和vector。这个时候Boost.MPLpz上用场?jin)。不q要当心(j)MPL带来漫长的编译时间?

I明{ 2011-11-22 21:04 发表评论
]]>
LLVM的调用协议与内存寚whttp://www.shnenglu.com/lingjingqiu/archive/2011/08/17/153655.htmlI明{I明{Wed, 17 Aug 2011 05:58:00 GMThttp://www.shnenglu.com/lingjingqiu/archive/2011/08/17/153655.htmlhttp://www.shnenglu.com/lingjingqiu/comments/153655.htmlhttp://www.shnenglu.com/lingjingqiu/archive/2011/08/17/153655.html#Feedback3http://www.shnenglu.com/lingjingqiu/comments/commentRss/153655.htmlhttp://www.shnenglu.com/lingjingqiu/services/trackbacks/153655.html在设计一门语a与其他语a交互的API与ABIQApplication Binary InterfaceQ二q制接口Q时Q调用协议和内存寚w是两个无从回避的问题?/p>

本文讨论如何在LLVM上生成正的内存寚w和调用协议的代码?/p>

在这里ؓ(f)?jin)方便和标准赯Q假定应用LLVM的语a的Extending和Embedding的对象都是C?/p>

调用协议

先来讨论调用协议。调用协议用于保证调用方和被调用方在二进?汇编一U上是相容的。合适的调用协议可以帮助构造出以下代码Q?/p>
// Callee Signature of LLVM code
void __cdecl foo( int a, float b, float4 c);

// C caller
typedef void (__cdecl* fn_ptr)(int, float, float4)
fn_ptr p = static_cast<fn_ptr>( get_jit_function("foo") );
p(1, 1.0, vec);

一般来说调用协议包括参C递和q回g递和堆栈q三个部分。在x86q_上的C/C++~译器中常见的调用协议有cdecl, fastcall和stdcall。具体的协议内容请参见MSDN?/p>

在C++中还有一cȝD的调用协议thiscallQ用于调用对象的成员函数。但是这一c调用协议不同的q_Q不同的~译器实现皆有不同,既无书面标准Q也无事实标准,再加上virtual call{复杂的情况存在Qƈ不适合用于做跨语言的调用?/p>

对于x64q_而言Q在windows下和linux下分别有两种调用协议?/p>

先来看x86。由于x86在cdecl和fastcall上是有着跨^台的标准的,因此LLVM对它的支持是比较完整的。程序只要在创徏Function的时候指定Call Convention卛_?/p>

但是对于x64QLLVM的支持便不是那么完善。以windowsZQwindows的x64调用协议要求以rcxQrdxQr8Qr9寄存器传递前四个不大?4bit的参敎ͼ其余参数攑֜栈上。如果参数大?4bitQ则要求传递它的指针。Q点用xmm0-3来传递。但是对于LLVM而言Q一旦参数大?4bitQ它便会(x)整个对象而不是指针压到栈上传递。因此在遇到x64Ӟ需要小?j)处理API部分的调用协议?/p>

在这里,我们需要将所有超q?4bit的结构体处理成指针(或者拷贝后处理成指针)(j)传递?/p>

同时QLLVM提供?jin)readonly和byval两个参数属性(AttributeQ来保参数的D义。前者意味着传入的指针所指向的值是不被修改的,Q类gT const*Q,而后者会(x)对传入的指针做一份内存拷贝,保写g被传递出函数Q类g值拷贝)(j)。这PLLVM生成的函C可以MSVC生成的x64代码正确调用?jin)?/p>

内存寚w

与移动^台的体系l构相比Qx86对内存对齐的条g是相当宽松的了(jin)。大部分的指令对内存寚w基本上是没有Ҏ(gu)要求的。只有一些SIMD的指令会(x)对内存对齐有所限定Q例如movaps?/p>

Z(jin)方便后端生成SIMD代码QLLVM提供?jin)vectorcdQ例如vector<float, 1>。在代码生成的时候,vector?x)编译成最有可能的SIMDcd。因此在x86q_上,vector<float, 1-4>都被处理成类g__m128的类型,更长的vector则被拆分成多个__m128cd?/p>

q实际上意味着Q所有的vector都应该遵?6Bytes寚w的原则?/p>

考虑到我们的需求,cM于struct{ float[3]; }q样的结构,如果能表CZؓ(f)vector<float, 3>昄适合一些数学运,例如shuffleQ逐元素的addQsubQmulQ同时LLVM指o(h)的选择也更加灵zR但是显?dng)q个l构体有两个条g是不满的:(x)16字节寚w?6字节的大(movups和movaps都是一ơ取16字节Q。这?x)造成边界下读写的内存界。因此非常可惜,q些数据必须表示为struct{ float ,float, float }。在d的时候,也会(x)生成正确的指令:(x)movss?/p>

那么Q对于一般的非对齐的vec4应用vector<float,4>行不行呢Q?/p>

{案是,很困难。对于LLVM而言Q他们在设计的时候就没有q多的考虑vector在非寚w时候的应用。尽load和store都能够指定alignment以生成非寚w的内存操作(例如movupsQƈ且确实会(x)hQ但是由于代码优化、(f)时存取等Ҏ(gu)的存在Q导致一些非load和store的内存操作仍然是要求寚w的(例如生成?jin)addaps xmm, [addr]Q。此时仍然有可能为非寚w的数据生成了(jin)内存寚w的指令?/p>

因此l合权衡QSASL在API界面上用了(jin)struct{float x,y,z,w;} q样的ABI来表C数据,在代码生成时Q会(x)首先struct的数据{换成vectorQ然后再执行其它的操作,兼顾ABI与SIMDQ同时对于IntrinsicQ由于ƈ不暴露给HostQ所以它们仍然尽可能使用VectorQ便于LLVMq行优化?/p>

I明{ 2011-08-17 13:58 发表评论
]]>
SALVIA Milestone 1.1 Fix 1: 新Sponza Demohttp://www.shnenglu.com/lingjingqiu/archive/2011/07/17/151230.htmlI明{I明{Sun, 17 Jul 2011 09:46:00 GMThttp://www.shnenglu.com/lingjingqiu/archive/2011/07/17/151230.htmlhttp://www.shnenglu.com/lingjingqiu/comments/151230.htmlhttp://www.shnenglu.com/lingjingqiu/archive/2011/07/17/151230.html#Feedback0http://www.shnenglu.com/lingjingqiu/comments/commentRss/151230.htmlhttp://www.shnenglu.com/lingjingqiu/services/trackbacks/151230.html目主页Q?/font>

源码下蝲地址Q?/font>

  • Zip格式Q?a title="https://bitbucket.org/wuye9036/salvia/get/tip.tar.bz2" >https://bitbucket.org/wuye9036/salvia/get/tip.tar.bz2
  • Mercurial地址1Q?a href="https://wuye9036@bitbucket.org/wuye9036/salvia">https://bitbucket.org/wuye9036/salvia
  • Mercurial地址2Q?a >https://code.google.com/p/softart/
版本Q?/font>
  • Milestone 1.1 Fix 1
更新记录Q?/font>
  • d?jin)?jin)新的DemoQSponza
  • Wavefront Objd?2位烦(ch)引的支持?
  • 修复?Wavefront Obj 错误的顶点共享的问题?
  • 修复?Mip-map 计算错误的问题?
  • 修复?jin)对多边形错误剔除的问题?/li>
Demo下蝲Q?/font>

Demo截图Q?/strong>

image

image

image



I明{ 2011-07-17 17:46 发表评论
]]>
ۺϾþþƷ| þþþþþþþþþƷ| ҹ888þ| רþ| þþþó˾ƷĻ | Ʒþþþþ| ŷ þ| þþƷѹۿ| þ㽶߿ۿ| ľƷþþþ޲| þavСݲ| þˬˬƬAV | 97Ʒ˾þô߽app| Ʒþþþû| ˳ɾƷþþþ| þĻ| ɫۺϾþþþ| Avþ| þĻ| ŷ˾þþƷ| þ99ȺݺɫƷһ| AV12þ| ҹƵþþþһ| Ʒþþþ| ޹Ʒþ66| þ99ƷۺϹҳ| ɫۺϾþþĻ | þþƷ99þ޶| þþƷƷʢۿ| ɫʹþۺ| þþWWW| þþþ뾫Ʒapp| ѹۿ˾þѹۿ| 69ۺϾþþƷ| vaþþþͬ| ŷ޹Ʒþ| 99þѹƷػ| þøŮ߳MBA| ˳ɾƷþþþ| vaþþþúݺ| ŷɫ۾þþƷ|