我试图在Cuda中使用cudaAddressModeWrap
功能,但是,我遇到了一些困难。
我在下面提供了我的代码:
texture <float, 2, cudaReadModeElementType> tex;
__global__ void transformKernel( float* Btmp, int width, int height)
{
unsigned int x = blockIdx.x*blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y*blockDim.y + threadIdx.y;
if ( (x < width) && (y < height) )
{
if( x == 0 || x == 1 )
Btmp[y*width+x] = tex2D(tex, x, y);
else
{
Btmp[y*width+x] = tex2D(tex, x, y) + \
(0.15 * tex2D(tex, x - 2, y)) + \
(0.65 * tex2D(tex, x - 1, y)) + \
(1.35 * tex2D(tex, x + 1, y)) + \
(1.85 * tex2D(tex, x + 2, y));
Btmp[y * width + x] /= float(5);
}
}
}
我想要周期性的边界条件,因此Mode Wrap应该是完美的。我想我正在设置参数不正确,但我不确定。这是相关的代码。
int i, j;
float **A;
float *Atmp;
A = (float **)malloc( ndim * sizeof(float *));
Atmp = (float *)malloc ( ndim * mdim * sizeof(float));
for(i=0;i<ndim;i++)
A[i] = &Atmp[i * mdim];
for(i=0;i<ndim;i++)
{
for(j=0;j<mdim;j++)
{
A[i][j] = 0;
}
A[i][0] = 0.85 * (float)((i+1)*(i+1))/(float)(ndim*ndim);
A[i][1] = 1.00 * (float)((i+1)*(i+1))/(float)(ndim*ndim);
}
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);
cudaArray* cu_array;
cudaMallocArray( &cu_array, &channelDesc, mdim, ndim );
cudaMemcpyToArray( cu_array, 0, 0, Atmp, ndim * mdim *sizeof(float), cudaMemcpyHostToDevice);
tex.addressMode[0] = cudaAddressModeWrap;
tex.addressMode[1] = cudaAddressModeWrap;
tex.filterMode = cudaFilterModePoint;
tex.normalized = false;
cudaBindTextureToArray(tex, cu_array, channelDesc);
dim3 dimBlock(4, 4, 1);
dim3 dimGrid(mdim / dimBlock.x, ndim / dimBlock.y, 1);
float* d_data = NULL;
cudaMalloc( (void**) &d_data, ndim * mdim *sizeof(float));
transformKernel<<< dimGrid, dimBlock, 0 >>>(d_data, mdim, ndim);
cudaMemcpy(Btmp, d_data, ndim*mdim*sizeof(float), cudaMemcpyDeviceToHost);
所需的输出是:
1.33e-02 1.56e-02 2.43e-03 4.69e-04 0.00e+00 0.00e+00 4.91e-03 9.37e-03
5.31e-02 6.25e-02 9.72e-03 1.88e-03 0.00e+00 0.00e+00 1.97e-02 3.75e-02
1.20e-01 1.41e-01 2.19e-02 4.22e-03 0.00e+00 0.00e+00 4.42e-02 8.43e-02
2.13e-01 2.50e-01 3.89e-02 7.50e-03 0.00e+00 0.00e+00 7.86e-02 1.50e-01
3.32e-01 3.91e-01 6.07e-02 1.17e-02 0.00e+00 0.00e+00 1.23e-01 2.34e-01
4.78e-01 5.62e-01 8.75e-02 1.69e-02 0.00e+00 0.00e+00 1.77e-01 3.37e-01
6.51e-01 7.66e-01 1.19e-01 2.30e-02 0.00e+00 0.00e+00 2.41e-01 4.59e-01
8.50e-01 1.00e+00 1.56e-01 3.00e-02 0.00e+00 0.00e+00 3.15e-01 6.00e-01
使用纹理记忆我得到:
1.33e-02 1.56e-02 2.43e-03 4.69e-04 0.00e+00 0.00e+00 0.00e+00 0.00e+00
5.31e-02 6.25e-02 9.72e-03 1.88e-03 0.00e+00 0.00e+00 0.00e+00 0.00e+00
1.20e-01 1.41e-01 2.19e-02 4.22e-03 0.00e+00 0.00e+00 0.00e+00 0.00e+00
2.13e-01 2.50e-01 3.89e-02 7.50e-03 0.00e+00 0.00e+00 0.00e+00 0.00e+00
3.32e-01 3.91e-01 6.07e-02 1.17e-02 0.00e+00 0.00e+00 0.00e+00 0.00e+00
4.78e-01 5.62e-01 8.75e-02 1.69e-02 0.00e+00 0.00e+00 0.00e+00 0.00e+00
6.51e-01 7.66e-01 1.19e-01 2.30e-02 0.00e+00 0.00e+00 0.00e+00 0.00e+00
8.50e-01 1.00e+00 1.56e-01 3.00e-02 0.00e+00 0.00e+00 0.00e+00 0.00e+00
答案 0 :(得分:1)
根据寻址模式的documentation:
寻址模式。使用超出范围的坐标调用B.8节的设备功能是有效的。寻址模式定义了那种情况下发生的情况。默认寻址模式是将坐标钳位到有效范围:[0,N]表示非标准化坐标,[0.0,1.0表示标准化坐标。如果指定了边框模式,则带有超出范围的纹理坐标的纹理提取将返回零。 对于标准化坐标,还可以使用环绕模式和镜像模式。当使用环绕模式时,每个坐标x被转换为frac(x)= x floor(x),其中floor(x)是不大于x的最大整数。当使用镜像模式时,如果floor(x)是偶数,则每个坐标x被转换为frac(x),如果floor(x)是奇数,则每个坐标x被转换为1-frac(x)。寻址模式被指定为大小为3的数组,其第一,第二和第三元素分别指定第一,第二和第三纹理坐标的寻址模式;寻址模式为
cudaAddressModeBorder
,cudaAddressModeClamp
,cudaAddressModeWrap
和cudaAddressModeMirror
;cudaAddressModeWrap
和cudaAddressModeMirror
仅支持规范化纹理坐标
由于您没有使用标准化坐标:
tex.normalized = false;
环绕模式不可用。