Game Development Reference
In-Depth Information
Working Around a Bug in FloatBuffer
The reason for the Hero's dismal performance with the new SpriteBatcher method isn't obvious.
Our SpriteBatcher puts a float array into a direct ByteBuffer each frame when we call Vertices.
setVertices() . The method boils down to calling FloatBuffer.put(float[]) , and that's the
culprit for the performance hit. While desktop Java implements that FloatBuffer method via a
real bulk memory move, the Harmony version used in older Android versions calls FloatBuffer.
put(float) for each element in the array. And that's extremely unfortunate, as that method is a
JNI method, which has a lot of overhead (much like the OpenGL ES methods, which are also
JNI methods).
There are a couple of solutions. IntBuffer.put(int[]) does not suffer from this problem, for
example. We could replace the FloatBuffer in our Vertices class with an IntBuffer , and modify
Vertices.setVertices() so that it first transfers the floats from the float array to a temporary
int array and then copies the contents of that int array to the IntBuffer . This solution was
proposed by Ryan McNally, a fellow game developer, who also reported the bug on the Android
bug tracker. It produces a five-times performance increase on the Hero, and a little less on other
Android devices.
We modify the Vertices class to include this fix. We change the vertices member to an
IntBuffer . We add a new member called tmpBuffer , which is an int array. The tmpBuffer array is
initialized in the constructor of Vertices , as follows:
this.tmpBuffer = new int [maxVertices * vertexSize / 4];
We also get an IntBuffer view from the ByteBuffer in the constructor, instead of a FloatBuffer :
vertices = buffer.asIntBuffer();
And the Vertices.setVertices() method looks like this now:
public void setVertices( float [] vertices, int offset, int length) {
this .vertices.clear();
int len = offset + length;
for ( int i = offset, j = 0; i < len; i++, j++)
tmpBuffer[j] = Float.floatToRawIntBits(vertices[i]);
this .vertices.put(tmpBuffer, 0, length);
this .vertices.flip();
}
First, we transfer the contents of the vertices parameter to the tmpBuffer . The static method
Float.floatToRawIntBits() reinterprets the bit pattern of a float as an int. We then need to copy
the contents of the int array to the IntBuffer , formerly known as a FloatBuffer . Does it improve
performance? Running the SpriteBatcherTest produces the following output now on the Hero,
Droid, and Nexus One:
Hero (1.5):
12-28 00:24:54.770: DEBUG/FPSCounter(2538): fps: 61
12-28 00:24:54.770: DEBUG/FPSCounter(2538): fps: 61
12-28 00:24:55.790: DEBUG/FPSCounter(2538): fps: 62
12-28 00:24:55.790: DEBUG/FPSCounter(2538): fps: 62
 
Search WWH ::




Custom Search