JMEDesktop stuttering

Tora said:

Also that may be of interest to you:

Tuning Garbage Collection with Java 5.0 VM




Yep. Thanks. I was actually reading that and trying various settings earlier today. So far not luck.
Tora said:

Try to not to call repaint() inside setText().

Anyway, we don't know what else you've got on your code. If you do a setText() at 500fps for example, you're creating 500 strings per frame, thats a lot of strings ;)

There could be a lot of things involved. But you can isolate the problem by removing parts of your ui. For example, don't update any label. If the blocking persists, probably it was something else, so try stop updating any other things until you find out what was causing the problem.

We could help you better if you could provide some 'test case' to show us. A small application doing something that presents the same symptons as your full application.

Edit: As Llama said before, the 'desktop' JMEDesktop shows is a texture. That needs to be recreated each time something changes. And loaded into video memory. That's expensive, very expensive ;) One thing you can do to check if it's that, is to create your JDesktop as a usual swing JDesktop, not being rendered inside the opengl window but as a normal swing frame.


Well, if I don't use repaint() then how do I get swing to call paint every time a value changes?

Just a little bit about the app, I'm only running fixedLogic at 20 ticks per second. So yeah, 20 times per second setText gets called on several text components. For my test I have about 30 on the screen, but only 7 are being actively refreshed. I'm only using a single JMEDesktop and I'm attaching the components directly to it. The one thing that I mentioned earlier and has me a little miffed is why are my fps showing exactly 20? I would think they should be higher. Don't know if that could help the issue (probably not), but it just struck me as an anomaly that the fps mached my logic rate.

Thanks again for all the suggestions!

Hi!



Call repaint somewhere else, not inside the component. Thats what I wanted to say :wink:



I'm not sure right now about the fixed logic rate application base, but if your logic is updating at 20fps, why would you need your display being refreshed at a higher frame rate? Nothing should change on your display unless something changed on your logic. Methinks.

Made a quick test using the examples, and adding 30 labels. Updating them all causes horrible things XD Just updating four of them still is ugly.



So my final advice is: Don't use JMEDesktop for that purpose.



I think Llama had the answer, too much texture processing on each frame. That along the swing things is just a killer for the performance.



I don't believe there's a solution, swing designers didn't focus on that use and the texture thing is just as is. So looks like you have to implement your own 3d labels using the jme text classes, or maybe using one of the other ui implementations for jme as bui or nui.



Looking at what you posted first, seems that you don't use any decorations on your labels, just the 'plain text' with no borders or backgrounds. So using the text classes provided by jme to render text on screen seems to fit. If you don't like the font, you can use another :wink:



Sorry for not finding a way to solve this using swing. I'm out of ideas now.

Interesting. I would have to agree with you that the problem is in painting, because yesterday when I wasn't repainting and the values where changing slowly I didn't see the problem. Whenever I repainted whenever the value was changed (every 20th of a second), I started seeing the problem. Anyway, I did your test and the values were pretty much like this:



updated: 316:282

updated: 251:22

updated: 316:282

updated: 316:22

updated: 251:22



So I reduced the size of the text fields down to about 34:22 and the problem occured about that much less proportionally. It still happens, just far more infrequently.



The reason you probably didn't see much of a performance hit with typing fast is that it seems to be worse when several components are being repainted. If it's just one component, then I don't really see the problem (from what I can tell). Unless in that case I'm just seeing the problem so much less that it only occurs every 10 minutes and I'm not testing long enough.



Here's the thing that miffs me. I played around with all kinds of gc settings so it would try to gc more frequent, but faster collections and it still stuttered when it finally decided to jettison the swing garbarge. Am I missing someething or is that not the crux of the problem?


I assume the size of your label that holds the value your are changing is smaller than 316:282 pixels. So the question is, what more is repainting and why?



After all, why would it be different if I type a value in a textfield (the whole texfield gets repainted), or if you use

speedText.setText(ship.getCurrentSpeed() + "m/s");

?  Or did you suddenly increase the scope of your project without telling us? :slight_smile:



First thing I'd suspect is the layout manager. Make sure your component stays the same width, so the layout manager doesn't decide to repaint a lot of other things.






