我正在尝试脱离CUDA并学习OpenCL。我认为n身体模拟可能是一个不错的起点。我一直在使用c ++包装器,并按照提供的教程here来了解事物的工作原理。
该程序加载2个源文件,每个内核函数一个。每个都被编译,并内置到单独的内核中。在我的第一次尝试中,它们位于同一内核中。这是尝试通过做一些不同的事情来解决此问题。
nbs_forces.cl:
typedef struct body_t {
...
};
__kernel void execute(__global struct body_t* bodies, const float G, const int n){
...
}
nbs_positions.cl:
typedef struct body_t {
...
};
__kernel void execute(__global struct body_t* bodies, const float dt, const int n){
...
}
缓冲区是这样分配的:
// create memory buffers
bGravity = new cl::Buffer(*context, CL_MEM_READ_ONLY, sizeof(float));
bBodies = new cl::Buffer(*context, CL_MEM_READ_WRITE,
capacity * sizeof(body_t));
bTimestep = new cl::Buffer(*context, CL_MEM_READ_ONLY, sizeof(float));
bSize = new cl::Buffer(*context, CL_MEM_READ_ONLY, sizeof(int));
将数据复制到缓冲区后,该运行模拟了,我将内核参数设置为:
fKernel->setArg(0, *bBodies);
fKernel->setArg(1, *bGravity);
fKernel->setArg(2, *bSize);
pKernel->setArg(0, *bBodies);
pKernel->setArg(1, *bTimestep);
pKernel->setArg(2, *bSize);
cl::NDRange global(capacity);
cl::NDRange local(1);
for (int step = 0; step < steps; step++) {
queue->enqueueNDRangeKernel(*fKernel, cl::NullRange, global, local);
queue->enqueueNDRangeKernel(*pKernel, cl::NullRange, global, local);
}
但是在执行模拟函数的第二行(setKernelArg(1,* bGravity))时,程序以CL_INVALID_ARG_SIZE终止。看来应该解决这是一个微不足道的错误,但请尝试尝试,但似乎找不到导致它的任何东西。
我尝试传递不同的数据类型,包括opencl提供的类型(cl_float等),但是问题仍然存在。我敢肯定我做过一些愚蠢的事情,但过去几天我一直在撞墙,无济于事。
[为了简短起见,如果我忽略了任何关键代码,所有内容都可以在git repo here上找到。
我对OpenCL的C ++包装器不是很熟悉,但是对code的Kernel::setArg
却有所了解:
template <typename T>
cl_int setArg(cl_uint index, const T &value)
{
return detail::errHandler(
::clSetKernelArg(
object_,
index,
detail::KernelArgumentHandler<T>::size(value),
detail::KernelArgumentHandler<T>::ptr(value)),
__SET_KERNEL_ARGS_ERR);
}
和detail::KernelArgumentHandler
的相关专业:
template <typename T>
struct KernelArgumentHandler
{
static ::size_t size(const T&) { return sizeof(T); }
static const T* ptr(const T& value) { return &value; }
};
我们want是指用clSetKernelArg()
和sizeof(cl_mem)
指针为您的缓冲区调用cl_mem*
。
[由于看不到任何可以为您解包cl::Buffer
对象的东西,在我看来,您需要将已经解包的原始OpenCL缓冲区对象传递给setArg()
。如果我没记错的话,那会让你的代码看起来像这样:
fKernel->setArg(0, (*bBodies)());
fKernel->setArg(1, (*bGravity)());
fKernel->setArg(2, (*bSize)());
这将在operator()
基类上调用cl::Wrapper<cl_mem>
,该基类将基础OpenCL对象返回为cl_mem&
。然后,ptr()
的size()
和KernelArgumentHandler
功能应返回正确的值。