OpenCL-GL interop context crashes on Linux with segmentation fault (driver 390.25).

Hi,

I am testing a C code where I am making use of OpenCL for computation and OpenGL for rendering the results in a shared interoperability graphics context. I am working on two different systems: Mac (high Sierra) an Linux (Manjaro, driver 390.25).

On Linux I am experiencing a problem: when I create the shared graphics context by using the function:
context = clCreateContext(properties, 1, &devices[1], NULL, NULL, &err);

the system crashes giving a segmentation fault from the graphics Nvidia library, while when creating the context with:
context = clCreateContextFromType(properties, CL_DEVICE_TYPE_GPU, NULL, NULL, &err);

the program works fine.

As opposed to this situation, on my Mac computer both variants always work: therefore I speculate there is a bug in the Linux graphics library.

The code for reproducing this behaviour is the following (see below) and can be compiled this way:

  • on MAC: g++ clgl_interop.cpp -o clgl_interop -framework OpenCL -framework OpenGL -lGLEW -lglfw
  • on Linux: g++ clgl_interop.cpp -o clgl_interop -lOpenCL -lOpenGL -lGLEW -lglfw

My graphics card is NVIDIA GeForce GT 640, I separately tested both OpenCL and OpenGL and they work: the problem arises when using a CL-GL interop context. Could you please help me understanding this situation?

Best regards,

Erik

CODE: clgl_interop.cpp

#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>

#ifdef WINDOWS
#define GLFW_EXPOSE_NATIVE_WIN32
#define GLFW_EXPOSE_NATIVE_WGL
#endif

#ifdef linux
#define GLFW_EXPOSE_NATIVE_X11
#define GLFW_EXPOSE_NATIVE_GLX
#endif

#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>

#ifdef APPLE
#include <OpenGL/OpenGL.h>
#include <OpenCL/opencl.h>
#else
#include <GL/gl.h>
#include <CL/cl.h>
#include <CL/cl_gl.h>
#endif

void window_refresh_callback(GLFWwindow* window)
{
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}

int main()
{
GLFWwindow* window;
int i;
int j;
char* value;
size_t valueSize;
cl_uint platformCount;
cl_platform_id* platforms;
cl_uint deviceCount;
cl_device_id* devices;
cl_uint maxComputeUnits;
cl_context context;
int err;

////////////////////////////////////////////////////////////////////////////////
///////////////////////// Creating OpenGL context… ///////////////
////////////////////////////////////////////////////////////////////////////////

if (glfwInit() != GLFW_TRUE)
{
printf(“Unable to initialize GLFW!\n”);
glfwTerminate();
exit(EXIT_FAILURE);
}

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_SAMPLES, 4);

window = glfwCreateWindow(800, 600, “Test interop CPP”, NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}

glfwMakeContextCurrent(window);
glfwSetWindowRefreshCallback(window, window_refresh_callback);
glfwSetKeyCallback(window, key_callback);

glewExperimental = GL_TRUE;

if (glewInit() != GLEW_OK)
{
printf("Unable to initialize GLEW!\n");
exit(EXIT_FAILURE);

}

////////////////////////////////////////////////////////////////////////////////
///////////////////////// Creating OpenCL context… ///////////////
////////////////////////////////////////////////////////////////////////////////

// get all platforms
clGetPlatformIDs(0, NULL, &platformCount);
platforms = (cl_platform_id*) malloc(sizeof(cl_platform_id) * platformCount);
clGetPlatformIDs(platformCount, platforms, NULL);

for (i = 0; i < platformCount; i++)
{
// print platform name
clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME, 0, NULL, &valueSize);
value = (char*) malloc(valueSize);
clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME, valueSize, value, NULL);
printf("\n%d Platform: %s\n", i + 1, value);
free(value);

// print platform profile
clGetPlatformInfo(platforms[i], CL_PLATFORM_PROFILE, 0, NULL, &valueSize);
value = (char*) malloc(valueSize);
clGetPlatformInfo(platforms[i], CL_PLATFORM_PROFILE, valueSize, value, NULL);
printf(" %d.%d Platform profile: %s\n", i + 1, 1, value);
free(value);

// print platform version
clGetPlatformInfo(platforms[i], CL_PLATFORM_VERSION, 0, NULL, &valueSize);
value = (char*) malloc(valueSize);
clGetPlatformInfo(platforms[i], CL_PLATFORM_VERSION, valueSize, value, NULL);
printf(" %d.%d Platform version: %s\n", i + 1, 2, value);
free(value);

// print platform vendor
clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR, 0, NULL, &valueSize);
value = (char*) malloc(valueSize);
clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR, valueSize, value, NULL);
printf(" %d.%d Platform vendor: %s\n", i + 1, 3, value);
free(value);

