My App works fine on Emulator and all-test devices but not with PowerVR SGX544 powered devices

This topic contains 12 replies, has 2 voices, and was last updated by  Joe Davis 3 years, 11 months ago.

Viewing 13 posts - 1 through 13 (of 13 total)
  • Author
    Posts
  • #31495

    AndreaF
    Member

    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 {
    private final int N = 48;
    private ShortBuffer verticeIdx;
    private FloatBuffer vertexBuf;
    private ByteBuffer colorBuf;
    private int vertexVbo, colorVbo, vertexElementVbo;
    private boolean useVBO;
    private int nVertex;

    Graph3d(GL11 gl) {
    short[] b = new short[N*N];
    int p = 0;
    for (int i = 0; i < N; i++) {
    short v = 0;
    for (int j = 0; j < N; v += N+N, j+=2) {
    b[p++] = (short)(v+i);
    b[p++] = (short)(v+N+N-1-i);
    }
    v = (short) (N*(N-2));
    i++;
    for (int j = N-1; j >= 0; v -= N+N, j-=2) {
    b[p++] = (short)(v+N+N-1-i);
    b[p++] = (short)(v+i);
    }
    }
    verticeIdx = buildBuffer(b);

    String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
    useVBO = extensions.indexOf("vertex_buffer_object") != -1;
    Calculator.log("VBOs support: " + useVBO + " version " + gl.glGetString(GL10.GL_VERSION));

    if (useVBO) {
    int[] out = new int[3];
    gl.glGenBuffers(3, out, 0);
    vertexVbo = out[0];
    colorVbo = out[1];
    vertexElementVbo = out[2];
    }
    }

    private static FloatBuffer buildBuffer(float[] b) {
    ByteBuffer bb = ByteBuffer.allocateDirect(b.length < < 2);
    bb.order(ByteOrder.nativeOrder());
    FloatBuffer sb = bb.asFloatBuffer();
    sb.put(b);
    sb.position(0);
    return sb;
    }

    private static ShortBuffer buildBuffer(short[] b) {
    ByteBuffer bb = ByteBuffer.allocateDirect(b.length < < 1);
    bb.order(ByteOrder.nativeOrder());
    ShortBuffer sb = bb.asShortBuffer();
    sb.put(b);
    sb.position(0);
    return sb;
    }

    private static ByteBuffer buildBuffer(byte[] b) {
    ByteBuffer bb = ByteBuffer.allocateDirect(b.length < < 1);
    bb.order(ByteOrder.nativeOrder());
    bb.put(b);
    bb.position(0);
    return bb;
    }

    public void update(GL11 gl, Function f, float zoom) {
    final int NTICK = Calculator.useHighQuality3d ? 5 : 0;
    final float size = 4*zoom;
    final float minX = -size, maxX = size, minY = -size, maxY = size;

    Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo);
    nVertex = N*N+6+8 + NTICK*6;
    int nFloats = nVertex * 3;
    float vertices[] = new float[nFloats];
    byte colors[] = new byte[nVertex < < 2];
    if (f != null) {
    Calculator.log("Graph3d update");
    float sizeX = maxX - minX;
    float sizeY = maxY - minY;
    float stepX = sizeX / (N-1);
    float stepY = sizeY / (N-1);
    int pos = 0;
    double sum = 0;
    float y = minY;
    float x = minX - stepX;
    int nRealPoints = 0;
    for (int i = 0; i < N; i++, y+=stepY) {
    float xinc = (i & 1) == 0 ? stepX : -stepX;
    x += xinc;
    for (int j = 0; j < N; ++j, x+=xinc, pos+=3) {
    float z = (float) f.eval(x, y);
    vertices[pos] = x;
    vertices[pos+1] = y;
    vertices[pos+2] = z;
    if (z == z) { // not NAN
    sum += z * z;
    ++nRealPoints;
    }
    }
    }
    float maxAbs = (float) Math.sqrt(sum / nRealPoints);
    maxAbs *= .9f;
    maxAbs = Math.min(maxAbs, 15);
    maxAbs = Math.max(maxAbs, .001f);

    final int limitColor = N*N*4;
    for (int i = 0, j = 2; i < limitColor; i+=4, j+=3) {
    float z = vertices[j];
    if (z == z) {
    final float a = z / maxAbs;
    final float abs = a < 0 ? -a : a;
    colors = floatToByte(a);
    colors[i+1] = floatToByte(1-abs*.3f);
    colors[i+2] = floatToByte(-a);
    colors[i+3] = (byte) 255;
    } else {
    vertices[j] = 0;
    z = 0;
    colors
    = 0;
    colors[i+1] = 0;
    colors[i+2] = 0;
    colors[i+3] = 0;
    }
    }
    }
    int base = N*N*3;
    int colorBase = N*N*4;
    int p = base;
    final int baseSize = 2;
    for (int i = -baseSize; i < = baseSize; i+=2*baseSize) {
    vertices[p] = i; vertices[p+1] = -baseSize; vertices[p+2] = 0;
    p += 3;
    vertices[p] = i; vertices[p+1] = baseSize; vertices[p+2] = 0;
    p += 3;
    vertices[p] = -baseSize; vertices[p+1] = i; vertices[p+2] = 0;
    p += 3;
    vertices[p] = baseSize; vertices[p+1] = i; vertices[p+2] = 0;
    p += 3;
    }
    for (int i = colorBase; i < colorBase+8*4; i += 4) {
    colors
    = 0;
    colors[i+1] = 0;
    colors[i+2] = (byte) 255;
    colors[i+3] = (byte) 255;
    }
    base += 8*3;
    colorBase += 8*4;

    final float unit = 2;
    final float axis[] = {
    0, 0, 0,
    unit, 0, 0,
    0, 0, 0,
    0, unit, 0,
    0, 0, 0,
    0, 0, unit,
    };
    System.arraycopy(axis, 0, vertices, base, 6*3);
    for (int i = colorBase; i < colorBase+6*4; i+=4) {
    colors
    = (byte) 255;
    colors[i+1] = (byte) 255;
    colors[i+2] = (byte) 255;
    colors[i+3] = (byte) 255;
    }
    base += 6*3;
    colorBase += 6*4;

    p = base;
    final float tick = .03f;
    final float offset = .01f;
    for (int i = 1; i < = NTICK; ++i) {
    vertices[p] = i-tick;
    vertices[p+1] = -offset;
    vertices[p+2] = -offset;

    vertices[p+3] = i+tick;
    vertices[p+4] = offset;
    vertices[p+5] = offset;
    p += 6;

    vertices[p] = -offset;
    vertices[p+1] = i-tick;
    vertices[p+2] = -offset;

    vertices[p+3] = offset;
    vertices[p+4] = i+tick;
    vertices[p+5] = offset;
    p += 6;

    vertices[p] = -offset;
    vertices[p+1] = -offset;
    vertices[p+2] = i-tick;

    vertices[p+3] = offset;
    vertices[p+4] = offset;
    vertices[p+5] = i+tick;
    p += 6;

    }
    for (int i = colorBase+NTICK*6*4-1; i >= colorBase; --i) {
    colors
    = (byte) 255;
    }

    vertexBuf = buildBuffer(vertices);
    colorBuf = buildBuffer(colors);

    if (useVBO) {
    gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexVbo);
    gl.glBufferData(GL11.GL_ARRAY_BUFFER, vertexBuf.capacity()*4, vertexBuf, GL11.GL_STATIC_DRAW);
    vertexBuf = null;

    gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorVbo);
    gl.glBufferData(GL11.GL_ARRAY_BUFFER, colorBuf.capacity(), colorBuf, GL11.GL_STATIC_DRAW);
    gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
    colorBuf = null;

    gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
    gl.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, verticeIdx.capacity()*2, verticeIdx, GL11.GL_STATIC_DRAW);
    gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
    }
    }

    private byte floatToByte(float v) {
    return (byte) (v < = 0 ? 0 : v >= 1 ? 255 : (int)(v*255));
    }

    public void draw(GL11 gl) {
    if (useVBO) {
    gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexVbo);
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, 0);

    gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorVbo);
    gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, 0);

    gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
    // gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N*N);

    gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
    gl.glDrawElements(GL10.GL_LINE_STRIP, N*N, GL10.GL_UNSIGNED_SHORT, 0);
    gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
    } else {
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuf);
    gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, colorBuf);
    gl.glDrawElements(GL10.GL_LINE_STRIP, N*N, GL10.GL_UNSIGNED_SHORT, verticeIdx);
    }
    final int N2 = N*N;
    gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N2);
    gl.glDrawArrays(GL10.GL_LINES, N2, nVertex - N2);
    }
    }

    More details HERE

    #38022

    Joe Davis
    Member

    Hi,

    Can you share screenshots of a correct and incorrect render? I’d like to better understand the artefacts you’re seeing.

    Also, can you try disabling depth tests? On some SGX544 platforms, we’ve seen depth fighting when co-planar primitives are drawn in 2D renders. You shouldn’t need depth tests for your graphs render anyway.

    Thanks,
    Joe

    #38023

    AndreaF
    Member

    Hi,

    Can you share screenshots of a correct and incorrect render? I’d like to better understand the artefacts you’re seeing.

    Also, can you try disabling depth tests? On some SGX544 platforms, we’ve seen depth fighting when co-planar primitives are drawn in 2D renders. You shouldn’t need depth tests for your graphs render anyway.

    Thanks,
    Joe

    Thanks for the answer,

    This is what appears on emulator and devices (both smartphone and tablets) with various GPU of Tegra, Adreno and Mali series


    The image can be rotated with touch and respond istantly to the touch

    Here what I see on PowerVR SGX544 tablet

    the result seems freezed and if I try to rotate with touch the graph responds after many seconds and appears similar non-sense glitches

    Where (and how) exactly I have to disable depth test?

    #38024

    Joe Davis
    Member

    Hi,

    Sorry for the slow response.

    Based on the artefacts in your images, I don’t think depth buffer tests are the cause.

    On each of your target devices, which ones are using the VBO path? Could there possibly be a flaw in one of your rendering paths?

    Can you email devtech@imgtec.com with either a PVRTrace recording of your application or the APK itself so we can investigate? If required, we can give you details for our file sharing system.

    Regards,
    Joe

    #38025

    Joe Davis
    Member

    Hi,

    Can you share the name of the tablet you’re using? Can you also give us the version number of the device’s graphics driver (instructions to query it can be found here). It seems like the bug may be specific to that device.

    I’ve ran the app on a Galaxy S 4 (GT-I9500) which contains an SGX544, but the calculation I’d entered (x^2+y^2) is rendering as I’d expected.

    Thanks,
    Joe

    #38026

    AndreaF
    Member

    For the test I use Goclever Orion 7o

    CPU Soc: AllWinner A31 8CORE GPU POWERVR SGX544MP2 (afaik Galaxy S4 should use the SGX544MP3)
    OS: Android 4.2.2 Kernel 3.3.0
    Firmware version 1.00_20130605 build JDQ39
    SGXDDK: 1.10@2359475
    SGX revision = 1.1.5

    #38027

    Joe Davis
    Member

    Hi,

    Can you also share the calculation you’re using in your reproduction case? I want to remove the possibility that the calculation I’ve chosen doesn’t hit the problem.

    Regards,
    Joe

    #38028

    AndreaF
    Member

    Hi,

    Can you also share the calculation you’re using in your reproduction case? I want to remove the possibility that the calculation I’ve chosen doesn’t hit the problem.

    Regards,
    Joe

    Happens with every 3D graph calculation. sin(x)cos(y) cos(y)x etc

    #38029

    Joe Davis
    Member

    Hi,

    I was able to reproduce artefacts on a tablet with an AllWinner A31 SoC (Onda v972). I’m still not sure what the cause is. I’ll continue investigating the issue later this week.

    Regards,
    Joe

    #38030

    AndreaF
    Member

    Hi,

    I was able to reproduce artefacts on a tablet with an AllWinner A31 SoC (Onda v972). I’m still not sure what the cause is. I’ll continue investigating the issue later this week.

    Regards,
    Joe

    Thanks, I hope you could help me. My knowledge of PowerVR GPU is not enough to find a workaround for this absurd issue

    #38031

    Joe Davis
    Member

    After further investigation, I don’t believe this is a graphics driver or hardware problem.

    I used PVRTrace to capture the application running on a device that renders as expected (Galaxy Nexus) and another that reproduces the artefacts you’ve seen (Onda V972). When replaying the OpenGL ES capture in PVRTraceGUI, the Onda recording is still incorrect. If it was a graphics driver issue, then the PVRTraceGUI render shouldn’t contain the artefacts. It seems that the data submitted to OpenGL ES is incorrect.

    Have you tried reviewing the contents of the buffers you’re submitting to GL to ensure the values are correct?

    Regards,
    Joe

    #38032

    AndreaF
    Member

    After further investigation, I don’t believe this is a graphics driver or hardware problem.

    I used PVRTrace to capture the application running on a device that renders as expected (Galaxy Nexus) and another that reproduces the artefacts you’ve seen (Onda V972). When replaying the OpenGL ES capture in PVRTraceGUI, the Onda recording is still incorrect. If it was a graphics driver issue, then the PVRTraceGUI render shouldn’t contain the artefacts. It seems that the data submitted to OpenGL ES is incorrect.

    Have you tried reviewing the contents of the buffers you’re submitting to GL to ensure the values are correct?

    Regards,
    Joe

    I don’t know what kind of test should I do. How is possible that the buffer content is wrong only for this GPU?

    However I have posted the methods buildBuffer in this thread, (and I have used in each method bb.order(ByteOrder.nativeOrder());). Is there any other thing that should I do to ensure compatibility also to this GPU?

    #38033

    Joe Davis
    Member

    I don’t think it’s a GPU compatibility problem. I suspect that something is causing your buffer to become corrupt/incorrect before it is uploaded to GL. As I mentioned above, using PVRTrace to capture the data your application has submitted to GL (before it’s been sent to the graphics driver) has reproduced the artefacts. When I used PVRTrace to play back a capture I took on a Galaxy Nexus, the render was correct.

    It may be the case that a bug was introduced into OS functionality when it was ported to the platform. I would recommend performing the same calculation on two devices (ones that works, one that doesn’t) and comparing the resultant values that are uploaded to GL. This way, you should be able to isolate the cause of the incorrect values.

    Regards,
    Joe

Viewing 13 posts - 1 through 13 (of 13 total)
You must be logged in to reply to this topic.