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.opengl.EGL14; 15 import android.opengl.EGLConfig; 16 import android.opengl.EGLContext; 17 import android.opengl.EGLDisplay; 18 import android.opengl.EGLExt; 19 import android.opengl.EGLSurface; 20 import android.opengl.GLException; 21 import android.os.Build; 22 import android.view.Surface; 23 import androidx.annotation.Nullable; 24 import org.webrtc.EglBase; 25 26 /** 27 * Holds EGL state and utility methods for handling an EGL14 EGLContext, an EGLDisplay, 28 * and an EGLSurface. 29 */ 30 @SuppressWarnings("ReferenceEquality") // We want to compare to EGL14 constants. 31 class EglBase14Impl implements EglBase14 { 32 private static final String TAG = "EglBase14Impl"; 33 private EGLContext eglContext; 34 @Nullable private EGLConfig eglConfig; 35 private EGLDisplay eglDisplay; 36 private EGLSurface eglSurface = EGL14.EGL_NO_SURFACE; 37 38 public static class Context implements EglBase14.Context { 39 private final EGLContext egl14Context; 40 41 @Override getRawContext()42 public EGLContext getRawContext() { 43 return egl14Context; 44 } 45 46 @Override getNativeEglContext()47 public long getNativeEglContext() { 48 return egl14Context.getNativeHandle(); 49 } 50 Context(android.opengl.EGLContext eglContext)51 public Context(android.opengl.EGLContext eglContext) { 52 this.egl14Context = eglContext; 53 } 54 } 55 56 // Create a new context with the specified config type, sharing data with sharedContext. 57 // `sharedContext` may be null. EglBase14Impl(EGLContext sharedContext, int[] configAttributes)58 public EglBase14Impl(EGLContext sharedContext, int[] configAttributes) { 59 eglDisplay = getEglDisplay(); 60 eglConfig = getEglConfig(eglDisplay, configAttributes); 61 final int openGlesVersion = EglBase.getOpenGlesVersionFromConfig(configAttributes); 62 Logging.d(TAG, "Using OpenGL ES version " + openGlesVersion); 63 eglContext = createEglContext(sharedContext, eglDisplay, eglConfig, openGlesVersion); 64 } 65 66 // Create EGLSurface from the Android Surface. 67 @Override createSurface(Surface surface)68 public void createSurface(Surface surface) { 69 createSurfaceInternal(surface); 70 } 71 72 // Create EGLSurface from the Android SurfaceTexture. 73 @Override createSurface(SurfaceTexture surfaceTexture)74 public void createSurface(SurfaceTexture surfaceTexture) { 75 createSurfaceInternal(surfaceTexture); 76 } 77 78 // Create EGLSurface from either Surface or SurfaceTexture. createSurfaceInternal(Object surface)79 private void createSurfaceInternal(Object surface) { 80 if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture)) { 81 throw new IllegalStateException("Input must be either a Surface or SurfaceTexture"); 82 } 83 checkIsNotReleased(); 84 if (eglSurface != EGL14.EGL_NO_SURFACE) { 85 throw new RuntimeException("Already has an EGLSurface"); 86 } 87 int[] surfaceAttribs = {EGL14.EGL_NONE}; 88 eglSurface = EGL14.eglCreateWindowSurface(eglDisplay, eglConfig, surface, surfaceAttribs, 0); 89 if (eglSurface == EGL14.EGL_NO_SURFACE) { 90 throw new GLException(EGL14.eglGetError(), 91 "Failed to create window surface: 0x" + Integer.toHexString(EGL14.eglGetError())); 92 } 93 } 94 95 @Override createDummyPbufferSurface()96 public void createDummyPbufferSurface() { 97 createPbufferSurface(1, 1); 98 } 99 100 @Override createPbufferSurface(int width, int height)101 public void createPbufferSurface(int width, int height) { 102 checkIsNotReleased(); 103 if (eglSurface != EGL14.EGL_NO_SURFACE) { 104 throw new RuntimeException("Already has an EGLSurface"); 105 } 106 int[] surfaceAttribs = {EGL14.EGL_WIDTH, width, EGL14.EGL_HEIGHT, height, EGL14.EGL_NONE}; 107 eglSurface = EGL14.eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttribs, 0); 108 if (eglSurface == EGL14.EGL_NO_SURFACE) { 109 throw new GLException(EGL14.eglGetError(), 110 "Failed to create pixel buffer surface with size " + width + "x" + height + ": 0x" 111 + Integer.toHexString(EGL14.eglGetError())); 112 } 113 } 114 115 @Override getEglBaseContext()116 public Context getEglBaseContext() { 117 return new Context(eglContext); 118 } 119 120 @Override hasSurface()121 public boolean hasSurface() { 122 return eglSurface != EGL14.EGL_NO_SURFACE; 123 } 124 125 @Override surfaceWidth()126 public int surfaceWidth() { 127 final int widthArray[] = new int[1]; 128 EGL14.eglQuerySurface(eglDisplay, eglSurface, EGL14.EGL_WIDTH, widthArray, 0); 129 return widthArray[0]; 130 } 131 132 @Override surfaceHeight()133 public int surfaceHeight() { 134 final int heightArray[] = new int[1]; 135 EGL14.eglQuerySurface(eglDisplay, eglSurface, EGL14.EGL_HEIGHT, heightArray, 0); 136 return heightArray[0]; 137 } 138 139 @Override releaseSurface()140 public void releaseSurface() { 141 if (eglSurface != EGL14.EGL_NO_SURFACE) { 142 EGL14.eglDestroySurface(eglDisplay, eglSurface); 143 eglSurface = EGL14.EGL_NO_SURFACE; 144 } 145 } 146 checkIsNotReleased()147 private void checkIsNotReleased() { 148 if (eglDisplay == EGL14.EGL_NO_DISPLAY || eglContext == EGL14.EGL_NO_CONTEXT 149 || eglConfig == null) { 150 throw new RuntimeException("This object has been released"); 151 } 152 } 153 154 @Override release()155 public void release() { 156 checkIsNotReleased(); 157 releaseSurface(); 158 detachCurrent(); 159 synchronized (EglBase.lock) { 160 EGL14.eglDestroyContext(eglDisplay, eglContext); 161 } 162 EGL14.eglReleaseThread(); 163 EGL14.eglTerminate(eglDisplay); 164 eglContext = EGL14.EGL_NO_CONTEXT; 165 eglDisplay = EGL14.EGL_NO_DISPLAY; 166 eglConfig = null; 167 } 168 169 @Override makeCurrent()170 public void makeCurrent() { 171 checkIsNotReleased(); 172 if (eglSurface == EGL14.EGL_NO_SURFACE) { 173 throw new RuntimeException("No EGLSurface - can't make current"); 174 } 175 synchronized (EglBase.lock) { 176 if (!EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { 177 throw new GLException(EGL14.eglGetError(), 178 "eglMakeCurrent failed: 0x" + Integer.toHexString(EGL14.eglGetError())); 179 } 180 } 181 } 182 183 // Detach the current EGL context, so that it can be made current on another thread. 184 @Override detachCurrent()185 public void detachCurrent() { 186 synchronized (EglBase.lock) { 187 if (!EGL14.eglMakeCurrent( 188 eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) { 189 throw new GLException(EGL14.eglGetError(), 190 "eglDetachCurrent failed: 0x" + Integer.toHexString(EGL14.eglGetError())); 191 } 192 } 193 } 194 195 @Override swapBuffers()196 public void swapBuffers() { 197 checkIsNotReleased(); 198 if (eglSurface == EGL14.EGL_NO_SURFACE) { 199 throw new RuntimeException("No EGLSurface - can't swap buffers"); 200 } 201 synchronized (EglBase.lock) { 202 EGL14.eglSwapBuffers(eglDisplay, eglSurface); 203 } 204 } 205 206 @Override swapBuffers(long timeStampNs)207 public void swapBuffers(long timeStampNs) { 208 checkIsNotReleased(); 209 if (eglSurface == EGL14.EGL_NO_SURFACE) { 210 throw new RuntimeException("No EGLSurface - can't swap buffers"); 211 } 212 synchronized (EglBase.lock) { 213 // See 214 // https://android.googlesource.com/platform/frameworks/native/+/tools_r22.2/opengl/specs/EGL_ANDROID_presentation_time.txt 215 EGLExt.eglPresentationTimeANDROID(eglDisplay, eglSurface, timeStampNs); 216 EGL14.eglSwapBuffers(eglDisplay, eglSurface); 217 } 218 } 219 220 // Return an EGLDisplay, or die trying. getEglDisplay()221 private static EGLDisplay getEglDisplay() { 222 EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); 223 if (eglDisplay == EGL14.EGL_NO_DISPLAY) { 224 throw new GLException(EGL14.eglGetError(), 225 "Unable to get EGL14 display: 0x" + Integer.toHexString(EGL14.eglGetError())); 226 } 227 int[] version = new int[2]; 228 if (!EGL14.eglInitialize(eglDisplay, version, 0, version, 1)) { 229 throw new GLException(EGL14.eglGetError(), 230 "Unable to initialize EGL14: 0x" + Integer.toHexString(EGL14.eglGetError())); 231 } 232 return eglDisplay; 233 } 234 235 // Return an EGLConfig, or die trying. getEglConfig(EGLDisplay eglDisplay, int[] configAttributes)236 private static EGLConfig getEglConfig(EGLDisplay eglDisplay, int[] configAttributes) { 237 EGLConfig[] configs = new EGLConfig[1]; 238 int[] numConfigs = new int[1]; 239 if (!EGL14.eglChooseConfig( 240 eglDisplay, configAttributes, 0, configs, 0, configs.length, numConfigs, 0)) { 241 throw new GLException(EGL14.eglGetError(), 242 "eglChooseConfig failed: 0x" + Integer.toHexString(EGL14.eglGetError())); 243 } 244 if (numConfigs[0] <= 0) { 245 throw new RuntimeException("Unable to find any matching EGL config"); 246 } 247 final EGLConfig eglConfig = configs[0]; 248 if (eglConfig == null) { 249 throw new RuntimeException("eglChooseConfig returned null"); 250 } 251 return eglConfig; 252 } 253 254 // Return an EGLConfig, or die trying. createEglContext(@ullable EGLContext sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig, int openGlesVersion)255 private static EGLContext createEglContext(@Nullable EGLContext sharedContext, 256 EGLDisplay eglDisplay, EGLConfig eglConfig, int openGlesVersion) { 257 if (sharedContext != null && sharedContext == EGL14.EGL_NO_CONTEXT) { 258 throw new RuntimeException("Invalid sharedContext"); 259 } 260 int[] contextAttributes = {EGL14.EGL_CONTEXT_CLIENT_VERSION, openGlesVersion, EGL14.EGL_NONE}; 261 EGLContext rootContext = sharedContext == null ? EGL14.EGL_NO_CONTEXT : sharedContext; 262 final EGLContext eglContext; 263 synchronized (EglBase.lock) { 264 eglContext = EGL14.eglCreateContext(eglDisplay, eglConfig, rootContext, contextAttributes, 0); 265 } 266 if (eglContext == EGL14.EGL_NO_CONTEXT) { 267 throw new GLException(EGL14.eglGetError(), 268 "Failed to create EGL context: 0x" + Integer.toHexString(EGL14.eglGetError())); 269 } 270 return eglContext; 271 } 272 } 273