[Openmcl-devel] Multi-dimensional foreign memory array

Gary Byers gb at clozure.com
Sat Mar 5 23:06:13 UTC 2005



On Sat, 5 Mar 2005, nrms wrote:

> Is it possible to copy a multi-dimensional array to foreign memory?
> Probably this is quite obvious,  but I am rather new to lisp and the
> examples I found copy only 1-dimensional arrays to foreign memory (I
> looked at the rubix example). I want to call  the Opengl function
> glDrawPixels and the last parameter it gets is something like
>
> GLubyte checkImage[checkImageHeight][checkImageWidth][3]

This example happens to be a little more complicated than some others
could be: depending on various GL parameters (glPixelStore*, etc),
a GL pixmap may have its scan lines (the rows) padded out to satisfy
alignment constraints.  Let's ignore that issue for the time being,
and assume that we're just trying to enforce byte-alignment and that
we're telling #_glDrawPixels that the pixmap has format #$GL_RGB and
type #$GL_UNSIGNED_BYTE and we've set the glPixelStore* parameters
to indicate that everything's "packed" with no scan-line padding.
GL will interpret the pixel data as a linear sequence (a vector)
of unsigned bytes whose values are:

the blue component of the pixel at height = 0, width = 0 ; (aref x 0 0 0)
the green component of the pixel at height = 0, width = 0 ; (aref x 0 0 1)
the red component of the pixel at height = 0, width = 0 ; (aref x 0 0 2)
the blue component of the pixel at height = 0, width = 1 ; (aref x 0 1 0)
the green component of the pixel at height = 0, width = 1 ; (aref x 0 1 1)
the red component of the pixel at height = 0, width = 1 ; (aref x 0 1 2)
...
the blue component of the pixel at height = 1, width = 0 ; (aref x 1 0 0)
the green component of the pixel at height = 1, width = 0 ; (aref x 1 0 1)
the red component of the pixel at height = 1, width = 0 ; (aref x 1 0 2)
the blue component of the pixel at height = 1, width = 1 ; (aref x 1 1 0)
the green component of the pixel at height = 1, width = 1 ; (aref x 1 1 1)
the red component of the pixel at height = 1, width = 1 ; (aref x 1 1 2)
...

This particular way of ordering the elements of a multidimensional array
in memory - where the last index varies most rapidly - is often called
"row-major order", and happens to be the way that C (and, in general,
Common Lisp) stores arrays in memory.  (Fortran arrays are stored in
"column-major" order, and there are certainly other possibilities;
just to confuse the issue, I believe that it's the case that OpenGL
sometimes wants array parameters to be Fortan-style column-major arrays.)

I said that Common Lisp "in general" uses row-major order; recall that
CL arrays can be displaced to (share storage with) other CL arrays in
some cases (and if this is explicitly requested via options to MAKE-ARRAY).
If displacement isn't specified when a multidimensional array is created,
the order of its elements in memory isn't specified (though you can
use the CL function ROW-MAJOR-AREF to access those elements in row-major
order.)

So, if we had:

(defparameter *check-image-height* 10)
(defparameter *check-image-width* 10)
(defparameter *check-image*
   (make-array (list *check-image-height* *check-image-width* 3)
              :element-type '(unsigned-byte 8)))

(defun copy-unsigned-byte-array-to-foreign-memory (array pointer)
  (dotimes (i (array-total-size array))
    (setf (%get-unsigned-byte pointer i)
          (row-major-aref array i))))

where "pointer" is a foreign pointer of at least (array-total-size array)
bytes.


>
> I would like to do this in a rather clean way. Maybe someone has an
> example I missed.

Well, that's fairly clean, and probably OK performance-wise if the
array's fairly small.  (There are all kinds of complicated issues
involved in other cases, but I think that this should get you
started.)

>
> Any hints appreciated.
>
> Nils
>



More information about the Openmcl-devel mailing list