Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (489)
Games in Android Showcase (112)
games submitted by our members
Games in WIP (553)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Bad rendering loop?  (Read 3883 times)
0 Members and 1 Guest are viewing this topic.
Offline Jamison

Junior Member




We're all idiots in one way or another.


« Posted 2006-12-27 23:42:49 »

Hey all,

I'm trying to make a frame loop which can be limited. The code I have written is intended to limit it to 60 frames per second. However, I only get 40 frames per second. When I remove my limiter code, I get more than 250 frames per second (and if I remove the random balls on the screen, I get over 800 FPS, without the limiter code). I'm hoping somebody here can shed some light on what I'm doing wrong or what I need to do.

Here's my code:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
import java.awt.*;
import java.awt.image.*;

public class FPS extends Canvas implements Runnable {
   private int FPS = 60;
   private int gameW = 1024;
   private int gameH = 768;

   private Graphics screen;
   private BufferedImage buffer;

   private int fps = 0;
   private   int frames = 0;
   private long lastLoopTime = System.currentTimeMillis();

   public FPS() {
      setSize(gameW, gameH);
   }

   public void addNotify() {
      super.addNotify();

      buffer = new BufferedImage(gameW, gameH, Transparency.OPAQUE);
      screen = buffer.getGraphics();

      (new Thread(this)).start();
   }

   public void run() {
      long next = System.currentTimeMillis()+(1000/FPS);

      while(true) {
         if (System.currentTimeMillis() >= next) {
            long last = (System.currentTimeMillis()-lastLoopTime);
            if (last >= 1000) {
               fps = frames;
               frames = 0;
               lastLoopTime = System.currentTimeMillis();
            }
            frames++;

            screen.setColor(Color.black);
            screen.fillRect(0, 0, gameW, gameH);

            gameLoop();

            next = System.currentTimeMillis()+(1000/FPS);
         }

         Graphics g = getGraphics();
         g.drawImage(buffer, 0, 0, this);
         g.dispose();
      }
   }

   public void gameLoop() {
      screen.setColor(Color.green);
      screen.drawString("FPS = "+fps, 100, 100);

      int w = 20;
      int h = 20;
      screen.setColor(Color.gray);
      for (int i=0; i<100; i++) {
         int x = (int)(Math.random() * (gameW-w));
         int y = (int)(Math.random() * (gameH-h));
         screen.drawOval(x, y, w, h);
      }
   }

   public static void main(String args[]) {
      Frame f = new Frame("FPS");

      f.add(new FPS());
      f.setResizable(false);

      f.pack();
      f.show();
   }
}


System specs are as follows:
CPU: 2GHz AMD Athlon 64-bit 3200+
RAM: 1GB DDR2 SDRAM
Video: 256MB nVidia GeForce 7600GT

Thanks in advanced,
Jamison

I don't like you. Check out my site Smiley www.gamedevforums.com
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 783
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #1 - Posted 2006-12-27 23:51:27 »

1  
2  
3  
4  
5  
6  
      if (System.currentTimeMillis() >= next) {

            // LOTS OF LONG STUFF

            next = System.currentTimeMillis()+(1000/FPS);
      }


The time between the if-check and the 'next =', is basicly lost...


Try:

1  
2  
3  
4  
5  
6  
7  
long now = System.currentTimeMillis();
      if (now >= next) {

            // LOTS OF LONG STUFF

            next = now+(1000/FPS);
      }


Or:

1  
2  
3  
4  
5  
6  
      if (System.currentTimeMillis() >= next) {

            // LOTS OF LONG STUFF

            next += (1000/FPS);
      }

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Jamison

Junior Member




We're all idiots in one way or another.


« Reply #2 - Posted 2006-12-28 04:43:15 »

Wow, thanks so much. It works perfectly now. Limiting it to 60 FPS exceeds by about 3 (63 FPS) but every other frame rate is exact. Much is appreciated! Oh, by the way, I used the second method explained (next += 1000/FPS).

I don't like you. Check out my site Smiley www.gamedevforums.com
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline oNyx

JGO Coder


Medals: 2


pixels! :x


« Reply #3 - Posted 2006-12-28 09:42:58 »

>Limiting it to 60 FPS exceeds by about 3 (63 FPS)[...]

