OpenCL kernel -44 compilation error while using OpenGL context on Intel

I have posted this also to StackOverflow because this is a programming issue, but I am posting this here because it is only related to Manjaro.

Recently I’ve been trying to use OpenCL-OpenGL interop. After some trial and error I’ve found that I need to initialize OpenCL context providing it correct properties. I got it working under Manjaro with NVIDIA GPU, NVIDIA driver and CUDA installed but I got some problems on Intel devices.

(Problem is only under Manjaro with Intel and I am not able to test it under Windows on same devices because there are not mine)

The problem is: to use OpenCL-OpenGL interop I need to create OpenCL context using properties:

cl_context_properties properties[] = { //for Linux
    CL_GL_CONTEXT_KHR, (cl_context_properties) glXGetCurrentContext(),
    CL_GLX_DISPLAY_KHR, (cl_context_properties) glXGetCurrentDisplay(),
    CL_CONTEXT_PLATFORM, (cl_context_properties) platform,
    0
};

but if I provide this to context cl::Context context(default_device, properties); then after compilation of any kernel int buildCode = program.build(); ‘buildCode’ is equal to -44 and program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(default_device) returns 0 character string.
From OpenCL documentation I know that -44 is returned “if program is a not a valid program object” but after searching more on the internet I have found this so my problem could be anything that was unmapped by developers.

I have found that it really des not matter what I throw into the kernel code. It could be something like this:

std::string kernel_code =
        "not a valid kernel";

and I will get the same -44 build code.
On most of those devices there is no problem compiling any kernel after creating OpenCL context without properties.

I’ve tried It on:

  1. Manjaro 1st with NVIDIA GPU (GTX1070)- working
  2. Windows with AMD GPU (r9 380x) - working
  3. MacOs with AMD GPU (radeon pro 450) - working; and Intel CPU (i7-6700HQ) - working
  4. Manjaro 2nd with Intel CPU (i5-3320M)- error -44 (cannot create OpenCL context without properties)
  5. Manjaro 3rd with Intel GPU (UHD Graphics 620) - error -44
  6. Manjaro 4th with Intel GPU (UHD Graphics 620) - error -44

Every single device but (Manjaro with Intel CPU) I have tested was properly recognized and listed by clinfo command.
This is clinfo from Manjaro with Intel CPU:

Number of platforms                               1
  Platform Name                                   Intel(R) OpenCL
  Platform Vendor                                 Intel(R) Corporation
  Platform Version                                OpenCL 1.2 
  Platform Profile                                FULL_PROFILE
  Platform Extensions                             cl_khr_icd cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_byte_addressable_store cl_khr_depth_images cl_khr_3d_image_writes cl_intel_exec_by_local_thread cl_khr_spir cl_khr_fp64
  Platform Extensions function suffix             INTEL

  Platform Name                                   Intel(R) OpenCL
Number of devices                                 1
  Device Name                                            Intel(R) Core(TM) i5-3320M CPU @ 2.60GHz
  Device Vendor                                   Intel(R) Corporation
  Device Vendor ID                                0x8086
  Device Version                                  OpenCL 1.2 (Build 475)
  Driver Version                                  1.2.0.475
  Device OpenCL C Version                         OpenCL C 1.2 
  Device Type                                     CPU
  Device Profile                                  FULL_PROFILE
  Device Available                                Yes
  Compiler Available                              Yes
  Linker Available                                Yes
  Max compute units                               4
  Max clock frequency                             2600MHz
  Device Partition                                (core)
    Max number of sub-devices                     4
    Supported partition types                     by counts, equally, by names (Intel)
    Supported affinity domains                    (n/a)
  Max work item dimensions                        3
  Max work item sizes                             8192x8192x8192
  Max work group size                             8192
zsh: segmentation fault (core dumped)  clinfo

This is most simplified code with proper initialization that will reproduce this error:

#define CL_HPP_TARGET_OPENCL_VERSION 200

#include <CL/opencl.hpp>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <GL/glx.h>

#include <vector>
#include <cstdio>



