▶ 表面内存使用

● 创建 cuda 数组时使用标志 cudaArraySurfaceLoadStore 来创建表面内存,可以用表面对象(surface object)或表面引用(surface reference)来对其进行读写。

● 使用 Surface Object API

■ 涉及的结构定义、接口函数。

 // vector_types.h
struct __device_builtin__ __align__() uchar4
{
unsigned char x, y, z, w;
}; // surface_types.h
typedef __device_builtin__ unsigned long long cudaSurfaceObject_t;

■ 完整的测试代码,使用表面内存进行简单的读写。

 #include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <cuda_runtime_api.h>
#include "device_launch_parameters.h" #define CEIL(x,y) (((x) + (y) - 1) / (y) + 1) __global__ void myKernel(cudaSurfaceObject_t inputSurfObj, cudaSurfaceObject_t outputSurfObj, int width, int height)
{
unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y;
if (idx < width && idy < height)
{
uchar4 data;
// 简单的表面内存读写,使用了字节地址,而不是简单的线程编号
surf2Dread(&data, inputSurfObj, sizeof(float) * idx, idy);
surf2Dwrite(data, outputSurfObj, sizeof(float) * idx, idy);
}
cudaBindSurfaceToArray();
} int main()
{
// 基本数据
int i;
float *h_data, *d_data;
int width = ;
int height = ; int size = sizeof(float)*width*height;
h_data = (float *)malloc(size);
cudaMalloc((void **)&d_data, size); for (i = ; i < width*height; i++)
h_data[i] = (float)i; printf("\n\n");
for (i = ; i < width*height; i++)
{
printf("%6.1f ", h_data[i]);
if ((i + ) % width == )
printf("\n");
} // 申请 cuda 数组
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(, , , , cudaChannelFormatKindUnsigned);
cudaArray* cuInputArray;
cudaMallocArray(&cuInputArray, &channelDesc, width, height, cudaArraySurfaceLoadStore);
cudaArray* cuOutputArray;
cudaMallocArray(&cuOutputArray, &channelDesc, width, height, cudaArraySurfaceLoadStore);
cudaMemcpyToArray(cuInputArray, , , h_data, size,cudaMemcpyHostToDevice); // 指定表面内存
struct cudaResourceDesc resDesc;
memset(&resDesc, , sizeof(resDesc));
resDesc.resType = cudaResourceTypeArray; // 创建表面对象
resDesc.res.array.array = cuInputArray;
cudaSurfaceObject_t inputSurfObj = ;
cudaCreateSurfaceObject(&inputSurfObj, &resDesc);
resDesc.res.array.array = cuOutputArray;
cudaSurfaceObject_t outputSurfObj = ;
cudaCreateSurfaceObject(&outputSurfObj, &resDesc); // 运行核函数
dim3 dimBlock(, );
dim3 dimGrid(CEIL(width, dimBlock.x), CEIL(height, dimBlock.y));
myKernel << <dimGrid, dimBlock >> > (inputSurfObj, outputSurfObj, width, height); // 结果回收和检查结果
memset(h_data,,size);// 刷掉原来的 h_data,再用 cuOutputArray 的数据写入
cudaMemcpyFromArray(h_data, cuOutputArray, , , size, cudaMemcpyDeviceToHost); printf("\n\n");
for (i = ; i < width*height; i++)
{
printf("%6.1f ", h_data[i]);
if ((i + ) % width == )
printf("\n");
} // 回收工作
cudaDestroySurfaceObject(inputSurfObj);
cudaDestroySurfaceObject(outputSurfObj);
cudaFreeArray(cuInputArray);
cudaFreeArray(cuOutputArray); getchar();
return ;
}

● 使用 Surface Reference API。

■ 表面引用的一些只读属性需要在声明的时候指定,以便编译时提前确定,只能在全局作用域内静态指定,不能作为参数传递给函数。使用 surface 指定纹理引用属性,Datatype 为数据类型,Type 为纹理引用类型,有 7 种,默认 cudaSurfaceType1D。

 surface<void, Type> surfRef;

 // cuda_texture_types.h
