遍歷圖像設計threadIdx blockIdx blockDim 解釋

最近進行gpu編程,受困於雜事,對threadIdx blockIdx blockDim理解存在偏頗導致浪費不少時日。遂整理資料加深認識。

以下是最常見的gpu圖像遍歷方式:

dim3 dimBlock( 線程數1, 線程數2,1) ;//最開始,望文生義而把後面數據理解爲 threadIdx 的值導致大量時間浪費在這上面。這邊就是線程數,不是塊數。不要被網上代碼迷惑
dim3 dimGrid( ceil( ( 圖像寬 + 線程數1 - 1)/線程數1 ) ,ceil( ( 圖像高 + 線程數 2-1) /線程數2) , 1 ) ;
Cal<<<dimGrid , dimBlock>>>(圖像數據首地址 …… );
__global__ void Cal(unsigned char * srcData ……)
{
	const int idx = threadIdx.x + blockIdx.x * blockDim.x;
	const int idy = threadIdx.y + blockIdx.y * blockDim.y;
…………
         if(idx  < 圖像寬 && idy < 圖像高) //圖像寬 ,圖像高通過參數傳入
	{
<span style="white-space: pre;">		</span>……//對圖像進行相應單像素操作
	}
}

按照上面訪問方式 就可以進行圖像逐像素遍歷。 各個元素解釋如下:

dim3             :  定義如下

  struct __device_builtin__ dim3
{
    unsigned int x, y, z;
#if defined(__cplusplus)
    __host__ __device__ dim3(unsigned int vx = 1, unsigned int vy = 1, unsigned int vz = 1) : x(vx), y(vy), z(vz) {}
    __host__ __device__ dim3(uint3 v) : x(v.x), y(v.y), z(v.z) {}
    __host__ __device__ operator uint3(void) { uint3 t; t.x = x; t.y = y; t.z = z; return t; }
#endif /* __cplusplus */
};


blockDim.x : 塊操作x方向維數 , 對應   ceil( ( 圖像寬 + 線程數1 - 1)/線程數1 )  所在位置指定值。

blockDim.y : 快操作y方向維數 , 對應   ceil( ( 圖像高 + 線程數 2-1) /線程數2)   所在位置指定值。

threadIdx.x : 當前線程 x 方向值 , 範圍 0~ 線程數1 -1 。

threadIdx.y : 當前線程y方向值   , 範圍 0~ 線程數2 - 1 。

blockIdx.x   : 當前塊 x方向值 ,       範圍 0~ceil( ( 圖像寬 + 線程數1 - 1)/線程數1 )  -  1

blockIdx.y   : 當前塊 y方向值 ,       範圍 0~ceil( ( 圖像高 + 線程數 2-1) /線程數2) - 1


通過以上 知識,可以計算得到   idx 的最小值= 0 , idx最大值<=  圖像寬 + 線程數1 - 1 ,並且遍歷 最大最小值之間所有值,因此可以把寬度方向遍歷完畢。同理,y方向也剛好每行遍歷一次,不存在重複遍歷元素情況。

在之後,因爲有共有參數,嫌這樣方式慢,我更改爲二維方式訪問。頻繁出錯,出錯原因就在於  忽略  “遍歷 最大最小值之間所有值” 這個條件導致出錯。

最後遍歷方式:

//塊,線程設置

dim3 dimBlock(線程數1, 線程數2,1) ;

dim3 dimGrid(1, 塊數2, 1 ) ;

//調用

Cal<<<dimGrid , dimBlock>>>(圖像數據首地址 …… );

__global__ void Cal(unsigned char * srcData ……)

{

const int idx = threadIdx.x ;

const int idy = threadIdx.y + blockIdx.y * blockDim.y ;

//載入共享數據

……

for(int dy = idy + offsetLoc;dy < 圖像高; dy += 線程數2*blockDim.y)

{

for(int dx = idx ; dx < 圖像寬; dx += 線程數1)

{

//逐像素操作

}

}

}


之所以按照上面訪問方式,是因爲有使用共享內存的需要。並不是最優方案,按照自己需求更改訪問方式。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章