1000/60=16.6...
1000/16=62.5

Thats why the maximum framerate in games with a 1msec res timer, which are sorta kinda capped to 60, jumps between 62 and 63.

弾幕 ☆ @mahonnaiseblog
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 783
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #4 - Posted 2006-12-28 10:27:03 »

I normally fix that using:

1  
2  
3  
4  
5  
6  
7  
8  
9  
long[] intervals = new long[]{16,17,17}; // 16.666666667
int counter=0;

      if (System.currentTimeMillis() >= next) {

            // LOTS OF LONG STUFF

            next += intervals[(counter++) % intervals.length];
      }

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline appel

JGO Wizard


Medals: 50
Projects: 4


I always win!


« Reply #5 - Posted 2006-12-28 20:28:12 »

I only get around 24fps. Something as simple as that should run a lot faster, something seriously is killing the speed.

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Offline Jamison

Junior Member




We're all idiots in one way or another.


« Reply #6 - Posted 2006-12-29 04:05:59 »

Have you applied Riven's fix? As I stated before, I was only getting 40 FPS before. Here is the complete code, with his fix:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
import java.awt.*;
import java.awt.image.*;

public class FPS extends Canvas implements Runnable {
   private int FPS = 60;
   private int gameW = 1024;
   private int gameH = 768;

   private Graphics screen;
   private BufferedImage buffer;

   private int fps = 0;
   private   int frames = 0;
   private long lastLoopTime = System.currentTimeMillis();

   public FPS() {
      setSize(gameW, gameH);
      setIgnoreRepaint(true);
   }

   public void addNotify() {
      super.addNotify();

      buffer = new BufferedImage(gameW, gameH, Transparency.OPAQUE);
      screen = buffer.getGraphics();

      (new Thread(this)).start();
   }

   public void run() {
      long next = System.currentTimeMillis()+(1000/FPS);

      while(true) {
         if (System.currentTimeMillis() >= next) {
            long last = (System.currentTimeMillis()-lastLoopTime);
            if (last >= 1000) {
               fps = frames;
               frames = 0;
               lastLoopTime = System.currentTimeMillis();
            }
            frames++;

            screen.setColor(Color.black);
            screen.fillRect(0, 0, gameW, gameH);

            gameLoop();

            next += 1000/FPS;
         }

         Graphics g = getGraphics();
         g.drawImage(buffer, 0, 0, this);
         g.dispose();
      }
   }

   public void gameLoop() {
      screen.setColor(Color.green);
      screen.drawString("FPS = "+fps, 100, 100);

      int w = 20;
      int h = 20;
      screen.setColor(Color.gray);
      for (int i=0; i<100; i++) {
         int x = (int)(Math.random() * (gameW-w));
         int y = (int)(Math.random() * (gameH-h));
         screen.drawOval(x, y, w, h);
      }
   }

   public static void main(String args[]) {
      Frame f = new Frame("FPS");

      f.add(new FPS());
      f.setResizable(false);

      f.pack();
      f.show();
   }
}


UPDATE: This also has ignore repaint set to true (the orignal did not) because it was causing repaint problems (screen flicker, bleeding) when the OS would attempt to repaint the screen.

I don't like you. Check out my site Smiley www.gamedevforums.com
Offline trembovetski

Senior Member




If only I knew what I'm talking about!


« Reply #7 - Posted 2007-01-14 01:54:31 »

Using BufferedImage for a back-buffer is a bad idea. You should use either VolatileImage or BufferStrategy (preferably the
latter). Basically, with your current code you don't get any hardware acceleration: your rendering
goes to the an image in heap, and it is then copied to the screen.

Search around for examples on BufferStrategy or take a look at javadocs for jdk6
(much improved docs for how to use the BS):
   http://java.sun.com/javase/6/docs/api/java/awt/image/BufferStrategy.html

Thanks,
   Dmitri
Java2D Team
Offline Jamison

Junior Member




We're all idiots in one way or another.


« Reply #8 - Posted 2007-01-15 22:30:16 »

Tell me this: How is a BufferStrategy better than a BufferedImage when I can get about 500 frames per second with a BufferedImage (when nothing is rendered, just the back ground color and the FPS) and only about 150 frames per second with a BufferStrategy.

