Part.3 CUDA Array

Part.3 CUDA Array


在 CUDA Texture 文章的第一篇大概�v了一下 texture 在 CUDA �e的基本概念,而第二篇�t是�v了 linear memory 的 texture,接下�恚�自然就是 CUDA Array 的 texture 了~


CUDA Array
CUDA array 在 cuda 中是一��特殊的�Y料型�e,叫做 cudaArray,在 CUDA 中,他���是�iT�o texture 用的一�N型�e;要�λ�做����w的管�e,�t是要透�^ cudaMallocArray()、cudaFreeArray()、cudaMemcpyToArray() 等函式。此外,由於 cudaArray 本身�K非 template 的型�e,所以在透�^ cudaMallocArray() �砼渲糜����w�r,也要透�^ cudaChannelFormatDesc �@��特殊的�Y料型�e,�碓O定他的�Y料型�e。
  1. cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
  2. cudaArray* cuArray;
  3. cudaMallocArray(&cuArray, &channelDesc, width, height);
复制代码
上面就是一����蔚睦�子,所宣告出�淼� cuArray,就是一���炔抠Y料是 float,大小是 width * height 的 CUDA Array。其中,cudaChannelFormatDesc 是一��用�砻枋� fetch 一�� texture �r,回�髦档馁Y料的型�e;而要�a生���型�e的�Y料,只要使用他的 template function:
  1. template<class T>
  2. struct cudaChannelFormatDesc cudaCreateChannelDesc<T>();
复制代码
而在 cudaMallocArray() 的使用上,也只需要�o四����担�cudaArray**、cudaChannelFormatDesc*、��、高。


而相�^於一般 linear memory 是用 cudaMemcpy() ��①Y料由 host memory �}�u到 device memory,CUDA Array 要改用 cudaMemcpyToArray() �碜鲅}�u的�幼鳎贿@��函式的形式�椋�
  1. cudaError_t cudaMemcpyToArray(struct cudaArray* dstArray,
  2.                               size_t dstX, size_t dstY,
  3.                               const void* src, size_t count,
  4.                               enum cudaMemcpyKind kind);
复制代码
�@��函式��把�碓促Y料 src �}�u到 dstArray 中;而 cudaMemcpyKind �t是用�碇付ㄑ}�u的方向,有 cudaMemcpyHostToHost、cudaMemcpyHostToDevice、cudaMemcpyDeviceToHost、cudaMemcpyDeviceToDevice 四�N值。

第五����� count 是代表要�}�u的�Y料量;而 dstX 和 dstY �t是代表要由 src 的左上角 (dstX, dstY) 的位置�_始�}�u�Y料,一般�碚f���都是�o 0。

Texture with CUDA array
��於使用 CUDA array 的 texture,是要使用 cudaBindTextureToArray() �@��函式�戆� CUDA array 和 texture ��M起�恚皇褂蒙希�只要�o他 texture 和 cudaArray ��作��稻涂梢粤恕�其函式形式�椋�
  1. template<class T, int dim, enum cudaTextureReadMode readMode>
  2. cudaError_t cudaBindTextureToArray(
  3.                const struct texture<T, dim, readMode>& texRef,
  4.                const struct cudaArray* cuArray);
复制代码
而要解除 texture 和 CUDA array 的�P�S,使用的函式和 linear memory �r是一�拥模�都是 cudaUnbindTexture()。


而在存取上,和 linear memory 的 texture �r的 tex1Dfetch() 不同,是要使用 tex1D()、tex2D() �@���函式,分�e是用在 1D 和 2D 的 texture。其形式分�e�椋�
  1. template<class Type, enum cudaTextureReadMode readMode>
  2. Type tex1D(texture<Type, 1, readMode> texRef, float x);

  3. template<class Type, enum cudaTextureReadMode readMode>
  4. Type tex2D(texture<Type, 2, readMode> texRef, float x, float y);
复制代码


��喂�例

接下�恚��是用��例�砜窗伞��@�是用 CUDA Array 的 texture �碜� transpose 的�幼鳌�[程式原始�a下�d]
首先,main() 的�热萑缦拢�
  1. void main( int argc, char** argv )
  2. {
  3.     int w    = 1920,
  4.         h    = 1200;

  5.     // Setup test data
  6.     unsigned char  *aSrc = new unsigned char[ w * h ],
  7.                    *aRS1 = new unsigned char[ w * h ],
  8.                    *aRS2 = new unsigned char[ w * h ];
  9.     for( int i = 0; i < w * h ; ++ i )
  10.         aSrc = i % 256;

  11.     // CPU code
  12.     Transpose_CPU( aSrc, aRS1, w, h );

  13.     // GPU Code
  14.     Transpose_GPU( aSrc, aRS2, w, h );

  15.     // check
  16.     for( int i = 0; i < w * h; ++ i )
  17.         if( aRS1 != aRS2 )
  18.         {
  19.             printf( "Error!!!!\n" );
  20.             break;
  21.         }
  22. }
复制代码
一 �雍芎��危�就先宣告出原始�Y料的 aSrc,�有�D置�^的�Y料 aRS1 和 aRS2;然後在原始�Y料 aSrc 中,填入一些值。(以此例,aSrc ���是 1920*1200,aRS1 和 aRS2 ���是 1200 * 1920;不�^由於在宣告成一�S�列�r�]差�e,所以�]特�e去修改。)


