blob: c1cb906c5d834cb37974ba6a08d63c85fd155eeb [file] [log] [blame]
Magnus Jedvert80cf97c2015-06-11 10:08:59 +02001/*
kjellanderb24317b2016-02-10 07:54:43 -08002 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
Magnus Jedvert80cf97c2015-06-11 10:08:59 +02003 *
kjellanderb24317b2016-02-10 07:54:43 -08004 * 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 Jedvert80cf97c2015-06-11 10:08:59 +02009 */
10
11package org.webrtc;
12
Magnus Jedvert1ab271c2015-09-28 11:05:44 +020013import android.graphics.SurfaceTexture;
Artem Titarenko69540f42018-12-10 12:30:46 +010014import android.support.annotation.Nullable;
magjed3e0f6022015-11-16 02:04:50 -080015import android.view.Surface;
Magnus Jedvert94079f82019-05-18 14:49:27 +020016import java.util.ArrayList;
magjed8c425aa2015-10-22 16:52:39 -070017import javax.microedition.khronos.egl.EGL10;
perkj96381432015-12-15 02:48:07 -080018
Magnus Jedvert80cf97c2015-06-11 10:08:59 +020019/**
perkj40455d62015-12-02 01:07:18 -080020 * Holds EGL state and utility methods for handling an egl 1.0 EGLContext, an EGLDisplay,
21 * and an EGLSurface.
Magnus Jedvert80cf97c2015-06-11 10:08:59 +020022 */
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +010023public interface EglBase {
perkj96381432015-12-15 02:48:07 -080024 // EGL wrapper for an actual EGLContext.
Sami Kalliomäki8db246a2018-10-04 10:58:24 +020025 public interface Context {
Magnus Jedvert7c6fbf22018-11-30 21:52:28 +010026 public final static long NO_CONTEXT = 0;
27
Sami Kalliomäki8db246a2018-10-04 10:58:24 +020028 /**
Magnus Jedvert7c6fbf22018-11-30 21:52:28 +010029 * Returns an EGL context that can be used by native code. Returns NO_CONTEXT if the method is
Sami Kalliomäki8db246a2018-10-04 10:58:24 +020030 * unsupported.
31 *
32 * @note This is currently only supported for EGL 1.4 and not for EGL 1.0.
33 */
34 long getNativeEglContext();
35 }
perkj96381432015-12-15 02:48:07 -080036
Magnus Jedvert3db6f9b2016-03-31 13:17:11 +020037 // 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
magjed8c425aa2015-10-22 16:52:39 -070043 // 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
magjed47815522017-08-25 06:28:00 -070047 public static final int EGL_OPENGL_ES2_BIT = 4;
Magnus Jedvert94079f82019-05-18 14:49:27 +020048 public static final int EGL_OPENGL_ES3_BIT = 0x40;
Magnus Jedvert80cf97c2015-06-11 10:08:59 +020049 // Android-specific extension.
magjed47815522017-08-25 06:28:00 -070050 public static final int EGL_RECORDABLE_ANDROID = 0x3142;
Magnus Jedvert80cf97c2015-06-11 10:08:59 +020051
Magnus Jedvert94079f82019-05-18 14:49:27 +020052 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 Jedvert80cf97c2015-06-11 10:08:59 +0200147
magjedb04646f2017-04-21 01:34:12 -0700148 /**
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äkie7592d82018-03-22 13:32:44 +0100153 public static EglBase create(@Nullable Context sharedContext, int[] configAttributes) {
Magnus Jedvert98d85fe2019-03-20 11:17:02 +0100154 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");
perkj40455d62015-12-02 01:07:18 -0800163 }
164
magjedb04646f2017-04-21 01:34:12 -0700165 /**
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 */
perkj40455d62015-12-02 01:07:18 -0800169 public static EglBase create() {
magjedb04646f2017-04-21 01:34:12 -0700170 return create(null /* shaderContext */, CONFIG_PLAIN);
perkj40455d62015-12-02 01:07:18 -0800171 }
172
magjedb04646f2017-04-21 01:34:12 -0700173 /**
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 */
Perec2922f2016-01-27 15:25:46 +0100177 public static EglBase create(Context sharedContext) {
178 return create(sharedContext, CONFIG_PLAIN);
179 }
180
Magnus Jedvert98d85fe2019-03-20 11:17:02 +0100181 /** 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
magjedb04646f2017-04-21 01:34:12 -0700186 /**
Magnus Jedvert98d85fe2019-03-20 11:17:02 +0100187 * Explicitly create a root EGl 1.0 context with the specified config attributes and shared
188 * context.
magjedb04646f2017-04-21 01:34:12 -0700189 */
Magnus Jedvert98d85fe2019-03-20 11:17:02 +0100190 public static EglBase10 createEgl10(EglBase10.Context sharedContext, int[] configAttributes) {
191 return new EglBase10Impl(
192 sharedContext == null ? null : sharedContext.getRawContext(), configAttributes);
magjedb04646f2017-04-21 01:34:12 -0700193 }
194
195 /**
deadbeefa615e172017-05-25 10:11:25 -0700196 * Explicitly create a root EGl 1.0 context with the specified config attributes
197 * and shared context.
198 */
Magnus Jedvert98d85fe2019-03-20 11:17:02 +0100199 public static EglBase10 createEgl10(
deadbeefa615e172017-05-25 10:11:25 -0700200 javax.microedition.khronos.egl.EGLContext sharedContext, int[] configAttributes) {
Magnus Jedvert98d85fe2019-03-20 11:17:02 +0100201 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);
deadbeefa615e172017-05-25 10:11:25 -0700207 }
208
209 /**
Magnus Jedvert98d85fe2019-03-20 11:17:02 +0100210 * Explicitly create a root EGl 1.4 context with the specified config attributes and shared
211 * context.
magjedb04646f2017-04-21 01:34:12 -0700212 */
Magnus Jedvert98d85fe2019-03-20 11:17:02 +0100213 public static EglBase14 createEgl14(EglBase14.Context sharedContext, int[] configAttributes) {
214 return new EglBase14Impl(
215 sharedContext == null ? null : sharedContext.getRawContext(), configAttributes);
magjedb04646f2017-04-21 01:34:12 -0700216 }
217
deadbeefa615e172017-05-25 10:11:25 -0700218 /**
219 * Explicitly create a root EGl 1.4 context with the specified config attributes
220 * and shared context.
221 */
Magnus Jedvert98d85fe2019-03-20 11:17:02 +0100222 public static EglBase14 createEgl14(
deadbeefa615e172017-05-25 10:11:25 -0700223 android.opengl.EGLContext sharedContext, int[] configAttributes) {
Magnus Jedvert98d85fe2019-03-20 11:17:02 +0100224 return new EglBase14Impl(sharedContext, configAttributes);
deadbeefa615e172017-05-25 10:11:25 -0700225 }
226
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100227 void createSurface(Surface surface);
Magnus Jedvert1ab271c2015-09-28 11:05:44 +0200228
229 // Create EGLSurface from the Android SurfaceTexture.
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100230 void createSurface(SurfaceTexture surfaceTexture);
Magnus Jedvert80cf97c2015-06-11 10:08:59 +0200231
232 // Create dummy 1x1 pixel buffer surface so the context can be made current.
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100233 void createDummyPbufferSurface();
magjedb28678c2015-07-26 05:17:19 -0700234
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100235 void createPbufferSurface(int width, int height);
Magnus Jedvert80cf97c2015-06-11 10:08:59 +0200236
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100237 Context getEglBaseContext();
Magnus Jedvert80cf97c2015-06-11 10:08:59 +0200238
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100239 boolean hasSurface();
Magnus Jedvert80cf97c2015-06-11 10:08:59 +0200240
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100241 int surfaceWidth();
Magnus Jedvertd476b952015-08-20 09:58:31 +0200242
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100243 int surfaceHeight();
Magnus Jedvertd476b952015-08-20 09:58:31 +0200244
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100245 void releaseSurface();
Magnus Jedvert80cf97c2015-06-11 10:08:59 +0200246
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100247 void release();
Magnus Jedvert80cf97c2015-06-11 10:08:59 +0200248
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100249 void makeCurrent();
Magnus Jedvert80cf97c2015-06-11 10:08:59 +0200250
Magnus Jedvert4ae28a12015-09-15 09:44:07 +0200251 // Detach the current EGL context, so that it can be made current on another thread.
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100252 void detachCurrent();
Magnus Jedvert4ae28a12015-09-15 09:44:07 +0200253
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100254 void swapBuffers();
magjed47815522017-08-25 06:28:00 -0700255
Sami Kalliomäkib9f3f9b2017-11-30 11:23:33 +0100256 void swapBuffers(long presentationTimeStampNs);
Magnus Jedvert80cf97c2015-06-11 10:08:59 +0200257}