zeroone
|
 |
«
Posted
2006-10-16 15:32:39 » |
|
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?
|
|
|
|
|
Abuse
|
 |
«
Reply #1 - Posted
2006-10-16 15:37:12 » |
|
Why not just grab a new one every game loop? It doesn't effect performance, and will give u smaller bytecode.
|
Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! 
|
|
|
zeroone
|
 |
«
Reply #2 - Posted
2006-10-16 15:51:49 » |
|
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?
|
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Abuse
|
 |
«
Reply #3 - Posted
2006-10-16 15:54:14 » |
|
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.
|
Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! 
|
|
|
woogley
|
 |
«
Reply #4 - Posted
2006-10-16 16:12:04 » |
|
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)
|
|
|
|
|
Son Of Cain
|
 |
«
Reply #5 - Posted
2006-10-16 16:26:17 » |
|
I do it like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| while ( running ) { long elapsedTime = System.nanoTime() - current; current += elapsedTime; Graphics g = game.getGraphics(); Image screen = game.createImage(800, 600); Graphics2D g2d = (Graphics2D) screen.getGraphics();
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
|
|
|
|
|
zeroone
|
 |
«
Reply #6 - Posted
2006-10-16 16:44:12 » |
|
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?
|
|
|
|
|
woogley
|
 |
«
Reply #7 - Posted
2006-10-16 17:39:04 » |
|
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, For efficiency, programmers should call dispose when finished using a Graphics object only if it was created directly from a component or another Graphics object.
thus, you should dispose() the Graphics object you receive from getGraphics(). This is an example of when you do not need to dispose it: 1 2 3 4 5
| public void paint(Graphics g) { } |
|
|
|
|
|
zeroone
|
 |
«
Reply #8 - Posted
2006-10-16 17:54:19 » |
|
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?
|
|
|
|
|
woogley
|
 |
«
Reply #9 - Posted
2006-10-16 17:59:14 » |
|
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.
|
|
|
|
|
Games published by our own members! Check 'em out!
|
|
zeroone
|
 |
«
Reply #10 - Posted
2006-10-16 18:02:16 » |
|
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?
|
|
|
|
|
woogley
|
 |
«
Reply #11 - Posted
2006-10-16 18:08:05 » |
|
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.
|
|
|
|
|
zeroone
|
 |
«
Reply #12 - Posted
2006-10-16 18:12:00 » |
|
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.
|
|
|
|
|
woogley
|
 |
«
Reply #13 - Posted
2006-10-16 18:16:29 » |
|
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)
|
|
|
|
|
oNyx
|
 |
«
Reply #14 - Posted
2006-10-16 18:18:37 » |
|
>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.)
|
|
|
|
zeroone
|
 |
«
Reply #15 - Posted
2006-10-16 18:35:49 » |
|
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?
|
|
|
|
|
zeroone
|
 |
«
Reply #16 - Posted
2006-10-16 19:14:54 » |
|
From http://fivedots.coe.psu.ac.th/~ad/jg/ch1/ch1.pdf: 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. 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.
|
|
|
|
|
oNyx
|
 |
«
Reply #17 - Posted
2006-10-16 19:20:23 » |
|
>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.
|
|
|
|
woogley
|
 |
«
Reply #18 - Posted
2006-10-16 19:22:48 » |
|
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 .. 1 2 3 4 5 6 7 8 9
| Graphics gfx = buffer.createGraphics(); Graphics g = getGraphics(); if (g != null) g.drawImage(buffer,0,0,null); g.dispose(); gfx.dispose(); |
|
|
|
|
|
zeroone
|
 |
«
Reply #19 - Posted
2006-10-16 19:32:42 » |
|
you do not need to check for exceptions if you "get, draw, dispose"
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.
|
|
|
|
|
woogley
|
 |
«
Reply #20 - Posted
2006-10-16 19:34:53 » |
|
an exception will not be thrown unless you're doing something out of the ordinary. e.g. drawing to an Image that was created with createImage(width,height) using a Window that was invisible. and if its so rare, you do not need to bother checking for it, especially in 4K (exception catching is nearly nonexistant in 4K..) but that doesn't even matter, the only 100% away to avoid such an exception is not to draw at all 
|
|
|
|
|
zeroone
|
 |
«
Reply #21 - Posted
2006-10-16 19:47:51 » |
|
If you bother to check if the Graphics object is null, then you might as well check for the exception. Both appear to indicate the same issue; it's just a matter of where you are in the game loop when it occurs. If you detect for the null condition to prevent the game from crashing, then you should catch the exception. Doing one without the other doesn't make a lot of sense. Either accept that the thread can die in the unlikely event that the Graphics object becomes invalid or completely cover your bases to let the program carry on.
I suspect that getGraphics() will only return null or an exception will be thrown during "draw" is when the frame/panel cannot be drawn to prior to being displayed or during shutdown of the application.
I still don't understand why the Graphics object for a BufferedImage ever needs to be disposed. What could render it invalid?
|
|
|
|
|
woogley
|
 |
