Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (539)
Games in Android Showcase (133)
games submitted by our members
Games in WIP (603)
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  
  Can a Swing GUI be used in a direct-rendering game?  (Read 9450 times)
0 Members and 1 Guest are viewing this topic.
Offline CommanderKeith
« Posted 2006-04-08 14:10:20 »

Hi,

I just gave up on the roll-my-own GUI and converted to Swing - its what I know and its beautiful.  I use direct rendering in my game loop thread and while I know that painting Swing/AWT components directly from such a thread is not safe, I read in a book somewhere that you can stop the AWT Event dispatching thread from painting by installing a 'NullRepaintManager', a class you make as a sub-class of RepaintManager that over-rides:

public void addInvalidComponent(JComponent c)
public void markComponentDirty(JComponent c)
public void addDirtyRegion(JComponent c)
public void paintDirtyRegions()


with empty method bodies.  You install it as follows::

RepaintManager rm = new NullRepaintManager();
rm.setDoubleBufferingEnabled(false);
RepaintManager.setCurrentManager(rm);


Apparently that stops 'OS-level' paint requests but I'm not sure if it stops internal painting on the AWT Event thread.  I did this to stop the AWT Event dispactching thread from painting so I can call aSwingComponent.paint(myGraphics) from my game thread without threading problems.  It seemed to work fine at first, but sometimes my game freezes and I fear that its because there is a thread conflict.  I assume its because things like JTextFields paint themselves (like the flashing caret) on some thread (the Event Dispatching thread?) which conflicts with the painting of that JTextField in my game loop thread.

How can I stop painting in the Event Dispatching thread for good or am I barking up the wrong tree?

Thanks,
Keith

Offline Jeff

JGO Coder




Got any cats?


« Reply #1 - Posted 2006-04-08 17:34:29 »

"Use the setIgnoreRepaint method on your application window and components to turn off all paint events dispatched from the operating system completely, since these may be called during inappropriate times, or worse, end up calling paint, which can lead to race conditions between the AWT event thread and your rendering loop."

http://java.sun.com/docs/books/tutorial/extra/fullscreen/rendering.html

This is pretty m,uch vrigin territory though so expect some gotcha's you'll have to figure out yourself.

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline CommanderKeith
« Reply #2 - Posted 2006-04-09 12:05:36 »

Thanks Jeff, I'll give it a go. 

That article in the java tutorial is a relief because all other Sun documentation says that Swing components can't be painted from any thread except the Event Dispatch thread....

Hopefully someone has used Swing in a direct-rendering game and can verify that it can be made to work. 

If I do get it working I'll post my experiences here.

Keith

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

Junior Devvie




Java games rock!


« Reply #3 - Posted 2006-04-09 12:55:41 »

You can also use the invokeAndWait (or invokeLater) method of javax.swing.SwingUtilities, that will allow you execute code in the Event Dispatch Thread. If you execute all the game code there eventually then it's much easier to have normal swing components as game controls, because you won't have to queue and synchronize everything.
Offline Jeff

JGO Coder




Got any cats?


« Reply #4 - Posted 2006-04-09 19:35:04 »

If you let Swing/AWT render your game then
(a) You lose performance.
(b) You lose predictability (when a paint actually happens is some-random-measure-of-time-after-the-repaint-is-called)

In general hthis works okay for non-action games, but for action games whre frame rate and close timing are critical, Id recommend against such a technique.

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline Jeff

JGO Coder




Got any cats?


« Reply #5 - Posted 2006-04-09 19:42:38 »


That article in the java tutorial is a relief because all other Sun documentation says that Swing components can't be painted from any thread except the Event Dispatch thread....


All the other articles youve read assume you are using Swing/AWT. If you were then yes, yo uwoudl have yo paint from the EVent thread because Swing is not thread safe.

 In this case you are totally by passing those mechanisms and turnign off Swing/AWT rendering entirely so its safe to paint from antoher thread.  You still shoudl only paint from one thread though.  (in active rendered apps this is generally your own game thread.)

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline CommanderKeith
« Reply #6 - Posted 2006-04-11 00:32:47 »

I'm really confused about this... there's conflicting info out there.

Although the AWT event thread can't paint the Swing components because I turned that off, it can still modify the state of the components at the same time I paint them from my game thread. 

For example, what if I paint a JButton from my game thread while its state is being changed in the AWT Event thread when the button is rolled over whith the mouse (or the JTextField is typed into, etc).  So how can I possibly paint Swing components from my own thread???  I fear this is why my game freezes when I play around with the Swing menus I added.

