我是C,C++和OpenCL的新手,现在正尽力学习它们.这是一个预先存在的C++函数,我试图弄清楚如何使用C或C++绑定移植到OpenCL.
#include <vector>
using namespace std;
class Test {
private:
double a;
vector<double> b;
vector<long> c;
vector<vector<double> > d;
public:
double foo(long x, double y) {
// mathematical operations
// using x, y, a, b, c, d
// and also b.size()
// to calculate return value
return 0.0;
}
};
Run Code Online (Sandbox Code Playgroud)
从广义上讲,我的问题是如何将此函数访问的所有类成员传递到绑定和内核中.我理解如何传递标量值但是我不确定的矢量值.是否有一种方法可以将指针传递给上述每个成员或内存映射它们,以便OpenCL的视图与主机内存同步?细分我的问题如下.
我非常感谢答案中的C或C++绑定和内核代码示例源代码.
非常感谢.
rei*_*ima 13
您必须分配OpenCL缓冲区并将CPU数据复制到其中.OpenCL缓冲区具有固定大小,因此如果数据大小发生更改或者使其"足够大",则必须重新创建它,如果需要更少的内存,则只使用它的子部分.例如,要为其创建缓冲区b
并同时将其所有数据复制到设备:
cl_mem buffer_b = clCreateBuffer(
context, // OpenCL context
CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, // Only read access from kernel,
// copy data from host
sizeof(cl_double) * b.size(), // Buffer size in bytes
&b[0], // Pointer to data to copy
&errorcode); // Return code
Run Code Online (Sandbox Code Playgroud)
也可以直接映射主机内存(CL_MEM_USE_HOST_PTR
),但这会在创建缓冲区后对对齐和对主机内存的访问施加一些限制.基本上,当您没有映射它时,主机内存可能包含垃圾.
这取决于.第二维中矢量的大小是否一致?然后在将它们上传到OpenCL设备时将它们展平.否则会变得更复杂.
您将缓冲区参数声明为__global
内核中的指针.例如,对于__global double *b
在1中创建的缓冲区是合适的.您可以在内核中使用数组表示法来访问缓冲区中的各个元素.
您无法从内核中查询缓冲区大小,因此必须手动传递它.这也可以隐式发生,例如,如果工作项的数量与大小相匹配b
.
可以访问计算所有数据的内核可能如下所示:
__kernel void foo(long x, double y, double a, __global double* b, int b_size,
__global long* c, __global double* d,
__global double* result) {
// Here be dragons
*result = 0.0;
}
Run Code Online (Sandbox Code Playgroud)
请注意,您还必须为结果分配内存.如果需要,可能需要传递额外的大小参数.您可以按如下方式调用内核:
// Create/fill buffers
// ...
// Set arguments
clSetKernelArg(kernel, 0, sizeof(cl_long), &x);
clSetKernelArg(kernel, 1, sizeof(cl_double), &y);
clSetKernelArg(kernel, 2, sizeof(cl_double), &a);
clSetKernelArg(kernel, 3, sizeof(cl_mem), &b_buffer);
cl_int b_size = b.size();
clSetKernelArg(kernel, 4, sizeof(cl_int), &b_size);
clSetKernelArg(kernel, 5, sizeof(cl_mem), &c_buffer);
clSetKernelArg(kernel, 6, sizeof(cl_mem), &d_buffer);
clSetKernelArg(kernel, 7, sizeof(cl_mem), &result_buffer);
// Enqueue kernel
clEnqueueNDRangeKernel(queue, kernel, /* ... depends on your domain */);
// Read back result
cl_double result;
clEnqueueReadBuffer(queue, result_buffer, CL_TRUE, 0, sizeof(cl_double), &result,
0, NULL, NULL);
Run Code Online (Sandbox Code Playgroud)