(NOTE: I could get much more than 500 frames per second if I did not use Thread.sleep())

I don't like you. Check out my site Smiley www.gamedevforums.com
Offline Kova

Senior Member





« Reply #9 - Posted 2007-01-16 09:55:16 »

When debuging my game I wrote a small test, BufferStrategy vs. BufferedImage, BS was noticably better. Here is a conclusion:

...
For test I drawed 100 ovals in a loop, 50 rectangles and 50 20x20 png images with alpha channel. Resoults are good, without png images BS rendering goes to 220 fps, and BI rendering only 90. With png images BS drops to 80, but it's still a lot better then 60 BI render gets. So conclusion of this small benchmark is this: BS rendering is noticablely faster then BI rendering, and extreamly faster when dealing with java shapes.
...

all this in windowed mode, later in thread Commander Keith told me BS should be even faster in full screen because it can use page flipping (pointer shifting).

So I guess your example is broken somewhere in rendering loop when using BS.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Jamison

Junior Member




We're all idiots in one way or another.


« Reply #10 - Posted 2007-01-17 04:42:39 »

In my game, I'm drawing full-alpha PNG images and I changed my buffer to a BufferStrategy and I only got about 120 FPS. Why stick with 120 FPS when I can get over 500 FPS with a BufferedImage? It just makes absolutely no sense at all - it's a huge speed decrease.

I don't like you. Check out my site Smiley www.gamedevforums.com
Offline oNyx

JGO Coder


Medals: 2


pixels! :x


« Reply #11 - Posted 2007-01-17 05:12:56 »

>Tell me this: How is a BufferStrategy better than a BufferedImage when I can get about 500 frames per second
>with a BufferedImage (when nothing is rendered, just the back ground color and the FPS) and only about 150
>frames per second with a BufferStrategy.

Your follow up post answers that question. You are using some rendering pipeline, which does alpha stuff in software. So keeping the buffer over in software land is surely faster than going back and forth a zillion times a frame.

弾幕 ☆ @mahonnaiseblog
Offline Linuxhippy

Senior Member


Medals: 1


Java games rock!


« Reply #12 - Posted 2007-01-17 07:32:23 »

do you just draw into the bufferedimage or do you also once per round draw it to screen?
Offline Jamison

Junior Member




We're all idiots in one way or another.


« Reply #13 - Posted 2007-01-18 04:45:45 »

Obviously, yes, I draw it to the screen. Why wouldn't I? If I didn't than nothing would be visible... Look at the code.

I don't like you. Check out my site Smiley www.gamedevforums.com
Offline Linuxhippy

Senior Member


Medals: 1


Java games rock!


« Reply #14 - Posted 2007-01-20 12:13:22 »

Jamison: 1.) I wonder why your tone is so agressive. Theres absolutly no need to do so!

2.) You are rendering stuff which can't be done in hw with the java2d-backend you are using. This triggers readbacks from vram->ram which is slow. Run you application with -Dsun.java2d.trace=count to see where software rendering happens and then try to alter your code, and/or experiment with other rendering pipelines (OpenGL for example).

lg Clemens
Offline CommanderKeith
« Reply #15 - Posted 2007-01-20 14:05:35 »

I think what they're saying is that the BufferStrategy is using "hardware acceleration" by using DirectDraw/Direct3D whereas the BufferImage is not, its all in software (ie no graphics card & VRAM, just the CPU & normal RAM).

In this case it seems like the hardware 'acceleration' is actually slower than software mode, thus your slow-down.

To make sure this is the problem, compare your two approaches when both use the noddraw option so neither have hardware acceleration.  This VM option is: -Dsun.java2d.noddraw=true

from: http://java.sun.com/j2se/1.5.0/docs/guide/2d/flags.html 

Keith

