1 /* 2 * libjingle 3 * Copyright 2015 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 package org.webrtc; 29 30 import android.annotation.TargetApi; 31 import android.graphics.SurfaceTexture; 32 import android.opengl.EGL14; 33 import android.opengl.EGLConfig; 34 import android.opengl.EGLContext; 35 import android.opengl.EGLDisplay; 36 import android.opengl.EGLExt; 37 import android.opengl.EGLSurface; 38 import android.view.Surface; 39 40 import org.webrtc.Logging; 41 42 /** 43 * Holds EGL state and utility methods for handling an EGL14 EGLContext, an EGLDisplay, 44 * and an EGLSurface. 45 */ 46 @TargetApi(18) 47 final class EglBase14 extends EglBase { 48 private static final String TAG = "EglBase14"; 49 private static final int EGLExt_SDK_VERSION = android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; 50 private static final int CURRENT_SDK_VERSION = android.os.Build.VERSION.SDK_INT; 51 private EGLContext eglContext; 52 private EGLConfig eglConfig; 53 private EGLDisplay eglDisplay; 54 private EGLSurface eglSurface = EGL14.EGL_NO_SURFACE; 55 56 // EGL 1.4 is supported from API 17. But EGLExt that is used for setting presentation 57 // time stamp on a surface is supported from 18 so we require 18. isEGL14Supported()58 public static boolean isEGL14Supported() { 59 Logging.d(TAG, "SDK version: " + CURRENT_SDK_VERSION 60 + ". isEGL14Supported: " + (CURRENT_SDK_VERSION >= EGLExt_SDK_VERSION)); 61 return (CURRENT_SDK_VERSION >= EGLExt_SDK_VERSION); 62 } 63 64 public static class Context extends EglBase.Context { 65 private final android.opengl.EGLContext egl14Context; 66 Context(android.opengl.EGLContext eglContext)67 Context(android.opengl.EGLContext eglContext) { 68 this.egl14Context = eglContext; 69 } 70 } 71 72 // Create a new context with the specified config type, sharing data with sharedContext. 73 // |sharedContext| may be null. EglBase14(EglBase14.Context sharedContext, int[] configAttributes)74 EglBase14(EglBase14.Context sharedContext, int[] configAttributes) { 75 eglDisplay = getEglDisplay(); 76 eglConfig = getEglConfig(eglDisplay, configAttributes); 77 eglContext = createEglContext(sharedContext, eglDisplay, eglConfig); 78 } 79 80 // Create EGLSurface from the Android Surface. 81 @Override createSurface(Surface surface)82 public void createSurface(Surface surface) { 83 createSurfaceInternal(surface); 84 } 85 86 // Create EGLSurface from the Android SurfaceTexture. 87 @Override createSurface(SurfaceTexture surfaceTexture)88 public void createSurface(SurfaceTexture surfaceTexture) { 89 createSurfaceInternal(surfaceTexture); 90 } 91 92 // Create EGLSurface from either Surface or SurfaceTexture. createSurfaceInternal(Object surface)93 private void createSurfaceInternal(Object surface) { 94 if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture)) { 95 throw new IllegalStateException("Input must be either a Surface or SurfaceTexture"); 96 } 97 checkIsNotReleased(); 98 if (eglSurface != EGL14.EGL_NO_SURFACE) { 99 throw new RuntimeException("Already has an EGLSurface"); 100 } 101 int[] surfaceAttribs = {EGL14.EGL_NONE}; 102 eglSurface = EGL14.eglCreateWindowSurface(eglDisplay, eglConfig, surface, surfaceAttribs, 0); 103 if (eglSurface == EGL14.EGL_NO_SURFACE) { 104 throw new RuntimeException("Failed to create window surface"); 105 } 106 } 107 108 @Override createDummyPbufferSurface()109 public void createDummyPbufferSurface() { 110 createPbufferSurface(1, 1); 111 } 112 113 @Override createPbufferSurface(int width, int height)114 public void createPbufferSurface(int width, int height) { 115 checkIsNotReleased(); 116 if (eglSurface != EGL14.EGL_NO_SURFACE) { 117 throw new RuntimeException("Already has an EGLSurface"); 118 } 119 int[] surfaceAttribs = {EGL14.EGL_WIDTH, width, EGL14.EGL_HEIGHT, height, EGL14.EGL_NONE}; 120 eglSurface = EGL14.eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttribs, 0); 121 if (eglSurface == EGL14.EGL_NO_SURFACE) { 122 throw new RuntimeException("Failed to create pixel buffer surface"); 123 } 124 } 125 126 @Override getEglBaseContext()127 public Context getEglBaseContext() { 128 return new EglBase14.Context(eglContext); 129 } 130 131 @Override hasSurface()132 public boolean hasSurface() { 133 return eglSurface != EGL14.EGL_NO_SURFACE; 134 } 135 136 @Override surfaceWidth()137 public int surfaceWidth() { 138 final int widthArray[] = new int[1]; 139 EGL14.eglQuerySurface(eglDisplay, eglSurface, EGL14.EGL_WIDTH, widthArray, 0); 140 return widthArray[0]; 141 } 142 143 @Override surfaceHeight()144 public int surfaceHeight() { 145 final int heightArray[] = new int[1]; 146 EGL14.eglQuerySurface(eglDisplay, eglSurface, EGL14.EGL_HEIGHT, heightArray, 0); 147 return heightArray[0]; 148 } 149 150 @Override releaseSurface()151 public void releaseSurface() { 152 if (eglSurface != EGL14.EGL_NO_SURFACE) { 153 EGL14.eglDestroySurface(eglDisplay, eglSurface); 154 eglSurface = EGL14.EGL_NO_SURFACE; 155 } 156 } 157 checkIsNotReleased()158 private void checkIsNotReleased() { 159 if (eglDisplay == EGL14.EGL_NO_DISPLAY || eglContext == EGL14.EGL_NO_CONTEXT 160 || eglConfig == null) { 161 throw new RuntimeException("This object has been released"); 162 } 163 } 164 165 @Override release()166 public void release() { 167 checkIsNotReleased(); 168 releaseSurface(); 169 detachCurrent(); 170 EGL14.eglDestroyContext(eglDisplay, eglContext); 171 EGL14.eglReleaseThread(); 172 EGL14.eglTerminate(eglDisplay); 173 eglContext = EGL14.EGL_NO_CONTEXT; 174 eglDisplay = EGL14.EGL_NO_DISPLAY; 175 eglConfig = null; 176 } 177 178 @Override makeCurrent()179 public void makeCurrent() { 180 checkIsNotReleased(); 181 if (eglSurface == EGL14.EGL_NO_SURFACE) { 182 throw new RuntimeException("No EGLSurface - can't make current"); 183 } 184 if (!EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { 185 throw new RuntimeException("eglMakeCurrent failed"); 186 } 187 } 188 189 // Detach the current EGL context, so that it can be made current on another thread. 190 @Override detachCurrent()191 public void detachCurrent() { 192 if (!EGL14.eglMakeCurrent( 193 eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) { 194 throw new RuntimeException("eglMakeCurrent failed"); 195 } 196 } 197 198 @Override swapBuffers()199 public void swapBuffers() { 200 checkIsNotReleased(); 201 if (eglSurface == EGL14.EGL_NO_SURFACE) { 202 throw new RuntimeException("No EGLSurface - can't swap buffers"); 203 } 204 EGL14.eglSwapBuffers(eglDisplay, eglSurface); 205 } 206 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 // See https://android.googlesource.com/platform/frameworks/native/+/tools_r22.2/opengl/specs/EGL_ANDROID_presentation_time.txt 213 EGLExt.eglPresentationTimeANDROID(eglDisplay, eglSurface, timeStampNs); 214 EGL14.eglSwapBuffers(eglDisplay, eglSurface); 215 } 216 217 // Return an EGLDisplay, or die trying. getEglDisplay()218 private static EGLDisplay getEglDisplay() { 219 EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); 220 if (eglDisplay == EGL14.EGL_NO_DISPLAY) { 221 throw new RuntimeException("Unable to get EGL14 display"); 222 } 223 int[] version = new int[2]; 224 if (!EGL14.eglInitialize(eglDisplay, version, 0, version, 1)) { 225 throw new RuntimeException("Unable to initialize EGL14"); 226 } 227 return eglDisplay; 228 } 229 230 // Return an EGLConfig, or die trying. getEglConfig(EGLDisplay eglDisplay, int[] configAttributes)231 private static EGLConfig getEglConfig(EGLDisplay eglDisplay, int[] configAttributes) { 232 EGLConfig[] configs = new EGLConfig[1]; 233 int[] numConfigs = new int[1]; 234 if (!EGL14.eglChooseConfig( 235 eglDisplay, configAttributes, 0, configs, 0, configs.length, numConfigs, 0)) { 236 throw new RuntimeException("Unable to find any matching EGL config"); 237 } 238 return configs[0]; 239 } 240 241 // Return an EGLConfig, or die trying. createEglContext( EglBase14.Context sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig)242 private static EGLContext createEglContext( 243 EglBase14.Context sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) { 244 int[] contextAttributes = {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE}; 245 EGLContext rootContext = 246 sharedContext == null ? EGL14.EGL_NO_CONTEXT : sharedContext.egl14Context; 247 EGLContext eglContext = 248 EGL14.eglCreateContext(eglDisplay, eglConfig, rootContext, contextAttributes, 0); 249 if (eglContext == EGL14.EGL_NO_CONTEXT) { 250 throw new RuntimeException("Failed to create EGL context"); 251 } 252 return eglContext; 253 } 254 } 255