«
Reply #22 - Posted
2006-10-16 19:56:36 » |
|
... the exception and null value can be completely different issues. you should check for null because the Window can return null when the Window is minimized or otherwise unfocused/invisible/nondisplayable. this does not mean you need to check for an extremely rare exception (I've never heard of it myself), that's a waste of space. The doc does not say Graphics will throw an exception, but the doc for getGraphics() does mention it can return null. that's why you should check for null, and shouldn't be worried about the Exception ,that's more on the VM level than anything (probably not something you can control - especially since it will crash your game whether you catch it or not) I still don't understand why the Graphics object for a BufferedImage ever needs to be disposed. What could render it invalid?
can't say for sure, probably something to do with the underlying buffers. as oNyx mentioned, for reasons unknown, holding any Graphics object in memory will consume ram. so if you're grabbing a new Graphics object each frame, it's only logical to dispose of it at the end of each frame
|
|
|
|
|
g666
|
 |
«
Reply #23 - Posted
2006-10-16 19:58:44 » |
|
>Can I safely hold onto a Graphics object to a BufferedImage for the duration of the program run?
Like manual double buffering? No.
ive done that for my 4k stuff last year and some stuff ive started this year, ive never had any problems.
|
desperately seeking sanity
|
|
|
woogley
|
 |
«
Reply #24 - Posted
2006-10-16 19:59:46 » |
|
ive done that for my 4k stuff last year and some stuff ive started this year, ive never had any problems.
were you on Mac? as stated earlier, different Graphics problems stretch across the different platforms
|
|
|
|
|
Son Of Cain
|
 |
«
Reply #25 - Posted
2006-10-16 21:50:52 » |
|
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.
Thanks, dude  My first time on 4K  The creteGraphics(int, int) returns an Image, which I assumed to be of subtype BufferedImage. Am I wrong? Having the reference declared as a super class changes nothing right, since the methods will be called on the correct subclass (BufferedImage, in this case, if I'm not wrong). The image creation within the loop was dumb, I acknowledge that. Thanks for the tip, now it's fixed 
|
|
|
|
|
woogley
|
 |
«
Reply #26 - Posted
2006-10-16 21:56:51 » |
|
Thanks, dude  My first time on 4K  awesome. welcome  The creteGraphics(int, int) returns an Image, which I assumed to be of subtype BufferedImage. Am I wrong?
actually, BufferedImage is a sublcass of Image. Image has been around since java 1.0, BufferedImage wasn't on the scene until Java 1.3 I believe. Also note that creating a BufferedImage does not rely on your Window to be visible (like createImage(int,int) does).
|
|
|
|
|
Son Of Cain
|
 |
«
Reply #27 - Posted
2006-10-16 22:31:30 » |
|
Yes, I meant that, the other way around :p As you see, i'm not a native english speaker :p
|
|
|
|
|
Markus_Persson
|
 |
«
Reply #28 - Posted
2006-10-17 15:39:49 » |
|
I still don't understand why the Graphics object for a BufferedImage ever needs to be disposed. What could render it invalid?
can't say for sure, probably something to do with the underlying buffers. as oNyx mentioned, for reasons unknown, holding any Graphics object in memory will consume ram. so if you're grabbing a new Graphics object each frame, it's only logical to dispose of it at the end of each frame I've never seen this happen, and I can find no mention at all of Graphics objects to be disposed because "they're no longer valid" in the javadocs. Source?
|
|
|
|
woogley
|
 |
«
Reply #29 - Posted
2006-10-17 16:03:20 » |
|
"no longer invalid" is zeroone's words, not mine. what you quoted is my best guess, after my recent buffer revelation  I quote the javadoc as saying: "When a Java program runs, a large number of Graphics objects can be created within a short time frame."
it goes onto say how the Graphics in paint(Graphics) and update(Graphics) are disposed of automatically, but then says otherwise-acquired Graphics objects should be disposed of manually: "Graphics objects which are provided as arguments to the paint and update methods of components are automatically released by the system when those methods return. For efficiency, programmers should call dispose when finished using a Graphics object only if it was created directly from a component or another Graphics object."
(source: http://java.sun.com/j2se/1.4.2/docs/api/java/awt/Graphics.html#dispose()) as far as solid proof goes, you'd need that program oNyx was talking about and a Mac platform to test it on. I'm stuck on Windows, and Windows doesn't seem to be affected by dispose() (or lack thereof). I've also heard from Kevin Glass (when I was asking him why he didn't remove dispose() in his Goop4K game to save space) that dispose needs to be called to avoid graphical glitches on different platforms. when you read the javadoc quoted above, the major unclarity is when you're considered to be "done" with a Graphics object - in oNyx's case, he wasn't done until the program closed, which resulted in (according to him) RAM consumption. being on windows, the whole issue is somewhat confusing to me. up until now, I have never used dispose() (just check out the Goomba4K source), but maybe those random glitches (see the Goomba4K thread) were caused by the lack of dipose(). if kevglass isn't going to take the risk, I'm certainly not either o_O
|
|
|
|
|
|