Ответ 1
-
Вы должны выделить буфер OpenCL и скопировать в него данные ЦП. Буфер 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
), но это накладывает некоторые ограничения на выравнивание и доступ к памяти хоста после создания буфера. В основном, память хоста может содержать мусор, когда вы в настоящее время не отображаете его. -
Это зависит. Величины ли размеры векторов во втором измерении равны? Затем просто сгладьте их при загрузке на устройство 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;
}
Обратите внимание, что вам также необходимо выделить память для результата. Может потребоваться передать дополнительные аргументы размера, если они вам понадобятся. Вы вызываете ядро следующим образом:
// 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);