Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (511)
Games in Android Showcase (119)
games submitted by our members
Games in WIP (577)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2
  ignore  |  Print  
  Rendering Performance Issues  (Read 8417 times)
0 Members and 1 Guest are viewing this topic.
Offline ghostsoldier23

Junior Duke


Medals: 1



« Posted 2012-05-05 22: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++) {
                  // 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:
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++) {
                  // 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:
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.
Offline ra4king

JGO Kernel


Medals: 350
Projects: 3
Exp: 5 years


I'm the King!


« Reply #1 - Posted 2012-05-05 23: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.

Offline Cero
« Reply #2 - Posted 2012-05-05 23: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!
Legends of Yore - The Casual Retro Roguelike
Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #3 - Posted 2012-05-06 01: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.
Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #4 - Posted 2012-05-06 01: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.
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #5 - Posted 2012-05-06 01: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.
Offline ra4king

JGO Kernel


Medals: 350
Projects: 3
Exp: 5 years


I'm the King!


« Reply #6 - Posted 2012-05-06 01: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.

Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #7 - Posted 2012-05-06 03: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)?
Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #8 - Posted 2012-05-06 04: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?
Offline ra4king

JGO Kernel


Medals: 350
Projects: 3
Exp: 5 years


I'm the King!


« Reply #9 - Posted 2012-05-06 04:21:22 »

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

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #10 - Posted 2012-05-06 04:24:57 »

Already doing both of those.
Offline ra4king

JGO Kernel


Medals: 350
Projects: 3
Exp: 5 years


I'm the King!


« Reply #11 - Posted 2012-05-06 04:30:29 »

What OS + hardware are you on?

Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #12 - Posted 2012-05-06 04: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
Offline ra4king

JGO Kernel


Medals: 350
Projects: 3
Exp: 5 years


I'm the King!


« Reply #13 - Posted 2012-05-06 04:43:16 »

You should be getting FPS's in the hundreds, maybe thousands, with those specs.....

Offline roland
« Reply #14 - Posted 2012-05-06 04:54:12 »

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
Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #15 - Posted 2012-05-06 05: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).
Offline ra4king

JGO Kernel


Medals: 350
Projects: 3
Exp: 5 years


I'm the King!


« Reply #16 - Posted 2012-05-06 05:48:03 »

System.arrayCopy?

Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #17 - Posted 2012-05-06 05: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());
Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #18 - Posted 2012-05-06 05:48:54 »

System.arrayCopy?

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

Junior Duke


Medals: 1



« Reply #19 - Posted 2012-05-06 06: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?
Offline jonjava
« Reply #20 - Posted 2012-05-06 07:32:28 »

The pixel data you get is nothing more but a 2Darray inside a 1D array. A 1D array can just as easily represent 2D dimensions.

For every "row" you simply increment the position by the width of the image.

http://stackoverflow.com/questions/2151084/map-a-2d-array-onto-a-1d-array-c
http://en.wikipedia.org/wiki/Row-major_order
http://processing.org/learning/2darray/

Offline pitbuller
« Reply #21 - Posted 2012-05-06 08: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.
Offline nsigma
« Reply #22 - Posted 2012-05-06 10:30:14 »

A couple of corrections to things said earlier.  There are some general misconceptions with managed images around here!  Smiley

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.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #23 - Posted 2012-05-06 16: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...
Offline jonjava
« Reply #24 - Posted 2012-05-06 17: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).
The pixel data you get is nothing more but a 2Darray inside a 1D array. A 1D array can just as easily represent 2D dimensions.

For every "row" you simply increment the position by the width of the image.

http://stackoverflow.com/questions/2151084/map-a-2d-array-onto-a-1d-array-c
http://en.wikipedia.org/wiki/Row-major_order
http://processing.org/learning/2darray/

Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #25 - Posted 2012-05-06 17: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)
Offline davedes
« Reply #26 - Posted 2012-05-06 17:09:43 »

The first answer here is useful for copying an image:
http://stackoverflow.com/questions/2825837/java-how-to-do-fast-copy-of-a-bufferedimages-pixels-unit-test-included

Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #27 - Posted 2012-05-06 17: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.
Offline jonjava
« Reply #28 - Posted 2012-05-06 17: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).
The pixel data you get is nothing more but a 2Darray inside a 1D array. A 1D array can just as easily represent 2D dimensions.

For every "row" you simply increment the position by the width of the image.

http://stackoverflow.com/questions/2151084/map-a-2d-array-onto-a-1d-array-c
http://en.wikipedia.org/wiki/Row-major_order
http://processing.org/learning/2darray/

Offline ghostsoldier23

Junior Duke


Medals: 1



« Reply #29 - Posted 2012-05-06 17: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).
The pixel data you get is nothing more but a 2Darray inside a 1D array. A 1D array can just as easily represent 2D dimensions.

For every "row" you simply increment the position by the width of the image.

http://stackoverflow.com/questions/2151084/map-a-2d-array-onto-a-1d-array-c
http://en.wikipedia.org/wiki/Row-major_order
http://processing.org/learning/2darray/

What is your point?
Pages: [1] 2
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Longarmx (50 views)
2014-10-17 03:59:02

Norakomi (39 views)
2014-10-16 15:22:06

Norakomi (31 views)
2014-10-16 15:20:20

lcass (36 views)
2014-10-15 16:18:58

TehJavaDev (66 views)
2014-10-14 00:39:48

TehJavaDev (65 views)
2014-10-14 00:35:47

TehJavaDev (56 views)
2014-10-14 00:32:37

BurntPizza (72 views)
2014-10-11 23:24:42

BurntPizza (44 views)
2014-10-11 23:10:45

BurntPizza (84 views)
2014-10-11 22:30:10
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!