Converting/optimizing a Swing setup to something with better performance..

Hey there! Glad to have found this forum.

I’m working on a tile and turn-based game similar to UFO/XCOM, jagged alliance and the sort. It is currently completely unoptimized and the interface is setup as a JLayeredPane with the scene at the default layer, and GUI panels in the palette one. The scene is a JPanel with an overriden paint method.
The graphics is “asleep” while waiting for the player or computer triggers an event, like “A fire weapon at B” in which a thread is triggered asking for repeated repaints.
I’m using alpha-channeled images for per-tile light and shadows, and some simple draw routines like lines.

My current issue is that repainting the scene automatically repaints the GUI on top, which is not “necessary” in the game atleast. This is cutting performance atleast in half.

Now, my question is, which would you suggest be the easiest and most effective way to optimize? I’ve looked at bufferstrategy and jogl and what not, but I’m not sure which would benefit me most, and what would be overkill. I can’t seem to get the JOGL demos to work, so I’m not sure how a JOGL enabled frame would interact with JComponents lying on top of it.
Would I be able to use a bufferstrategy directly on the JFrame for the scene, and still have JPanels on top, not beeing redrawn when the scene is, or do I have to render the GUI components offscreen and simple blit the result at repaint?

Please excuse any obvious conceptual missunderstandings I might have, it seems I’ve confused myself looking at differents sollutions already.

reading similar threads, like http://www.java-gaming.org/forums/index.php?topic=12189.0
don’t want to waste your time.

Gained tons of performance by keeping my JPanels, creating my images through BufferedImage GraphicsConfiguration.createCompatibleImage() and enabling the OpenGL-based pipeline. I think this’ll be enough for my game, but any comments are greatly appreciated!

edit: Never change two things at once and assume they’re both at work. No OpenGL pipeline yet.
edit 2: … and now I’ve finally got it. Faster than I could’ve hoped for :slight_smile:

Even with a turn based game like XCOM, you should still use active rendering for your scene. There are moments of inactivity, but then you have a stretch of active moments. At this point passive rendering will fail. Repeated calls to repaint may actually only generate a single call to paint.

Note that many systems have trouble with the OGL pipeline. If you repaint only rectangles containing the animated stuff, that will probably save loads of time.

Thank you for your replies! You have a good point about repaint, it’s pretty much how NOT to do the rendering, so I’ll have to move to something smoother. I could have a rendering thread attempting to keep a ~30 fps rendering, still might keep the no-repaint while there’s no commands beeing processed. It just seems wasteful.

I have considered to repaint only the animated areas, however when the player f.ex. instructs a unit to move, the dynamic lights are beeing re-calculated and thus the whole scene needs to update. For enemy movements and in combat, this would be something to look into though.

I’m not sure what issues people have with the OGL pipeline, as for my first beta I will pretty much assume people to have the same setup as I do, and work from there. It’s not the latest hardware and pretty common stuff too. It will probably take a while aswell and by then things might have gotten more stable (?)

Well lets say it a little bit different, people have problems with their OpenGL drivers :wink:
I definitivly know that the latest NVidia drivers for windows/linux are able to host the opengl-java2d pipeline very well, ATI cards work with some issues (or have they been fixed recently by ATI?) but you can forget pretty much about Intel, SiS, Via etc which are >50% of sold computers.

lg Clemens

ATI has loads of issues. I have a dual boot linux/windows on my laptop. It’s impossible for me to enable the pipeline in windows, though I’ve tried like three different drivers. In Linux there is this strange (serious) driver problem which is discussed somewhere in the java2d forum, but it can be enabled. In short: don’t assume people can run the OGL pipeline (people can manually enable it when running games, or you could be “nice” and supply an option which allows people to enable it in a more convenient way, though this cannot be done when the game is running).

I see, that’s a shame.

does this apply to other Open GL implementations aswell that is out there, JOGL and LWJGL f.ex? And if not, which would you chose? Do they demand their own frame or can they “co-exist” with other containers?

