1

我想要完成的事情:
我正在尝试在 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_imageuiread_imageuiopencl 函数使编译器无法编译我的代码(这就是我检查“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 永远不会返回(或者会在很长一段时间内返回)

4

1 回答 1

2

我在过去几天发现的可能有点不正确。我的编辑 3(来自原始帖子/问题)指出,用 __read_only 替换 __read_write 会导致编译器完全崩溃。这是不正确的,我现在可以确认,我只是在编译调用之后没有添加任何更多的调试输出代码。在 clBuildProgram 调用显示后添加更多调试行,它确实有效。

我不知道,为什么这会导致 OpenCL 编译器实际上没有输出任何错误,并且驱动程序的供应商应该明确地修复这个/输出一些东西(评论中的设备信息),以使开发更容易一些。(即使只是一个警告也会有帮助)

我找到了这篇stackoverflow帖子,讨论了一个类似的问题:OpenCL - Pass image2d_t two to get both read and write from kernel? . 这就是我什至想到的,这可能会导致毁灭性的问题。
公平地说,官方文档说明了这一点,但我理解它更像是它们可以结合到 __read_write (read_only | write_only == __read_write):

下表中的 aQual 是指访问限定符之一。对于写函数,这可能是 write_only 或 read_write。

我只用 write_image 调用 (write_imageui) 替换了我的内核,并将 image2d_t 设置为 __write_only,以获得最小的调试可能性。这导致着色器/内核编译成功,但屏幕仍然是空的。但后者是另一个问题。

于 2021-12-09T11:13:03.950 回答