GLFWwindow* initializeGLFW(uint width, uint height);
char initializeGLEW();
cl::Device getDefaultClDevice();
cl::Program compileTestKernel(cl::Context context, cl::Device default_device);


int main(){

    int width = 1024, height = 1024;
    GLFWwindow* window = initializeGLFW(width, height);
    if (window == nullptr){
        return 1;
    }

    if (initializeGLEW()){
        return 1;
    }

    cl::Device default_device = getDefaultClDevice();
    if (!default_device()){
        return 1;
    }


    cl_platform_id platform;
    clGetPlatformIDs(1, &platform, NULL);

    cl_context_properties properties[] = {
        CL_GL_CONTEXT_KHR, (cl_context_properties) glXGetCurrentContext(),
        CL_GLX_DISPLAY_KHR, (cl_context_properties) glXGetCurrentDisplay(),
        //if I comment any of properties above I get segmentatnion fault if trying to acces OpenGL memory on NVIDIA;
        //if I comment both of those I get segmentatnion fault on Intel creating context;
        //if I comment one or none I get -44 from program.build();
        //only on Intel CPU I need this to create context;

        CL_CONTEXT_PLATFORM, (cl_context_properties) platform,//this didn't influence resaults of my tests but everyone uses this in example so I guess it is important in some way;
        0
    };
    cl::Context context(default_device, properties);
    cl::Program program = compileTestKernel(context, default_device);

    cl::CommandQueue queue(context, default_device);

    cl::Kernel test(program, "test");
    queue.enqueueNDRangeKernel(test, cl::NullRange, cl::NullRange, cl::NullRange);
    queue.finish();

    int error = glGetError();
    if (error != GL_NO_ERROR) {
        std::fprintf(stderr, "OpenGL error: %d\n", error);
    }

    glfwDestroyWindow(window);

    return 0;
}


void glfwErrorCallback(int error, const char* description){
    std::fprintf(stderr, "Error: %s\n", description);
}


GLFWwindow* initializeGLFW(uint width, uint height){
    if (!glfwInit()){
        std::fprintf(stderr, "Failed to initialize GLFW!\n");
        return nullptr;
    }
    glfwSetErrorCallback(glfwErrorCallback);


    GLFWwindow* window = glfwCreateWindow(width, height, "test", NULL, NULL);
    if (!window){
        std::fprintf(stderr, "Failed to create GLFW window!\n");
        glfwTerminate();
        return nullptr;
    }

    glfwMakeContextCurrent(window);
    glViewport(0,0, width, height);
    glfwSwapInterval(1);

    return window;
}


char initializeGLEW(){
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK) {
        std::fprintf(stderr, "Failed to initialize GLEW!\n");
        glfwTerminate();
        return -1;
    }

    GLenum error = glGetError();
    if (error != GL_NO_ERROR) {
        std::fprintf(stderr, "OpenGL error: %d\n", error);
    }


    const GLubyte* glVersion = glGetString(GL_VERSION);
    const GLubyte* glVendor = glGetString(GL_VENDOR);
    const GLubyte* glRenderer = glGetString(GL_RENDERER);

    std::printf("GL version:\t%s\n", glVersion);
    std::printf("GL vendor:\t%s\n", glVendor);
    std::printf("GL renderer:\t%s\n\n", glRenderer);

    return 0;
}


cl::Device getDefaultClDevice(){
    std::vector<cl::Platform> all_platforms;
    cl::Platform::get(&all_platforms);

    if (all_platforms.empty()){
        std::fprintf(stderr, "No platforms found. Check OpenCL installation!\n");
        return cl::Device();
    }

    int selection=0;

    cl::Platform default_platform = all_platforms[0];
    std::printf("Using platform:\t%s\n", default_platform.getInfo<CL_PLATFORM_NAME>().c_str());

    std::vector<cl::Device> all_devices;
    default_platform.getDevices(CL_DEVICE_TYPE_ALL, &all_devices);


    if (all_devices.size() == 0){
        std::fprintf(stderr, "No devices found. Check OpenCL installation!\n");
        return cl::Device();
    }

    cl::Device default_device = all_devices[0];
    std::printf("Using device:\t%s\n", default_device.getInfo<CL_DEVICE_NAME>().c_str());

    return default_device;
}