template<class T, int dim = >
struct __device_builtin_surface_type__ surface : public surfaceReference
{
#if !defined(__CUDACC_RTC__)
__host__ surface(void)
{
channelDesc = cudaCreateChannelDesc<T>();
} __host__ surface(struct cudaChannelFormatDesc desc)
{
channelDesc = desc;
}
#endif /* !__CUDACC_RTC__ */
}; //surface_types.h
#define cudaSurfaceType1D 0x01
#define cudaSurfaceType2D 0x02
#define cudaSurfaceType3D 0x03
#define cudaSurfaceTypeCubemap 0x0C
#define cudaSurfaceType1DLayered 0xF1
#define cudaSurfaceType2DLayered 0xF2
#define cudaSurfaceTypeCubemapLayered 0xFC // 访问边界模式
enum __device_builtin__ cudaSurfaceBoundaryMode
{
cudaBoundaryModeZero = , // 0 边界模式
cudaBoundaryModeClamp = , // 挤压模式
cudaBoundaryModeTrap = // 陷阱模式
}; // ?表面格式模式
enum __device_builtin__ cudaSurfaceFormatMode
{
cudaFormatModeForced = , // 强制模式
cudaFormatModeAuto = // 自动模式
}; // 表面引用的通道描述
struct __device_builtin__ surfaceReference
{
struct cudaChannelFormatDesc channelDesc;
}; // cuda_runtime_api.h
extern __host__ cudaError_t CUDARTAPI cudaBindSurfaceToArray(const struct surfaceReference *surfref, cudaArray_const_t array, const struct cudaChannelFormatDesc *desc);

■ 表面引用使用字节地址来定位访问(而不是像纹理那样使用 fetch 函数),如以上代码中 surf1Dread(surfRef, sizeof(float) * idx) 或是 surf1Dread(surfRef, sizeof(float) * idx) 。

■ 表面引用必须用函数 cudaBindSurfaceToArray() 绑定到 cuda 数组上才能使用,要求表面引用的维度、数据类型与该数组匹配,否则操作时未定义的,使用完后不需要特殊函数来解除绑定。

■ 将表面引用绑定到 cuda 数组上的范例代码。

 // 准备工作
surface<void, Type>surfRef; ... int width, height;
size_t pitch;
float *d_data;
cudaMallocPitch((void **)&d_data, &pitch, sizeof(float)*width, height); // 第一种方法,低层 API
surfaceReference* surfRefPtr;
cudaGetSurfaceReference(&surfRefPtr, "surfRef");
cudaChannelFormatDesc channelDesc;
cudaGetChannelDesc(&channelDesc, cuArray);
cudaBindSurfaceToArray(surfRef, cuArray, &channelDesc); // 第二种方法,高层 API
cudaBindSurfaceToArray(surfRef, cuArray);

■ 完整的应用样例代码。与前面表面对象代码的功能相同。

 #include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <cuda_runtime_api.h>
#include "device_launch_parameters.h" #define CEIL(x,y) (((x) + (y) - 1) / (y) + 1) // 声明表面引用
surface<void, > inputSurfRef;
surface<void, > outputSurfRef; __global__ void myKernel(int width, int height)
{
unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y;
if (idx < width && idy < height)
{
uchar4 data;
// 简单的表面内存读写,使用了字节地址,而不是简单的线程编号
surf2Dread(&data, inputSurfRef, sizeof(float) * idx, idy);
surf2Dwrite(data, outputSurfRef, sizeof(float) * idx, idy);
}
} int main()
{
// 基本数据
int i;
float *h_data, *d_data;
int width = ;
int height = ; int size = sizeof(float)*width*height;
h_data = (float *)malloc(size);
cudaMalloc((void **)&d_data, size); for (i = ; i < width*height; i++)
h_data[i] = (float)i; printf("\n\n");
for (i = ; i < width*height; i++)
{
printf("%6.1f ", h_data[i]);
if ((i + ) % width == )
printf("\n");
} // 申请 cuda 数组
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(, , , , cudaChannelFormatKindUnsigned);
cudaArray* cuInputArray;
cudaMallocArray(&cuInputArray, &channelDesc, width, height, cudaArraySurfaceLoadStore);
cudaArray* cuOutputArray;
cudaMallocArray(&cuOutputArray, &channelDesc, width, height, cudaArraySurfaceLoadStore);
cudaMemcpyToArray(cuInputArray, , , h_data, size,cudaMemcpyHostToDevice); // 绑定表面引用,注意与表面对象的使用不一样
cudaBindSurfaceToArray(inputSurfRef, cuInputArray);
cudaBindSurfaceToArray(outputSurfRef, cuOutputArray); // 运行核函数
dim3 dimBlock(, );
dim3 dimGrid(CEIL(width, dimBlock.x), CEIL(height, dimBlock.y));
myKernel << <dimGrid, dimBlock >> > (width, height); // 结果回收和检查结果
memset(h_data,,size);// 刷掉原来的 h_data,再用 cuOutputArray 的数据写入
cudaMemcpyFromArray(h_data, cuOutputArray, , , size, cudaMemcpyDeviceToHost); printf("\n\n");
for (i = ; i < width*height; i++)
{
printf("%6.1f ", h_data[i]);
if ((i + ) % width == )
printf("\n");
} // 回收工作
cudaFreeArray(cuInputArray);
cudaFreeArray(cuOutputArray); getchar();
return ;
}

