Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (109)
games submitted by our members
Games in WIP (536)
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  
  Confused: why is libgdx 12x faster than slick2d?  (Read 9762 times)
0 Members and 1 Guest are viewing this topic.
Offline Grunnt

JGO Wizard


Medals: 66
Projects: 8
Exp: 5 years


Complex != complicated


« Posted 2012-08-09 15:33:03 »

Hey all, I hope someone is able to shed some light on a thing that baffles me. So far I've been using slick2d to build a game, which is nice because it gives me hardware accelleration and all. However, I just played around a bit with libdgx, and the way I'm doing things it appears libdgx is about 12x faster! I'm not sure if this is because I'm using slick2d wrong, my test is flawed, or whether there simply is such a difference. Can anyone help me with this?

Here's some code I used to test this. Both run at roughly the same FPS on my machine, even though the libgdx one draws 12 x as many images. I draw the images in a circle so every image is drawn visibly to avoid differences in clipping or whatever (just so every image is actually rendered in the viewport and not all on the same spot).

Slick2d:
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  
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;

public class SlickTest extends BasicGame {

   private Image image;
   private long lastFpsTime;
   private float angle;

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

   @Override
   public void render(GameContainer container, Graphics graphics) throws SlickException {
      for (int i = 0; i < 2500; i++) {
         angle += 6.28f / 200f;
         image.draw(200 + (float) Math.cos(angle) * 100f, 200 + (float) Math.sin(angle) * 100f);
      }
   }

   @Override
   public void init(GameContainer container) throws SlickException {
      image = new Image("image/test.png");
      lastFpsTime = System.nanoTime();
   }

   @Override
   public void update(GameContainer container, int delta) throws SlickException {
      if (System.nanoTime() - lastFpsTime > 1000000000) {
         System.out.println(container.getFPS());
         lastFpsTime = System.nanoTime();
      }
   }

   public static void main(String[] args) throws SlickException {
      AppGameContainer app = new AppGameContainer(new SlickTest());
      app.setShowFPS(false);

      app.setDisplayMode(800, 600, false);
      app.start();
   }
}


And for libgdx:

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  
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class ConstellationControl implements ApplicationListener {
   private OrthographicCamera camera;
   private SpriteBatch batch;
   private Texture texture;
   private Sprite sprite;
   long lastFpsTime;
   private float angle;

   @Override
   public void create() {
      float w = Gdx.graphics.getWidth();
      float h = Gdx.graphics.getHeight();

      camera = new OrthographicCamera(w, h);
      batch = new SpriteBatch();

      texture = new Texture(Gdx.files.internal("data/test.png"));

      sprite = new Sprite(texture);

      lastFpsTime = System.nanoTime();
   }

   @Override
   public void dispose() {
      batch.dispose();
      texture.dispose();
   }

   @Override
   public void render() {
      if (System.nanoTime() - lastFpsTime > 1000000000) {
         System.out.println(Gdx.graphics.getFramesPerSecond());
         lastFpsTime = System.nanoTime();
      }

      Gdx.gl.glClearColor(0, 0, 0, 1);
      Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

      batch.setProjectionMatrix(camera.combined);
      batch.begin();
      for (int i = 0; i < 30000; i++) {
         angle += 6.28f / 200f;
         sprite.setPosition(100 + (float) Math.cos(angle) * 100f, 100 + (float) Math.sin(angle) * 100f);
         sprite.draw(batch);
      }
      batch.end();
   }

   @Override
   public void resize(int width, int height) {
   }

   @Override
   public void pause() {
   }

   @Override
   public void resume() {
   }
}

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;

public class Main {
   public static void main(String[] args) {
      LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
      cfg.title = "constellationcontrol";
      cfg.useGL20 = false;
      cfg.width = 800;
      cfg.height = 600;

      new LwjglApplication(new ConstellationControl(), cfg);
   }
}

Offline UprightPath
« Reply #1 - Posted 2012-08-09 16:05:38 »

LibGDX: You write your own loop.
Slick2D: Controls the loop for you. Try using.. app.setTargetFrameRate(300) in your main and see how much quicker it seems to be.

Offline princec

JGO Kernel


Medals: 343
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #2 - Posted 2012-08-09 16:28:24 »

Hm I couldn't get slick to go faster than vsync no matter what I tried.

Cas Smiley

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline UprightPath
« Reply #3 - Posted 2012-08-09 16:57:09 »

