引言:
雖然GPU已經被用於很多通用計算當中了,但是還是有很多GPGPU的研究始於圖形圖像相關的,例如光線跟蹤, 流體模擬等等。我們經常會需要通用計算的接口去訪問DX或者OpenGL裏面的一些資源。由於圖形接口的紋理資源都是在顯存裏面存儲的,如果僅僅爲了讓GPU的內核訪問這些資源,就必須把圖形接口的內存從顯卡傳到主存,然後在轉換成相應的GPGPU接口形式傳會顯卡中,這樣無疑繁瑣了很多,而且做了很多不必要的工作。
爲了方便GPU內核訪問圖形接口的資源,很多GPGPU接口都爲程序員提供了Interoperability的功能。利用這個功能,程序員只需要簡單的設置,就可以用相應的接口(CUDA C , Brook+ , OpenCL等)來訪問這些顯卡里面的資源。
本文介紹了CAL提供的Dx interoperability功能。實現了一個簡單的Demo。
正文:
這已經是我第三次寫關於interoperability的Demo了。前兩次分別是CUDA和Brook+的interoperability (http://codeboycjy.blogbus.com/logs/40925084.html http://codeboycjy.blogbus.com/logs/39810508.html )。爲了一致一些,我又實現了一個一摸一樣的Demo。不過這回不同的是圖形接口是Dx10,並且是基於CAL的。還是那張截圖:
這次的Demo和以前兩次也是一樣的。用Pixel Shader寫的話,會非常簡單。但是這個Demo的目的不是Show怎麼做像素處理的,而是展示一下怎樣用GPGPU的Kernel訪問Dx的紋理。
下面我們主要看兩點:
1.怎樣設置紋理與GPGPU資源的Mapping。
2.我會逐行解釋一下第一個Kernel,第二個kernel留給讀者自己分析了(裏面應該有處漏洞,有興趣可以試着找一下)。
首先,爲了做interop,看看我們需要做些什麼。
1. 首先我們需要檢查一下當前設備是否支持interop,事實上,只有在vista系統下,CAL才支持Dx(9/10)的interop。
2. 然後我們需要找到mapping的兩個函數指針,一個負責設備的對應,還有個負責資源的對應。
3. 利用這兩個指針,我們需要把設備首先對應起來,注意,這裏需要你把CAL和DX的設備都創建完畢後,纔可以做Mapping。
4. 然後利用Map資源的函數,就可以把Dx資源與CAL資源對應起來。
第四點裏面有些需要我們注意的地方。首先,對於那個CAL資源和Dx資源的時候,Dx的資源必須是創建完畢的,而CAL的資源是不用創建的。CAL會爲我們自動對應。否則創建兩份資源就是拷貝了。這裏的對應就好像C++裏面兩個指針知道一處地址,誰都可以更改裏面的內容。Dx 的資源並不一定僅僅是這個Demo裏面利用的紋理,事實上,只要Dx認爲是資源的東西,CAL都可以做對應,從而直接用內核訪問,例如頂點緩衝,索引緩衝等等。
當資源對應後,我們就可以像對待正常的CAL資源一樣對待和DX資源綁定的資源了。只不過這裏我們修改的內存是有Dx系統爲我們來存儲的,而不是以CAL的資源存儲格式存儲的。但是其實對於GPU內核來說,這並沒有什麼影響。
做紋理interop基本就是這些內容,其實很easy的東西。下面我們來看看GPU的kernel怎麼寫的吧。
il_ps_2_0
dcl_input_interp(linear) v0.xy__
dcl_resource_id(0)_type(2d,unnorm)_fmtx(float)_fmtx(float)_fmtx(float)_fmtx(float)
dcl_cb cb0[1]
dcl_output_generic o0
dcl_literal l0 , 5.0 , 0.25 , 0.0 , 0.0
flr r0 , v0
mad r1.x , l0.y , r0.y , cb[0].z
cos r1.y , r1.x
mad r0.w , l0.x , r1.y , r0.x
sample_resource(0)_sampler(0) r2, r0.wyxx
mov o0 , r2
end上面就是這個Demo的第一個內核函數。比上次介紹的複雜一點點,但是其實仔細看,基本是一樣的。我們還是照例提上其他類C語言的內核代碼吧,方便對比一些。貼個Brook+的好了:
kernel void brook_wave_Texture( float t , float4 src[][] , out float4 desc<> )
{
//get the index
int2 index = instance().xy;
int srcX = (int) ( 5.0f * cos( t + 0.25f * (float) index.y ) ) + index.x ;
int srcY = index.y;
dest = src[srcY][srcX];
}Brook+的內核函數很簡單,沒什麼好說的。主要來看一下上面CAL的代碼是怎麼work的好了。
前面聲明與上一次介紹的東西基本是一樣的,有不理解的朋友可以看下上次的解釋。唯一不一樣的就是有一個constant的變量。這個變量在程序中,每一幀都被CPU傳入的數據更改,是根據時間變化的。
flr r0 , v0 : 把0.5開始的索引變爲0.0開始。
mad r1.x , l0.y , cb[0].z : 這裏其實就是Brook內核裏面的 t + 0.25f * (float) index.y 。mad a , b , c , d的意思是 a = b * c + d
cos r1.y , r1.x : 把x分量的餘弦值記錄到x分量裏面。
mad r0.w , l0.x , r1.y , r0.x : 這裏就是對應上面的 srcX = (int) ( 5.0f * cos( t + 0.25f * (float) index.y ) ) + index.x。因爲cos( t + 0.25f * (float) index.y )的值是r1.y,所以這個可以簡化爲 srcX = (int) ( 5.0f * r1.y ) + index.x;
這行指令執行完了以後,我們可以直接從資源裏面去獲取像素的值了。細心一點的朋友可能會注意到這裏的索引是可能有越界現象的,但是CAL在訪問Dx紋理的時候,越界的索引都被Clamp了,這一點和Brook+是一樣的。所以我們不需要處理越界情況。
這次基本就是這些內容了,其實還是沒有什麼東西。想了解Dx interop,Dx10 初始化,以及CAL的kernel的朋友,可以把Demo下來看看。裏面有這些相關的內容。
http://filer.blogbus.com/4730079/resource_473007912594659841.rar
用CAL直接訪問Dx的紋理資源 (interoperability)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.