cl::Program compileTestKernel(cl::Context context, cl::Device default_device){
    cl::Program::Sources sources;
    std::string kernel_code =
        "   void kernel create_gradient(){}";

    sources.push_back({kernel_code.c_str(), kernel_code.length()});
    cl::Program program(context, sources);

    int buildCode = program.build();

    int error = glGetError();
    if (error != GL_NO_ERROR) {
        std::fprintf(stderr, "OpenGL error: %d\n", error);
    }

    if (buildCode != CL_SUCCESS) {
        std::fprintf(stderr, "Error building (%d): %s\n", buildCode, program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(default_device).c_str());
        exit(1);
    }
    return program;
}

EDIT:
I compiled this code using g++ main.cpp -lglfw -lGLEW -lOpenCL -lGL -lX11 -lXrandr -lXi -ldl -lpthread
END OF EDIT

Those are messages That I got from my devices:

GL version:     4.6.0 NVIDIA 535.113.01
GL vendor:      NVIDIA Corporation
GL renderer:    NVIDIA GeForce GTX 1070/PCIe/SSE2

Using platform: NVIDIA CUDA
Using device:   NVIDIA GeForce GTX 1070

and

GL version:     3.0 Mesa 21.3.9 Amber
GL vendor:      Intel Open Source Technology Center
GL renderer:    Mesa DRI Intel(R) HD Graphics 4000 (IVB GT2)

Using platform: Intel(R) OpenCL
Using device:   Intel(R) Core(TM) i5-3320M CPU @ 2.60GHz
Error building (-44):

I am new to either OpenCL or OpenGL so probably my problem could be easily explained by someone with more experience. If you have any idea of what the problem could be I would appreciate sharing it with me.
Please also tell me if there is any additional useful info that I can provide because there are many devices I’ve been testing this on. I don’t wanna flood this page with irrelevant stream of text and also I would have to ask my friends to do this for me (only Manjaro with NVIDIA and Manjaro with Intel CPU are mine).

Looks to me that it targets OpenCL 2.0, while your Intel GPU only support up to OpenCL 1.2.

You are absolutely right. Sadly, after rewriting whole code in OpenCL 1.2 results are the same:

  1. Manjaro with Intel CPU - with properties: error -44; without: segmentation fault while creating OpenCL context
  2. Manjaro with NVIDIA GPU - everything fine
  3. Manjaro with Intel GPU - with properties: error -44; without: everything fine

Now at least we know that OpenCL version does not play any role here.

New code:

#define CL_TARGET_OPENCL_VERSION 120

#include <CL/cl.h>
#include <CL/cl_gl.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <GL/glx.h>

#include <cstdio>


GLFWwindow* initializeGLFW(uint width, uint height);
char initializeGLEW();
cl_device_id getDefaultClDevice();
cl_program compileTestKernel(cl_context context, cl_device_id default_device);


int main() {
    int width = 1024, height = 1024;
    GLFWwindow* window = initializeGLFW(width, height);
    if (window == NULL) {
        return 1;
    }

    if (initializeGLEW()) {
        return 1;
    }

    cl_device_id default_device = getDefaultClDevice();
    if (!default_device) {
        return 1;
    }

    cl_platform_id platform;
    clGetPlatformIDs(1, &platform, NULL);

    cl_context_properties properties[] = {
        CL_GL_CONTEXT_KHR, (cl_context_properties) glXGetCurrentContext(),
        CL_GLX_DISPLAY_KHR, (cl_context_properties) glXGetCurrentDisplay(),
        CL_CONTEXT_PLATFORM, (cl_context_properties) platform,
        0
    };

    cl_context context = clCreateContext(properties, 1, &default_device, NULL, NULL, NULL);
    cl_program program = compileTestKernel(context, default_device);

    int error;

    cl_command_queue_properties queueProperties = CL_QUEUE_PROFILING_ENABLE;
    cl_command_queue queue = clCreateCommandQueue(context, default_device, queueProperties, &error);
    if (error != GL_NO_ERROR) {
        fprintf(stderr, "OpenGL error: %d\n", error);
    }

    cl_kernel test = clCreateKernel(program, "create_gradient", NULL);
    clEnqueueNDRangeKernel(queue, test, 1, NULL, NULL, NULL, 0, NULL, NULL);
    clFinish(queue);

    error = glGetError();
    if (error != GL_NO_ERROR) {
        fprintf(stderr, "OpenGL error: %d\n", error);
    }

    glfwDestroyWindow(window);

    return 0;
}




