青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

歲月流轉,往昔空明

C++博客 首頁 新隨筆 聯系 聚合 管理
  118 Posts :: 3 Stories :: 413 Comments :: 0 Trackbacks

梗概

SALVIA 0.5.2 的優化經歷是一個“跌宕起伏”的過程。這個過程的結果很簡單:

在Core 2 Duo T5800(2.0GHz x 2)上,Sponza的性能提升了60%,ComplexMesh性能提升了26%。

 

背景

SALVIA的整個渲染流程主要是以下幾部分:

  • 根據Index Buffer獲得需要進行變換的頂點;
  • 將頂點利用Vertex Shader進行變換;
  • 將變換后的頂點,輸出成若干個float4;
  • 將三角形光柵化。SALVIA的光柵化是將三角形拆分成4x4的像素塊若干,不滿的塊有掩碼來處理;
  • 將像素進行插值;
  • 插完值后把像素送到Pixel Shader中處理一趟;
  • 處理完的結果用Blend Shader塞到Back buffer里面去。

用于測試的場景:

  • Sponza 26萬個面,20個左右的Diffuse紋理(1024x1024);
  • PartOfSponza 約200個面,4個Diffuse紋理(1024x1024);
  • ComplexMesh 兩萬個面,無紋理,有個能量保守的光照。

最初的版本(V1231)中,性能的主要瓶頸在插值階段,各種耗時林林總總占了一半以上(50% - 70%)。

相比之下其他階段對性能的影響要么有限,要么沒有多少優化空間。所以最近一周的優化,就都集中在了“插值”上。

 

插值算法

線性的插值算法常見的實現有兩種,

第一種是拿UV插值,第二種是用ddx和ddy累積。

UV是先計算像素的u和v(基本方法是用面積比,不記得就復習一下中學幾何吧),然后用插值公式:

pixel = v0 * u + v1 * v + v2 * (1-u-v)

后者的步驟是選一個主頂點,然后計算這個頂點的ddx和ddy,最后用

pixel = v0 + ddx * offset_x + ddy * offset_y

計算出相應頂點。

但是在圖形學中,我們還需要對插值進行透視修正,獲得在3D空間中線性的插值結果。

我們將步驟修正到透視空間

先將v0,v1,v2弄到透視空間中,變成projected_v0, projected_v1, projected_v2

對于UV的插值是

pixel = ( projected_v0*u + projected_v1*v + projected_v2 * (1-u-v) ) / pixel_w

對于用ddx和ddy的累積公式是:

pixel = ( projected_v0 + projected_ddx * offset_x + projected_ddy * offset_y ) / pixel_w

 

插值算法的選擇

何詠(Graphixer)大神之前也寫了一個渲染器,比我快許多(大概是4-6倍),用的是UV;

gameKnife大神兩個禮拜寫成的渲染器,速度比我用五年寫出來的半成品要快7倍,用的辦法是Lerp到Scanline上,再Lerp到像素。

SALVIA采用了累積法:

struct transformed_vertex { float4 attributes[MAX_ATTRIBUTE_COUNT]; };
transformed_vertex projected_corner;

// 計算角點的坐標
projected_scanline_start = projected_v0 + projected_ddx * offset_x + projected_ddy * offset_y; 

// 像素的透視修正值
float inv_w; 

// 最終輸出的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)
  {
      // 透視空間轉換到線性空間并輸出到px_in中
      px_in[i][j] = unproject( projected_pixel );
     // 累加x方向上的值(透視空間)
      projected_pixel += projected_ddx;
  }
  // 累加y方向上的值(透視空間)
  projected_scanline_start += projected_ddy;
}

 

本輪優化之前對插值算法的優化嘗試

注意那個MAX_ATTRIBUTE_COUNT,這個值通常比較大,在v1231中,它是32。

不過,顯然我們不需要對所有的屬性進行計算。敏敏在這里運用了一點小小的技巧進行了優化:只計算必要的屬性。同時,為了減少分支的使用,他甚至用

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];
    }
}

