BufferStrategy crashes in native code? <Solved>

First off, I’m new - sorry if I missed an introduction thread or an FAQ or something.

I’m having a very strange issue with BufferStrategy and getDrawGraphics().

I’m working on a tile based game, and I wanted to add a background. While the background by itself drew fine, and the tiles by themselves drew fine, having tiles on a background caused a lot of flickering. I moved from Graphics to Grahpics2D, which shaved my frame redraw time from ~170MS to ~60MS, but there was still a noticeable flicker. After poking around the internet, I realized that even though I was using createBufferStrategy(2) (drawing on a Canvas), I need to use getDrawGraphics() and not getGraphics(). However, after adding that my game crashes immediately after trying to render anything, or if it doesn’t crash simply doesn’t draw anything (and Windows says that the display driver stopped responding and recovered).
This is the gist of the error (I omitted the whole file because it was just loaded dynamic libraries and such).

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x6d0b7521, pid=4000, tid=4784
#
# JRE version: 6.0_18-b07
# Java VM: Java HotSpot(TM) Client VM (16.0-b13 mixed mode, sharing windows-x86 )
# Problematic frame:
# C  [awt.dll+0xb7521]
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

Here’s my main game loop (with non-graphics code trimmed as I don’t think you’re interested in my awful world generation ;))

public void run(){
	...
	Graphics2D g = null;
	try{
		g = (Graphics2D)gui.bufferer.getDrawGraphics();
		while(true){
			gui.drawPlanet(p, g);
                        ...
		}
	} finally{
		g.dispose();
                 ...
	}
}

drawPlanet:

int bx = p.getPlayerPosition()[0] - 32;
int by = p.getPlayerPosition()[1] - 21;
g.setColor(Color.BLACK);
g.fill(new Rectangle(0, 0, getSize().width, getSize().height)); //I probably should prealloc this I know
for(int i = 42; i > 0; i--){
	for (int j = 0; j < 64; j++){
		int tile = p.worldData[bx + j][by + i];
		Tile t = Tile.tiles[tile];
		if (tile != 0){
			int index = t.sIndex;
			drawTile(j, i, index, g);
		}
	}
}

drawTile:


g.drawImage(sprites[index], x*16, y*16, 16, 16, this);

I’m new to Java2D, so this is probably something blindingly stupid, but thanks for looking at this.

I guess gui.bufferer is your buffer strategy object…? In that case, I think you’re missing a call to strategy.show(), something like this:

public void run(){
	...
	Graphics2D g = null;
	try{
		g = (Graphics2D)gui.bufferer.getDrawGraphics();
		while(true){
			gui.drawPlanet(p, g);
			gui.bufferer.show(); // <<<< ADDED LINE

                        ...
		}
	} finally{
		g.dispose();
                 ...
	}
}

edit: you might want to move g.dispose() so it’s called inside the while(true) loop, otherwise you’ll only dispose for the final frame. Obviously this depends on what else is happening inside the loop!

Ah, thank you. I should have mentioned that bufferer was the BufferStrategy object, yes.
I did both things that you mentioned (bufferer.show() - though I stuck this in drawPlanet as apparently calling it from an outside thread leads to illegal state exceptions, and g.dispose() into the main loop). This drew the background, but no tiles. Commenting out g.dispose() drew the tiles, but led to a sudden spike, then steady climb in screen drawing times, from what I assume is un-disposed objects crowding memory.

Rendered tiles 370, 402 through 434, 444 in 2
Rendered tiles 370, 402 through 434, 444 in 1
Rendered tiles 370, 402 through 434, 444 in 1
Rendered tiles 370, 402 through 434, 444 in 1
Rendered tiles 370, 402 through 434, 444 in 4
Rendered tiles 370, 402 through 434, 444 in 1
Rendered tiles 370, 402 through 434, 444 in 1
Rendered tiles 370, 401 through 434, 443 in 58
Rendered tiles 370, 400 through 434, 442 in 101
Rendered tiles 370, 397 through 434, 439 in 162
Rendered tiles 370, 392 through 434, 434 in 318
Rendered tiles 370, 382 through 434, 424 in 621
Rendered tiles 370, 378 through 434, 420 in 730
Rendered tiles 370, 378 through 434, 420 in 725
Rendered tiles 370, 378 through 434, 420 in 726
Rendered tiles 370, 378 through 434, 420 in 710
Rendered tiles 370, 376 through 434, 418 in 777
Rendered tiles 370, 376 through 434, 418 in 785
Rendered tiles 370, 376 through 434, 418 in 784
Rendered tiles 370, 376 through 434, 418 in 780
Rendered tiles 370, 376 through 434, 418 in 779
Rendered tiles 370, 376 through 434, 418 in 775
Rendered tiles 370, 376 through 434, 418 in 777
Rendered tiles 370, 375 through 434, 417 in 811
Rendered tiles 370, 375 through 434, 417 in 814
Rendered tiles 370, 375 through 434, 417 in 824

EDIT: I tested a bit more, and that sudden spike is exactly when tiles begin to come onscreen (I can scroll around the world with the arrow keys).

That first error happened outside of Java, in native code, specifically awt.dll. You also said the Windows display driver stopped responding and recovered. This could mean you have a bad driver for you graphics card. However, your recent posts suggest that calling show() stopped the error from occurring?
Anywho, this should be how you handle your drawing code.


//game loop
while(true) {
    //logic
    
    do{
        do{
            Graphics2D g = (Graphics2D)buffer.getDrawGraphics();
            //drawing code
            g.dispose();
        }while(buffer.contentsRestored());
        buffer.show();
    }while(buffer.contentsLost());
}

BTW - There is no difference between using Graphics or Graphics2D these days in Java, since all Graphics objects you get are actually instances of Graphics2D but are there for backwards compatibility.

public void run(){
    ...
    Graphics2D g = null;
    try{
        g = (Graphics2D)gui.bufferer.getDrawGraphics();
        while(true){
            gui.drawPlanet(p, g);
                        ...
        }
    } finally{
        g.dispose();
                 ...
    }
}

Should be:

public void run(){
    ...
    Graphics2D g = null;
        while(true){
        g = (Graphics2D)gui.bufferer.getDrawGraphics();
            gui.drawPlanet(p, g);
                        ...
        g.dispose();        

      }
    }
}

An put show somewhere.

Thanks for your help guys - I tweaked my code some, and found that the main source of my lag was some old code. The gist was I was resizing my tile sprites each draw. Not so bad for a few calls. Awful for 1,677. Anyways, I now resize them when loading and the game runs like a dream (300 MS draw time for over 3000 calls!)

300MS draw time for only 3000 calls?!? That’s slow!! >:(