[Openmcl-devel] Foreign Function Questions

Brent Fulgham bfulg at pacbell.net
Sat Nov 25 10:29:14 PST 2006


Thanks for that (as always) very detailed explanation.  In looking  
over the various incomplete OpenGL offerings, most of them make use  
of the UFFI to bind to either SDL or OpenGL.  I'm not sure if it  
would be better to attempt to port one of these libraries over to  
OpenMCL, or to make use of the native bindings.  Since I prefer  
OpenMCL's close integration with the Aqua and Objective C bindings, I  
would prefer a similar binding for OpenGL.  So perhaps the effort is  
worth it.

The current binding is a thin interface to the underlying C api.  It  
might make sense to provide a Lisp-level library with some  
convenience functions to make interacting with the C core a bit  
easier.  Your function to produce the stack-based raw data for the C  
call would be a good candidate for this, as would the "opengl:with- 
matrix-mode" macro in the example OpenGL that comes with OpenMCL.

I'll see if I can write a few simple helper functions/macros to make  
these steps easier.



On Nov 24, 2006, at 11:15 PM, Gary Byers wrote:

> On Fri, 24 Nov 2006, Brent Fulgham wrote:
>> I have a couple of questions regarding the FFI and interface
>> databases.  Perhaps this is covered in the documentation, but an
>> initial review did not turn up what I was looking for.
>> 1.  Is there a way to get the correct "decorated" names of the FFI
>> functions from the database?  While it's pretty easy (in many cases)
>> to guess from the original C header, I can't always figure out how
>> things like arrays and other pointer types are expected to be passed.
> When dealing with foreign function call arguments and results,  
> OpenMCL's FFI basically deals with:
>  - signed and unsigned integers of width 8/16/32/64
>  - single and double floats
>  - aggregate objects (structures/unions) that're passed by value
>    on some platforms
>  - pointers.
> If you ignore the issue of vector (AltiVec/XMM) types, that's
> pretty much what C deals with.  Note that the difference between
> an array type and a pointer type in C is often pretty subtle,
> and it's often possible to use arrays an pointers interchangably.
> I don't remember whether the interface database stores syntactically
> richer type information; by the time #_ has looked up a foreign
> function definition, everything's boiled down to one of those
> basic types (:signed-halfword, :address, etc.)
>> 2.  I would like to define some materials for the OpenGL FFI
>> interface.  In C, this might look something like:
>>      glMaterialfv(GL_BACK, GL_DIFFUSE, {0.396, 0.74151, 0.69102,  
>> 1.0});
>>      But if I attempt to call it using something like:
>>       (#_glMaterialfv #$GL_FRONT #$_GL_AMBIENT #(0.396D0 0.74151D0
>> 0.69102D0 1.0D0))
>> I get an error:  "> Error: value #<SIMPLE-VECTOR 4> is not of the
>> expected type MACPTR."
>> What's the proper way to declare this in the FFI description?
> Suppose that we wanted to call the C library function #_open, which
> will return a file descriptor (small non-negative integer) or -1  
> (error
> indicator) given a file namestring and an integer which specifies some
> mode flags.  If we did:
> ? (#_open "/etc/passwd" #$O_RDONLY) ; open an existing file
>                                                     ; for reading
> we'd get a similar error (a complaint that the string "/etc/passwd"
> isn't a MACPTR).
> In C, a string (for all intents and purposes; it could be argued that
> C doesn't have a "string" data type, just a few sets of conventions)
> is just the address of a sequence of 8-bit bytes with a #\nul byte
> at the end.
> In Lisp in general (and in OpenMCL in particular), a string is ...
> something else entirely.  In particular, it has some bits (somewhere)
> that say that it's a string, and it probably has some bits (somewhere)
> that say how many elements it contains, as well as some bits (or the
> absence of some bits) that say whether or not it's a SIMPLE-STRING,
> and whether or not it has a fill pointer and other things ... To
> the extent that it has an "address", that address is generally
> determined by the GC and can change at any instruction boundary.
> (There are exceptions to this general rule.)
> What we sort of want to do in order to be able to call #_open is
> to:
> a) allocate a block of non-relocatable memory somewhere.  Since
>    we'll only need that block of memory until we're done calling
>    #_open, a stack would be a good place to allocate it.  The
>    block of memory needs to be of length N+1, where N is the
>    length of the lisp string.
> b) copy the character codes of the characters in the lisp string
>    to successive 8-bit bytes in the memory block.
> c) slap a trailing #\Nul byte on the end of the memory block
> d) pass the address of that memory block as the first argument to
>    #_open.
> This is a common enough idiom that there's a macro that does most
> of it for is (WITH-CSTRS).  If we used WITH-CSTRS when attempting
> to call #_open, as in:
> (with-cstrs ((c-name "/etc/passwd"))
>   (#_open c-name #$O_RDONLY))
> the FFI shouldn't complain and we should get a non-negative
> file descriptor back from the call to #_open.
> Back to your example: I'm not entirely sure that the best lisp
> interface to #_glMaterialfv would involve passing a lisp array
> around, and if it did there might be some question as to whether
> an array of element-type SINGLE-FLOAT should be used or whether
> the interface we'd want should be more general.  Assuming that
> we decided to lisp SINGLE-FLOAT vector around, we'd wind up
> with a similar set of issues as existed in the string case:
> In C, an array of SINGLE-FLOATs is just the address of a block
> of memory that contains some bits that can be interpreted as
> SINGLE-FLOATs (or what C would probably just call a "float").
> In Lisp (especially in OpenMCL), a (VECTOR SINGLE-FLOAT) is something
> else entirely; as in the case of a Lisp STRING, it has a lot of  
> auxiliary information about it encoded in bits that are part of
> the object, and (as in the string case) we can't meaningfully talk
> about the "address" of a (VECTOR SINGLE-FLOAT) in general without
> running into GC issues.
> We'd have to go through essentially the same steps (stack-allocate
> some foreign memory, copy the values in the lisp SINGLE-FLOAT array
> into the foreign memory block, then pass the address of that block
> to #_glMaterialfv).  Doing that would be simpler and less error-prone
> if there was a WITH-FOREIGN-SINGLE-FLOAT-VECTOR (analogous to WITH- 
> CSTRs), but ... there isn't.  If we were going to do a lot of
> this and had thought about if or how a lisp vector was the best
> way to represent the material matrix and had thought about whether
> a specialize vector type should be used or whether we wanted to
> be more general about it, we might find it useful to write
> WITH-FOREIGN-SINGLE-FLOAT-VECTOR.  (We'd also find it easier to
> write if OpenMCL offered some syntactic sugar for dealing with
> foreign arrays; without that, the code looks uglier and is probably
> more error-prone as well.)
> A less-than-general approach that'd do the right thing in this
> particular case would be something like:
> (rlet ((c-float-array (:array :float 4)))
>   ;; We happen to know that a single-float value is 32-bits/4 bytes
>   ;; wide, so we can multiply each array index by 4 to get a byte
>   ;; index.  The FFI could do this for us.
>  (dotimes (i 4)
>    (setf (%get-single-float c-float-array (* i 4))
>          (aref lisp-float-array i)))
>  (#_glMaterialfv #$GL_FRONT #$_GL_AMBIENT c-float-array))
>> Thanks,
>> -Brent
>> _______________________________________________
>> Openmcl-devel mailing list
>> Openmcl-devel at clozure.com
>> http://clozure.com/mailman/listinfo/openmcl-devel

More information about the Openmcl-devel mailing list