有没有办法从设备中读取cudaArray
中的值而不将其包装在纹理参考/对象中?我看过的所有示例都使用cudaArray
专门用于创建纹理。这是他们可以使用的唯一方式,还是我可以做的事情:
__global__ kernel(cudaArray *arr, ...) {
float x = tex1D<float>(arr, ...);
...
}
cudaArray *arr;
cudaMallocArray(&arr, ...);
cudaMemcpyToArray(arr, ...);
kernel<<<...>>>(arr, ...);
基本上,那里应该取代tex1D
的是什么?此外,如果这是可能的,我会很好奇,如果有人认为这样做会有任何性能上的好处,但我也会运行自己的测试来看看。
谢谢!
答案 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));
}