/* * Copyright © 2012 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include #include #include #include #include "CL/cl.h" #include "CL/cl_gl.h" #include "cl_platform_id.h" #include "cl_device_id.h" #include "cl_context.h" #include "cl_alloc.h" #include "cl_mutex.h" #include "cl_internals.h" #include "cl_driver.h" #define CHECK(var) \ if (var) \ return CL_INVALID_PROPERTY; \ else \ var = 1; static cl_int cl_context_properties_process(const cl_context_properties *prop, struct _cl_context_prop *cl_props, cl_uint * prop_len) { int set_cl_context_platform = 0, set_cl_gl_context_khr = 0, set_cl_egl_display_khr = 0, set_cl_glx_display_khr = 0, set_cl_wgl_hdc_khr = 0, set_cl_cgl_sharegroup_khr = 0; cl_int err = CL_SUCCESS; cl_props->gl_type = CL_GL_NOSHARE; cl_props->platform_id = 0; if (prop == NULL) goto exit; while(*prop) { switch (*prop) { case CL_CONTEXT_PLATFORM: CHECK (set_cl_context_platform); cl_props->platform_id = *(prop + 1); if (UNLIKELY(((cl_platform_id) (cl_props->platform_id))->magic != CL_MAGIC_PLATFORM_HEADER)) { err = CL_INVALID_PLATFORM; goto exit; } break; case CL_GL_CONTEXT_KHR: CHECK (set_cl_gl_context_khr); cl_props->gl_context = *(prop + 1); break; case CL_EGL_DISPLAY_KHR: CHECK (set_cl_egl_display_khr); cl_props->gl_type = CL_GL_EGL_DISPLAY; cl_props->egl_display = *(prop + 1); break; case CL_GLX_DISPLAY_KHR: CHECK (set_cl_glx_display_khr); cl_props->gl_type = CL_GL_GLX_DISPLAY; cl_props->glx_display = *(prop + 1); break; case CL_WGL_HDC_KHR: CHECK (set_cl_wgl_hdc_khr); cl_props->gl_type = CL_GL_WGL_HDC; cl_props->wgl_hdc = *(prop + 1); break; case CL_CGL_SHAREGROUP_KHR: CHECK (set_cl_cgl_sharegroup_khr); cl_props->gl_type = CL_GL_CGL_SHAREGROUP; cl_props->cgl_sharegroup = *(prop + 1); break; default: err = CL_INVALID_PROPERTY; goto exit; } prop += 2; *prop_len += 2; } (*prop_len)++; exit: return err; } static cl_context cl_context_new(const cl_context_properties *properties, struct _cl_context_prop* props, cl_uint prop_len, cl_uint num_devices, const cl_device_id *devices, void (CL_CALLBACK * pfn_notify) (const char*, const void*, size_t, void*), void *user_data) { cl_context ctx = NULL; cl_uint i; ctx = CL_CALLOC(1, sizeof(_cl_context)); if (ctx == NULL) return NULL; ctx->devices = CL_CALLOC(num_devices, sizeof(cl_device_id)); if (ctx->devices == NULL) { CL_FREE(ctx); return NULL; } /* Create the private pointer array if device > 1 */ if (num_devices > 1) { ctx->pdata = CL_CALLOC(num_devices, sizeof(void*)); if (ctx->pdata == NULL) { CL_FREE(ctx->devices); CL_FREE(ctx); return NULL; } } if(properties != NULL && prop_len > 0) { ctx->prop_user = CL_CALLOC(prop_len, sizeof(cl_context_properties)); if (ctx->prop_user == NULL) { CL_FREE(ctx->devices); if (ctx->device_num > 1) { CL_FREE(ctx->pdata); } CL_FREE(ctx); return NULL; } memcpy(ctx->prop_user, properties, sizeof(cl_context_properties)*prop_len); } ctx->props = *props; ctx->magic = CL_MAGIC_CONTEXT_HEADER; cl_ref_set_val(&ctx->ref_n, 1); CL_MUTEX_INIT(&ctx->lock); CL_COND_INIT(&ctx->cond); memcpy(ctx->devices, devices, sizeof(cl_device_id)*num_devices); ctx->device_num = num_devices; /* Add all refs to devices. */ for (i = 0; i < num_devices; i++) { cl_retain_device_id(devices[i]); } ctx->prop_len = prop_len; /* Save the user callback and user data*/ ctx->pfn_notify = pfn_notify; ctx->user_data = user_data; return ctx; } static void cl_context_delete(cl_context ctx) { cl_uint i; assert(ctx); CL_MUTEX_DESTROY(&ctx->lock); CL_COND_DESTROY(&ctx->cond); /* delete refs to devices. */ for (i = 0; i < ctx->device_num; i++) { cl_release_device_id(ctx->devices[i]); } if (ctx->device_num > 1) { CL_FREE(ctx->pdata); } CL_FREE(ctx->prop_user); CL_FREE(ctx->devices); ctx->magic = CL_MAGIC_DEAD_HEADER; /* For safety */ CL_FREE(ctx); } LOCAL void cl_release_context(cl_context ctx) { cl_uint i; cl_int err; assert(ctx); cl_int barrier_events_num = 0; cl_event* barrier_events_list = NULL; /* Add a check point here. */ barrier_events_list = cl_check_context_barrier_events(ctx, &barrier_events_num, &err); assert(err == CL_SUCCESS); if (barrier_events_list) { assert(barrier_events_num > 0); CL_FREE(barrier_events_list); } /* We are not done yet */ if (cl_ref_dec(&ctx->ref_n) > 1) return; /* All object lists should have been freed. Otherwise, the reference counter * of the context cannot be 0 */ assert(ctx->queues == NULL); assert(ctx->programs == NULL); assert(ctx->buffers == NULL); assert(ctx->events == NULL); assert(ctx->barrier_events == NULL); assert(ctx->barrier_events_num == 0); for (i = 0; i < ctx->device_num; i++) { ctx->devices[i]->driver->release_context(ctx, ctx->devices[i]); } cl_context_delete(ctx); } static cl_context cl_create_context(const cl_context_properties *properties, cl_uint num_devices, const cl_device_id *devices, void (CL_CALLBACK * pfn_notify) (const char*, const void*, size_t, void*), void *user_data, cl_int *errcode_ret) { /* cl_platform_id platform = NULL; */ struct _cl_context_prop props; cl_context ctx = NULL; cl_int err = CL_SUCCESS; cl_uint prop_len = 0; cl_uint i; /* Check that we are getting the right platform */ if (UNLIKELY(((err = cl_context_properties_process(properties, &props, &prop_len)) != CL_SUCCESS))) goto exit; /* We are good */ if (UNLIKELY((ctx = cl_context_new(properties, &props, prop_len, num_devices, devices, pfn_notify, user_data)) == NULL)) { err = CL_OUT_OF_HOST_MEMORY; goto exit; } for (i = 0; i < num_devices; i++) { err = ctx->devices[i]->driver->create_context(ctx, ctx->devices[i]); if (err != CL_SUCCESS) break; } if (err != CL_SUCCESS) cl_release_context(ctx); exit: if (errcode_ret != NULL) *errcode_ret = err; return ctx; } LOCAL cl_int cl_retain_context(cl_context ctx) { assert(ctx); int ret = cl_ref_inc_if_positive(&ctx->ref_n); if (ret > 0) return ret; return 0; } LOCAL cl_int cl_context_get_device_index(cl_context ctx, const cl_device_id device) { cl_uint i = 0; assert(device); for (i = 0; i < ctx->device_num; i++) { if (device == ctx->devices[i]) { return i; } } return -1; } static cl_int cl_get_context_info(cl_context context, cl_context_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) { if (param_name == CL_CONTEXT_DEVICES) { FILL_GETINFO_RET(cl_device_id, context->device_num, context->devices, CL_SUCCESS); } else if (param_name == CL_CONTEXT_NUM_DEVICES) { cl_uint n = context->device_num; FILL_GETINFO_RET(cl_uint, 1, &n, CL_SUCCESS); } else if (param_name == CL_CONTEXT_REFERENCE_COUNT) { cl_uint ref = cl_ref_get_val(&context->ref_n); FILL_GETINFO_RET(cl_uint, 1, &ref, CL_SUCCESS); } else if (param_name == CL_CONTEXT_PROPERTIES) { if(context->prop_len > 0) { FILL_GETINFO_RET(cl_context_properties, context->prop_len, context->prop_user, CL_SUCCESS); } else { cl_context_properties n = 0; FILL_GETINFO_RET(cl_context_properties, 1, &n, CL_SUCCESS); } } else { return CL_INVALID_VALUE; } } /************************************************************************************** ************************* CL APIs ******************************** **************************************************************************************/ cl_context clCreateContext(const cl_context_properties * properties, cl_uint num_devices, const cl_device_id * devices, void (* pfn_notify) (const char*, const void*, size_t, void*), void * user_data, cl_int * errcode_ret) { cl_int err = CL_SUCCESS; cl_context context = NULL; /* Assert parameters correctness */ INVALID_VALUE_IF(devices == NULL); INVALID_VALUE_IF(num_devices == 0); INVALID_VALUE_IF(pfn_notify == NULL && user_data != NULL); context = cl_create_context(properties, num_devices, devices, pfn_notify, user_data, &err); error: if (errcode_ret) *errcode_ret = err; return context; } cl_context clCreateContextFromType(const cl_context_properties * properties, cl_device_type device_type, void (CL_CALLBACK *pfn_notify) (const char *, const void *, size_t, void *), void * user_data, cl_int * errcode_ret) { cl_context context = NULL; cl_int err = CL_SUCCESS; cl_device_id devices[1]; cl_uint num_devices = 1; INVALID_VALUE_IF(pfn_notify == NULL && user_data != NULL); // err = cl_check_device_type(device_type); if(err != CL_SUCCESS) { goto error; } //err = cl_get_device_ids(NULL, // device_type, // 1, // &devices[0], // &num_devices); if (err != CL_SUCCESS) { goto error; } context = cl_create_context(properties, num_devices, devices, pfn_notify, user_data, &err); error: if (errcode_ret) *errcode_ret = err; return context; } cl_int clRetainContext(cl_context context) { cl_int err = CL_SUCCESS; CHECK_CONTEXT(context); if (cl_retain_context(context) == 0) { err = CL_INVALID_CONTEXT; } error: return err; } cl_int clReleaseContext(cl_context context) { cl_int err = CL_SUCCESS; CHECK_CONTEXT(context); cl_release_context(context); error: return err; } cl_int clGetContextInfo(cl_context context, cl_context_info param_name, size_t param_value_size, void * param_value, size_t * param_value_size_ret) { cl_int err = CL_SUCCESS; CHECK_CONTEXT(context); err = cl_get_context_info(context, param_name, param_value_size, param_value, param_value_size_ret); error: return err; }