Good golly miss molly. I must be tired this morning to have missed that. Well, I checked and I definitely do not have a text field that large. What I see happening is for every 7 setText calls (the number of text fields being updated during each iteration) there is one call to LWJGLImageGraphics update(). In most cases it is printing "updated: 316:22" but then (and sometimes this is every other call) it gives "updated: 316:282". The only thing I can think of is that this is the total extent of all the updated text components as they are grouped into an area of about 316x282. To my knowledge the size of the fields are definitely not changing. They are all fixed at 247x18.



I'm even more puzzled now.

BTW, I pulled all these variable declarations out of their methods to cut down on the gc. It seems to have helped the situation, but not completely eliminated it.



    private ByteBuffer scratch;

    private ByteBuffer tempData;

    private boolean updateChildren;

    private boolean hasMipMaps;

    private int dx1;

    private int dy1;

    private int dx2;

    private int dy2;

    private int dw ;

    private int dh;

    private Composite composite;



I can post the whole class if you think these changes should be checked in.

Aaah, so you have several textfields you are updating each frame? Here I was being all puzzled why one tiny textfield could be making everything to slow :slight_smile:

Maybe you can use one textfield total (using linefeeds)?

A wild suggestion…



Why not handle all the text you want to print in just one single JComponent?



That is, implementing a 'multitext label', which may have something like this:



setText(int index, String text);



and paint every text you set on it's paint method, arranging it by yourself, so you can also get rid of layout managers.

llama said:

Aaah, so you have several textfields you are updating each frame? Here I was being all puzzled why one tiny textfield could be making everything to slow :)
Maybe you can use one textfield total (using linefeeds)?
Tora said:

A wild suggestion....

Why not handle all the text you want to print in just *one* single JComponent?

That is, implementing a 'multitext label', which may have something like this:

setText(int index, String text);

and paint every text you set on it's paint method, arranging it by yourself, so you can also get rid of layout managers.



That was a wild suggestion. So I tried it. :lol:

I wrote a custom JComponent class that holds an array of all the text I need updated. Then it goes through an update loop and only once does it repaint() if one of those field values has changed. Mind you it's just drawing them directly onto my parent component, no other JComponents are invovled. Ok. So basically what I have now is just one large component updating fairly frequently. And it is just as bad as several JTextField components updating frequently. So the bottom line is, contrary to what your girlfriend might tell you, it's the size that matters, not the number of components. I guess because in this case it's still creating a 404:304 texture (roughly the area of all the text that I need to render) and Swing or JME's implementation just can't handle a texture larger than say 15x200 being updated regularly.

Ugh.

Just to clarify. If you wanted a test case, I'm sure if you put just two tiny JTextFields, say containing just one number, with one component in the upper left corner of the screen and one in the lower right corner, and then updated them regularly, you'd probably have a pretty severe problem because it would be rendering a 1280x1024 (or whatever size your screen is) texture.

Updating a texture with OpenGL should slow your framerate, but not create stuttering (at least not due to garbage collecting). Do you still have actual stuttering, and do you still see spikes in the GC view? If so, where does the garbage come from?



Like I said, the BufferedImage -> Texture uploading process is not that great. The awtImage.getRaster().getDataElements( dirty.x, dirty.y, dirty.width, dirty.height, data ) in particular seems slow. So we could try and optimize that, but if you still get random stuttering every 5/10 seconds, that's of little use.



For example, I wrote a video-to-texture package for jME that updates things like a 640x480 texture 30 times a second (using the same OpenGL method at LWJGLImage), without much problems. You still have plenty CPU left, even after decoding the video stream.

Something that could help:



jmeDesktop.getJDesktop().setDebugGraphicsOptions(DebugGraphics.LOG_OPTION|DebugGraphics.BUFFERED_OPTION);



Prints what the swing is doing. And seems that does a huge lot of things!  :-o

The stuttering is maybe a bit more infrequent that 5-10 seconds now. It happens say every 45-60 seconds when the big gc kicks in. I wish I had a better grasp of YourKit to analyze the gc. Would it be helpful if I sent you a snapshot of memory?



I turned on the debugging and this is what I got for one frame. Seems like a bit of redundant stuff going on. And why is it constantly setting the font and color? I guess I just don't understand the low level workings of Swing.



