<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Render Loop</title>
	<atom:link href="http://renderloop.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://renderloop.wordpress.com</link>
	<description>frame by frame, again and again...</description>
	<lastBuildDate>Sat, 11 Jul 2009 17:00:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='renderloop.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://1.gravatar.com/blavatar/53ae5b0dd53fbf42ef4c2ee2f3fce5f8?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>Render Loop</title>
		<link>http://renderloop.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://renderloop.wordpress.com/osd.xml" title="Render Loop" />
	<atom:link rel='hub' href='http://renderloop.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Render M materials and N lights</title>
		<link>http://renderloop.wordpress.com/2009/07/06/render-m-materials-and-n-lights/</link>
		<comments>http://renderloop.wordpress.com/2009/07/06/render-m-materials-and-n-lights/#comments</comments>
		<pubDate>Sun, 05 Jul 2009 16:49:23 +0000</pubDate>
		<dc:creator>renderloop</dc:creator>
				<category><![CDATA[學習研究]]></category>
		<category><![CDATA[deferred shading]]></category>
		<category><![CDATA[lighting]]></category>
		<category><![CDATA[shading]]></category>

		<guid isPermaLink="false">http://renderloop.wordpress.com/?p=130</guid>
		<description><![CDATA[在 hardware render pipeline 中，若現在場景內有 M 個 material 相異的物件與 N 盞 lights， render 的方式會有幾種選擇？ single-pass, multi-light multi-pass, multi-light deferred shading Single-pass, Multi-light for each object: 　render object with all lights in one shader 此種作法是最單純且直接，但是此方式會連 hidden surface 也一併 shading ，造成運算上的浪費。此外，當光源數目 N &#8230; <a href="http://renderloop.wordpress.com/2009/07/06/render-m-materials-and-n-lights/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=renderloop.wordpress.com&amp;blog=4637338&amp;post=130&amp;subd=renderloop&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>在 hardware render pipeline 中，若現在場景內有 M 個 material 相異的物件與 N 盞 lights， render 的方式會有幾種選擇？</p>
<ul>
<li><strong>single-pass, multi-light</strong></li>
<li><strong>multi-pass, multi-light</strong></li>
<li><strong>deferred shading</strong><em><code> </code></em></li>
</ul>
<h3></h3>
<h3>Single-pass, Multi-light</h3>
<blockquote><p><code> for each object:<br />
　render object with all lights in one shader<br />
</code></p></blockquote>
<p>此種作法是最單純且直接，但是此方式會連 hidden surface 也一併 shading ，造成運算上的浪費。此外，當光源數目 N 很大的時候，shader code 必須擴展進而去計算每盞光源的作用。但若是指令數超過 shader model 的限制時(視 shader model 而定)，就不得不拆成多個 render pass。</p>
<h3>Multi-pass, Multi-light</h3>
<blockquote><p><code>for each light:<br />
　for each object affected by light:<br />
　　render target += BRDF(object, light)</code></p></blockquote>
<p>這方式是將每盞燈光的所影響的結果累加於 render target，+= 的部分是透過 ping-pong 的方式在兩個 render target 之間作替換。然而 invisible surface 所造成的計算浪費仍舊沒有獲得解決之道，新增的 geometry pass 也在 vertex transform 與 setup 的部分帶來了額外的開銷。這部份的問題，雖然可以透過粗略的 front-to-back sorting 獲得一些抒解，但 deferred shading 卻對此問題有著更根本的解決方案(當然也會帶來其他的限制)。</p>
<h3>Deferred Shading</h3>
<blockquote><p><code>for each object:<br />
　render lighting properties to G-buffer<br />
for each light:<br />
　render target += BRDF(G-buffer, light)</code></p></blockquote>
<p>Deferred shading 之所以能解決 hidden surface 所造成的 shading 浪費，主要是因為它在第一階段先輸出 position, normal 與其他參數至 G-buffer。使第二階段的 lighting 運算能完全作用在 visible 的 fragment 上，同時也有助於降低 light/object 之間的相依性，藉此達到 render 效率的提升。一切看起來似乎都很美好，但故事就這樣結束了嗎？喔！不，故事才剛開始&#8230;</p>
<p><span id="more-130"></span></p>
<p>每個 pixel 的顏色在 <a title="Cg Tutorial - Ch5 Lighting" href="http://http.developer.nvidia.com/CgTutorial/cg_tutorial_chapter05.html" target="_blank">lighting</a> 的階段是由 ambient, diffuse 和 specular 這三個部分所組合而成的。由於 deferred shading 一般都把 ambient light 和 environment light 的部分拆在其他 pass 獨立運算，因此在僅考慮 local lighting model 的情況下，deferred shading 的公式主要可分為 diffuse 和 specular 兩個部分：</p>
<p><img src='http://s0.wp.com/latex.php?latex=L_o%28v%29%3D%5Csum_%7Bk%3D1%7D+%5En%7B%28c_%7Bdiff%7D%2Af_%7Bdiff%7D%28v%2Cn%2CI_%7BL_k%7D%29%2Bc_%7Bspec%7D%2Af_%7Bspec%7D%28v%2Cn%2Cl_k%2CI_%7BL_k%7D%29%29%7D&amp;bg=0f0f0f&amp;fg=bbbbbb&amp;s=1' alt='L_o(v)=&#92;sum_{k=1} ^n{(c_{diff}*f_{diff}(v,n,I_{L_k})+c_{spec}*f_{spec}(v,n,l_k,I_{L_k}))}' title='L_o(v)=&#92;sum_{k=1} ^n{(c_{diff}*f_{diff}(v,n,I_{L_k})+c_{spec}*f_{spec}(v,n,l_k,I_{L_k}))}' class='latex' /></p>
<p>其中 <img src='http://s0.wp.com/latex.php?latex=f_%7Bdiff%7D&amp;bg=0f0f0f&amp;fg=bbbbbb&amp;s=0' alt='f_{diff}' title='f_{diff}' class='latex' /> 和 <img src='http://s0.wp.com/latex.php?latex=f_%7Bspec%7D&amp;bg=0f0f0f&amp;fg=bbbbbb&amp;s=0' alt='f_{spec}' title='f_{spec}' class='latex' /> 是 diffuse 和 specular 的 local reflection model(ex. lambert, phong, blinn, &#8230; etc)，<img src='http://s0.wp.com/latex.php?latex=c_%7Bdiff%7D%2C+c_%7Bspec%7D&amp;bg=0f0f0f&amp;fg=bbbbbb&amp;s=0' alt='c_{diff}, c_{spec}' title='c_{diff}, c_{spec}' class='latex' /> 是 surface 的 diffuse 和 specular color，<img src='http://s0.wp.com/latex.php?latex=l_k&amp;bg=0f0f0f&amp;fg=bbbbbb&amp;s=0' alt='l_k' title='l_k' class='latex' /> 與 <img src='http://s0.wp.com/latex.php?latex=I_%7BL_k%7D&amp;bg=0f0f0f&amp;fg=bbbbbb&amp;s=0' alt='I_{L_k}' title='I_{L_k}' class='latex' /> 則分別代表著第 k 盞燈光的方向與 intensity。</p>
<p>傳統的 deferred shading 大致將上式的運算分解成下列步驟：</p>
<ol>
<li>render 場景內<strong>非</strong>透明的物件，並將所需的參數存至 G-buffer (ex. position, normal, albedo, roughness, &#8230; etc)。</li>
<li>render 一個 image plane (screen space quad)，在 pixel shader 中透過 texture sampler 讀取所需的參數並完成上面 shading 的計算。</li>
<li>按照 back-to-front 的順序，render 場景中透明的物件。</li>
</ol>
<p>現在，light/object 的相依性已經從原先的 O(MN) 轉變至 O(N)，也就是說，現在運算複雜度主要會卡在步驟 2 的 fill-rate。其效率主要受到兩個因素所影響：傳輸 G-buffers 所需的 bandwidth 與燈光的個數 N 。</p>
<p>G-buffers 所儲存的資訊和場景中那 M 個 material 有著密切的關係，當 M 個 material 的 reflection model 過於複雜時，G-buffers 必然要儲存更多的資訊，否則便無法在步驟 2 中完成相對應的 shading 計算。因此，降低 bandwidth 的方式便是針對場景內 M 個 material 的內容作進一步的調整與簡化，試圖在 visualization 和 computation 之間作個取捨。而 G-buffers 裡各參數的配置也要作更詳盡的規劃，使其盡可能滿足 MRT 的 layout 以便增進步驟 1 中 G-buffers 的輸出效率。</p>
<p>有了 G-buffers 所提供的 material 資訊之後，便可在步驟 2 中搭配 lights 的各項參數完成 shading 的計算。為了要在一個 pixel shader 中同時支援 directional lights, spot lights 和 point lights 的運算，直覺的作法便是在 pixel shader 中用 branch 分派運算的內容，並盡可能在同一個 pass 處理複數盞燈(因為一旦 N 的數目變大，accumulate 的成本便隨之提升)。此外，為了增進 fill-rate ，對於 spot lights 和 point lights 等具範圍性的光源，尚可以搭配 stencil buffer 來濾掉一些燈光所照射不到的 pixels ，盡可能地降低 pixel shader 的負擔。</p>
<h3>Light Indexed Deferred Lighting</h3>
<p>既然，material 的複雜度會嚴重影響到 bandwidth，那何不反過來，把參數複雜度較為固定的 light 資訊存進 buffers 中呢？LIDL [<a href="http://lightindexed-deferredrender.googlecode.com/files/LightIndexedDeferredLighting1.1.pdf">Damian Trebilco</a>] 的概念就是作了一個這樣的嘗試，不過它不是在每個 shading pixel 裡直接紀錄 light 的參數(ex. position, color, attenuation, &#8230; etc)，而是先賦予每個 light 一個獨立的 index，將其記錄在每個 shading pixel 中，然後透過這 index 去另一批參數 buffers 擷取 light 的參數。主要的步驟大致如下：</p>
<ol>
<li>render depth。</li>
<li>將每盞燈影響的範圍(light volume)  render 至 light index texture。</li>
<li>用 forward rendering 的方式 render geometry，從 light index texture 擷取參數並完成 lighting 的運算。</li>
</ol>
<p>步驟 1 是為了讓步驟 2 能免去 hidden surface 造成的運算浪費。步驟 2 主要的目的則是記錄每個 pixel 會被哪些燈光所影響，降低後續 lighting 計算方面的開銷。儘管現在需要 cache 的參數相對降低，但在步驟 2 中有時會發生 light volume 重疊的情況。RGBA 共可以記錄 4 個 indices，倘若每個 pixel 受到超過 4 盞光源的照射，一種作法是按照 priority 篩選出 4 盞燈光，或是增加 buffer 來記錄更多組 index(但除非每個 pixel 都被超過 4 個的光源所照射，不然在一般情況下，這方式恐怕不會帶來令人滿意的效益)。</p>
<p>除了 light index texture 之外，還需要另一批 textures 來儲存每盞燈光的各項參數。根據燈光種類的不同，各參數於 textures 中的配置會是另一項議題。若參數儲存配置不得宜，一樣會造成 bandwidth 的瓶頸。要舒緩這部份的問題，還是需要做出取捨，去調整與簡化 lighting 運算的實作才行。</p>
<h3>Pre-Lighting / Light Pre-Pass Render</h3>
<p>為了降低傳統 deferred shading 於 bandwidth 的瓶頸，pre-lighting/light pre-pass render 的觀念也在近幾年應運而生[<a href="http://diaryofagraphicsprogrammer.blogspot.com/2008/03/light-pre-pass-renderer.html">Wolfgang Engel</a>] [<a href="http://www.crytek.com/fileadmin/user_upload/inside/presentations/2009/A_bit_more_deferred_-_CryEngine3.ppt">CryEngine3</a>]。和以往最大不同的地方是它把 lights 相關的性質(ex. light color, attneuation, N.L, &#8230;etc)，再進一步從 shading 公式中抽離出來：</p>
<p><img src='http://s0.wp.com/latex.php?latex=L_o%28v%29%3Dc_%7Bdiff%7D%2A%5Csum_%7Bk%3D1%7D+%5En%7Bf_%7Bdiff%7D%28v%2Cn%2CI_%7BL_k%7D%29%7D+%2B+c_%7Bspec%7D%2A%5Csum_%7Bk%3D1%7D%5En%7Bf_%7Bspec%7D%28v%2Cn%2Cl_k%2CI_%7BL_k%7D%29%7D&amp;bg=0f0f0f&amp;fg=bbbbbb&amp;s=1' alt='L_o(v)=c_{diff}*&#92;sum_{k=1} ^n{f_{diff}(v,n,I_{L_k})} + c_{spec}*&#92;sum_{k=1}^n{f_{spec}(v,n,l_k,I_{L_k})}' title='L_o(v)=c_{diff}*&#92;sum_{k=1} ^n{f_{diff}(v,n,I_{L_k})} + c_{spec}*&#92;sum_{k=1}^n{f_{spec}(v,n,l_k,I_{L_k})}' class='latex' /></p>
<ol>
<li>render 非透明的物件，輸出 normal, depth 等資訊。</li>
<li>render 一個 screen quad pass，將 lights 的屬性輸出至 light buffers。</li>
<li>再 render 一次場景內所有不透明的物件，搭配 light buffers 的各項資訊完成每個 material 的 shading 計算。</li>
<li>render 場景內透明的物件。</li>
</ol>
<p>這方式最大的優點是有效降低參數傳遞的 bandwidth，但是它最大的代價是需要兩次 geometry pass (步驟 1 和 3 )。此外，步驟 2 輸出的資訊可能無法充分滿足 material 的運算式，進而造成 material 設計彈性上的犧牲(像是 roughness 在步驟 2 中便無法得到確切的數值，替代方案是用定值或是從步驟 3 中 reconstruct 出 R.V 再運算 roughness 的影響)。此法的中心思想是降低 bandwidth，所以步驟 1 和 2 輸出的資訊自然也不能為了滿足 material 的運算而過度膨脹，若是 bandwidth 沒有達到某種程度的節約，第二次的 geometry pass 就會顯得不太值得，變成無謂的額外開銷。</p>
<p>以上，便是我目前為止對 deferred shading  粗淺的認識。基本上，deferred shading 的目的就是要去除 invisible surface 的 shading 浪費，同時並降低 light 與 object 之間的耦合度，使其在 M 個 material 相異的物件與 N 盞 lights 的情況下，盡可能地提升 render 的效率。各種形式的 deferred shading 都沒有絕對的優劣高下，所以在實際應用的過程中，還是免不了要在彼此的優缺點中不斷地作出權衡與取捨&#8230;</p>
<h3>References</h3>
<ul>
<li><a href="http://www.realtimerendering.com/blog/deferred-lighting-approaches/">Deferred lighting approaches</a> from Real-Time Rendering</li>
<li><a href="http://www.wolfgang-engel.info/RendererDesign.zip">The Light Pre-Pass Renderer &#8211; Designing a Renderer for Multiple Lights</a>, by <a href="http://diaryofagraphicsprogrammer.blogspot.com/">Wolfgang Engel</a></li>
<li><a href="http://download.nvidia.com/developer/presentations/2004/6800_Leagues/6800_Leagues_Deferred_Shading.pdf">6800 Leagues Deferred Shading</a></li>
<li><a href="http://www.beyond3d.com/content/articles/19/1">Photo-realistic Deferred Lighting</a> from Beyond3D</li>
</ul>
<br />Posted in 學習研究 Tagged: deferred shading, lighting, shading <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/renderloop.wordpress.com/130/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/renderloop.wordpress.com/130/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/renderloop.wordpress.com/130/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/renderloop.wordpress.com/130/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/renderloop.wordpress.com/130/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/renderloop.wordpress.com/130/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/renderloop.wordpress.com/130/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/renderloop.wordpress.com/130/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/renderloop.wordpress.com/130/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/renderloop.wordpress.com/130/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/renderloop.wordpress.com/130/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/renderloop.wordpress.com/130/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/renderloop.wordpress.com/130/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/renderloop.wordpress.com/130/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=renderloop.wordpress.com&amp;blog=4637338&amp;post=130&amp;subd=renderloop&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://renderloop.wordpress.com/2009/07/06/render-m-materials-and-n-lights/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/539e6469384c5c9dbbdd22212389ac1c?s=96&#38;d=identicon" medium="image">
			<media:title type="html">renderloop</media:title>
		</media:content>
	</item>
		<item>
		<title>y-twist cont.</title>
		<link>http://renderloop.wordpress.com/2009/04/16/y-twist-cont/</link>
		<comments>http://renderloop.wordpress.com/2009/04/16/y-twist-cont/#comments</comments>
		<pubDate>Wed, 15 Apr 2009 17:54:10 +0000</pubDate>
		<dc:creator>renderloop</dc:creator>
				<category><![CDATA[程式筆記]]></category>
		<category><![CDATA[CUDA]]></category>

		<guid isPermaLink="false">http://renderloop.wordpress.com/?p=102</guid>
		<description><![CDATA[上次只用一個 thread 算 y-twist 的時候成效不彰，這次便把它拆成一堆 thread blocks 來試試看!! 先前提到要讓 SM 中平行處理的 wraps 數目越多越好，使其盡可能地增進平行化的效能。但在這次實驗的發現，y-twist 的 kernel 在 block size 設定為 512 或是 64 個 threads 去 deform 99 萬個 vertices 時，運算時間的差距其實只在 1 ms 左右。所以接下來便以每個 block  含 512 個 threads 為前提，將 memory &#8230; <a href="http://renderloop.wordpress.com/2009/04/16/y-twist-cont/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=renderloop.wordpress.com&amp;blog=4637338&amp;post=102&amp;subd=renderloop&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><img class="alignnone size-full wp-image-103" title="y-twist-test" src="http://renderloop.files.wordpress.com/2009/04/y-twist-test.png?w=584" alt="y-twist-test"   /></p>
<p>上次只用一個 thread 算 y-twist 的時候成效不彰，這次便把它拆成一堆 thread blocks 來試試看!!</p>
<p><span id="more-102"></span></p>
<p>先前提到要讓 SM 中平行處理的 wraps 數目越多越好，使其盡可能地增進平行化的效能。但在這次實驗的發現，y-twist 的 kernel 在 block size 設定為 512 或是 64 個 threads 去 deform 99 萬個 vertices 時，運算時間的差距其實只在 1 ms 左右。所以接下來便以每個 block  含 512 個 threads 為前提，將 memory access 的部分作為變因，再繼續作一些小測試。</p>
<p>將上次 kernel 中的 for loop 展開成 1D 的 grid ，每個 grid cell 含有一個 2D block 會變成下面這個新的 kernel：</p>
<p><pre class="brush: cpp;">
__global__ void gpu_twist(float4 pts[], float magnitude, float env)
{
	int k = blockIdx.x * BLOCK_WIDTH * BLOCK_WIDTH + threadIdx.y * BLOCK_WIDTH + threadIdx.x;

	float ff = magnitude * pts[k].y * env;
	if( ff != 0.0f )
	{
		double cct = __cosf(ff);
		double cst = __sinf(ff);
		double tt = pts[k].x * cct - pts[k].z * cst;

		pts[k].z = pts[k].x * cst + pts[k].z * cct;
		pts[k].x = tt;
	}
}
</pre></p>
<p>拆成多個 threads 之後，運算時間便從 1620 ms 大幅降為 19 ms，而對照組 CPU 版本的計算時間則是大約在 120 ms 左右(可見在 GPU 只用一個 thread 作運算有多麼搞笑)。現在 kernel 裡的變數除了幾個是 automatic variable 之外，其餘都是來自 global memory。因為 y-twist 的運算單純到沒變數需要 share，所以接著要作的事便是把一些多次存取 global memory 的部分轉至 automatic variable 中。不過我在這過程中犯了一個錯誤：我原先認為 pts[k].y 只被讀取一次，若將其放進 automatic variable 中，反倒多浪費一個 register，似乎不太划算，因此我最初只把重複存取的 pts[k].x 和 .z  放進 automatic variable 中:</p>
<p style="padding-left:30px;">float ptX = pts[k].x;<br />
float ptZ = pts[k].z;</p>
<p>雖然這樣也可獲得一些成效，使計算時間降至 15.7 ms 左右，但後來在翻閱 programming guide 時發現了下面這一段話：</p>
<blockquote><p><em>the device is capable of reading 32-bit, 64-bit, or 128-bit words from global memory into registers in a single instruction.</em></p></blockquote>
<p>這代表直接把 pts 讀進 float4 其實比拆成兩個要有效率：</p>
<p style="padding-left:30px;">float4 pt = pts[k];</p>
<p>另一個重點是 kernel automatic variable 的個數其實並不直接等於 register 的個數!! 雖然它一般都會被放進 register 裡頭，但若遇到比較複雜的 structure 或是 array 時，這些變數是會放至 local memory 裡的 (其存取的 cost 和存取 global memory 是差不多的)。但這些資訊很難直接從程式碼中推測出來，有時稍微變更一下 expression 的順序，便會影響 register 的使用數目。若需精確查詢 kernel 裡面 register 的使用數目或是 shared/local/const memory 的使用量，有以下兩種方式：</p>
<ul>
<li>將 <strong>PtxAsOptionV</strong> 設為 Yes (&#8211;ptxas-options=-v)<br />
之後在 build 的時候，便可以在 output panel 看到每個 kernel 的資源使用狀況。</li>
<li>開啟 <strong>keep preprocessed files</strong><br />
相關資訊都寫在 .cubin 檔案中每個 code 區塊的標頭裡。</li>
</ul>
<p>此外， SDK 也提供了一個很實用的 excel 檔案 &#8212; <em>&#8220;CUDA_Occupancy_calculator&#8221;</em>。只要先選擇現在使用的 compute capability，並將剛剛那些查詢得來的數值一一輸入相對應的欄位，便可掌握目前 SIMT 配置 threads 的概況。</p>
<p>結果把 pts 的讀取方式作修改之後，每個 kernel 中使用的 register 數目雖由 6 個增為 8 個，但此數值仍是在安全範圍內。最後計算的時間則是再快個 1 ms，時間約為 13.7 ms。哈! Hello World 差不多告一段落了，該是找實戰練習題的時候了!! <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<br />Posted in 程式筆記 Tagged: CUDA <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/renderloop.wordpress.com/102/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/renderloop.wordpress.com/102/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/renderloop.wordpress.com/102/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/renderloop.wordpress.com/102/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/renderloop.wordpress.com/102/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/renderloop.wordpress.com/102/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/renderloop.wordpress.com/102/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/renderloop.wordpress.com/102/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/renderloop.wordpress.com/102/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/renderloop.wordpress.com/102/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/renderloop.wordpress.com/102/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/renderloop.wordpress.com/102/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/renderloop.wordpress.com/102/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/renderloop.wordpress.com/102/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=renderloop.wordpress.com&amp;blog=4637338&amp;post=102&amp;subd=renderloop&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://renderloop.wordpress.com/2009/04/16/y-twist-cont/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/539e6469384c5c9dbbdd22212389ac1c?s=96&#38;d=identicon" medium="image">
			<media:title type="html">renderloop</media:title>
		</media:content>

		<media:content url="http://renderloop.files.wordpress.com/2009/04/y-twist-test.png" medium="image">
			<media:title type="html">y-twist-test</media:title>
		</media:content>
	</item>
		<item>
		<title>SIMT 與 threads 配置的兩三事&#8230;</title>
		<link>http://renderloop.wordpress.com/2009/04/09/simt-%e8%88%87-threads-%e9%85%8d%e7%bd%ae%e7%9a%84%e5%85%a9%e4%b8%89%e4%ba%8b/</link>
		<comments>http://renderloop.wordpress.com/2009/04/09/simt-%e8%88%87-threads-%e9%85%8d%e7%bd%ae%e7%9a%84%e5%85%a9%e4%b8%89%e4%ba%8b/#comments</comments>
		<pubDate>Wed, 08 Apr 2009 16:53:53 +0000</pubDate>
		<dc:creator>renderloop</dc:creator>
				<category><![CDATA[程式筆記]]></category>
		<category><![CDATA[CUDA]]></category>

		<guid isPermaLink="false">http://renderloop.wordpress.com/?p=82</guid>
		<description><![CDATA[因為 CUDA 程式的執行效能存有太多和硬體實作相關的變因，所以在進一步改善 y-twist 小實驗的執行效能之前，先稍微把目前所瞭解的資訊作個概略的整理，希望能讓自己在未來優化程式時更有方向感… 若文中有任何錯誤的地方還煩請大家不吝指導!! CUDA 的架構是由 N 個 SM (streaming multiprocessor) 所構成的，而每個 SM 內含有 M 個 SP (scalar processor) 、 shared memory 和其他硬體原件。當 host CPU 呼叫 kernel function 時，硬體是以 block 為單位將工作分派給目前有能力處理的 SM 進行(據說以 block 為單位是為了方便 porting 至其他硬體)。當 SM &#8230; <a href="http://renderloop.wordpress.com/2009/04/09/simt-%e8%88%87-threads-%e9%85%8d%e7%bd%ae%e7%9a%84%e5%85%a9%e4%b8%89%e4%ba%8b/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=renderloop.wordpress.com&amp;blog=4637338&amp;post=82&amp;subd=renderloop&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>因為 CUDA 程式的執行效能存有太多和硬體實作相關的變因，所以在進一步改善 y-twist 小實驗的執行效能之前，先稍微把目前所瞭解的資訊作個概略的整理，希望能讓自己在未來優化程式時更有方向感… 若文中有任何錯誤的地方還煩請大家不吝指導!! <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
<span id="more-82"></span></p>
<p>CUDA 的架構是由 N 個 SM (streaming multiprocessor) 所構成的，而每個 SM 內含有 M 個 SP (scalar processor) 、 shared memory 和其他硬體原件。當 host CPU 呼叫 kernel function 時，硬體是<strong>以 block 為單位</strong>將工作分派給目前有能力處理的 SM 進行(據說以 block 為單位是為了方便 porting 至其他硬體)。當 SM 接受到任務之後，便會處理手頭上的 blocks，執行其中所包含的 threads。當手邊任一個 block 裡的 threads 皆執行完畢之後，該 SM 才能再去多接另一個新的 block 的工作。</p>
<p>那 SM 是如何處理 block 呢？ CUDA 是透過一個稱為 SIMT (<em>single-instruction, multiple-thread</em>) 的架構來處理整個流程。SIMT 會將數以千百計的 threads 分成一堆 wraps，每個 wrap 內含 K 個 ID 連續的 threads，並<strong>以 wrap 為單位</strong>作排程。在處理每個 wrap 時，SIMT 會將其中的每一個 thread 批次對應於每個 SP，而這些 thread 都保有自身 register 的狀態，並在<strong>同一時間各自獨立地執行某個相同的 instruction</strong>。</p>
<p>在G80的架構下，每個 SM 有8個 SP，每個 wrap 有 32 threads。所以每個 wrap 在執行每項指令時，總共需要 32/8 = 4 輪，才能處理完畢。而該 wrap 會一直執行，直到指令全部結束或是停在需要 sync 的位置，SIMT 這時便會選擇其他等待執行的 wrap 來遞補接替，如此反覆交替進行到全部的 wraps 皆處理完畢為止。至於branch 的部分，SIMT 則會執行每一個分歧的路線，最後在根據每個 thread 的狀態，選擇符合條件的結果。</p>
<p>從上述的流程中，我們可以發現到，真正平行處理的 threads 其實是每一個 SP 當下所處理的 thread，而這些 threads 則是來自於每個 wrap 中的某一輪。所以為了要 hide I/O latency，便要盡可能增加 wrap 的數量，使 SIMT 在排程時有更多的選擇(盡量讓硬體總有事情可作，避免讓它晾在那裡等 I/O 之後的 synchronization)。但是為了要增加平行處理的 thread 數量，單單只增加 gridDim 和 blockDim 的值來呼叫 kernel function 是不夠的(值越大還不見得比較好，有時候反會導致平行執行的 threads 更少)，我們還必須考量 Compute Capability 所帶來的限制。以 Compute Capability 1.0 為例：</p>
<ul>
<li>每個 block 中最多只能有 512 threads</li>
<li>每個 wrap 含有 32 threads</li>
<li>每個 SM 最多只能有8個block、24個wraps、768個threads</li>
</ul>
<p>再看以下幾種 block 設定與每個 SM 所含最多 thread 數目的關係：</p>
<table border="1">
<tbody>
<tr bgcolor="d8e9f4">
<td><strong>Threads in Block</strong></td>
<td><strong>Blocks in SM</strong></td>
<td><strong>Threads in SM</strong></td>
</tr>
<tr>
<td><span style="color:#808080;"><span style="text-decoration:line-through;">1024</span></span>(這裡就爆了)</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>512</td>
<td>1</td>
<td>512 (再多一個 block 就爆了)</td>
</tr>
<tr>
<td>256</td>
<td>3</td>
<td><span style="color:#ff6600;"><strong>768</strong></span> (滿載! 內含 24 個 wraps!)</td>
</tr>
<tr>
<td>64</td>
<td><span style="color:#ff0000;"><strong>8</strong></span></td>
<td>512 (這裡還有空間，但是 block 數目已到極限)</td>
</tr>
</tbody>
</table>
<p>雖然 CUDA 程式的執行效能不單只受平行處理的 threads 數目所影響，memory access 的 pattern 也是另一個重要的因素。但是在優化程式過程中，若發現平行 threads 的負載量已經到達某種極限時，便可以摒除這部分的因素，朝其他方面著手。以免投注太多心力於錯誤的方向，造成事倍功半的遺憾。在 CUDA 的架構下，如何將有限的資源，發揮最大的效用，之中還有很多課題需要再進一步地學習與探索。希望，有一天，我也能找到 CUDA 的方向感!! <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<br />Posted in 程式筆記 Tagged: CUDA <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/renderloop.wordpress.com/82/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/renderloop.wordpress.com/82/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/renderloop.wordpress.com/82/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/renderloop.wordpress.com/82/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/renderloop.wordpress.com/82/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/renderloop.wordpress.com/82/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/renderloop.wordpress.com/82/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/renderloop.wordpress.com/82/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/renderloop.wordpress.com/82/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/renderloop.wordpress.com/82/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/renderloop.wordpress.com/82/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/renderloop.wordpress.com/82/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/renderloop.wordpress.com/82/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/renderloop.wordpress.com/82/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=renderloop.wordpress.com&amp;blog=4637338&amp;post=82&amp;subd=renderloop&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://renderloop.wordpress.com/2009/04/09/simt-%e8%88%87-threads-%e9%85%8d%e7%bd%ae%e7%9a%84%e5%85%a9%e4%b8%89%e4%ba%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/539e6469384c5c9dbbdd22212389ac1c?s=96&#38;d=identicon" medium="image">
			<media:title type="html">renderloop</media:title>
		</media:content>
	</item>
		<item>
		<title>CUDA in Maya plugin</title>
		<link>http://renderloop.wordpress.com/2009/03/30/cuda-in-maya-plugin/</link>
		<comments>http://renderloop.wordpress.com/2009/03/30/cuda-in-maya-plugin/#comments</comments>
		<pubDate>Mon, 30 Mar 2009 13:23:04 +0000</pubDate>
		<dc:creator>renderloop</dc:creator>
				<category><![CDATA[程式筆記]]></category>
		<category><![CDATA[CUDA]]></category>
		<category><![CDATA[MayaAPI]]></category>

		<guid isPermaLink="false">http://renderloop.wordpress.com/?p=38</guid>
		<description><![CDATA[最近一直在想，是否可以在 Maya plugin 裡面使用 CUDA 來作運算。便趁著週末參考 CUDA SDK cppIntegration 的範例，依樣畫葫蘆地在 Maya yTwistNode 的這個範例上作個簡單的小實驗，把 y-twist deform 的計算移至 CUDA kernel function 裡&#8230; 環境設定 在撰寫 CUDA 的程式碼之前，我們必須先在原來的 cpp project 中新增一條 build rule&#8230; 將 CUDA SDK 附的 Cuda.rules 加入列表並啟用&#8230; (為了方便起見，我們可先新增一個環境變數 CUDA_SDK_PATH 使其指向 CUDA SDK &#8230; <a href="http://renderloop.wordpress.com/2009/03/30/cuda-in-maya-plugin/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=renderloop.wordpress.com&amp;blog=4637338&amp;post=38&amp;subd=renderloop&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>最近一直在想，是否可以在 Maya plugin 裡面使用 CUDA 來作運算。便趁著週末參考 CUDA SDK cppIntegration 的範例，依樣畫葫蘆地在 Maya yTwistNode 的這個範例上作個簡單的小實驗，把 y-twist deform 的計算移至 CUDA kernel function 裡&#8230;</p>
<p><span id="more-38"></span></p>
<h2>環境設定</h2>
<p>在撰寫 CUDA 的程式碼之前，我們必須先在原來的 cpp project 中新增一條 build rule&#8230;<br />
<img class="alignnone size-full wp-image-40" style="margin:5px;" title="sshot-vc-cuda" src="http://renderloop.files.wordpress.com/2009/03/sshot-11.png?w=584" alt="sshot-vc-cuda"   /></p>
<p>將 CUDA SDK 附的 Cuda.rules 加入列表並啟用&#8230;<br />
(為了方便起見，我們可先新增一個環境變數 CUDA_SDK_PATH 使其指向 CUDA SDK 的安裝位置。 而 Cuda.rules 所在的位置則是在 $(CUDA_SDK_PATH)common 裡面)<br />
<img class="size-full wp-image-42 alignnone" style="margin:5px;" title="sshot-vc-cuda" src="http://renderloop.files.wordpress.com/2009/03/sshot-2.png?w=584" alt="sshot-vc-cuda"   /></p>
<p>啟用 Cuda.rules 之後， project properties 便會出現一個 CUDA 的分類，一些相關的參數都可以在這裡作設定。 <img class="alignnone size-full wp-image-41" style="margin:5px;" title="sshot-vc-cuda" src="http://renderloop.files.wordpress.com/2009/03/sshot-3.png?w=584" alt="sshot-vc-cuda"   /></p>
<h2>程式重構</h2>
<p>環境設定完之後，我們新增一個 .cu 的檔案，實作與 cpp code 的溝通介面以及處理 y-twist 的 kernel function</p>
<p><pre class="brush: cpp;">
#include
#include 

__global__ void  gpu_twist(float4 pts[], int len,
                           float magnitude, float env)
{
	for(int k=0; k&lt;len; k++)
	{
		float ff = magnitude * pts[k].y * env;
		if( ff != 0.0f )
		{
			double cct= cosf(ff);
			double cst= sinf(ff);
			double tt = pts[k].x * cct - pts[k].z * cst;

			pts[k].z = pts[k].x * cst + pts[k].z * cct;
			pts[k].x = tt;
		}
	}
}

extern &quot;C&quot;
void	gpu_calc(float ptData[][4], unsigned int len,
                        float magnitude, float env)
{
	const unsigned int memSize = len * sizeof(float) * 4;
	float4 *d_data;

	cutilSafeCall( cudaMalloc((void**) &amp;d_data, memSize) );

	// Copy data to gpu memory
	cutilSafeCall( cudaMemcpy(d_data, ptData, memSize,
                                     cudaMemcpyHostToDevice) );

	// Invoke the kernel with one thread
	gpu_twist&lt;&lt;&lt;1,1&gt;&gt;&gt;(d_data, len, magnitude, env);

	// Copy result from gpu memory to host memory
	cutilSafeCall( cudaMemcpy(ptData, d_data, memSize,
                                    cudaMemcpyDeviceToHost) );

	cudaFree(d_data);
}</pre></p>
<p>回到原來的 yTwistNode.cpp 補上溝通介面的宣告，並對 deform function 作一點小幅修改&#8230;</p>
<p><pre class="brush: cpp;">
extern &quot;C&quot;
void	gpu_calc(float ptData[][4], unsigned int len, float magnitude, float env);

MStatus
yTwist::deform( MDataBlock&amp; block,
		MItGeometry&amp; iter,
		const MMatrix&amp; m,
		unsigned int multiIndex)
{
	MStatus status = MS::kSuccess;

	// determine the angle of the yTwist
	//
	MDataHandle angleData = block.inputValue(angle,&amp;status);
	McheckErr(status, &quot;Error getting angle data handlen&quot;);
	double magnitude = angleData.asDouble();

	// determine the envelope (this is a global scale factor)
	//
	MDataHandle envData = block.inputValue(envelope,&amp;status);
	McheckErr(status, &quot;Error getting envelope data handlen&quot;);
	float env = envData.asFloat();

	// { Modified block
	MPointArray ptArray;
	status = iter.allPositions(ptArray);

	// Get raw data
	float (*rawData)[4] = new float[ptArray.length()][4];
	ptArray.get(rawData);

	// Invoke cuda
	gpu_calc(rawData, ptArray.length(), magnitude, env);

	// Retrieve the data
	for(int i=0; i&lt;ptArray.length(); ++i)
	{
		ptArray.set(rawData[i], i);
	}
	delete [] rawData;

	iter.setAllPositions(ptArray);
	// } End of modified

	return status;
}
</pre></p>
<p>接著在 project properties 補上一些相關設定:</p>
<ul>
<li>Additional Include Directories<br />
$(CUDA_INC_PATH); $(CUDA_SDK_PATH)commoninc</li>
<li>Additional Library Directories<br />
$(CUDA_LIB_PATH); $(CUDA_SDK_PATH)commonlib</li>
<li>Additional Dependencies<br />
cudart.lib cutil32D.lib</li>
<li>CUDA 的 Additional Include Directories<br />
<strong>&#8220;</strong>$(CUDA_SDK_PATH)commoninc<strong>&#8220;</strong><br />
Ps. 這裡的 path 記得要 quote 起來，不然會有 <em>nvcc fatal   : A single input file is required for a non-link phase when an outputfile is specified</em> 的錯誤訊息!!</li>
</ul>
<p>最後的步驟當然是 build &amp; execute 囉!! 至於執行效能，還真的如預期中的<strong>慢</strong>!? 這是因為 y-twist 其實也沒做多少事，花在 memcpy 的時間搞不好還比計算的時間多。加上我全部的資料都宣告在 global memory ， thread 也只用一個而已。所以執行效能較慢也是預料中的事情，不過經過這一次的實驗，總算大致熟悉了從 cpp project 引入 CUDA 的流程，也終於在 CUDA 的世界中心呼喊 Hello World 了!!  <img src='http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<br />Posted in 程式筆記 Tagged: CUDA, MayaAPI <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/renderloop.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/renderloop.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/renderloop.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/renderloop.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/renderloop.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/renderloop.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/renderloop.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/renderloop.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/renderloop.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/renderloop.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/renderloop.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/renderloop.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/renderloop.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/renderloop.wordpress.com/38/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=renderloop.wordpress.com&amp;blog=4637338&amp;post=38&amp;subd=renderloop&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://renderloop.wordpress.com/2009/03/30/cuda-in-maya-plugin/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/539e6469384c5c9dbbdd22212389ac1c?s=96&#38;d=identicon" medium="image">
			<media:title type="html">renderloop</media:title>
		</media:content>

		<media:content url="http://renderloop.files.wordpress.com/2009/03/sshot-11.png" medium="image">
			<media:title type="html">sshot-vc-cuda</media:title>
		</media:content>

		<media:content url="http://renderloop.files.wordpress.com/2009/03/sshot-2.png" medium="image">
			<media:title type="html">sshot-vc-cuda</media:title>
		</media:content>

		<media:content url="http://renderloop.files.wordpress.com/2009/03/sshot-3.png" medium="image">
			<media:title type="html">sshot-vc-cuda</media:title>
		</media:content>
	</item>
	</channel>
</rss>
