【CUDA编程】系列博客参考NVIDIA官方文档“CUDA C++ Programming Guide(v12.6)”。
本文为原创文章,未经本人允许,禁止转载。转载请注明出处。
1.Synchronization Functions
1
void __syncthreads();
__syncthreads()
会等待线程块中的所有线程到达这个同步点。__syncthreads()
可以在条件语句中使用,但只有当条件在整个线程块中计算结果相同时才可以。否则,代码执行可能会挂起或产生意外的副作用。
计算能力2.x及以上的device支持__syncthreads()
的三种变体,如下所示。
1
int __syncthreads_count(int predicate);
predicate是一个布尔表达式或逻辑判断,用于检查某个线程是否满足特定的条件。__syncthreads_count()
返回满足条件的线程数量。比如int count = __syncthreads_count(threadIdx.x % 2 == 0);
返回线程块中线程索引为偶数的线程数量。
1
int __syncthreads_and(int predicate);
当所有线程都满足条件时(即所有线程的predicate都为非零值时),__syncthreads_and()
返回非零值。
1
int __syncthreads_or(int predicate);
当至少有一个线程满足条件时,__syncthreads_or()
就返回非零值。
1
void __syncwarp(unsigned mask=0xffffffff);
__syncwarp()
是一种轻量级的同步机制,专门用于同步warp内的线程。通过指定mask,可以选择性的同步warp内的某些线程,而非同步整个warp。其中,mask是一个32位的整数,每一位对应warp中的一个线程。若mask的某一位为1,则表示对应线程需要参与同步。默认值0xffffffff表示warp中所有线程都需要同步。所有参与同步的线程必须调用相同的__syncwarp()
,并使用相同的mask,否则结果是未定义的。
执行__syncwarp()
能够保证参与屏障的线程之间的内存顺序。因此,warp中的线程若需要通过内存进行通信,可以先写入内存,然后执行__syncwarp()
,接着安全地读取其他线程存储的值。
2.Texture Functions
2.1.Texture Object API
2.1.1.tex1Dfetch()
1
2
template<class T>
T tex1Dfetch(cudaTextureObject_t texObj, int x);
tex1Dfetch()
从一维纹理对象texObj
指定的线性内存区域中,根据整数纹理坐标x
获取数据。tex1Dfetch()
仅支持非归一化坐标,因此仅支持clamp mode和border mode作为寻址模式。此函数不执行任何纹理过滤。对于整数类型的纹理数据,它可能会选择性地将整数提升为单精度浮点数。
2.1.2.tex1D()
1
2
template<class T>
T tex1D(cudaTextureObject_t texObj, float x);
tex1D()
从一维纹理对象texObj
指定的CUDA array中,根据纹理坐标x
获取数据。与tex1Dfetch()
不同,tex1D()
使用的是归一化坐标。
2.1.3.tex1DLod()
1
2
template<class T>
T tex1DLod(cudaTextureObject_t texObj, float x, float level);
为了解释参数level
,我们先来解释mipmap。mipmap(也称为MIP maps或pyramids)是计算机图形学中用于纹理采样和优化的一种技术。它通过存储纹理的多个分辨率版本,解决了纹理放缩时的性能和质量问题。比如原始纹理的分辨率为$1024 \times 1024$(第0层),通常来说,mipmap中每一层的分辨率是上一层分辨率的一半,那么第1层纹理的分辨率就是$512 \times 512$,第2层纹理的分辨率就是$256 \times 256$,直至分辨率降为$1 \times 1$。下面是一个mipmap如何存储的例子,左边的主图伴有一系列逐层缩小的备份小图。
而我们可以使用LOD(level-of-detail,即参数level
)的值决定从哪个分辨率层级中采样。假设mipmap一共有$n$层,那么LOD的取值范围就是$[0,n]$,非整数的LOD值会进行插值,使用相邻两个层级的纹理数据混合得到采样值。
tex1DLod()
从一维纹理对象texObj
指定的CUDA array中,根据特定level
层级中的纹理坐标x
来获取数据。
2.1.4.tex1DGrad()
1
2
template<class T>
T tex1DGrad(cudaTextureObject_t texObj, float x, float dx, float dy);
与tex1DLod()
不同之处在于,tex1DGrad()
所用的LOD值是通过X方向梯度dx
和Y方向梯度dy
推导得到的。
2.1.5.tex2D()
1
2
template<class T>
T tex2D(cudaTextureObject_t texObj, float x, float y);
tex2D()
从二维纹理对象texObj
指定的CUDA array或线性内存区域中,根据二维纹理坐标(x,y)
获取数据。
2.1.6.tex2D() for sparse CUDA arrays
1
2
template<class T>
T tex2D(cudaTextureObject_t texObj, float x, float y, bool* isResident);
从二维纹理对象texObj
指定的稀疏CUDA array中,根据二维纹理坐标(x,y)
获取数据。同时,通过指针isResident
返回该texel是否驻留在显存中。如果texel不在显存中,则函数返回值为零。
2.1.7.tex2Dgather()
1
2
3
template<class T>
T tex2Dgather(cudaTextureObject_t texObj,
float x, float y, int comp = 0);
从二维纹理对象texObj
指定的CUDA array中,根据二维纹理坐标(x,y)
以及参数comp
(详见:Texture Gather)获取数据。
2.1.8.tex2Dgather() for sparse CUDA arrays
1
2
3
template<class T>
T tex2Dgather(cudaTextureObject_t texObj,
float x, float y, bool* isResident, int comp = 0);
从二维纹理对象texObj
指定的稀疏CUDA array中,根据二维纹理坐标(x,y)
以及参数comp
获取数据。同时,通过指针isResident
返回该texel是否驻留在显存中。如果texel不在显存中,则函数返回值为零。
2.1.9.tex2DGrad()
1
2
3
template<class T>
T tex2DGrad(cudaTextureObject_t texObj, float x, float y,
float2 dx, float2 dy);
从二维纹理对象texObj
指定的CUDA array中,根据二维纹理坐标(x,y)
获取数据。LOD值通过梯度dx
和dy
计算得到。
2.1.10.tex2DGrad() for sparse CUDA arrays
1
2
3
template<class T>
T tex2DGrad(cudaTextureObject_t texObj, float x, float y,
float2 dx, float2 dy, bool* isResident);
从二维纹理对象texObj
指定的稀疏CUDA array中,根据二维纹理坐标(x,y)
获取数据。LOD值通过梯度dx
和dy
计算得到。同时,通过指针isResident
返回该texel是否驻留在显存中。如果texel不在显存中,则函数返回值为零。
2.1.11.tex2DLod()
1
2
template<class T>
tex2DLod(cudaTextureObject_t texObj, float x, float y, float level);
从二维纹理对象texObj
指定的CUDA array或线性内存区域中,在特定level
层级(即LOD值)中,根据二维纹理坐标(x,y)
获取数据。
2.1.12.tex2DLod() for sparse CUDA arrays
1
2
template<class T>
tex2DLod(cudaTextureObject_t texObj, float x, float y, float level, bool* isResident);
从二维纹理对象texObj
指定的稀疏CUDA array中,在特定level
层级(即LOD值)中,根据二维纹理坐标(x,y)
获取数据。同时,通过指针isResident
返回该texel是否驻留在显存中。如果texel不在显存中,则函数返回值为零。
2.1.13.tex3D()
1
2
template<class T>
T tex3D(cudaTextureObject_t texObj, float x, float y, float z);
从三维纹理对象texObj
指定的CUDA array中,根据三维纹理坐标(x,y,z)
获取数据。
2.1.14.tex3D() for sparse CUDA arrays
1
2
template<class T>
T tex3D(cudaTextureObject_t texObj, float x, float y, float z, bool* isResident);
从三维纹理对象texObj
指定的稀疏CUDA array中,根据三维纹理坐标(x,y,z)
获取数据。同时,通过指针isResident
返回该texel是否驻留在显存中。如果texel不在显存中,则函数返回值为零。
2.1.15.tex3DLod()
1
2
template<class T>
T tex3DLod(cudaTextureObject_t texObj, float x, float y, float z, float level);
从三维纹理对象texObj
指定的CUDA array或线性内存区域中,在特定level
层级(即LOD值)中,根据三维纹理坐标(x,y,z)
获取数据。
2.1.16.tex3DLod() for sparse CUDA arrays
1
2
template<class T>
T tex3DLod(cudaTextureObject_t texObj, float x, float y, float z, float level, bool* isResident);
从三维纹理对象texObj
指定的稀疏CUDA array或线性内存区域中,在特定level
层级(即LOD值)中,根据三维纹理坐标(x,y,z)
获取数据。同时,通过指针isResident
返回该texel是否驻留在显存中。如果texel不在显存中,则函数返回值为零。
2.1.17.tex3DGrad()
1
2
3
template<class T>
T tex3DGrad(cudaTextureObject_t texObj, float x, float y, float z,
float4 dx, float4 dy);
从三维纹理对象texObj
指定的CUDA array中,在特定LOD值下,根据三维纹理坐标(x,y,z)
获取数据。其中,LOD值通过X方向梯度dx
和Y方向梯度dy
计算得到。
2.1.18.tex3DGrad() for sparse CUDA arrays
1
2
3
template<class T>
T tex3DGrad(cudaTextureObject_t texObj, float x, float y, float z,
float4 dx, float4 dy, bool* isResident);
从三维纹理对象texObj
指定的稀疏CUDA array中,在特定LOD值下,根据三维纹理坐标(x,y,z)
获取数据。其中,LOD值通过X方向梯度dx
和Y方向梯度dy
计算得到。同时,通过指针isResident
返回该texel是否驻留在显存中。如果texel不在显存中,则函数返回值为零。
2.1.19.tex1DLayered()
1
2
template<class T>
T tex1DLayered(cudaTextureObject_t texObj, float x, int layer);
从一维纹理对象texObj
指定的CUDA array中,根据一维纹理坐标x
和层索引layer
获取数据。
2.1.20.tex1DLayeredLod()
1
2
template<class T>
T tex1DLayeredLod(cudaTextureObject_t texObj, float x, int layer, float level);
从一维纹理对象texObj
指定的CUDA array中,在特定level
层级(即LOD值)中,根据一维纹理坐标x
和层索引layer
获取数据。
2.1.21.tex1DLayeredGrad()
1
2
3
template<class T>
T tex1DLayeredGrad(cudaTextureObject_t texObj, float x, int layer,
float dx, float dy);
从一维纹理对象texObj
指定的CUDA array中,在特定LOD值下,根据一维纹理坐标x
和层索引layer
获取数据。其中,LOD值通过X方向梯度dx
和Y方向梯度dy
计算得到。
2.1.22.tex2DLayered()
1
2
3
template<class T>
T tex2DLayered(cudaTextureObject_t texObj,
float x, float y, int layer);
从二维纹理对象texObj
指定的CUDA array中,根据二维纹理坐标(x,y)
和层索引layer
获取数据。
2.1.23.tex2DLayered() for Sparse CUDA Arrays
1
2
3
template<class T>
T tex2DLayered(cudaTextureObject_t texObj,
float x, float y, int layer, bool* isResident);
从二维纹理对象texObj
指定的稀疏CUDA array中,根据二维纹理坐标(x,y)
和层索引layer
获取数据。同时,通过指针isResident
返回该texel是否驻留在显存中。如果texel不在显存中,则函数返回值为零。
2.1.24.tex2DLayeredLod()
1
2
3
template<class T>
T tex2DLayeredLod(cudaTextureObject_t texObj, float x, float y, int layer,
float level);
从二维纹理对象texObj
指定的CUDA array中,在特定level
层级(即LOD值)中,根据二维纹理坐标(x,y)
和层索引layer
获取数据。
2.1.25.tex2DLayeredLod() for sparse CUDA arrays
1
2
3
template<class T>
T tex2DLayeredLod(cudaTextureObject_t texObj, float x, float y, int layer,
float level, bool* isResident);
从二维纹理对象texObj
指定的稀疏CUDA array中,在特定level
层级(即LOD值)中,根据二维纹理坐标(x,y)
和层索引layer
获取数据。同时,通过指针isResident
返回该texel是否驻留在显存中。如果texel不在显存中,则函数返回值为零。
2.1.26.tex2DLayeredGrad()
1
2
3
template<class T>
T tex2DLayeredGrad(cudaTextureObject_t texObj, float x, float y, int layer,
float2 dx, float2 dy);
从二维纹理对象texObj
指定的CUDA array中,在特定LOD值下,根据二维纹理坐标(x,y)
和层索引layer
获取数据。其中,LOD值通过X方向梯度dx
和Y方向梯度dy
计算得到。
2.1.27.tex2DLayeredGrad() for sparse CUDA arrays
1
2
3
template<class T>
T tex2DLayeredGrad(cudaTextureObject_t texObj, float x, float y, int layer,
float2 dx, float2 dy, bool* isResident);
从二维纹理对象texObj
指定的稀疏CUDA array中,在特定LOD值下,根据二维纹理坐标(x,y)
和层索引layer
获取数据。其中,LOD值通过X方向梯度dx
和Y方向梯度dy
计算得到。同时,通过指针isResident
返回该texel是否驻留在显存中。如果texel不在显存中,则函数返回值为零。
2.1.28.texCubemap()
1
2
template<class T>
T texCubemap(cudaTextureObject_t texObj, float x, float y, float z);
从cubemap纹理对象texObj
指定的CUDA array中,根据纹理坐标(x,y,z)
获取数据。
2.1.29.texCubemapGrad()
1
2
3
template<class T>
T texCubemapGrad(cudaTextureObject_t texObj, float x, float, y, float z,
float4 dx, float4 dy);
从cubemap纹理对象texObj
指定的CUDA array中,根据纹理坐标(x,y,z)
获取数据。梯度dx
和dy
用于确定LOD值。
2.1.30.texCubemapLod()
1
2
3
template<class T>
T texCubemapLod(cudaTextureObject_t texObj, float x, float, y, float z,
float level);
从cubemap纹理对象texObj
指定的CUDA array中,根据纹理坐标(x,y,z)
获取数据。参数level
用于指定LOD值。
2.1.31.texCubemapLayered()
1
2
3
template<class T>
T texCubemapLayered(cudaTextureObject_t texObj,
float x, float y, float z, int layer);
从cubemap分层纹理对象texObj
指定的CUDA array中,根据纹理坐标(x,y,z)
和层索引layer
获取数据。
2.1.32.texCubemapLayeredGrad()
1
2
3
template<class T>
T texCubemapLayeredGrad(cudaTextureObject_t texObj, float x, float y, float z,
int layer, float4 dx, float4 dy);
从cubemap分层纹理对象texObj
指定的CUDA array中,根据纹理坐标(x,y,z)
和层索引layer
获取数据。梯度dx
和dy
用于确定LOD值。
2.1.33.texCubemapLayeredLod()
1
2
3
template<class T>
T texCubemapLayeredLod(cudaTextureObject_t texObj, float x, float y, float z,
int layer, float level);
从cubemap分层纹理对象texObj
指定的CUDA array中,根据纹理坐标(x,y,z)
和层索引layer
获取数据。参数level
用于指定LOD值。
3.Surface Functions
参考:Surface Memory。
表面函数(surface functions)仅支持计算能力2.0及以上的device。
在第3.1部分中,boundaryMode
指定了边界模式,即如何处理超出范围的表面坐标。当边界模式设置为cudaBoundaryModeClamp
时,超出范围的坐标会被限制在有效范围内。当边界模式设置为cudaBoundaryModeZero
时,超出范围的读操作返回零,写操作会被忽略。当边界模式设置为cudaBoundaryModeTrap
时,超出范围的访问会导致kernel执行失败。
3.1.Surface Object API
3.1.1.surf1Dread()
1
2
3
template<class T>
T surf1Dread(cudaSurfaceObject_t surfObj, int x,
boundaryMode = cudaBoundaryModeTrap);
从一维表面对象surfObj
指定的CUDA array中,使用字节坐标x
读取数据。
3.1.2.surf1Dwrite
1
2
3
4
5
template<class T>
void surf1Dwrite(T data,
cudaSurfaceObject_t surfObj,
int x,
boundaryMode = cudaBoundaryModeTrap);
将值data
写入到由一维表面对象surfObj
指定的CUDA array中,写入的位置由字节坐标x
指定。
3.1.3.surf2Dread()
1
2
3
4
5
6
7
8
9
template<class T>
T surf2Dread(cudaSurfaceObject_t surfObj,
int x, int y,
boundaryMode = cudaBoundaryModeTrap);
template<class T>
void surf2Dread(T* data,
cudaSurfaceObject_t surfObj,
int x, int y,
boundaryMode = cudaBoundaryModeTrap);
从二维表面对象surfObj
指定的CUDA array中,使用字节坐标x
和y
读取数据。
3.1.4.surf2Dwrite()
1
2
3
4
5
template<class T>
void surf2Dwrite(T data,
cudaSurfaceObject_t surfObj,
int x, int y,
boundaryMode = cudaBoundaryModeTrap);
将值data
写入到由二维表面对象surfObj
指定的CUDA array中,写入的位置由字节坐标x
和y
指定。
3.1.5.surf3Dread()
1
2
3
4
5
6
7
8
9
template<class T>
T surf3Dread(cudaSurfaceObject_t surfObj,
int x, int y, int z,
boundaryMode = cudaBoundaryModeTrap);
template<class T>
void surf3Dread(T* data,
cudaSurfaceObject_t surfObj,
int x, int y, int z,
boundaryMode = cudaBoundaryModeTrap);
从三维表面对象surfObj
指定的CUDA array中,使用字节坐标x
、y
、z
读取数据。
3.1.6.surf3Dwrite()
1
2
3
4
5
template<class T>
void surf3Dwrite(T data,
cudaSurfaceObject_t surfObj,
int x, int y, int z,
boundaryMode = cudaBoundaryModeTrap);
将值data
写入到由三维表面对象surfObj
指定的CUDA array中,写入的位置由字节坐标x
、y
、z
指定。
3.1.7.surf1DLayeredread()
1
2
3
4
5
6
7
8
9
10
template<class T>
T surf1DLayeredread(
cudaSurfaceObject_t surfObj,
int x, int layer,
boundaryMode = cudaBoundaryModeTrap);
template<class T>
void surf1DLayeredread(T data,
cudaSurfaceObject_t surfObj,
int x, int layer,
boundaryMode = cudaBoundaryModeTrap);
从一维分层表面对象surfObj
指定的CUDA array中,使用字节坐标x
和层索引layer
读取数据。
3.1.8.surf1DLayeredwrite()
1
2
3
4
5
template<class Type>
void surf1DLayeredwrite(T data,
cudaSurfaceObject_t surfObj,
int x, int layer,
boundaryMode = cudaBoundaryModeTrap);
将值data
写入到由一维分层表面对象surfObj
指定的CUDA array中,写入的位置由字节坐标x
和层索引layer
指定。
3.1.9.surf2DLayeredread()
1
2
3
4
5
6
7
8
9
10
template<class T>
T surf2DLayeredread(
cudaSurfaceObject_t surfObj,
int x, int y, int layer,
boundaryMode = cudaBoundaryModeTrap);
template<class T>
void surf2DLayeredread(T data,
cudaSurfaceObject_t surfObj,
int x, int y, int layer,
boundaryMode = cudaBoundaryModeTrap);
从二维分层表面对象surfObj
指定的CUDA array中,使用字节坐标x
、y
和层索引layer
读取数据。
3.1.10.surf2DLayeredwrite()
1
2
3
4
5
template<class T>
void surf2DLayeredwrite(T data,
cudaSurfaceObject_t surfObj,
int x, int y, int layer,
boundaryMode = cudaBoundaryModeTrap);
将值data
写入到由二维分层表面对象surfObj
指定的CUDA array中,写入的位置由字节坐标x
、y
和层索引layer
指定。
3.1.11.surfCubemapread()
1
2
3
4
5
6
7
8
9
10
template<class T>
T surfCubemapread(
cudaSurfaceObject_t surfObj,
int x, int y, int face,
boundaryMode = cudaBoundaryModeTrap);
template<class T>
void surfCubemapread(T data,
cudaSurfaceObject_t surfObj,
int x, int y, int face,
boundaryMode = cudaBoundaryModeTrap);
从cubemap表面对象surfObj
指定的CUDA array中,使用字节坐标x
、y
和面索引face
读取数据。
3.1.12.surfCubemapwrite()
1
2
3
4
5
template<class T>
void surfCubemapwrite(T data,
cudaSurfaceObject_t surfObj,
int x, int y, int face,
boundaryMode = cudaBoundaryModeTrap);
将值data
写入到由cubemap表面对象surfObj
指定的CUDA array中,写入的位置由字节坐标x
、y
和面索引face
指定。
3.1.13.surfCubemapLayeredread()
1
2
3
4
5
6
7
8
9
10
template<class T>
T surfCubemapLayeredread(
cudaSurfaceObject_t surfObj,
int x, int y, int layerFace,
boundaryMode = cudaBoundaryModeTrap);
template<class T>
void surfCubemapLayeredread(T data,
cudaSurfaceObject_t surfObj,
int x, int y, int layerFace,
boundaryMode = cudaBoundaryModeTrap);
从cubemap分层表面对象surfObj
指定的CUDA array中,使用字节坐标x
、y
和索引layerFace
读取数据。
3.1.14.surfCubemapLayeredwrite()
1
2
3
4
5
template<class T>
void surfCubemapLayeredwrite(T data,
cudaSurfaceObject_t surfObj,
int x, int y, int layerFace,
boundaryMode = cudaBoundaryModeTrap);
将值data
写入到由cubemap分层表面对象surfObj
指定的CUDA array中,写入的位置由字节坐标x
、y
和索引layerFace
指定。
4.Read-Only Data Cache Load Function
只读数据缓存加载函数(read-only data cache load function)仅支持计算能力为5.0及以上的device。
1
T __ldg(const T* address);
__ldg()
用于将全局内存中的数据放到只读数据缓存中,从而提高后续访问速度。适用于kernel中频繁读取、不会被修改的数据。
类型T
可以是:
char
、signed char
、short
、int
、long
、long long
、unsigned char
、unsigned short
、unsigned int
、unsigned long
、unsigned long long
。char2
、char4
、short2
、short4
、int2
、int4
、longlong2
、uchar2
、uchar4
、ushort2
、ushort4
、uint2
、uint4
、ulonglong2
。float
、float2
、float4
、double
、double2
。- 如果包含了
cuda_fp16.h
头文件,类型T
还可以是__half
或__half2
。 - 如果包含了
cuda_bf16.h
头文件,类型T
还可以是__nv_bfloat16
或__nv_bfloat162
。