JMEDesktop stuttering

I just spent a week implementing JMEDesktop throughout my game and I love it. The only problem is that it has introduced a stutter into my game. For example, in my test, I'm only displaying one JTextField that is setup like so:



speedText = new JTextField();

speedText.setSize(247, 18);

speedText.setLocation(550, 597);

speedText.setOpaque(false);

speedText.setBorder(null);

speedText.setForeground(TEXT_COLOR_DEFAULT);

speedText.setFont(DEFAULT_FONT);

speedText.setEditable(false);

speedText.setFocusable(false);





In the update loop I do call setText on it like:



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



And sure enough, about every 5-10 seconds at random intervals it will stutter the whole game for a split second. But it's too noticable to ignore. I've tried a few different things, but nothing seems to stop the stutter other than removing the setText call. Ugh. Please help! I really want to use JMEDesktop. I'll provide whatever you need to test. Just let me know.



Many thanks,



Slowdive




What is your FPS right now? Seems like too much garbage is created. Try setting the text at a more reasonable interval (like every second instead of every frame). Eg. if you're using those anonymous inner classes in combination with SwingUtils.invokeLater, that creates garbage. Also, never use invokeAndWait from your update loop… as you can't be sure how long it will wait.






Currently FPS are showing 20 fairly solid. That kind of surprises me, because I'm using fixedLogicRateGame at 20 ticks per second, but would expect fps to be really high considering I'm running a GeForce 7900GT. Hmm.



But anyway, I'm not using any anonymous inner classes with these info text boxes, nor am I using invokeLater or invokeAndWait, just calling it straight from the GameState update method. I had previously tried lowering the calls to setText to 10 per second and still had the problem. Just now I tried 1 per second and the problem seems to have gone away, but 1 update per second is useless for in game information like speed and distance that is changing many times a second.:frowning:



Thanks for the hints though. Any other thoughts?

All Swing methods should be done from the Swing thread.



http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html



Not doing that can lead to completly unexpected results… maybe this is one of them.

Yep. I thought of that, I had already tried to use InvokeLater like so:



Constructor:



doWorkRunnable = new Runnable() {

    public void run() { speedText.setText(ship.getCurrentSpeed() + "m/s");}

};



Update:



SwingUtilities.invokeLater(doWorkRunnable);



It still hickups.:frowning:

If you want speed, don't use swing :wink:



I would suggest that you use the same method of printing things on screen as the jme examples do. Create a text node and use StringBuffer. That would work great and won't produce performance hogs on your application :slight_smile:



Also check what jvm version you're using. On 1.4 swing doesn't works too swift… But from 1.5 onwards you get improved performance (and visuals). Anyway, still not recommended if you want to update values often and keeping the best performance.

No more ideas really. Maybe you should try some profiling (keep an eye on the garbage collector), try and find out what's going on here.



Texture updates (because the Swing frame changes) can slow you down a lot, but they don't create stutters later on. You wouldn't expect "setText" to be that heavy either.

Well I was using NUI for awhile and just the basic Text class, but Swing looks so much nicer than that fixed width stuff. My game is UI heavy and I need to fit as much text into a small area as possible. So that's why I liked JMEDesktop and Swing. I'm using JRE 1.5.06 btw. So I would think it should be ok from that standpoint.



The profiling idea sounds good, although I'm not very experienced with that. I would like to get to the bottom of this though. I'm sure it will be an issue for others if they do more than the simplest tasks with it.

Well, as irrisor usually states, JMEDesktop is not always ideal for GUI heavy games. Still doesn't explain the sturring for something this simple though.



If you can reproduce the problem in a very simple test, then I'll do some profiling if you want.

Thanks for the offer. I'd love to take you up on it, but my game at this point is rather complex and I don't think I could break out a sample piece to test with really. What tools are best for this sort of thing? I was about to take a shot using HPjtune.

For jME I use YourKit. That's not free however, it has a trial though. Netbeans has a pretty good profiler integrated…  maybe a good question for the offtopic forum if you need more?


Hi again!



You're using JTextField. If you want just 'print' values, and not entering any text, maybe it will help if you use JLabel.