▶ 立方体表面 Cubemap Surface 。 (想象成一个正方体的外表面)

● 一种特殊的二维分层表面。函数 surfCubemapread() 和函数 surfCubemapwrite() 来对其进行读写,使用一个整数下标和两个浮点数有序组来定义层号和表面坐标。

▶ 分层立方体表面 Cubemap Layered Surfaces 。(想象成一个多层的正方体的各外表面)

● 一种特殊的二维分层表面。函数 surfCubemapread() 和函数 surfCubemapwrite() 来对齐进行读写。使用一个整数下标和两个浮点数有序组来定义层号和表面坐标。

● 分层立方体贴图纹理只能使用函数 cudaMAlloc3DArray() 加上 cudaArrayLayered 和 cudaArrayCubemap 标志来声明,使用函数 texCubemapLayered() 来进行访问滤波只在同一层内部进行,不会跨层执行。

▶ cuda 数组。

● cuda 优化的数组类型,可以有一维或二维或三维,每个元素可以有 1 个或 2 个或 4 个分量,各分量可以是 1 B 或 2 B 或 4 B 尺寸的有符号或无符号整数,或 2 B 或 4 B 尺寸的浮点数。cuda 数组只能用纹理访问函数来访问,或表面函数来进行读写。

● 纹理内存和表面内存都是可缓存的,且不能保证缓存和内存的一致性。同一个核函数中,用纹理访问或表面访问来读取“已经全局写入或表面写入的内存”是未定义的。

▶ 压缩版的 surface_types.h

 #if !defined(__SURFACE_TYPES_H__)
#define __SURFACE_TYPES_H__ #include "driver_types.h" #define cudaSurfaceType1D 0x01
#define cudaSurfaceType2D 0x02
#define cudaSurfaceType3D 0x03
#define cudaSurfaceTypeCubemap 0x0C
#define cudaSurfaceType1DLayered 0xF1
#define cudaSurfaceType2DLayered 0xF2
#define cudaSurfaceTypeCubemapLayered 0xFC //CUDA Surface boundary modes
enum __device_builtin__ cudaSurfaceBoundaryMode
{
cudaBoundaryModeZero = , // Zero boundary mode */
cudaBoundaryModeClamp = , // Clamp boundary mode */
cudaBoundaryModeTrap = // Trap boundary mode */
}; //CUDA Surface format modes
enum __device_builtin__ cudaSurfaceFormatMode
{
cudaFormatModeForced = , // Forced format mode */
cudaFormatModeAuto = // Auto format mode */
}; //CUDA Surface reference
struct __device_builtin__ surfaceReference
{
// Channel descriptor for surface reference
struct cudaChannelFormatDesc channelDesc;
}; //An opaque value that represents a CUDA Surface object
typedef __device_builtin__ unsigned long long cudaSurfaceObject_t; #endif