(PS: this is a hairy topic full of wierd performance things so good luck!  Not even the J2D team can work out which pipeline is the best for different computers but they're working on it...)

Offline Jamison

Junior Member




We're all idiots in one way or another.


« Reply #16 - Posted 2007-01-20 15:52:29 »

I'm sorry about the tone. It's just this is getting me so agrivated as to why I only got so low framerate while almost every other game I've ran gets over 1200+ or something.

Also, those -Dsun.java2d.* commands don't seem to do anything. But am I using them correctly? I put them in a BAT file to run my game:
1  
2  
3  
4  
@ECHO OFF

java FPS -Dsun.java2d.trace=count
pause


Let me also point out that my screen size (not my actual monitor, but the game's screen, the buffer) is only 320x240. If I change that to 1024x768, I get less than 60 frames per second.

I don't like you. Check out my site Smiley www.gamedevforums.com
Offline Linuxhippy

Senior Member


Medals: 1


Java games rock!


« Reply #17 - Posted 2007-01-21 11:47:28 »

To make sure this is the problem, compare your two approaches when both use the noddraw option so neither have hardware acceleration.  This VM option is: -Dsun.java2d.noddraw=true
Well, noddraw just disables the use of direct draw, as far as I know this does not mean everything is unaccalerated (however I could be wrong).

@jamison: I don't know wether its ok to specify the -D arguments after the main class, better try java -Dsun.java2d.trace=count FPS

You'll see how often stuff was calles, whereas names with java2d.loopsn in it are in general "bad" -> loops mean stuff is done in Software, however this is only a problem if the count is very high. (-> frequently using software rendering)

lg Clemens
Offline oNyx

JGO Coder


Medals: 2


pixels! :x


« Reply #18 - Posted 2007-01-21 13:19:12 »

>But am I using them correctly?

No you hand that parameter over to your program and not over to java.

java [switches for java] YourProgram [switches for your program]

弾幕 ☆ @mahonnaiseblog
Offline Jamison

Junior Member




We're all idiots in one way or another.


« Reply #19 - Posted 2007-01-21 18:13:59 »

Okay, I got the -Dsun.java2d.* stuff to work. And trace=count just outputs some weird stuff. Here's the output, I can't understand it.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
3 calls to GDIFillRect
31769 calls to sun.java2d.loops.Blit::Blit(IntRgb, SrcNoEa, IntRgb)
2787 calls to sun.java2d.loops.DrawGlyphList::DrawGlyphList(AnyColor, SrcNoEa, A
nyInt)
26210 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa,
 IntRgb)
1 call to sun.java2d.loops.TransformHelper::TransformHelper(IntArgb, SrcNoEa, In
tArgbPre)
1858 calls to sun.java2d.loops.FillRect::FillRect(AnyColor, SrcNoEa, AnyInt)
3 calls to GDIDrawRect
931 calls to sun.java2d.windows.GDIBlitLoops::Blit(IntRgb, SrcNoEa, "GDI")
26210 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntRgb)
6790 calls to sun.java2d.windows.DDBlitLoops::Blit("Integer RGB DirectDraw", Src
NoEa, "Integer RGB DirectDraw")
96562 total calls to 10 different primitives

I don't like you. Check out my site Smiley www.gamedevforums.com
Offline Linuxhippy

Senior Member


Medals: 1


Java games rock!


« Reply #20 - Posted 2007-01-21 20:00:07 »

Ok, its not that complicated to read at all.
1.) the number tells you how often this pipeline-functionality has been used.
2.) The name of the pipelinefunctionality used, almost everything with "loops" in it and a high count in 1.) is evil.

In fact your profile here shows that *everything* happens in the software rendering loops. If  you did trace your BufferedImage implementation, then this is no surpise - everything is done in SW except blitting some images. If no you're doing some fancy stuff which cannot be accalerated by the default java2d-pipeline.

Try wether -Dsun.java2d.opengl=True helps (java displays wether this works or not). Use Java-6 if you plant to try it.

The following operations could cause problems on the windows default pipeline:
- Antialiasing
- Translucent stuff (transparent images work)
- Image transformations
- ...........

The X11 pipeline seems to be even a little bit trickier, e.g. Substance LNF is very slow on Linux but works OK on Windows. However accalerated stuff is on X11 as fast / almost as fast / faster than on Windows.

Best wishes, lg Clemens
Offline Jamison

Junior Member




We're all idiots in one way or another.


« Reply #21 - Posted 2007-01-22 22:00:42 »

OK, I understand that. But even if they are high, what can I do about it?