并配合函數指針的方法,以促使編譯器展開循環,減少分支。

不過從實際生成的匯編來看,這個部分并沒有被展開到期望的形式,可能是編譯器認為x86的Branch Predication性能已經足夠高了吧。

這個“優化”在v1231中就已經具備了。

 

首輪優化:unproject函數,operator += 與 operator =

第一個Profiling是用BenchmarkPartOfSponza和Sponza跑的;unproject,operator +=和operator = 加在一起大約占用了15-20%的時間。單獨的unproject

最初的實現就是普通的標量。既不要求對齊,也沒有使用SIMD。

所以當然會以為用了SIMD后,優化效果會很好。于是在v1232中,中間頂點和像素輸入的分配都以16字節對齊,unproj,+=和=也都使用了SSE進行了重寫。

從跑分來看,PartOfSponza性能提升了20%。但是,在測試ComplexMesh和Sponza時,并未發現幀率有顯著提升。

其實在進行優化之前,何詠就告誡過我,因為現代CPU的一些技術,比方說超標量啥的,四個數據寬度的SSE和標量運算相比,就只有50%的性能差距。

并且這些函數的指令已經極為簡單,瓶頸也很明確的落在計算指令上。例如Unproject優化后,性能焦點就落在_mm_mul_ps上(3.7%),幾無優化余地。

 

二輪優化:插值算法的調整

在進行第二輪優化之前同樣運行了一次Profiling。因為對PartOfSponza性能基本滿意,因此這次優化的目標主要在Sponza上。

排名前幾位的小函數,分別是sub_n,unproj,+= 和tex2D。對sub_n例行優化后,性能沒什么變化。當然,這也是意料之中的事情了。

因此,第二輪優化便著重考慮在插值算法本身上。

在優化之前,我嘗試對代碼成本做個粗略的評估:

在現有算法下,假設每個像素有N個需要插值的屬性,則平均每個像素有

(corner)3N/16個讀 + 2N/16個乘法 + 2N/16個加法 + N/16個寫

(x:+=)2N個讀 + N個加法 + N個寫

(x:*)  N個讀 + 1個標量除法 + N個乘法 + N個寫

(y:+=)2N/4個讀 + N/4個加法 + N/4個寫

(y:=) N/4個讀 + N/4個寫

因為每個都是函數指針,所以這些都是優化不掉的。因此首先將一些操作合并了一下,比如把+= 和*合并以減少一下讀寫操作。只可惜效果也不是很明顯。

 

第二刀就砍到算法的頭上。因為累加本身是為了減少乘法的運用,但是這可能帶來了多余的存取開銷。

因此直接套用公式:

pixel = ( projected_v0 + projected_ddx * offset_x + projected_ddy * offset_y ) / pixel_w

這樣就有:3N讀,2N乘法,2N加法,N個乘法和N個寫(假設寄存器夠用的話)。不算Corner的計算成本,這樣比較一下,就等于是3N/4個讀,N/2+N個寫,N/4個加法來換取2N個乘法的時間。本來以為作為IO瓶頸的應用,這樣可以提高一些性能。不過結果證實這個買賣實在是很不劃算,整體性能不增反減。

 

三輪優化:減少內存占用,柳暗花明

雖然所有的操作只針對已使用的屬性,但是空間上還是浪費了許多。

考慮到內存占用較大也會導致一些性能損失,于是將MAX_ATTRIBUTE_COUNT從32下調到了8。

結果令人大跌眼鏡。性能瞬間提升了20-30%之多。

再加上SSE也不知道為什么開始發力了,使用上之后性能大約又有了10-15%的提升。

我猜測可能是因為換頁頻率下降,以及Cache的命中率提升。不過手上沒有VTune這種工具,所以也不太好驗證。

 

四輪優化:精度敏感性下降的額外紅利

