Sign in to follow this  
thejavagamer

Per Pixel Rendering

Recommended Posts

Hi, I'm making a game kind of similar to World of Sand (http://www.onemorelevel.com/worldofsand.php) where all the objects will be particles the size of a pixel, so I plan on rendering it pixel by pixel. The problem I'm running into is right now without anything moving and in a 640x480 window I'm getting 50fps tops (with a pretty fast processor) and I know that things will slow down a lot once I start adding physics. Here's a snippet of my current rendering code which should give a reasonable idea about what I'm doing: http://pastebin.com/f21628542 At the moment I'm using Java, though if I could significantly speed things up by switching to C++ then that's possible, though I would prefer to stay with Java though. Anyways, I'm pretty sure I've narrowed down the slowness to setRGB, but I'm not sure what would be better to use. I can certainly get all the pixel data as an array first if there's a way to set all of the pixels at once from one (I think this is possible using getRaster). Also, is there any way I can offload some of this to the graphics card? I feel like there should be a really fast way to do this since I'm determining what all the pixels should be myself and the computer just has to display them. Anyways, any help would be appreciated, I really need to get this much faster since I think the physics I hope to implement are going to be rather CPU-intensive.

Share this post


Link to post
Share on other sites
I understand that I should be doing that, but can you give me any direction as to how? What's the best way to access the graphics card in Java? Will the built-in Java2D stuff work, do I need to use JOGL or some other OpenGL binding?

Share this post


Link to post
Share on other sites
Not the fastest, but certainly quick and dead simple, GDI has the CreateDIBSection() function that you can use to work with individual pixels.

You get a pointer to the data, making changes is fast and simple. 640x480 will be a cakewalk.

Share this post


Link to post
Share on other sites
i would try have a precreated array of pixels which is what you actually work on and you render with that instead of setting one pixel at a time

might want to look into this function

g.drawRGB(int[] rgbData, int offset, int scanlength, int x, int y, int width, int height, boolean processAlpha)

Another option if that doesn't work is creating a mutable image from an array of pixels ( just like before ) and drawing that image

http://java.sun.com/j2se/1.4.2/docs/api/java/awt/image/MemoryImageSource.html

Share this post


Link to post
Share on other sites
Remaining cross-platform is a must so GDI is out.
drawRGB looks like that's only in java for micro devices like cellphones so that's out, MemoryImageSource doesn't look bad though, however it seemed simpler to set up a raster once I found a nice code sample at http://www.exampledepot.com/egs/java.awt.image/Mandelbrot2.html?l=rel . My new code is now:
http://pastebin.com/f31e1b4ff
Where generateColorModel generates a an IndexColorModel which has all 3 colors my game is currently using.
While this certainly works at 640x480 all the way up to 100fps on my computer, I'm wondering if there's not some hardware acceleration I can incorporate to get it even faster. If possible I'd like to be able to run this at 1280x960 while maintaining at least 50fps. I'll start tweaking my benchmarking code to see which part is taking the longest, but any suggestions as how to better incorporate my graphics card are certainly welcome.
Also, thanks to everyone who's contributed thus far.

Share this post


Link to post
Share on other sites
Alright, benchmarking shows the only significant amount of is spent on making the pixel array. It's taking on average 7ms to create it on 640x480. Isn't that quite a bit?
I think most of it has to do with requesting data from the particles array. It drops down to 1ms or less if I just pretend that every pixel is black. I think the slowdown might be due to particles being shared between threads (my physics thread will act on it and my rendering thread just renders it). I'll try cloning the array before I start working on it.

Share this post


Link to post
Share on other sites
if that code is happening each frame, your doing far too much

first of all,
byte[] pixels = new byte[width * height];
should be created once and reused

can you avoid doing all that junk at the bottom of the code
and just use the MemoryImageSource technique?

as for the double for loop with the switch in it [ahhh!]
you can at least get rid of the switch be having the particle know what color it is ahead of time [ more memory but you can get rid of the switch ]

Also the probably best solution would be getting rid of the double for loop copy code entirely by making the particle update code directly edit the pixel array as they move around

at least that's what i'd try

Share this post


