Monday, 4 November 2019

Why has my OpenGL fragment stopped redrawing on an update tick?

I have a beginner OpenGL app I made that shows a spinning taurus loaded from an obj file. It was working just fine and I showed my friends. Yesterday I opened the app and the view doesn't update anymore. If I press the home button and then tap on the app again, it will update the view so I know the main loop is active.

I went home and plugged it into android studio to confirm the render thread is firing just fine and view.requestRender(); is also being called.

I have no idea why this stopped working.

Here's my android fragment that loads the view and renderer

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    /**
     * Inflate the layout for this fragment
     */
    View root = inflater.inflate(R.layout.glfragment, container, false);

    GLSurfaceView glview = (GLSurfaceView)root.findViewById(R.id.surface_view);

    Log.i("Method", "OpenGLFragment::onCreateView()");

    Context context = this.getActivity().getApplicationContext();

    MyRenderer renderer = new MyRenderer(context);
    glview.setEGLContextClientVersion(2);
    glview.setRenderer(renderer);
    glview.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

    loadMeshes(context); // loads obj file into variable tourus

    renderer.addToScene(tourus);

    update = new GraphicsThread(glview);
    update.start();

    return root;
}

@Override
public void onDestroyView() {
    if(update != null) {
        update.quit();
    }

    super.onDestroyView();
}

Here's the graphics thread:

public class GraphicsThread extends Thread {
    private GLSurfaceView.Renderer renderer;
    private GLSurfaceView view;

    private boolean isRunning;

    public GraphicsThread(GLSurfaceView view) {
        this.view = view;
        this.isRunning = true;
    }

    @Override
    public void run() {
        while (this.isRunning) {
            view.requestRender(); // I verified this loop is executed just fine
        }
    }

    public void quit() {
        this.isRunning = false;
    }
}

Here's MyRenderer code

public class MyRenderer implements GLSurfaceView.Renderer {
    private int program; // default shader program
    private List<Mesh> drawables;
    private Context context;
    private long lastFrameTime;
    private RenderInfo info; // MVP and Light matrices
    private Bitmap bg;

    public MyRenderer(Context context) {
        this.drawables = new ArrayList<>();
        this.context = context;
        this.lastFrameTime = 0;
        this.info = null;
    }

    @Override
    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        info = new RenderInfo(context);

        GLES20.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
        GLES20.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

        GLES20.glEnable(GLES20.GL_CULL_FACE);
    }

    public void onDrawFrame(GL10 unused){
        // Redraw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        float elapsed = getElapsedTime();

        float rot = 10.0f*elapsed;

        for(Mesh m : drawables) {
            m.rotateX(rot);
            m.draw(info, elapsed);
        }
    }

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

        if(width > 0 && height > 0) {
            final float ratio = (float) width / height;
            final float left = -ratio;
            final float right = ratio;
            info.resizePerspective(left, right, 1, -1);
        }
    }

    public void addToScene(Mesh mesh) {
        drawables.add(mesh);
    }

    private float getElapsedTime() {
        long currentTime = SystemClock.elapsedRealtime();
        float elapsed = (float)(currentTime - lastFrameTime) / 1000.0f; //convert ms to seconds
        lastFrameTime = currentTime;

        return elapsed;
    }
}

Finally here is how I draw my meshes. RenderInfo has world information like camera MVP matrix and lights and their matrices. Nothing related to the issue.

public void draw(RenderInfo info, float elapsed) {
    if(!loaded) {
        Log.d("Mesh", "failed to draw");
        return;
    };

    final int program = info.getProgram();

    int position = GLES20.glGetAttribLocation(program, "a_Position");
    int normal = GLES20.glGetAttribLocation(program, "a_Normal");
    int aColor = GLES20.glGetAttribLocation(program, "a_Color");

    //int textcoord = GLES20.glGetAttribLocation(program, "a_TexCoordinate");

    GLES20.glEnableVertexAttribArray(position);
    GLES20.glVertexAttribPointer(position, 3, GLES20.GL_FLOAT, false, 3 * 4, verticesBuffer);

    GLES20.glEnableVertexAttribArray(aColor);
    GLES20.glVertexAttribPointer(aColor, 4, GLES20.GL_FLOAT, true, 4*4, colorBuffer);

    //GLES20.glEnableVertexAttribArray(normal);
    //GLES20.glVertexAttribPointer(normal, 3, GLES20.GL_FLOAT, false, 3 * 4, normalBuffer);

    float[] modelMatrix = new float[16];

    Matrix.setIdentityM(modelMatrix, 0);
    Matrix.setRotateM(modelMatrix, 0, rotX , 1.0f, 0.0f, 0.0f);
    //Matrix.setRotateM(modelMatrix, 0, rotY , 0.0f, 1.0f, 0.0f);
    //Matrix.setRotateM(modelMatrix, 0, rotZ , 0.0f, 0.0f, 1.0f);

    float[] mvpMatrix = info.getMVP(modelMatrix);
    int MVP = GLES20.glGetUniformLocation(program, "u_MVP");
    GLES20.glUniformMatrix4fv(MVP, 1, false, mvpMatrix, 0);

    float[] mvMatrix = info.getMV();
    int MV = GLES20.glGetUniformLocation(program, "u_MV");
    GLES20.glUniformMatrix4fv(MV, 1, false, mvMatrix, 0);

    int lightM = GLES20.glGetAttribLocation(program, "u_LightPos");
    GLES20.glUniformMatrix4fv(lightM, 1, false, info.getLightMatrix(), 0);

    int lightCol = GLES20.glGetAttribLocation(program, "u_LightCol");
    GLES20.glUniform4fv(lightCol, 1, info.getLightColor(), 0);
    Log.d("boogio", "u_LightCol is: " + Integer.toString(lightCol));


    GLES20.glDrawElements(GLES20.GL_TRIANGLES, facesList.size() * 3, GLES20.GL_UNSIGNED_SHORT, facesBuffer);
    GLES20.glDisableVertexAttribArray(position);
    GLES20.glDisableVertexAttribArray(aColor);
    //GLES20.glDisableVertexAttribArray(normal);
}

TL;DR: App renders fine and used to update fine. Suddenly the app doesn't update visually (no redraws). It only redraws when the app loses and regains focus for 1 frame. No idea why.



from Why has my OpenGL fragment stopped redrawing on an update tick?

No comments:

Post a Comment