Well that depends, Java2D’s OpenGL pipeline hides all the OpenGL specific stuff from the programmer, taking away tons of complexity but also opportunities for working arround of driver issues. I hope you don’t misunderstand - the java2d-opengl pipeline is quite well-written and designed, but drivers are that broken. For what I can say only nvidia cards are able to run java2d/opengl powered games/applications well.
It euns well on drivers that are not seriously broken (the sad thing is that most are broken, since they are only tested for gaming where special conditions happen like e.g. a guaranteed repaint of the whole surface every update). There have been efforts ongoing to make the java2d pipeline less dependant on a good Opengl implementation as well as talks to driver programmers / card manufacturers.

So if you use JOGL or LwJGL you have more or less direct access to the OpenGL API, so if a driver is broken you have to work arround yourself, as well as you need to validate against many cards/driver combinations to make problems show up.
Yep you can embed them into your frame as long as no swing-widgets should overlap them it works pretty fast, otherwise more or less a “screenshot” is taken and rendered into your swing app which is not optimal and slow.

lg Clemens

You should use time based rendering, not try to lock the framerate. Also, try to stick to a single thread. Threading is not necessary for games.

Don’t try to pre-optimize by reducing what seems to be a waste. Just get the game working first. If later on you can reduce cycles by limiting repainting only when an update occured, then do it. If it does not affect your game, just run it as is.

I made this code to turn on VM options including the openGL pipeline on start-up.

Its good because you can turn the options on and off and when the user launches your program from, say, a double-clickable jar file (with a no-options VM running) it will launch another VM with the options.

Compile and execute it as is and it should work. You can tell if it worked because it should emit a beep sound.

// author: Keith Woodward, keith@slavebot.net

import java.io.*;

public class Tester{

static boolean enableOptions = false;			// make this true to enable true options below
	static boolean enableServerVM = false;		// server VM
	static boolean enableOpenGL = false;		// OpenGL pipeline
	boolean enableCMSGC = true;			// Concurrent-Mark-Sweep garbage collector - see http://java.sun.com/developer/technicalArticles/Programming/turbo/#The_new_GC.
// the above boolean options should be stored to disc and looked up on each program invocation.

static String noOptions = "noOptions";			// flag that signals no options should be used.

public static void main(String[] args){

	/*
	//The below code will let you see the output by printing it to a text file.
	PrintStream printStream = null;
	// set your own file
	File outputFile = new File("C:/Documents and Settings/Keith.KIDS/My Documents/outputFile.txt");
	try{
		outputFile.createNewFile();
		printStream = new PrintStream(outputFile);
		System.setOut(printStream);
		System.setErr(printStream);
	}catch(IOException e){	System.exit(-1);}
	*/

	boolean doWithOutOptions = true;
	System.out.println("beginning");
	System.out.println("if you here a beep, it has worked...");

	if (!(args.length > 0 && args[0].equals(noOptions))){
		if (enableOptions == true){
			doWithOutOptions = false;
			try{
				String fileSeparator = System.getProperty("file.separator");
				String classPathOption = "-classpath"+" "+"\""+System.getProperty("java.class.path")+"\"";
				String serverVMOption = "-server";
				String openGLOption = "-Dsun.java2d.opengl=True";
				String cmsGCOption = "-XX:+UseConcMarkSweepGC";

				String commandString = System.getProperty("java.home")+fileSeparator+"bin"+fileSeparator+"java.exe"+" ";
				if (enableServerVM){
					commandString += serverVMOption+" ";
				}
				if (enableOpenGL){
					commandString += openGLOption+" ";
				}
				if (enableCMSGC){
					commandString += cmsGCOption+" ";
				}
				// add the 'noOptions' flag so that this process is not re-done again.
				String fullClassName = Tester.class.getCanonicalName();
				commandString += classPathOption+" "+fullClassName+" "+noOptions;

				System.out.println(commandString);
				// start a new VM process with our options
				Runtime.getRuntime().exec(commandString);
			}
			catch (java.io.IOException e){
				e.printStackTrace();
				doWithOutOptions = true;
			}
			catch (SecurityException e){
				e.printStackTrace();
				doWithOutOptions = true;
			}
		}
	}
	if (doWithOutOptions == true){
		java.awt.Toolkit.getDefaultToolkit().beep();
		// insert the code to start your game here...
	}
}

}

Hope it helps,

Keith

Edit: My apologies, the code didn’t work with packages but I changed it and now it should. Also added the CMS gc option.