Link to post
Share on other sites
I was thinking by making the pixel array each frame I could possibly have the window resize and still work, but that's really not necessary.
Also, I didn't realize MemoryImageSource was so much more efficient, definitely switching over to that.

The switch statement is those for loops isn't very useful, but removing it didn't really save me any speed so that's why I've kept it in, but I can certainly remove it for now.

I'll look into having the physics code update the pixel array. I could certainly save on speed if I only changed pixels that changed, but the problem is the view is centered on the player, so if the player moves everything else does relative to him. I could probably get around that by rendering the whole particles array and just rendering the section centered on the player, but I think that would probably take a lot more time.

Also, from discussions I've had on IRC channels shaders have been mentioned a lot. If I switched over to JOGL could I possibly use shaders to offload anything to the graphics card?
Also, thanks for all your help thus far bladeofodinx

Share this post


Link to post
Share on other sites
I must be using MemoryImageSource wrong because my framerate went from not great to terrible. Do I need to create the image every frame or will the image update itself every time I call newPixels? If I do need to create the image every frame then what am I doing so wrong that makes everything so slow?
Here most of my current render loop code, any idea how to fix it?
http://pastebin.com/d46734168
Just realized I still forgot to remove the switch statement. Either ways that can't be responsible for this, all of the sudden slowdown is in section 4 & 5.

Share this post


Link to post
Share on other sites
Drawing pixels like that will probably never be all that fast, especially in Java. 1280x960 is not a small image, and getting any quality graphics at that resolution in software can be less than trivial, even in optimized C++. If you can do it with JOGL and GLSL shaders, then that could make it much much faster. What exactly are you trying to achieve?
It should definitely be possible to do with OpenGL, but how complicated it will be depends a lot on what you need to do.

Share this post


Link to post
Share on other sites
I'm trying to achieve a game like World of Sand (URL in my first post), but more complex. Basically other than the player every object will be one pixel large. I'll have physics and things interacting with each other and the player. Need any more details? If there's a way to render more efficiently I'd certainly be open to it, but as far as I can tell this has to be done pixel by pixel.

Share this post


Link to post
Share on other sites
I'm pretty sure that there would be more CPU overhead involved in sending draw commands to the GPU than there would be if you just locked a bitmap and wrote to it as a large linear array.

Unless you can fit your entire simulation in a GPGPU implementation.

[Edited by - Nypyren on December 25, 2009 7:12:53 PM]

Share this post


Link to post
Share on other sites
Doing everything on the GPU will of course be optimal, but I think that glTexSubImage2D might give better performance than normal images too (should give close to optimal pixel transfers to the graphics card, though of course slower than actually keeping everything on the GPU in the first place).
You might not need it though. I tried a MemoryImageSource method, and I get over a hundred FPS for 1280x960.

import java.awt.Frame;
import java.awt.Image;
import java.awt.Graphics;
import java.awt.image.MemoryImageSource;
import java.awt.image.DirectColorModel;

public class asdf {
public static void main(String[] args) {
Test test = new Test();

test.run();
}
};

class Test extends Frame {
private int mWidth;
private int mHeight;
private int[] mPixels;

private MemoryImageSource mImgSource;
private Image mImage;

private Graphics mGraphics;

public Test() {
super("Test");

mWidth = 1280;
mHeight = 960;

mPixels = new int[mHeight*mWidth];

setUndecorated(true);
setSize(mWidth, mHeight);
setVisible(true);

mImgSource = new MemoryImageSource(mWidth, mHeight, new DirectColorModel(24, 0xff0000, 0xff00, 0xff), mPixels, 0, mWidth);
mImgSource.setAnimated(true);

mImage = createImage(mImgSource);

mGraphics = getGraphics();
}

void updateImage() {
for(int i=0;i<mHeight;++i) {
int c = (int)(Math.random() * 9155351.0);

for(int j=0;j<mWidth;++j)
mPixels[i*mWidth+j] = (c += 333);
}
}

public void run() {
long lastTime = System.currentTimeMillis();
int currentFrame = 0;
int lastFrame = 0;

while(true) {
updateImage();

mImgSource.newPixels();
mGraphics.drawImage(mImage, 0, 0, null);

++currentFrame;
long currentTime = System.currentTimeMillis();
if(currentTime-lastTime > 1000) {
long fps = (1000 * (currentFrame - lastFrame)) / (currentTime - lastTime);
System.out.println("FPS: " + fps);
lastTime = currentTime;
lastFrame = currentFrame;
}
}
}
};