CUDA C Programming Guide 在线教程学习笔记 Part 3的更多相关文章

  1. CUDA C Programming Guide 在线教程学习笔记 Part 5

    附录 A,CUDA计算设备 附录 B,C语言扩展 ▶ 函数的标识符 ● __device__,__global__ 和 __host__ ● 宏 __CUDA_ARCH__ 可用于区分代码的运行位置. ...

  2. CUDA C Programming Guide 在线教程学习笔记 Part 4

    ▶ 图形互操作性,OpenGL 与 Direct3D 相关.(没学过,等待填坑) ▶ 版本号与计算能力 ● 计算能力(Compute Capability)表征了硬件规格,CUDA版本号表征了驱动接口 ...

  3. CUDA C Programming Guide 在线教程学习笔记 Part 2

    ▶ 纹理内存使用 ● 纹理内存使用有两套 API,称为 Object API 和 Reference API .纹理对象(texture object)在运行时被 Object API 创建,同时指定 ...

  4. CUDA C Programming Guide 在线教程学习笔记 Part 10【坑】

    ▶ 动态并行. ● 动态并行直接从 GPU 上创建工作,可以减少主机和设备间数据传输,在设备线程中调整配置.有数据依赖的并行工作可以在内核运行时生成,并利用 GPU 的硬件调度和负载均衡.动态并行要求 ...

  5. CUDA C Programming Guide 在线教程学习笔记 Part 13

    ▶ 纹理内存访问补充(见纹理内存博客 http://www.cnblogs.com/cuancuancuanhao/p/7809713.html) ▶ 计算能力 ● 不同计算能力的硬件对计算特性的支持 ...

  6. CUDA C Programming Guide 在线教程学习笔记 Part 9

    ▶ 协作组,要求 cuda ≥ 9.0,一个简单的例子见 http://www.cnblogs.com/cuancuancuanhao/p/7881093.html ● 灵活调节需要进行通讯的线程组合 ...

  7. CUDA C Programming Guide 在线教程学习笔记 Part 8

    ▶ 线程束表决函数(Warp Vote Functions) ● 用于同一线程束内各线程通信和计算规约指标. // device_functions.h,cc < 9.0 __DEVICE_FU ...

  8. CUDA C Programming Guide 在线教程学习笔记 Part 7

    ▶ 可缓存只读操作(Read-Only Data Cache Load Function),定义在 sm_32_intrinsics.hpp 中.从地址 adress 读取类型为 T 的函数返回,T ...

  9. CUDA C Programming Guide 在线教程学习笔记 Part 1

    1. 简介 2. 编程模型 ▶ SM version 指的是硬件构架和特性,CUDA version 指的是软件平台版本. 3. 编程接口.参考 http://chenrudan.github.io/ ...

随机推荐

  1. 51Nod:活动安排问题(区间问题)

    X轴上有N条线段,每条线段有1个起点S和终点E.最多能够选出多少条互不重叠的线段.(注:起点或终点重叠,不算重叠). 例如:[1 5][2 3][3 6],可以选[2 3][3 6],这2条线段互不重 ...

  2. 2018-2019-2 《网络对抗技术》Kali安装 Week1 20165212

    2018-2019-2 <网络对抗技术>Kali安装 Week1 20165212 1.完成安装linux kali和vm tools 装的第三遍成功安装.前面两次镜像文件不行,没驱动(网 ...

  3. 使用js 文件参数 以及IHttpModule实现服务验证asp.net 版的初步实现

    接上面的文章,上面的主要是进行html 页面自己进行处理.但是对于进行asp.net 的开发者以及其他的就显的不太好了. 我的实现方式是使用IHttpModule 进行对于用户请求的带有参数的js文件 ...

  4. A glance at C# vNext

    Contents Introduction Background A list of features Primary constructor Read only auto-properties St ...

  5. mysql常用的聚合函数

    GROUP BY(聚合)函数本章论述了用于一组数值操作的 group (集合)函数.除非另作说明, group 函数会忽略 NULL 值. 假如你在一个不包含 ROUP BY子句的语句中使用一个 gr ...

  6. http报头 Accept 与 Content-Type 的区别

    Accept属于请求头, Content-Type属于实体头. Http报头分为通用报头,请求报头,响应报头和实体报头. 请求方的http报头结构:通用报头|请求报头|实体报头 响应方的http报头结 ...

  7. loadrunner 函数解释

    一.lr_save_string 使用介绍1.该函数主要是将程序中的常量或变量保存为lr中的参数.格式: //将常量保存为参数lr_save_string("777"," ...

  8. 未能正确加载“VSTS for Database Professionals Sql Server Data-tier Application”包。(转)

    今天费了九牛二虎之力,重转好了vs2010之后,打开解决方案,报出下面的错误: ---------------------------Microsoft Visual Studio---------- ...

  9. Microsoft Dynamics CRM service 创建,更新等操作时,注意写抛出异常时,抛出SoapException异常

    具体如下: using System.Web.Services.Protocols; try{ crmService.Update(procurementPlanEntity);//更新操作}catc ...

  10. JAVA课程设计——多源教学数据管理系统

    团队简介 团队名称: 419圣斗士 团队成员 姓名 成员介绍 任务分配 周炳辉(组长) 来自网络的一个大佬,穿女装很合适 poi与servlet 徐宏伟 网络中一个具有强大隐藏实力的大哥 css,部分 ...