Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 1 | /* |
kjellander | b24317b | 2016-02-10 07:54:43 -0800 | [diff] [blame] | 2 | * Copyright 2015 The WebRTC project authors. All Rights Reserved. |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 3 | * |
kjellander | b24317b | 2016-02-10 07:54:43 -0800 | [diff] [blame] | 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. |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 9 | */ |
| 10 | |
| 11 | package org.webrtc; |
| 12 | |
Magnus Jedvert | 1ab271c | 2015-09-28 11:05:44 +0200 | [diff] [blame] | 13 | import android.graphics.SurfaceTexture; |
Artem Titarenko | 69540f4 | 2018-12-10 12:30:46 +0100 | [diff] [blame] | 14 | import android.support.annotation.Nullable; |
magjed | 3e0f602 | 2015-11-16 02:04:50 -0800 | [diff] [blame] | 15 | import android.view.Surface; |
Magnus Jedvert | 94079f8 | 2019-05-18 14:49:27 +0200 | [diff] [blame^] | 16 | import java.util.ArrayList; |
magjed | 8c425aa | 2015-10-22 16:52:39 -0700 | [diff] [blame] | 17 | import javax.microedition.khronos.egl.EGL10; |
perkj | 9638143 | 2015-12-15 02:48:07 -0800 | [diff] [blame] | 18 | |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 19 | /** |
perkj | 40455d6 | 2015-12-02 01:07:18 -0800 | [diff] [blame] | 20 | * Holds EGL state and utility methods for handling an egl 1.0 EGLContext, an EGLDisplay, |
| 21 | * and an EGLSurface. |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 22 | */ |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 23 | public interface EglBase { |
perkj | 9638143 | 2015-12-15 02:48:07 -0800 | [diff] [blame] | 24 | // EGL wrapper for an actual EGLContext. |
Sami Kalliomäki | 8db246a | 2018-10-04 10:58:24 +0200 | [diff] [blame] | 25 | public interface Context { |
Magnus Jedvert | 7c6fbf2 | 2018-11-30 21:52:28 +0100 | [diff] [blame] | 26 | public final static long NO_CONTEXT = 0; |
| 27 | |
Sami Kalliomäki | 8db246a | 2018-10-04 10:58:24 +0200 | [diff] [blame] | 28 | /** |
Magnus Jedvert | 7c6fbf2 | 2018-11-30 21:52:28 +0100 | [diff] [blame] | 29 | * Returns an EGL context that can be used by native code. Returns NO_CONTEXT if the method is |
Sami Kalliomäki | 8db246a | 2018-10-04 10:58:24 +0200 | [diff] [blame] | 30 | * unsupported. |
| 31 | * |
| 32 | * @note This is currently only supported for EGL 1.4 and not for EGL 1.0. |
| 33 | */ |
| 34 | long getNativeEglContext(); |
| 35 | } |
perkj | 9638143 | 2015-12-15 02:48:07 -0800 | [diff] [blame] | 36 | |
Magnus Jedvert | 3db6f9b | 2016-03-31 13:17:11 +0200 | [diff] [blame] | 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 | |
magjed | 8c425aa | 2015-10-22 16:52:39 -0700 | [diff] [blame] | 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 |
magjed | 4781552 | 2017-08-25 06:28:00 -0700 | [diff] [blame] | 47 | public static final int EGL_OPENGL_ES2_BIT = 4; |
Magnus Jedvert | 94079f8 | 2019-05-18 14:49:27 +0200 | [diff] [blame^] | 48 | public static final int EGL_OPENGL_ES3_BIT = 0x40; |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 49 | // Android-specific extension. |
magjed | 4781552 | 2017-08-25 06:28:00 -0700 | [diff] [blame] | 50 | public static final int EGL_RECORDABLE_ANDROID = 0x3142; |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 51 | |
Magnus Jedvert | 94079f8 | 2019-05-18 14:49:27 +0200 | [diff] [blame^] | 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 | |
| 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 | |
| 70 | public ConfigBuilder setHasAlphaChannel(boolean hasAlphaChannel) { |
| 71 | this.hasAlphaChannel = hasAlphaChannel; |
| 72 | return this; |
| 73 | } |
| 74 | |
| 75 | public ConfigBuilder setSupportsPixelBuffer(boolean supportsPixelBuffer) { |
| 76 | this.supportsPixelBuffer = supportsPixelBuffer; |
| 77 | return this; |
| 78 | } |
| 79 | |
| 80 | public ConfigBuilder setIsRecordable(boolean isRecordable) { |
| 81 | this.isRecordable = isRecordable; |
| 82 | return this; |
| 83 | } |
| 84 | |
| 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 | |
| 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 | } |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 147 | |
magjed | b04646f | 2017-04-21 01:34:12 -0700 | [diff] [blame] | 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 | */ |
Sami Kalliomäki | e7592d8 | 2018-03-22 13:32:44 +0100 | [diff] [blame] | 153 | public static EglBase create(@Nullable Context sharedContext, int[] configAttributes) { |
Magnus Jedvert | 98d85fe | 2019-03-20 11:17:02 +0100 | [diff] [blame] | 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"); |
perkj | 40455d6 | 2015-12-02 01:07:18 -0800 | [diff] [blame] | 163 | } |
| 164 | |
magjed | b04646f | 2017-04-21 01:34:12 -0700 | [diff] [blame] | 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 | */ |
perkj | 40455d6 | 2015-12-02 01:07:18 -0800 | [diff] [blame] | 169 | public static EglBase create() { |
magjed | b04646f | 2017-04-21 01:34:12 -0700 | [diff] [blame] | 170 | return create(null /* shaderContext */, CONFIG_PLAIN); |
perkj | 40455d6 | 2015-12-02 01:07:18 -0800 | [diff] [blame] | 171 | } |
| 172 | |
magjed | b04646f | 2017-04-21 01:34:12 -0700 | [diff] [blame] | 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 | */ |
Per | ec2922f | 2016-01-27 15:25:46 +0100 | [diff] [blame] | 177 | public static EglBase create(Context sharedContext) { |
| 178 | return create(sharedContext, CONFIG_PLAIN); |
| 179 | } |
| 180 | |
Magnus Jedvert | 98d85fe | 2019-03-20 11:17:02 +0100 | [diff] [blame] | 181 | /** Explicitly create a root EGl 1.0 context with the specified config attributes. */ |
| 182 | public static EglBase10 createEgl10(int[] configAttributes) { |
| 183 | return new EglBase10Impl(/* sharedContext= */ null, configAttributes); |
| 184 | } |
| 185 | |
magjed | b04646f | 2017-04-21 01:34:12 -0700 | [diff] [blame] | 186 | /** |
Magnus Jedvert | 98d85fe | 2019-03-20 11:17:02 +0100 | [diff] [blame] | 187 | * Explicitly create a root EGl 1.0 context with the specified config attributes and shared |
| 188 | * context. |
magjed | b04646f | 2017-04-21 01:34:12 -0700 | [diff] [blame] | 189 | */ |
Magnus Jedvert | 98d85fe | 2019-03-20 11:17:02 +0100 | [diff] [blame] | 190 | public static EglBase10 createEgl10(EglBase10.Context sharedContext, int[] configAttributes) { |
| 191 | return new EglBase10Impl( |
| 192 | sharedContext == null ? null : sharedContext.getRawContext(), configAttributes); |
magjed | b04646f | 2017-04-21 01:34:12 -0700 | [diff] [blame] | 193 | } |
| 194 | |
| 195 | /** |
deadbeef | a615e17 | 2017-05-25 10:11:25 -0700 | [diff] [blame] | 196 | * Explicitly create a root EGl 1.0 context with the specified config attributes |
| 197 | * and shared context. |
| 198 | */ |
Magnus Jedvert | 98d85fe | 2019-03-20 11:17:02 +0100 | [diff] [blame] | 199 | public static EglBase10 createEgl10( |
deadbeef | a615e17 | 2017-05-25 10:11:25 -0700 | [diff] [blame] | 200 | javax.microedition.khronos.egl.EGLContext sharedContext, int[] configAttributes) { |
Magnus Jedvert | 98d85fe | 2019-03-20 11:17:02 +0100 | [diff] [blame] | 201 | return new EglBase10Impl(sharedContext, configAttributes); |
| 202 | } |
| 203 | |
| 204 | /** Explicitly create a root EGl 1.4 context with the specified config attributes. */ |
| 205 | public static EglBase14 createEgl14(int[] configAttributes) { |
| 206 | return new EglBase14Impl(/* sharedContext= */ null, configAttributes); |
deadbeef | a615e17 | 2017-05-25 10:11:25 -0700 | [diff] [blame] | 207 | } |
| 208 | |
| 209 | /** |
Magnus Jedvert | 98d85fe | 2019-03-20 11:17:02 +0100 | [diff] [blame] | 210 | * Explicitly create a root EGl 1.4 context with the specified config attributes and shared |
| 211 | * context. |
magjed | b04646f | 2017-04-21 01:34:12 -0700 | [diff] [blame] | 212 | */ |
Magnus Jedvert | 98d85fe | 2019-03-20 11:17:02 +0100 | [diff] [blame] | 213 | public static EglBase14 createEgl14(EglBase14.Context sharedContext, int[] configAttributes) { |
| 214 | return new EglBase14Impl( |
| 215 | sharedContext == null ? null : sharedContext.getRawContext(), configAttributes); |
magjed | b04646f | 2017-04-21 01:34:12 -0700 | [diff] [blame] | 216 | } |
| 217 | |
deadbeef | a615e17 | 2017-05-25 10:11:25 -0700 | [diff] [blame] | 218 | /** |
| 219 | * Explicitly create a root EGl 1.4 context with the specified config attributes |
| 220 | * and shared context. |
| 221 | */ |
Magnus Jedvert | 98d85fe | 2019-03-20 11:17:02 +0100 | [diff] [blame] | 222 | public static EglBase14 createEgl14( |
deadbeef | a615e17 | 2017-05-25 10:11:25 -0700 | [diff] [blame] | 223 | android.opengl.EGLContext sharedContext, int[] configAttributes) { |
Magnus Jedvert | 98d85fe | 2019-03-20 11:17:02 +0100 | [diff] [blame] | 224 | return new EglBase14Impl(sharedContext, configAttributes); |
deadbeef | a615e17 | 2017-05-25 10:11:25 -0700 | [diff] [blame] | 225 | } |
| 226 | |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 227 | void createSurface(Surface surface); |
Magnus Jedvert | 1ab271c | 2015-09-28 11:05:44 +0200 | [diff] [blame] | 228 | |
| 229 | // Create EGLSurface from the Android SurfaceTexture. |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 230 | void createSurface(SurfaceTexture surfaceTexture); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 231 | |
| 232 | // Create dummy 1x1 pixel buffer surface so the context can be made current. |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 233 | void createDummyPbufferSurface(); |
magjed | b28678c | 2015-07-26 05:17:19 -0700 | [diff] [blame] | 234 | |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 235 | void createPbufferSurface(int width, int height); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 236 | |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 237 | Context getEglBaseContext(); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 238 | |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 239 | boolean hasSurface(); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 240 | |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 241 | int surfaceWidth(); |
Magnus Jedvert | d476b95 | 2015-08-20 09:58:31 +0200 | [diff] [blame] | 242 | |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 243 | int surfaceHeight(); |
Magnus Jedvert | d476b95 | 2015-08-20 09:58:31 +0200 | [diff] [blame] | 244 | |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 245 | void releaseSurface(); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 246 | |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 247 | void release(); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 248 | |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 249 | void makeCurrent(); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 250 | |
Magnus Jedvert | 4ae28a1 | 2015-09-15 09:44:07 +0200 | [diff] [blame] | 251 | // Detach the current EGL context, so that it can be made current on another thread. |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 252 | void detachCurrent(); |
Magnus Jedvert | 4ae28a1 | 2015-09-15 09:44:07 +0200 | [diff] [blame] | 253 | |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 254 | void swapBuffers(); |
magjed | 4781552 | 2017-08-25 06:28:00 -0700 | [diff] [blame] | 255 | |
Sami Kalliomäki | b9f3f9b | 2017-11-30 11:23:33 +0100 | [diff] [blame] | 256 | void swapBuffers(long presentationTimeStampNs); |
Magnus Jedvert | 80cf97c | 2015-06-11 10:08:59 +0200 | [diff] [blame] | 257 | } |