Thanks,
Keith

Offline Jeff

JGO Coder




Got any cats?


« Reply #7 - Posted 2006-04-11 00:42:19 »

I'm really confused about this... there's conflicting info out there.

Although the AWT event thread can't paint the Swing components because I turned that off, it can still modify the state of the components at the same time I paint them from my game thread. 

Painting does not modify model state so its perfectly safe as long as you dont re-enter the paint code.

I've never seen an issue with modifying the model from outside of the AWT threads.  If you want to be sure though, ask the guys in the JavaDesktop forums.

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline CommanderKeith
« Reply #8 - Posted 2006-04-11 02:11:20 »

Painting does not modify model state so its perfectly safe as long as you dont re-enter the paint code.

Great, I wasn't aware of that.  I wonder how that works because if I type delete (runs in AWT Event Thread) in a JTextField and remove a character mid-way through my game thread's paint, you'd think that there'd be an ArrayOutOfBoundsException or the like thrown when the game thread tries to paint the character that no longer exists.

This hasn't happened though, when I hold down delete in the JTextField after a short time my game thread just freezes and stops painting anything....  Anyhow, I'll make sure its not because I'm re-entering the paint code accidentally.

Cheers,
Keith

Offline DaveLloyd

Junior Devvie




Making things happen fast with Java!


« Reply #9 - Posted 2006-04-11 12:51:53 »

Yep, Swing on JOGL works fine for me. Ignore repaints and repaint the swing parts afresh each frame.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline CommanderKeith
« Reply #10 - Posted 2006-04-11 13:25:24 »

Thanks Dave, that's good to know.  Unfortunately my experiences are of deadlocking.  And I just found these articles that its unsafe to use Swing at all unless its from the Event dispatch thread (EDT).

From a Sun developers blog site - http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html

"Initially there was a rule that it is safe to create and use Swing components until they are realized
but this rule is not valid any more, and now it is recommended to interact with Swing from EDT only"

And this on the Java Tutorial site - http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html

"To avoid the possibility of deadlock, you must take extreme care that Swing components and models are created, modified, and queried only from the event-dispatching thread. "

The above tell me that Swing cannot be directly-rendered (ie painted directly in a separate game thread).  But this conflicts with the full-screen mode tutorial - http://java.sun.com/docs/books/tutorial/extra/fullscreen/rendering.html:

"Feel free to call Swing methods such as paintComponents, paintComponent, paintBorder, and paintChildren directly from your rendering loop"

For my Swing menus I have only had deadlocks a couple of times, but the JTextFields I use reliably cause AWT Event thread deadlocks when I type or delete characters.  What kind of Swing components are you using in your game?  Maybe it only works because you use simple components which rarely cause a dead-lock with your game thread.

I'd love to hear other developer's experiences, surely not everyone has created their own self-rolled GUI.  I assumed Swing was the default for game developers...

Cheers,
Keith

Offline DaveLloyd

Junior Devvie




Making things happen fast with Java!


« Reply #11 - Posted 2006-04-11 13:35:22 »

Quote
For my Swing menus I have only had deadlocks a couple of times, but the JTextFields I use reliably cause AWT Event thread deadlocks when I type or delete characters.  What kind of Swing components are you using in your game?  Maybe it only works because you use simple components which rarely cause a dead-lock with your game thread.
I think I'm using virtually every Swing component known somewhere or other! Not everything works quite as expected (JOptionPane is a big no-no) but mostly it does. All my painting etc is done ultimately under the JOGL display () method which I suspect is in fact on the EDT.

Offline Jeff

JGO Coder




Got any cats?


« Reply #12 - Posted 2006-04-11 18:41:24 »


The above tell me that Swing cannot be directly-rendered (ie painted directly in a separate game thread).  But this conflicts with the full-screen mode tutorial - http://java.sun.com/docs/books/tutorial/extra/fullscreen/rendering.html:

Given that MIke Martak, the author, was part of the AWT team at the time he wrote that article.  Id personally trust him unless you find later stuff thats epcificly says this as broken.

Keep in mind that full-screen exclusive mode is an esoteric thing that very few people whow rite abotu Swing even know exists.

Quote
For my Swing menus I have only had deadlocks a couple of times, but the JTextFields I use reliably cause AWT Event thread deadlocks when I type or delete characters.

How are you using them? Id like to see the code as Im having trouble even iomaging a  multi-trheaded access case to the model..


Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline Ask_Hjorth_Larsen

