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 |