Vertex Buffer Filling slow

Started by mslootweg, October 21, 2011, 22:53:34

Previous topic - Next topic

mslootweg

I am working on a 2d game and I need to draw the same image at a couple thousand locations. these locations change each frame. What I do is fill a Vertex buffer with the coordinates of the images and then send that buffer to OpenGL to draw.

I fill the buffer in this style:

currentbuffer.put(x1);
currentbuffer.put(y1);
currentbuffer.put(x2);
currentbuffer.put(y2);
currentbuffer.put(x3);
currentbuffer.put(y3);
currentbuffer.put(x4);
currentbuffer.put(y4);


This has become a real bottleneck now. my game is spending most of it's time processing those lines. It takes OpenGL 500 microseconds to draw the images to the screen once it recieves the buffer, but it takes my code 3000 microseconds to fill this buffer. Is there a different way to get my vertex data to OpenGL that takes less CPU time?
For instance, can I send a single x,y per object to be drawn and let OpenGL figure out what the corners are?


Full code:

This vertex buffer filling code fetches the x,y of the center of an object to be drawn, translates that into the x,y of all the corners and puts this in a vertex buffer.

private void loadbufferspreview() {

		//variables
		float x, y, xbotleft, ybotleft;
		GLImage currentimg;
		FloatBuffer currentbuffer;
		int currentimgid;

		while (gamecontrol.lastfbuffer.hasRemaining()) {
			//This while loop loops through all the several thousand objects that need drawing
			
			//Fetch the id of the image to use for this object
			currentimgid = gamecontrol.lastibuffer.get();
			
			//If the imageID is zero this means the object should not be drawn
			if (currentimgid != 0) {
			
			//Fetch the image to use for this object
			currentimg = img[currentimgid];
			
			//Select vertexbuffer that goes with this texture
			currentbuffer = imgvertices.get(currentimgid);

			//retrieve the location the object is going to be drawn at next frame
			//this is the x,y of the center of the object
			x = gamecontrol.lastfbuffer.get()+ playarealeft;
			y = gamecontrol.lastfbuffer.get();
			
			//Ignore another value currently not interesting
			gamecontrol.lastfbuffer.get();
	
			
			//OpenGL needs the corners of textures, so calculate the bottomleft corner
			xbotleft = x - (currentimg.origwidth / 2);
			ybotleft = y - (currentimg.origheight / 2);

			//Now put the 8 floats (4 times x,y) that describe the quad into the buffer to be drawn later
			
			/*
			currentbuffer.put(xbotleft);
			currentbuffer.put(ybotleft);
			currentbuffer.put(xbotleft);
			currentbuffer.put(currentimg.origheight + ybotleft);
			currentbuffer.put(currentimg.origwidth + xbotleft);
			currentbuffer.put(currentimg.origheight + ybotleft);
			currentbuffer.put(currentimg.origwidth + xbotleft);
			currentbuffer.put(ybotleft);
			*/
			
			
			}else{
				
				//Dump the values that would've been used, not interesting at the moment
				gamecontrol.lastfbuffer.get();
				gamecontrol.lastfbuffer.get();
				gamecontrol.lastfbuffer.get();
			}
		}

	}



Cubic

I think a better approach would be to just use 4 vertices - cause you're just going to draw the same rectangular quad again and again - and then use another floatbuffer which just stores the position vectors of the drawing instances, and then you just transform the quad based on that vector. That way you have to update far less values per frame (namely, 2 floats per quad). Not sure if that's actually the best solution, but it I think it should be a bit faster than storing thousands of individual quads.

CodeBunny

Is this a particle system (or does it operate under similar rules)? Try looking up ways to render optimized particle systems and see what you can do.

mslootweg

I've tried what you suggested before Cubic, but this requires a different transform per quad. The only way I know of doing this is drawing 1 quad at a time, supplying a different transform each time. This would mean that each quad would require multiple openGL calls. And at a couple thousand quads, this starts adding up...

I did actually find a faster way of writing to the buffer. I've not tried using other methods because of this thread:
http://www.java-gaming.org/index.php?topic=23505.0
It shows that individual puts that I was using was generally the fastest way of filling floatbuffers, however I actually found that in my implementation, filling an array and then filling the floatbuffer with that is actually 10x faster.

I haven't thought of looking at this like a particle system yet. I'll look into that. It's not a particle system, simply a game that uses many instances of the same image (bullets)