cf4ocl (C Framework for OpenCL)  v2.1.0
Object-oriented framework for developing and benchmarking OpenCL projects in C/C++
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ccl_context_wrapper.c
Go to the documentation of this file.
1 /*
2  * This file is part of cf4ocl (C Framework for OpenCL).
3  *
4  * cf4ocl is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as
6  * published by the Free Software Foundation, either version 3 of the
7  * License, or (at your option) any later version.
8  *
9  * cf4ocl is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with cf4ocl. If not, see
16  * <http://www.gnu.org/licenses/>.
17  * */
18 
29 #include "ccl_context_wrapper.h"
30 #include "_ccl_abstract_dev_container_wrapper.h"
31 #include "_ccl_defs.h"
32 
38 struct ccl_context {
39 
44  CCLDevContainer base;
45 
50  CCLPlatform* platf;
51 
52 };
53 
63 static void ccl_context_release_fields(CCLContext* ctx) {
64 
65  /* Make sure context wrapper object is not NULL. */
66  g_return_if_fail(ctx != NULL);
67 
68  /* Release devices. */
69  ccl_dev_container_release_devices((CCLDevContainer*) ctx);
70 
71  /* Release platform. */
72  if (ctx->platf) {
73  ccl_platform_unref(ctx->platf);
74  }
75 }
76 
88 #define ccl_context_properties_default_free(properties, ctx_props) \
89  if (properties == NULL) /* Could also be (properties != ctx_props) */ \
90  g_slice_free1(3 * sizeof(cl_context_properties), ctx_props)
91 
109 static cl_context_properties* ccl_context_properties_default(
110  const cl_context_properties* properties,
111  cl_device_id device, CCLErr** err) {
112 
113  /* Make sure device is not NULL. */
114  g_return_val_if_fail(device != NULL, NULL);
115  /* Make sure err is NULL or it is not set. */
116  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
117 
118  /* Context properties. */
119  cl_context_properties* ctx_props = NULL;
120 
121  /* The OpenCL platform object. */
122  cl_platform_id platform;
123 
124  /* OpenCL function call status. */
125  cl_int ocl_status;
126 
127  /* Check if the original const properties object is NULL... */
128  if (properties == NULL) {
129 
130  /* ...if so, create a default set of context properties. */
131 
132  /* Allocate memory for default properties. */
133  ctx_props = g_slice_alloc(3 * sizeof(cl_context_properties));
134 
135  /* Get context platform using first device. */
136  ocl_status = clGetDeviceInfo(device, CL_DEVICE_PLATFORM,
137  sizeof(cl_platform_id), &platform, NULL);
139  CL_SUCCESS != ocl_status, ocl_status, error_handler,
140  "%s: unable to get platform from device (OpenCL error %d: %s).",
141  CCL_STRD, ocl_status, ccl_err(ocl_status));
142 
143  /* Set context properties using discovered platform. */
144  ctx_props[0] = CL_CONTEXT_PLATFORM;
145  ctx_props[1] = (cl_context_properties) platform;
146  ctx_props[2] = 0;
147 
148  } else {
149 
150  /* If properties parameter is not NULL, use it instead. */
151  ctx_props = (cl_context_properties*) properties;
152  }
153 
154  /* If we got here, everything is OK. */
155  g_assert(err == NULL || *err == NULL);
156  goto finish;
157 
158 error_handler:
159  /* If we got here there was an error, verify that it is so. */
160  g_assert(err == NULL || *err != NULL);
161 
162 finish:
163 
164  /* Return properties. */
165  return ctx_props;
166 
167 }
168 
183 static CCLWrapperInfo* ccl_context_get_cldevices(
184  CCLDevContainer* devcon, CCLErr** err) {
185 
186  return ccl_context_get_info(devcon, CL_CONTEXT_DEVICES, err);
187 }
188 
211 CCL_EXPORT
212 CCLContext* ccl_context_new_wrap(cl_context context) {
213 
214  return (CCLContext*) ccl_wrapper_new(
215  CCL_CONTEXT, (void*) context, sizeof(CCLContext));
216 
217 }
218 
245 CCL_EXPORT
247  const cl_context_properties* properties, CCLDevSelFilters* filters,
248  ccl_context_callback pfn_notify, void* user_data, CCLErr **err) {
249 
250  /* Make sure number ds is not NULL. */
251  g_return_val_if_fail(filters != NULL, NULL);
252  /* Make sure err is NULL or it is not set. */
253  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
254 
255  /* Error reporting object. */
256  CCLErr* err_internal = NULL;
257 
258  /* Array of selected/filtered CCL device wrappers. */
259  GPtrArray* devices = NULL;
260 
261  /* Context wrapper to create. */
262  CCLContext* ctx = NULL;
263 
264  /* Get selected/filtered devices. */
265  devices = ccl_devsel_select(filters, &err_internal);
266  ccl_if_err_propagate_goto(err, err_internal, error_handler);
267 
268  /* Check if any device was found. */
269  ccl_if_err_create_goto(*err, CCL_ERROR, devices->len == 0,
270  CCL_ERROR_DEVICE_NOT_FOUND, error_handler,
271  "%s: no device found for selected filters.",
272  CCL_STRD);
273 
274  /* Create context wrapper. */
275  ctx = ccl_context_new_from_devices_full(properties, devices->len,
276  (CCLDevice**) devices->pdata, pfn_notify, user_data,
277  &err_internal);
278  ccl_if_err_propagate_goto(err, err_internal, error_handler);
279 
280  /* If we got here, everything is OK. */
281  g_assert(err == NULL || *err == NULL);
282  goto finish;
283 
284 error_handler:
285 
286  /* If we got here there was an error, verify that it is so. */
287  g_assert(err == NULL || *err != NULL);
288 
289 finish:
290 
291  /* Free array object containing device wrappers. */
292  if (devices != NULL) g_ptr_array_free(devices, TRUE);
293 
294  /* Return ctx. */
295  return ctx;
296 }
297 
318 CCL_EXPORT
320  const cl_context_properties* properties, cl_uint num_devices,
321  CCLDevice* const* devices, ccl_context_callback pfn_notify,
322  void* user_data, CCLErr** err) {
323 
324  /* Make sure number of devices is not zero. */
325  g_return_val_if_fail(num_devices > 0, NULL);
326  /* Make sure device array is not NULL. */
327  g_return_val_if_fail(devices != NULL, NULL);
328  /* Make sure err is NULL or it is not set. */
329  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
330 
331  /* Array of unwrapped devices. */
332  cl_device_id* cl_devices = NULL;
333  /* Context properties, in case the properties parameter is NULL. */
334  cl_context_properties* ctx_props = NULL;
335  /* Return status of OpenCL function calls. */
336  cl_int ocl_status;
337  /* OpenCL context. */
338  cl_context context = NULL;
339  /* New context wrapper. */
340  CCLContext* ctx = NULL;
341  /* Error reporting object. */
342  CCLErr* err_internal = NULL;
343 
344  /* Allocate memory for devices. */
345  cl_devices =
346  (cl_device_id*) g_slice_alloc(sizeof(cl_device_id) * num_devices);
347 
348  /* Unwrap devices. */
349  for (guint i = 0; i < num_devices; i++)
350  cl_devices[i] = ccl_device_unwrap(devices[i]);
351 
352  /* Get a set of default context properties, if required. */
353  ctx_props = ccl_context_properties_default(
354  properties, cl_devices[0], &err_internal);
355 
356  /* Create OpenCL context. */
357  context = clCreateContext(
358  (const cl_context_properties*) ctx_props, num_devices,
359  (const cl_device_id*) cl_devices, pfn_notify, user_data,
360  &ocl_status);
362  CL_SUCCESS != ocl_status, ocl_status, error_handler,
363  "%s: unable to create cl_context (OpenCL error %d: %s).",
364  CCL_STRD, ocl_status, ccl_err(ocl_status));
365 
366  /* Wrap OpenCL context. */
367  ctx = ccl_context_new_wrap(context);
368 
369  /* If we got here, everything is OK. */
370  g_assert(err == NULL || *err == NULL);
371  goto finish;
372 
373 error_handler:
374  /* If we got here there was an error, verify that it is so. */
375  g_assert(err == NULL || *err != NULL);
376 
377  /* Destroy what was built for the context wrapper. */
378  ccl_context_destroy(ctx);
379  ctx = NULL;
380 
381 finish:
382 
383  /* Free stuff. */
384  ccl_context_properties_default_free(properties, ctx_props);
385  g_slice_free1(sizeof(cl_device_id) * num_devices, cl_devices);
386 
387  /* Return result of function call. */
388  return ctx;
389 
390 }
391 
410 CCL_EXPORT
412  void* filter, void* data, CCLErr** err) {
413 
414  /* Make sure err is NULL or it is not set. */
415  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
416 
417  /* Error reporting object. */
418  CCLErr* err_internal = NULL;
419 
420  /* Context wrapper to create. */
421  CCLContext* ctx = NULL;
422 
423  /* Set of device selection filters. */
424  CCLDevSelFilters filters = NULL;
425 
426  /* Add filter, if any was specified. */
427  if (filter != NULL) {
428 
429  /* What type of filter? */
430  if (ftype == CCL_DEVSEL_DEP) {
431  /* Dependent filter. */
433  &filters, (ccl_devsel_dep) filter, data);
434  } else if (ftype == CCL_DEVSEL_INDEP) {
435  /* Independent filter. */
437  &filters, (ccl_devsel_indep) filter, data);
438  } else {
439  /* Unknown filter type. */
441  error_handler, "%s: Unknown filter type.", CCL_STRD);
442  }
443 
444  }
445 
446  /* Found devices should belong to the same platform. */
448 
449  /* Create a context with selected device. */
450  ctx = ccl_context_new_from_filters(&filters, &err_internal);
451  ccl_if_err_propagate_goto(err, err_internal, error_handler);
452 
453  /* If we got here, everything is OK. */
454  g_assert(err == NULL || *err == NULL);
455  goto finish;
456 
457 error_handler:
458 
459  /* If we got here there was an error, verify that it is so. */
460  g_assert(err == NULL || *err != NULL);
461 
462 finish:
463 
464  /* Return new context wrapper. */
465  return ctx;
466 
467 }
468 
477 CCL_EXPORT
479 
480  ccl_wrapper_unref((CCLWrapper*) ctx, sizeof(CCLContext),
481  (ccl_wrapper_release_fields) ccl_context_release_fields,
482  (ccl_wrapper_release_cl_object) clReleaseContext, NULL);
483 
484 }
485 
505 CCL_EXPORT
507 
508  /* Make sure ctx is not NULL. */
509  g_return_val_if_fail(ctx != NULL, 0);
510  /* Make sure err is NULL or it is not set. */
511  g_return_val_if_fail(err == NULL || *err == NULL, 0);
512 
513  CCLPlatform* platf;
514  cl_uint ver;
515 
516  platf = ccl_context_get_platform(ctx, err);
517  if (platf == NULL) {
518  ver = 0;
519  } else {
520  ver = ccl_platform_get_opencl_version(platf, err);
521  }
522  return ver;
523 }
524 
536 CCL_EXPORT
538 
539  /* Make sure context is not NULL. */
540  g_return_val_if_fail(ctx != NULL, NULL);
541  /* Make sure err is NULL or it is not set. */
542  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
543 
544  CCLPlatform* platf = NULL;
545  CCLDevice* dev = NULL;
546  CCLErr* err_internal = NULL;
547 
548  /* Check if platform wrapper already in context object. */
549  if (ctx->platf != NULL) {
550  /* Yes, use it. */
551  platf = ctx->platf;
552  } else {
553  /* Get platform using device. */
554  dev = ccl_context_get_device(ctx, 0, &err_internal);
555  ccl_if_err_propagate_goto(err, err_internal, error_handler);
556  platf = ccl_platform_new_from_device(dev, &err_internal);
557  ccl_if_err_propagate_goto(err, err_internal, error_handler);
558  /* Keep platform. */
559  ctx->platf = platf;
560  }
561 
562  /* If we got here, everything is OK. */
563  g_assert(err == NULL || *err == NULL);
564  goto finish;
565 
566 error_handler:
567 
568  /* If we got here there was an error, verify that it is so. */
569  g_assert(err == NULL || *err != NULL);
570 
571 finish:
572 
573  /* Return platform wrapper. */
574  return platf;
575 
576 }
577 
596 CCL_EXPORT
598  CCLContext* ctx, cl_mem_flags flags, cl_mem_object_type image_type,
599  cl_uint* num_image_formats, CCLErr** err) {
600 
601  /* Make sure ctx is not NULL. */
602  g_return_val_if_fail(ctx != NULL, NULL);
603  /* Make sure num_image_formats is not NULL. */
604  g_return_val_if_fail(num_image_formats != NULL, NULL);
605  /* Make sure err is NULL or it is not set. */
606  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
607 
608  /* Information object. We use it to keep image format information
609  * in the information table, so that it can be automatically
610  * destroyed when the context is destroyed. */
611  CCLWrapperInfo* info = NULL;
612 
613  /* Variable to return. */
614  const cl_image_format* image_formats = NULL;
615 
616  /* Let's query OpenCL object.*/
617  cl_int ocl_status;
618 
619  /* Get number of image formats. */
620  ocl_status = clGetSupportedImageFormats(ccl_context_unwrap(ctx),
621  flags, image_type, 0, NULL, num_image_formats);
623  CL_SUCCESS != ocl_status, ocl_status, error_handler,
624  "%s: get number of supported image formats (OpenCL error %d: %s).",
625  CCL_STRD, ocl_status, ccl_err(ocl_status));
627  *num_image_formats == 0, CCL_ERROR_OTHER, error_handler,
628  "%s: number of returned supported image formats is 0.",
629  CCL_STRD);
630 
631  /* Allocate memory for number of image formats. */
632  info = ccl_wrapper_info_new(
633  (*num_image_formats) * sizeof(cl_image_format));
634 
635  /* Get image formats. */
636  ocl_status = clGetSupportedImageFormats(ccl_context_unwrap(ctx),
637  flags, image_type, *num_image_formats,
638  (cl_image_format*) info->value, NULL);
640  CL_SUCCESS != ocl_status, ocl_status, error_handler,
641  "%s: get supported image formats (OpenCL error %d: %s).",
642  CCL_STRD, ocl_status, ccl_err(ocl_status));
643 
644  /* Keep information in information table for latter disposal. */
645  ccl_wrapper_add_info((CCLWrapper*) ctx, CL_IMAGE_FORMAT, info);
646 
647  /* If we got here, everything is OK. */
648  g_assert(err == NULL || *err == NULL);
649  image_formats = (const cl_image_format*) info->value;
650  goto finish;
651 
652 error_handler:
653  /* If we got here there was an error, verify that it is so. */
654  g_assert(err == NULL || *err != NULL);
655  *num_image_formats = 0;
656 
657 finish:
658 
659  /* Return requested supported image formats. */
660  return image_formats;
661 }
662 
663 
676 CCL_EXPORT
678  CCLContext* ctx, cl_uint index, CCLErr** err) {
679 
680  return ccl_dev_container_get_device((CCLDevContainer*) ctx,
681  ccl_context_get_cldevices, index, err);
682 }
683 
695 CCL_EXPORT
697 
698  return ccl_dev_container_get_num_devices((CCLDevContainer*) ctx,
699  ccl_context_get_cldevices, err);
700 
701 }
702 
718 CCL_EXPORT
720  CCLErr** err) {
721 
722  return ccl_dev_container_get_all_devices((CCLDevContainer*) ctx,
723  ccl_context_get_cldevices, err);
724 
725 }
726 
void ccl_context_destroy(CCLContext *ctx)
Decrements the reference count of the context wrapper object.
CCLDevice *const * ccl_context_get_all_devices(CCLContext *ctx, CCLErr **err)
Get all device wrappers in context.
#define CCL_OCL_ERROR
Resolves to error category identifying string, in this case an error in the OpenCL library...
Definition: ccl_common.h:324
CCLDevSelDevices ccl_devsel_dep_platform(CCLDevSelDevices devices, void *data, CCLErr **err)
Dependent filter function which only accepts devices of the same platform (the platform to which the ...
CCLPlatform * ccl_context_get_platform(CCLContext *ctx, CCLErr **err)
Get the platform associated with the context devices.
const cl_image_format * ccl_context_get_supported_image_formats(CCLContext *ctx, cl_mem_flags flags, cl_mem_object_type image_type, cl_uint *num_image_formats, CCLErr **err)
Get the list of image formats supported by a given context.
CCLContext * ccl_context_new_from_devices_full(const cl_context_properties *properties, cl_uint num_devices, CCLDevice *const *devices, ccl_context_callback pfn_notify, void *user_data, CCLErr **err)
Creates a context wrapper given an array of CCLDevice wrappers and the remaining parameters required ...
Any other errors.
Definition: ccl_common.h:315
#define ccl_if_err_create_goto(err, quark, error_condition, error_code, label, msg,...)
If error is detected (error_code != no_error_code), create an error object (CCLErr) and go to the spe...
Definition: _ccl_defs.h:91
#define ccl_context_unwrap(ctx)
Get the OpenCL context object.
CCLContext * ccl_context_new_from_filter(CCLDevSelFilterType ftype, void *filter, void *data, CCLErr **err)
Creates a context wrapper using one device filter specified in the function parameters.
Useful definitions used internally by cf4ocl.
Definition of a wrapper class and its methods for OpenCL context objects.
The context wrapper class.
#define ccl_if_err_propagate_goto(err_dest, err_src, label)
Same as ccl_if_err_goto(), but rethrows error in a source CCLErr object to a new destination CCLErr o...
Definition: _ccl_defs.h:120
CCLDevice * ccl_context_get_device(CCLContext *ctx, cl_uint index, CCLErr **err)
Get CCLDevice wrapper at given index.
const char * ccl_err(int code)
Convert OpenCL error code to a readable string.
Definition: ccl_errors.c:118
CCLContext * ccl_context_new_wrap(cl_context context)
Get the context wrapper for the given OpenCL context.
cl_uint ccl_context_get_opencl_version(CCLContext *ctx, CCLErr **err)
Get the OpenCL version of the platform associated with this context.
Context object.
Definition: ccl_common.h:96
cl_bool(* ccl_devsel_indep)(CCLDevice *device, void *data, CCLErr **err)
Independent filter function: Abstract function for filtering one OpenCL device at a time...
Base class for wrappers which contain devices, i.e., CCLPlatform, CCLProgram and CCLContext.
#define CCL_ERROR
Resolves to error category identifying string, in this case an error in cf4ocl.
Definition: ccl_common.h:320
The requested OpenCL device was not found.
Definition: ccl_common.h:308
#define ccl_platform_unref(platform)
Alias to ccl_platform_destroy().
Independent filter, filters one device at a time.
Base class for all OpenCL wrappers.
CCLDevSelDevices ccl_devsel_select(CCLDevSelFilters *filters, CCLErr **err)
Select one or more OpenCL devices based on the provided filters.
void ccl_devsel_add_dep_filter(CCLDevSelFilters *filters, ccl_devsel_dep filter, void *data)
Add a dependent filter to the filter set.
CCLPlatform * ccl_platform_new_from_device(CCLDevice *dev, CCLErr **err)
Get the platform wrapper for the given device wrapper.
#define ccl_device_unwrap(dev)
Get the OpenCL device_id object.
void ccl_devsel_add_indep_filter(CCLDevSelFilters *filters, ccl_devsel_indep filter, void *data)
Add an independent filter to the filter set.
void(* ccl_context_callback)(const char *errinfo, const void *private_info, size_t cb, void *user_data)
A callback function used by the OpenCL implementation to report information on errors during context ...
Invalid function arguments.
Definition: ccl_common.h:302
#define ccl_context_new_from_filters(filters, err)
Create a new context wrapper object selecting devices using the given set of filters.
CCLDevSelDevices(* ccl_devsel_dep)(CCLDevSelDevices devices, void *data, CCLErr **err)
Dependent filter function: Abstract function for filtering several OpenCL devices depending on the av...
GPtrArray * CCLDevSelFilters
A set of independent and dependent device filters.
Dependent filter, filters devices depending on the currently available device choices.
void * value
Object information.
enum ccl_devsel_filter_type CCLDevSelFilterType
Filter type.
Class which represents information about a wrapped OpenCL object.
GError CCLErr
Error handling class.
Definition: ccl_common.h:291
cl_uint ccl_context_get_num_devices(CCLContext *ctx, CCLErr **err)
Return number of devices in context.
#define ccl_context_get_info(ctx, param_name, err)
Get a CCLWrapperInfo context information object.
Device wrapper class.
The platform wrapper class.
CCLContext * ccl_context_new_from_filters_full(const cl_context_properties *properties, CCLDevSelFilters *filters, ccl_context_callback pfn_notify, void *user_data, CCLErr **err)
Create a new context wrapper object selecting devices using the given set of filters.
cl_uint ccl_platform_get_opencl_version(CCLPlatform *platf, CCLErr **err)
Get the OpenCL version of this platform.