Recent

Author Topic: Pascal OpenCL bindings  (Read 18314 times)

AFirebat

  • New member
  • *
  • Posts: 5
Pascal OpenCL bindings
« on: February 10, 2010, 04:03:13 pm »
Hello

I've just finished a unit that implements OpenCL bindings (http://www.khronos.org/opencl/) for FreePascal.

I do not have access to an FTP on which I can upload this unit to submit it via the "contribute" link on the FreePascal.org homepage, so I am instead posting it here, apologies if I got the wrong subforum.

I've tested it on Win32. It theoretically supports Linux, but doesn't "know" the default OpenCL library name for Linux yet. Further notes in the file.

AlmightyFirebat.

Edit - New file further down in topic.
« Last Edit: February 21, 2010, 11:30:59 pm by AFirebat »

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2562
    • havefunsoft.com
Re: Pascal OpenCL bindings
« Reply #1 on: February 21, 2010, 05:11:49 pm »
That's great!

you could also test OpenCL FPC package: http://svn.freepascal.org/svn/fpc/trunk/packages/opencl

and see if there're any mistakes in the existing porting. (note it supports both Windows and OSX).

If you find any you could make a patch for it: http://wiki.freepascal.org/Creating_A_Patch
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

AFirebat

  • New member
  • *
  • Posts: 5
Re: Pascal OpenCL bindings
« Reply #2 on: February 21, 2010, 06:07:14 pm »
The existing package is mostly solid, but with a couple of probably accidental ommisions, specifically:
type: csize_t was not defined, but I just aliased it to PtrUint as that's what it is.
csize_t's corresponding pointer type was also missing. Adding these permitted my (very simple) test program to compile and run as expected.

(Might this be an issue with the "ctypes.pas" unit? It doesn't define size_t correctly either - I'm sure you're already aware, but size_t = PtrUint)

Other points:
My bindings link dynamically, rather than statically - I'm not sure as to which is preferable, but I don't see a difference as I provide an auto-load feature, and use the "DynLibs" unit from the RTL, which works on all supported systems. (that have a concept of dynamic libraries)

My bindings also use the more "Pascal-like" convention of prefixing type names with "T", and I'm considering replacing the last of the C caused type aliasing with direct references to appropiate native Pascal types (eg: size_t would be replaced, rather than just aliased, with PtrUint) but these points are only stylistic, really.

As a last point, my bindings use "var" (pass by reference) parameters in places where I felt, by reading through the specification, it was appropiate, unlike the existing package, which simply uses pointers everywhere, which can look ugly, but again, mostly stylistic.

I will copy the support for MacOSX from that unit into mine, as well as the NVidea specific platform value constant, and look up ATi/AMD's platform specific value from my ATi/AMD headers.

I'd like advice as to whether it is acceptable to create a patch that replaces the unit entirely, or whether convention (or indeed rules) dictate I should work from the existing code. (As my RTL and/or Lazarus directory doesn't contain this unit, I assume it hasn't made it to a final release yet, I'm using FPC 2.4.0, Lazarus 0.9.28.2 - Beta, thus meaning that any code incompatabitlies aren't too important yet?)

Finally: my copy of "gl_cl.h", the OpenCL extension to support copying to/from OpenGL data buffers has last date of modification by Khronos as 27/8/09 - (27th August 2009), and the "cl_gl.pp" unit within the package has its date of creation as 08/04/09 - (8th April 2009), yet there are no differences (that I can see), so I assume the revisions related to C-specific language variant support, and fixing a typo!)
I can't see anything wrong with the cl_gl.pp unit.

AlmightyFirebat

Edit: I've changed my unit to include the various extras as I described previously, the new copy is attatched to this post. I couldn't find the ATi/AMD specific platform value. :(
As it's your package, skalogryz, I was wondering if you'd mind me simply suggesting the unit is replaced? If you'd rather an edit, I will do so, I'll wait until you reply before submitting any patch. :)

