Skip to content

Latest commit

 

History

History
128 lines (100 loc) · 6.85 KB

opencl-interop.md

File metadata and controls

128 lines (100 loc) · 6.85 KB

Interoperability with OpenCL

{{#include interop_excerpts.md:1:4}}

ArrayFire manages its own context, queue, memory, and creates custom IDs for devices. As such, most of the interoperability functions focus on reducing potential synchronization conflicts between ArrayFire and OpenCL.

Basics

{{#include interop_excerpts.md:6:7}}

Function Purpose
Array::new_from_device_ptr Construct an ArrayFire Array from cl_mem
Array::device_ptr Obtain a pointer to the device memory (implies lock)
Array::lock Removes ArrayFire's control of a device memory pointer
Array::unlock Restores ArrayFire's control over a device memory pointer
get_platform Get ArrayFire's current cl_platform
get_device Gets the current ArrayFire device ID
get_device_id Get ArrayFire's current cl_device_id
set_device_id Set ArrayFire's device from a cl_device_id
set_device Switches ArrayFire to the specified device
get_context Get ArrayFire's current cl_context
get_queue Get ArrayFire's current cl_command_queue
get_device_type Get the current DeviceType

Note that the pointer returned by Array::device_ptr should be cast to cl_mem before using it with OpenCL opaque types. The pointer is a cl_mem internally that is force casted to pointer type by ArrayFire before returning the value to caller.

Additionally, the OpenCL backend permits the programmer to add and remove custom devices from the ArrayFire device manager. These permit you to attach ArrayFire directly to the OpenCL queue used by other portions of your application.

Function Purpose
add_device_context Add a new device to ArrayFire's device manager
set_device_context Set ArrayFire's device from cl_device_id & cl_context
delete_device_context Remove a device from ArrayFire's device manager

Below we provide two worked examples on how ArrayFire can be integrated into new and existing projects.

Adding custom OpenCL kernels to an existing ArrayFire application

By default, ArrayFire manages its own context, queue, memory, and creates custom IDs for devices. Thus there is some bookkeeping that needs to be done to integrate your custom OpenCL kernel.

If your kernels can share operate in the same queue as ArrayFire, you should:

  1. Obtain the OpenCL context, device, and queue used by ArrayFire
  2. Obtain cl_mem references to Array objects
  3. Load, build, and use your kernels
  4. Return control of Array memory to ArrayFire

Note, ArrayFire uses an in-order queue, thus when ArrayFire and your kernels are operating in the same queue, there is no need to perform any synchronization operations.

This process is best illustrated with a fully worked example:

{{#include ../../opencl-interop/examples/custom_kernel.rs}}

If your kernels needs to operate in their own OpenCL queue, the process is essentially identical, except you need to instruct ArrayFire to complete its computations using the sync function prior to launching your own kernel and ensure your kernels are complete using clFinish (or similar) commands prior to returning control of the memory to ArrayFire:

  1. Obtain the OpenCL context, device, and queue used by ArrayFire
  2. Obtain cl_mem references to Array objects
  3. Instruct ArrayFire to finish operations using sync
  4. Load, build, and use your kernels
  5. Instruct OpenCL to finish operations using clFinish() or similar commands.
  6. Return control of Array memory to ArrayFire

Adding ArrayFire to an existing OpenCL application

{{#include interop_excerpts.md:9:15}}

  1. Instruct OpenCL to complete its operations using clFinish (or similar)
  2. Instruct ArrayFire to use the user-created OpenCL Context
  3. Create ArrayFire arrays from OpenCL memory objects
  4. Perform ArrayFire operations on the Arrays
  5. Instruct ArrayFire to finish operations using sync
  6. Obtain cl_mem references for important memory
  7. Continue your OpenCL application

ArrayFire's memory manager automatically assumes responsibility for any memory provided to it. If you are creating an array from another RAII style object, you should retain it to ensure your memory is not deallocated if your RAII object were to go out of scope.

If you do not wish for ArrayFire to manage your memory, you may call the Array::unlock function and manage the memory yourself; however, if you do so, please be cautious not to call clReleaseMemObj on a cl_mem when ArrayFire might be using it!

Given below is a fully working example:

{{#include ../../opencl-interop/examples/ocl_af_app.rs}}