Software rendering to a Canvas

Hi!

I my trying to see how my pixel seting will perform before I move on with the next part of my software renderer.

I’m not sure if I’ve setup everything right since I’m geting 30fps with a 400x400 pixel area on an my Athlon 1700xp (Java 1.4.2) by simply setting all pixels green at each frame:


for(int i = 0; i < 400*0; i++)
    colorBuffer[i] = 0xFF00AA00;

What I did so far is:

  • extend Canvas
    • setIgnoreRepaint(true);
    • createBufferStrategy(2);
    • bufferStrategy = getBufferStrategy();
  • create my color buffer
    • int[] colorBuffer
  • create a BufferedImage
    • new BufferedImage(400, 400, BufferedImage.TYPE_INT_RGB);

and finally in my render loop:

  • for(int i=0; i<400*400; i++)
    colorBuffer[i] = 0xFF00AA00;
  • bufferedImage.setRGB(0,0,400,400,colorBuffer,0,400);
  • Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
  • g.paintImage(0,0,bufferedImage,null)
  • g.dispose()

Does that look right? How many FPS should I be getting when setting all pixels individually, by using an integer array, and then copying the entire array at once?

Note:
~2800fps: when I just clear the screen

  • using g.fillRec(0,0,400,400)
    ~205fps: once I paint the unchanged BufferImage.
  • using g.paintImage(0,0,bufferedImage,null)
    ~34fps: when I update the BufferImage with my pixel data, and thats without changing the color buffer / integer array itself!
  • using bufferedImage.setRGB(0,0,400,400,colorBuffer,0,400);
    ~31fps: when I set all my pixels (integer array) green
  • using the above for loop

I wouldn’t expect dramatically more. It seems the problem usually comes in the render of the buffer to screen (DirectDraw copy or GDI, something nasty anyway).

The actual writing to the int array is really fast - within 90% of C++ speed at least.

The most efficient way it to set up an ImageProducer/ImageConsumer system.

Theres some info & sample code here, though its centred around software rendering in an applet, but I think its applicable to your case:

http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=2D;action=d isplay;num=1073992902;start=5#5

And:

http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=Tuning;acti on=display;num=1089310877;start=10#10

Hope this helps,

Dom

If you want to do your own rendering to a buffered image and don’t care much about losing a possibility of hardware acceleration for this image, you can get the array of pixels directly by calling BufferedImage.getRaster().getDataBuffer(), casting the data buffer to the appropriate DataBuffer subtype and getting the pixels array with getData().

WOW! I got 100 more fps … from ~32 to ~135 fps! … and thats while modifying all the pixels every frame, with


for(int i = 0, j = getRandom(0,0xFF000000); i < 400*400; i++)
  colorBuffer[i] = 0xFF00AA00+i+j;

What I did is instead of using my own new int[], I got it from the buffered image:


colorBuffer = 
  ((DataBufferInt) bufferedImage.getRaster().getDataBuffer()).getData();

Thanks for the tip trembovetski!

Getting your pixel array directy from the BufferedImage and changing its values is almoust too easy to be true … I hope its not a bug :slight_smile:

Well, everything comes with a price… In this case - once you get a hold on the pixels array, your image will never be hardware accelerated, which may or may not be a concern for you.

For an interesting example of direct pixel manipulation, check out the ZoomyBackground class (developed by Jim Graham, Java2D tech lead) from the Ping demo we’ve published. It works pretty fast, and is very pretty =)
https://ping.dev.java.net/

Interesting demo… but it needs some attention :slight_smile: :


Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_UNSIGNED 22050.0 Hz, 8 bit, mono, 1 bytes/frame,  is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_UNSIGNED 11127.0 Hz, 8 bit, mono, 1 bytes/frame,  is supported.
Can't load sound due to: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
Exception in thread "Thread-10" java.lang.NullPointerException
      at ping.SoundFactory.playClip(SoundFactory.java:116)
      at ping.SoundFactory.playPaddleHitSound(SoundFactory.java:107)
      at ping.Collider.intersect(Collider.java:215)
      at ping.Ball.processCollisions(Ball.java:126)
      at ping.DynamicGameObjects.updatePosition(DynamicGameObjects.java:75)
      at ping.Ping.run(Ping.java:142)
      at java.lang.Thread.run(Thread.java:595)

On SuSE 9.1
KDE 3.2.1
Kernel 2.6.5-7.111-bigsmp
i686

Tsk-tsk-tsk… Bad JavaSound, bad [insert a mental picture of JavaSound’s nose being pushed into a fresh exception]

If the exception persists, you can turn off sound with ‘s’ key…