Junior Devvie




Java games rock!


« Reply #13 - Posted 2006-04-12 01:11:30 »

If pressing a button or doing anything with the mouse - which all happens from the EDT *UNLESS* lots of work is done to requeue all the stuff to the game thread in every mouse listener and... jeez I'm dizzy now - affects the game state, and if on the other hand the game state might affect the model of a swing component (say, a thing dies and is removed from a list) then we have two threads accessing the model of a swing component.

I am surprised that this isn't a common problem, which is why I made a thread (org.javagaming.Thread, not java.lang.Thread Smiley ) about it a while ago, and it basically seemed that no one uses swing components for their games. I for one don't want to write my own version of JTree so I use the approach mentioned by me above (SwingUtils.invokeAndWait to ensure logic update and active rendering from the EDT). Really, it's the only solution I can imagine!
Offline fletchergames

Senior Devvie





« Reply #14 - Posted 2006-04-12 01:49:12 »

I use Swing Components in direct-rendering games as well.  In fact, I set up one Component for the whole screen that everything gets drawn to.  I use regular Components as well.  Dialogs are the only things that don't seem to work.

I also have a NullRepaintManager and used setIgnoreRepaint to true.  Here's my code that actually draws the Components to the screen:

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  
/**   shows the GameFrame*/
public void showFrame() {
   //initialization
   BufferStrategy bufferStrategy = mainFrame.getBufferStrategy();
   Graphics g = bufferStrategy.getDrawGraphics();

   if(!(g instanceof Graphics2D)) {
      ErrorLog.output(
         ErrorList.applicationGameFrameGraphics2DUnavailableInShowScreen);
      System.exit(0);
   } //end if we don't have a Graphics2D

   final Graphics2D g2 = (Graphics2D)g;
   g2.setRenderingHints(renderingHints);
   Insets insets = mainFrame.getInsets();
   g2.setTransform(AffineTransform.getTranslateInstance(insets.left, insets.top));

   //draw Swing components
   //wrap the drawing in an EventQueue if and only if this method isn't already in an
   //the AWT event thread.  Swing Components must be drawn in the AWT event thread, but
   //invokeAndWait can't be called from within the AWT event thread.
   final JLayeredPane layeredPane = mainFrame.getLayeredPane();
   try {
      //if this is in the AWT event thread, just paint the components
      if(EventQueue.isDispatchThread())
         layeredPane.paintComponents(g2);
      else { //else this isn't in the AWT event thread, so invokeAndWait
         EventQueue.invokeAndWait(new Runnable() {
            public void run() {layeredPane.paintComponents(g2);}
         });
      } //end else this isn't in the AWT event thread
   } catch(Exception exception) {
      ErrorLog.output(exception,
         ErrorList.applicationGameFrameErrorPaintingComponents);
   }

   //on Linux, this prevents tearing
   Toolkit.getDefaultToolkit().sync();

   //stop drawing and flip the buffer
   g.dispose();
   bufferStrategy.show();
} //end showFrame


I doubt the code will help you because you're already doing the same thing.  But I posted it anyways.  It was originally inspired by similar code from a book called "Developing Games in Java".  My code's "better" than the code in the book, but it's the same general idea.
Offline CommanderKeith
« Reply #15 - Posted 2006-04-12 03:06:41 »

Thanks everyone for the help.

I am surprised that this isn't a common problem
Me too. 

I tried to make a test case that produced the same problem but it's working fine >> not deadlocking which I couldn't understand.  But now I realize that in my game the JTextField is in a movable JInternalFrame whilst in the test case it isn't.  Perhaps I'm having the same trouble as fletchergames since JInternalFrames are probably similar to Dialogs- "Dialogs are the only things that don't seem to work". 

How are you using them? Id like to see the code as Im having trouble even iomaging a multi-trheaded access case to the model..

I'll post the test case when I get home and have tried it with the JInternalFrame.  Basically I create a frame and put compnents in it and just continuously paint them in the main thread.  I manipulate the components with the mouse & keyboard (and this happens in the EDT which must sometimes conflict with the main thread, but doesn't for my current test case....)

It was originally inspired by similar code from a book called "Developing Games in Java".
Yes! By David Brackeen, that's the book where I got the code from.  Thanks for posting your code. 

The interesting thing about what you do is that you paint your Swing components in the EDT (through invokeAndWait) onto the BufferStrategy and then you show the BufferStrategy in your own thread.  So you're kind of using a weird combination of passive and active rendering.  This should have the same draw back pointed out by Jeff earlier that (part of) the painting is done in the EDT - so your screen paints may come late while you wait for the EDT to do the job - not really direct/active rendering.

