如何从2D纹理成功读取

时间:2010-09-30 21:42:51

标签: c++ cuda textures

我怎么能:

  1. 将cudaMallocPitch浮动内存绑定到2D纹理参考
  2. 将一些主机数据复制到设备上的2D阵列
  3. 将一个添加到纹理参考并写入a。)Pitch 2D数组或b。)写入线性存储器阵列
  4. 阅读回答并显示。
  5. 以下是应该实现此目的的代码。请注意,对于NxN数组大小,我的代码可以正常工作。对于N!M,其中N!= M,我的代码咬了灰尘(不是正确的结果)。如果你能解决这个问题,我将奖励你1个互联网(供应有限)。也许我很疯狂,但根据文档,这应该工作(它确实适用于方阵!)。附加的代码应该使用'nvcc whateveryoucallit.cu -o runit'运行。

    非常感谢帮助!

    #include<stdio.h>
    #include<cuda.h>
    #include<iostream>
    #define height 16
    #define width 11
    #define BLOCKSIZE 16
    
    using namespace std;
    
    // Device Kernels
    
    //Texture reference Declaration
    texture<float,2> texRefEx;
    
    
    __global__ void kernel_w_textures(float* devMPPtr, float * devMPtr, int pitch)
    {
     // Thread indexes
            unsigned int idx = blockIdx.x*blockDim.x + threadIdx.x;
            unsigned int idy = blockIdx.y*blockDim.y + threadIdx.y;
    
     // Texutre Coordinates
     float u=(idx)/float(width);
     float v=(idy)/float(height);
     devMPtr[idy*width+idx]=devMPPtr[idy*pitch/sizeof(float)+idx];
     // Write Texture Contents to malloc array +1
     devMPtr[idy*width+idx]= tex2D(texRefEx,u,v);//+1.0f;
    }
    int main()
    {
     // memory size
     size_t memsize=height*width;
     size_t offset;
     float * data,  // input from host
      *h_out,  // host space for output
      *devMPPtr, // malloc Pitch ptr
      *devMPtr; // malloc ptr
    
     size_t pitch;
    
     // Allocate space on the host
     data=(float *)malloc(sizeof(float)*memsize);
     h_out=(float *)malloc(sizeof(float)*memsize);
    
    
    // Define data
    for (int i = 0; i <  height; i++)
     for (int j=0; j < width; j++)
      data[i*width+j]=float(j);
    
    // Define the grid
    dim3 grid((int)(width/BLOCKSIZE)+1,(int)(height/BLOCKSIZE)+1), threads(BLOCKSIZE,BLOCKSIZE);
    
    // allocate Malloc Pitch
    cudaMallocPitch((void**)&devMPPtr,&pitch, width * sizeof(float), height);
    
    // Print the pitch
    printf("The pitch is %d \n",pitch/sizeof(float));
    
    // Texture Channel Description
    //cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
    cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32,0,0,0,cudaChannelFormatKindFloat);
    
    // Bind texture to pitch mem:
    cudaBindTexture2D(&offset,&texRefEx,devMPPtr,&channelDesc,width,height,pitch);
    cout << "My Description x is " << channelDesc.x << endl;
    cout << "My Description y is " << channelDesc.y << endl;
    cout << "My Description z is " << channelDesc.z << endl;
    cout << "My Description w is " << channelDesc.w << endl;
    cout << "My Description kind is " << channelDesc.f << endl;
    cout << "Offset is " << offset << endl;
    
    // Set mutable properties:
    texRefEx.normalized=true;
    texRefEx.addressMode[0]=cudaAddressModeWrap;
    texRefEx.addressMode[1]=cudaAddressModeWrap;
    texRefEx.filterMode= cudaFilterModePoint;
    
    // Allocate cudaMalloc memory
    cudaMalloc((void**)&devMPtr,memsize*sizeof(float));
    
    // Read data from host to device
    cudaMemcpy2D((void*)devMPPtr,pitch,(void*)data,sizeof(float)*width,
      sizeof(float)*width,height,cudaMemcpyHostToDevice);
    
    //Read back and check this memory
    cudaMemcpy2D((void*)h_out,width*sizeof(float),(void*)devMPPtr,pitch,
      sizeof(float)*width,height,cudaMemcpyDeviceToHost);
    
    // Print the memory
     for (int i=0; i<height; i++){
      for (int j=0; j<width; j++){
       printf("%2.2f ",h_out[i*width+j]);
      }
     cout << endl;
     }
    
     cout << "Done" << endl;
    // Memory is fine... 
    
    kernel_w_textures<<<grid,threads>>>(devMPPtr, devMPtr, pitch);
    
    // Copy back data to host
    cudaMemcpy((void*)h_out,(void*)devMPtr,width*height*sizeof(float),cudaMemcpyDeviceToHost);
    
    
    // Print the Result
     cout << endl;
     for (int i=0; i<height; i++){
      for (int j=0; j<width; j++){
       printf("%2.2f ",h_out[i*width+j]);
      }
     cout << endl;
     }
     cout << "Done" << endl;
    
    return(0);
    }
    

    编辑10月17日:所以我仍然没有找到解决这个问题的方法。 Nvidia在这方面相当沉默似乎世界也是如此。我找到了使用共享内存的解决方法,但如果有人有纹理解决方案,我会很高兴。

    编辑 Octoboer 26:仍然没有解决问题,但如果有人知道,仍然对此感兴趣。

    编辑 7月26日:哇哇已经9个月了 - 我一直忽略了正确的答案。诀窍是:

    if ( idx < width  && idy < height){//.... code }
    

    正如之前所指出的那样。感谢所有贡献者!

5 个答案:

答案 0 :(得分:3)

它可能与你的块大小有关。在此代码中,您尝试将一个16x16线程块写入11x16内存块。这意味着你的一些线程正在写入未分配的内存。这也解释了为什么你的测试(16 * M乘32 * N)有效:没有线程写入未分配的内存,因为你的尺寸是16的倍数。

解决此问题的简单方法是这样的:

if ((x < width) && (y < height)) {
   // write output 
  devMPtr[idy*width+idx]= tex2D(texRefEx,u,v); 
}

在调用内核之前,您需要将高度和宽度传递给内核函数或将常量复制到卡上。

答案 1 :(得分:2)

我想:

 float u=(idx)/float(width);
 float v=(idy)/float(height);

应该是

 float u=(idx+0.5f)/float(width);
 float v=(idy+0.5f)/float(height);

为了得到相同的输入/输出,否则第二列输出等于第一列输入而不是第二列,第二列输出也是错误的。

如果你有不同的观察,请纠正我。

答案 2 :(得分:1)

 // Texutre Coordinates
 float u=(idx + 0.5)/float(width);
 float v=(idy + 0.5)/float(height);

您需要偏移才能到达纹素的中心。我认为你的16个纹理的非多重可能存在一些舍入误差。我尝试了这个,它对我有用(两个输出都相同)。

答案 3 :(得分:0)

显卡通常期望纹理的尺寸为2的幂,对于nVidia卡尤其如此。 Cuda的cudaMallocPitch和cudaMemcpy2D使用这些音高并查看您的代码,最安全的解决方案是自己调整宽度和高度以确保安全。否则,Cuda可能会写入无效的内存,因为它会出现错误的偏移:

#define height 16
#define width 11

...

size_t roundUpToPowerOf2(size_t v)
{
  // See http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
  --v;
  v |= v >> 1;
  v |= v >> 2;
  v |= v >> 4;
  v |= v >> 8;
  v |= v >> 16;
  ++v;
  return v;
}
...

size_t horizontal_pitch = roundUpToPowerOf2(width);
size_t vertical_pitch = roundUpToPowerOf2(height);
size_t memsize = horizontal_pitch * vertical_pitch;

...

// Read data from host to device
cudaMemcpy2D((void*)devMPPtr,pitch,(void*)data,sizeof(float)*horizontal_pitch,
  sizeof(float)*width,height,cudaMemcpyHostToDevice);

//Read back and check this memory
cudaMemcpy2D((void*)h_out,horizontal_pitch*sizeof(float),(void*)devMPPtr,pitch,
  sizeof(float)*width,height,cudaMemcpyDeviceToHost);

// Print the memory
 for (int i=0; i<height; i++){
  for (int j=0; j<width; j++){
   printf("%2.2f ",h_out[i*horizontal_pitch+j]);
  }
 cout << endl;
 }

...

// Copy back data to host
cudaMemcpy((void*)h_out,(void*)devMPtr,horizontal_pitch*vertical_pitch*sizeof(float),cudaMemcpyDeviceToHost);

// Print the Result
 cout << endl;
 for (int i=0; i<height; i++){
  for (int j=0; j<width; j++){
   printf("%2.2f ",h_out[i*horizontal_pitch+j]);
  }
 cout << endl;
 }
 cout << "Done" << endl;

希望我没有忽略应该使用horizo​​ntal_pitch / vertical_pitch而不是普通宽度/高度的任何地方。

答案 4 :(得分:0)

或许看一下这个帖子:http://forums.nvidia.com/index.php?showtopic=186585

另一个非常有用的示例代码片段目前在NVIDIA SDK中;正如NVIDIA论坛上面的帖子中所提到的,simplePitchLinearTexture示例运行良好。

由于我们使用纹理存储器,我相信2D网格的大小在某些硬件上必须是2的幂,正如上面的一个答案中所建议的那样。