Skip to main content

What is the fastest way to process pixels?

1 reply [Last post]
sylken
Offline
Joined: 2006-02-27
Points: 0

Hi,

I'm experimenting with some basic particle engine and I wanted to know how I can get the best performance.

I've seen some examples using the MemoryImageSource class to be able to process each pixel.
I've also read that the BufferedImage getRGB and setRGB methods are fast, but I don't seem to be getting any perfomance there.

What is the best way to process and draw pixels?

Thanks,
SylKen

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
sunflar
Offline
Joined: 2005-10-28
Points: 0

MemoryImageSource is old 1.1 technology. Access to the pixels is fast, but you have to manually trigger a reload of the data via the ImageProducer/ImageConsumer interface every time you change something. This need for a manual trigger is because the "toolkit images" created from a MemoryImageSource use a batch processing "push" technology.

BufferedImage objects are more immediate in that you can modify the actual pixels that the system uses to copy the image to the screen - there is no batching inherent with the "image source" of the older ImageProducer/ImageConsumer APIs. Depending on how directly you want to access the pixels, BufferedImage offers a number of APIs from convenience level down to the nitty gritty level.

BufferedImage.get/setRGB are the most convenient, but they must use the ColorModel, Raster and SampleModel objects to convert from the 32-bit non-premultiplied ARGB format of their arguments into the format in which the data is actually stored in the BufferedImage. There are a number of internal method calls per call to the top level get/setRGB call that reduce performance, but make access easy.

BufferedImage also lets you get its Raster and ColorModel. From the Raster you can get the SampleModel and DataBuffer. These let you access the pixels more directly. ColorModel controls how color samples are turned into the data samples that are stored in the image. SampleModel describes how the data samples are laid out in memory, and the DataBuffer provides the actual memory where the samples are stored.

There are lots of different variants of each of these objects because we provide the capability of storing data in a wide variety of formats - from packed 32-bit integer ARGB, xRGB, and xBGR to the 3-byte and 4-byte RGB, BGR, and ARGB formats, to the 15 or 16-bit packed formats to the 8-bit INDEXED format.

The good news, though, is that if you pick one of those formats that you would like to access your pixel data in, then the details of the storage are pre-determined so you can just dig down from a BufferedImage to its associated DataBuffer and start changing the pixels directly. The easiest to modify would be the 32-bit packed ARGB or xRGB formats (depending on whether you need alpha or not). The pixels can be loaded and stored using a single integer and unpacking the integer into color components is a simple matter of shifting and masking. Other formats may trade-off space for pixel or color-component access complexity, depending on your needs.

The main drawback of digging down to the DataBuffer of an image is that once we've let you get the actual array that the pixels are stored in, we have no way to track when you change pixels so we can no longer cache a copy of the image on the display card - we have to go back to the source every time we copy the pixels. You may or may not notice the performance drop depending on the size of your images and/or how many times you copy them to a screen destination between each modification. We are working on APIs that will let you have "nearly direct access" to the pixels, but with enough tracking that we know when you've modified the pixels and when we can update our caches. The work-around is to either use higher level APIs that don't require you to fetch the DataBuffer or to manually copy the image into an accelerated destination like a VolatileImage every time you modify it (that copy into a VolatileImage is essentially what we try to do under the covers for you to cache a copy).

Hope that helps!