OpenCL - можно ли вызывать другую функцию из ядра?

Я следую вместе с учебником, расположенным здесь: http://opencl.codeplex.com/wikipage?title=OpenCL%20Tutorials%20-%201

Ядро, которое они перечисляли, является этим, которое вычисляет сумму двух чисел и сохраняет его в выходной переменной:

__kernel void vector_add_gpu (__global const float* src_a,
                     __global const float* src_b,
                     __global float* res,
           const int num)
{
   /* get_global_id(0) returns the ID of the thread in execution.
   As many threads are launched at the same time, executing the same kernel,
   each one will receive a different ID, and consequently perform a different computation.*/
   const int idx = get_global_id(0);

   /* Now each work-item asks itself: "is my ID inside the vector range?"
   If the answer is YES, the work-item performs the corresponding computation*/
   if (idx < num)
      res[idx] = src_a[idx] + src_b[idx];
}

1) Скажем, например, что выполненная операция была намного сложнее суммирования - что-то, что гарантирует его собственную функцию. Позвольте называть его ComplexOp (in1, in2, out). Как я могу реализовать эту функцию, чтобы vector_add_gpu() мог ее вызвать и использовать? Можете ли вы привести пример кода?

2) Теперь давайте рассмотрим пример до крайности, и теперь я хочу назвать общую функцию, которая работает с двумя числами. Как мне настроить его так, чтобы ядру можно было передать указатель на эту функцию и вызвать его по мере необходимости?

Ответ 1

Да, это возможно. Вы просто должны помнить, что OpenCL основан на C99 с некоторыми оговорками. Вы можете создавать другие функции либо внутри одного и того же файла ядра, либо в отдельном файле и просто включать его в начале. Вспомогательные функции необязательно должны быть объявлены как встроенные, однако имейте в виду, что OpenCL будет встроить функции при вызове. Указатели также недоступны для использования при вызове вспомогательных функций.

Пример

float4 hit(float4 ray_p0, float4 ray_p1, float4 tri_v1, float4 tri_v2, float4 tri_v3)
{
//logic to detect if the ray intersects a triangle
}

__kernel void detection(__global float4* trilist, float4 ray_p0, float4 ray_p1)
{
int gid = get_global_id(0);
float4 hitlocation = hit(ray_p0, ray_p1, trilist[3*gid], trilist[3*gid+1], trilist[3*gid+2]);
}