在這輪優化之后,PartOfSponza出現了精度問題。因為視錐體的上下左右四個面都沒有Clip,所以可能會出現非常大的三角形。這樣累積的時候一旦起始點選擇的不好,就會出現比較大的誤差。在之前版本中,使用/fp: precise來減少這一問題出現的機會。但是因為使用了SSE,也讓這個問題再難解決。因此我選用了一些辦法,來改善精度問題。在大問題都修正以后,換用/fp: fast來編譯整個SALVIA,最終也獲得了0-10%左右的性能收益。

 

結論

對于運算和IO都密集的程序來說,優化真可能是牽一發而動全身的問題。比如在我的例子中,所有猜測是性能瓶頸的地方,都沒有得到預想中的改善。

倒是在內存占用這個地方無心插柳,才得以柳暗花明,而且還讓別的優化方案體現了價值。所以如果你不像qiaojie大牛那樣對x86了如指掌,還是要習慣于從多方面猜測,例如內存占用,對齊或緊縮,計算強度,訪存密度,并行度等多個角度進行設想并用實踐去驗證。盡管可能會遇到很多挫折,但是,只要是直覺上有優化的余地,一般都可以找到合適的方案。

posted on 2013-02-11 20:09 空明流轉 閱讀(2837) 評論(2)  編輯 收藏 引用

評論

# re: SALVIA 0.5.2優化談 2013-02-15 23:56 egmkang
跪拜巨巨  回復  更多評論
  