I haven't actually tried it! So I wouldn't know if it works.

However, I do know that Slick2D has a strict manager for the frame rate/update call rate, which is why the two versions are probably showing different speeds. I'd try them both with the same number of images, then scale the number up and up, and see at what point you start to get Slick2D going below the 'normal' frame rate.

I could be wrong though. Shortly, we'll probably end up having KevGlass answering the question, or someone else who's actually part of the development team.

Offline Grunnt

JGO Wizard


Medals: 66
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #4 - Posted 2012-08-09 17:02:46 »

Thanks for the replies! I did aim for an FPS of around 50, so the framerate limiting should not come into play. Anyway, I repeated the same test using:
1  
app.setTargetFrameRate(300)
, but that did not make a difference.

Could it have something to do with using libdgx SpriteBatch.begin() and SpriteBatch.end(), and not using something similar for Slick2d? I have no idea ho to do something similar in Slick2d though.

Offline Danny02
« Reply #5 - Posted 2012-08-09 17:14:00 »

my bet is that libgdx uses a better way to render the images. With this amount of images you are rendering, batching the does of course speed things up. And when slick doesn't anything like that in the background it is just that why gdx is faster.
Offline teletubo
« League of Dukes »

JGO Ninja


Medals: 48
Projects: 4
Exp: 8 years



« Reply #6 - Posted 2012-08-09 17:24:23 »

Last time I checked Slick2d code, it used immediate mode to render the sprites.

I'm pretty sure libgdx doesn't use immediate mode, otherwise it wouldn't make sense to call a begin/end for a batch (which probably means flushing the buffered vertex data using VBO or similar).

Offline sproingie

JGO Kernel


Medals: 202



« Reply #7 - Posted 2012-08-09 17:43:05 »

Recent versions of slick have a spritebatch class, but I'm not sure it's used by default.
Offline R.D.

Senior Member


Medals: 2
Projects: 1


"For the last time, Hats ARE Awesome"


« Reply #8 - Posted 2012-08-09 19:36:40 »

Recent versions of slick have a spritebatch class, but I'm not sure it's used by default.


What? No this not true. At least I can't find one Wink I think davedes posted once such a SpriteBatch which was really cool and worked a lot like the one in libGDX.
Offline davedes
« Reply #9 - Posted 2012-08-09 20:09:03 »

Ultimately LibGDX should be more performant since it was written with low-spec in mind (Android), and uses more modern OpenGL standards (remember, Slick is now many years old). On top of that, Slick's codebase is a bit of a mess, and there are many areas where it could be optimized.

  • As I've advised in the wiki, it's best to use Image.startUse/endUse/drawEmbedded instead of Image.draw(). In short, Image.draw pushes quads individually to the GPU, whereas drawEmbedded allows you to push them altogether in a single list.
  • Also described in the wiki is the "Vertex Array Renderer" which mimics LibGDX's sprite batch, albeit with the fixed-function pipeline and Vertex Arrays instead of VBO/GLSL and the programmable pipeline. If you're using the vertex array renderer, Image.draw() calls should be batched properly.
  • Slick clears the depth buffer by default (not sure why..). You may find a very slight performance increase by using container.setClearEachFrame(false) and then adding g.clear() to the beginning of your render method (it only clears the color buffer).
  • There have been many improvements to Slick2D over the past few months, so please test with the latest version. Also be sure to use the latest version of LWJGL.
  • You should also call container.setShowFPS(false) when benchmarking, and show FPS in some other manner (i.e. every couple seconds print it to stdout, or set the window title through Display.setTitle).

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

JGO Kernel


Medals: 343
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #10 - Posted 2012-08-09 20:12:41 »

I wonder how libgdx compares to the awesomeness of the new SPGL2 sprite and effects engine.

Cas Smiley

Offline davedes
« Reply #11 - Posted 2012-08-09 20:13:35 »

I wonder how libgdx compares to the awesomeness of the new SPGL2 sprite and effects engine.

Cas Smiley
I think it's time for another sprite-shootout...  Grin

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 757
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #12 - Posted 2012-08-09 20:13:45 »

with fixed-function Vertex Arrays instead of VBO/GLSL.
There is no such thing as 'fixed-function vertex arrays'

You have immediate mode vs. retained mode
And fixed-function vs. shaders.

You can mix 'n match these (from immediate mode with shaders, to retained mode with fixed-function pipeline, to give you the odd extremes)

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline davedes
« Reply #13 - Posted 2012-08-09 20:24:25 »

