EXT_draw_instanced - javaw.exe crashes

Hi!

I’m trying to test the instanced drawing extension of OpenGL on a basic example program and am desperately longing for help!
I have no experience using this extension and it is very likely that I have missed a vital point in using it…

Basicly the program prepares to draw a number of simple GL_QUADS by storing the information about the scene in the glVertexPointer-, glNormalPointer- and glIndexPointer-Buffers and then tries to draw them using the glDrawElementsInstancedEXT function of the javax.media.opengl.GL from the JOGL-lib in a simple opengl-environment.
For a number of 10000 vertices the view seams to be ok until - at some seamingly random point - the program crashes giving me nothing to go on as of where the problem lies… Also sometimes there are some very weird graphic bugs and the meshes are totally destroyed - I can’t make anything out of this…

It is probably best if I paste the code. Hopefully it is not a system problem and you find the problem in my coding.
Note that I am using no shaders - I don’t know if this is the reason.

Here the init-function… it basicaly establishes the environment settings and the view-matrices which allow navigation.
It calls myPrepare() at the end which calculates all the vertices and stores all the information about the scene into the buffers.


	public void init(GLAutoDrawable drawable) {
		gl= drawable.getGL();
		
		gl.glClearColor(0.85f, 0.85f, 0.7f, 0.0f);  // canvas background color
		
		gl.glEnable(GL.GL_LIGHTING);  // light enabled
		gl.glEnable(GL.GL_LIGHT0);
		
		gl.glClearDepth(1.0);  // depth testing enabled
		gl.glDepthFunc(GL.GL_LEQUAL);
		gl.glEnable(GL.GL_DEPTH_TEST);
				
		gl.glEnable(GL.GL_COLOR_MATERIAL);  //enable some material characteristics
		gl.glColorMaterial(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE);
		gl.glShadeModel(GL.GL_SMOOTH);  // enable smooth color shading
		
		float light_ambient[]  = { 0.3f, 0.3f, 0.3f, 1.0f };	// ambient light
		float light_diffuse[]  = { 0.3f, 0.3f, 0.3f, 1.0f };	// diffuse light
		float light_specular[] = { 0.4f, 0.4f, 0.4f, 1.0f };	// specular light
		
		float shininess[] = {100.0f};
		
		gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, light_specular,0);	// material characteristics
		gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, shininess,0);
		
		gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT,  light_ambient,0);	// adding the different light
		gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE,  light_diffuse,0);	// parts to the light model
		gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, light_specular,0);
	
		float light_position[] = {leftx, 0.0f, -dist, 1.0f }; 	// light position

		gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_position,0);  	// headlight
		
		gl.glMatrixMode(GL.GL_MODELVIEW);
		
		gl.glLoadIdentity();
		gl.glTranslatef(0, 0, +600);
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, viewTransNeg,0);
		
		gl.glLoadIdentity();
		gl.glTranslatef(0, 0, -600);
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, viewAll,0);
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, viewTrans,0);
		
		myPrepare();
	}

Here myPrepare()… note that if you variate ‘range’ you will get more quads. The program crashes at a range of 4000 instantly after running and runs at a range of 2000 for duration of about 30 seconds (seams to be random).
myPrepare() calls the myPlaneArrays() function which calculates the vertices and normals for a quad and returns them as an ArrayList-collection.


	IntBuffer indexBuffer;
	int elements;
	ArrayList<Float> vertices= new ArrayList<Float>();
	ArrayList<Float> normals= new ArrayList<Float>();
	
	private void myPrepare() {
		int range= 2000;
		float step= 250f;
		
		MyArrayElements myArrays;
		
		for (float x= -range; x < range; x+= step) {
			for (float y= -range; y < range; y+= step) {
				myArrays= myPlaneArrays(x,y,0,100.0f);
				vertices.addAll(myArrays.vertices);
				normals.addAll(myArrays.normals);
			}
		}
		
		// create buffers...
		FloatBuffer vertexBuffer = BufferUtil.newFloatBuffer(vertices.size());		
		for (int i= 0; i < vertices.size(); i++)
			vertexBuffer.put(i,vertices.get(i));
		
		gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
		gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertexBuffer);
		
		FloatBuffer normalBuffer = BufferUtil.newFloatBuffer(normals.size());
		for (int i= 0; i < normals.size(); i++)
			normalBuffer.put(i,normals.get(i));
		
		gl.glEnableClientState(GL.GL_NORMAL_ARRAY);
		gl.glNormalPointer(GL.GL_FLOAT, 0, normalBuffer);
		
		elements= vertices.size()/3;
		indexBuffer= BufferUtil.newIntBuffer(elements);
		for (int i= 0; i < elements; i++)
			indexBuffer.put(i,i);
		
		gl.glEnableClientState(GL.GL_INDEX_ARRAY);
		gl.glIndexPointer(GL.GL_UNSIGNED_INT, 0, indexBuffer);
		
		System.out.println("prepare done.");
		System.out.println("vertices.size= "+vertices.size());
	}

Here myPlaneArrays()… MyArrayElements is a simple class which contains the ArrayLists for vertices, normals, colors and indices (colors and indices are not used atm).


	private MyArrayElements myPlaneArrays(float x0, float y0, float z0, float size) {
		ArrayList<Float> vertices= new ArrayList<Float>();
		ArrayList<Float> normals= new ArrayList<Float>();
		ArrayList<Float> colors= new ArrayList<Float>();
		ArrayList<Integer> indices= new ArrayList<Integer>();
		Integer s= 0;
		
		normals.add(0.0f);
		normals.add(0.0f);
		normals.add(1.0f);
		vertices.add(x0+ -size);
		vertices.add(y0+ -size);
		vertices.add(z0+ 0.0f);
		vertices.add(x0+ size);
		vertices.add(y0+ -size);
		vertices.add(z0+ 0.0f);
		vertices.add(x0+ size);
		vertices.add(y0+ size);
		vertices.add(z0+ 0.0f);
		vertices.add(x0+ -size);
		vertices.add(y0+ size);
		vertices.add(z0+ 0.0f);
		
		return new MyArrayElements(vertices, normals, colors, indices);
	}

Here comes the display routine which essentially establishes the view, controlls navigation and the calls the myDrawing() routine in which the instance extension is used.


	public void display(GLAutoDrawable drawable) {
		gl= drawable.getGL();
/** 
* VIEWPORT
*/
		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		
		gl.glViewport(0, 0, this.getSize().width, this.getSize().height); // reset the current viewport and perspective transformation	
	    gl.glGetIntegerv(GL.GL_VIEWPORT, vp, 0);
	    
		gl.glMatrixMode(GL.GL_PROJECTION);// select the projection matrix
		gl.glLoadIdentity();
		gl.glFrustum(-0.25, 0.25, -0.25, 0.25, 1.0, 10000.0);

/** 
* ANSICHT
*/
		gl.glMatrixMode(GL.GL_MODELVIEW);
		
		gl.glLoadMatrixf(viewTrans,0);
		gl.glTranslatef(leftx, upy, -dist);
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, viewTrans,0);
		gl.glRotatef(rotx, 1, 0, 0);
		gl.glMultMatrixf(viewTransNeg,0);
		gl.glMultMatrixf(viewAll,0);
		gl.glRotatef(rotz, 0, 0, 1);
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, viewAll,0);
		
		gl.glLoadMatrixf(viewTransNeg,0);
		gl.glTranslatef(-leftx, -upy, dist);
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, viewTransNeg,0);
		
		gl.glLoadMatrixf(viewAll,0);
		
		resetViewVars();

/** 
* DRAWING
*/		
		
		myDrawing();
		
		gl.glFinish();
		gl.glFlush();
	}

And here the myDrawing() function which only calls uppon the glDrawElementsInstancedEXT routine. Note that the first 3 if-clauses do not print out the warnings - the buffers are active at this point.


	private void myDrawing() {
		if (!gl.glIsEnabled(GL.GL_VERTEX_ARRAY)) System.out.println("! GL_VERTEX_ARRAY nicht aktiv !");
		if (!gl.glIsEnabled(GL.GL_NORMAL_ARRAY)) System.out.println("! GL_NORMAL_ARRAY nicht aktiv !");
		if (!gl.glIsEnabled(GL.GL_INDEX_ARRAY)) System.out.println("! GL_INDEX_ARRAY nicht aktiv !");
		
		gl.glDrawElementsInstancedEXT(GL.GL_QUADS, elements, GL.GL_UNSIGNED_INT, indexBuffer, 16);
	}

I hope you can make some sense of my coding. :slight_smile:
Feel free to ask me questions if anything is unclear.

I am most happy for ANY INSIGHT on the matter!!!

Oh, almost forgot my system information:

  • WinXP-Prof SP2
  • 2.6GHz dual core
  • NVIDIA GeForce 8600GT with newest drivers

Thank you so much for reading this!

Regards,
Daniel

Any chance this happens after a GC?

Maybe you pass a java.nio.Buffer to a JOGL function, and the JOGL part only grabs the pointer for later use (not keeping the Buffer around). On a GC, the Buffer may get freed, making the pointer invalid as the memory region doesn’t belong to the JVM anymore.

If this is the case, you need to make sure you keep your Buffers referenced.
For testing, this might work (and is a horrible memoryleak):


// WARNING: horrible, memory leaking code ahead

private static List all_buffers = new ArrayList();

public static IntBuffer newImmortalIntBuffer()
{
   IntBuffer buf = BufferUtil.newIntBuffer();
   immortalize(buf);
   return buf;
}

public static FloatBuffer newImmortalFloatBuffer()
{
   FloatBuffer buf = BufferUtil.newFloatBuffer();
   immortalize(buf);
   return buf;
}

private static final void immortalize(Buffer buf)
{
   synchronized(all_buffers)
   {
      all_buffers.add(buf);
   }
}

If this fixes your crashes, then my assumption was right. Otherwise, the bug is in your code. (I think…)

I know this is taken care off in LWJGL, but not sure whether this is also taken into account in JOGL…

I’ve never used the extension myself, but I must ask why you’re using it without shaders. From a glance at the extension, it seemed the main benefit would be to automatically pass everything into the shader, and update insanceID for each model. This way, you can adjust the transform for each model, otherwise I would expect that every model is drawn on top of each other.

Also, you probably don’t need both glFlush() and glFinish() at the end of drawing, I’ve found glFlush() to be sufficient.