我想要完成的事情:
我正在尝试在 OpenCL 中渲染一些东西并将其写入 OpenGL 帧缓冲区(因为它是我可以通过渲染缓冲区等获得的唯一帧缓冲区,但我很乐意接受我可以使用的任何其他帧缓冲区 - 你告诉我使用 glsl 着色器对我没有帮助)
问题:
正如标题所说,OpenCL 函数clBuildProgram失败并出现错误 -11 (CL_BUILD_PROGRAM_FAILURE)。这不是问题,但 CL 编译器的日志是空的。我仔细检查了我的日志代码,但应该没问题。我还是把它贴在下面,只是为了让你看到自己。
我试图解决的问题:
- 谷歌搜索,当然
- 阅读来自 Khronos Groups 的文档
- 检查我的设备是否支持“cl_khr_gl_sharing”扩展,它确实支持(它包含在从返回的字符串中
clGetDeviceInfo(device_id, CL_DEVICE_EXTENSIONS, retSize, extensions, &retSize);
) - 修改着色器/内核:
- 犯了一些故意的错误,看看日志代码是否真的有效(它确实有效)
- 并缩小着色器/内核,看看着色器中的某些东西是否不能正常工作(正如我所读到的,一些缺失的东西会使 cl 的编译器崩溃)
我发现:
从我尝试的最后一点,我注意到,write_imageui
和read_imageui
opencl 函数使编译器无法编译我的代码(这就是我检查“cl_khr_gl_sharing”扩展名的原因)
此外:
我的操作系统是 Windows 10,我使用的 C 编译器是 GCC(我不知道,这有什么帮助,因为主机程序编译得很好,但这里仍然如此)
一些代码:
着色器/内核(尽可能缩小以重现问题,我也希望对你有用;我认为最后两行调用是导致 opencl 编译器无法工作的原因;其他东西在那里,让它是一个着色器,一旦它工作,它实际上可以处理某些东西):
#define ScreenWidth 1000
#define ScreenHight 1000
const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST;
__kernel void rainbow(__read_write image2d_t asd) {
int i = get_global_id(0);
unsigned int x = i%ScreenWidth;
unsigned int y = i/ScreenHight;
uint4 pixel;
pixel = read_imageui(asd, sampler, (int2)(x, y));
write_imageui(asd, (int2)(x, y), pixel);
}
最小化调用代码 (C),它执行所有必要的初始化工作(注意:日志缓冲区是动态可更改的):
cl_program program = clCreateProgramWithSource(contextZ, 1, (const char **)&source_str, (const size_t *)&source_size, &ret);
size_t retSize = 0;
clGetDeviceInfo(device_id, CL_DEVICE_EXTENSIONS, 0, NULL, &retSize);
char extensions[retSize];
clGetDeviceInfo(device_id, CL_DEVICE_EXTENSIONS, retSize, extensions, &retSize);
printf("%s\n", extensions);
// Build the program
ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);
if (ret == CL_BUILD_PROGRAM_FAILURE) {
l_logError("Could not build Kernel!");
// Determine the size of the log
size_t log_size;
printf(" reta: %i\n", clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size));
// Allocate memory for the log
char *log = (char *) malloc(log_size);
// Get the log
printf(" retb: %i\n", clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, log_size, log, NULL));
// Print the log
printf(" ret-val: %i\n", ret);
printf("%s\n", log);
}
您可能对输出感兴趣(最后两行是由于未构建内核引起的。该程序可以从源代码制作 - 查看代码):
E: Could not build Kernel!
reta: 0
retb: 0
ret-val: -11
E: Could not create Kernel!
kernel error: -45
其他人有类似的问题吗?任何想法,我应该怎么做?可能有 cl 内核/着色器的标题,我需要包含在其中吗?我的 clBuildProgram 调用可能不正确?(我读到有人没有通过设备,所以我的代码中可能缺少其他东西)
如果您需要更多详细信息,请务必告诉我,以便我提供(我想不出您现在可能需要的任何其他信息)
在此先感谢您的时间!
编辑:
根据规范,设备需要支持CL_DEVICE_IMAGE_SUPPORT扩展,它确实
我用这个检查了它:
cl_bool image_support = CL_FALSE;
clGetDeviceInfo(device_id, CL_DEVICE_IMAGE_SUPPORT, sizeof(cl_bool), &image_support, NULL);
printf("image_support: %i\n", image_support);
哪个输出:
image_support: 1
又名。CL_TRUE
编辑 2:
事实证明,需要在内核中启用 OpenCL 扩展:https
:
//www.khronos.org/registry/OpenCL/sdk/2.2/docs/man/html/EXTENSION.html#pragma OPENCL EXTENSION all : enable
在第一行添加内核/着色器确实会导致相同的问题
编辑 3:
从内核映像参数中删除 __read_write 标志或将其替换为其他内容(如 __read_only)会导致 OpenCL 编译器崩溃或无限循环,因为 clBuildProgram 永远不会返回(或者会在很长一段时间内返回)