Since all of you - Dave, fletchergames and Ask_Hjorth_Larsen seem to only be having success with painting from the EDT then perhaps Swing cannot be used for non-JOGL direct-rendering games.

But I'll look deeper into my test case (which is working, strangely enough) and I'll post the code ASAP.

Keith

Offline CommanderKeith
« Reply #16 - Posted 2006-04-12 06:21:08 »

From - http://www.clientjava.com/blog/2004/08/24/1093363375000.html

"The single-thread rule (from the Java Tutorial)
Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread.
...
Realized means that the component's paint() method has been or might be called. A Swing component that's a top-level window is realized by having one of these methods invoked on it: setVisible(true), show(), or (this might surprise you) pack()."

Since painting depends on the state of the component then painting from outside the Event Dispatch Thread (EDT) must not be thread-safe.  Is this reasoning correct because it makes Swing useless for active-rendering and also contradicts what Jeff said in an earlier post. 

Thanks,
Keith

PS:
Keep in mind that full-screen exclusive mode is an esoteric thing that very few people who write about Swing even know exists.
I only mentioned the full screen mode tutorial because it prescribes calling setIgnoreRepaint() on components.  I am not actuallly using full screen mode when doing direct-rendering with Swing.


Offline Jeff

JGO Coder




Got any cats?


« Reply #17 - Posted 2006-04-12 21:59:07 »

If pressing a button or doing anything with the mouse - which all happens from the EDT *UNLESS* lots of work is done to requeue all the stuff to the game thread in every mouse listener

Right.  hats one thread.

Where is the other one?

Its that which im having a hard time imgining.

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline Jeff

JGO Coder




Got any cats?


« Reply #18 - Posted 2006-04-12 22:08:03 »

From - http://www.clientjava.com/blog/2004/08/24/1093363375000.html

"The single-thread rule (from the Java Tutorial)
Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread.
...
Realized means that the component's paint() method has been or might be called.

No.

In that context it means it has been ro might be called BY THE AWT PAINT tHREAD.

The problem with all these things you keep quoting is that they are ALL written with the asusmption that you are doing normal AWT/Swing repainting, *not* active rendering.

I'm  not saying your wrong, because I don't know those internals, but I think its more likely you are then you arent.  I DO knwo that all these articles are orthogonal to the issue.

This is because the ONLY source on this option and what it really does under the hood is Mike Martak, who is no longer with us and thus cannot comment.  Given that, I take his writings, which DO address manual painting, as definitive.

Question: have you gotten rid of all the WEIRD sh-t you were doing?
Quote
I read in a book somewhere that you can stop the AWT Event dispatching thread from painting by installing a 'NullRepaintManager', a class you make as a sub-class of RepaintManager that over-rides:

public void addInvalidComponent(JComponent c)
public void markComponentDirty(JComponent c)
public void addDirtyRegion(JComponent c)
public void paintDirtyRegions()

with empty method bodies.  You install it as follows::

RepaintManager rm = new NullRepaintManager();
rm.setDoubleBufferingEnabled(false);
RepaintManager.setCurrentManager(rm);

If not thats far more likely to be the cause of your problems.


Thats all I have to give on this subject and Im repeatign myself so I'll stop here.

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline CommanderKeith
« Reply #19 - Posted 2006-04-13 05:19:11 »

Test case that deadlocks:

import java.awt.*;
import javax.swing.*;
import java.awt.image.*;
import java.awt.geom.*;

public class SwingDirectRendering extends JFrame{

   public JPanel content;
   public JTextField textField;