Further edit - oops! I uploaded the wrong file!  :-[
I'll make changes then upload an actually fixed version! :-[
« Last Edit: February 21, 2010, 09:39:21 pm by AFirebat »

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2562
    • havefunsoft.com
Re: Pascal OpenCL bindings
« Reply #3 on: February 21, 2010, 07:43:38 pm »
My bindings also use the more "Pascal-like" convention of prefixing type names with "T", and
I'd say "Delphi-like" convention. Of course, any new library developed with FPC/Delphi usually follows the "T"prefix convention, but most of low-level system libraries (especially non-delphi) doesn't follow it.
Since OpenCL is quite low-level stuff, i'd suggest not to add T prefix.

Take OpenGL and OpenAL libraries as the example, they do NOT provide T prefix for the library types.

I'm considering replacing the last of the C caused type aliasing with direct references to appropiate native Pascal types (eg: size_t would be replaced, rather than just aliased, with PtrUint) but these points are only stylistic, really.
That's very questionable. Are you sure your OpenCL bindings would work for x64 too? It would be easier to control types if library is to change in future.
Using C-alias names also makes poring C code easier.

I will copy the support for MacOSX from that unit into mine, as well as the NVidea specific platform value constant, and look up ATi/AMD's platform specific value from my ATi/AMD headers.
Are there ATI headers provided for OpenCL in Windows?

I'm using FPC 2.4.0, Lazarus 0.9.28.2 - Beta, thus meaning that any code incompatabitlies aren't too important yet?)
Please note, that Lazarus is not FPC, and vice versa. Both projects are almost independent. So FPC packages (as OpenCL) doesn't depend on Lazarus versions, and might already be in used by someone.

As it's your package, skalogryz, I was wondering if you'd mind me simply suggesting the unit is replaced? If you'd rather an edit, I will do so, I'll wait until you reply before submitting any patch. :)
I'll review changes later (in the monday). Sorry, don't have much time right now.

Note there're examples provided with OpenCL package. Could you run them with your version of the library?!
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

AFirebat

  • New member
  • *
  • Posts: 5
Re: Pascal OpenCL bindings
« Reply #4 on: February 21, 2010, 08:31:01 pm »
I'll change the types back then, I just prefer it that way. Oh well...

I happen to own an x64 system, I'll test it using the 64-bit edition of ATi/AMD's implementation. They should work.

ATi/AMD OpenCL Implementation homepage here.

I'm aware that FPC and Lazarus are different, hence I specified it was neither in the RTL, nor the Lazarus directory. (as I wasn't sure which it would be included with, as these are the Lazarus forums... I know now  :-[)

I'll further test the examples provided - I don't expect any problems, all of my functions were translated manually from the specification guide.

Finally, no suggestion as to whether the existing static linking is better than my dynamic linking? Does this matter at all?

AlmightyFirebat

Troodon

  • Sr. Member
  • ****
  • Posts: 484
Re: Pascal OpenCL bindings
« Reply #5 on: February 21, 2010, 09:38:36 pm »
From the khronos.org web site: "OpenCL is the first open, royalty-free standard for cross-platform, parallel programming of modern processors found in personal computers, servers and handheld/embedded devices." -- I am not sure I understand this, is there a library to download, for Windows, Mac OS X, Linux? Thanks.
Lazarus/FPC on Linux

AFirebat

  • New member
  • *
  • Posts: 5
Re: Pascal OpenCL bindings
« Reply #6 on: February 21, 2010, 09:49:52 pm »
OpenCL works like OpenGL, it has a specification, and various vendors provide implementations (normally in the form of dynamically or statically linked libraries). For OpenGL, implementations include, but are not limited to, Windows GL (OpenGL32.DLL on most editions of Windows), ATi/AMD (Provided in their drivers), NVidea (also in their drivers), Intel, etc etc.

For OpenCL, implementations include ATi/AMD's Stream, which you should use if you own an ATi/AMD graphics card - Stream Homepage;

NVidia's CUDA implementation - homepage here, which is the better option if you own an Nvidia graphics card.

