试图在Cuda中使用Mode Wrap

时间:2018-04-02 13:16:37

标签: cuda

我试图在Cuda中使用cudaAddressModeWrap功能,但是,我遇到了一些困难。

我在下面提供了我的代码:

texture <float, 2, cudaReadModeElementType> tex;

__global__ void transformKernel( float* Btmp, int width, int height)
{
    unsigned int x = blockIdx.x*blockDim.x + threadIdx.x;
    unsigned int y = blockIdx.y*blockDim.y + threadIdx.y;

  if ( (x < width) && (y < height) )
  {
    if( x == 0 || x == 1 )
      Btmp[y*width+x] = tex2D(tex, x, y);
    else
    {
      Btmp[y*width+x] = tex2D(tex, x, y) + \
        (0.15 * tex2D(tex, x - 2, y))    + \
        (0.65 * tex2D(tex, x - 1, y))    + \
        (1.35 * tex2D(tex, x + 1, y))    + \
        (1.85 * tex2D(tex, x + 2, y));
      Btmp[y * width + x] /= float(5);
    }   
  }
}

我想要周期性的边界条件,因此Mode Wrap应该是完美的。我想我正在设置参数不正确,但我不确定。这是相关的代码。

  int i, j;
  float **A;
  float *Atmp;

  A = (float **)malloc( ndim * sizeof(float *));
  Atmp = (float *)malloc ( ndim * mdim * sizeof(float));
  for(i=0;i<ndim;i++)
    A[i] = &Atmp[i * mdim];

  for(i=0;i<ndim;i++)
  {
    for(j=0;j<mdim;j++)
    {
      A[i][j] = 0;
    }
    A[i][0] = 0.85 * (float)((i+1)*(i+1))/(float)(ndim*ndim);
    A[i][1] = 1.00 * (float)((i+1)*(i+1))/(float)(ndim*ndim);
  }   

  cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);

  cudaArray* cu_array;
  cudaMallocArray( &cu_array, &channelDesc, mdim, ndim );
  cudaMemcpyToArray( cu_array, 0, 0, Atmp, ndim * mdim *sizeof(float), cudaMemcpyHostToDevice);

  tex.addressMode[0] = cudaAddressModeWrap;
  tex.addressMode[1] = cudaAddressModeWrap;

  tex.filterMode = cudaFilterModePoint;

  tex.normalized = false;

  cudaBindTextureToArray(tex, cu_array, channelDesc);

  dim3 dimBlock(4, 4, 1);
  dim3 dimGrid(mdim / dimBlock.x, ndim / dimBlock.y, 1);

  float* d_data = NULL;
  cudaMalloc( (void**) &d_data, ndim * mdim *sizeof(float));

  transformKernel<<< dimGrid, dimBlock, 0 >>>(d_data, mdim, ndim);

  cudaMemcpy(Btmp, d_data, ndim*mdim*sizeof(float), cudaMemcpyDeviceToHost);

所需的输出是:

1.33e-02 1.56e-02 2.43e-03 4.69e-04 0.00e+00 0.00e+00 4.91e-03 9.37e-03 
5.31e-02 6.25e-02 9.72e-03 1.88e-03 0.00e+00 0.00e+00 1.97e-02 3.75e-02 
1.20e-01 1.41e-01 2.19e-02 4.22e-03 0.00e+00 0.00e+00 4.42e-02 8.43e-02 
2.13e-01 2.50e-01 3.89e-02 7.50e-03 0.00e+00 0.00e+00 7.86e-02 1.50e-01 
3.32e-01 3.91e-01 6.07e-02 1.17e-02 0.00e+00 0.00e+00 1.23e-01 2.34e-01 
4.78e-01 5.62e-01 8.75e-02 1.69e-02 0.00e+00 0.00e+00 1.77e-01 3.37e-01 
6.51e-01 7.66e-01 1.19e-01 2.30e-02 0.00e+00 0.00e+00 2.41e-01 4.59e-01 
8.50e-01 1.00e+00 1.56e-01 3.00e-02 0.00e+00 0.00e+00 3.15e-01 6.00e-01

使用纹理记忆我得到:

1.33e-02 1.56e-02 2.43e-03 4.69e-04 0.00e+00 0.00e+00 0.00e+00 0.00e+00 
5.31e-02 6.25e-02 9.72e-03 1.88e-03 0.00e+00 0.00e+00 0.00e+00 0.00e+00 
1.20e-01 1.41e-01 2.19e-02 4.22e-03 0.00e+00 0.00e+00 0.00e+00 0.00e+00 
2.13e-01 2.50e-01 3.89e-02 7.50e-03 0.00e+00 0.00e+00 0.00e+00 0.00e+00 
3.32e-01 3.91e-01 6.07e-02 1.17e-02 0.00e+00 0.00e+00 0.00e+00 0.00e+00 
4.78e-01 5.62e-01 8.75e-02 1.69e-02 0.00e+00 0.00e+00 0.00e+00 0.00e+00 
6.51e-01 7.66e-01 1.19e-01 2.30e-02 0.00e+00 0.00e+00 0.00e+00 0.00e+00 
8.50e-01 1.00e+00 1.56e-01 3.00e-02 0.00e+00 0.00e+00 0.00e+00 0.00e+00

1 个答案:

答案 0 :(得分:1)

根据寻址模式的documentation

  

寻址模式。使用超出范围的坐标调用B.8节的设备功能是有效的。寻址模式定义了那种情况下发生的情况。默认寻址模式是将坐标钳位到有效范围:[0,N]表示非标准化坐标,[0.0,1.0表示标准化坐标。如果指定了边框模式,则带有超出范围的纹理坐标的纹理提取将返回零。 对于标准化坐标,还可以使用环绕模式和镜像模式。当使用环绕模式时,每个坐标x被转换为frac(x)= x floor(x),其中floor(x)是不大于x的最大整数。当使用镜像模式时,如果floor(x)是偶数,则每个坐标x被转换为frac(x),如果floor(x)是奇数,则每个坐标x被转换为1-frac(x)。寻址模式被指定为大小为3的数组,其第一,第二和第三元素分别指定第一,第二和第三纹理坐标的寻址模式;寻址模式为cudaAddressModeBordercudaAddressModeClampcudaAddressModeWrapcudaAddressModeMirror; cudaAddressModeWrapcudaAddressModeMirror仅支持规范化纹理坐标

由于您没有使用标准化坐标:

tex.normalized = false;

环绕模式不可用。