Rendering Performance Issues

I’m trying to do pixel-by-pixel rendering to an image using for loops. I have an int array where pixel data is written to, and then, once per frame, that array is rendered to the BufferedImage.

I’m having MAJOR performance issues here. I’m getting 20-25 fps with only a background and single image being rendered on fullscreen. That’s also with little to no frame rate limitation involved and WITH caching.

Is the nature of this idea just bad? If so, how else does Graphics.drawImage do it? At some point, the pixel data has to be iterated through right?

Loop for adding each object to data:


			int[] colors = rdata.pixels;
			int tcx = rdata.x, tcy = rdata.y;
			xloop:
				for(int cx = rdata.x;cx < (rdata.x + rdata.wt);cx++) {
					for(int cy = rdata.y;cy < (rdata.y + rdata.ht);cy++) {
						// Bounds checking ----
						if(cy >= pri.getHeight())
							break;
						else if(cy < 0)
							continue;
						if(cx >= pri.getWidth())
							break xloop;
						else if(cx < 0)
							continue xloop;
						// -----------

						int pval = colors[(cx - tcx)*rdata.ht + (cy - tcy)];
						if(pval != rdata.ctrl)
							data[cx*pri.getHeight() + cy] = pval;
					}
				}

Loop for rendering to image:


xloop:
				for(int cx = 0;cx < pri.getWidth();cx++) {
					for(int cy = 0;cy < pri.getHeight();cy++) {
						// Bounds checking ----
						if(cy >= pri.getHeight())
							break;
						else if(cy < 0)
							continue;
						if(cx >= pri.getWidth())
							break xloop;
						else if(cx < 0)
							continue xloop;
						// -----------

						int pval = data[cx*pri.getHeight() + cy];
						if(pval != cacheData[cx*pri.getHeight() + cy]) {
							pri.setRGB(cx, cy, pval);
							cacheData[cx*pri.getHeight() + cy] = pval;
						}
					}
				}

UPDATE:

New setup:


	protected void render(RenderData rdata) {
		try {
			if(pri.getType() != rdata.img.getType()) {
				Graphics g = rdata.img.createGraphics();
				rdata.img = ImageUtils.getNativeImage(rdata.img, g);
				g.dispose();
			}
			
			Rectangle r = new Rectangle(0,0,pri.getWidth(),pri.getHeight());
			Rectangle r2 = new Rectangle(rdata.x, rdata.y, rdata.img.getWidth(), rdata.img.getHeight());
			if(!r.contains(r2)) {
				Rectangle ri = r.createIntersection(r2).getBounds();
				int x = (int) Math.round(ri.getX());
				int y = (int) Math.round(ri.getY());
				int wt = (int) Math.round(ri.getWidth());
				int ht = (int) Math.round(ri.getHeight());
				pri.getRaster().setDataElements(x, y, rdata.img.getSubimage(x, y, wt, ht));
			} else {
				pri.getRaster().setDataElements(rdata.x, rdata.y, rdata.img.getRaster());	
			}
		} catch(Throwable t) {
			t.printStackTrace();
		}
	}

New problem: drawing a partial image when it’s out of bounds.

That label and the bounds checking if statements are useless.

Try using a profiler like VisualVM to figure out where the bottleneck is. Simply copying pixels shouldn’t cause any slowdowns.

correct me if I’m wrong, but I think
setRGB is incredibly slow
and you have to get the Raster, and change that

No they aren’t. If the x and y coordinates are out of bounds, an ArrayIndexOutOfBoundsException will be thrown in both of those cases.

How can I align the raster data with my scan setup? If I’m still using the for loop sequence, the int[] returned by DataBufferInt.getData() is not in the same order, therefore it the image is completely screwed up.

Correct. setRGB will cause the entire image to become unmanaged. When this happens, instead of keeping a bitmap in video memory, Java 2D will now have to transfer the entire image from memory to video memory every frame.

Slooooowwww. Search for managed images to find out more info.

The bounds checking in the for loop takes care of that. And I’m talking about the second code section, not the first.

Managed images are slow, but they shouldn’t be 20-25FPS slow.

Yes I’m aware that it’s redundant. That’s because 1) part of it was copy/pasted and 2) I have been trying to replace the first loop with other methods so the second one needed the bounds checking.

If I modify the raster data array directly, how can I ensure that I assign the values according the way I read them into my data []s (column by column)?

I changed to a system that uses Graphics.drawImage (native platform compatible BufferedImages) and I’m still having scalability issues. The drawImage method is expensive and the performance drop builds up with each addition of a new image to render.

What is the most efficient/scalable method to doing this?

Try making compatible images and also use BufferStrategy. Look here for this more info :slight_smile:

Already doing both of those.

What OS + hardware are you on?

Windows Vista Home Premium
Dell Studio XPS
i7 processor
6GB RAM
ATI Radeon HD 4800 Series 1GB Graphics Driver
x64 (64 bit) architecture

You should be getting FPS’s in the hundreds, maybe thousands, with those specs…

Get all the pixels in one go, and set all the pixels in one go afterwards

see http://www.exampledepot.com/egs/java.awt.image/imagepixel.html

Ok if I have two images, and I obtain the rasters for both, how can I do an arraycopy from one to the other at a coordinate offset?

In other words, copy data from image 1 to image 2 at coordinate x,y in image 2 (using the raster data array NOT rgb get/set).

System.arrayCopy?

Ok I think this did the trick (maybe)


		if(pri.getType() != rdata.img.getType()) {
			Graphics g = rdata.img.createGraphics();
			rdata.img = ImageUtils.getNativeImage(rdata.img, g);
			g.dispose();
		}
		pri.getRaster().setDataElements(rdata.x, rdata.y, rdata.img.getRaster());

Yes but I was asking how I could find out where to start in the Raster data array…

Problem:

Using the method I proposed above, we need to be able to keep rendering the image even when partially off screen. Right now it just throws exceptions.

Ideas?