Part.2 Linear Memory

Part.2 Linear Memory

在前一篇已�大概介�B�^ texture 的基本概念了,在�@一篇,就�泶蟾趴匆幌拢�一般使用 linear memory 的 texture 的方法吧。

在宣告的部分,前面已�提�^了,大致上就是:
  1. texture<int, 1, cudaReadModeElementType> texRef;
复制代码
的形式。�@�樱�就可以宣告出一��一�S的整�� texture 了;而由於他的�x取模式是�o定�� cudaReadModeElementType,所以之後由�@�� texture 取出的值,也都��是整�担ㄈ绻�是 cudaReadModeNormalizedFloat,就��是浮�c�担�。
而宣告出 texture reference 的物件後,接下�砭褪且�和�F有的��底鲞B�Y了~



Bind Texture
使用 linear memory �r,是要�⒃� global memory 中用 cudaMalloc() 定�x出�淼挠����w空�g,透�^ cudaBindTexture() �@��函式,��� texture reference �B�Y到��怠F浜�式的型�B�椋�
  1. template<class T, int Dim, enum cudaReadModeElementType readMode>
  2. cudaError_t cudaBindTexture( size_t* offset,
  3.                          const struct texture<T, dim, readMode>& texRef,
  4.                          const void* devPtr,
  5.                          size_t size = UINT_MAX);
复制代码
其中, offset 算是比�^�M�A的�O定,在�@�先略�^,不�^一般是都�o 0。而 texRef 就是要 bind 的 texture, devPtr �t是要 bind 到 texRef 的�Y料;size 就是 devPtr 的����w空�g大小,不�^一般���是可以省略不�o。

而除了 cudaBindTexture() 外,��然也有相反的 cudaUnbindTexture()。他的�幼骶褪墙獬� texture reference 和��档年P�S。
  1. template<class T, int Dim, enum cudaReadModeElementType readMode>
  2. cudaError_t cudaunBindTexture(
  3.                 const struct texture<T, dim, readMode>& texRef );
复制代码

在 kernel 中使用
在 kernel function 中,要存取使用 linear memory 的 texture reference,要透�^ tex1Dfetch() �@��函式;其型�B�椋�

  1. template<class Type>
  2. Type tex1Dfetch( texture<Type, 1, ReadMode> texRef, int x);
复制代码
也就是只要�o他要�x取的 texture reference,以及要�x取的位置 x,就可以取得�Y料的值了~



��蔚墓�例
上面已�把要使用 linear memory 的 CUDA texture �r所需要的基本功能都介�B�^了,接下�砭�斫o����蔚墓�例吧~程式可以到�@���B�Y下�d。


Heresy �@�用的例子,是把����D做 alpha blending,也就是把����D各自�O定透明度,�B在一起看;不�^�榱撕�化,所以�]有去�x�D�n,而是直接建立�y�的�Y料。下面就是 main() 的部分
  1. void main( int argc, char** argv )
  2. {
  3.     int width   = 1920,
  4.         height  = 1200,
  5.         channel = 3;

  6.     // Setup test data
  7.     unsigned char *aImg1 = new unsigned char[ width*height*channel ],
  8.                   *aImg2 = new unsigned char[ width*height*channel ],
  9.                   *aRS1  = new unsigned char[ width*height*channel ],
  10.                   *aRS2  = new unsigned char[ width*height*channel ];
  11.     for( int i = 0; i < width * height * channel; ++ i )
  12.     {
  13.         aImg1 = 0;
  14.         aImg2 = 255;
  15.     }

  16.     // CPU code
  17.     Blend_CPU( aImg1, aImg2, aRS1, width, height, channel );
  18.         
  19.     // GPU Code
  20.     Blend_GPU( aImg1, aImg2, aRS2, width, height, channel );

  21.     // check
  22.     for( int i = 0; i < width * height * channel; ++ i )
  23.         if( aRS1 != aRS2 )
  24.         {
  25.             printf( "Error!!!!\n" );
  26.             break;
  27.         }
  28. }
复制代码
在 �@�e,是建立了四��大小是 1920*1200*3 的 unsigned char 一�S�列�沓洚��D�n;其中,aImg1 和 aImg2 是��作�碓矗�分�e全部填入 0 和 255,而 aRS1 和 aRS2 �t分�e拿��Υ嬗� CPU 以及 GPU �算後的�Y果。其中 Blend_CPU() 就是用 CPU �算的函式、Blend_GPU() �t是用 GPU �算的函式;在�算完後,�Y果��分�e存在 aRS1 和 aRS2 中。最後「check」的部分,就是在��C CPU 和 GPU �算的�Y果是否一致了~
而其中,Blend_CPU() 的�热菔牵�
  1. void Blend_CPU( unsigned char* aImg1, unsigned char* aImg2,
  2.                 unsigned char* aRS,
  3.                 int width, int height, int channel )
  4. {
  5.     for( int i = 0; i < width * height * channel; ++ i )
  6.         aRS = (unsigned char)( 0.5 * aImg1 + 0.5 * aImg2 );
  7. }
