-
Notifications
You must be signed in to change notification settings - Fork 4
Overview
This page is obsolete and does not represent the current API correctly. I plan to update the documentation and load it up to http://flyx.github.io/OpenCLAda/. Meanwhile, have a look at the test code, it shows how to use the current API.
OpenCLAda is a thick binding, that is to say, it doesn't just provide the raw C functions in Ada syntax. The major features OpenCLAda adds to the C API are:
- Object orientation
- A class hierarchy of the OpenCL object types
- Automatic reference counting with
Controlled
types - Type safety (obviously, as it's Ada)
- Getter functions for every property of an object instead of one generic function for retrieving all properties
Here's an UML diagram showing the class hierarchy and package organisation of OpenCLAda:
OpenCLAda currently includes most functions of OpenCL 1.0. It does not include support for any extensions; however, I plan to implement the OpenGL interfacing extension. I currently have no plans for implementing other extensions.
OpenCLAda encapsulates the OpenCL object types in an object-oriented class hierarchy (which is code-wise non-existent in the C API). The class hierarchy is depicted above.
The CL_Object
class provides a "="
operator with the usual semantics. Only Platform
and Device
are derived directly from CL_Object
because these are not user-generated run-time objects. All other objects derive from Runtime_Object
. All CL_Object
variables are references to OpenCL objects; that is to say, if you assign an CL_Object
value from one to another variable, they both will point to the same OpenCL object.
Runtime_Object
implements the Adjust
and Finalize
procedures from Ada.Finalization.Controlled
(which is the parent of CL_Object
). These procedures take care of memory management via the reference counting mechanism provided by OpenCL. While Runtime_Object
provides a function Reference_Count
to get the current reference count value, the user doesn't have to take care of deallocating objects he doesn't use anymore - they will be deallocated automatically as soon as the last variable referencing the object reaches its end of life.
As the user does not need to initialize a Runtime_Object
at declaration, it provides an Initialized
function. If this returns false, the variable does not reference an OpenCL object. Using an uninitialized Runtime_Object
with the API will result in an exception.
OpenCL does have quite a few error codes. These are translated into exceptions in OpenCLAda. A lot of erroneous calls to the OpenCL API that result in error codes are prevented by OpenCLAda because of its higher level interface, but of course there is still a lot of stuff the user can do wrong.
Everywhere the C API uses void pointers, OpenCLAda provides generic functions or packages. Take for example this function:
extern CL_API_ENTRY cl_int CL_API_CALL
clSetKernelArg(cl_kernel /* kernel */,
cl_uint /* arg_index */,
size_t /* arg_size */,
const void * /* arg_value */) CL_API_SUFFIX__VERSION_1_0;
The corresponding procedure in OpenCLAda looks like this:
generic
type Argument_Type is private;
Argument_Index : UInt;
procedure Set_Kernel_Argument (Target : Kernel; Value : Argument_Type);
The C API provides one property getter function for every OpenCL object, like this:
extern CL_API_ENTRY cl_int CL_API_CALL
clGetPlatformInfo(cl_platform_id /* platform */,
cl_platform_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0;
OpenCLAda instead provides one getter function per property, eg:
function Profile (Source : Platform) return String;
function Version (Source : Platform) return String;
OpenCL does provide quite a lot of constants. A good part of them are used for the generic property getter functions, so they are hidden in the OpenCLAda backend in favor of specific property getters. The other C constants fall in two categories:
- Constants used as enumeration values. Those are translated into enumeration types in OpenCLAda.
- Constants used for bit vectors. Those are translated into record types with Boolean fields representing the corresponding bit vector.
A special case is the cl_memory_flags
bit vector. It has the following structure:
type Bits58 is mod 2 ** 58;
type Memory_Flags is
record
Read_Write : Boolean := False;
Write_Only : Boolean := False;
Read_Only : Boolean := False;
Use_Host_Ptr : Boolean := False;
Alloc_Host_Ptr : Boolean := False;
Copy_Host_Ptr : Boolean := False;
Reserved : Bits58 := 0;
end record;
Because quite some of these flags are mutually exclusive, the record type is not visible for the user of OpenCLAda. Instead, a type Access_Kind
together with additional Boolean function parameters is used where needed:
type Access_Kind is (Read_Only, Write_Only, Read_Write);
[...]
function Create_Buffer (Context : Contexts.Context;
Mode : Access_Kind;
Size : CL.Size;
Use_Host_Memory : Boolean := False) return Buffer;
OpenCLAda provides that standard vector types of OpenCL; named Typen, where Type is any of {Char, Short, Int, Long, UChar, UShort, UInt, ULong, Float} and n is any of {2, 3, 4, 8, 16}. Basic arithmetic operations on these vector types are available in the generic package CL.Vector_Operations. You have to instantiate it for each type you want to use with it, eg:
package Int2_Operations is new CL.Vector_Operations
(CL.Int, CL."+", CL."-", CL."*", CL."/", CL."<", Range2, CL.Int2);
You do not need to explicitly specify the operations on CL.Int if they are directly visible.