Also, I did some messing around with both BufferStrategy and BufferedImage. It seems that if I'm drawing only transparent PNG images (and a String to show the FPS display), I can draw over 25,000 images and still get almost 80 frames per second (no differance whether using BufferStrategy or a BufferedImage). My screen size is 1024x768 (my screen resolution, however, is 1280x1024; not in FSEM). My images are 16x16, 204 colors. However, on the down side, my CPU was shot upto like 90%. I'm using code that is supposed to load the images as accelarated (using the video RAM and not CPU), however, if it was in the video memory, shouldn't my CPU usage be a lot lower? Or is it because I'm running through almost 80 for...loops in one second in which each loops 25,000 times?

Here's the code I got from Kev's site, cokeandcode.com - from his Space Invaders 101 tutorial:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
      try {
         URL url = getClass().getClassLoader().getResource("Image.png");
         Image source = ImageIO.read(url);

         GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
         image = gc.createCompatibleImage(source.getWidth(null), source.getHeight(null), Transparency.BITMASK);
         image.getGraphics().drawImage(source, 0, 0, null);
      } catch(Exception e) {
         e.printStackTrace();
         System.exit(-1);
      }


UPDATE: A BufferStrategy actually gets about 10 frames per second more (almost 90 frames per second) than using a BufferedImage (about 80 frames per second) when doing what's explained above.

UPDATE: I get pretty close to 100 frames per second with FSEM (about 96 FPS average, using BufferStrategy, 1024x768x32 at 75mhz).

I don't like you. Check out my site Smiley www.gamedevforums.com
Offline Kova

Senior Member





« Reply #22 - Posted 2007-01-22 22:11:15 »

25k images  Shocked
I'm surprised it works that well beyond 1k Smiley Your high CPU usage is from all that drawing I guess. Do you even use sleep() ? If not it's logical that CPU usage is near 100% becouse it's doing your program all the time.
Offline Jamison

Junior Member




We're all idiots in one way or another.


« Reply #23 - Posted 2007-01-22 22:14:37 »

Yes, I'm sleeping for one millisecond every frame. So I'm assuming this is pretty damn good? So my code should be OK then, right?

OK, I just looked at my code and realized my screen size is actually 640x480x32 at 75mhz. I thought I had it at 1024x768... However, I still get 90 frames per second even at 1280x1024x32 at 75mhz.

UPDATE: I'm so stupid. Sad More than like 9/10 of the images weren't even on the screen. I changed my code to actually draw ALL 5,120 images to screen, and I get only about 30 frames per second (at 1280x1024x32, 75mhz).

Here's a summery of how many images I can draw at 5 major used resolutions and the average framerated displayed.
320x240, 300 images, 250 frames per second
640x480, 1200 images, 110 frames per second
800x600, 1850 images, 77 frames per second
1024x768, 3072 images, 49 frames per second
1280x1024, 5120 images, 30 frames per second

I don't like you. Check out my site Smiley www.gamedevforums.com
Offline Jamison

Junior Member




We're all idiots in one way or another.


« Reply #24 - Posted 2007-01-22 23:57:06 »

Thank you all very much for all of your help (especially to trembovetski, for pointing that a BufferStrategy is much better). After realizing that when using a BufferStrategy in combination with accelarated images (placing them in video memory), my game now runs at over 500 frames per second in any resolution tested with (with a BufferedImage, I could not get that to happen, usually at the highest res. 1280x1024, it ran at only 40-60 fps). Thank you all again so much for the great information!!!

Also by the way... sorry for the double post, I just wanted you guys to receive the "New reply" notification to see I got it working just the way I needed it.

--Jamison

I don't like you. Check out my site Smiley www.gamedevforums.com
Pages: [1]
  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.

TehJavaDev (18 views)
2014-08-28 18:26:30

CopyableCougar4 (26 views)
2014-08-22 19:31:30

atombrot (39 views)
2014-08-19 09:29:53

Tekkerue (36 views)
2014-08-16 06:45:27

Tekkerue (33 views)
2014-08-16 06:22:17

Tekkerue (22 views)
2014-08-16 06:20:21

Tekkerue (33 views)
2014-08-16 06:12:11

Rayexar (70 views)
2014-08-11 02:49:23

BurntPizza (47 views)
2014-08-09 21:09:32

BurntPizza (37 views)
2014-08-08 02:01:56
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

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
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!