Сбой Android 5.1 glDrawArrays GL_POINTS Фатальный сигнал 7 (SIGBUS), код 2

Пару месяцев назад, после того как я обновил свой Nexus 4 до Android 5.1 (теперь 5.1.1 — оба стоковых заводских изображения от Google), одна из моих игр начала падать при рисовании частиц с помощью glDrawArrays с GL_POINTS. Я упростил, заново реализовал код на Java и воспроизвел сбой.

Сбой всегда является фатальным сигналом 7 (SIGBUS), код 2 в том, что кажется кодом драйвера OpenGL.

В этом тесте со 118 вызовами drawPoint() в цикле for все работает нормально, но происходит сбой (в следующем кадре), если я пытаюсь выполнить 119 вызовов drawPoint(). Любое количество вызовов drawPoint(), превышающее 119, также приводит к сбою.

Этот код Java нормально работает на виртуальном устройстве Nexus 4. Оригинальный код C без проблем работает на ПК, iOS и других устройствах Android.

Похоже, это может быть проблема с драйвером Nexus 4. Любые идеи?

Логкат:

--------- beginning of crash
A/libc﹕ Fatal signal 7 (SIGBUS), code 2, fault addr 0xa2876000 in tid 17998 (GLThread 14477)
I/DEBUG﹕ *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG﹕ Build fingerprint: 'google/occam/mako:5.1.1/LMY47V/1836172:user/release-keys'
I/DEBUG﹕ Revision: '11'
I/DEBUG﹕ ABI: 'arm'
I/DEBUG﹕ pid: 17822, tid: 17998, name: GLThread 14477  >>> com.joeco.pointsprites <<<
I/DEBUG﹕ signal 7 (SIGBUS), code 2 (BUS_ADRERR), fault addr 0xa2876000
I/DEBUG﹕ r0 c0004600  r1 a2876000  r2 04000000  r3 a2876000
I/DEBUG﹕ r4 b7755818  r5 00000000  r6 b776d550  r7 00000018
I/DEBUG﹕ r8 b776d550  r9 04000000  sl 00008000  fp 00000000
I/DEBUG﹕ ip fc000000  sp a4601850  lr abad3c91  pc abac38e6  cpsr 60030030
I/DEBUG﹕ backtrace:
I/DEBUG﹕ #00 pc 000ab8e6  /system/vendor/lib/egl/libGLESv2_adreno.so (oxili_write_event_write+41)
I/DEBUG﹕ #01 pc 000bbc8d  /system/vendor/lib/egl/libGLESv2_adreno.so (oxili_wa_predraw+234)
I/DEBUG﹕ #02 pc 000bbef1  /system/vendor/lib/egl/libGLESv2_adreno.so (oxili_wa_point_sprite_dummy_draw+204)
I/DEBUG﹕ #03 pc 000ba47b  /system/vendor/lib/egl/libGLESv2_adreno.so (oxili_primitive_drawarrays+318)
I/DEBUG﹕ #04 pc 000825cf  /system/vendor/lib/egl/libGLESv2_adreno.so (rb_primitive_drawarrays+298)
I/DEBUG﹕ #05 pc 0005a4f7  /system/vendor/lib/egl/libGLESv2_adreno.so (core_glDrawArraysInstancedXXX+294)
I/DEBUG﹕ #06 pc 0005a877  /system/vendor/lib/egl/libGLESv2_adreno.so (core_glDrawArrays+6)
I/DEBUG﹕ #07 pc 00049acb  /system/vendor/lib/egl/libGLESv2_adreno.so (glDrawArrays+24)
I/DEBUG﹕ #08 pc 00a5befb  /data/dalvik-cache/arm/system@[email protected]

Код для MainActivity.java:

// MainActivity.java -- pointsprite crash -- Joe Linhoff 6/15/2015
package com.joeco.pointsprites;

import android.app.Activity;
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.os.Bundle;
import android.os.SystemClock;

import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ByteBuffer;

import javax.microedition.khronos.opengles.GL10;

// starting point: http://developer.android.com/training/graphics/opengl/index.html

