ghostsoldier23
|
 |
«
Posted
2012-05-06 00:09:22 » |
|
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: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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++) { 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: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| xloop: for(int cx = 0;cx < pri.getWidth();cx++) { for(int cy = 0;cy < pri.getHeight();cy++) { 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: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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.
|
|
|
|
|
ra4king
|
 |
«
Reply #1 - Posted
2012-05-06 01:09:24 » |
|
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.
|
|
|
|
Cero
|
 |
«
Reply #2 - Posted
2012-05-06 01:16:04 » |
|
correct me if I'm wrong, but I think setRGB is incredibly slow and you have to get the Raster, and change that
|
|
|
|
Games published by our own members! Check 'em out!
|
|
ghostsoldier23
|
 |
«
Reply #3 - Posted
2012-05-06 03:02:34 » |
|
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.
No they aren't. If the x and y coordinates are out of bounds, an ArrayIndexOutOfBoundsException will be thrown in both of those cases.
|
|
|
|
|
ghostsoldier23
|
 |
«
Reply #4 - Posted
2012-05-06 03:11:56 » |
|
correct me if I'm wrong, but I think setRGB is incredibly slow and you have to get the Raster, and change that
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.
|
|
|
|
|
loom_weaver
|
 |
«
Reply #5 - Posted
2012-05-06 03:21:57 » |
|
correct me if I'm wrong, but I think setRGB is incredibly slow and you have to get the Raster, and change that
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.
|
|
|
|
|
ra4king
|
 |
«
Reply #6 - Posted
2012-05-06 03:44:45 » |
|
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.
No they aren't. If the x and y coordinates are out of bounds, an ArrayIndexOutOfBoundsException will be thrown in both of those cases. The bounds checking in the for loop takes care of that. And I'm talking about the second code section, not the first. correct me if I'm wrong, but I think setRGB is incredibly slow and you have to get the Raster, and change that
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. Managed images are slow, but they shouldn't be 20-25FPS slow.
|
|
|
|
ghostsoldier23
|
 |
«
Reply #7 - Posted
2012-05-06 05:13:22 » |
|
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.
No they aren't. If the x and y coordinates are out of bounds, an ArrayIndexOutOfBoundsException will be thrown in both of those cases. The bounds checking in the for loop takes care of that. And I'm talking about the second code section, not the first. correct me if I'm wrong, but I think setRGB is incredibly slow and you have to get the Raster, and change that
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. 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)?
|
|
|
|
|
ghostsoldier23
|
 |
«
Reply #8 - Posted
2012-05-06 06:10:43 » |
|
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?
|
|
|
|
|
|
|
Games published by our own members! Check 'em out!
|
|
ghostsoldier23
|
 |
«
Reply #10 - Posted
2012-05-06 06:24:57 » |
|
Already doing both of those.
|
|
|
|
|
ra4king
|
 |
«
Reply #11 - Posted
2012-05-06 06:30:29 » |
|
What OS + hardware are you on?
|
|
|
|
ghostsoldier23
|
 |
«
Reply #12 - Posted
2012-05-06 06:33:45 » |
|
Windows Vista Home Premium Dell Studio XPS i7 processor 6GB RAM ATI Radeon HD 4800 Series 1GB Graphics Driver x64 (64 bit) architecture
|
|
|
|
|
ra4king
|
 |
«
Reply #13 - Posted
2012-05-06 06:43:16 » |
|
You should be getting FPS's in the hundreds, maybe thousands, with those specs.....
|
|
|
|
|
|
ghostsoldier23
|
 |
«
Reply #15 - Posted
2012-05-06 07:00:08 » |
|
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).
|
|
|
|
|
ra4king
|
 |
«
Reply #16 - Posted
2012-05-06 07:48:03 » |
|
System.arrayCopy?
|
|
|
|
ghostsoldier23
|
 |
«
Reply #17 - Posted
2012-05-06 07:48:19 » |
|
Ok I think this did the trick (maybe) 1 2 3 4 5 6
| 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()); |
|
|
|
|
|
ghostsoldier23
|
 |
«
Reply #18 - Posted
2012-05-06 07:48:54 » |
|
System.arrayCopy?
Yes but I was asking how I could find out where to start in the Raster data array...
|
|
|
|
|
ghostsoldier23
|
 |
