OLD | NEW |
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2015 Google Inc. | 3 * Copyright 2015 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
(...skipping 10 matching lines...) Expand all Loading... |
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 */ | 26 */ |
27 | 27 |
28 package org.webrtc; | 28 package org.webrtc; |
29 | 29 |
30 import android.graphics.SurfaceTexture; | 30 import android.graphics.SurfaceTexture; |
31 import android.opengl.EGL14; | |
32 import android.opengl.EGLConfig; | |
33 import android.opengl.EGLContext; | |
34 import android.opengl.EGLDisplay; | |
35 import android.opengl.EGLSurface; | |
36 import android.view.Surface; | 31 import android.view.Surface; |
37 | 32 |
38 import org.webrtc.Logging; | 33 import org.webrtc.Logging; |
39 | 34 |
| 35 import javax.microedition.khronos.egl.EGL10; |
| 36 import javax.microedition.khronos.egl.EGLConfig; |
| 37 import javax.microedition.khronos.egl.EGLContext; |
| 38 import javax.microedition.khronos.egl.EGLDisplay; |
| 39 import javax.microedition.khronos.egl.EGLSurface; |
| 40 |
40 /** | 41 /** |
41 * Holds EGL state and utility methods for handling an EGLContext, an EGLDisplay
, and an EGLSurface. | 42 * Holds EGL state and utility methods for handling an EGLContext, an EGLDisplay
, and an EGLSurface. |
42 */ | 43 */ |
43 public final class EglBase { | 44 public final class EglBase { |
44 private static final String TAG = "EglBase"; | 45 private static final String TAG = "EglBase"; |
45 private static final int EGL14_SDK_VERSION = android.os.Build.VERSION_CODES.JE
LLY_BEAN_MR1; | 46 // These constants are taken from EGL14.EGL_OPENGL_ES2_BIT and EGL14.EGL_CONTE
XT_CLIENT_VERSION. |
46 private static final int CURRENT_SDK_VERSION = android.os.Build.VERSION.SDK_IN
T; | 47 // https://android.googlesource.com/platform/frameworks/base/+/master/opengl/j
ava/android/opengl/EGL14.java |
| 48 // This is similar to how GlSurfaceView does: |
| 49 // http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.androi
d/android/5.1.1_r1/android/opengl/GLSurfaceView.java#760 |
| 50 private static final int EGL_OPENGL_ES2_BIT = 4; |
| 51 private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; |
47 // Android-specific extension. | 52 // Android-specific extension. |
48 private static final int EGL_RECORDABLE_ANDROID = 0x3142; | 53 private static final int EGL_RECORDABLE_ANDROID = 0x3142; |
49 | 54 |
| 55 private final EGL10 egl; |
50 private EGLContext eglContext; | 56 private EGLContext eglContext; |
51 private ConfigType configType; | 57 private ConfigType configType; |
52 private EGLConfig eglConfig; | 58 private EGLConfig eglConfig; |
53 private EGLDisplay eglDisplay; | 59 private EGLDisplay eglDisplay; |
54 private EGLSurface eglSurface = EGL14.EGL_NO_SURFACE; | 60 private EGLSurface eglSurface = EGL10.EGL_NO_SURFACE; |
55 | |
56 public static boolean isEGL14Supported() { | |
57 Logging.d(TAG, "SDK version: " + CURRENT_SDK_VERSION); | |
58 return (CURRENT_SDK_VERSION >= EGL14_SDK_VERSION); | |
59 } | |
60 | 61 |
61 // EGLConfig constructor type. Influences eglChooseConfig arguments. | 62 // EGLConfig constructor type. Influences eglChooseConfig arguments. |
62 public static enum ConfigType { | 63 public static enum ConfigType { |
63 // No special parameters. | 64 // No special parameters. |
64 PLAIN, | 65 PLAIN, |
65 // Configures with EGL_SURFACE_TYPE = EGL_PBUFFER_BIT. | 66 // Configures with EGL_SURFACE_TYPE = EGL_PBUFFER_BIT. |
66 PIXEL_BUFFER, | 67 PIXEL_BUFFER, |
67 // Configures with EGL_RECORDABLE_ANDROID = 1. | 68 // Configures with EGL_RECORDABLE_ANDROID = 1. |
68 // Discourages EGL from using pixel formats that cannot efficiently be | 69 // Discourages EGL from using pixel formats that cannot efficiently be |
69 // converted to something usable by the video encoder. | 70 // converted to something usable by the video encoder. |
70 RECORDABLE | 71 RECORDABLE |
71 } | 72 } |
72 | 73 |
73 // Create root context without any EGLSurface or parent EGLContext. This can b
e used for branching | 74 // Create root context without any EGLSurface or parent EGLContext. This can b
e used for branching |
74 // new contexts that share data. | 75 // new contexts that share data. |
75 public EglBase() { | 76 public EglBase() { |
76 this(EGL14.EGL_NO_CONTEXT, ConfigType.PLAIN); | 77 this(EGL10.EGL_NO_CONTEXT, ConfigType.PLAIN); |
77 } | 78 } |
78 | 79 |
79 // Create a new context with the specified config type, sharing data with shar
edContext. | 80 // Create a new context with the specified config type, sharing data with shar
edContext. |
80 public EglBase(EGLContext sharedContext, ConfigType configType) { | 81 public EglBase(EGLContext sharedContext, ConfigType configType) { |
| 82 this.egl = (EGL10) EGLContext.getEGL(); |
81 this.configType = configType; | 83 this.configType = configType; |
82 eglDisplay = getEglDisplay(); | 84 eglDisplay = getEglDisplay(); |
83 eglConfig = getEglConfig(eglDisplay, configType); | 85 eglConfig = getEglConfig(eglDisplay, configType); |
84 eglContext = createEglContext(sharedContext, eglDisplay, eglConfig); | 86 eglContext = createEglContext(sharedContext, eglDisplay, eglConfig); |
85 } | 87 } |
86 | 88 |
87 // Create EGLSurface from the Android Surface. | 89 // Create EGLSurface from the Android Surface. |
88 public void createSurface(Surface surface) { | 90 public void createSurface(Surface surface) { |
89 createSurfaceInternal(surface); | 91 createSurfaceInternal(surface); |
90 } | 92 } |
91 | 93 |
92 // Create EGLSurface from the Android SurfaceTexture. | 94 // Create EGLSurface from the Android SurfaceTexture. |
93 public void createSurface(SurfaceTexture surfaceTexture) { | 95 public void createSurface(SurfaceTexture surfaceTexture) { |
94 createSurfaceInternal(surfaceTexture); | 96 createSurfaceInternal(surfaceTexture); |
95 } | 97 } |
96 | 98 |
97 // Create EGLSurface from either Surface or SurfaceTexture. | 99 // Create EGLSurface from either Surface or SurfaceTexture. |
98 private void createSurfaceInternal(Object surface) { | 100 private void createSurfaceInternal(Object surface) { |
99 if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture)) { | 101 if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture)) { |
100 throw new IllegalStateException("Input must be either a Surface or Surface
Texture"); | 102 throw new IllegalStateException("Input must be either a Surface or Surface
Texture"); |
101 } | 103 } |
102 checkIsNotReleased(); | 104 checkIsNotReleased(); |
103 if (configType == ConfigType.PIXEL_BUFFER) { | 105 if (configType == ConfigType.PIXEL_BUFFER) { |
104 Logging.w(TAG, "This EGL context is configured for PIXEL_BUFFER, but uses
regular Surface"); | 106 Logging.w(TAG, "This EGL context is configured for PIXEL_BUFFER, but uses
regular Surface"); |
105 } | 107 } |
106 if (eglSurface != EGL14.EGL_NO_SURFACE) { | 108 if (eglSurface != EGL10.EGL_NO_SURFACE) { |
107 throw new RuntimeException("Already has an EGLSurface"); | 109 throw new RuntimeException("Already has an EGLSurface"); |
108 } | 110 } |
109 int[] surfaceAttribs = {EGL14.EGL_NONE}; | 111 int[] surfaceAttribs = {EGL10.EGL_NONE}; |
110 eglSurface = EGL14.eglCreateWindowSurface(eglDisplay, eglConfig, surface, su
rfaceAttribs, 0); | 112 eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, surface, surf
aceAttribs); |
111 if (eglSurface == EGL14.EGL_NO_SURFACE) { | 113 if (eglSurface == EGL10.EGL_NO_SURFACE) { |
112 throw new RuntimeException("Failed to create window surface"); | 114 throw new RuntimeException("Failed to create window surface"); |
113 } | 115 } |
114 } | 116 } |
115 | 117 |
116 // Create dummy 1x1 pixel buffer surface so the context can be made current. | 118 // Create dummy 1x1 pixel buffer surface so the context can be made current. |
117 public void createDummyPbufferSurface() { | 119 public void createDummyPbufferSurface() { |
118 createPbufferSurface(1, 1); | 120 createPbufferSurface(1, 1); |
119 } | 121 } |
120 | 122 |
121 public void createPbufferSurface(int width, int height) { | 123 public void createPbufferSurface(int width, int height) { |
122 checkIsNotReleased(); | 124 checkIsNotReleased(); |
123 if (configType != ConfigType.PIXEL_BUFFER) { | 125 if (configType != ConfigType.PIXEL_BUFFER) { |
124 throw new RuntimeException( | 126 throw new RuntimeException( |
125 "This EGL context is not configured to use a pixel buffer: " + configT
ype); | 127 "This EGL context is not configured to use a pixel buffer: " + configT
ype); |
126 } | 128 } |
127 if (eglSurface != EGL14.EGL_NO_SURFACE) { | 129 if (eglSurface != EGL10.EGL_NO_SURFACE) { |
128 throw new RuntimeException("Already has an EGLSurface"); | 130 throw new RuntimeException("Already has an EGLSurface"); |
129 } | 131 } |
130 int[] surfaceAttribs = {EGL14.EGL_WIDTH, width, EGL14.EGL_HEIGHT, height, EG
L14.EGL_NONE}; | 132 int[] surfaceAttribs = {EGL10.EGL_WIDTH, width, EGL10.EGL_HEIGHT, height, EG
L10.EGL_NONE}; |
131 eglSurface = EGL14.eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAtt
ribs, 0); | 133 eglSurface = egl.eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttri
bs); |
132 if (eglSurface == EGL14.EGL_NO_SURFACE) { | 134 if (eglSurface == EGL10.EGL_NO_SURFACE) { |
133 throw new RuntimeException("Failed to create pixel buffer surface"); | 135 throw new RuntimeException("Failed to create pixel buffer surface"); |
134 } | 136 } |
135 } | 137 } |
136 | 138 |
137 public EGLContext getContext() { | 139 public EGLContext getContext() { |
138 return eglContext; | 140 return eglContext; |
139 } | 141 } |
140 | 142 |
141 public boolean hasSurface() { | 143 public boolean hasSurface() { |
142 return eglSurface != EGL14.EGL_NO_SURFACE; | 144 return eglSurface != EGL10.EGL_NO_SURFACE; |
143 } | 145 } |
144 | 146 |
145 public int surfaceWidth() { | 147 public int surfaceWidth() { |
146 final int widthArray[] = new int[1]; | 148 final int widthArray[] = new int[1]; |
147 EGL14.eglQuerySurface(eglDisplay, eglSurface, EGL14.EGL_WIDTH, widthArray, 0
); | 149 egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_WIDTH, widthArray); |
148 return widthArray[0]; | 150 return widthArray[0]; |
149 } | 151 } |
150 | 152 |
151 public int surfaceHeight() { | 153 public int surfaceHeight() { |
152 final int heightArray[] = new int[1]; | 154 final int heightArray[] = new int[1]; |
153 EGL14.eglQuerySurface(eglDisplay, eglSurface, EGL14.EGL_HEIGHT, heightArray,
0); | 155 egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_HEIGHT, heightArray); |
154 return heightArray[0]; | 156 return heightArray[0]; |
155 } | 157 } |
156 | 158 |
157 public void releaseSurface() { | 159 public void releaseSurface() { |
158 if (eglSurface != EGL14.EGL_NO_SURFACE) { | 160 if (eglSurface != EGL10.EGL_NO_SURFACE) { |
159 EGL14.eglDestroySurface(eglDisplay, eglSurface); | 161 egl.eglDestroySurface(eglDisplay, eglSurface); |
160 eglSurface = EGL14.EGL_NO_SURFACE; | 162 eglSurface = EGL10.EGL_NO_SURFACE; |
161 } | 163 } |
162 } | 164 } |
163 | 165 |
164 private void checkIsNotReleased() { | 166 private void checkIsNotReleased() { |
165 if (eglDisplay == EGL14.EGL_NO_DISPLAY || eglContext == EGL14.EGL_NO_CONTEXT | 167 if (eglDisplay == EGL10.EGL_NO_DISPLAY || eglContext == EGL10.EGL_NO_CONTEXT |
166 || eglConfig == null) { | 168 || eglConfig == null) { |
167 throw new RuntimeException("This object has been released"); | 169 throw new RuntimeException("This object has been released"); |
168 } | 170 } |
169 } | 171 } |
170 | 172 |
171 public void release() { | 173 public void release() { |
172 checkIsNotReleased(); | 174 checkIsNotReleased(); |
173 releaseSurface(); | 175 releaseSurface(); |
174 detachCurrent(); | 176 detachCurrent(); |
175 EGL14.eglDestroyContext(eglDisplay, eglContext); | 177 egl.eglDestroyContext(eglDisplay, eglContext); |
176 EGL14.eglReleaseThread(); | 178 egl.eglTerminate(eglDisplay); |
177 EGL14.eglTerminate(eglDisplay); | 179 eglContext = EGL10.EGL_NO_CONTEXT; |
178 eglContext = EGL14.EGL_NO_CONTEXT; | 180 eglDisplay = EGL10.EGL_NO_DISPLAY; |
179 eglDisplay = EGL14.EGL_NO_DISPLAY; | |
180 eglConfig = null; | 181 eglConfig = null; |
181 } | 182 } |
182 | 183 |
183 public void makeCurrent() { | 184 public void makeCurrent() { |
184 checkIsNotReleased(); | 185 checkIsNotReleased(); |
185 if (eglSurface == EGL14.EGL_NO_SURFACE) { | 186 if (eglSurface == EGL10.EGL_NO_SURFACE) { |
186 throw new RuntimeException("No EGLSurface - can't make current"); | 187 throw new RuntimeException("No EGLSurface - can't make current"); |
187 } | 188 } |
188 if (!EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { | 189 if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { |
189 throw new RuntimeException("eglMakeCurrent failed"); | 190 throw new RuntimeException("eglMakeCurrent failed"); |
190 } | 191 } |
191 } | 192 } |
192 | 193 |
193 // Detach the current EGL context, so that it can be made current on another t
hread. | 194 // Detach the current EGL context, so that it can be made current on another t
hread. |
194 public void detachCurrent() { | 195 public void detachCurrent() { |
195 if (!EGL14.eglMakeCurrent( | 196 if (!egl.eglMakeCurrent( |
196 eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CON
TEXT)) { | 197 eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CON
TEXT)) { |
197 throw new RuntimeException("eglMakeCurrent failed"); | 198 throw new RuntimeException("eglMakeCurrent failed"); |
198 } | 199 } |
199 } | 200 } |
200 | 201 |
201 public void swapBuffers() { | 202 public void swapBuffers() { |
202 checkIsNotReleased(); | 203 checkIsNotReleased(); |
203 if (eglSurface == EGL14.EGL_NO_SURFACE) { | 204 if (eglSurface == EGL10.EGL_NO_SURFACE) { |
204 throw new RuntimeException("No EGLSurface - can't swap buffers"); | 205 throw new RuntimeException("No EGLSurface - can't swap buffers"); |
205 } | 206 } |
206 EGL14.eglSwapBuffers(eglDisplay, eglSurface); | 207 egl.eglSwapBuffers(eglDisplay, eglSurface); |
207 } | 208 } |
208 | 209 |
209 // Return an EGLDisplay, or die trying. | 210 // Return an EGLDisplay, or die trying. |
210 private static EGLDisplay getEglDisplay() { | 211 private EGLDisplay getEglDisplay() { |
211 EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); | 212 EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); |
212 if (eglDisplay == EGL14.EGL_NO_DISPLAY) { | 213 if (eglDisplay == EGL10.EGL_NO_DISPLAY) { |
213 throw new RuntimeException("Unable to get EGL14 display"); | 214 throw new RuntimeException("Unable to get EGL10 display"); |
214 } | 215 } |
215 int[] version = new int[2]; | 216 int[] version = new int[2]; |
216 if (!EGL14.eglInitialize(eglDisplay, version, 0, version, 1)) { | 217 if (!egl.eglInitialize(eglDisplay, version)) { |
217 throw new RuntimeException("Unable to initialize EGL14"); | 218 throw new RuntimeException("Unable to initialize EGL10"); |
218 } | 219 } |
219 return eglDisplay; | 220 return eglDisplay; |
220 } | 221 } |
221 | 222 |
222 // Return an EGLConfig, or die trying. | 223 // Return an EGLConfig, or die trying. |
223 private static EGLConfig getEglConfig(EGLDisplay eglDisplay, ConfigType config
Type) { | 224 private EGLConfig getEglConfig(EGLDisplay eglDisplay, ConfigType configType) { |
224 // Always RGB888, GLES2. | 225 // Always RGB888, GLES2. |
225 int[] configAttributes = { | 226 int[] configAttributes = { |
226 EGL14.EGL_RED_SIZE, 8, | 227 EGL10.EGL_RED_SIZE, 8, |
227 EGL14.EGL_GREEN_SIZE, 8, | 228 EGL10.EGL_GREEN_SIZE, 8, |
228 EGL14.EGL_BLUE_SIZE, 8, | 229 EGL10.EGL_BLUE_SIZE, 8, |
229 EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, | 230 EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
230 EGL14.EGL_NONE, 0, // Allocate dummy fields for specific options. | 231 EGL10.EGL_NONE, 0, // Allocate dummy fields for specific options. |
231 EGL14.EGL_NONE | 232 EGL10.EGL_NONE |
232 }; | 233 }; |
233 | 234 |
234 // Fill in dummy fields based on configType. | 235 // Fill in dummy fields based on configType. |
235 switch (configType) { | 236 switch (configType) { |
236 case PLAIN: | 237 case PLAIN: |
237 break; | 238 break; |
238 case PIXEL_BUFFER: | 239 case PIXEL_BUFFER: |
239 configAttributes[configAttributes.length - 3] = EGL14.EGL_SURFACE_TYPE; | 240 configAttributes[configAttributes.length - 3] = EGL10.EGL_SURFACE_TYPE; |
240 configAttributes[configAttributes.length - 2] = EGL14.EGL_PBUFFER_BIT; | 241 configAttributes[configAttributes.length - 2] = EGL10.EGL_PBUFFER_BIT; |
241 break; | 242 break; |
242 case RECORDABLE: | 243 case RECORDABLE: |
243 configAttributes[configAttributes.length - 3] = EGL_RECORDABLE_ANDROID; | 244 configAttributes[configAttributes.length - 3] = EGL_RECORDABLE_ANDROID; |
244 configAttributes[configAttributes.length - 2] = 1; | 245 configAttributes[configAttributes.length - 2] = 1; |
245 break; | 246 break; |
246 default: | 247 default: |
247 throw new IllegalArgumentException(); | 248 throw new IllegalArgumentException(); |
248 } | 249 } |
249 | 250 |
250 EGLConfig[] configs = new EGLConfig[1]; | 251 EGLConfig[] configs = new EGLConfig[1]; |
251 int[] numConfigs = new int[1]; | 252 int[] numConfigs = new int[1]; |
252 if (!EGL14.eglChooseConfig( | 253 if (!egl.eglChooseConfig( |
253 eglDisplay, configAttributes, 0, configs, 0, configs.length, numConfigs,
0)) { | 254 eglDisplay, configAttributes, configs, configs.length, numConfigs)) { |
254 throw new RuntimeException("Unable to find RGB888 " + configType + " EGL c
onfig"); | 255 throw new RuntimeException("Unable to find RGB888 " + configType + " EGL c
onfig"); |
255 } | 256 } |
256 return configs[0]; | 257 return configs[0]; |
257 } | 258 } |
258 | 259 |
259 // Return an EGLConfig, or die trying. | 260 // Return an EGLConfig, or die trying. |
260 private static EGLContext createEglContext( | 261 private EGLContext createEglContext( |
261 EGLContext sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) { | 262 EGLContext sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) { |
262 int[] contextAttributes = {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NO
NE}; | 263 int[] contextAttributes = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE}; |
263 EGLContext eglContext = | 264 EGLContext eglContext = |
264 EGL14.eglCreateContext(eglDisplay, eglConfig, sharedContext, contextAttr
ibutes, 0); | 265 egl.eglCreateContext(eglDisplay, eglConfig, sharedContext, contextAttrib
utes); |
265 if (eglContext == EGL14.EGL_NO_CONTEXT) { | 266 if (eglContext == EGL10.EGL_NO_CONTEXT) { |
266 throw new RuntimeException("Failed to create EGL context"); | 267 throw new RuntimeException("Failed to create EGL context"); |
267 } | 268 } |
268 return eglContext; | 269 return eglContext; |
269 } | 270 } |
270 } | 271 } |
OLD | NEW |