If I invoke getGraphics() on a panel or a frame from a worker thread (as opposed to the swing/awt event-dispatching thread) and use the returned Graphics object for drawing, how often do I need to dispose it and grab a new one? Will it occationally become invalid and if so, how do you detect when it can no longer be used for drawing?
Why not just grab a new one every game loop?
It doesn’t effect performance, and will give u smaller bytecode.
Are you sure it does not affect performance if I obtain a new one per loop iteration and dispose the old one? What’s the basis of that? And, why would that compile to a smaller class file?
I wouldn’t bother disposing of it - that will definitely save you space.
you should -always- dispose() after each frame, otherwise on some platforms the game will not be displayed correctly.
at least, that is what kevin glass told me (I asked him why he didn’t get rid of dispose() in his Goop 4K game)
I do it like this:
// Loop
while ( running ) {
long elapsedTime = System.nanoTime() - current;
current += elapsedTime;
// Graphics and Graphics2D
// game is a JPanel, instance of my main and only class
Graphics g = game.getGraphics();
Image screen = game.createImage(800, 600);
Graphics2D g2d = (Graphics2D) screen.getGraphics();
// draw with g2d
// ...
// in the end
g.drawImage(screen, 0, 0, game);
g2d.dispose();
I only dispose of the graphics instance of the BufferedImage, which is the “screen” where I render all my stuff. Didn’t notice anything unusual up to now.
Rodrigo
In that loop, you not only create and dispose new Graphics objects, you create a new image. Why not create an image once and use it throughout? Does anyone have documentation about when Graphics objects need to be disposed?
wow, Son of Cain. for one, you’re using Image, not BufferedImage. secondly, you should not create a new image for each frame, that’s a huge performance killer.
if you used an actual BufferedImage instance, you wouldn’t need to cast (Graphics2D) either, as BufferedImage’s createGraphics() method returns a Graphics2D object.
zeroone, from the JavaDoc,
thus, you should dispose() the Graphics object you receive from getGraphics(). This is an example of when you do not need to dispose it:
public void paint(Graphics g) {
// drawing stuff here
// ..
// we do not need to call g.dispose() here, because the class that called this method will do it automatically
}
I agree the Javadoc says that you should dispose it, but when should you do it? Once per game loop iteration or once per application execution? Can I safely hold onto a Graphics handle for the full program run or is there a chance it will become invalid?
since the doc says that several Graphics objects can be created in a short time frame, I would say it’s best to dispose() of the Graphics object per frame. I’ve heard some people say (on the Sun forums I believe) that the Graphics context can change at any time, so if you’re going to bother grabbing getGraphics() every frame, you might as well dispose() of it also.
I’ve heard similar things, but where’s the proof? Does this only apply to Graphics objects that point to panels/frames/components? How about Graphics objects that point to BufferedImages?
proof is this: you call getGraphics() every frame, yeah? why in the hell wouldn’t you dispose of the old one, since you’re never going to use it again?
solid proof isnt available to me, I’ve only heard about Graphcis glitches from those who use macs and some versions of linux. (I’m stuck on windows)
the Graphics from BufferedImages fall under the same rule. the only Graphics objects that aren’t affected by the rule are the ones passed through the paint method, because the object that called paint will dispose of the Graphics automatically. (of course, if you called paint yourself, then you’d have to dispose of the Graphics yourself)
in the end, every Graphics object is supposed to be disposed, the real question is “who” does it. If you don’t call paint, then you don’t have to dispose of the Graphics object that comes with the parameter. if you acquire a Graphics object in any other way, through getGraphics() on an image or component or wherever, you’re supposed to dispose of it yourself.
I agree that it makes sense to dispose of the Graphics object once per frame if it were obtained with getGraphics() once per frame. However, is there really anything wrong with calling getGraphics() once and only once at the start of the program since this is not full screen exclusive mode.
I can’t say for sure, some people say there’s no problem with it (I’ve never had a glitch on my windows box), others on non-windows boxes have experienced some graphical glitches.
I would play it safe and dispose every frame, because due to java’s cross-platform compatibility, you can’t be 100% confident in the underlying rendering system. maybe windows doesn’t experience glitches because of the DirectDraw that java uses? well linux and mac dont have DirectDraw, which could be why not disposing on certain versions of mac/linux produce errors.
it would be really nice if Dmitri could enlighten us on this. (he’s pointed out some very interesting things about java2d)
Can I safely hold onto a Graphics handle for the full program run[…]
No. Your program might consume all ram and then hang. One of my first games did that on Macs, because I initially recycled the Graphics object.
So dont do that. Its glitchy and not any faster.
Get, draw, dispose… each frame. (I think its about the 5th time I wrote that.)
oNyx,
Does that apply only to the Graphics object that points to visible components (i.e. frames or panels)? Can I safely hold onto a Graphics object to a BufferedImage for the duration of the program run?
Any idea why it consumes resources to hold onto the Graphics object for a long period of time?
From http://fivedots.coe.psu.ac.th/~ad/jg/ch1/ch1.pdf:
[quote]The panel’s graphics context may be changed by the JVM, typically when the canvas
is resized or when it becomes the front window after being behind others. Also, the
context may disappear if the application or applet exits while the animation thread is
running.
For these reasons, the graphics context must be freshly obtained each time it is needed
(by calling getGraphics()). Also, its use must be surrounded by a try-catch block to
capture any failure due to its disappearance.
In practice, if the program has a fixed window size, then the most likely time for an
exception is when a game applet is terminated by the user closing its surrounding
Web page.
[/quote]
This suggests that holding onto a Graphics object will not slowly eat up system resources; however, it does mean that the object may eventually become unusable. What’s worse is that getGraphics() may return null; so, we need to check for that. Also, when the Graphics object becomes unuseable, it may throw an exception when you invoke one of its methods; so, we need to catch that exception.
It’s still unclear if this applies to Graphics objects that point to BufferedImages.
Is anyone really going to do for a 4K game. Seems like a lot of code to prepare for an extremely unlikely event. I’ve never had getGraphics() return null and I’ve never had a Graphics object throw an exception.
Can I safely hold onto a Graphics object to a BufferedImage for the duration of the program run?
Like manual double buffering? No.
Any idea why it consumes resources to hold onto the Graphics object for a long period of time?
Dunno. Guess the mac implementation stored the things you did in some list for some reason (the mem consumption was rather slow… after 15minutes it ate 300mb iirc).
edit: null… never seen that, never wrote a check for that.
Graphics are Graphics. whether they come from JFrame, or BufferedImage, or Image. the only time you’re not supposed to dispose() it is when you’re using a Graphics object passed through a method, because the method caller will dispose it automatically.
and this is not hard in a 4K game, you do not need to check for exceptions if you “get, draw, dispose”
example …
Graphics gfx = buffer.createGraphics(); // the buffer graphics
// draw stuff
// ..
// now render buffer to screen
Graphics g = getGraphics();
if (g != null) g.drawImage(buffer,0,0,null);
g.dispose();
gfx.dispose();
[quote]you do not need to check for exceptions if you “get, draw, dispose”
[/quote]
Apparently, “draw” can throw an exception if the Graphics object becomes invalid between “get” and “draw”. If you don’t bother to catch the exception, there is no point in refreshing the Graphics object with “get” in the first place. Your program will crash in that rare event.