OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 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.videoengine; | |
12 | |
13 import java.util.concurrent.locks.ReentrantLock; | |
14 | |
15 import javax.microedition.khronos.egl.EGL10; | |
16 import javax.microedition.khronos.egl.EGLConfig; | |
17 import javax.microedition.khronos.egl.EGLContext; | |
18 import javax.microedition.khronos.egl.EGLDisplay; | |
19 import javax.microedition.khronos.opengles.GL10; | |
20 | |
21 import android.app.ActivityManager; | |
22 import android.content.Context; | |
23 import android.content.pm.ConfigurationInfo; | |
24 import android.graphics.PixelFormat; | |
25 import android.opengl.GLSurfaceView; | |
26 | |
27 import org.webrtc.Logging; | |
28 | |
29 public class ViEAndroidGLES20 extends GLSurfaceView | |
30 implements GLSurfaceView.Renderer { | |
31 private static String TAG = "WEBRTC-JR"; | |
32 private static final boolean DEBUG = false; | |
33 // True if onSurfaceCreated has been called. | |
34 private boolean surfaceCreated = false; | |
35 private boolean openGLCreated = false; | |
36 // True if NativeFunctionsRegistered has been called. | |
37 private boolean nativeFunctionsRegisted = false; | |
38 private ReentrantLock nativeFunctionLock = new ReentrantLock(); | |
39 // Address of Native object that will do the drawing. | |
40 private long nativeObject = 0; | |
41 private int viewWidth = 0; | |
42 private int viewHeight = 0; | |
43 | |
44 public static boolean UseOpenGL2(Object renderWindow) { | |
45 return ViEAndroidGLES20.class.isInstance(renderWindow); | |
46 } | |
47 | |
48 public ViEAndroidGLES20(Context context) { | |
49 super(context); | |
50 init(false, 0, 0); | |
51 } | |
52 | |
53 public ViEAndroidGLES20(Context context, boolean translucent, | |
54 int depth, int stencil) { | |
55 super(context); | |
56 init(translucent, depth, stencil); | |
57 } | |
58 | |
59 private void init(boolean translucent, int depth, int stencil) { | |
60 | |
61 // By default, GLSurfaceView() creates a RGB_565 opaque surface. | |
62 // If we want a translucent one, we should change the surface's | |
63 // format here, using PixelFormat.TRANSLUCENT for GL Surfaces | |
64 // is interpreted as any 32-bit surface with alpha by SurfaceFlinger. | |
65 if (translucent) { | |
66 this.getHolder().setFormat(PixelFormat.TRANSLUCENT); | |
67 } | |
68 | |
69 // Setup the context factory for 2.0 rendering. | |
70 // See ContextFactory class definition below | |
71 setEGLContextFactory(new ContextFactory()); | |
72 | |
73 // We need to choose an EGLConfig that matches the format of | |
74 // our surface exactly. This is going to be done in our | |
75 // custom config chooser. See ConfigChooser class definition | |
76 // below. | |
77 setEGLConfigChooser( translucent ? | |
78 new ConfigChooser(8, 8, 8, 8, depth, stencil) : | |
79 new ConfigChooser(5, 6, 5, 0, depth, stencil) ); | |
80 | |
81 // Set the renderer responsible for frame rendering | |
82 this.setRenderer(this); | |
83 this.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); | |
84 } | |
85 | |
86 private static class ContextFactory implements GLSurfaceView.EGLContextFacto
ry { | |
87 private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; | |
88 public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig
eglConfig) { | |
89 Logging.w(TAG, "creating OpenGL ES 2.0 context"); | |
90 checkEglError("Before eglCreateContext", egl); | |
91 int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }
; | |
92 EGLContext context = egl.eglCreateContext(display, eglConfig, | |
93 EGL10.EGL_NO_CONTEXT, attrib_list); | |
94 checkEglError("After eglCreateContext", egl); | |
95 return context; | |
96 } | |
97 | |
98 public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext con
text) { | |
99 egl.eglDestroyContext(display, context); | |
100 } | |
101 } | |
102 | |
103 private static void checkEglError(String prompt, EGL10 egl) { | |
104 int error; | |
105 while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { | |
106 Logging.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); | |
107 } | |
108 } | |
109 | |
110 private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser
{ | |
111 | |
112 public ConfigChooser(int r, int g, int b, int a, int depth, int stencil)
{ | |
113 mRedSize = r; | |
114 mGreenSize = g; | |
115 mBlueSize = b; | |
116 mAlphaSize = a; | |
117 mDepthSize = depth; | |
118 mStencilSize = stencil; | |
119 } | |
120 | |
121 // This EGL config specification is used to specify 2.0 rendering. | |
122 // We use a minimum size of 4 bits for red/green/blue, but will | |
123 // perform actual matching in chooseConfig() below. | |
124 private static int EGL_OPENGL_ES2_BIT = 4; | |
125 private static int[] s_configAttribs2 = | |
126 { | |
127 EGL10.EGL_RED_SIZE, 4, | |
128 EGL10.EGL_GREEN_SIZE, 4, | |
129 EGL10.EGL_BLUE_SIZE, 4, | |
130 EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, | |
131 EGL10.EGL_NONE | |
132 }; | |
133 | |
134 public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { | |
135 | |
136 // Get the number of minimally matching EGL configurations | |
137 int[] num_config = new int[1]; | |
138 egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config); | |
139 | |
140 int numConfigs = num_config[0]; | |
141 | |
142 if (numConfigs <= 0) { | |
143 throw new IllegalArgumentException("No configs match configSpec"
); | |
144 } | |
145 | |
146 // Allocate then read the array of minimally matching EGL configs | |
147 EGLConfig[] configs = new EGLConfig[numConfigs]; | |
148 egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs,
num_config); | |
149 | |
150 if (DEBUG) { | |
151 printConfigs(egl, display, configs); | |
152 } | |
153 // Now return the "best" one | |
154 return chooseConfig(egl, display, configs); | |
155 } | |
156 | |
157 public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, | |
158 EGLConfig[] configs) { | |
159 for(EGLConfig config : configs) { | |
160 int d = findConfigAttrib(egl, display, config, | |
161 EGL10.EGL_DEPTH_SIZE, 0); | |
162 int s = findConfigAttrib(egl, display, config, | |
163 EGL10.EGL_STENCIL_SIZE, 0); | |
164 | |
165 // We need at least mDepthSize and mStencilSize bits | |
166 if (d < mDepthSize || s < mStencilSize) | |
167 continue; | |
168 | |
169 // We want an *exact* match for red/green/blue/alpha | |
170 int r = findConfigAttrib(egl, display, config, | |
171 EGL10.EGL_RED_SIZE, 0); | |
172 int g = findConfigAttrib(egl, display, config, | |
173 EGL10.EGL_GREEN_SIZE, 0); | |
174 int b = findConfigAttrib(egl, display, config, | |
175 EGL10.EGL_BLUE_SIZE, 0); | |
176 int a = findConfigAttrib(egl, display, config, | |
177 EGL10.EGL_ALPHA_SIZE, 0); | |
178 | |
179 if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == m
AlphaSize) | |
180 return config; | |
181 } | |
182 return null; | |
183 } | |
184 | |
185 private int findConfigAttrib(EGL10 egl, EGLDisplay display, | |
186 EGLConfig config, int attribute, int defaultValue) { | |
187 | |
188 if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { | |
189 return mValue[0]; | |
190 } | |
191 return defaultValue; | |
192 } | |
193 | |
194 private void printConfigs(EGL10 egl, EGLDisplay display, | |
195 EGLConfig[] configs) { | |
196 int numConfigs = configs.length; | |
197 Logging.w(TAG, String.format("%d configurations", numConfigs)); | |
198 for (int i = 0; i < numConfigs; i++) { | |
199 Logging.w(TAG, String.format("Configuration %d:\n", i)); | |
200 printConfig(egl, display, configs[i]); | |
201 } | |
202 } | |
203 | |
204 private void printConfig(EGL10 egl, EGLDisplay display, | |
205 EGLConfig config) { | |
206 int[] attributes = { | |
207 EGL10.EGL_BUFFER_SIZE, | |
208 EGL10.EGL_ALPHA_SIZE, | |
209 EGL10.EGL_BLUE_SIZE, | |
210 EGL10.EGL_GREEN_SIZE, | |
211 EGL10.EGL_RED_SIZE, | |
212 EGL10.EGL_DEPTH_SIZE, | |
213 EGL10.EGL_STENCIL_SIZE, | |
214 EGL10.EGL_CONFIG_CAVEAT, | |
215 EGL10.EGL_CONFIG_ID, | |
216 EGL10.EGL_LEVEL, | |
217 EGL10.EGL_MAX_PBUFFER_HEIGHT, | |
218 EGL10.EGL_MAX_PBUFFER_PIXELS, | |
219 EGL10.EGL_MAX_PBUFFER_WIDTH, | |
220 EGL10.EGL_NATIVE_RENDERABLE, | |
221 EGL10.EGL_NATIVE_VISUAL_ID, | |
222 EGL10.EGL_NATIVE_VISUAL_TYPE, | |
223 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, | |
224 EGL10.EGL_SAMPLES, | |
225 EGL10.EGL_SAMPLE_BUFFERS, | |
226 EGL10.EGL_SURFACE_TYPE, | |
227 EGL10.EGL_TRANSPARENT_TYPE, | |
228 EGL10.EGL_TRANSPARENT_RED_VALUE, | |
229 EGL10.EGL_TRANSPARENT_GREEN_VALUE, | |
230 EGL10.EGL_TRANSPARENT_BLUE_VALUE, | |
231 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, | |
232 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, | |
233 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, | |
234 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, | |
235 EGL10.EGL_LUMINANCE_SIZE, | |
236 EGL10.EGL_ALPHA_MASK_SIZE, | |
237 EGL10.EGL_COLOR_BUFFER_TYPE, | |
238 EGL10.EGL_RENDERABLE_TYPE, | |
239 0x3042 // EGL10.EGL_CONFORMANT | |
240 }; | |
241 String[] names = { | |
242 "EGL_BUFFER_SIZE", | |
243 "EGL_ALPHA_SIZE", | |
244 "EGL_BLUE_SIZE", | |
245 "EGL_GREEN_SIZE", | |
246 "EGL_RED_SIZE", | |
247 "EGL_DEPTH_SIZE", | |
248 "EGL_STENCIL_SIZE", | |
249 "EGL_CONFIG_CAVEAT", | |
250 "EGL_CONFIG_ID", | |
251 "EGL_LEVEL", | |
252 "EGL_MAX_PBUFFER_HEIGHT", | |
253 "EGL_MAX_PBUFFER_PIXELS", | |
254 "EGL_MAX_PBUFFER_WIDTH", | |
255 "EGL_NATIVE_RENDERABLE", | |
256 "EGL_NATIVE_VISUAL_ID", | |
257 "EGL_NATIVE_VISUAL_TYPE", | |
258 "EGL_PRESERVED_RESOURCES", | |
259 "EGL_SAMPLES", | |
260 "EGL_SAMPLE_BUFFERS", | |
261 "EGL_SURFACE_TYPE", | |
262 "EGL_TRANSPARENT_TYPE", | |
263 "EGL_TRANSPARENT_RED_VALUE", | |
264 "EGL_TRANSPARENT_GREEN_VALUE", | |
265 "EGL_TRANSPARENT_BLUE_VALUE", | |
266 "EGL_BIND_TO_TEXTURE_RGB", | |
267 "EGL_BIND_TO_TEXTURE_RGBA", | |
268 "EGL_MIN_SWAP_INTERVAL", | |
269 "EGL_MAX_SWAP_INTERVAL", | |
270 "EGL_LUMINANCE_SIZE", | |
271 "EGL_ALPHA_MASK_SIZE", | |
272 "EGL_COLOR_BUFFER_TYPE", | |
273 "EGL_RENDERABLE_TYPE", | |
274 "EGL_CONFORMANT" | |
275 }; | |
276 int[] value = new int[1]; | |
277 for (int i = 0; i < attributes.length; i++) { | |
278 int attribute = attributes[i]; | |
279 String name = names[i]; | |
280 if (egl.eglGetConfigAttrib(display, config, attribute, value)) { | |
281 Logging.w(TAG, String.format(" %s: %d\n", name, value[0])); | |
282 } else { | |
283 // Logging.w(TAG, String.format(" %s: failed\n", name)); | |
284 while (egl.eglGetError() != EGL10.EGL_SUCCESS); | |
285 } | |
286 } | |
287 } | |
288 | |
289 // Subclasses can adjust these values: | |
290 protected int mRedSize; | |
291 protected int mGreenSize; | |
292 protected int mBlueSize; | |
293 protected int mAlphaSize; | |
294 protected int mDepthSize; | |
295 protected int mStencilSize; | |
296 private int[] mValue = new int[1]; | |
297 } | |
298 | |
299 // IsSupported | |
300 // Return true if this device support Open GL ES 2.0 rendering. | |
301 public static boolean IsSupported(Context context) { | |
302 ActivityManager am = | |
303 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERV
ICE); | |
304 ConfigurationInfo info = am.getDeviceConfigurationInfo(); | |
305 if(info.reqGlEsVersion >= 0x20000) { | |
306 // Open GL ES 2.0 is supported. | |
307 return true; | |
308 } | |
309 return false; | |
310 } | |
311 | |
312 public void onDrawFrame(GL10 gl) { | |
313 nativeFunctionLock.lock(); | |
314 if(!nativeFunctionsRegisted || !surfaceCreated) { | |
315 nativeFunctionLock.unlock(); | |
316 return; | |
317 } | |
318 | |
319 if(!openGLCreated) { | |
320 if(0 != CreateOpenGLNative(nativeObject, viewWidth, viewHeight)) { | |
321 return; // Failed to create OpenGL | |
322 } | |
323 openGLCreated = true; // Created OpenGL successfully | |
324 } | |
325 DrawNative(nativeObject); // Draw the new frame | |
326 nativeFunctionLock.unlock(); | |
327 } | |
328 | |
329 public void onSurfaceChanged(GL10 gl, int width, int height) { | |
330 surfaceCreated = true; | |
331 viewWidth = width; | |
332 viewHeight = height; | |
333 | |
334 nativeFunctionLock.lock(); | |
335 if(nativeFunctionsRegisted) { | |
336 if(CreateOpenGLNative(nativeObject,width,height) == 0) | |
337 openGLCreated = true; | |
338 } | |
339 nativeFunctionLock.unlock(); | |
340 } | |
341 | |
342 public void onSurfaceCreated(GL10 gl, EGLConfig config) { | |
343 } | |
344 | |
345 public void RegisterNativeObject(long nativeObject) { | |
346 nativeFunctionLock.lock(); | |
347 this.nativeObject = nativeObject; | |
348 nativeFunctionsRegisted = true; | |
349 nativeFunctionLock.unlock(); | |
350 } | |
351 | |
352 public void DeRegisterNativeObject() { | |
353 nativeFunctionLock.lock(); | |
354 nativeFunctionsRegisted = false; | |
355 openGLCreated = false; | |
356 this.nativeObject = 0; | |
357 nativeFunctionLock.unlock(); | |
358 } | |
359 | |
360 public void ReDraw() { | |
361 if(surfaceCreated) { | |
362 // Request the renderer to redraw using the render thread context. | |
363 this.requestRender(); | |
364 } | |
365 } | |
366 | |
367 private native int CreateOpenGLNative(long nativeObject, | |
368 int width, int height); | |
369 private native void DrawNative(long nativeObject); | |
370 | |
371 } | |
OLD | NEW |