   public SwingDirectRendering(){
       super("SwingDirectRendering Test");

      setIgnoreRepaint(true);         // disable OS-triggered repaint requests
      RepaintManager.currentManager(this).setDoubleBufferingEnabled(false);
      // disable double-buffering since we do this in the BufferStrategy

      content = new JPanel(new BorderLayout());
        setContentPane(content);

        textField = new JTextField("Type & delete stuff here", 50);

        JPanel panel = new JPanel(new BorderLayout());
        panel.add(textField);
        content.add(panel);
        //content.add(textField);   // comment out the above 3 lines and
                             // uncomment this and it will work -
                             // there will be no deadlock

      setUndecorated(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setExtendedState(MAXIMIZED_BOTH);

      setVisible(true);

      createBufferStrategy(2);
   }

   public static void main(String[] arrghImAPirate){
      SwingDirectRendering frame = new SwingDirectRendering();

      while (true){
         Graphics g = frame.getBufferStrategy().getDrawGraphics();

         //Graphics g = frame.content.getGraphics()
         // to show that its not a BufferStrategy
         // problem you can uncomment the above and leave
         // out the BufferStrategy code

         frame.content.paintComponents(g);
         frame.getBufferStrategy().show();
      }
   }
}


I've found that component.paintComponent(Graphics) works when its children have no child components themselves.  When its child components have their own child components then deadlock results.  You can see this by commenting out the intermediate JPanel that sits between the content pane and the JTextField.

Help appreciated  Smiley,
Keith

Offline CommanderKeith
« Reply #20 - Posted 2006-04-13 14:47:23 »

I said I'd tell how my experiences with Swing panned out, so...

I've read a lot about how GUIs work, including the SWT (IBM's alternative to AWT/Swing) and as far as I can see (not very), Swing is fundamentally flawed for use in direct-rendering games since it is so closely tied to the AWT Event Dispatch Thread (EDT).  As Ask_Hjorth_Larsen said it looks like the only thread-safe way Swing can be used is to have the whole game running in the EDT which won't work.

The SWT (Standard Widget Toolkit) would work in direct-rendering games since there is no EDT, all communication with the Operating System for events and painting is done through the main thread.  But I've decided not to use the SWT because its not completely flexible & portable due to the way SWT components are all backed by their native/heavyweight OS equivalents.

I've decided to go with my own crappy GUI system because at least it works and I know what it's doing.

I'd love to know if anybody has used Swing successfully without doing EventQueue.invokeAndWait() etc, but unless I've stuffed up something obvious, the above example shows how Swing can't be used in a direct-rendering game.

Keith

Offline Luke

Senior Newbie




I love YaBB 1G - SP1!


« Reply #21 - Posted 2006-04-13 15:40:26 »

I think the problem is that the AWT event thread is accessing your swing components at the same time that you are drawing them from another thread.  I have had the same problem and the following solution worked for me.

Add the following class..
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 java.awt.AWTEvent;
import java.awt.EventQueue;
import java.awt.Toolkit;

//import jfreerails.controller.ReportBugTextGenerator;


/**
 * This event queue is synchronized on the MUTEX. This lets one control when
 * events can be dispatched.
 *
 * Note, changed to be a singleton to get it working on pre 1.4.2 VMs.
 *
 * @author Luke
 *
 */

final public class SynchronizedEventQueue extends EventQueue {
   public static final Object MUTEX = new Object();

   private static final SynchronizedEventQueue instance = new SynchronizedEventQueue();

   private static boolean alreadyInUse = false;

   /** Enforce singleton property. */
   private SynchronizedEventQueue() {
   }

   public static synchronized void use() {
      if (!alreadyInUse) {
         /* set up the synchronized event queue */
         EventQueue eventQueue = Toolkit.getDefaultToolkit()
               .getSystemEventQueue();
         eventQueue.push(instance);
         alreadyInUse = true;
      }
   }

   protected void dispatchEvent(AWTEvent aEvent) {
      synchronized (MUTEX) {
         try {
            super.dispatchEvent(aEvent);
         } catch (Exception e) {
            /*
             * If something goes wrong, lets kill the game straight away to
             * avoid hard-to-track-down bugs.
             */

            //ReportBugTextGenerator.unexpectedException(e);
         }
      }
   }
}


then change your game loop to...

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
public static void main(String[] arrghImAPirate) {
      SwingDirectRendering frame = new SwingDirectRendering();
      SynchronizedEventQueue.use();
      while (true) {
         synchronized (SynchronizedEventQueue.MUTEX) {

            Graphics g = frame.getBufferStrategy().getDrawGraphics();

            //Graphics g = frame.content.getGraphics()
            // to show that its not a BufferStrategy
            // problem you can uncomment the above and leave
            // out the BufferStrategy code

            frame.content.paintComponents(g);
            frame.getBufferStrategy().show();
         }
      }
   }


On my machine it seems to solve the deadlock problem.

Hope it helps

Luke
Offline CommanderKeith
« Reply #22 - Posted 2006-04-13 16:41:48 »

100% Sensational!    Cheesy  Luke you are a legend, that peice of code is a silver bullet!

Not only is it kicking ass in the test case but I just tried it in my game and it works perfect!