# re: SALVIA 0.5.2優化談 2014-02-17 23:17 Kitchen020
一直有SALVIA的代碼,最近開始研究,LZ繼續努力!!  回復  更多評論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲精品美女久久7777777| 久久婷婷国产综合国色天香| 久久婷婷麻豆| 久久久亚洲欧洲日产国码αv | 午夜在线观看免费一区| 国产精品乱码妇女bbbb| 久久精品99国产精品| 久久久久久久久久久久久女国产乱 | 99热免费精品在线观看| 欧美日韩一级黄| 欧美主播一区二区三区| 久久精品国产亚洲高清剧情介绍| 在线日韩av| 日韩视频在线观看免费| 国产精品尤物福利片在线观看| 久久久噜久噜久久综合| 欧美激情一区二区三区在线视频观看| 亚洲在线日韩| 久久精品欧美日韩| 一区二区成人精品| 欧美一进一出视频| 亚洲精品免费在线观看| 亚洲一二三区在线观看| 在线欧美影院| 亚洲一区免费观看| 亚洲精品久久久久久久久久久久久 | 老司机精品导航| 欧美色欧美亚洲另类二区| 久久久亚洲精品一区二区三区| 欧美精品在线免费播放| 久久久噜噜噜久久中文字免| 欧美日本二区| 欧美成人午夜视频| 国产精品伊人日日| 日韩视频一区二区| 亚洲日本一区二区| 久久精品最新地址| 午夜精品在线看| 欧美日本亚洲视频| 免费观看在线综合色| 国产精品丝袜白浆摸在线| 欧美高清视频| 伊人久久婷婷色综合98网| 亚洲午夜一区二区三区| 一区二区国产在线观看| 久久综合福利| 久久伊人精品天天| 国产女精品视频网站免费 | 亚洲精品无人区| 亚洲国产va精品久久久不卡综合| 亚洲欧美韩国| 欧美一区二区三区另类 | 欧美凹凸一区二区三区视频| 久久国产精品99久久久久久老狼| 国产精品www.| 一区二区高清视频| 欧美日韩中文在线观看| 亚洲综合精品一区二区| 欧美精品 日韩| 欧美国产精品专区| 亚洲国产影院| 免费久久99精品国产自| 欧美护士18xxxxhd| 亚洲国产欧美日韩精品| 麻豆精品一区二区综合av| 美女国产精品| 亚洲国产精品国自产拍av秋霞| 久久精品亚洲一区| 美女网站在线免费欧美精品| 好吊色欧美一区二区三区四区| 久久国产精品99国产精| 免费视频一区| 日韩亚洲欧美一区| 欧美亚男人的天堂| 午夜精品福利一区二区蜜股av| 欧美影院在线| 在线看成人片| 欧美精品免费在线| 中文在线不卡| 久久理论片午夜琪琪电影网| 亚洲电影免费观看高清完整版在线 | 亚洲人成网站精品片在线观看| 亚洲精品欧美激情| 国产精品久久久久999| 欧美一级久久| 欧美激情第3页| 亚洲图片在区色| 国产日韩欧美中文在线播放| 久久这里有精品15一区二区三区| 亚洲国产欧美一区二区三区同亚洲 | 亚洲第一网站免费视频| 欧美久久电影| 午夜亚洲伦理| 亚洲国产视频a| 欧美在线免费一级片| 亚洲高清免费在线| 国产精品久久九九| 六月婷婷一区| 校园春色综合网| 91久久国产自产拍夜夜嗨| 欧美影院午夜播放| 一本色道久久综合亚洲精品按摩| 国产麻豆精品在线观看| 毛片一区二区三区| 亚洲欧美电影在线观看| 亚洲国产一区二区视频| 久久99伊人| 中文网丁香综合网| 在线视频观看日韩| 国产精品久久久久久影视| 欧美大片在线观看一区| 欧美在线观看网站| 制服诱惑一区二区| 亚洲成人直播| 美女黄网久久| 久久精品道一区二区三区| 亚洲一区二区三区乱码aⅴ| 亚洲二区三区四区| 韩国v欧美v日本v亚洲v| 国产精品久久久久77777| 欧美片网站免费| 另类激情亚洲| 久久久91精品| 亚洲天堂久久| 国产日本欧美一区二区三区在线| 久久一区二区三区超碰国产精品| 亚洲一区二区免费看| 亚洲国产精品久久久久久女王| 久久综合99re88久久爱| 久久丁香综合五月国产三级网站| 中文精品视频| av成人黄色| 日韩午夜在线电影| 日韩网站在线| 一区二区冒白浆视频| 亚洲精品国精品久久99热一| 亚洲高清精品中出| 亚洲国产精品视频一区| 亚洲国产岛国毛片在线| 在线视频观看日韩| 亚洲高清不卡| 99riav1国产精品视频| 日韩亚洲欧美一区| 亚洲视频一二| 午夜激情亚洲| 久久国产精品亚洲va麻豆| 欧美一区二区三区播放老司机| 欧美亚洲综合久久| 久久精品91久久香蕉加勒比| 久久久噜噜噜久久久| 美日韩免费视频| 亚洲电影免费| 亚洲伦理在线观看| 亚洲一区二区三区777| 午夜精品久久久久久久99黑人| 午夜综合激情| 美日韩精品免费| 欧美日韩精品一区| 国产老女人精品毛片久久| 国内精品嫩模av私拍在线观看| 尤物在线观看一区| aa级大片欧美三级| 欧美综合国产| 亚洲成在线观看| 一本色道久久88综合日韩精品| 午夜亚洲性色福利视频| 久久一区二区三区四区五区| 欧美精选午夜久久久乱码6080| 欧美少妇一区二区| 国产综合精品| 99精品欧美一区二区三区综合在线| 亚洲欧美www| 久热精品视频| 9l视频自拍蝌蚪9l视频成人| 欧美一级二级三级蜜桃| 欧美福利视频网站| 国产日本亚洲高清| 亚洲免费av网站| 久久久久国内| 在线一区二区三区四区五区| 欧美一区二区私人影院日本| 欧美国产精品一区| 国产视频在线观看一区| 一本一本大道香蕉久在线精品| 久久国产加勒比精品无码| 亚洲国产乱码最新视频| 欧美亚洲三区| 欧美午夜久久| 亚洲精品女人| 蜜桃精品一区二区三区 | 亚洲大胆在线| 欧美主播一区二区三区| 欧美日韩亚洲一区二区| 亚洲激情电影中文字幕| 久久国产精品电影| 在线亚洲电影| 欧美日韩国产首页| 亚洲精品一品区二品区三品区| 久久久久久成人| 亚洲欧美清纯在线制服|