3

在发布之前,我已经在具有不同屏幕尺寸(以及不同的 Android SDK 和 CPU 仿真)的模拟器上以及许多真实设备上准确地测试了我的应用程序。没问题,一切正常。现在,一位用户报告了他的平板电脑的错误。

我正在大量设备上测试该应用程序,只有当设备使用某种带有PowerVR SGX544和 Android 4.x的 soc ARM 时才会出现问题。

该应用程序不使用任何纹理,仅使用 GL11、GL10 和 GLView 来绘制一些图形,并且在具有至少 Gingerbread 的旧廉价智能手机上也能流畅运行......但是使用这个 Power VR,绘图的结果是不可读和滞后图形故障

Eclipse 日志中没有错误,没有崩溃或代码弃用警告

我必须假设错误存在于 GPU 驱动程序中吗?

有错误的部分的代码(我不能更综合,因为我没有收到错误)

public class My3dView extends GLView implements 
                                            Grapher,
                                            TouchHandler.TouchHandlerInterface
{

    private float lastTouchX, lastTouchY;
    private TouchHandler touchHandler;
    private float zoomLevel = 1, targetZoom, zoomStep = 0, currentZoom;
    private FPS fps = new FPS();
    private Graph3d graph;

    public My3dView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public My3dView(Context context) {
        super(context);
        touchHandler = new TouchHandler(this);
        init();
    }

    private void init() {
        startLooping();
        zoomController.setOnZoomListener(this);

        Matrix.setIdentityM(matrix1, 0);
        Matrix.rotateM(matrix1, 0, -75, 1, 0, 0);
    }

    public void onVisibilityChanged(boolean visible) {
    }

    @Override
    protected void glDraw() {
        if ((zoomStep < 0 && zoomLevel > targetZoom) ||
            (zoomStep > 0 && zoomLevel < targetZoom)) {
            zoomLevel += zoomStep;
        } else if (zoomStep != 0) {
            zoomStep = 0;
            zoomLevel = targetZoom;
            isDirty = true;
            if (!shouldRotate()) {
                stopLooping();
            }
        }
        super.glDraw();
    }

    @Override
    public void onDetachedFromWindow() {
        zoomController.setVisible(false);
        super.onDetachedFromWindow();
    }

    public void onTouchDown(float x, float y) {
        zoomController.setVisible(true);
        stopLooping();
        lastTouchX = x;
        lastTouchY = y;
    }

    public void onTouchMove(float x, float y) {
        float deltaX = x - lastTouchX;
        float deltaY = y - lastTouchY;
        if (deltaX > 1 || deltaX < -1 || deltaY > 1 || deltaY < -1) {
            setRotation(deltaX, deltaY);
            glDraw();
            lastTouchX = x;
            lastTouchY = y;
        }
    }

    public void onTouchUp(float x, float y) {
        float vx = touchHandler.velocityTracker.getXVelocity();
        float vy = touchHandler.velocityTracker.getYVelocity();
        setRotation(vx/100, vy/100);
        if (shouldRotate()) {
            startLooping();
        }
    }

    public void onTouchZoomDown(float x1, float y1, float x2, float y2) {

    }

    public void onTouchZoomMove(float x1, float y1, float x2, float y2) {

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return touchHandler != null ? touchHandler.onTouchEvent(event) : super.onTouchEvent(event);
    }

    private float[] matrix1 = new float[16], matrix2 = new float[16], matrix3 = new float[16];
    private float angleX, angleY;
    private boolean isDirty;
    private Function function;
    private static final float DISTANCE = 15f;

    void setRotation(float x, float y) {
        angleX = x;
        angleY = y;
    }

    boolean shouldRotate() {
        final float limit = .5f;
        return angleX < -limit || angleX > limit || angleY < -limit || angleY > limit;
    }

    public void setFunction(Function f) {
        function = f;
        zoomLevel = 1;
        isDirty = true;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, int width, int height) {
        gl.glDisable(GL10.GL_DITHER);
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);               
        gl.glClearColor(0, 0, 0, 1);
        gl.glShadeModel(GL10.GL_SMOOTH);
        gl.glDisable(GL10.GL_LIGHTING);
        graph = new Graph3d((GL11) gl);
        isDirty = true;
        angleX = .5f;
        angleY = 0;

        gl.glViewport(0, 0, width, height);
        initFrustum(gl, DISTANCE * zoomLevel);
        currentZoom = zoomLevel;
    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        GL11 gl = (GL11) gl10;
        if (currentZoom != zoomLevel) {
            initFrustum(gl, DISTANCE * zoomLevel);
            currentZoom = zoomLevel;
        }
        if (isDirty) {
            graph.update(gl, function, zoomLevel);
            isDirty = false;
        }

        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
        gl.glTranslatef(0, 0, -DISTANCE*zoomLevel);

        Matrix.setIdentityM(matrix2, 0);
        float ax = Math.abs(angleX);
        float ay = Math.abs(angleY);
        if (ay * 3 < ax) {
            Matrix.rotateM(matrix2, 0, angleX, 0, 1, 0);
        } else if (ax * 3 < ay) {
            Matrix.rotateM(matrix2, 0, angleY, 1, 0, 0);
        } else {
            if (ax > ay) {
                Matrix.rotateM(matrix2, 0, angleX, 0, 1, 0);
                Matrix.rotateM(matrix2, 0, angleY, 1, 0, 0);
            } else {
                Matrix.rotateM(matrix2, 0, angleY, 1, 0, 0);
                Matrix.rotateM(matrix2, 0, angleX, 0, 1, 0);
            }
        }
        Matrix.multiplyMM(matrix3, 0, matrix2, 0, matrix1, 0);
        gl.glMultMatrixf(matrix3, 0);
        System.arraycopy(matrix3, 0, matrix1, 0, 16);
        graph.draw(gl);
    }

    private void initFrustum(GL10 gl, float distance) {
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        float near = distance * (1/3f);
        float far  = distance * 3f;
        float dimen = near/5f;
        float h = dimen * height / width;
        gl.glFrustumf(-dimen, dimen, -h, h, near, far);
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
    }
}

我设置 FloatBuffers 的代码:

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[i]   = 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[i]   = 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[i] = 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[i] = (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[i] = (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);
    }
}
4

0 回答 0