Allow EglBase instances to share EGLConnection.

This enables clients of EglBase to keep using it but
share underlying EGLContext with other clients.
go/meet-android-eglcontext-reduction

Bug: b/225229697
Change-Id: I42719f25be7db169c39878b57a5f1487e3c1894e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/301941
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Commit-Queue: Linus Nilsson <lnilsson@webrtc.org>
Reviewed-by: Xavier Lepaul‎ <xalep@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39961}
This commit is contained in:
Linus Nilsson 2023-04-25 17:53:38 +02:00 committed by WebRTC LUCI CQ
parent 9ecc76e15b
commit df4bc33e11
5 changed files with 263 additions and 67 deletions

View file

@ -34,6 +34,38 @@ public interface EglBase {
long getNativeEglContext();
}
/**
* Wraps the objects needed to interact with EGL that are independent of a particular EGLSurface.
* In practice this means EGLContext, EGLDisplay and EGLConfig objects. Separating them out in a
* standalone object allows for multiple EglBase instances to use the same underlying EGLContext,
* while still operating on their own EGLSurface.
*/
public interface EglConnection extends RefCounted {
/** Analogous to corresponding EglBase#create below. */
public static EglConnection create(@Nullable Context sharedContext, int[] configAttributes) {
if (sharedContext == null) {
return EglConnection.createEgl14(configAttributes);
} else if (sharedContext instanceof EglBase14.Context) {
return new EglBase14Impl.EglConnection(
((EglBase14.Context) sharedContext).getRawContext(), configAttributes);
} else if (sharedContext instanceof EglBase10.Context) {
return new EglBase10Impl.EglConnection(
((EglBase10.Context) sharedContext).getRawContext(), configAttributes);
}
throw new IllegalArgumentException("Unrecognized Context");
}
/** Analogous to corresponding EglBase#createEgl10 below. */
public static EglConnection createEgl10(int[] configAttributes) {
return new EglBase10Impl.EglConnection(/* sharedContext= */ null, configAttributes);
}
/** Analogous to corresponding EglBase#createEgl14 below. */
public static EglConnection createEgl14(int[] configAttributes) {
return new EglBase14Impl.EglConnection(/* sharedContext= */ null, configAttributes);
}
}
// 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
@ -145,6 +177,24 @@ public interface EglBase {
return 1;
}
/**
* Creates a new EglBase with a shared EglConnection. EglBase instances sharing the same
* EglConnection should be used on the same thread to avoid the underlying EGLContext being made
* current on multiple threads. It is up to the client of EglBase to ensure that instances with a
* shared EglConnection are current on that thread before each use since other EglBase instances
* may have used the same EGLContext since the last interaction.
*/
public static EglBase create(EglConnection eglConnection) {
if (eglConnection == null) {
return create();
} else if (eglConnection instanceof EglBase14Impl.EglConnection) {
return new EglBase14Impl((EglBase14Impl.EglConnection) eglConnection);
} else if (eglConnection instanceof EglBase10Impl.EglConnection) {
return new EglBase10Impl((EglBase10Impl.EglConnection) eglConnection);
}
throw new IllegalArgumentException("Unrecognized EglConnection");
}
/**
* Create a new context with the specified config attributes, sharing data with `sharedContext`.
* If `sharedContext` is null, a root EGL 1.4 context is created.

View file

@ -10,11 +10,24 @@
package org.webrtc;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
/** EGL 1.0 implementation of EglBase. */
public interface EglBase10 extends EglBase {
interface Context extends EglBase.Context {
EGLContext getRawContext();
}
interface EglConnection extends EglBase.EglConnection {
EGL10 getEgl();
EGLContext getContext();
EGLDisplay getDisplay();
EGLConfig getConfig();
}
}

View file

@ -10,11 +10,21 @@
package org.webrtc;
import android.opengl.EGLConfig;
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
/** EGL 1.4 implementation of EglBase. */
public interface EglBase14 extends EglBase {
interface Context extends EglBase.Context {
EGLContext getRawContext();
}
interface EglConnection extends EglBase.EglConnection {
EGLContext getContext();
EGLDisplay getDisplay();
EGLConfig getConfig();
}
}

View file

@ -13,7 +13,6 @@ package org.webrtc;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.opengl.EGL14;
import android.opengl.GLException;
import android.view.Surface;
import android.view.SurfaceHolder;
@ -33,11 +32,10 @@ class EglBase10Impl implements EglBase10 {
// This constant is taken from EGL14.EGL_CONTEXT_CLIENT_VERSION.
private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
private final EGL10 egl;
private EGLContext eglContext;
@Nullable private EGLConfig eglConfig;
private EGLDisplay eglDisplay;
private static final EglConnection EGL_NO_CONNECTION = new EglConnection();
private EGLSurface eglSurface = EGL10.EGL_NO_SURFACE;
private EglConnection eglConnection;
// EGL wrapper for an actual EGLContext.
private static class Context implements EglBase10.Context {
@ -90,14 +88,80 @@ class EglBase10Impl implements EglBase10 {
}
}
public static class EglConnection implements EglBase10.EglConnection {
private final EGL10 egl;
private final EGLContext eglContext;
private final EGLDisplay eglDisplay;
private final EGLConfig eglConfig;
private final RefCountDelegate refCountDelegate;
public EglConnection(EGLContext sharedContext, int[] configAttributes) {
egl = (EGL10) EGLContext.getEGL();
eglDisplay = getEglDisplay(egl);
eglConfig = getEglConfig(egl, eglDisplay, configAttributes);
final int openGlesVersion = EglBase.getOpenGlesVersionFromConfig(configAttributes);
Logging.d(TAG, "Using OpenGL ES version " + openGlesVersion);
eglContext = createEglContext(egl, sharedContext, eglDisplay, eglConfig, openGlesVersion);
// Ref count delegate with release callback.
refCountDelegate = new RefCountDelegate(() -> {
synchronized (EglBase.lock) {
egl.eglMakeCurrent(
eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
}
egl.eglDestroyContext(eglDisplay, eglContext);
egl.eglTerminate(eglDisplay);
});
}
// Returns a "null" EglConnection. Useful to represent a released instance with default values.
private EglConnection() {
egl = (EGL10) EGLContext.getEGL();
eglContext = EGL10.EGL_NO_CONTEXT;
eglDisplay = EGL10.EGL_NO_DISPLAY;
eglConfig = null;
refCountDelegate = new RefCountDelegate(() -> {});
}
@Override
public void retain() {
refCountDelegate.retain();
}
@Override
public void release() {
refCountDelegate.release();
}
@Override
public EGL10 getEgl() {
return egl;
}
@Override
public EGLContext getContext() {
return eglContext;
}
@Override
public EGLDisplay getDisplay() {
return eglDisplay;
}
@Override
public EGLConfig getConfig() {
return eglConfig;
}
}
// Create a new context with the specified config type, sharing data with sharedContext.
public EglBase10Impl(EGLContext sharedContext, int[] configAttributes) {
this.egl = (EGL10) EGLContext.getEGL();
eglDisplay = getEglDisplay();
eglConfig = getEglConfig(egl, eglDisplay, configAttributes);
final int openGlesVersion = EglBase.getOpenGlesVersionFromConfig(configAttributes);
Logging.d(TAG, "Using OpenGL ES version " + openGlesVersion);
eglContext = createEglContext(sharedContext, eglDisplay, eglConfig, openGlesVersion);
this.eglConnection = new EglConnection(sharedContext, configAttributes);
}
public EglBase10Impl(EglConnection eglConnection) {
this.eglConnection = eglConnection;
this.eglConnection.retain();
}
@Override
@ -186,8 +250,11 @@ class EglBase10Impl implements EglBase10 {
if (eglSurface != EGL10.EGL_NO_SURFACE) {
throw new RuntimeException("Already has an EGLSurface");
}
EGL10 egl = eglConnection.getEgl();
int[] surfaceAttribs = {EGL10.EGL_NONE};
eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, nativeWindow, surfaceAttribs);
eglSurface = egl.eglCreateWindowSurface(
eglConnection.getDisplay(), eglConnection.getConfig(), nativeWindow, surfaceAttribs);
if (eglSurface == EGL10.EGL_NO_SURFACE) {
throw new GLException(egl.eglGetError(),
"Failed to create window surface: 0x" + Integer.toHexString(egl.eglGetError()));
@ -206,8 +273,10 @@ class EglBase10Impl implements EglBase10 {
if (eglSurface != EGL10.EGL_NO_SURFACE) {
throw new RuntimeException("Already has an EGLSurface");
}
EGL10 egl = eglConnection.getEgl();
int[] surfaceAttribs = {EGL10.EGL_WIDTH, width, EGL10.EGL_HEIGHT, height, EGL10.EGL_NONE};
eglSurface = egl.eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttribs);
eglSurface = egl.eglCreatePbufferSurface(
eglConnection.getDisplay(), eglConnection.getConfig(), surfaceAttribs);
if (eglSurface == EGL10.EGL_NO_SURFACE) {
throw new GLException(egl.eglGetError(),
"Failed to create pixel buffer surface with size " + width + "x" + height + ": 0x"
@ -217,7 +286,8 @@ class EglBase10Impl implements EglBase10 {
@Override
public org.webrtc.EglBase.Context getEglBaseContext() {
return new Context(egl, eglContext, eglConfig);
return new Context(
eglConnection.getEgl(), eglConnection.getContext(), eglConnection.getConfig());
}
@Override
@ -228,28 +298,29 @@ class EglBase10Impl implements EglBase10 {
@Override
public int surfaceWidth() {
final int widthArray[] = new int[1];
egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_WIDTH, widthArray);
eglConnection.getEgl().eglQuerySurface(
eglConnection.getDisplay(), eglSurface, EGL10.EGL_WIDTH, widthArray);
return widthArray[0];
}
@Override
public int surfaceHeight() {
final int heightArray[] = new int[1];
egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_HEIGHT, heightArray);
eglConnection.getEgl().eglQuerySurface(
eglConnection.getDisplay(), eglSurface, EGL10.EGL_HEIGHT, heightArray);
return heightArray[0];
}
@Override
public void releaseSurface() {
if (eglSurface != EGL10.EGL_NO_SURFACE) {
egl.eglDestroySurface(eglDisplay, eglSurface);
eglConnection.getEgl().eglDestroySurface(eglConnection.getDisplay(), eglSurface);
eglSurface = EGL10.EGL_NO_SURFACE;
}
}
private void checkIsNotReleased() {
if (eglDisplay == EGL10.EGL_NO_DISPLAY || eglContext == EGL10.EGL_NO_CONTEXT
|| eglConfig == null) {
if (eglConnection == EGL_NO_CONNECTION) {
throw new RuntimeException("This object has been released");
}
}
@ -258,12 +329,8 @@ class EglBase10Impl implements EglBase10 {
public void release() {
checkIsNotReleased();
releaseSurface();
detachCurrent();
egl.eglDestroyContext(eglDisplay, eglContext);
egl.eglTerminate(eglDisplay);
eglContext = EGL10.EGL_NO_CONTEXT;
eglDisplay = EGL10.EGL_NO_DISPLAY;
eglConfig = null;
eglConnection.release();
eglConnection = EGL_NO_CONNECTION;
}
@Override
@ -273,7 +340,9 @@ class EglBase10Impl implements EglBase10 {
throw new RuntimeException("No EGLSurface - can't make current");
}
synchronized (EglBase.lock) {
if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
EGL10 egl = eglConnection.getEgl();
if (!egl.eglMakeCurrent(
eglConnection.getDisplay(), eglSurface, eglSurface, eglConnection.getContext())) {
throw new GLException(egl.eglGetError(),
"eglMakeCurrent failed: 0x" + Integer.toHexString(egl.eglGetError()));
}
@ -284,8 +353,9 @@ class EglBase10Impl implements EglBase10 {
@Override
public void detachCurrent() {
synchronized (EglBase.lock) {
if (!egl.eglMakeCurrent(
eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)) {
EGL10 egl = eglConnection.getEgl();
if (!egl.eglMakeCurrent(eglConnection.getDisplay(), EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)) {
throw new GLException(egl.eglGetError(),
"eglDetachCurrent failed: 0x" + Integer.toHexString(egl.eglGetError()));
}
@ -299,7 +369,7 @@ class EglBase10Impl implements EglBase10 {
throw new RuntimeException("No EGLSurface - can't swap buffers");
}
synchronized (EglBase.lock) {
egl.eglSwapBuffers(eglDisplay, eglSurface);
eglConnection.getEgl().eglSwapBuffers(eglConnection.getDisplay(), eglSurface);
}
}
@ -310,7 +380,7 @@ class EglBase10Impl implements EglBase10 {
}
// Return an EGLDisplay, or die trying.
private EGLDisplay getEglDisplay() {
private static EGLDisplay getEglDisplay(EGL10 egl) {
EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (eglDisplay == EGL10.EGL_NO_DISPLAY) {
throw new GLException(egl.eglGetError(),
@ -343,8 +413,8 @@ class EglBase10Impl implements EglBase10 {
}
// Return an EGLConfig, or die trying.
private EGLContext createEglContext(@Nullable EGLContext sharedContext, EGLDisplay eglDisplay,
EGLConfig eglConfig, int openGlesVersion) {
private static EGLContext createEglContext(EGL10 egl, @Nullable EGLContext sharedContext,
EGLDisplay eglDisplay, EGLConfig eglConfig, int openGlesVersion) {
if (sharedContext != null && sharedContext == EGL10.EGL_NO_CONTEXT) {
throw new RuntimeException("Invalid sharedContext");
}

View file

@ -18,10 +18,8 @@ import android.opengl.EGLDisplay;
import android.opengl.EGLExt;
import android.opengl.EGLSurface;
import android.opengl.GLException;
import android.os.Build;
import android.view.Surface;
import androidx.annotation.Nullable;
import org.webrtc.EglBase;
/**
* Holds EGL state and utility methods for handling an EGL14 EGLContext, an EGLDisplay,
@ -30,10 +28,10 @@ import org.webrtc.EglBase;
@SuppressWarnings("ReferenceEquality") // We want to compare to EGL14 constants.
class EglBase14Impl implements EglBase14 {
private static final String TAG = "EglBase14Impl";
private EGLContext eglContext;
@Nullable private EGLConfig eglConfig;
private EGLDisplay eglDisplay;
private static final EglConnection EGL_NO_CONNECTION = new EglConnection();
private EGLSurface eglSurface = EGL14.EGL_NO_SURFACE;
private EglConnection eglConnection;
public static class Context implements EglBase14.Context {
private final EGLContext egl14Context;
@ -53,14 +51,74 @@ class EglBase14Impl implements EglBase14 {
}
}
public static class EglConnection implements EglBase14.EglConnection {
private final EGLContext eglContext;
private final EGLDisplay eglDisplay;
private final EGLConfig eglConfig;
private final RefCountDelegate refCountDelegate;
public EglConnection(EGLContext sharedContext, int[] configAttributes) {
eglDisplay = getEglDisplay();
eglConfig = getEglConfig(eglDisplay, configAttributes);
final int openGlesVersion = EglBase.getOpenGlesVersionFromConfig(configAttributes);
Logging.d(TAG, "Using OpenGL ES version " + openGlesVersion);
eglContext = createEglContext(sharedContext, eglDisplay, eglConfig, openGlesVersion);
// Ref count delegate with release callback.
refCountDelegate = new RefCountDelegate(() -> {
synchronized (EglBase.lock) {
EGL14.eglMakeCurrent(
eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
EGL14.eglDestroyContext(eglDisplay, eglContext);
}
EGL14.eglReleaseThread();
EGL14.eglTerminate(eglDisplay);
});
}
// Returns a "null" EglConnection. Useful to represent a released instance with default values.
private EglConnection() {
eglContext = EGL14.EGL_NO_CONTEXT;
eglDisplay = EGL14.EGL_NO_DISPLAY;
eglConfig = null;
refCountDelegate = new RefCountDelegate(() -> {});
}
@Override
public void retain() {
refCountDelegate.retain();
}
@Override
public void release() {
refCountDelegate.release();
}
@Override
public EGLContext getContext() {
return eglContext;
}
@Override
public EGLDisplay getDisplay() {
return eglDisplay;
}
@Override
public EGLConfig getConfig() {
return eglConfig;
}
}
// Create a new context with the specified config type, sharing data with sharedContext.
// `sharedContext` may be null.
public EglBase14Impl(EGLContext sharedContext, int[] configAttributes) {
eglDisplay = getEglDisplay();
eglConfig = getEglConfig(eglDisplay, configAttributes);
final int openGlesVersion = EglBase.getOpenGlesVersionFromConfig(configAttributes);
Logging.d(TAG, "Using OpenGL ES version " + openGlesVersion);
eglContext = createEglContext(sharedContext, eglDisplay, eglConfig, openGlesVersion);
this.eglConnection = new EglConnection(sharedContext, configAttributes);
}
// Create a new EglBase using an existing, possibly externally managed, EglConnection.
public EglBase14Impl(EglConnection eglConnection) {
this.eglConnection = eglConnection;
this.eglConnection.retain();
}
// Create EGLSurface from the Android Surface.
@ -85,7 +143,8 @@ class EglBase14Impl implements EglBase14 {
throw new RuntimeException("Already has an EGLSurface");
}
int[] surfaceAttribs = {EGL14.EGL_NONE};
eglSurface = EGL14.eglCreateWindowSurface(eglDisplay, eglConfig, surface, surfaceAttribs, 0);
eglSurface = EGL14.eglCreateWindowSurface(
eglConnection.getDisplay(), eglConnection.getConfig(), surface, surfaceAttribs, 0);
if (eglSurface == EGL14.EGL_NO_SURFACE) {
throw new GLException(EGL14.eglGetError(),
"Failed to create window surface: 0x" + Integer.toHexString(EGL14.eglGetError()));
@ -104,7 +163,8 @@ class EglBase14Impl implements EglBase14 {
throw new RuntimeException("Already has an EGLSurface");
}
int[] surfaceAttribs = {EGL14.EGL_WIDTH, width, EGL14.EGL_HEIGHT, height, EGL14.EGL_NONE};
eglSurface = EGL14.eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttribs, 0);
eglSurface = EGL14.eglCreatePbufferSurface(
eglConnection.getDisplay(), eglConnection.getConfig(), surfaceAttribs, 0);
if (eglSurface == EGL14.EGL_NO_SURFACE) {
throw new GLException(EGL14.eglGetError(),
"Failed to create pixel buffer surface with size " + width + "x" + height + ": 0x"
@ -114,7 +174,7 @@ class EglBase14Impl implements EglBase14 {
@Override
public Context getEglBaseContext() {
return new Context(eglContext);
return new Context(eglConnection.getContext());
}
@Override
@ -124,29 +184,28 @@ class EglBase14Impl implements EglBase14 {
@Override
public int surfaceWidth() {
final int widthArray[] = new int[1];
EGL14.eglQuerySurface(eglDisplay, eglSurface, EGL14.EGL_WIDTH, widthArray, 0);
final int[] widthArray = new int[1];
EGL14.eglQuerySurface(eglConnection.getDisplay(), eglSurface, EGL14.EGL_WIDTH, widthArray, 0);
return widthArray[0];
}
@Override
public int surfaceHeight() {
final int heightArray[] = new int[1];
EGL14.eglQuerySurface(eglDisplay, eglSurface, EGL14.EGL_HEIGHT, heightArray, 0);
final int[] heightArray = new int[1];
EGL14.eglQuerySurface(eglConnection.getDisplay(), eglSurface, EGL14.EGL_HEIGHT, heightArray, 0);
return heightArray[0];
}
@Override
public void releaseSurface() {
if (eglSurface != EGL14.EGL_NO_SURFACE) {
EGL14.eglDestroySurface(eglDisplay, eglSurface);
EGL14.eglDestroySurface(eglConnection.getDisplay(), eglSurface);
eglSurface = EGL14.EGL_NO_SURFACE;
}
}
private void checkIsNotReleased() {
if (eglDisplay == EGL14.EGL_NO_DISPLAY || eglContext == EGL14.EGL_NO_CONTEXT
|| eglConfig == null) {
if (eglConnection == EGL_NO_CONNECTION) {
throw new RuntimeException("This object has been released");
}
}
@ -155,15 +214,8 @@ class EglBase14Impl implements EglBase14 {
public void release() {
checkIsNotReleased();
releaseSurface();
detachCurrent();
synchronized (EglBase.lock) {
EGL14.eglDestroyContext(eglDisplay, eglContext);
}
EGL14.eglReleaseThread();
EGL14.eglTerminate(eglDisplay);
eglContext = EGL14.EGL_NO_CONTEXT;
eglDisplay = EGL14.EGL_NO_DISPLAY;
eglConfig = null;
eglConnection.release();
eglConnection = EGL_NO_CONNECTION;
}
@Override
@ -173,7 +225,8 @@ class EglBase14Impl implements EglBase14 {
throw new RuntimeException("No EGLSurface - can't make current");
}
synchronized (EglBase.lock) {
if (!EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
if (!EGL14.eglMakeCurrent(
eglConnection.getDisplay(), eglSurface, eglSurface, eglConnection.getContext())) {
throw new GLException(EGL14.eglGetError(),
"eglMakeCurrent failed: 0x" + Integer.toHexString(EGL14.eglGetError()));
}
@ -184,8 +237,8 @@ class EglBase14Impl implements EglBase14 {
@Override
public void detachCurrent() {
synchronized (EglBase.lock) {
if (!EGL14.eglMakeCurrent(
eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) {
if (!EGL14.eglMakeCurrent(eglConnection.getDisplay(), EGL14.EGL_NO_SURFACE,
EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) {
throw new GLException(EGL14.eglGetError(),
"eglDetachCurrent failed: 0x" + Integer.toHexString(EGL14.eglGetError()));
}
@ -199,7 +252,7 @@ class EglBase14Impl implements EglBase14 {
throw new RuntimeException("No EGLSurface - can't swap buffers");
}
synchronized (EglBase.lock) {
EGL14.eglSwapBuffers(eglDisplay, eglSurface);
EGL14.eglSwapBuffers(eglConnection.getDisplay(), eglSurface);
}
}
@ -212,8 +265,8 @@ class EglBase14Impl implements EglBase14 {
synchronized (EglBase.lock) {
// See
// https://android.googlesource.com/platform/frameworks/native/+/tools_r22.2/opengl/specs/EGL_ANDROID_presentation_time.txt
EGLExt.eglPresentationTimeANDROID(eglDisplay, eglSurface, timeStampNs);
EGL14.eglSwapBuffers(eglDisplay, eglSurface);
EGLExt.eglPresentationTimeANDROID(eglConnection.getDisplay(), eglSurface, timeStampNs);
EGL14.eglSwapBuffers(eglConnection.getDisplay(), eglSurface);
}
}