I have accurately tested my app before release it, on Emulator set with different screen size (and with different Android SDK and CPU emulations), and many real devices. No problems, everything works fine. Now an user has reported a bug with his tablet.
I’m testing the app on tons of devices and the issue happens only if the devices use some kind of soc ARM with PowerVR SGX544(and maybe other similar GPUs) and Android 4.x.
The app doesn’t use any texture, only GL11, GL10 and GLView to plot some graph, and runs smooth also on old cheap smartphones with at least Gingerbread… but with this Power VR the result of the plot is an unreadable and laggy graphic glitch
No error in the Eclipse logs, No crash or code deprecation warning
The code of the section with the bug (I cannot be more syntetic because I get no error)
class Graph3d {<br />
private final int N = 48;<br />
private ShortBuffer verticeIdx;<br />
private FloatBuffer vertexBuf;<br />
private ByteBuffer colorBuf;<br />
private int vertexVbo, colorVbo, vertexElementVbo;<br />
private boolean useVBO;<br />
private int nVertex;<br />
<br />
Graph3d(GL11 gl) {<br />
short[] b = new short[N*N];<br />
int p = 0;<br />
for (int i = 0; i < N; i++) {<br />
short v = 0;<br />
for (int j = 0; j < N; v += N+N, j+=2) {<br />
b[p++] = (short)(v+i);<br />
b[p++] = (short)(v+N+N-1-i);<br />
}<br />
v = (short) (N*(N-2));<br />
i++;<br />
for (int j = N-1; j >= 0; v -= N+N, j-=2) {<br />
b[p++] = (short)(v+N+N-1-i);<br />
b[p++] = (short)(v+i);<br />
}<br />
}<br />
verticeIdx = buildBuffer(b);<br />
<br />
String extensions = gl.glGetString(GL10.GL_EXTENSIONS);<br />
useVBO = extensions.indexOf("vertex_buffer_object") != -1;<br />
Calculator.log("VBOs support: " + useVBO + " version " + gl.glGetString(GL10.GL_VERSION));<br />
<br />
if (useVBO) {<br />
int[] out = new int[3];<br />
gl.glGenBuffers(3, out, 0);<br />
vertexVbo = out[0];<br />
colorVbo = out[1];<br />
vertexElementVbo = out[2];<br />
}<br />
}<br />
<br />
private static FloatBuffer buildBuffer(float[] b) {<br />
ByteBuffer bb = ByteBuffer.allocateDirect(b.length << 2);<br />
bb.order(ByteOrder.nativeOrder());<br />
FloatBuffer sb = bb.asFloatBuffer();<br />
sb.put(b);<br />
sb.position(0);<br />
return sb;<br />
}<br />
<br />
private static ShortBuffer buildBuffer(short[] b) {<br />
ByteBuffer bb = ByteBuffer.allocateDirect(b.length << 1);<br />
bb.order(ByteOrder.nativeOrder());<br />
ShortBuffer sb = bb.asShortBuffer();<br />
sb.put(b);<br />
sb.position(0);<br />
return sb;<br />
}<br />
<br />
private static ByteBuffer buildBuffer(byte[] b) {<br />
ByteBuffer bb = ByteBuffer.allocateDirect(b.length << 1);<br />
bb.order(ByteOrder.nativeOrder());<br />
bb.put(b);<br />
bb.position(0);<br />
return bb;<br />
}<br />
<br />
public void update(GL11 gl, Function f, float zoom) {<br />
final int NTICK = Calculator.useHighQuality3d ? 5 : 0;<br />
final float size = 4*zoom;<br />
final float minX = -size, maxX = size, minY = -size, maxY = size;<br />
<br />
Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo);<br />
nVertex = N*N+6+8 + NTICK*6;<br />
int nFloats = nVertex * 3;<br />
float vertices[] = new float[nFloats];<br />
byte colors[] = new byte[nVertex << 2];<br />
if (f != null) {<br />
Calculator.log("Graph3d update");<br />
float sizeX = maxX - minX;<br />
float sizeY = maxY - minY;<br />
float stepX = sizeX / (N-1);<br />
float stepY = sizeY / (N-1);<br />
int pos = 0;<br />
double sum = 0;<br />
float y = minY;<br />
float x = minX - stepX;<br />
int nRealPoints = 0;<br />
for (int i = 0; i < N; i++, y+=stepY) {<br />
float xinc = (i & 1) == 0 ? stepX : -stepX;<br />
x += xinc;<br />
for (int j = 0; j < N; ++j, x+=xinc, pos+=3) {<br />
float z = (float) f.eval(x, y);<br />
vertices[pos] = x;<br />
vertices[pos+1] = y;<br />
vertices[pos+2] = z;<br />
if (z == z) { // not NAN<br />
sum += z * z;<br />
++nRealPoints;<br />
}<br />
}<br />
}<br />
float maxAbs = (float) Math.sqrt(sum / nRealPoints);<br />
maxAbs *= .9f;<br />
maxAbs = Math.min(maxAbs, 15);<br />
maxAbs = Math.max(maxAbs, .001f);<br />
<br />
final int limitColor = N*N*4;<br />
for (int i = 0, j = 2; i < limitColor; i+=4, j+=3) {<br />
float z = vertices[j];<br />
if (z == z) {<br />
final float a = z / maxAbs;<br />
final float abs = a < 0 ? -a : a;<br />
colors<i> = floatToByte(a);<br />
colors[i+1] = floatToByte(1-abs*.3f);<br />
colors[i+2] = floatToByte(-a);<br />
colors[i+3] = (byte) 255;<br />
} else {<br />
vertices[j] = 0;<br />
z = 0;<br />
colors<i> = 0;<br />
colors[i+1] = 0;<br />
colors[i+2] = 0;<br />
colors[i+3] = 0;<br />
}<br />
}<br />
}<br />
int base = N*N*3;<br />
int colorBase = N*N*4;<br />
int p = base;<br />
final int baseSize = 2;<br />
for (int i = -baseSize; i <= baseSize; i+=2*baseSize) {<br />
vertices[p] = i; vertices[p+1] = -baseSize; vertices[p+2] = 0;<br />
p += 3;<br />
vertices[p] = i; vertices[p+1] = baseSize; vertices[p+2] = 0;<br />
p += 3;<br />
vertices[p] = -baseSize; vertices[p+1] = i; vertices[p+2] = 0;<br />
p += 3;<br />
vertices[p] = baseSize; vertices[p+1] = i; vertices[p+2] = 0;<br />
p += 3;<br />
}<br />
for (int i = colorBase; i < colorBase+8*4; i += 4) {<br />
colors<i> = 0;<br />
colors[i+1] = 0;<br />
colors[i+2] = (byte) 255;<br />
colors[i+3] = (byte) 255;<br />
}<br />
base += 8*3;<br />
colorBase += 8*4;<br />
<br />
final float unit = 2;<br />
final float axis[] = {<br />
0, 0, 0,<br />
unit, 0, 0,<br />
0, 0, 0,<br />
0, unit, 0,<br />
0, 0, 0,<br />
0, 0, unit,<br />
};<br />
System.arraycopy(axis, 0, vertices, base, 6*3);<br />
for (int i = colorBase; i < colorBase+6*4; i+=4) {<br />
colors<i> = (byte) 255;<br />
colors[i+1] = (byte) 255;<br />
colors[i+2] = (byte) 255;<br />
colors[i+3] = (byte) 255;<br />
}<br />
base += 6*3;<br />
colorBase += 6*4;<br />
<br />
p = base;<br />
final float tick = .03f;<br />
final float offset = .01f;<br />
for (int i = 1; i <= NTICK; ++i) {<br />
vertices[p] = i-tick;<br />
vertices[p+1] = -offset;<br />
vertices[p+2] = -offset;<br />
<br />
vertices[p+3] = i+tick;<br />
vertices[p+4] = offset;<br />
vertices[p+5] = offset;<br />
p += 6;<br />
<br />
vertices[p] = -offset;<br />
vertices[p+1] = i-tick;<br />
vertices[p+2] = -offset;<br />
<br />
vertices[p+3] = offset;<br />
vertices[p+4] = i+tick;<br />
vertices[p+5] = offset;<br />
p += 6;<br />
<br />
vertices[p] = -offset;<br />
vertices[p+1] = -offset;<br />
vertices[p+2] = i-tick;<br />
<br />
vertices[p+3] = offset;<br />
vertices[p+4] = offset;<br />
vertices[p+5] = i+tick;<br />
p += 6;<br />
<br />
}<br />
for (int i = colorBase+NTICK*6*4-1; i >= colorBase; --i) {<br />
colors<i> = (byte) 255;<br />
}<br />
<br />
vertexBuf = buildBuffer(vertices);<br />
colorBuf = buildBuffer(colors);<br />
<br />
if (useVBO) {<br />
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexVbo);<br />
gl.glBufferData(GL11.GL_ARRAY_BUFFER, vertexBuf.capacity()*4, vertexBuf, GL11.GL_STATIC_DRAW);<br />
vertexBuf = null;<br />
<br />
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorVbo);<br />
gl.glBufferData(GL11.GL_ARRAY_BUFFER, colorBuf.capacity(), colorBuf, GL11.GL_STATIC_DRAW);<br />
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);<br />
colorBuf = null;<br />
<br />
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);<br />
gl.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, verticeIdx.capacity()*2, verticeIdx, GL11.GL_STATIC_DRAW);<br />
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);<br />
}<br />
}<br />
<br />
private byte floatToByte(float v) {<br />
return (byte) (v <= 0 ? 0 : v >= 1 ? 255 : (int)(v*255));<br />
}<br />
<br />
public void draw(GL11 gl) {<br />
if (useVBO) {<br />
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexVbo);<br />
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, 0);<br />
<br />
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorVbo);<br />
gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, 0);<br />
<br />
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);<br />
// gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N*N);<br />
<br />
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);<br />
gl.glDrawElements(GL10.GL_LINE_STRIP, N*N, GL10.GL_UNSIGNED_SHORT, 0);<br />
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);<br />
} else {<br />
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuf);<br />
gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, colorBuf);<br />
gl.glDrawElements(GL10.GL_LINE_STRIP, N*N, GL10.GL_UNSIGNED_SHORT, verticeIdx);<br />
}<br />
final int N2 = N*N;<br />
gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N2);<br />
gl.glDrawArrays(GL10.GL_LINES, N2, nVertex - N2);<br />
}<br />
}
```<br />
<br />
<br />
<a href="http://stackoverflow.com/questions/18728871/android-opengl-es-issue-only-with-a-specific-gpu-without-any-error-in-logcat">More details HERE</a></i></i></i></i></i>