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