在设备代码中阅读cudaArray

时间:2013-02-17 23:50:43

标签: cuda textures device

有没有办法从设备中读取cudaArray中的值而不将其包装在纹理参考/对象中?我看过的所有示例都使用cudaArray专门用于创建纹理。这是他们可以使用的唯一方式,还是我可以做的事情:

__global__ kernel(cudaArray *arr, ...) {
    float x = tex1D<float>(arr, ...);
    ...
}

cudaArray *arr;
cudaMallocArray(&arr, ...);
cudaMemcpyToArray(arr, ...);
kernel<<<...>>>(arr, ...);

基本上,那里应该取代tex1D的是什么?此外,如果这是可能的,我会很好奇,如果有人认为这样做会有任何性能上的好处,但我也会运行自己的测试来看看。

谢谢!

2 个答案:

答案 0 :(得分:6)

cudaArray是为纹理或表面记忆目的而定义的。如上所示here

  

CUDA数组是针对纹理提取而优化的不透明内存布局。   它们是一维的,二维的或三维的   由元素组成,每个元素都有1,2或4个组成部分   有符号或无符号8,16或32位整数,16位浮点数或32   位漂浮。 CUDA数组只能通过纹理访问内核   按照纹理记忆或表面读写中的描述进行提取   如表面记忆中所述。

因此,实际上你必须在内核中使用texture functions or surface functions来访问cudaArray中的数据。

使用纹理有几个与性能相关的可能性。纹理可以暗示插值(即,使用浮点坐标从纹理读取)。任何需要这种数据插值的应用程序都可以从GPU上纹理单元内的HW插值引擎中受益。

在任意GPU代码中使用纹理最重要的另一个好处是纹理缓存,它可以备份存储在全局内存中的纹理。纹理是一种只读操作,但如果您有一组只读数据,纹理缓存可能会提高或扩展您快速访问数据的能力。这通常意味着您的函数中必须存在数据局部性/数据重用,这些函数访问存储在纹理机制中的数据。检索到的纹理数据不会破坏L1缓存中的任何内容,因此通常这种数据分段/优化将成为围绕数据缓存的更大策略的一部分。如果L1缓存没有其他要求,纹理机制/缓存不能提供比在L1中更快的数据访问。

答案 1 :(得分:3)

Robert Crovella已经回答了你的问题。我相信下一个用户可以使用两个解决方案的工作示例:纹理和表面。

#include <stdio.h>
#include <thrust\device_vector.h>

// --- 2D float texture
texture<float, cudaTextureType2D, cudaReadModeElementType> texRef;

// --- 2D surface memory
surface<void, 2> surf2D;

/********************/
/* CUDA ERROR CHECK */
/********************/
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, char *file, int line, bool abort=true)
{
    if (code != cudaSuccess) 
    {
        fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
        if (abort) exit(code);
    }
}

/*************************************/
/* cudaArray PRINTOUT TEXTURE KERNEL */
/*************************************/
__global__ void cudaArrayPrintoutTexture(int width, int height)
{
    unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
    unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;

    printf("Thread index: (%i, %i); cudaArray = %f\n", x, y, tex2D(texRef, x / (float)width + 0.5f, y / (float)height + 0.5f));
}

/*************************************/
/* cudaArray PRINTOUT TEXTURE KERNEL */
/*************************************/
__global__ void cudaArrayPrintoutSurface(int width, int height)
{
    unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
    unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;

    float temp;

    surf2Dread(&temp, surf2D, x * 4, y);

    printf("Thread index: (%i, %i); cudaArray = %f\n", x, y, temp);
}

/********/
/* MAIN */
/********/
void main()
{
    int width = 3, height = 3;

    thrust::host_vector<float> h_data(width*height, 3.f);

    // --- Allocate CUDA array in device memory
    cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);

    cudaArray* cuArray;

    /*******************/
    /* TEXTURE BINDING */
    /*******************/
    gpuErrchk(cudaMallocArray(&cuArray, &channelDesc, width, height));

    // --- Copy to host data to device memory
    gpuErrchk(cudaMemcpyToArray(cuArray, 0, 0, thrust::raw_pointer_cast(h_data.data()), width*height*sizeof(float), cudaMemcpyHostToDevice));

    // --- Set texture parameters
    texRef.addressMode[0] = cudaAddressModeWrap;
    texRef.addressMode[1] = cudaAddressModeWrap;
    texRef.filterMode = cudaFilterModeLinear;
    texRef.normalized = true;

    // --- Bind the array to the texture reference
    gpuErrchk(cudaBindTextureToArray(texRef, cuArray, channelDesc));

    // --- Invoking printout kernel
    dim3 dimBlock(3, 3);
    dim3 dimGrid(1, 1);
    cudaArrayPrintoutTexture<<<dimGrid, dimBlock>>>(width, height);

    gpuErrchk(cudaUnbindTexture(texRef));

    gpuErrchk(cudaFreeArray(cuArray));

    /******************/
    /* SURFACE MEMORY */
    /******************/
    gpuErrchk(cudaMallocArray(&cuArray, &channelDesc, width, height, cudaArraySurfaceLoadStore));

    // --- Copy to host data to device memory
    gpuErrchk(cudaMemcpyToArray(cuArray, 0, 0, thrust::raw_pointer_cast(h_data.data()), width*height*sizeof(float), cudaMemcpyHostToDevice));

    gpuErrchk(cudaBindSurfaceToArray(surf2D, cuArray));

    cudaArrayPrintoutSurface<<<dimGrid, dimBlock>>>(width, height);
    gpuErrchk(cudaPeekAtLastError());
    gpuErrchk(cudaDeviceSynchronize());

    gpuErrchk(cudaFreeArray(cuArray));
}