Skip to content

Commit d76eae0

Browse files
DualGladNRanjan-17
authored andcommitted
opengl: Don't request render in GLSurfaceView.GLThread ctr
Requesting render in GLSurfaceView.GLThread constructor will likely result in extra redrawing the surface at its initialization. This is harmful and unexpected behavior, especially when using GLSurfaceView RENDERMODE_WHEN_DIRTY: for example, the initial "background" drawing on the surface will occur several times, while it's supposed to be done only once at the startup. The following scenario occurs in the most cases (due to multi-thread nature sometimes this couldn't happen - see below): 1. At the OpenGL application startup GLSurfaceView.setRenderer(Renderer) will call GLThread constructor, that sets up GLThread.mRequestRender to true value. 2. After that GLThread.start() launches GLThread.run() that starts GLThread.guardedRun() method and enters synchronized(sGLThreadManager) block. Nevertheless, it can neither draw something nor reset mRequestRender (it's reseted after drawing only, if we're ready to draw, while we aren't). 3. System creates surface to draw on, calling GLSurfaceView.surfaceCreated() first and GLSurfaceView.surfaceChanged() second. surfaceChanged() launches GLThread.onWindowResize() that waits for entering into synchronized(sGLThreadManager) block, where mRequestRenderer will be set up to true. 4. When surface is created, the first thread in synchronized block will draw the surface (the first draw). It'll exit synchronized block, allowing the second thread to enter its block (from onWindowResize()), that will set up mRequesRender to true again and launch redrawing shortly. This problem would not occur in the following cases (workarounds): 1. Due to abnormal latencies entering guardedRun() occurs after onWindowResize() done its work - the mRequestRenderer will be set up two times in a row - no redrawing occurs. 2. A task is added using GLSurfaceView.queueEvent(Runnable). The task will be pushed into GLThread.mEventQueue, which is checked inside guardedRun() in synchronized block. Existing task makes guardedRun() to exit this block, that allows onWindowResize() enter it and set up mRequestRenderer (which is already/still true) - similar to the the 1st case above. Test: the problem can be reproduced using a simple application snippet: Using Activity.setContentView(new X(this)) for class X: class X extends GLSurfaceView implements GLSurfaceView.Renderer { X(Context c) { super(c); setEGLContextClientVersion(2); setRenderer(this); setRenderMode(RENDERMODE_WHEN_DIRTY); } } will result in the following callback calls: onSurfaceChanged()->onSurfaceCreated()->onDrawFrame()->onDrawFrame(). Workaround methods described above could mitigate the issue, but not fully fix it. Change-Id: If04aa6dfe0940d5502145cae561747c6a935eea5 Signed-off-by: dlwlrma123 <alexfinhart@gmail.com> Signed-off-by: NRanjan-17 <nalinishranjan05@gmail.com>
1 parent 606ef14 commit d76eae0

File tree

1 file changed

+2
-1
lines changed

1 file changed

+2
-1
lines changed

opengl/java/android/opengl/GLSurfaceView.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1255,7 +1255,8 @@ static class GLThread extends Thread {
12551255
super();
12561256
mWidth = 0;
12571257
mHeight = 0;
1258-
mRequestRender = true;
1258+
// Render will be requested later when it'll be really needed
1259+
mRequestRender = false;
12591260
mRenderMode = RENDERMODE_CONTINUOUSLY;
12601261
mWantRenderNotification = false;
12611262
mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;

0 commit comments

Comments
 (0)