[plt-scheme] Byte Swapping Bitmap Performance

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Wed Aug 5 08:21:00 EDT 2009

At Mon, 3 Aug 2009 11:28:49 -0700, Sam Phillips wrote:
> Except that the bytes from cairo_image_surface_get_data come back as
> BGRA, and I have to do a byte swapping operation before setting the
> pixels in the bitmap-dc.  Which adds about a second to each screen draw.
> Is there a faster way to do this that I'm missing?

1 second sounds like a long time. Can you show the code that you're
using for the swap?

I tried

 (define (rgba->argb src)
   (let* ([len (bytes-length src)]
          [dest (make-bytes len)]) ; could be just src to overwrite
     (for ([i (in-range 0 len 4)])
       (let ([r (bytes-ref src i)]
             [g (bytes-ref src (+ i 1))]
             [b (bytes-ref src (+ i 2))]
             [a (bytes-ref src (+ i 3))])
         (bytes-set! dest i a)
         (bytes-set! dest (+ i 1) r)
         (bytes-set! dest (+ i 2) g)
         (bytes-set! dest (+ i 3) b)))

which swaps a byte string representing a 1024x768 area in about 0.1
seconds on my machine.

The following version is about twice as fast, because it uses
`bytes-copy!' to shift the RGB part and then a loop to patch the A

 (define (rgba->argb2 src)
   (let* ([len (bytes-length src)]
          [dest (make-bytes len)])
     (bytes-copy! dest 1 src 0 (sub1 len))
     (for ([i (in-range 0 len 4)])
       (let ([a (bytes-ref src (+ i 3))])
         (bytes-set! dest i a)))

Allocation of the new byte string account for about 1/3 of the time for
that second version. So, if it's ok to update the array:

 (define (rgba->argb! src)
   (let* ([len (bytes-length src)]
          [dest src]
          [last (bytes-ref src (sub1 len))])
     (bytes-copy! dest 1 src 0 (sub1 len))
     (for ([i (in-range 0 (- len 4) 4)])
       (let ([a (bytes-ref src (+ i 4))])
         (bytes-set! dest i a)))
     (bytes-set! dest (- len 4) last)))

which takes about 0.025 seconds on my machine for a 1024x768x4 byte

It looks like an implementation of `rgba->argb!' in C would be about 10
times as fast as that last version.

Posted on the users mailing list.