I thought that the synchronized block would sap performance but no, the frame rate doesn't change whether or not I use the SynchronizedEventQueue.  That's a very elegant solution.
Being able to use Swing in my menus will make life a lot easier Cool.

By the way, what is the cost (if any) of sync'ing these events?  Speed? Mouse & keyboard responsiveness? In the test case how much of the game loop needs to be synchronized?  To reduce cost of sync'ing, could you safely change it to this since much time is taken blitting from the bufferStrategy to the screen compared with painting to the bufferStrategy:

while (true) {

  Graphics g = frame.getBufferStrategy().getDrawGraphics();
  synchronized (SynchronizedEventQueue.MUTEX) {
    frame.content.paintComponents(g);
  }
  frame.getBufferStrategy().show();
  }
}

Many thanks,
Keith

Offline fletchergames

Senior Devvie





« Reply #23 - Posted 2006-04-15 18:14:49 »

I think the problem is that the AWT event thread is accessing your swing components at the same time that you are drawing them from another thread.  I have had the same problem and the following solution worked for me.

...

Wow, I never thought of trying anything like that before.  When I get a chance, I'll try doing something similar in my code to see what happens.  Thanks for the idea.
Offline Ask_Hjorth_Larsen

Junior Devvie




Java games rock!


« Reply #24 - Posted 2006-04-16 17:15:51 »

Whoa, whoa, wait a minute.

It's possible to use active rendering within the EDT unless I have completely misunderstood the concept. Rendering is not magically active or passive as determined by which thread it runs from. The repaint() system, which queues and collapses calls and so on is passive rendering. If you perform the rendering immediately when desired, as opposed to queueing and collapsing, then it is active rendering. If this is correct (which is not trivial because the invokeAndWait method which I'm going to suggest may involve some EDT queueing along with peripheral input and so on, though no repaint management takes place), then the invokeAndWait method can easily be used to render actively from the EDT. I assume the invokeAndWait is sufficiently efficient (i.e. that the passive rendering overhead which we hate is incurred mostly by the paint management and thus not the queueing itself).

Jeff said:
Quote
Right.  hats one thread.

Where is the other one?

Its that which im having a hard time imgining.

It's the main Thread of the game, which is used for the main loop. That's not the EDT, so it *is* another Thread.

So basically the user fiddles with the mouse and the corresponding stuff happens in some actionPerformed or mouseMoved method from the EDT. Perhaps the user action causes the window to scroll. Now, it's a pain in the lower back to queue this event and execute it from the main thread instead of the EDT. So if it's executed from the EDT then the window scrolls while the main thread is likely busy painting, possibly resulting in tearing because - well - perspective changes while the screen is updated.

I hope this was clear.
Offline Mr_Light

Senior Devvie


Medals: 1


shiny.


« Reply #25 - Posted 2006-04-16 17:42:19 »

the difference between passive and active is that passive is wenn it's told to/wenn it's needed vs active which is all the time.

the whole deathlock issue has to do with swing not beeing thread save. and has inheritely nothing todo with the whole active of passive rendering. It's the way we achive active rendering that causes the issues.


It's harder to read code than to write it. - it's even harder to write readable code.

The gospel of brother Riven: "The guarantee that all bugs are in *your* code is worth gold." Amen brother a-m-e-n.
Offline fletchergames

Senior Devvie





« Reply #26 - Posted 2006-04-17 02:24:37 »

I tried Luke's code.  Since I was using active rendering before (yes, from within the EDT), that wasn't really the issue.  I was hoping for a performance gain.  It turns out that frame rate is, on average, the same.

It may end my problem with dialogs being displayed oddly, but I'm not really concerned with that as I wrote my own almost-a-dialog class almost a year ago.

I also tried removing the NullRepaintManager code (which came from Developing Games in Java).  There was no performance gain, but I was getting periodic NullExceptions for some reason.  I was already randomly getting NullExceptions at start up once I started using Java 6 beta.  But the NullExceptions were caught and had no effect except to add text to the error log.  Since I then suspected that the problem was somehow solved by NullRepaintManager, I moved the NullRepaintManager to occur earlier in the code.  Now there are no more NullExceptions at all.

I think the issue is that the regular Java RepaintManager was trying to draw Components that weren't completely initialized after I went into full-screen exclusive mode but before I installed the NullRepaintManager.  I could probably do away with the NullRepaintManager altogether if I made sure that Components weren't made visible before their time, but it's easier just to keep the NullRepaintManager.
Offline nanobomber

Junior Newbie