public class MainActivity extends Activity {

    public GLSurfaceView mGLView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mGLView = new MyGLSurfaceView(this);
        setContentView(mGLView);
    } // onCreate()

    class MyGLSurfaceView extends GLSurfaceView {
        private final MyGLRenderer mRenderer;
        public MyGLSurfaceView(Context context) {
            super(context);
            setEGLContextClientVersion(2); // create OpenGL ES 2.0 context
            mRenderer = new MyGLRenderer();
            setRenderer(mRenderer);
            setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
        } // MyGLSurfaceView()
    } // class MyGLSurvaceView

    public class PointGeo {

        FloatBuffer vertexBuffer;
        static final int floatsPerVertex = 3;
        float pointCoords[] = { 0.1f, 0.0f, 0.0f }; // xyz
        final int vertexCount = pointCoords.length / floatsPerVertex;
        final int vertexStride = floatsPerVertex * 4; // 4 bytes per float

        public PointGeo() {
            ByteBuffer bb = ByteBuffer.allocateDirect(pointCoords.length * 4); // each is 4 bytes
            bb.order(ByteOrder.nativeOrder()); // device's native byte order
            vertexBuffer = bb.asFloatBuffer(); // create floating point buffer
            vertexBuffer.put(pointCoords); // copy coordinates into buffer
            vertexBuffer.position(0); // set to first item
        } // PointGeo()

    } // class PointGeo

    public class MyGLRenderer implements GLSurfaceView.Renderer {

        private boolean mSetup = false;
        private PointGeo mPoint;
        private int mTriangleShaderProgram;
        private int mTriangleShaderLoc_uMVPMat;
        private int mTriangleShaderLoc_vPos;
        private float[] mViewMat = new float[16];
        private float[] mModelMat = new float[16];
        private float[] mProjMat = new float[16];
        private float[] mMVPMat = new float[16];

        public void onDrawFrame(GL10 unused) {

            if(!mSetup)
                lazySetup();

            GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

            // build model matrix -- rotate
            int time = (int)SystemClock.uptimeMillis() & 8191;
            float angleInDegrees = (360.0f / 8191.0f) * time;
            Matrix.setIdentityM(mModelMat, 0);
            Matrix.rotateM(mModelMat, 0, angleInDegrees, 0.0f, 0.0f, 1.0f);

            // draw -- 118:ok 119:crash on next frame
            for(int i=0;i<119;i++)
                drawPoint();

        } // onDrawFrame()

        void drawPoint()
        {
            // setup
            GLES20.glUseProgram(mTriangleShaderProgram);
            GLES20.glEnableVertexAttribArray(mTriangleShaderLoc_vPos);
            GLES20.glVertexAttribPointer(mTriangleShaderLoc_vPos, mPoint.floatsPerVertex,
                    GLES20.GL_FLOAT, false, mPoint.vertexStride, mPoint.vertexBuffer);

            // build mvp matrix
            Matrix.multiplyMM(mMVPMat,0,mViewMat,0,mModelMat,0);
            Matrix.multiplyMM(mMVPMat, 0, mProjMat, 0, mMVPMat, 0);
            GLES20.glUniformMatrix4fv(mTriangleShaderLoc_uMVPMat, 1, false, mMVPMat, 0);

            // draw
            GLES20.glDrawArrays(GLES20.GL_POINTS, 0, mPoint.vertexCount);

            // finish
            GLES20.glDisableVertexAttribArray(mTriangleShaderLoc_vPos);
            GLES20.glUseProgram(0);
        } // drawPoint()

        @Override
        public void onSurfaceCreated(GL10 gl10, javax.microedition.khronos.egl.EGLConfig eglConfig) {
        } // onSurfaceCreated()

        public void onSurfaceChanged(GL10 unused, int width, int height) {
            GLES20.glViewport(0, 0, width, height);

            // create projection matrix
            final float ratio = (float) width / height;
            final float left = -ratio;
            final float right = ratio;
            final float bottom = -1.0f;
            final float top = 1.0f;
            final float near = 1.0f;
            final float far = 10.0f;
            Matrix.frustumM(mProjMat, 0, left, right, bottom, top, near, far);
        } // onSurfaceChanged()

        public int loadShader(int type, String shaderCode) {
            int shader = GLES20.glCreateShader(type); // create shader
            GLES20.glShaderSource(shader, shaderCode); // add source
            GLES20.glCompileShader(shader); // compile
            return shader;
        } // loadShader()

        private final String vertexShaderCode =
                "attribute vec4 vPos;" +
                "uniform mat4 uMVPMat;" +
                "void main() {" +
                "  gl_Position = vPos*uMVPMat;" +
                "  gl_PointSize = 40.0f; " +
                "}";

        private final String fragmentShaderCode =
                "void main() {" +
                "  gl_FragColor = vec4(0.5f,0.7f,0.5f,1.f);" +
                "}";

        void lazySetup()
        {
            mSetup=true;
            mPoint = new PointGeo();
            int vshader = loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
            int fshader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);
            mTriangleShaderProgram = GLES20.glCreateProgram();
            GLES20.glAttachShader(mTriangleShaderProgram, vshader);
            GLES20.glAttachShader(mTriangleShaderProgram, fshader);
            GLES20.glLinkProgram(mTriangleShaderProgram);
            int err = GLES20.glGetError();

            mTriangleShaderLoc_uMVPMat = GLES20.glGetUniformLocation(mTriangleShaderProgram, "uMVPMat");
            mTriangleShaderLoc_vPos = GLES20.glGetAttribLocation(mTriangleShaderProgram, "vPos");

            setViewMat();
            Matrix.setIdentityM(mModelMat,0);

        } // lazySetup()

        void setViewMat()
        {
            final float eyeX = 0.0f;
            final float eyeY = 0.0f;
            final float eyeZ = 5.0f;

            final float lookX = 0.0f;
            final float lookY = 0.0f;
            final float lookZ = -1.0f;

            final float upX = 0.0f;
            final float upY = 1.0f;
            final float upZ = 0.0f;
            Matrix.setLookAtM(mViewMat, 0, eyeX, eyeY, eyeZ,
                    lookX, lookY, lookZ, upX, upY, upZ);
        } // setViewMat()

    } // class MyGLRenderer

} // class MainActivity