而接下�恚�就是分�e跑 CPU 版和 GPU 版的程式,�K比�^�烧叩慕Y果了~而 CPU 版的函式 Transpose_CPU() �热萑缦拢�
  1. void Transpose_CPU( unsigned char* sImg, unsigned char *tImg,
  2.                     int w, int h )
  3. {
  4.     int x, y, idx1, idx2;
  5.     for( y = 0; y < h; ++ y )
  6.         for( x = 0; x < w; ++ x )
  7.         {
  8.             idx1 = y * w + x;
  9.             idx2 = x * h + y;
  10.             tImg[idx2] = sImg[idx1];
  11.         }
  12. }
复制代码
�热���不用多加解�了~�之,就是根��方向的不同,�袢〔煌�的方法�算出 idx1 和 idx2 �������w空�g的索引值,以此�戆奄Y料由 sImg �}�u到 tImg,藉此做到�D置的�幼鳌�

而 Transpose_GPU() 所在的 .cu �n,�热�t如下:
  1. #define BLOCK_DIM 16

  2. texture<unsigned char, 2, cudaReadModeElementType> rT;

  3. extern "C"
  4. void Transpose_GPU( unsigned char* sImg, unsigned char *tImg,
  5.                     int w, int h );

  6. __global__
  7. void Transpose_Texture( unsigned char* aRS, int w, int h )
  8. {
  9.     int idxX = blockIdx.x * blockDim.x + threadIdx.x,
  10.         idxY = blockIdx.y * blockDim.y + threadIdx.y;
  11.     if( idxX < w && idxY < h )
  12.         aRS[ idxX * h + idxY ] = tex2D( rT, idxX, idxY );
  13. }

  14. void Transpose_GPU( unsigned char* sImg, unsigned char *tImg,
  15.                     int w, int h )
  16. {
  17.     // compute the size of data
  18.     int data_size = sizeof(unsigned char) * w * h;


  19.     // part1a. prepare the result data
  20.     unsigned char *dImg;
  21.     cudaMalloc( (void**)&dImg, data_size );

  22.     // part1b. prepare the source data
  23.     cudaChannelFormatDesc chDesc = cudaCreateChannelDesc<unsigned char>();
  24.     cudaArray* cuArray;
  25.     cudaMallocArray(&cuArray, &chDesc, w, h);
  26.     cudaMemcpyToArray( cuArray, 0, 0, sImg, data_size,
  27.                        cudaMemcpyHostToDevice );
  28.     cudaBindTextureToArray( rT, cuArray );

  29.     // part2. run kernel
  30.     dim3 block( BLOCK_DIM, BLOCK_DIM ),
  31.          grid( ceil( (float)w / BLOCK_DIM), ceil( (float)h / BLOCK_DIM) );
  32.     Transpose_Texture<<< grid, block>>>( dImg, w, h );

  33.     // part3. copy the data from device
  34.     cudaMemcpy( tImg, dImg, data_size, cudaMemcpyDeviceToHost );

  35.     // par4. release data
  36.     cudaUnbindTexture( rT );
  37.     cudaFreeArray( cuArray );
  38.     cudaFree( dImg );
  39. }
复制代码
首先,之前也有提�^了,目前的 CUDA 似乎只允�S把 texture 宣告在 file-scope,所以一�_始就要宣告一�� 2D texture �懋��入�Y料;�f���,��於�@�c Heresy �X得��在不是很方便。


接下�恚�直接看 main() 所呼叫的 Transpose_GPU() 吧~他做的�热萑缦拢�


  • 先把所需要的����w大小�算出��
  • [part1a] 宣告 dImg,�K指派����w位址�o dImg ��Υ嬗�算後的�Y果。
  • [part1b] 建立 CUDA array cuArray、派����w位址,�①Y料由 host memory(sImg) �}�u到 device memory(cuArray);�K透�^ cudaBindTextureToArray() �� rT 和 cuArray 做��M。
  • [part2] 呼叫 kernel function:Transpose_Texture() �磉M行�算。在�@�,thread block 的大小是定�x�� BLOCK_DIM*BLOCK_DIM(16*16),grid 的大小�t是根����和高�沓�以 block 的大小。
  • [part3] �⒔Y果由 device memory(dImg)�}�u回 host memory(tImg)。
  • [part4] 透�^ cudaUnbindTexture() �� rT 和 sImg �g的��M解除,�K使用 cudaFreeArray()、cudaFree() �� device memory �放掉。

而本程式的 kernel function Transpose_Texture() �龋��t是直接透�^ blockIdx、blockDim、threadIdx �@三����担��算出二�S中的位置,�K在 x、y 都�]有超�^����r,�M行�Y料�D置的�}�u,把 (idxX, idxY) 的�Y料,透�^ tex2D() 取出,�Υ娴� aRS[ idxX * h + idxY ]。

到此�橹梗����是使用 CUDA 2D texture 最基本的方法了~���H上正如在 part.1 �r所提及的,使用 CUDA Array 的 texture 其���有一些�~外的功能可以使用!而除了 high-level 的使用外,也�有 low-level、更��的功能可以使用~不�^�@�就��r不提了~之後有空再�f吧。 :p

你可能感兴趣的:(职场,休闲)