The Miasma applet is a modification of the Plasma applet. All the modifications are released into the public domain.
The original Plasma applet can be found here:
http://rsb.info.nih.gov/plasma/
The main changes I made are:
- producer-thread does not outrun consumer (drawing) thread
- horizontal scaling is now correct, according to scale factor
- controllable: priority, drawing, delivery, filtering, pixel-type
- an accurate average frame-rate is calculated and shown
- frame-rates are shown using Applet.showStatus()
At high frame-rates, the cost of drawing the frame-rate display in the original Plasma becomes significant. That is, Plasma is measurably faster if it doesn't show frame-rate. In a benchmark, this is poor. By changing to Applet.showStatus(), the cost of updating the frame-rate is amortized over more frames as the frame-rate increases, so it consumes less, percentage-wise.
The average frame-rate can be calculated over a configurable period of time. As with most averaging, smaller periods are more volatile.
Some of the code I changed from Plasma was just to help me understand what it was doing. For example, it was not clear to me what the palette-filling code was doing, so I dissected it and recoded it.
To better see whether RGB or palette pixels were being drawn, I made the RGB display a red/green image instead of a red/blue one. Red/green is not as aesthetically pleasing as red/blue, but so what. Benchmarks don't have to be aesthetically pleasing.
I changed some code to more efficiently iterate during the pixel calculation. Mostly I was curious what kind of speed gains could be had there. This has the visual effect of "reversing" the animation, but since I'm not trying to exactly emulate Plasma, so what. If exact Plasma emulation was needed, the sine-wave lookup tables or stepping variables could be calculated differently, and the animation would be identical to Plasma.
Finally, I did not fix all of Plasma's flaws, only the most egregious ones. Miasma itself can be improved.
I did nothing with Plasma2, which is a completely different beast. In particular, it uses a different pixel production algorithm, so comparing Plasma to Plasma2 lies somewhere between unwise and misleading. There may be some relevance, but it's hard to tease out exactly what it is. Furthermore, Plasma2 shows nothing that Plasma can't show, so why does Plasma2 exist at all?If you want, feel free to modify Miasma to do what Plasma2 does. It should be easy.
I'M NOT INTERESTED IN WHAT RESULTS YOU GET ON YOUR MACHINE. Don't send me Miasma results, because I'm not interested in how fast or slow your machine/JVM/video-card is.This may be hard to understand, considering how many changes I made to Plasma. But I didn't do Miasma as an inter-platform comparison benchmark. I did it to help developers identify and understand the individual costs of doing animation with a MemoryImageSource and a produced Image. That is, I did Miasma mainly as an aid to understanding exactly what contributes to the speed of a particular animation algorithm.
The other reason I did Miasma, and published it, is to show that writing even a simple benchmark is not as easy as measuring the frame-rate of a simplistic animation program. In short, the benchmark itself must not have weaknesses that invalidate its own measurements. I think Plasma is fatally flawed in that respect, and Miasma simply demonstrates that fact. Making a measurement is easy. Making a VALID measurement may not be.
There are other ways to do animation, and other forms of Image that are faster (often MUCH faster), so most of what Plasma or Miasma does is moot or obsolete, unless you're limited to JDK 1.1. Even on JDK 1.1, there are other ways of doing animation, and Miasma/Plasma does not represent the only possible solution, nor even necessarily the best.
If you disagree with my conclusions about Plasma, feel free to ignore them. Also feel free to improve on Plasma yourself, or improve on Miasma.
The different parameters to the Miasma applet control the following things:
- name=showfps
A boolean controlling whether frame-rates are shown or not. As a benchmark, it's useless without frame-rates, but maybe you like it for its aesthetic appeal.- name=avg
A number of seconds over which to calculate the average frame-rate. This is calculated to the nearest resolvable millisecond, and shown to the nearest 1/10 second.- name=scale
An integer scale-factor. The underlying image is produced at 1/scale, and is drawn on the screen scaled up by the scale factor. In general, the scale-factor should evenly divide into both the height and width, so the platform can scale the image best.- name=draw
A boolean controlling whether the delivered image is drawn or not. Setting this to false will tell you the maximum frame-rate possible, as if drawing the image took no time at all. Doing this can help you gauge exactly how much the overall frame-rate depends on calculation-speed and how much on drawing-speed. Very revealing.- name=deliver
A count of how many images will be delivered. Set to a positive number, say 500 or so, then 500 images will be calculated and delivered (and drawn if 'draw' is true). The 501st image will be calculated, but not delivered. That is, after 500 images the 500th image will be redrawn ever after. The purpose of this is to compare the difference between drawing alone vs. delivering and drawing new images. That is, between doing animation by flipping through existing images vs. calculating a new image for each frame. On some platforms, there may not be a difference.
Set to a negative number, billions of images will be delivered, effectively delivering all images all the time.- name=filter
A boolean controlling whether scaling is done by drawImage() itself, or by a ReplicateScaleFilter. This determines how many pixels are in the image actually drawn. The effects are often revealing.
Exercises:
1) With scale=1, measure unfiltered and filtered frame-rates. Explain any difference.
2) With scale=10, measure unfiltered and filtered frame-rates. Explain any difference.- name=rgb
A boolean controlling whether RGB (int) or palette (byte) pixels are delivered and drawn. Both sizes of pixels are always calculated, since early testing showed little performance difference of one vs. both. By always calculating both sizes of pixels, the pixel-calculation's contribution is normalized (equal regardless of which is display).- name=sync
A boolean controlling whether the pixel-producing thread is coordinated (synchronized) with the image-drawing thread. This has a drastic effect on animation jerkiness. It can have a significant effect on speed, too. When false, the pixel-producing thread over-produces images, which are never drawn. This is usually considered a bad idea.- name=pri
A number 1-10 for the thread priority. Had little effect in my testing, but YMMV.