// print platform extensions
clGetPlatformInfo(platforms[i], CL_PLATFORM_EXTENSIONS, 0, NULL, &valueSize);
value = (char*) malloc(valueSize);
clGetPlatformInfo(platforms[i], CL_PLATFORM_EXTENSIONS, valueSize, value, NULL);
printf(" %d.%d Platform extensions: %s\n", i + 1, 4, value);
free(value);

// get all devices
clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 0, NULL, &deviceCount);
devices = (cl_device_id*) malloc(sizeof(cl_device_id) * deviceCount);
clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, deviceCount, devices, NULL);

// for each device print critical attributes
for (j = 0; j < deviceCount; j++)
{
  // print device name
  clGetDeviceInfo(devices[j], CL_DEVICE_NAME, 0, NULL, &valueSize);
  value = (char*) malloc(valueSize);
  clGetDeviceInfo(devices[j], CL_DEVICE_NAME, valueSize, value, NULL);
  printf("\n%d.%d Device: %s\n", i + 1, j + 1, value);
  free(value);

  // print hardware device version
  clGetDeviceInfo(devices[j], CL_DEVICE_VERSION, 0, NULL, &valueSize);
  value = (char*) malloc(valueSize);
  clGetDeviceInfo(devices[j], CL_DEVICE_VERSION, valueSize, value, NULL);
  printf(" %d.%d.%d Hardware version: %s\n", i + 1, j + 1, 1, value);
  free(value);

  // print software driver version
  clGetDeviceInfo(devices[j], CL_DRIVER_VERSION, 0, NULL, &valueSize);
  value = (char*) malloc(valueSize);
  clGetDeviceInfo(devices[j], CL_DRIVER_VERSION, valueSize, value, NULL);
  printf(" %d.%d.%d Software version: %s\n", i + 1, j + 1, 2, value);
  free(value);

  // print c version supported by compiler for device
  clGetDeviceInfo(devices[j], CL_DEVICE_OPENCL_C_VERSION, 0, NULL, &valueSize);
  value = (char*) malloc(valueSize);
  clGetDeviceInfo(devices[j], CL_DEVICE_OPENCL_C_VERSION, valueSize, value, NULL);
  printf(" %d.%d.%d OpenCL C version: %s\n", i + 1, j + 1, 3, value);
  free(value);

  // print parallel compute units
  clGetDeviceInfo(devices[j], CL_DEVICE_MAX_COMPUTE_UNITS,
              sizeof(maxComputeUnits), &maxComputeUnits, NULL);
  printf(" %d.%d.%d Parallel compute units: %d\n", i + 1, j + 1, 4, maxComputeUnits);
}

}

#ifdef APPLE
CGLContextObj kCGLContext = CGLGetCurrentContext();
CGLShareGroupObj kCGLShareGroup = CGLGetShareGroup(kCGLContext);
cl_context_properties properties =
{
CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE,
(cl_context_properties) kCGLShareGroup,
0
};

#endif

#ifdef linux
cl_context_properties properties =
{
CL_GL_CONTEXT_KHR, (cl_context_properties)glfwGetGLXContext(window),
CL_GLX_DISPLAY_KHR, (cl_context_properties)glfwGetX11Display(),
CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[0],
0
};
#endif

#ifdef __WINDOWS__
cl_context_properties properties[] =
{
	CL_GL_CONTEXT_KHR, (cl_context_properties)glfwGetWGLContext(window),
	CL_WGL_HDC_KHR, (cl_context_properties)GetDC(glfwGetWin32Window(window)),
	CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[0],
	0
};
#endif

////////////////////////////////////////////////////////////////////////////////
//////////////////////////// HERE IS THE PROBLEM: ////////////////
////////////////////////////////////////////////////////////////////////////////

// On my Linux machine, this works:
context = clCreateContextFromType(properties, CL_DEVICE_TYPE_GPU, NULL, NULL, &err);

// On my Mac machine, this works but if I use it in Linux than it crashes with segmentation fault:
//context = clCreateContext(properties, 1, &devices[1], NULL, NULL, &err);

////////////////////////////////////////////////////////////////////////////////
///////////////////////////// END OF THE PROBLEM: ////////////////
////////////////////////////////////////////////////////////////////////////////

if (!(context))
{
  printf("\nError: Failed creating OpenCL-GL shared context!\n");
  exit(err);
}
else
{
  printf("\nCreated OpenCL-GL shared context!\n");
}

while (!glfwWindowShouldClose(window)) // Looping here until the window is closed…
{
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}

glfwDestroyWindow(window);
glfwTerminate();

free(devices);
free(platforms);

return 0;
}

END OF CODE.

Try this:
context = clCreateContext(properties, 1, &devices[0], NULL, NULL, &err);

Your code have a problem that &devices[1] becomes invalid pointer when deviceCount<=1.
I guess you have two or more devices on Mac but only one on Linux.

You are right!
In fact on my mac the program recognises two computation devices: the CPU and the GPU, while on my linux machine it sees only the GPU.
Therefore…

Thanks!

Erik