CUDA内核中的2D图像索引错误

时间:2011-11-29 10:29:46

标签: cuda

我正在使用CUDA对图像进行线性过滤。我使用2D线程块和2D网格来使问题自然。以下是我的索引:( 高度宽度是图像尺寸)

dim3 BlockDim(16,16);

dim3 GridDim;
GridDim.x = (width + 15) / 16;
GridDim.y = (height + 15) / 16;

在内核中,我按如下方式访问位置:

unsigned int xIndex = blockIdx.x*16+ threadIdx.x;
unsigned int yIndex = blockIdx.y*16+ threadIdx.y;
unsigned int tid = yIndex * width + xIndex;

我想要返回四个边界(我稍后会提供它们)。我这样做:

if(yIndex>=height-N || xIndex>=width-N || yIndex<N || xIndex<N)
  return;

其中N是每个边界的像素数,我不想计算。

问题:

代码在所有标准图像大小上运行良好。但对于一些随机图像尺寸,它显示对角线。例如,在我的情况下,500x333图像(即使没有尺寸是16的倍数)显示正确的输出,而450x365显示输出中的对角线。即使我只是返回网格的额外线程而没有其他类似的东西,问题仍然存在:

if(yIndex>=height || xIndex>=width)
return;

代码保持不变,有些输入运行正常而有些则没有。任何人都可以发现这个错误吗?我在这里附加了输入和输出样本:IMAGES谢谢!

更新

内核代码(简化为返回输入图像,但同样存在问题)

__global__ void filter_8u_c1_kernel(unsigned char* in, unsigned char* out, int width, int height, float* filter, int fSize)
{
    unsigned int xIndex = blockIdx.x*BLOCK_SIZE + threadIdx.x;
    unsigned int yIndex = blockIdx.y*BLOCK_SIZE + threadIdx.y;
    unsigned int tid = yIndex * width + xIndex;

    unsigned int N = filterSize/2;

    if(yIndex>=height-N || xIndex>=width-N || yIndex<N || xIndex<N)
        return;

       /*Filter code removed, still gives the same problem*/

    out[tid] = in[tid];
}

更新2:

我还通过撤消 if 条件删除了 return 语句。但问题仍然存在。

if(yIndex<=height-N && xIndex<=width-N && yIndex>N && xIndex>N){

  /*Kernel Code*/

}

1 个答案:

答案 0 :(得分:3)

有很多事情你还没有描述得很好,但根据你发布的信息,我构建了我猜的是一个合理的复制案例,参数与你说它失败的情况相符(450 x 364与filterSize=5):

#include <stdio.h>
#include <assert.h>

template<int filterSize>
__global__ void filter_8u_c1_kernel(unsigned char* in, unsigned char* out, int width, int height, float* filter, int fSize)
{
    unsigned int xIndex = blockIdx.x*blockDim.x + threadIdx.x;
    unsigned int yIndex = blockIdx.y*blockDim.y + threadIdx.y;
    unsigned int tid = yIndex * width + xIndex;

    unsigned int N = filterSize/2;

    if(yIndex>=height-N || xIndex>=width-N || yIndex<N || xIndex<N)
        return;

    out[tid] = in[tid];
}

int main(void)
{
    const int width = 450, height = 365, filterSize=5;
    const size_t isize = sizeof(unsigned char) * size_t(width * height);
    unsigned char * _in, * _out, * out;

    assert( cudaMalloc((void **)&_in, isize) == cudaSuccess ); 
    assert( cudaMalloc((void **)&_out, isize) == cudaSuccess ); 
    assert( cudaMemset(_in, 'Z', isize) == cudaSuccess );
    assert( cudaMemset(_out, 'A', isize) == cudaSuccess );

    const dim3 BlockDim(16,16);
    dim3 GridDim;
    GridDim.x = (width + BlockDim.x - 1) / BlockDim.x;
    GridDim.y = (height + BlockDim.y - 1) / BlockDim.y;

    filter_8u_c1_kernel<filterSize><<<GridDim,BlockDim>>>(_in,_out,width,height,0,0);
    assert( cudaPeekAtLastError() == cudaSuccess );

    out = (unsigned char *)malloc(isize);
    assert( cudaMemcpy(out, _out, isize, cudaMemcpyDeviceToHost) == cudaSuccess);

    for(int i=0; i<width; i++) {
        fprintf(stdout, "%d: ", i);
        for(int j=0; j<height; j++) {
            unsigned int idx = i + j*width;
            fprintf(stdout, "%c", out[idx]);
        }
        fprintf(stdout, "\n");
    }

    return cudaThreadExit();
}

当它运行时,它完全按照我的预期,用输入覆盖输出内存,除了第一行和最后两行以及中间所有行中的第一个和最后两个条目。这是在OS X 10.6.5上运行带有计算1.2 GPU的CUDA 3.2。所以无论你的代码发生了什么,它都不会发生在我的复制案例中,这或者意味着我误解了你所写的内容,或者还有其他你没有描述的导致问题的内容。