« Reply #27 - Posted 2006-04-20 22:05:52 »

Hi,

I was reading your postings since I wanted to use Swing as data input framework for my game so that I don't need to develop one of my own.

Here I send you a little test program which open a dialog for text input and it seems to work OK. Don't know if it represent the kind of problems you have with your rendering code.

I followed the active rendering examples from the book Killer Game Programming it seems to be deadlock free (can't assure it though).

The problem I found with this is that it seems to me that the code is somewhat slow and the cube doesn't get rendered solid but I shows some flickering. So I post the code to see if anyone has a better idea of why those things are happening.

Regards,
Gabriel

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  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
189  
190  
191  
192  
193  
194  
195  
196  
197  
198  
199  
200  
201  
202  
203  
204  
205  
206  
207  
208  
209  
210  
211  
212  
213  
214  
215  
216  
217  
218  
219  
220  
221  
222  
223  
224  
225  
226  
227  
228  
229  
230  
231  
232  
233  
234  
235  
236  
237  
238  
239  
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

import com.sun.j3d.utils.timer.*;

public class ActiveSwingTest implements Runnable {

  static final int VEL = 1;

  // Number of frames with a delay of 0 ms before the animation thread yields
  // to other running threads.
  private static final int NO_DELAYS_PER_YIELD = 16;

  // no. of frames that can be skipped in any one animation loop
  // i.e the games state is updated but not rendered
  private static int MAX_FRAME_SKIPS = 5; // was 2;

  JFrame f;
  JPanel panel;
  Image backBuffer;

  JDialog dialog;

  private long gameStartTime;
  private long prevStatsTime;
  private boolean running;
  private Graphics2D graphics;
  private long period;
  private long framesSkipped = 0;

  int x = 0;
  int y = 0;
  int vx = VEL;
  int vy = VEL;

  public ActiveSwingTest() {
    initGraphics();
  }

  public void initGraphics() {
    panel = new JPanel();
    panel.setPreferredSize(new Dimension(800, 600));
    panel.setFocusable(true);
    panel.requestFocus();
    panel.setIgnoreRepaint(true);
    readyForTermination();

    f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.getContentPane().add(panel);
    f.setIgnoreRepaint(true);

    f.setResizable(false);
    f.pack();

    backBuffer = createBackBuffer();
    if(backBuffer == null) {
      return;
    }

    f.setVisible(true);
  }

  public void run() {
    long timeDiff = 0;
    long overSleepTime = 0L;
    int noDelays = 0;
    long excess = 0L;

    gameStartTime = J3DTimer.getValue();
    prevStatsTime = gameStartTime;
    long beforeTime = gameStartTime;

    running = true;

    graphics = (Graphics2D) backBuffer.getGraphics();

    while(running) {
      update(timeDiff);
      render(graphics);

      paintScreen();

      long afterTime = J3DTimer.getValue();
      timeDiff = afterTime - beforeTime;
      long sleepTime = (period - timeDiff) - overSleepTime;

      if(sleepTime > 0) { // some time left in this cycle
        try {
          Thread.sleep(sleepTime / 1000000L); // nano -> ms
        }
        catch(InterruptedException ex) {}
        overSleepTime = (J3DTimer.getValue() - afterTime) - sleepTime;
      }
      else { // sleepTime <= 0; the frame took longer than the period
        excess -= sleepTime; // store excess time value
        overSleepTime = 0L;

        if(++noDelays >= NO_DELAYS_PER_YIELD) {
          Thread.yield(); // give another thread a chance to run
          noDelays = 0;
        }
      }

      beforeTime = J3DTimer.getValue();

      /* If frame animation is taking too long, update the game state
         without rendering it, to get the updates/sec nearer to
         the required FPS. */

      int skips = 0;
      while((excess > period) && (skips < MAX_FRAME_SKIPS)) {
        excess -= period;
        update(timeDiff); // update state but don't render
        skips++;
      }
      framesSkipped += skips;
    }

    System.exit(0); // so window disappears
  }

  private void showDialogo() {
    if ( dialog == null ) {
      dialog = new JDialog(f, "Example dialog", true);
      final JTextField t = new JTextField("hello");
      JButton bok = new JButton("OK");
      bok.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              System.out.println("text="+t.getText());
              dialog.setVisible(false);
              dialog.dispose();
              dialog = null;
            }
          });
      JButton bcancel = new JButton("Cancel");
      bcancel.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                  dialog.setVisible(false);
                }
              });

      final Container c = dialog.getContentPane();
      c.setLayout(new BorderLayout());
      c.add(t, BorderLayout.CENTER);

      final JPanel buttonPanel = new JPanel();

      buttonPanel.add(bok);
      buttonPanel.add(bcancel);

      c.add(buttonPanel, BorderLayout.PAGE_END);

      dialog.pack();
      dialog.setLocationRelativeTo(f);

      dialog.setVisible(true);
    }
    else {
      dialog.setVisible(true);
    }
  }

  private void paintScreen() {
    // use active rendering to put the buffered image on-screen
    try {
      final Graphics g = panel.getGraphics();
      if(g != null) {
        g.drawImage(backBuffer, 0, 0, null);
      }
      g.dispose();
    }
    catch(Exception e) {
      System.out.println("Graphics context error: " + e);
    }
  }

  private Image createBackBuffer() {
    final Image dbImage = panel.createImage(800, 600);
    if(dbImage == null) {
      System.out.println("could not create the backbuffer image!");
    }
    return dbImage;
  }

  private void readyForTermination() {
    panel.addKeyListener(new KeyAdapter() {
      // listen for esc, q, end, ctrl-c on the canvas to
      // allow a convenient exit from the full screen configuration
      public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        if((keyCode == KeyEvent.VK_ESCAPE) || (keyCode == KeyEvent.VK_Q) ||
           (keyCode == KeyEvent.VK_END) ||
           ((keyCode == KeyEvent.VK_C) && e.isControlDown())) {
          running = false;
        }
        else if ( keyCode == KeyEvent.VK_D ) {
          showDialogo();
        }
      }
    });
  }

  private void update(long dt) {
    x += vx;
    y += vy;

    if ( x < 0 ) {
      x = 0;
      vx = VEL;
    }
    else if ( x > 700 ) {
      x = 700;
      vx = -VEL;
    }

    if ( y < 0 ) {
      y = 0;
      vy = VEL;
    }
    else if ( y > 500 ) {
      y = 500;
      vy = -VEL;
    }
  }

  private void render(Graphics2D g) {
    g.setColor(Color.RED);
    g.fillRect(0, 0, 800, 600);
    g.setColor(Color.WHITE);
    g.fillRect(x, y, 100, 100);
  }

  public static void main(String[] args) {
    ActiveSwingTest test = new ActiveSwingTest();
    new Thread(test).start();
  }

}
Offline fletchergames