Share this post


Link to post
Share on other sites
out of random interest i tried making my own and this is what i made
I found it to be on the slow side....with the for loop causing a big slow down.
I think i'm going to blame java slowness on this abit.
my fps was around
2200 for res:200x200
390: for res:640x480
80: for res:1260x870

I say try to avoid setting all pixels all the time OR greatly reduce the amount of pixels [ via graphically scaling up or something ]



import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;


import javax.swing.JApplet;
import javax.swing.SwingUtilities;
import javax.swing.JLabel;

import java.awt.image.*;

import java.awt.Canvas;
import java.awt.Graphics2D;
import java.awt.Dimension;
import java.awt.image.BufferStrategy;
import java.applet.Applet;


public class PixelRenderer extends Applet implements Runnable
{
private Thread mainthread;
private Image gfxbuffer;
private int gfxlastwidth = -1;
private int gfxlastheight = -1;

private BufferStrategy bufferStrategy;
private Canvas drawArea;/*Drawing Canvas*/


public void init()
{
drawArea = new Canvas();
setIgnoreRepaint(true);

}

public void start()
{
if (mainthread == null)
{
mainthread = new Thread(this);
}
lasttime = System.currentTimeMillis();
fps_timer = lasttime;
mainthread.start();
}

// Executed whenever the browser leaves the page containing the applet.
public void stop()
{
mainthread = null;

}

public void run()
{
game_init();
drawArea.setSize(new Dimension(getWidth(),getHeight()));
game_resize(getWidth(),getHeight());
add(drawArea);
drawArea.createBufferStrategy(2);
bufferStrategy = drawArea.getBufferStrategy();

//Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

while (true)
{

if ( drawArea.getWidth() != getWidth() || drawArea.getHeight() != getHeight() )
{
drawArea.setSize(getWidth(),getHeight());
bufferStrategy = drawArea.getBufferStrategy();

game_resize(getWidth(),getHeight());
}

game_update();
// repaint();

Graphics g = bufferStrategy.getDrawGraphics();
game_render( g );
g.dispose();

if(!bufferStrategy.contentsLost())
{
//Show bufferStrategy
bufferStrategy.show();

}



}
}

//=====================================

int[] pixels;
int pixel_width;
int pixel_height;

long lasttime;
long fps_timer;
long fps_count;
long fps_lastvalue;

MemoryImageSource dynamic_source;
Image dynamic_image;

public void game_init()
{
}

public void game_resize(int w, int h)
{
pixel_width = w;
pixel_height = h;
pixels = new int[w*h];
dynamic_source = new MemoryImageSource(w, h, pixels, 0, w);
dynamic_source.setAnimated(true);
dynamic_source.setFullBufferUpdates(true);
dynamic_image = createImage(dynamic_source);
}

public void game_update()
{
long curtime = System.currentTimeMillis();
long diftime = curtime - lasttime;
lasttime = curtime;

fps_count++;
if ( curtime - fps_timer >= 1000 )
{
fps_lastvalue = (long) ( (float)1000*fps_count / (float)((curtime - fps_timer)) );
fps_timer = curtime;
fps_count = 0;
}

}

public void game_render(Graphics g)
{

g.setColor(Color.black);
g.fillRect(0,0,getWidth(),getHeight());



//change the pixels array
//int pixelindex = 0;

for (int pixelindex=0;pixelindex<pixel_height*pixel_width;pixelindex++)
//while (pixelindex<pixel_height*pixel_width)
{
/*
pixels[pixelindex] = (255 << 24) |
(((int)(255*Math.random())) << 16) |
(((int)(255*Math.random())) << 8) |
(((int)(255*Math.random())) << 0) ;
*/

pixels[pixelindex] = (255 << 24) |
( (255) << 16) |
( (0) << 8) |
( (0) << 0) ;
//pixelindex++;
}

//let the dynamic image stuff know that the pixels have been changed
dynamic_source.newPixels();
g.drawImage(dynamic_image, 0, 0, null);


g.setColor(Color.yellow);
g.drawString( "size:"+this.getWidth()+","+this.getHeight()+ " fps:"+fps_lastvalue,50, 50);


}




}