void glfwErrorCallback(int error, const char* description){
    std::fprintf(stderr, "Error: %s\n", description);
}


GLFWwindow* initializeGLFW(uint width, uint height){
    if (!glfwInit()){
        std::fprintf(stderr, "Failed to initialize GLFW!\n");
        return nullptr;
    }
    glfwSetErrorCallback(glfwErrorCallback);


    GLFWwindow* window = glfwCreateWindow(width, height, "test", NULL, NULL);
    if (!window){
        std::fprintf(stderr, "Failed to create GLFW window!\n");
        glfwTerminate();
        return nullptr;
    }

    glfwMakeContextCurrent(window);
    glViewport(0,0, width, height);
    glfwSwapInterval(1);

    return window;
}


char initializeGLEW(){
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK) {
        std::fprintf(stderr, "Failed to initialize GLEW!\n");
        glfwTerminate();
        return -1;
    }

    GLenum error = glGetError();
    if (error != GL_NO_ERROR) {
        std::fprintf(stderr, "OpenGL error: %d\n", error);
    }


    const GLubyte* glVersion = glGetString(GL_VERSION);
    const GLubyte* glVendor = glGetString(GL_VENDOR);
    const GLubyte* glRenderer = glGetString(GL_RENDERER);

    std::printf("GL version:\t%s\n", glVersion);
    std::printf("GL vendor:\t%s\n", glVendor);
    std::printf("GL renderer:\t%s\n\n", glRenderer);

    return 0;
}


cl_device_id getDefaultClDevice() {
    cl_uint num_platforms;
    cl_platform_id platform;
    cl_device_id device_id;
    clGetPlatformIDs(1, &platform, &num_platforms);

    if (num_platforms == 0) {
        fprintf(stderr, "No platforms found. Check OpenCL installation!\n");
        return NULL;
    }

    cl_uint num_devices;
    clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device_id, &num_devices);
    //I've changed this to CL_DEVICE_TYPE_CPU during CPU test

    if (num_devices == 0) {
        fprintf(stderr, "No GPU devices found. Check OpenCL installation!\n");
        return NULL;
    }

    return device_id;
}


cl_program compileTestKernel(cl_context context, cl_device_id default_device) {
    const char* kernel_code = "void kernel test(){}";

    cl_program program = clCreateProgramWithSource(context, 1, &kernel_code, NULL, NULL);
    clBuildProgram(program, 1, &default_device, NULL, NULL, NULL);

    cl_int buildCode = clBuildProgram(program, 1, &default_device, NULL, NULL, NULL);

    GLenum error = glGetError();
    if (error != GL_NO_ERROR) {
        fprintf(stderr, "OpenGL error: %d\n", error);
    }

    if (buildCode != CL_SUCCESS) {
        size_t log_size;
        clGetProgramBuildInfo(program, default_device, CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);

        char* build_log = (char*)malloc(log_size);
        clGetProgramBuildInfo(program, default_device, CL_PROGRAM_BUILD_LOG, log_size, build_log, NULL);

        fprintf(stderr, "Error building (%d): %s\n", buildCode, build_log);
        free(build_log);
        exit(1);
    }

    return program;
}

I have just realized that in messages returned by my program on Manjaro with Intel CPU I got different devices in OpenGL and OpenCL context. From what I understand it really should not work so no surprise here but this occurs only on this one device. On every other I made sure that both contexts use same device.