Senior Devvie





« Reply #28 - Posted 2006-04-24 03:13:02 »

Hi,

...

The problem I found with this is that it seems to me that the code is somewhat slow and the cube doesn't get rendered solid but I shows some flickering. So I post the code to see if anyone has a better idea of why those things are happening.

...

Try using the BufferStrategy class instead of drawing to your own BufferedImage and then drawing that to the screen.  BufferStrategy can use page flipping if your graphics hardware supports it.  And, if if it doesn't support page flipping, I believe it can wait for the vertical retrace period (or whatever it's called) to avoid drawing to the video memory while it's being displayed to the monitor.

If you don't want to do use BufferStrategy for some reason, at least try accelerating the BufferedImage using Image.setAccelerationPriority.  That's a bad idea though because Image.setAccelerationPriority just suggests that image acceleration occurs.  So, you should really use BufferStrategy.
Offline CommanderKeith
« Reply #29 - Posted 2006-04-29 10:56:18 »

Just wanted to add to this to the thread:

http://weblogs.java.net/blog/enicholas/archive/2006/04/leaking_evil.html

Its a memory leak bug which would pop up as an OutOfMemoryError when the GraphicsConfiguration is changed.  It popped up for me when I tried changing to full screen mode and back in the middle of the game.  Its fixed in Mustang (Java 1.6).

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.

rwatson462 (37 views)
2014-12-15 09:26:44

Mr.CodeIt (31 views)
2014-12-14 19:50:38

BurntPizza (62 views)
2014-12-09 22:41:13

BurntPizza (99 views)
2014-12-08 04:46:31

JscottyBieshaar (60 views)
2014-12-05 12:39:02

SHC (74 views)
2014-12-03 16:27:13

CopyableCougar4 (77 views)
2014-11-29 21:32:03

toopeicgaming1999 (138 views)
2014-11-26 15:22:04

toopeicgaming1999 (127 views)
2014-11-26 15:20:36

toopeicgaming1999 (38 views)
2014-11-26 15:20:08
Resources for WIP games
by kpars
2014-12-18 10:26:14

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
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!