如何将C ++向量传递给OpenCL内核?

我是C,C ++和OpenCL的新手,现在正尽力学习它们。 这是一个预先存在的C ++函数,我试图找出如何使用C或C ++绑定移植到OpenCL。

#include  using namespace std; class Test { private: double a; vector b; vector c; vector<vector > 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; } }; 

从广义上讲,我的问题是如何将此函数访问的所有类成员传入绑定和内核。 我理解如何传递标量值,但我不确定矢量值。 是否有一种方法可以将指针传递给上述每个成员或内存映射它们,以便OpenCL的视图与主机内存同步? 细分我的问题如下。

  1. 如果这些是可变大小的,我如何将成员b和c传递给绑定和内核?
  2. 如果它是二维的,我如何传递成员?
  3. 如何从内核中访问这些成员,以及在内核的参数中将它们声明为什么类型? 将简单地使用数组索引表示法,即b [0]用于访问?
  4. 我如何在内核函数中调用等效于b.size()的操作,或者我不会将绑定中的大小作为额外参数传递给内核? 如果它改变会发生什么?

我非常感谢C或C ++绑定以及答案中的内核代码示例源代码。

非常感谢。

  1. 您必须分配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 

    也可以直接映射主机内存( CL_MEM_USE_HOST_PTR ),但这会在创建缓冲区后对对齐和对主机内存的访问施加一些限制。 基本上,当您没有映射它时,主机内存可能包含垃圾。

  2. 这取决于。 第二维中矢量的大小是否一致? 然后在将它们上传到OpenCL设备时将它们展平。 否则会变得更复杂。

  3. 您将缓冲区参数声明为内核中的__global指针。 例如, __global double *b适用于在1中创建的缓冲区。您可以在内核中使用数组表示法来访问缓冲区中的各个元素。

  4. 您无法从内核中查询缓冲区大小,因此必须手动传递它。 这也可以隐式发生,例如,如果工作项的数量与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; } 

请注意,您还必须为结果分配内存。 如果需要,可能需要传递额外的大小参数。 您可以按如下方式调用内核:

 // 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);