使用CUDA计算2D像素阵列,声明适当的网格和块大小

时间:2013-11-23 19:01:06

标签: c++ c arrays opengl cuda

我正在使用CUDA来计算已被展平的64x64x4数组的值。该数组包含GLubytes,然后在z列中存储任何给定像素的RGBA值。我已经创建了一个与CUDA一起使用的内核,但我认为我的块和网格的尺寸已经关闭。最终的结果是不是绘制圆圈,而是仅绘制四分之一的圆圈。调用的内核和函数如下:

澄清:DIAMETER = 64,RADIUS = 32。

__global__ void drawKernel(GLubyte *ball)
{
    int x = (blockIdx.x * blockDim.x) + threadIdx.x;
    int y = (blockIdx.y * blockDim.y) + threadIdx.y;


    ball[4 * (x * DIAMETER + y)+3] = (GLubyte) 0x0;  
    if ((x * x) + (y * y) <= (RADIUS * RADIUS)){ 
        ball[4 * ((x+32) * DIAMETER + (y+32))+0] = (GLubyte) 0xffffff;  
        ball[4 * ((x+32) * DIAMETER + (y+32))+1] = (GLubyte) 0x0; 
        ball[4 * ((x+32) * DIAMETER + (y+32))+2] = (GLubyte) 0x0; 
        ball[4 * ((x+32) * DIAMETER + (y+32))+3] = (GLubyte) 0xaaaaaa;
    }
}

cudaError_t drawWithCuda()
{
    size_t memorySize = DIAMETER * DIAMETER * 4 *sizeof(GLubyte);
    GLubyte *dev_ball = 0; //device ball
    cudaError_t cudaStatus; //CUDA error status
    dim3 threadsPerBlock(8, 8);
    dim3 numBlocks(DIAMETER/threadsPerBlock.x, DIAMETER/threadsPerBlock.y);

    // Choose which GPU to run on, change this on a multi-GPU system.
    cudaStatus = cudaSetDevice(0);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaSetDevice(0) failed! CUDA-capable GPU not on board.");
        goto Error;
    }

    // Allocate GPU buffers for GLubyte array 
    cudaStatus = cudaMalloc((void**)&dev_ball, memorySize);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }

    //Begin CUDA-kernal call

    drawKernel<<<numBlocks, threadsPerBlock>>>(dev_ball);

    cudaDeviceSynchronize();

    //Copy from Device
    cudaStatus = cudaMemcpy(ball, dev_ball, memorySize, cudaMemcpyDeviceToHost);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "Device to Host failed!");
        goto Error;
    }

    Error:
        cudaFree(dev_ball);

    return cudaStatus;
}

我的问题是:我的问题是在我的Block和Grid的维度中找到的吗?还是别的什么?

输出(一旦我通过openGL运行arrray球)是下图: enter image description here

我应该补充一点,当我不使用cuda并且只使用常规for循环计算数组值时,内核中使用的逻辑可以很好地工作并绘制圆圈。

1 个答案:

答案 0 :(得分:3)

你正在分配这么多内存(在ball中):

    size_t memorySize = DIAMETER * DIAMETER * 4 *sizeof(GLubyte);

即。一个64 x 64 x 4字节深的数组

现在让我们看一下内核中的数组索引计算:

    ball[4 * ((x+32) * DIAMETER + (y+32))+0] = (GLubyte) 0xffffff; 

您的xy的计算方法如下:

int x = (blockIdx.x * blockDim.x) + threadIdx.x;
int y = (blockIdx.y * blockDim.y) + threadIdx.y;

鉴于您的内核启动维度,您将启动DIAMETER x DIAMETER线程数组,即64x64。因此,每个x从0到63不等,每个y从0到63不等,具体取决于主题。

当我们将一些xy值插入到您的内核中时,索引计算会爆炸(超过分配的内存):

    ball[4 * ((63+32) * 64 + (63+32))+0] = (GLubyte) 0xffffff; 

这超出ball中的64x64x4可用区域。如果您使用cuda-memcheck运行此代码,我很确定您会看到越界索引错误。

似乎您的数组索引应该类似于:

    ball[4 * ((x) * DIAMETER + (y))+0] = (GLubyte) 0xffffff;