Share this post


Link to post
Share on other sites
Hmmm... now I'm even more confused. On my (what I'd assume is relatively fast) computer Erik Rufelt's code runs at ~80fps while bladeofodinx's runs at 55-60fps when both of them are set to 1280x960. My code isn't running nearly as well with newPixels() taking 130+ ms and drawing the image taking 20+ ms (according to my in-code benchmarking stuff).
My new code (including lots of ugly bits I've commented out) is at: http://pastebin.com/f7a5f3a90
Any reason why it's running so absurdly slow?
Also, I see that the double for loop should be the biggest slowdown so I think once I get my rendering fixed I could certainly have pixels array managed by my physics thread.

Finally, it's certainly not too late for me to completely start over again. So long as I can compile it for every platform I have no problems working with C++ if it'll give me the speed I need. However, I'm rather new to working with things so low-level and have no idea how to unload most of my processing to the graphics card, could you give me any direction?
Thanks for everything Erik Rufelt and bladeofodinx

Share this post


Link to post
Share on other sites
I'm not sure, but you have like strategy.getDrawGraphics(), g.dispose(), sync() etc. which might take some time, though I don't think it should be much.

If it's all in the loop, then what are the values of top/bottom/left/right?
Do you have one particle for each pixel on the screen?
What does getType() do?
What's the color model, is it an indexed color model (I guess it must be since you do everything in bytes)?
When I tried indexed color it got a bit faster, but not by very much. If you simply make a loop 0->height,0->width and set the color to 0, what FPS do you get there?
Are you sure that the timing code is correct?

It's not certain that C++ will be much faster, and it will probably be more complicated. SDL and similar libraries allow cross platform code, but it must be compiled and built separately for each platform.

Share this post


Link to post
Share on other sites
The screen is centered on the player who spawns somewhere in a general spawn area so top, bottom, left, and right all vary, but the distance between them should always be 960 for top and bottom and 1280 for left and right.
I have a particle for every pixel on the screen (though some are type 0 which are drawn as black and will be treated as non-existant).
getType returns which type of particle it is which corresponds to a color.
The color model is very simple so far:

private static ColorModel generateColorModel() {
// Generate 16-color model
byte[] r = new byte[3];
byte[] g = new byte[3];
byte[] b = new byte[3];

r[0] = 0; g[0] = 0; b[0] = 0;
r[1] = (byte)255; g[1] = (byte)255; b[1] = 0;
r[2] = (byte)140; g[2] = (byte)100; b[2] = (byte)20;

return new IndexColorModel(4, 3, r, g, b);
}


I'm fairly certain the timing code is correct as the loop time corresponds to what it used to, the thing that's adding time is the MemoryImageSource related stuff (or so it appears anyways).
Any more questions? It's probably not necessary, but if need be I can upload all my source files.

Share this post


Link to post
Share on other sites
MemoryImageSource() sounds much alike what a DIB Section enables you to do.

I've never used it (or Java), but ideally you should probably be creating it once at load (or when you need to resize it) and only getting rid of it when you're 100% done with it.


It's ideal for it to be 32 bits, as reading / writing a pixel could be done in 1 shot instead of a bunch of bytes.

Only draw / blit the image when you're done with all your drawing.

Share this post


Link to post
Share on other sites
Quote:
Original post by thejavagamer
the thing that's adding time is the MemoryImageSource related stuff (or so it appears anyways).


You need to find out if this is truly the case. It shouldn't be, if you're doing pretty much the same thing as we tried, unless some of the other functions you use are stalling. Try replacing your pixel drawing code with a simple loop that erases the screen to black, and see if there's any difference. If there is, the problem is in your update loop, and if there isn't, it's somewhere in the other stuff, so that you can know where to look for the problem.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this