Quote
... albeit with the fixed-function pipeline and Vertex Arrays instead of VBO/GLSL and the programmable pipeline.

Happy now? Roll Eyes

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 757
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #14 - Posted 2012-08-09 20:25:12 »

Happy now? Roll Eyes
Very. You can never be too correct. Think of the children, among other things!

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

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Reply #15 - Posted 2012-08-09 22:48:20 »

In slick2d Image.draw() binds a texture, and then draws it. The spritebatch only binds once if I recall correctly. Try to set your spritesheet in slick2d to startUse(), and drawEmbedded(), and then stopUse(). That way you avoid rebinding the same texture again and again.

Offline davedes
« Reply #16 - Posted 2012-08-09 23:03:26 »

In slick2d Image.draw() binds a texture, and then draws it. The spritebatch only binds once if I recall correctly. Try to set your spritesheet in slick2d to startUse(), and drawEmbedded(), and then stopUse(). That way you avoid rebinding the same texture again and again.
Since we're getting all technical with OpenGL language... Smiley

Both draw() and startUse() bind a texture, but only when necessary. If the texture is already bound, it won't be bound again.

The performance difference has to do with many calls to glBegin/glEnd (Image.draw) vs just one (Image.startUse/endUse). Image.draw() also has a bit of matrix math which could further slow things down.

Offline badlogicgames
« Reply #17 - Posted 2012-08-10 02:41:57 »

By all means benchmark the shitout of things cas, especially on android, doesn'tmatter on the desktop imo Smiley

http://www.badlogicgames.com - musings on Android and Java game development
Offline Grunnt

JGO Wizard


Medals: 66
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #18 - Posted 2012-08-10 08:45:50 »

  • As I've advised in the wiki, it's best to use Image.startUse/endUse/drawEmbedded instead of Image.draw(). In short, Image.draw pushes quads individually to the GPU, whereas drawEmbedded allows you to push them altogether in a single list.
  • Also described in the wiki is the "Vertex Array Renderer" which mimics LibGDX's sprite batch, albeit with the fixed-function pipeline and Vertex Arrays instead of VBO/GLSL and the programmable pipeline. If you're using the vertex array renderer, Image.draw() calls should be batched properly.
  • Slick clears the depth buffer by default (not sure why..). You may find a very slight performance increase by using container.setClearEachFrame(false) and then adding g.clear() to the beginning of your render method (it only clears the color buffer).
  • There have been many improvements to Slick2D over the past few months, so please test with the latest version. Also be sure to use the latest version of LWJGL.
  • You should also call container.setShowFPS(false) when benchmarking, and show FPS in some other manner (i.e. every couple seconds print it to stdout, or set the window title through Display.setTitle).

Thanks a lot for this! I figured there must be things I could to to speed stuff up. I can't test these improvements now since I'm on my work laptop right now, but will post the results. By the way, I do enjoy working with Slick2D a lot, it's a very pleasant and accessible library to work with  Grin

Offline princec

JGO Kernel


Medals: 343
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #19 - Posted 2012-08-10 10:51:11 »

By all means benchmark the shitout of things cas, especially on android, doesn'tmatter on the desktop imo Smiley
I'm 100% sure libgdx is rather a lot faster tha SPGL2 on Android coz I don't have any native code or hax to help speed it up Cheesy Having said that I have been thinking perhaps I should base SPGL2 on top of low level libgdx.

Cas Smiley

Offline Grunnt

JGO Wizard


Medals: 66
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #20 - Posted 2012-08-10 14:27:30 »

Ok, thanks a lot to davedes for the advice. I adjusted the slick code, and now it renders at roughly the same speed as the libdgx code Grin So the main issue appeared to be the use of the "begin" and "end" commands, and using drawEmbedded instead of draw. I just have to figure out rotation etc..

Here's the faster 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  
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;

public class SlickTest extends BasicGame {

   private Image image;
   private long lastFpsTime;
   private float angle;

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

   @Override
   public void render(GameContainer container, Graphics graphics) throws SlickException {
      image.startUse();
      for (int i = 0; i < 30000; i++) {
         angle += 6.28f / 200f;
         image.drawEmbedded(200 + (float) Math.cos(angle) * 100f, 200 + (float) Math.sin(angle) * 100f,
               image.getWidth(), image.getHeight());
      }
      image.endUse();
   }

