对于OpenCL要与OpenGL进行交互,OpenCL的上下文必须基于OpenGL的上下文进行创建,原因在于OpenGL比OpenCL要早10多年诞生。因此,我们在创建OpenCL上下文之前必须确保OpenGL的上下文已经创建完毕,并且初始化设置都成功。
其次,OpenCL与OpenGL的可交互性是OpenCL平台的一个扩展。因此,我们在创建OpenCL上下文之前得先查询一下,当前OpenCL计算设备是否支持这个扩展。我们使用CL_PLATFORM_EXTENSIONS参数来调用clGetPlatformInfo函数,或用CL_DEVICE_EXTENSIONS参数来调用clGetDeviceInfo函数,然后遍历返回的字符串是否含有cl_khr_gl_sharing,如果包含则说明当前设备支持OpenCL与OpenGL的可互操作性;如果不包含,则当前设备可能不支持OpenCL与OpenGL的可互操作性。这里对于Mac用户要提醒一下。在OS X中(至少在10.9以及10.10版本中),查询结果是不含cl_khr_gl_sharing这个字符串的,但是却包含了Apple自己的cl_APPLE_gl_sharing。我们只要查询到有cl_APPLE_gl_sharing存在,那么说明当前的Mac能够支持OpenCL与OpenGL的可互操作性。
当前两步完成之后,我们就可以开始着手建立OpenCL上下文了。我们这里需要为OpenCL上下文配置其相关的,与OpenGL相关联的上下文的属性,通过传递cl_context_properties参数来实现。cl_context_properties这个类型其实是一个能完全包容主机端操作系统指针长度的整型。例如,如果当前操作系统是64位的,那么cl_context_properties就是64位的长整型;如果当前操作系统是32位的,那么cl_context_properties则是32位的整型。OpenCL上下文属性的配置采用的是键值对的数组。“键”是由OpenCL标准和实现定义好的属性,而值则是对应该键的具体数值。该数组以整数0结尾,表示结束。由于不同的桌面系统其底层图形驱动做的不一样,因此对于不同系统,我们需要分别调用不同的系统API来获得当前OpenGL的上下文。
OpenCL标准定义了一些属性名对应到不同的操作系统上。例如,在Linux上提供了CL_GLX_DISPLAY_KHR属性,在Windows上提供了CL_WGL_HDC_KHR属性用于设置显示设备对象。而提供CL_GL_CONTEXT_KHR属性来设置这两个系统的当前OpenGL上下文对象。但是在OS X系统下都没有定义这些属性名,因此我们只能使用Apple自带的CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE属性来设置当前OpenCL与OpenGL的共享组对象。所以,我们往往会通过条件预编译(针对C/C++以及Objective-C/C++)来配置OpenCL上下文属性,例如以下代码所示:
#ifdef _APPLE_
CGLContextObj cgl_context = CGLGetCurrentContext();
CGLShareGroupObj sharegroup = CGLGetShareGroup(cgl_context);
gcl_gl_set_sharegroup(sharegroup);
#endif
cl_context_properties properties[] =
{
#ifdef WIN32
CL_GL_CONTEXT_KHR ,
(cl_context_properties)wglGetCurrentContext(),
CL_WGL_HDC_KHR , (cl_context_properties)wglGetCurrentDC(),
#endif
#ifdef _linux_
CL_GL_CONTEXT_KHR ,
(cl_context_properties)glXGetCurrentContext(),
CL_GLX_DISPLAY_KHR ,
(cl_context_properties)glXGetCurrentDisplay(),
#endif
#ifdef _APPLE_
CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE,
(cl_context_properties)sharegroup,
#endif
0
};
context = clCreateContext(properties, 1, &oclDevice, NULL, NULL,
NULL);
对于上述分别应对Windows、Linux与OS X系统来创建cl_context对象的方法这里不过多描述。因为这个就是各家系统对OpenGL、OpenCL的支持不太一样所致,没有太多道理可讲。我们一旦将cl_context对象创建好之后,后续对各种buffer的使用其实都一样,均能满足OpenCL官方提供的标准API。