复制代码
可以看到�@�的程式非常��危�就是用一�� for �圈,把整���列�咭槐椋��K把 aImg1 和 aImg2 的值都乘上 0.5 後加起�怼�


接下�恚�就是 GPU 程式 Blend_GPU() 所在的的 .cu �n了~
  1. #define BLOCK_DIM 512
  2. texture<unsigned char, 1, cudaReadModeElementType> rT1;
  3. texture<unsigned char, 1, cudaReadModeElementType> rT2;

  4. extern "C"
  5. void Blend_GPU( unsigned char* aImg1, unsigned char* aImg2,
  6.                 unsigned char* aRS,
  7.                 int width, int height, int channel );

  8. __global__ void Blending_Texture( unsigned char* aRS, int size )
  9. {
  10.     int index = blockIdx.x * blockDim.x + threadIdx.x;

  11.     if( index < size )
  12.         aRS[index] = 0.5 * tex1Dfetch( rT1, index )
  13.                    + 0.5 * tex1Dfetch( rT2, index );
  14. }

  15. void Blend_GPU( unsigned char* aImg1, unsigned char* aImg2,
  16.                 unsigned char* aRS,
  17.                 int width, int height, int channel )
  18. {
  19.     int size = height * width * channel;
  20.     int data_size = size * sizeof( unsigned char );

  21.     // part1, allocate data on device
  22.     unsigned char        *dev_A,        *dev_B,        *dev_C;
  23.     cudaMalloc( (void**)&dev_A, data_size );
  24.     cudaMalloc( (void**)&dev_B, data_size );
  25.     cudaMalloc( (void**)&dev_C, data_size );

  26.     // part2, copy memory to device
  27.     cudaMemcpy( dev_A, aImg1, data_size, cudaMemcpyHostToDevice );
  28.     cudaMemcpy( dev_B, aImg2, data_size, cudaMemcpyHostToDevice );

  29.     // part2a, bind texture
  30.     cudaBindTexture(0, rT1, dev_A );
  31.     cudaBindTexture(0, rT2, dev_B );

  32.     // part3, run kernel
  33.     Blending_Texture<<< ceil((float)size/BLOCK_DIM), BLOCK_DIM >>>
  34.                     ( dev_C, size );

  35.     // part4, copy data from device
  36.     cudaMemcpy( aRS, dev_C, data_size, cudaMemcpyDeviceToHost );

  37.     // part5, release data
  38.     cudaUnbindTexture(rT1);
  39.     cudaUnbindTexture(rT2);

  40.     cudaFree(dev_A);
  41.     cudaFree(dev_B);
  42.     cudaFree(dev_C);
  43. }
复制代码
第 一行的所定�x的 BLOCK_DIM 是定�x成每一�� thread block 的大小�� 512 ��,而如果要�绦械� thread 超�^�@���抵档脑�,就再切成��� block �碜觯灰簿褪� part3 所指定的�绦��担骸�<<< ceil((float)size / BLOCK_DIM), BLOCK_DIM >>>」。


第二行和第三行是宣告出��� CUDA 的 1D texture rT1、rT2出�恚���渲�後拿�懋��入用的����列用;而由於 texture 不能��入,所以�出的�列也就�]必要�D�Q成 texture�硎褂昧恕6����是由於目前 CUDA 版本(1.1)的限制,texture reference 只能在 file-scope 宣告成��global ��担�在 kernel function 中使用。
接下�硐瓤� Blend_GPU() �@��函式,他的步�E如下:


  • 先把所需要的����w大小�算出��
  • [part1] 宣告 dev_A、dev_B、dev_C,�K指派����w空�g;此�r,dev_A、dev_B、dev_C 就是使用 global memory 的��怠�
  • [part2]  透�^ cudaMemcpy() 把�Y料由 host memory(aImg1、aImg2) �}�u到 device memory(dev_A、dev_B)。
  • [part2a] 透�^ cudaBindTexture() �� rT1、rT2 和 dev_A、dev_B 做��M。而此�r,rT1、rT2  就算是使用 texture memory 的��怠�
  • [part3] 呼叫 kernel function:Blending_Texture() �磉M行�算了。
  • [part4] �⒔Y果由 device memory(dev_C)�}�u回 host memory(aRS)。
  • [part4] 透�^ cudaUnbindTexture() �� rT1、rT2 和 dev_A、dev_B �g的��M解除,�K使用 cudaFree() �� device memory �放掉。

而最後就是�@份程式的 kernel function:Blending_Texture() 了~

在一�_始,�是先利用 CUDA 自�犹峁┑淖��� blockIdx、blockDim、threadIdx �碛�算出 index 值,�K判�嘣� thread 是否超出要�理的大小。而之後,就透�^ tex1Dfetch() �@��函式,����e取出 rT1 和 rT2 在 index 的值,�K�⒂�算後的�Y果,存入 aRS[index] 中。如此,就完成了 kernel function �做的事了。

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