0_Simple__simpleTexture + 0_Simple__simpleTextureDrv
使用纹理引用来旋转图片,并在使用了静态编译和运行时编译两种环境。
▶ 源代码:静态编译
#include <stdio.h>
#include <windows.h>
#include <cuda_runtime.h>
#include "device_launch_parameters.h"
#include <helper_functions.h>
#include <helper_cuda.h> #define MAX_EPSILON_ERROR 5e-3f
const float angle = 0.5f;
texture<float, , cudaReadModeElementType> tex; __global__ void transformKernel(float *outputData, int width, int height, float theta)
{
unsigned int x = blockIdx.x*blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y*blockDim.y + threadIdx.y;
float u = x / (float)width - 0.5f;
float v = y / (float)height - 0.5f; outputData[y*width + x] = tex2D(tex, u * cosf(theta) - v * sinf(theta) + 0.5f, v * cosf(theta) + u * sinf(theta) + 0.5f);
} int main()
{
printf("\n\tStart.\n"); // 读取图片数据
float *h_data = NULL, *h_dataRef = NULL;
unsigned int width, height, size;
sdkLoadPGM("D:\\Code\\CUDA\\cudaProjectTemp\\data\\lena_bw.pgm", &h_data, &width, &height);// 删掉了用函数 sdkFindFilePath() 查找输入文件的过程
size = width * height * sizeof(float);
sdkLoadPGM("D:\\Code\\CUDA\\cudaProjectTemp\\data\\ref_rotated.pgm", &h_dataRef, &width, &height);
printf("\n\tLoad input files, %d x %d pixels\n", width, height); // 申请设备内存
float *d_data = NULL;
cudaMalloc((void **)&d_data, size);
cudaArray *cuArray;
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(, , , , cudaChannelFormatKindFloat);
cudaMallocArray(&cuArray, &channelDesc, width, height);
cudaMemcpyToArray(cuArray, , , h_data, size, cudaMemcpyHostToDevice);// 与 simpleSurfaceWrite 中不同,直接拷贝进 cuArray // 绑定纹理引用
tex.addressMode[] = cudaAddressModeWrap;
tex.addressMode[] = cudaAddressModeWrap;
tex.filterMode = cudaFilterModeLinear;
tex.normalized = true;
cudaBindTextureToArray(tex, cuArray, channelDesc); // 预跑
dim3 dimBlock(, , );
dim3 dimGrid(width / dimBlock.x, height / dimBlock.y, );
transformKernel << <dimGrid, dimBlock, >> >(d_data, width, height, angle);
cudaDeviceSynchronize(); StopWatchInterface *timer = NULL;
sdkCreateTimer(&timer);
sdkStartTimer(&timer); transformKernel << <dimGrid, dimBlock, >> >(d_data, width, height, angle);
cudaDeviceSynchronize(); sdkStopTimer(&timer);
printf("\n\tCost time: %f ms, %.2f Mpixels/sec\n", sdkGetTimerValue(&timer), (width *height / (sdkGetTimerValue(&timer) / 1000.0f)) / 1e6);
sdkDeleteTimer(&timer); // 结果回收、输出和检验
cudaMemcpy(h_data, d_data, size, cudaMemcpyDeviceToHost);
sdkSavePGM("D:\\Code\\CUDA\\cudaProjectTemp\\data\\output.pgm", h_data, width, height);
printf("\n\tSave output file.\n");
printf("\n\tFinish, return %s.\n", compareData(h_data, h_dataRef, width * height, MAX_EPSILON_ERROR, 0.0f) ? "Passed" : "Failed"); cudaFree(d_data);
cudaFreeArray(cuArray);
getchar();
return ;
}
▶ 输出结果
Start. Load input files, x pixels Cost time: 0.362788 ms, 722.58 Mpixels/sec Save output file. Finish, return Passed.
▶ 源代码:运行时编译
// simpleTexture_kernel.cu
#ifndef _SIMPLETEXTURE_KERNEL_H_
#define _SIMPLETEXTURE_KERNEL_H_ texture<float, , cudaReadModeElementType> tex; extern "C" __global__ void transformKernel(float *g_odata, int width, int height, float theta)
{
unsigned int x = blockIdx.x*blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y*blockDim.y + threadIdx.y;
float u = x / (float)width - 0.5f;
float v = y / (float)height - 0.5f; g_odata[y*width + x] = tex2D(tex, u * cosf(theta) - v * sinf(theta) + 0.5f, v * cosf(theta) + u * sinf(theta) + 0.5f);
} #endif
// simpleTextureDrv.cpp
#include <stdio.h>
#include <iostream>
#include <helper_functions.h>
#include <cuda.h> #define MAX_EPSILON_ERROR 5e-3f
#define PATH "D:\\Program\\CUDA9.0\\Samples\\0_Simple\\simpleTextureDrv\\data\\"
using namespace std;
float angle = 0.5f;
CUmodule cuModule;
CUcontext cuContext; CUfunction initCUDA()
{
CUfunction cuFunction = ;
string module_path, ptx_source;
cuInit(); // 初始化设备,类似于 runtime 中的函数 cudaSetDevice()
cuCtxCreate(&cuContext, , ); // 创建上下文,后两个参数分别是标志参数和设备号 // 读取 .ptx 文件
module_path = PATH"simpleTexture_kernel64.ptx";
FILE *fp = fopen(module_path.c_str(), "rb");
fseek(fp, , SEEK_END);
int file_size = ftell(fp);
char *buf = new char[file_size + ];
fseek(fp, , SEEK_SET);
fread(buf, sizeof(char), file_size, fp);
fclose(fp);
buf[file_size] = '\0';
ptx_source = buf;
delete[] buf; if (module_path.rfind("ptx") != string::npos)// 使用的是.ptx,需要运行时编译
{
// 设定编译参数,CUjit_option 放置参数名,jitOptVals 放置参数值
const unsigned int jitNumOptions = ;
CUjit_option *jitOptions = new CUjit_option[jitNumOptions];
void **jitOptVals = new void *[jitNumOptions]; // 编译日志长度
jitOptions[] = CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES;
int jitLogBufferSize = ;
jitOptVals[] = (void *)(size_t)jitLogBufferSize; // 编译日志内容
jitOptions[] = CU_JIT_INFO_LOG_BUFFER;
char *jitLogBuffer = new char[jitLogBufferSize];
jitOptVals[] = jitLogBuffer; // 设定一个内核使用的寄存器数量
jitOptions[] = CU_JIT_MAX_REGISTERS;
int jitRegCount = ;
jitOptVals[] = (void *)(size_t)jitRegCount; // 编译模块
cuModuleLoadDataEx(&cuModule, ptx_source.c_str(), jitNumOptions, jitOptions, (void **)jitOptVals);
//printf("\n\tPTX JIT log:\n%s\n", jitLogBuffer);// 输出编译日志
}
else// 使用的是 .cubin,不用编译(本例中不经过这个分支)
cuModuleLoad(&cuModule, module_path.c_str()); // 取出编译好的模块中的函数
cuModuleGetFunction(&cuFunction, cuModule, "transformKernel");
return cuFunction;// 删掉了错误检查,如果中间某一步出错,则应该先销毁上下文再退出
} int main()
{
printf("\n\tStart.\n"); // 初始化设备,编译 PTX
CUfunction transform = initCUDA(); // 读取图片数据
float *h_data = NULL, *h_dataRef = NULL;
unsigned int width, height, size;
sdkLoadPGM(PATH"lena_bw.pgm", &h_data, &width, &height);// 删掉了用函数 sdkFindFilePath() 查找输入文件的过程
size = width * height * sizeof(float);
sdkLoadPGM(PATH"ref_rotated.pgm", &h_dataRef, &width, &height);
printf("\n\tLoad input files, %d x %d pixels\n", width, height); // 申请设备内存
CUdeviceptr d_data = (CUdeviceptr)NULL;
cuMemAlloc(&d_data, size);
CUarray cu_array;
CUDA_ARRAY_DESCRIPTOR desc;
desc.Format = CU_AD_FORMAT_FLOAT;
desc.NumChannels = ;
desc.Width = width;
desc.Height = height;
cuArrayCreate(&cu_array, &desc);
CUDA_MEMCPY2D copyParam;
memset(©Param, , sizeof(copyParam));
copyParam.dstMemoryType = CU_MEMORYTYPE_ARRAY;
copyParam.dstArray = cu_array;
copyParam.srcMemoryType = CU_MEMORYTYPE_HOST;
copyParam.srcHost = h_data;
copyParam.srcPitch = width * sizeof(float);
copyParam.WidthInBytes = copyParam.srcPitch;
copyParam.Height = height;
cuMemcpy2D(©Param); // 绑定纹理引用
CUtexref cu_texref;
cuModuleGetTexRef(&cu_texref, cuModule, "tex");
cuTexRefSetArray(cu_texref, cu_array, CU_TRSA_OVERRIDE_FORMAT);
cuTexRefSetAddressMode(cu_texref, , CU_TR_ADDRESS_MODE_WRAP);
cuTexRefSetAddressMode(cu_texref, , CU_TR_ADDRESS_MODE_WRAP);
cuTexRefSetFilterMode(cu_texref, CU_TR_FILTER_MODE_LINEAR);
cuTexRefSetFlags(cu_texref, CU_TRSF_NORMALIZED_COORDINATES);
cuTexRefSetFormat(cu_texref, CU_AD_FORMAT_FLOAT, );
cuParamSetTexRef(transform, CU_PARAM_TR_DEFAULT, cu_texref); int block_size = ;
StopWatchInterface *timer = NULL; // 两种调用 Driver API 的方式
if ()
{
void *args[] = {&d_data, &width, &height, &angle};
// 预跑
cuLaunchKernel(transform, (width / block_size), (height / block_size), , block_size, block_size, , , NULL, args, NULL);
cuCtxSynchronize();
// 再跑一次测试性能
sdkCreateTimer(&timer);
sdkStartTimer(&timer);
cuLaunchKernel(transform, (width / block_size), (height / block_size), , block_size, block_size, , , NULL, args, NULL);
}
else
{
int offset = ;
char argBuffer[];
// 在一个 CUdeviceptr(unsigned long long)长度的空间里写入调用参数
*((CUdeviceptr *)&argBuffer[offset]) = d_data;
offset += sizeof(d_data);
*((unsigned int *)&argBuffer[offset]) = width;
offset += sizeof(width);
*((unsigned int *)&argBuffer[offset]) = height;
offset += sizeof(height);
*((float *)&argBuffer[offset]) = angle;
offset += sizeof(angle);
void *kernel_launch_config[] = {CU_LAUNCH_PARAM_BUFFER_POINTER, argBuffer, CU_LAUNCH_PARAM_BUFFER_SIZE, &offset, CU_LAUNCH_PARAM_END };
// 预跑
cuLaunchKernel(transform, (width / block_size), (height / block_size), ,block_size, block_size, ,,NULL, NULL, (void **)&kernel_launch_config);
cuCtxSynchronize();
// 再跑一次测试性能
sdkCreateTimer(&timer);
sdkStartTimer(&timer);
cuLaunchKernel(transform, (width / block_size), (height / block_size), ,block_size, block_size, ,, ,NULL, (void **)&kernel_launch_config);
}
cuCtxSynchronize();
sdkStopTimer(&timer);
printf("\n\tCost time: %f ms, %.2f Mpixels/sec\n", sdkGetTimerValue(&timer), (width *height / (sdkGetTimerValue(&timer) / 1000.0f)) / 1e6);
sdkDeleteTimer(&timer); // 结果回收、输出和检验
cuMemcpyDtoH(h_data, d_data, size);
sdkSavePGM("D:\\Code\\CUDA\\cudaProjectTemp\\data\\output.pgm", h_data, width, height);
printf("\n\tSave output file.\n");
printf("\n\tFinish, return %s.\n", compareData(h_data, h_dataRef, width * height, MAX_EPSILON_ERROR, 0.15f) ? "Passed" : "Failed"); cuMemFree(d_data);
cuArrayDestroy(cu_array);
cuCtxDestroy(cuContext);
getchar();
return ;
}
▶ 输出结果:
Start. Load input files, x pixels Cost time: 0.355230 ms, 737.96 Mpixels/sec Save output file. Finish, return Passed.
▶ 涨姿势
● 一般,与 0_Simple__simpleSurfaceWrite 类似。
0_Simple__simpleTexture + 0_Simple__simpleTextureDrv的更多相关文章
随机推荐
- list.stream().parallel() 并行流
https://blog.csdn.net/u011001723/article/details/52794455/ : parallel()其实就是一个并行执行的流.它通过默认的ForkJoin ...
- hello1与hello2在glassfish上部署
部署hello1 打开项目实例 找到hello1(tutorial-examples-master\web\jsf\hello1) 并在当前目录打开cmd并输入mvn install命令在hello1 ...
- 【Quartz】Quartz将Job保存在数据库中所需表的说明
QRTZ_CALENDARS 以 Blob 类型存储 Quartz 的 Calendar 信息 QRTZ_CRON_TRIGGERS 存储 Cron Trigger,包括 Cron表达式和时区信息 ...
- python 取整
1.向下取整 向下取整直接用内建的 int() 函数即可: >>> a = 3.75 >>> int(a) 3 2.四舍五入 对数字进行四舍五入用 round() ...
- Linux配置NTP服务器,时间同步
当服务器多了,时间准确与否,一致与否是个大问题.虽然这个问题总是被忽略,但是统一一致的时间是很有必要的.下面说一下在局域网内配置Linux时间服务器的方法. 配置的环境及要求: 假设在192.168. ...
- RAC3——RAC原理开始
1.RAC并发 RAC的本质是一个数据库,只不过现在这个数据库运行在了多台计算机上,在原先的单实例中,一个进程是否可以修改一条数据,取决于是否有其他进程(同一台计算机上)并发修改.在RAC环境下,这种 ...
- 【ActiveMQ入门-10】ActiveMQ学习-通配符+异步接收
通配符介绍: 一般情况下,我们使用层次结构的方式来组织队列,比如A.B.C.D,这样便于归类和管理. 我们也可以使用通配符来配置或是操作多个队列. 通配符有三个: . 用来分隔路径: * 用来匹 ...
- 一款easyUI写的界面例子,小记
后台是用strut2的: 前台界面风格easyUI,感觉挺好用的: <!DOCTYPE html> <html> <head> <meta charset=& ...
- C++ 什么叫做离散化
C++ 什么叫做离散化 如果说今年这时候OIBH问得最多的问题是二分图,那么去年这时候问得最多的算是离散化了.对于“什么是离散化”,搜索帖子你会发现有各种说法,比如“排序后处理”.“对坐标的近似处理” ...
- requests-1快速学习
请直接转身官网http://docs.python-requests.org/zh_CN/latest/user/quickstart.html#url](http://docs.python-req ...