AMD OpenCL大学课程(3)
OpenCL内存对象:
OpenCL内存对象就是一些OpenCL数据,这些数据一般在设备内存中,能够被拷入也能够被拷出。OpenCL内存对象包括buffer对象和image对象。
buffer对象:连续的内存块----顺序存储,能够通过指针、行列式等直接访问。
image对象:是2维或3维的内存对象,只能通过read_image() 或 write_image()来读取。image对象可以是可读或可写的,但不能同时既可读又可写。
该函数会在指定的context上创建一个buffer对象,image对象相对比较复杂,留在后面再讲。
flags参数指定buffer对象的读写属性,host_ptr可以是NULL,如果不为NULL,一般是一个有效的host buffer对象,这时,函数创建OpenCL buffer对象后,会把对应host buffer的内容拷贝到OpenCL buffer中。
在Kernel执行之前,host中原始输入数据必须显式的传到device中,Kernel执行完后,结果也要从device内存中传回到host内存中。我们主要通过函数clEnqueue{Read|Write}{Buffer|Image}来实现这两种操作。从host到device,我们用clEnqueueWrite,从device到host,我们用clEnqueueRead。clEnqueueWrite命令包括初始化内存对象以及把host 数据传到device内存这两种操作。当然,像前面一段说的那样,也可以把host buffer指针直接用在CreateBuffer函数中来实现隐式的数据写操作。
这个函数初始化OpenCL内存对象,并把相应的数据写到OpenCL内存关联的设备内存中。其中,blocking_write参数指定是数拷贝完成后函数才返回还是数据开始拷贝后就立即返回(阻塞模式于非阻塞模式)。Events参数指定这个函数执行之前,必须要完成的Event(比如先要创建OpenCL内存对象的Event)。
OpenCL程序对象:
程序对象就是通过读入Kernel函数源代码或二进制文件,然后在指定的设备上进行编译而产生的OpenCL对象。
这个函数通过源代码(strings),创建一个程序对象,其中counts指定源代码串的数量,lengths指定源代码串的长度(为NULL结束的串时,可以省略)。当然,我们还必须自己编写一个从文件中读取源代码串的函数。
对context中的每个设备,这个函数编译、连接源代码对象,产生device可以执行的文件,对GPU而言就是设备对应shader汇编。如果device_list参数被提供,则只对这些设备进行编译连接。options参数主要提供一些附加的编译选项,比如宏定义、优化开关标志等等。
如果程序编译失败,我们能够根据返回的状态,通过调用clGetProgramBuildInfo来得到错误信息。
加上创建内存对象以及程序对象的代码如下:
1:
2: #include "stdafx.h"
3: #include <CL/cl.h>
4: #include <stdio.h>
5: #include <stdlib.h>
6: #include <time.h>
7: #include <iostream>
8: #include <fstream>
9:
10: using namespace std;
11: #define NWITEMS 262144
12:
13: #pragma comment (lib,"OpenCL.lib")
14:
15: //把文本文件读入一个string中
16: int convertToString(const char *filename, std::string& s)
17: {
18: size_t size;
19: char* str;
20:
21: std::fstream f(filename, (std::fstream::in | std::fstream::binary));
22:
23: if(f.is_open())
24: {
25: size_t fileSize;
26: f.seekg(0, std::fstream::end);
27: size = fileSize = (size_t)f.tellg();
28: f.seekg(0, std::fstream::beg);
29:
30: str = new char[size+1];
31: if(!str)
32: {
33: f.close();
34: return NULL;
35: }
36:
37: f.read(str, fileSize);
38: f.close();
39: str[size] = '\0';
40:
41: s = str;
42: delete[] str;
43: return 0;
44: }
45: printf("Error: Failed to open file %s\n", filename);
46: return 1;
47: }
48:
49: int main(int argc, char* argv[])
50: {
51: //在host内存中创建三个缓冲区
52: float *buf1 = 0;
53: float *buf2 = 0;
54: float *buf = 0;
55:
56: buf1 =(float *)malloc(NWITEMS * sizeof(float));
57: buf2 =(float *)malloc(NWITEMS * sizeof(float));
58: buf =(float *)malloc(NWITEMS * sizeof(float));
59:
60: //初始化buf1和buf2的内容
61: int i;
62: srand( (unsigned)time( NULL ) );
63: for(i = 0; i < NWITEMS; i++)
64: buf1[i] = rand()%65535;
65:
66: srand( (unsigned)time( NULL ) +1000);
67: for(i = 0; i < NWITEMS; i++)
68: buf2[i] = rand()%65535;
69:
70: cl_uint status;
71: cl_platform_id platform;
72:
73: //创建平台对象
74: status = clGetPlatformIDs( 1, &platform, NULL );
75:
76: cl_device_id device;
77:
78: //创建GPU设备
79: clGetDeviceIDs( platform, CL_DEVICE_TYPE_GPU,
80: 1,
81: &device,
82: NULL);
83: //创建context
84: cl_context context = clCreateContext( NULL,
85: 1,
86: &device,
87: NULL, NULL, NULL);
88: //创建命令队列
89: cl_command_queue queue = clCreateCommandQueue( context,
90: device,
91: CL_QUEUE_PROFILING_ENABLE, NULL );
92: //创建三个OpenCL内存对象,并把buf1的内容通过隐式拷贝的方式
93: //拷贝到clbuf1,buf2的内容通过显示拷贝的方式拷贝到clbuf2
94: cl_mem clbuf1 = clCreateBuffer(context,
95: CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
96: NWITEMS*sizeof(cl_float),buf1,
97: NULL );
98:
99: cl_mem clbuf2 = clCreateBuffer(context,
100: CL_MEM_READ_ONLY ,
101: NWITEMS*sizeof(cl_float),NULL,
102: NULL );
103:
104: status = clEnqueueWriteBuffer(queue, clbuf2, 1,
105: 0, NWITEMS*sizeof(cl_float), buf2, 0, 0, 0);
106:
107: cl_mem buffer = clCreateBuffer( context,
108: CL_MEM_WRITE_ONLY,
109: NWITEMS * sizeof(cl_float),
110: NULL, NULL );
111:
112: const char * filename = "add.cl";
113: std::string sourceStr;
114: status = convertToString(filename, sourceStr);
115: const char * source = sourceStr.c_str();
116: size_t sourceSize[] = { strlen(source) };
117:
118: //创建程序对象
119: cl_program program = clCreateProgramWithSource(
120: context,
121: 1,
122: &source,
123: sourceSize,
124: NULL);
125: //编译程序对象
126: status = clBuildProgram( program, 1, &device, NULL, NULL, NULL );
127: if(status != 0)
128: {
129: printf("clBuild failed:%d\n", status);
130: char tbuf[0x10000];
131: clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0x10000, tbuf, NULL);
132: printf("\n%s\n", tbuf);
133: return -1;
134: }
135:
136:
137:
138: if(buf)
139: free(buf);
140: if(buf1)
141: free(buf1);
142: if(buf2)
143: free(buf2);
144:
145: //删除OpenCL资源对象
146: clReleaseMemObject(clbuf1);
147: clReleaseMemObject(clbuf2);
148: clReleaseMemObject(buffer);
149: clReleaseProgram(program);
150: clReleaseCommandQueue(queue);
151: clReleaseContext(context);
152: return 0;
153: }
154: