I'm developing in OpenGL ES 2 on Android (my dev device uses Jelly Bean) and I created a scene with 3 full screen backgrounds (two scroll horizontally), 2 particle emitters, a sprite, and some other things dealing with audio and controls. After starting up my app I see the FPS is pretty sad, averaging around 19 FPS.
Based on my other app tests I was pretty sure it was the graphics, so as a blind shot in the dark I changed the max quads that my sprite batcher could handle before it needed to flush the buffer from 5000 to 1000. Started it back up and bang! I instantly hit 55+ FPS, change the max quads again to 500 and I'm back at 60 FPS
Could someone tell me why this worked?
I mean its awesome, but I really have no idea how this actually made my FPS skyrocket.
The max quads constant in my batcher does effect how big the the VBO/IBO are, but I would think that does not matter as my call to glBufferSubData only fills the VBO with what it needs and my call to glDrawElements only draws the number of vertices required for the quads.
Here is my flush method which is responsible for actually doing the draw call
private void FlushBatch()
{
//Back out if there is nothing to draw
if(vboIndex == 0)
return;
//Set up everything for the Shader Program to run
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, batchTextureID);
currentShaderProgram.UseProgram();
currentShaderProgram.UseUniform("projectionMatrix", batchProjectionMatrix.data);
currentShaderProgram.UseUniform("textureSampler", 0);
currentShaderProgram.EnableAttribute("vertexPos", currentShaderProgram.AttributesTotalByteSize(), 0);
currentShaderProgram.EnableAttribute("color", currentShaderProgram.AttributesTotalByteSize(), currentShaderProgram.Attribute("vertexPos").byteSize);
currentShaderProgram.EnableAttribute("texCoords", currentShaderProgram.AttributesTotalByteSize(), currentShaderProgram.Attribute("vertexPos").byteSize + currentShaderProgram.Attribute("color").byteSize);
//Prepare the vbo buffer that will be used by OpenGL
vboBuffer.put(vertexData, 0, vboIndex);
vboBuffer.position(0);
//Bind the buffer and fill the GPU buffer
glBindBuffer(GL_ARRAY_BUFFER, vbos[0]);
glBufferSubData(GL_ARRAY_BUFFER, 0, vboIndex * BYTES_PER_FLOAT, vboBuffer);
//Bind the IBO and draw our quads
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibos[0]);
glDrawElements(GL_TRIANGLES, (int)(INDICES_PER_QUAD * vboIndex * vboFloatsPerQuadRatio), GL_UNSIGNED_SHORT, 0);
//Reset where we are in the vbo buffer
vboIndex = 0;
}
Here is my VBO/IBO creation
private void CreateVboObjects()
{
//Gen the vbo names
vboCount = 1;
vbos = new int[vboCount];
glGenBuffers(vboCount, vbos, 0);
//setup vbo buffer (the java buffer) to be used by opengl
//MAX_QUADS_PER_BATCH was changed from 5000 to 500 and the FPS skyrocketed. Why?
vboBuffer = ByteBuffer.allocateDirect(MAX_QUADS_PER_BATCH * VERTEX_PER_QUAD * FLOAT_COMPONENTS_PER_VERTEX * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
vboBuffer.position(0);
vboIndex = 0;
vboFloatComponentsPerQuad = FLOAT_COMPONENTS_PER_VERTEX * VERTEX_PER_QUAD;
vboFloatsPerQuadRatio = 1.0f / (float)vboFloatComponentsPerQuad;
vboCurrentBuffer = 0;
//Create the intermediate container for the vbo data (used because Put for java buffers is super slow :( )
vertexData = new float[vboBuffer.limit()];
//Create the VBO for opengl
for(int i = 0; i < vbos.length; ++i)
{
glBindBuffer(GL_ARRAY_BUFFER, vbos[i]);
glBufferData(GL_ARRAY_BUFFER, vboBuffer.limit() * BYTES_PER_FLOAT, null, GL_DYNAMIC_DRAW);
}
}
private void CreateIboObject()
{
//Gen the ibo name
ibos = new int[1];
glGenBuffers(1, ibos, 0);
//Create the java buffer for the ibo
ShortBuffer iboData = ByteBuffer.allocateDirect(MAX_QUADS_PER_BATCH * INDICES_PER_QUAD * BYTES_PER_SHORT).order(ByteOrder.nativeOrder()).asShortBuffer();
iboData.position(0);
//Generate the ibo data to use
for(int i = 0, j = 0; i < MAX_QUADS_PER_BATCH * INDICES_PER_QUAD; i += INDICES_PER_QUAD, j += VERTEX_PER_QUAD)
{
iboData.put((short) j);
iboData.put((short)(j + 1));
iboData.put((short)(j + 2));
iboData.put((short)(j + 3));
iboData.put((short) j);
iboData.put((short)(j + 2));
}
iboData.flip();
//Create the IBO buffer for opengl
for(int i = 0; i < ibos.length; ++i)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibos[i]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iboData.limit() * BYTES_PER_SHORT, iboData, GL_STATIC_DRAW);
}
}