我目前正在尝试编辑已经使用OpenCL.dll的项目,以使其动态加载库。我希望能够在没有OpenCL系统的情况下使用它,只有一个错误信息和一个功能被禁用。
首先,我在函数中添加了一些包装器。 (此代码在C ++类中,并且是公共的)
typedef cl_int h_clGetPlatformIDs(cl_uint, cl_platform_id *, cl_uint *);
typedef cl_int h_clGetDeviceIDs(cl_platform_id, cl_device_type, cl_uint, cl_device_id *, cl_uint *);
typedef cl_context h_clCreateContext(cl_context_properties *, cl_uint, const cl_device_id *, void *(const char *, const void *, size_t, void *), void *, cl_int *);
typedef cl_command_queue h_clCreateCommandQueue(cl_context, cl_device_id, cl_command_queue_properties, cl_int *);
typedef cl_program h_clCreateProgramWithSource(cl_context, cl_uint, const char **, const size_t *, cl_int *);
typedef cl_int (CALLBACK h_clBuildProgram)(cl_program, cl_uint,const cl_device_id *, const char *, void (*)(cl_program, void * ), void * ) CL_API_SUFFIX__VERSION_1_0;
typedef cl_int h_clGetProgramBuildInfo(cl_program, cl_device_id, cl_program_build_info, size_t, void *, size_t *);
typedef cl_kernel h_clCreateKernel(cl_program, const char *, cl_int *);
typedef cl_mem h_clCreateBuffer(cl_context, cl_mem_flags, size_t, void *, cl_int *);
typedef cl_int h_clEnqueueWriteBuffer(cl_command_queue, cl_mem, cl_bool, size_t, size_t, const void *, cl_uint, const cl_event *, cl_event *);
typedef cl_int h_clSetKernelArg(cl_kernel, cl_uint, size_t, const void *);
typedef cl_int h_clEnqueueNDRangeKernel(cl_command_queue, cl_kernel, cl_uint, const size_t*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*);
typedef cl_int h_clFlush(cl_command_queue);
typedef cl_int h_clEnqueueReadBuffer(cl_command_queue, cl_mem, cl_bool, size_t, size_t, void *, cl_uint, const cl_event *, cl_event *);
typedef cl_int h_clWaitForEvents(cl_uint, const cl_event *);
typedef cl_int h_clReleaseMemObject(cl_mem );
typedef cl_int h_clReleaseEvent(cl_event );
typedef cl_int h_clReleaseProgram(cl_program );
typedef cl_int h_clReleaseKernel(cl_kernel);
typedef cl_int h_clReleaseCommandQueue(cl_command_queue );
typedef cl_int h_clReleaseContext(cl_context );
h_clGetPlatformIDs* clGetPlatformIDs;
h_clGetDeviceIDs* clGetDeviceIDs;
h_clCreateContext* clCreateContext;
h_clCreateCommandQueue* clCreateCommandQueue;
h_clCreateProgramWithSource* clCreateProgramWithSource;
h_clBuildProgram* clBuildProgram;
h_clGetProgramBuildInfo* clGetProgramBuildInfo;
h_clCreateKernel* clCreateKernel;
h_clCreateBuffer* clCreateBuffer;
h_clEnqueueWriteBuffer* clEnqueueWriteBuffer;
h_clSetKernelArg* clSetKernelArg;
h_clEnqueueNDRangeKernel* clEnqueueNDRangeKernel;
h_clFlush* clFlush;
h_clEnqueueReadBuffer* clEnqueueReadBuffer;
h_clWaitForEvents* clWaitForEvents;
h_clReleaseMemObject* clReleaseMemObject;
h_clReleaseEvent* clReleaseEvent;
h_clReleaseProgram* clReleaseProgram;
h_clReleaseKernel* clReleaseKernel;
h_clReleaseCommandQueue* clReleaseCommandQueue;
h_clReleaseContext* clReleaseContext;
有了这个,我可以直接为处理程序分配GetProcAdress返回的内容,之后只需调用该函数(当然,我首先加载DLL)。
clReleaseContext = (h_clReleaseContext*) GetProcAddress(ocl_lib_handle, "clReleaseContext");
一个常见的电话示例:
clReleaseContext((cl_context)context);
但我总是让SEGFAULT称之为:
clBuildProgram(program, 0, NULL, "-cl-fast-relaxed-math", NULL, NULL);
这很奇怪,因为所有其他的都可以正常工作。 我在这里发布clBuildProgram Args作为参考:
extern CL_API_ENTRY cl_int CL_API_CALL
clBuildProgram(cl_program /* program */,
cl_uint /* num_devices */,
const cl_device_id * /* device_list */,
const char * /* options */,
void (*pfn_notify)(cl_program /* program */, void * /* user_data */),
void * /* user_data */) CL_API_SUFFIX__VERSION_1_0;
谢谢!
答案 0 :(得分:1)
您的typedef必须与OpenCL标题中的声明完全匹配。他们没有,你不使用CL_API_ENTRY,CL_API_CALL。我没有在第一个参数的原始声明中看到CALLBACK。
这当然是编写和维护的可怕代码。 clBuildProgram()函数有很多机会在没有你帮助的情况下轰炸访问冲突。首先使用测试程序将其抽出,使主代码正常运行。请求,窃取或借用以利用MSVC链接器的/ DELAYLOAD功能。
答案 1 :(得分:1)
每次调用GetProcAddress
时,都应检查返回NULL,看看是否能够在DLL中找到该函数。
如果在尝试加载clBuildProgram时返回NULL,则函数名称查找出现问题。
如果它给你一个有效的指针,但是typedef与签名完全不匹配,那么你会将损坏的数据传递给函数,并可能崩溃。
如果你有一个有效的指针和一个正确的typedef,那么也许你只是传递不好的参数?我在0
的调用中看到了很多NULL
和clBuildProgram
- 也许这个错误在CL代码中?当你直接调用它时(即没有动态加载),你可以使用相同的参数调用clBuildProgram
吗?
答案 2 :(得分:1)
一个可能的int:你在C和C ++中合并的API没有相同的ABI,从二进制文件中传递参数是不同的(这就是为什么在C ++中使用C时,你需要使用
extern "C" {
#include "c_api.h"
}
你应该围绕这个主题进行谷歌搜索,看看如何使用C调用约定/修改来强制调用处理程序。不确定这是解决方案,但它绝对值得研究,因为它会导致这个确切的结果。
答案 3 :(得分:0)
我不知道究竟解决了什么问题。 我重写了.h文件,其中包含一个带有__stdcall添加的OpenCL文件的typedef副本。 然后使用extern“C”。
正在工作!!
谢谢大家!