#define CL_HPP_ENABLE_EXCEPTIONS
#define CL_HPP_MINIMUM_OPENCL_VERSION 120
#define CL_HPP_TARGET_OPENCL_VERSION 120
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#include <CL/cl2.hpp>
#pragma GCC diagnostic pop
#include <sstream>
#include <algorithm>
using namespace cl;
#if defined (OS_MAC)
#include <OpenGL/OpenGL.h>
static const std::string CL_GL_SHARING_EXT = "cl_APPLE_gl_sharing";
#else
static const std::string CL_GL_SHARING_EXT = "cl_khr_gl_sharing";
#endif
bool checkGLInterop(
const cl::Platform &plat,  
const cl::Device &pDevice, 
const forge::Window &wnd)
 {
    bool ret_val = false;
    
    std::string exts = pDevice.getInfo<CL_DEVICE_EXTENSIONS>();
    std::stringstream ss(exts);
    std::string item;
    while (std::getline(ss,item,' ')) {
        if (item == CL_GL_SHARING_EXT) {
            ret_val = true;
            break;
        }
    }
    if (!ret_val) return false;
#if !defined(OS_MAC) // Check on Linux, Windows
    
#if defined(OS_LNX)
    cl_context_properties cps[] = {
        CL_GL_CONTEXT_KHR, (cl_context_properties)wnd.
context(),
        CL_GLX_DISPLAY_KHR, (cl_context_properties)wnd.
display(),
        CL_CONTEXT_PLATFORM, (cl_context_properties)plat(),
        0
    };
#else 
    cl_context_properties cps[] = {
        CL_GL_CONTEXT_KHR, (cl_context_properties)wnd.
context(),
        CL_WGL_HDC_KHR, (cl_context_properties)wnd.
display(),
        CL_CONTEXT_PLATFORM, (cl_context_properties)plat(),
        0
    };
#endif
    
    
    
    auto func = (clGetGLContextInfoKHR_fn)
        clGetExtensionFunctionAddressForPlatform(plat(), "clGetGLContextInfoKHR");
    if (!func) return false;
    
    std::vector<cl_device_id> devices(16);
    size_t ret = 0;
    cl_int err = func(cps,
                      CL_DEVICES_FOR_GL_CONTEXT_KHR,
                      devices.size() * sizeof(cl_device_id),
                      devices.data(),
                      &ret);
    if (err != CL_SUCCESS) return false;
    int num = ret / sizeof(cl_device_id);
    devices.resize(num);
    
    cl_device_id current_device = pDevice();
    auto res = std::find(std::begin(devices), std::end(devices), current_device);
    ret_val = res != std::end(devices);
#endif
    return ret_val;
}
{
    std::vector<cl::Platform> platforms;
    Platform::get(&platforms);
    for (auto platform : platforms) {
        std::vector<cl::Device> devices;
        try {
            platform.getDevices(CL_DEVICE_TYPE_GPU, &devices);
        } catch(const cl::Error &err) {
            if (err.err() != CL_DEVICE_NOT_FOUND) {
                throw;
            } else {
                continue;
            }
        }
        for (auto device : devices) {
            if (!checkGLInterop(platform, device, wnd)) continue;
#if defined(OS_MAC)
            CGLContextObj cgl_current_ctx = CGLGetCurrentContext();
            CGLShareGroupObj cgl_share_group = CGLGetShareGroup(cgl_current_ctx);
            cl_context_properties cps[] = {
                CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, (cl_context_properties)cgl_share_group,
                0
            };
#elif defined(OS_LNX)
            cl_context_properties cps[] = {
                CL_GL_CONTEXT_KHR, (cl_context_properties)wnd.
context(),
                CL_GLX_DISPLAY_KHR, (cl_context_properties)wnd.
display(),
                CL_CONTEXT_PLATFORM, (cl_context_properties)platform(),
                0
            };
#else 
            cl_context_properties cps[] = {
                CL_GL_CONTEXT_KHR, (cl_context_properties)wnd.
context(),
                CL_WGL_HDC_KHR, (cl_context_properties)wnd.
display(),
                CL_CONTEXT_PLATFORM, (cl_context_properties)platform(),
                0
            };
#endif
            std::cout << "Platform: " << platform.getInfo<CL_PLATFORM_NAME>() << std::endl;
            std::cout << "Device: " << device.getInfo<CL_DEVICE_NAME>() << std::endl;
            return cl::Context(device, cps);
        }
    }
    throw std::runtime_error("No CL-GL sharing contexts found");
}
cl::CommandQueue queue;
cl::Context context;
cl_context getContext()
{
    return context();
}
cl_command_queue getCommandQueue()
{
    return queue();
}