   @Override
   public void init(GameContainer container) throws SlickException {
      image = new Image("image/test.png");
      lastFpsTime = System.nanoTime();
   }

   @Override
   public void update(GameContainer container, int delta) throws SlickException {
      if (System.nanoTime() - lastFpsTime > 1000000000) {
         System.out.println(container.getFPS());
         lastFpsTime = System.nanoTime();
      }
   }

   public static void main(String[] args) throws SlickException {
      AppGameContainer app = new AppGameContainer(new SlickTest());
      app.setShowFPS(false);

      app.setDisplayMode(800, 600, false);
      app.setTargetFrameRate(300);
      app.start();
   }
}

Offline badlogicgames
« Reply #21 - Posted 2012-08-10 15:30:50 »

By all means benchmark the shitout of things cas, especially on android, doesn'tmatter on the desktop imo Smiley
I'm 100% sure libgdx is rather a lot faster tha SPGL2 on Android coz I don't have any native code or hax to help speed it up Cheesy Having said that I have been thinking perhaps I should base SPGL2 on top of low level libgdx.

Cas Smiley

Yes, yes you should. We still haven't had your lovely skype convo. Maybe this weekend?

http://www.badlogicgames.com - musings on Android and Java game development
Offline ReBirth
« Reply #22 - Posted 2012-08-10 15:32:59 »

@OP
maybe your faster slick code can be put on wiki.

Offline appel

JGO Wizard


Medals: 50
Projects: 4


I always win!


« Reply #23 - Posted 2012-08-10 15:39:33 »

Valuable thread. I'm sure a few have wondered about the exact same question and reasons for this. And although I knew it was a question about rendering techniques, using immediate mode vs. vertex arrays/buffer, we now have an answer.

Hopefully those in charge on Slick now will revolutionize how rendering is accomplished to make it comparable to libgdx speeds.

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

JGO Wizard


Medals: 66
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #24 - Posted 2012-08-10 17:11:33 »

Hopefully those in charge on Slick now will revolutionize how rendering is accomplished to make it comparable to libgdx speeds.

I think they already did that Grin At least, the Slick2D "Performance & Memory Tips" wiki entry gives all the information you need.

Offline Grunnt

JGO Wizard


Medals: 66
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #25 - Posted 2012-08-10 18:08:20 »

This is soo cool! Now I can support 10 times as many ships (15000 simultaneously quite easily) using Slick2D. I'm so happy Grin

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 757
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #26 - Posted 2012-08-10 18:30:32 »

Why is nobody abusing the new try-with syntax yet? Clueless

1  
2  
3  
4  
5  
try (image.with()) {
   for (int i = 0; i < n; i++) {
      image.useEmbedded(...);
   }
}

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

Senior Member


Medals: 2
Projects: 1


"For the last time, Hats ARE Awesome"


« Reply #27 - Posted 2012-08-11 16:47:29 »

Why is nobody abusing the new try-with syntax yet? Clueless

1  
2  
3  
4  
5  
try (image.with()) {
   for (int i = 0; i < n; i++) {
      image.useEmbedded(...);
   }
}


Oh this is the first time I see this Cheesy What exactly does this?
Offline ReBirth
« Reply #28 - Posted 2012-08-12 05:27:35 »

The try-with syntax as far as I know is used for close something that should be closed, like *Stream object. I still dont know if it'll trigger close() method automatically or not.

Offline sproingie

JGO Kernel


Medals: 202



« Reply #29 - Posted 2012-08-12 07:00:03 »

I still dont know if it'll trigger close() method automatically or not.

It will, as soon as the scope of the try block is exited.  That's the contract of AutoClosable which is what makes the whole try-with-resource thing work.
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.

CogWheelz (18 views)
2014-07-30 21:08:39

Riven (27 views)
2014-07-29 18:09:19

Riven (16 views)
2014-07-29 18:08:52

Dwinin (14 views)
2014-07-29 10:59:34

E.R. Fleming (35 views)
2014-07-29 03:07:13

E.R. Fleming (13 views)
2014-07-29 03:06:25

pw (44 views)
2014-07-24 01:59:36

Riven (45 views)
2014-07-23 21:16:32

Riven (30 views)
2014-07-23 21:07:15

Riven (31 views)
2014-07-23 20:56:16
List of Learning Resources
by SilverTiger
2014-07-31 18:29:50

List of Learning Resources
by SilverTiger
2014-07-31 18:26:06

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

HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54
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!