«
Reply #19 - Posted
2012-05-06 08:08:51 » |
|
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?
|
|
|
|
|
|
|
pitbuller
|
 |
«
Reply #21 - Posted
2012-05-06 10:05:20 » |
|
So micro optimizations that you can use when everything else is corrected. You are calling pri.getHeight() six times in inner loop? It's static and can be asked one time before both loops. Don't compare against method call value in loop. Instead call against constant value. When somethin is changed you calculate this cx*pri.getHeight() + cy three times and when not two times. Pre calcualte it. Make simple code that compiler and JIT can understand more easily and optimize it further. But before you do any of these work with higher level optimizations that are allready told.
And when you ask some about your code make it ready for the reviews. It's lame excuse to say that there are some old copy paste buggers. Make it easy to other readers spot the right problem and fix everything that you know allready so time is not wasted.
|
|
|
|
|
nsigma
|
 |
«
Reply #22 - Posted
2012-05-06 12:30:14 » |
|
A couple of corrections to things said earlier. There are some general misconceptions with managed images around here!  Correct. setRGB will cause the entire image to become unmanaged.
There are two methods called setRGB, and I've only ever seen the issue with images becoming unmanaged mentioned with regard to the other one (that takes an array). I'm not sure it's still the case there either. It's still the slower way to do this though. 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.
If the OP is updating the image every frame (and only drawing it once) then there is absolutely no point in worrying about whether the image is managed or not. Drawing into a BufferedImage, even with Graphics2D, happens in software. The image is only synced to video memory when it's been drawn a couple of times without modification. If you need to update the pixel array of an image every frame, just grab the pixels array from the raster and stop worrying about whether it's managed or not (unless you have to draw it lots of times, or rotated / scaled, in which case copying to a VolatileImage first may help). If you ever need to update an image every frame with Graphics2D, then use a VolatileImage and you have a chance your drawing to (as well as rendering from) the image will be accelerated.
|
|
|
|
ghostsoldier23
|
 |
«
Reply #23 - Posted
2012-05-06 18:44:04 » |
|
So micro optimizations that you can use when everything else is corrected. You are calling pri.getHeight() six times in inner loop? It's static and can be asked one time before both loops. Don't compare against method call value in loop. Instead call against constant value. When somethin is changed you calculate this cx*pri.getHeight() + cy three times and when not two times. Pre calcualte it. Make simple code that compiler and JIT can understand more easily and optimize it further. But before you do any of these work with higher level optimizations that are allready told.
And when you ask some about your code make it ready for the reviews. It's lame excuse to say that there are some old copy paste buggers. Make it easy to other readers spot the right problem and fix everything that you know allready so time is not wasted.
But see... I still need that code...
|
|
|
|
|
jonjava
|
 |
«
Reply #24 - Posted
2012-05-06 19:03:04 » |
|
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).
|
|
|
|
ghostsoldier23
|
 |
«
Reply #25 - Posted
2012-05-06 19:08:55 » |
|
Ok I think this did the trick (maybe) 1 2 3 4 5 6
| 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()); |
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?
This is the current setup. I'm trying to create a subimage based on the intersection of the image and the master image but it's still throwing RasterFormatExceptions. Perhaps I'm doing it wrong? (Note: I will update OP with this new code)
|
|
|
|
|
davedes
|
 |
«
Reply #26 - Posted
2012-05-06 19:09:43 » |
|
|
|
|
|
ghostsoldier23
|
 |
«
Reply #27 - Posted
2012-05-06 19:17:01 » |
|
I'm not using that method anymore, but you're right that it's useful. Thanks for finding it! I will keep it in mind if I ever use it some other time.
|
|
|
|
|
jonjava
|
 |
«
Reply #28 - Posted
2012-05-06 19:24:00 » |
|
I'm not using that method anymore, but you're right that it's useful. Thanks for finding it! I will keep it in mind if I ever use it some other time. 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).
|
|
|
|
ghostsoldier23
|
 |
«
Reply #29 - Posted
2012-05-06 19:32:20 » |
|
I'm not using that method anymore, but you're right that it's useful. Thanks for finding it! I will keep it in mind if I ever use it some other time. 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).
What is your point?
|
|
|
|
|
|