设置内核参数时为CL_INVALID_ARG_SIZE

问题描述 投票:0回答:1

我正在尝试脱离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上找到。

c++ gpu opencl
1个回答
0
投票

我对OpenCL的C ++包装器不是很熟悉,但是对codeKernel::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功能应返回正确的值。

© www.soinside.com 2019 - 2024. All rights reserved.