person Joe    schedule 15.06.2015    source источник
comment
Возможно, в памяти есть какие-то дефектные биты. Как вы думаете, проблема в оборудовании?   -  person    schedule 15.06.2015
comment
Похоже, что это, скорее всего, ошибка драйвера. Судя по трассировке стека, проблема не в самих данных вершин, а в том, что происходит сбой при попытке настроить какое-то событие. В частности, если вы можете воспроизвести это на Java, где вы не можете легко топать по памяти, я не понимаю, как это может быть вашей ошибкой.   -  person Reto Koradi    schedule 15.06.2015
comment
Я не думаю, что это чисто аппаратная проблема, поскольку один и тот же код работал на том же оборудовании (мой Nexus 4) до обновления до 5.1. Это также полностью повторяемо. Причем, работает 118 петель, а не 119.   -  person Joe    schedule 16.06.2015
comment
Я разместил это как вопрос на сайте отслеживания ошибок Android.code. google.com/p/android/issues/detail?id=177219   -  person Joe    schedule 25.06.2015


Ответы (1)


у вас есть attribute vec4 vPos; в вашем VS, что составляет 4 числа с плавающей запятой, но вы загружаете только 3 числа с плавающей запятой на вершину... измените свой вершинный шейдер следующим образом:

attribute vec4 vPos; --> attribute vec3 vPos;

Также

gl_Position = vPos * uMVPMat; --> gl_Position = vec4(vPos, 1.0) * uMVPMat;

person agnu17    schedule 15.06.2015
comment
Вполне допустимо иметь меньше компонентов в атрибутах вершины, чем в переменной атрибута в шейдере. Поведение хорошо определено. В этом случае компоненту w автоматически присваивается значение 1. - person Reto Koradi; 15.06.2015
comment
Тот же результат с этим изменением — код по-прежнему дает сбой. - person Joe; 16.06.2015