Graphics(34027-5) Enabling debug

Graphics(34027-5) Setting color: sun.swing.PrintColorUIResource[r=51,g=51,b=51]

Graphics(34027-5) Setting font: javax.swing.plaf.FontUIResource[family=Dialog,name=Dialog,style=plain,size=12]

Graphics(34029-5) Setting color: java.awt.Color[r=0,g=0,b=0]

Graphics(34029-5) Filling rect: java.awt.Rectangle[x=0,y=0,width=1280,height=1024]

Graphics(34031-5) Setting color: java.awt.Color[r=110,g=110,b=110]

Graphics(34031-5) Setting font: java.awt.Font[family=Arial,name=arial,style=bold,size=16]

Graphics(34031-5) Setting color: java.awt.Color[r=110,g=110,b=110]

Graphics(34031-5) Setting font: java.awt.Font[family=Arial,name=arial,style=bold,size=16]

Graphics(34033-5) Setting color: java.awt.Color[r=110,g=110,b=110]

Graphics(34033-5) Drawing string: "5037m" at: java.awt.Point[x=0,y=15]

Graphics(34034-5) Setting color: java.awt.Color[r=110,g=110,b=110]

Graphics(34034-5) Setting font: java.awt.Font[family=Arial,name=arial,style=bold,size=16]

Graphics(34034-5) Setting color: java.awt.Color[r=110,g=110,b=110]

Graphics(34034-5) Setting font: java.awt.Font[family=Arial,name=arial,style=bold,size=16]

Graphics(34036-5) Setting color: java.awt.Color[r=110,g=110,b=110]

Graphics(34036-5) Drawing string: "0m/s" at: java.awt.Point[x=0,y=15]

Graphics(34037-5) Setting color: java.awt.Color[r=110,g=110,b=110]

Graphics(34037-5) Setting font: java.awt.Font[family=Arial,name=arial,style=bold,size=16]

Graphics(34037-5) Setting color: java.awt.Color[r=110,g=110,b=110]

Graphics(34037-5) Setting font: java.awt.Font[family=Arial,name=arial,style=bold,size=16]

Graphics(34039-5) Setting color: java.awt.Color[r=110,g=110,b=110]

Graphics(34039-5) Drawing string: "880m" at: java.awt.Point[x=0,y=15]

Graphics(34040-5) Setting color: java.awt.Color[r=110,g=110,b=110]

Graphics(34040-5) Setting font: java.awt.Font[family=Arial,name=arial,style=bold,size=16]

Graphics(34040-5) Setting color: java.awt.Color[r=110,g=110,b=110]

Graphics(34040-5) Setting font: java.awt.Font[family=Arial,name=arial,style=bold,size=16]

Graphics(34042-5) Setting color: java.awt.Color[r=110,g=110,b=110]

Graphics(34042-5) Drawing string: "0m/s" at: java.awt.Point[x=0,y=15]

updated: 199:22 - 487.0, 335.0



BTW, for this test I reverted to using JLabel for the text.

Yes, seems that swing does a lot of work for painting a single label :wink:



I've tried 30 custom labels, with the following parameters on the jvm:



-XX:+UseParallelGC

-Xoptimize

-XX:+DisableExplicitGC

-XX:+UseBiasedLocking

-XX:+UseParallelOldGC

-XX:+AggressiveOpts

-Xms128M

-Xmx128M



Now I've got a stable 30-36 fps, it doesn't stutter. Without doing the text setting was 400-500 fps, so it's not really that great XD


Improved the frame rate to ~120fps! :smiley:



Instead of calling repaint on each label, I called the repaint on the panel from the interfal  frame:



 internalFrame.getContentPane().repaint();



Seems that doing that skipped a lot of 'swing' stuff :)
Tora said:

Improved the frame rate to ~120fps! :D

Instead of calling repaint on each label, I called the repaint on the panel from the interfal

The labels are inside a JInternalFrame. Instead of calling repaint() on each label, I call repaint() on the JInternalFrame.



Not sure how did you arrange the components, but if its different, try calling 'repaint' on their parent component. Or maybe on the parent of the parent component :wink: