1 /*
2  *  Copyright 2015 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 package org.webrtc;
12 
13 import android.graphics.SurfaceTexture;
14 import android.support.annotation.Nullable;
15 import android.view.Surface;
16 import java.util.ArrayList;
17 import javax.microedition.khronos.egl.EGL10;
18 
19 /**
20  * Holds EGL state and utility methods for handling an egl 1.0 EGLContext, an EGLDisplay,
21  * and an EGLSurface.
22  */
23 public interface EglBase {
24   // EGL wrapper for an actual EGLContext.
25   public interface Context {
26     public final static long NO_CONTEXT = 0;
27 
28     /**
29      * Returns an EGL context that can be used by native code. Returns NO_CONTEXT if the method is
30      * unsupported.
31      *
32      * @note This is currently only supported for EGL 1.4 and not for EGL 1.0.
33      */
getNativeEglContext()34     long getNativeEglContext();
35   }
36 
37   // According to the documentation, EGL can be used from multiple threads at the same time if each
38   // thread has its own EGLContext, but in practice it deadlocks on some devices when doing this.
39   // Therefore, synchronize on this global lock before calling dangerous EGL functions that might
40   // deadlock. See https://bugs.chromium.org/p/webrtc/issues/detail?id=5702 for more info.
41   public static final Object lock = new Object();
42 
43   // These constants are taken from EGL14.EGL_OPENGL_ES2_BIT and EGL14.EGL_CONTEXT_CLIENT_VERSION.
44   // https://android.googlesource.com/platform/frameworks/base/+/master/opengl/java/android/opengl/EGL14.java
45   // This is similar to how GlSurfaceView does:
46   // http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/opengl/GLSurfaceView.java#760
47   public static final int EGL_OPENGL_ES2_BIT = 4;
48   public static final int EGL_OPENGL_ES3_BIT = 0x40;
49   // Android-specific extension.
50   public static final int EGL_RECORDABLE_ANDROID = 0x3142;
51 
configBuilder()52   public static ConfigBuilder configBuilder() {
53     return new ConfigBuilder();
54   }
55 
56   public static class ConfigBuilder {
57     private int openGlesVersion = 2;
58     private boolean hasAlphaChannel;
59     private boolean supportsPixelBuffer;
60     private boolean isRecordable;
61 
setOpenGlesVersion(int version)62     public ConfigBuilder setOpenGlesVersion(int version) {
63       if (version < 1 || version > 3) {
64         throw new IllegalArgumentException("OpenGL ES version " + version + " not supported");
65       }
66       this.openGlesVersion = version;
67       return this;
68     }
69 
setHasAlphaChannel(boolean hasAlphaChannel)70     public ConfigBuilder setHasAlphaChannel(boolean hasAlphaChannel) {
71       this.hasAlphaChannel = hasAlphaChannel;
72       return this;
73     }
74 
setSupportsPixelBuffer(boolean supportsPixelBuffer)75     public ConfigBuilder setSupportsPixelBuffer(boolean supportsPixelBuffer) {
76       this.supportsPixelBuffer = supportsPixelBuffer;
77       return this;
78     }
79 
setIsRecordable(boolean isRecordable)80     public ConfigBuilder setIsRecordable(boolean isRecordable) {
81       this.isRecordable = isRecordable;
82       return this;
83     }
84 
createConfigAttributes()85     public int[] createConfigAttributes() {
86       ArrayList<Integer> list = new ArrayList<>();
87       list.add(EGL10.EGL_RED_SIZE);
88       list.add(8);
89       list.add(EGL10.EGL_GREEN_SIZE);
90       list.add(8);
91       list.add(EGL10.EGL_BLUE_SIZE);
92       list.add(8);
93       if (hasAlphaChannel) {
94         list.add(EGL10.EGL_ALPHA_SIZE);
95         list.add(8);
96       }
97       if (openGlesVersion == 2 || openGlesVersion == 3) {
98         list.add(EGL10.EGL_RENDERABLE_TYPE);
99         list.add(openGlesVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT);
100       }
101       if (supportsPixelBuffer) {
102         list.add(EGL10.EGL_SURFACE_TYPE);
103         list.add(EGL10.EGL_PBUFFER_BIT);
104       }
105       if (isRecordable) {
106         list.add(EGL_RECORDABLE_ANDROID);
107         list.add(1);
108       }
109       list.add(EGL10.EGL_NONE);
110 
111       final int[] res = new int[list.size()];
112       for (int i = 0; i < list.size(); ++i) {
113         res[i] = list.get(i);
114       }
115       return res;
116     }
117   }
118 
119   public static final int[] CONFIG_PLAIN = configBuilder().createConfigAttributes();
120   public static final int[] CONFIG_RGBA =
121       configBuilder().setHasAlphaChannel(true).createConfigAttributes();
122   public static final int[] CONFIG_PIXEL_BUFFER =
123       configBuilder().setSupportsPixelBuffer(true).createConfigAttributes();
124   public static final int[] CONFIG_PIXEL_RGBA_BUFFER = configBuilder()
125                                                            .setHasAlphaChannel(true)
126                                                            .setSupportsPixelBuffer(true)
127                                                            .createConfigAttributes();
128   public static final int[] CONFIG_RECORDABLE =
129       configBuilder().setIsRecordable(true).createConfigAttributes();
130 
getOpenGlesVersionFromConfig(int[] configAttributes)131   static int getOpenGlesVersionFromConfig(int[] configAttributes) {
132     for (int i = 0; i < configAttributes.length - 1; ++i) {
133       if (configAttributes[i] == EGL10.EGL_RENDERABLE_TYPE) {
134         switch (configAttributes[i + 1]) {
135           case EGL_OPENGL_ES2_BIT:
136             return 2;
137           case EGL_OPENGL_ES3_BIT:
138             return 3;
139           default:
140             return 1;
141         }
142       }
143     }
144     // Default to V1 if no renderable type is specified.
145     return 1;
146   }
147 
148   /**
149    * Create a new context with the specified config attributes, sharing data with |sharedContext|.
150    * If |sharedContext| is null, a root context is created. This function will try to create an EGL
151    * 1.4 context if possible, and an EGL 1.0 context otherwise.
152    */
create(@ullable Context sharedContext, int[] configAttributes)153   public static EglBase create(@Nullable Context sharedContext, int[] configAttributes) {
154     if (sharedContext == null) {
155       return EglBase14Impl.isEGL14Supported() ? createEgl14(configAttributes)
156                                               : createEgl10(configAttributes);
157     } else if (sharedContext instanceof EglBase14.Context) {
158       return createEgl14((EglBase14.Context) sharedContext, configAttributes);
159     } else if (sharedContext instanceof EglBase10.Context) {
160       return createEgl10((EglBase10.Context) sharedContext, configAttributes);
161     }
162     throw new IllegalArgumentException("Unrecognized Context");
163   }
164 
165   /**
166    * Helper function for creating a plain root context. This function will try to create an EGL 1.4
167    * context if possible, and an EGL 1.0 context otherwise.
168    */
create()169   public static EglBase create() {
170     return create(null /* shaderContext */, CONFIG_PLAIN);
171   }
172 
173   /**
174    * Helper function for creating a plain context, sharing data with |sharedContext|. This function
175    * will try to create an EGL 1.4 context if possible, and an EGL 1.0 context otherwise.
176    */
create(Context sharedContext)177   public static EglBase create(Context sharedContext) {
178     return create(sharedContext, CONFIG_PLAIN);
179   }
180 
181   /** Explicitly create a root EGl 1.0 context with the specified config attributes. */
createEgl10(int[] configAttributes)182   public static EglBase10 createEgl10(int[] configAttributes) {
183     return new EglBase10Impl(/* sharedContext= */ null, configAttributes);
184   }
185 
186   /**
187    * Explicitly create a root EGl 1.0 context with the specified config attributes and shared
188    * context.
189    */
createEgl10(EglBase10.Context sharedContext, int[] configAttributes)190   public static EglBase10 createEgl10(EglBase10.Context sharedContext, int[] configAttributes) {
191     return new EglBase10Impl(
192         sharedContext == null ? null : sharedContext.getRawContext(), configAttributes);
193   }
194 
195   /**
196    * Explicitly create a root EGl 1.0 context with the specified config attributes
197    * and shared context.
198    */
createEgl10( javax.microedition.khronos.egl.EGLContext sharedContext, int[] configAttributes)199   public static EglBase10 createEgl10(
200       javax.microedition.khronos.egl.EGLContext sharedContext, int[] configAttributes) {
201     return new EglBase10Impl(sharedContext, configAttributes);
202   }
203 
204   /** Explicitly create a root EGl 1.4 context with the specified config attributes. */
createEgl14(int[] configAttributes)205   public static EglBase14 createEgl14(int[] configAttributes) {
206     return new EglBase14Impl(/* sharedContext= */ null, configAttributes);
207   }
208 
209   /**
210    * Explicitly create a root EGl 1.4 context with the specified config attributes and shared
211    * context.
212    */
createEgl14(EglBase14.Context sharedContext, int[] configAttributes)213   public static EglBase14 createEgl14(EglBase14.Context sharedContext, int[] configAttributes) {
214     return new EglBase14Impl(
215         sharedContext == null ? null : sharedContext.getRawContext(), configAttributes);
216   }
217 
218   /**
219    * Explicitly create a root EGl 1.4 context with the specified config attributes
220    * and shared context.
221    */
createEgl14( android.opengl.EGLContext sharedContext, int[] configAttributes)222   public static EglBase14 createEgl14(
223       android.opengl.EGLContext sharedContext, int[] configAttributes) {
224     return new EglBase14Impl(sharedContext, configAttributes);
225   }
226 
createSurface(Surface surface)227   void createSurface(Surface surface);
228 
229   // Create EGLSurface from the Android SurfaceTexture.
createSurface(SurfaceTexture surfaceTexture)230   void createSurface(SurfaceTexture surfaceTexture);
231 
232   // Create dummy 1x1 pixel buffer surface so the context can be made current.
createDummyPbufferSurface()233   void createDummyPbufferSurface();
234 
createPbufferSurface(int width, int height)235   void createPbufferSurface(int width, int height);
236 
getEglBaseContext()237   Context getEglBaseContext();
238 
hasSurface()239   boolean hasSurface();
240 
surfaceWidth()241   int surfaceWidth();
242 
surfaceHeight()243   int surfaceHeight();
244 
releaseSurface()245   void releaseSurface();
246 
release()247   void release();
248 
makeCurrent()249   void makeCurrent();
250 
251   // Detach the current EGL context, so that it can be made current on another thread.
detachCurrent()252   void detachCurrent();
253 
swapBuffers()254   void swapBuffers();
255 
swapBuffers(long presentationTimeStampNs)256   void swapBuffers(long presentationTimeStampNs);
257 }
258