This is the code that JTextField executes when you do 'setText()':



 public void setText(String t) {
        try {
            Document doc = getDocument();
            if (doc instanceof AbstractDocument) {
                ((AbstractDocument)doc).replace(0, doc.getLength(), t,null);
            }
            else {
                doc.remove(0, doc.getLength());
                doc.insertString(0, t, null);
            }
        } catch (BadLocationException e) {
       UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this);
        }
    }



And this is the code JLabel executes when you do 'setText()':


public void setText(String text) {

        String oldAccessibleName = null;
        if (accessibleContext != null) {
            oldAccessibleName = accessibleContext.getAccessibleName();
        }

        String oldValue = this.text;
        this.text = text;
        firePropertyChange("text", oldValue, text);

        setDisplayedMnemonicIndex(
                      SwingUtilities.findDisplayedMnemonicIndex(
                                          text, getDisplayedMnemonic()));

        if ((accessibleContext != null)
            && (accessibleContext.getAccessibleName() != oldAccessibleName)) {
                accessibleContext.firePropertyChange(
                        AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
                        oldAccessibleName,
                        accessibleContext.getAccessibleName());
        }
        if (text == null || oldValue == null || !text.equals(oldValue)) {
            revalidate();
            repaint();
        }
    }



I would say by the look of it, that JTextField does something more heavy than JLabel, despite that JLabel has more lines of code ;) Not sure what does involve the JTextField 'Document' operation, but as it was intended for user input and probably handles formattings and so, sure it won't be fast.

Try changing to JLabel, maybe it's worth it :)

EDIT: Just forgot to say that maybe implementing your own text component would be the best solution. You can extend JComponent and do exactly what you want and much more optimized, avoiding all those 'extra' operations for the JLabel & JTextField components.

Tora,



That's a really good suggestion. I tried it, but unfortunately it still made no difference. Right now I'm playing around with garbage collection settings. I don't know if this is going to yield anything though. It just seems odd to me that gc for this method is causing the whole app to just hang for maybe .2-.5 seconds. The setText method seems poorly written to me. Why are they creating a 2 new vars every call and who knows how many further on down the line?



I did find this interesting thread where someone seemed to be having the same stuttering issue with swing:



http://www.javagaming.org/forums/index.php?topic=8405.0



This is just so frustrating.

If you still want to try already existing classes, try the Label from awt (not swing). It has less operations on its setText() method:



public void setText(String text) {
        boolean testvalid = false;
   synchronized (this) {
       if (text != this.text && (this.text == null ||
                  !this.text.equals(text))) {
           this.text = text;
      LabelPeer peer = (LabelPeer)this.peer;
      if (peer != null) {
          peer.setText(text);
      }
      testvalid = true;
       }
   }

   // This could change the preferred size of the Component.
   if (testvalid && valid) {
       invalidate();
   }
    }



I've developed some tools using swing, most of them which rely on some heavy graphics operations and so, and I usually ended up implementing my own components as the swing provided ones didn't work well or didn't fit well enough on what I needed. Is worth it when you're not developing typical desktop applications, so if the awt Label still doesn't give you what you want, just try to implement your own Label (SlowdiveLabel ;)). Remember to use StringBuffer instead of Strings, as it would help to avoid a huge lot of garbage generation.

Also that may be of interest to you:



Tuning Garbage Collection with Java 5.0 VM


I'm not sure an AWT class will work with JMEDesktop.

You're right, Llama. Tried it and AWT's Label doesn't shows on JMEDesktop.



So Slowdive, seems that your best bet would be implement your own Label (and/or finetuning the garbage collector). Good luck!

Ok. I'm ready to jump out the window.  :expressionless:



I extended JComponent and overrode these two methods:



   public void paint(Graphics g) {
      g.drawString(textValue, 0, 14);
   }
   
   public void setText(String text){
         textValue = text;
         repaint();
   }



Guess what? IT STILL STUTTERS! Pardon my acronym, but WTF? Can it get any simpler than that? Am I missing something? Gah!!!!  :P

Whew. Ok. Banged my head hard on the table for a little bit and feel better now.  :smiley:



Anyway, I've noticed something. It actually doesn't stutter (from what I can observe) when just one text item is updating. But when you add in 6 or 7, then it is much more pronounced. So could something be blocking in the Swing thread? Maybe that's just desperation talking. I guess it is related to GC. I'm just at a loss.



BTW, I tried invoking the repaint later and it didn't change a thing.

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 :wink:



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 :wink: 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.