Android EGL: Synchronize calls to eglSwapBuffers and eglMakeCurrent

BUG=webrtc:5702
R=glaznev@webrtc.org, perkj@webrtc.org

Review URL: https://codereview.webrtc.org/1848483002 .

Cr-Commit-Position: refs/heads/master@{#12178}
This commit is contained in:
Magnus Jedvert
2016-03-31 13:17:11 +02:00
parent 71bdda0ede
commit 3db6f9b4df
4 changed files with 41 additions and 18 deletions

View File

@ -25,6 +25,12 @@ public abstract class EglBase {
public static class Context { public static class Context {
} }
// According to the documentation, EGL can be used from multiple threads at the same time if each
// thread has its own EGLContext, but in practice it deadlocks on some devices when doing this.
// Therefore, synchronize on this global lock before calling dangerous EGL functions that might
// deadlock. See https://bugs.chromium.org/p/webrtc/issues/detail?id=5702 for more info.
public static final Object lock = new Object();
// These constants are taken from EGL14.EGL_OPENGL_ES2_BIT and EGL14.EGL_CONTEXT_CLIENT_VERSION. // These constants are taken from EGL14.EGL_OPENGL_ES2_BIT and EGL14.EGL_CONTEXT_CLIENT_VERSION.
// https://android.googlesource.com/platform/frameworks/base/+/master/opengl/java/android/opengl/EGL14.java // https://android.googlesource.com/platform/frameworks/base/+/master/opengl/java/android/opengl/EGL14.java
// This is similar to how GlSurfaceView does: // This is similar to how GlSurfaceView does:

View File

@ -220,17 +220,21 @@ final class EglBase10 extends EglBase {
if (eglSurface == EGL10.EGL_NO_SURFACE) { if (eglSurface == EGL10.EGL_NO_SURFACE) {
throw new RuntimeException("No EGLSurface - can't make current"); throw new RuntimeException("No EGLSurface - can't make current");
} }
if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { synchronized (EglBase.lock) {
throw new RuntimeException("eglMakeCurrent failed"); if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
throw new RuntimeException("eglMakeCurrent failed");
}
} }
} }
// Detach the current EGL context, so that it can be made current on another thread. // Detach the current EGL context, so that it can be made current on another thread.
@Override @Override
public void detachCurrent() { public void detachCurrent() {
if (!egl.eglMakeCurrent( synchronized (EglBase.lock) {
eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)) { if (!egl.eglMakeCurrent(
throw new RuntimeException("eglMakeCurrent failed"); eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)) {
throw new RuntimeException("eglDetachCurrent failed");
}
} }
} }
@ -240,7 +244,9 @@ final class EglBase10 extends EglBase {
if (eglSurface == EGL10.EGL_NO_SURFACE) { if (eglSurface == EGL10.EGL_NO_SURFACE) {
throw new RuntimeException("No EGLSurface - can't swap buffers"); throw new RuntimeException("No EGLSurface - can't swap buffers");
} }
egl.eglSwapBuffers(eglDisplay, eglSurface); synchronized (EglBase.lock) {
egl.eglSwapBuffers(eglDisplay, eglSurface);
}
} }
// Return an EGLDisplay, or die trying. // Return an EGLDisplay, or die trying.

View File

@ -168,17 +168,21 @@ public final class EglBase14 extends EglBase {
if (eglSurface == EGL14.EGL_NO_SURFACE) { if (eglSurface == EGL14.EGL_NO_SURFACE) {
throw new RuntimeException("No EGLSurface - can't make current"); throw new RuntimeException("No EGLSurface - can't make current");
} }
if (!EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { synchronized (EglBase.lock) {
throw new RuntimeException("eglMakeCurrent failed"); if (!EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
throw new RuntimeException("eglMakeCurrent failed");
}
} }
} }
// Detach the current EGL context, so that it can be made current on another thread. // Detach the current EGL context, so that it can be made current on another thread.
@Override @Override
public void detachCurrent() { public void detachCurrent() {
if (!EGL14.eglMakeCurrent( synchronized (EglBase.lock) {
eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) { if (!EGL14.eglMakeCurrent(
throw new RuntimeException("eglMakeCurrent failed"); eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) {
throw new RuntimeException("eglDetachCurrent failed");
}
} }
} }
@ -188,7 +192,9 @@ public final class EglBase14 extends EglBase {
if (eglSurface == EGL14.EGL_NO_SURFACE) { if (eglSurface == EGL14.EGL_NO_SURFACE) {
throw new RuntimeException("No EGLSurface - can't swap buffers"); throw new RuntimeException("No EGLSurface - can't swap buffers");
} }
EGL14.eglSwapBuffers(eglDisplay, eglSurface); synchronized (EglBase.lock) {
EGL14.eglSwapBuffers(eglDisplay, eglSurface);
}
} }
public void swapBuffers(long timeStampNs) { public void swapBuffers(long timeStampNs) {
@ -196,9 +202,11 @@ public final class EglBase14 extends EglBase {
if (eglSurface == EGL14.EGL_NO_SURFACE) { if (eglSurface == EGL14.EGL_NO_SURFACE) {
throw new RuntimeException("No EGLSurface - can't swap buffers"); throw new RuntimeException("No EGLSurface - can't swap buffers");
} }
// See https://android.googlesource.com/platform/frameworks/native/+/tools_r22.2/opengl/specs/EGL_ANDROID_presentation_time.txt synchronized (EglBase.lock) {
EGLExt.eglPresentationTimeANDROID(eglDisplay, eglSurface, timeStampNs); // See https://android.googlesource.com/platform/frameworks/native/+/tools_r22.2/opengl/specs/EGL_ANDROID_presentation_time.txt
EGL14.eglSwapBuffers(eglDisplay, eglSurface); EGLExt.eglPresentationTimeANDROID(eglDisplay, eglSurface, timeStampNs);
EGL14.eglSwapBuffers(eglDisplay, eglSurface);
}
} }
// Return an EGLDisplay, or die trying. // Return an EGLDisplay, or die trying.

View File

@ -451,8 +451,12 @@ class SurfaceTextureHelper {
isTextureInUse = true; isTextureInUse = true;
hasPendingTexture = false; hasPendingTexture = false;
eglBase.makeCurrent(); // SurfaceTexture.updateTexImage apparently can compete and deadlock with eglSwapBuffers,
surfaceTexture.updateTexImage(); // as observed on Nexus 5. Therefore, synchronize it with the EGL functions.
// See https://bugs.chromium.org/p/webrtc/issues/detail?id=5702 for more info.
synchronized (EglBase.lock) {
surfaceTexture.updateTexImage();
}
final float[] transformMatrix = new float[16]; final float[] transformMatrix = new float[16];
surfaceTexture.getTransformMatrix(transformMatrix); surfaceTexture.getTransformMatrix(transformMatrix);
@ -473,7 +477,6 @@ class SurfaceTextureHelper {
if (yuvConverter != null) if (yuvConverter != null)
yuvConverter.release(); yuvConverter.release();
} }
eglBase.makeCurrent();
GLES20.glDeleteTextures(1, new int[] {oesTextureId}, 0); GLES20.glDeleteTextures(1, new int[] {oesTextureId}, 0);
surfaceTexture.release(); surfaceTexture.release();
eglBase.release(); eglBase.release();