Other companies probably also have OpenCL implementations - the aim is to provide a way of accelerating (mostly) floating point calculations using GPUs ("graphics cards") and other similar dedicated floating point processors (such as Nvidia's PhysX accelerator) etc.

Simply - pick an implementation that best matches your target hardware, if you intend to distribute, then include code that detects the system's hardware and installs the appropiate implementation and then use the OpenCL specification guide to get started on using OpenCL.

Back to the original topic - I made a major error in uploading the wrong file, so don't expect anything special from the one I uploaded. :-[
I am currently working to make it more in keeping with the existing cl.pp package.

As a note, the existing package doesn't work with ATi/AMD's implementation yet, I'll fix that as well. (Currently generating a hard-to-trace floating point exception)

=====================EDIT=====================
OK, caught up with myself and the uploading mistakes. :-[
Progress:
I have changed my "OpenCL.pas" to be entirely compatible* with the cl.pp package.
My test program, and the similar "clinfo" example within the "cl" package both compile and run on my Vista x64 machine, but as 32-bit binaries, dynamically linking to ATi/AMD Stream. 64-bit testing to come later.

The last example, "basicsample.pas" does compile and run, but generates a SIGFPE during the call to "clBuildProgram". The cause of this is unknown, however, there is a comment in basicsample.pas that notes that "CL_DEVICE_TYPE_CPU" doesn't seem to work on Windows, as I only have access to a CPU (My ATi HD2600 isn't ATi/AMD Stream enabled :( ) I am going to go out on a limb and suggest that the cause is neither my bindings nor the program, but the implementation. (This is backed up by the fact the existing bindings also fail, with not only the same error, but the same ASM at the same location according to Lazarus' debugging features).
It would be appreciated if anyone with an ATi/AMD graphics card in the "Supported Cards" table on this page could download, compile and then run "basicsample.pas" from the FreePascal SVN repository (links earlier in thread) which should then provide some output and shed light on the matter. (If you happen to have any other OpenCL 1.0 compatible device and implementation, that is also fine)

* The remaining issues, of which only #2 is a major concern:
1) Static linking has been replaced by dynamic linking, but this is now transparent to the user.

2) The major issue is that I chose to use "var" parameters in a lot of places where I thought it would be best to (which does include a couple of places where the parameters can be nil, but I didn't feel you would ever call that function in that way, generally where vital info relating to the size of buffers was returned) which means that you get a series of "got XXX expected YYY messages". There is no fix for this, besides changing existing code, or a change of my declarations.

Attatched: New version of OpenCL.txt (should be .pas - is there a reason the forums prevent the uploading of pas files?) which is almost entirely compatible with "cl.pp".
 
AlmightyFirebat

PS: Thank you for being so patient.
« Last Edit: February 21, 2010, 11:30:05 pm by AFirebat »

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2562
    • havefunsoft.com
Re: Pascal OpenCL bindings
« Reply #7 on: February 22, 2010, 02:10:45 am »
I'd like to add, that OpenCL is also available as Framework (system dynamic library) on MacOSX 10.6, no matter the video card used.

The basicsample works in CPU mode with Intel Graphic card on MacBook (with 10.6).

Anyway, I can agree with the proposed changes: Dynamic Linking and using "var" parameters, instead of pointers. But AFirebat, please pay attention to the parameters passed.
If OpenCL docs states, that parameter is option (might be NULL), then it should be passed as a pointer, rather than "var"

thanks,
dmitry
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2562
    • havefunsoft.com
Re: Pascal OpenCL bindings
« Reply #8 on: February 25, 2010, 10:53:59 am »
AFirebat:

1)
csize_t (at ctypes.pp) is already declared correctly as PtrUInt.
see  ctypes.pp, line 78
Code: [Select]
csize_t                = ptruint;
I see no reason to redeclare ctypes in OpenCL header again.

2) Too much types! Imho, the header is too overloaded with useless declarations!
Why should TclAPI be in the inteface section? It's not declared in C header, right?!
There's no clAPI variable in C header as well.

I can see you tried to make the initialization easier, but this made the header harder to understand, since there're declarations to related to OpenCL library itself.

It's also harder to maintain this number of structures.
Let's say someone is willing to extend the header (some functions have been added, in OpenCL x.0). The developer would be necessary to:
1. declare a type TNewOpenCLFunc.
2. add a field to the clAPI structure.
3. declare a global variable that absolutes to the field.
4. add a name to Names array.
5. add a absolute to Pointers array.
It's too much! Sorry, I can't accept it.

Why don't use OpenGL header style? Each function is declared as a global variable of the function type:
Code: [Select]
var
clGetPlatformIDs: function (
  num_entries   : cl_uint;
  platforms     : Pcl_platform_id;
  num_platforms : Pcl_uint
  ): cl_int; extdecl;

procedure LoadCL;
begin
    @clGetPlatformIDs := GetGLProcAddress(LibGL, 'clGetPlatformIDs');
    // a list of functions loading here
    ....
end;

This makes the header smaller in size, cleaner, as well as easier extensibility, since a developer only needs to make 2 steps: 1) declare a function variable and 2) the loading code into LoadCL () function.

Of course, initialization code doesn't not look really neat, but still it's the same effective.
« Last Edit: February 25, 2010, 11:22:47 am by skalogryz »
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2562
    • havefunsoft.com
Re: Pascal OpenCL bindings
« Reply #9 on: February 25, 2010, 11:32:25 am »
3) i'm against raising the exception in initialization section. Such exceptions are uncachable. If OpenCL fails to load, functions should be just "nil". CL_SAFELOADING just doesn't make any sense.

4) I know, "var" parameters are very nice and clean way of coding. But we're interfacing C library, that uses pointers. So, not to loose the flexibility we should use pointers as well, whenever applicable.

for example: http://www.khronos.org/opencl/sdk/1.0/docs/man/xhtml/clGetPlatformIDs.html

platforms, num_platforms parameters are optional and should be passed as pointers to appropriate types.

AFirebat: I've modified your OpenCL.pas and has tested it on OSX 10.6. It works now. Please see the changes, and let me know your thoughts about them.
« Last Edit: February 25, 2010, 12:15:25 pm by skalogryz »
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

AFirebat

  • New member
  • *
  • Posts: 5
Re: Pascal OpenCL bindings
« Reply #10 on: February 25, 2010, 06:57:25 pm »
Replies in the order of your points to avoid quote spam:

Fair enough, it's just such poor practice (to ignore the returned size of a buffer) that I didn't feel like facilitating it.

1) You end up linking to a unit (ctypes) for less than four lines, but if you'd rather link to it then... I translated (as per the OpenGL header, eg: GLInt = integer) the cl_*** types straight to (Free)Pascal's native ones. (To avoid cl_*** = cType; cType = *Native Pascal Type*; )

2) Yes, the header API record should have been in the implementation section, along with a few other bits. I prefer the method (as I generate that through a program (which I've nearly generalised enough for usage by others - I'll add an option for the GL style loading code as output also) from the function type declarations as it looks nicer, and these specs don't change all that often, but consistency with the original and the GL unit is ideal. (I took my approach out of a desire to remove the endless @*Function Variable* := GetProcAddress(...) lines because it's silly to have such a similar task typed out like that, and prefixing a variable with @ on the left side of := doesn't make all that much sense when read either)

3) The exception can go, (I mostly added that because I wasn't sure what would work there...) and just keep LoadOpenCL() returning false if a function isn't loaded, or lose the idea entirely? (I'm trying to create a greater degree of runtime safety)

4) <opinion> It's too ugly! :( </opinion>
If that's how things are done, then fair enough.

Incidentally "basicsample.pas", which is, I presume, a direct translation from a simple example in C, actually has implementation dependent behaviour in it, specifically not specifying a platformID in the call to clGetDeviceIDs which causes ATi/AMD's Stream to return an error code, so that's not very good. :(

Once I can get basicsample working, I will upload it - but that floating point exception just won't go away. :(

All in all, you know more about the "house style" for units within FreePascal than I do, so I'll accept the change in style (The loading code). Thank you for adding the Mac system library name.

EDIT:
The use of {$IFDEF MSWINDOWS} ExtDecl := Stdcall {$ELSE} ExtDecl := CDecl {$ENDIF}
is perhaps a little dodgy as an implementation for some other platform (or an implementation on say, Mac, might use a different calling convention...) - again, up to you, as I've only got a Windows PC at the moment.

AlmightyFirebat
« Last Edit: February 25, 2010, 07:03:08 pm by AFirebat »

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2562
    • havefunsoft.com
Re: Pascal OpenCL bindings
« Reply #11 on: February 26, 2010, 07:12:56 am »
4) <opinion> It's too ugly! :( </opinion>
If that's how things are done, then fair enough.

Incidentally "basicsample.pas", which is, I presume, a direct translation from a simple example in C, actually has implementation dependent behaviour in it, specifically not specifying a platformID in the call to clGetDeviceIDs which causes ATi/AMD's Stream to return an error code, so that's not very good. :(
It's different case here.
cl_platform_id is not actually a pointer, but rather a handle! Handle to OpenCL platform object.

http://www.khronos.org/opencl/sdk/1.0/docs/man/xhtml/clGetDeviceIDs.html
states that
Quote
If platform is NULL, the behavior is implementation-defined

So both, NVidia and OSX opencl allow for this "handle" to be nil, while AMD doesn't allow.

On the other hand, some pointer passed parameter are optional (as stated by the OpenCL standard). So it's safe to pass nil, instead of reference to a variable.


The problem with var/pointer can be worked around easily, using static linking + overloaded function.
Code: [Select]
procedure ProcA(var a: Integer); overload; external; name "ProcA";
procedure ProcA(a: PInteger); overload; external; name "ProcA";
this is cannot be done the same beautiful way for dynamic linking, because it's impossible to have 2 variables with the same name. But you provide wrapper functions:

Code: [Select]
interface

procedure ProcA(var a: Integer); overload;
procedure ProcA(a: Pointer); overload;

implementation

var
  _ProcA: procedure(param: PInteger);

procedure ProcA(var a: Integer);
begin
  _ProcA(@a);
end;

procedure ProcA(a: Pointer); overload;
begin
  _ProcA(a);
end;

 _ProcA:=GetProcAddress('ProcA');
« Last Edit: February 26, 2010, 07:30:20 am by skalogryz »
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

 

TinyPortal © 2005-2018