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.view.Surface; 15 import androidx.annotation.Nullable; 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 EGL 1.4 context is created. 151 */ create(@ullable Context sharedContext, int[] configAttributes)152 public static EglBase create(@Nullable Context sharedContext, int[] configAttributes) { 153 if (sharedContext == null) { 154 return createEgl14(configAttributes); 155 } else if (sharedContext instanceof EglBase14.Context) { 156 return createEgl14((EglBase14.Context) sharedContext, configAttributes); 157 } else if (sharedContext instanceof EglBase10.Context) { 158 return createEgl10((EglBase10.Context) sharedContext, configAttributes); 159 } 160 throw new IllegalArgumentException("Unrecognized Context"); 161 } 162 163 /** 164 * Helper function for creating a plain root context. This function will try to create an EGL 1.4 165 * context if possible, and an EGL 1.0 context otherwise. 166 */ create()167 public static EglBase create() { 168 return create(null /* shaderContext */, CONFIG_PLAIN); 169 } 170 171 /** 172 * Helper function for creating a plain context, sharing data with `sharedContext`. This function 173 * will try to create an EGL 1.4 context if possible, and an EGL 1.0 context otherwise. 174 */ create(Context sharedContext)175 public static EglBase create(Context sharedContext) { 176 return create(sharedContext, CONFIG_PLAIN); 177 } 178 179 /** Explicitly create a root EGl 1.0 context with the specified config attributes. */ createEgl10(int[] configAttributes)180 public static EglBase10 createEgl10(int[] configAttributes) { 181 return new EglBase10Impl(/* sharedContext= */ null, configAttributes); 182 } 183 184 /** 185 * Explicitly create a root EGl 1.0 context with the specified config attributes and shared 186 * context. 187 */ createEgl10(EglBase10.Context sharedContext, int[] configAttributes)188 public static EglBase10 createEgl10(EglBase10.Context sharedContext, int[] configAttributes) { 189 return new EglBase10Impl( 190 sharedContext == null ? null : sharedContext.getRawContext(), configAttributes); 191 } 192 193 /** 194 * Explicitly create a root EGl 1.0 context with the specified config attributes 195 * and shared context. 196 */ createEgl10( javax.microedition.khronos.egl.EGLContext sharedContext, int[] configAttributes)197 public static EglBase10 createEgl10( 198 javax.microedition.khronos.egl.EGLContext sharedContext, int[] configAttributes) { 199 return new EglBase10Impl(sharedContext, configAttributes); 200 } 201 202 /** Explicitly create a root EGl 1.4 context with the specified config attributes. */ createEgl14(int[] configAttributes)203 public static EglBase14 createEgl14(int[] configAttributes) { 204 return new EglBase14Impl(/* sharedContext= */ null, configAttributes); 205 } 206 207 /** 208 * Explicitly create a root EGl 1.4 context with the specified config attributes and shared 209 * context. 210 */ createEgl14(EglBase14.Context sharedContext, int[] configAttributes)211 public static EglBase14 createEgl14(EglBase14.Context sharedContext, int[] configAttributes) { 212 return new EglBase14Impl( 213 sharedContext == null ? null : sharedContext.getRawContext(), configAttributes); 214 } 215 216 /** 217 * Explicitly create a root EGl 1.4 context with the specified config attributes 218 * and shared context. 219 */ createEgl14( android.opengl.EGLContext sharedContext, int[] configAttributes)220 public static EglBase14 createEgl14( 221 android.opengl.EGLContext sharedContext, int[] configAttributes) { 222 return new EglBase14Impl(sharedContext, configAttributes); 223 } 224 createSurface(Surface surface)225 void createSurface(Surface surface); 226 227 // Create EGLSurface from the Android SurfaceTexture. createSurface(SurfaceTexture surfaceTexture)228 void createSurface(SurfaceTexture surfaceTexture); 229 230 // Create dummy 1x1 pixel buffer surface so the context can be made current. createDummyPbufferSurface()231 void createDummyPbufferSurface(); 232 createPbufferSurface(int width, int height)233 void createPbufferSurface(int width, int height); 234 getEglBaseContext()235 Context getEglBaseContext(); 236 hasSurface()237 boolean hasSurface(); 238 surfaceWidth()239 int surfaceWidth(); 240 surfaceHeight()241 int surfaceHeight(); 242 releaseSurface()243 void releaseSurface(); 244 release()245 void release(); 246 makeCurrent()247 void makeCurrent(); 248 249 // Detach the current EGL context, so that it can be made current on another thread. detachCurrent()250 void detachCurrent(); 251 swapBuffers()252 void swapBuffers(); 253 swapBuffers(long presentationTimeStampNs)254 void swapBuffers(long presentationTimeStampNs); 255 } 256