OLD | NEW |
(Empty) | |
| 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.graphics.Canvas; |
| 31 import android.graphics.SurfaceTexture; |
| 32 import android.graphics.Rect; |
| 33 import android.view.Surface; |
| 34 import android.view.SurfaceHolder; |
| 35 |
| 36 import javax.microedition.khronos.egl.EGL10; |
| 37 import javax.microedition.khronos.egl.EGLConfig; |
| 38 import javax.microedition.khronos.egl.EGLContext; |
| 39 import javax.microedition.khronos.egl.EGLDisplay; |
| 40 import javax.microedition.khronos.egl.EGLSurface; |
| 41 |
| 42 /** |
| 43 * Holds EGL state and utility methods for handling an egl 1.0 EGLContext, an EG
LDisplay, |
| 44 * and an EGLSurface. |
| 45 */ |
| 46 final class EglBase10 extends EglBase { |
| 47 // This constant is taken from EGL14.EGL_CONTEXT_CLIENT_VERSION. |
| 48 private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; |
| 49 |
| 50 private final EGL10 egl; |
| 51 private EGLContext eglContext; |
| 52 private EGLConfig eglConfig; |
| 53 private EGLDisplay eglDisplay; |
| 54 private EGLSurface eglSurface = EGL10.EGL_NO_SURFACE; |
| 55 |
| 56 // EGL wrapper for an actual EGLContext. |
| 57 public static class Context extends EglBase.Context { |
| 58 private final EGLContext eglContext; |
| 59 |
| 60 public Context(EGLContext eglContext) { |
| 61 this.eglContext = eglContext; |
| 62 } |
| 63 } |
| 64 |
| 65 // Create a new context with the specified config type, sharing data with shar
edContext. |
| 66 EglBase10(Context sharedContext, int[] configAttributes) { |
| 67 this.egl = (EGL10) EGLContext.getEGL(); |
| 68 eglDisplay = getEglDisplay(); |
| 69 eglConfig = getEglConfig(eglDisplay, configAttributes); |
| 70 eglContext = createEglContext(sharedContext, eglDisplay, eglConfig); |
| 71 } |
| 72 |
| 73 @Override |
| 74 public void createSurface(Surface surface) { |
| 75 /** |
| 76 * We have to wrap Surface in a SurfaceHolder because for some reason eglCre
ateWindowSurface |
| 77 * couldn't actually take a Surface object until API 17. Older versions fort
unately just call |
| 78 * SurfaceHolder.getSurface(), so we'll do that. No other methods are releva
nt. |
| 79 */ |
| 80 class FakeSurfaceHolder implements SurfaceHolder { |
| 81 private final Surface surface; |
| 82 |
| 83 FakeSurfaceHolder(Surface surface) { |
| 84 this.surface = surface; |
| 85 } |
| 86 |
| 87 @Override |
| 88 public void addCallback(Callback callback) {} |
| 89 |
| 90 @Override |
| 91 public void removeCallback(Callback callback) {} |
| 92 |
| 93 @Override |
| 94 public boolean isCreating() { |
| 95 return false; |
| 96 } |
| 97 |
| 98 @Deprecated |
| 99 @Override |
| 100 public void setType(int i) {} |
| 101 |
| 102 @Override |
| 103 public void setFixedSize(int i, int i2) {} |
| 104 |
| 105 @Override |
| 106 public void setSizeFromLayout() {} |
| 107 |
| 108 @Override |
| 109 public void setFormat(int i) {} |
| 110 |
| 111 @Override |
| 112 public void setKeepScreenOn(boolean b) {} |
| 113 |
| 114 @Override |
| 115 public Canvas lockCanvas() { |
| 116 return null; |
| 117 } |
| 118 |
| 119 @Override |
| 120 public Canvas lockCanvas(Rect rect) { |
| 121 return null; |
| 122 } |
| 123 |
| 124 @Override |
| 125 public void unlockCanvasAndPost(Canvas canvas) {} |
| 126 |
| 127 @Override |
| 128 public Rect getSurfaceFrame() { |
| 129 return null; |
| 130 } |
| 131 |
| 132 @Override |
| 133 public Surface getSurface() { |
| 134 return surface; |
| 135 } |
| 136 } |
| 137 |
| 138 createSurfaceInternal(new FakeSurfaceHolder(surface)); |
| 139 } |
| 140 |
| 141 // Create EGLSurface from the Android SurfaceTexture. |
| 142 @Override |
| 143 public void createSurface(SurfaceTexture surfaceTexture) { |
| 144 createSurfaceInternal(surfaceTexture); |
| 145 } |
| 146 |
| 147 // Create EGLSurface from either a SurfaceHolder or a SurfaceTexture. |
| 148 private void createSurfaceInternal(Object nativeWindow) { |
| 149 if (!(nativeWindow instanceof SurfaceHolder) && !(nativeWindow instanceof Su
rfaceTexture)) { |
| 150 throw new IllegalStateException("Input must be either a SurfaceHolder or S
urfaceTexture"); |
| 151 } |
| 152 checkIsNotReleased(); |
| 153 if (eglSurface != EGL10.EGL_NO_SURFACE) { |
| 154 throw new RuntimeException("Already has an EGLSurface"); |
| 155 } |
| 156 int[] surfaceAttribs = {EGL10.EGL_NONE}; |
| 157 eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, nativeWindow,
surfaceAttribs); |
| 158 if (eglSurface == EGL10.EGL_NO_SURFACE) { |
| 159 throw new RuntimeException("Failed to create window surface"); |
| 160 } |
| 161 } |
| 162 |
| 163 // Create dummy 1x1 pixel buffer surface so the context can be made current. |
| 164 @Override |
| 165 public void createDummyPbufferSurface() { |
| 166 createPbufferSurface(1, 1); |
| 167 } |
| 168 |
| 169 @Override |
| 170 public void createPbufferSurface(int width, int height) { |
| 171 checkIsNotReleased(); |
| 172 if (eglSurface != EGL10.EGL_NO_SURFACE) { |
| 173 throw new RuntimeException("Already has an EGLSurface"); |
| 174 } |
| 175 int[] surfaceAttribs = {EGL10.EGL_WIDTH, width, EGL10.EGL_HEIGHT, height, EG
L10.EGL_NONE}; |
| 176 eglSurface = egl.eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttri
bs); |
| 177 if (eglSurface == EGL10.EGL_NO_SURFACE) { |
| 178 throw new RuntimeException("Failed to create pixel buffer surface"); |
| 179 } |
| 180 } |
| 181 |
| 182 @Override |
| 183 public org.webrtc.EglBase.Context getEglBaseContext() { |
| 184 return new EglBase10.Context(eglContext); |
| 185 } |
| 186 |
| 187 @Override |
| 188 public boolean hasSurface() { |
| 189 return eglSurface != EGL10.EGL_NO_SURFACE; |
| 190 } |
| 191 |
| 192 @Override |
| 193 public int surfaceWidth() { |
| 194 final int widthArray[] = new int[1]; |
| 195 egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_WIDTH, widthArray); |
| 196 return widthArray[0]; |
| 197 } |
| 198 |
| 199 @Override |
| 200 public int surfaceHeight() { |
| 201 final int heightArray[] = new int[1]; |
| 202 egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_HEIGHT, heightArray); |
| 203 return heightArray[0]; |
| 204 } |
| 205 |
| 206 @Override |
| 207 public void releaseSurface() { |
| 208 if (eglSurface != EGL10.EGL_NO_SURFACE) { |
| 209 egl.eglDestroySurface(eglDisplay, eglSurface); |
| 210 eglSurface = EGL10.EGL_NO_SURFACE; |
| 211 } |
| 212 } |
| 213 |
| 214 private void checkIsNotReleased() { |
| 215 if (eglDisplay == EGL10.EGL_NO_DISPLAY || eglContext == EGL10.EGL_NO_CONTEXT |
| 216 || eglConfig == null) { |
| 217 throw new RuntimeException("This object has been released"); |
| 218 } |
| 219 } |
| 220 |
| 221 @Override |
| 222 public void release() { |
| 223 checkIsNotReleased(); |
| 224 releaseSurface(); |
| 225 detachCurrent(); |
| 226 egl.eglDestroyContext(eglDisplay, eglContext); |
| 227 egl.eglTerminate(eglDisplay); |
| 228 eglContext = EGL10.EGL_NO_CONTEXT; |
| 229 eglDisplay = EGL10.EGL_NO_DISPLAY; |
| 230 eglConfig = null; |
| 231 } |
| 232 |
| 233 @Override |
| 234 public void makeCurrent() { |
| 235 checkIsNotReleased(); |
| 236 if (eglSurface == EGL10.EGL_NO_SURFACE) { |
| 237 throw new RuntimeException("No EGLSurface - can't make current"); |
| 238 } |
| 239 if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { |
| 240 throw new RuntimeException("eglMakeCurrent failed"); |
| 241 } |
| 242 } |
| 243 |
| 244 // Detach the current EGL context, so that it can be made current on another t
hread. |
| 245 @Override |
| 246 public void detachCurrent() { |
| 247 if (!egl.eglMakeCurrent( |
| 248 eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CON
TEXT)) { |
| 249 throw new RuntimeException("eglMakeCurrent failed"); |
| 250 } |
| 251 } |
| 252 |
| 253 @Override |
| 254 public void swapBuffers() { |
| 255 checkIsNotReleased(); |
| 256 if (eglSurface == EGL10.EGL_NO_SURFACE) { |
| 257 throw new RuntimeException("No EGLSurface - can't swap buffers"); |
| 258 } |
| 259 egl.eglSwapBuffers(eglDisplay, eglSurface); |
| 260 } |
| 261 |
| 262 // Return an EGLDisplay, or die trying. |
| 263 private EGLDisplay getEglDisplay() { |
| 264 EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); |
| 265 if (eglDisplay == EGL10.EGL_NO_DISPLAY) { |
| 266 throw new RuntimeException("Unable to get EGL10 display"); |
| 267 } |
| 268 int[] version = new int[2]; |
| 269 if (!egl.eglInitialize(eglDisplay, version)) { |
| 270 throw new RuntimeException("Unable to initialize EGL10"); |
| 271 } |
| 272 return eglDisplay; |
| 273 } |
| 274 |
| 275 // Return an EGLConfig, or die trying. |
| 276 private EGLConfig getEglConfig(EGLDisplay eglDisplay, int[] configAttributes)
{ |
| 277 EGLConfig[] configs = new EGLConfig[1]; |
| 278 int[] numConfigs = new int[1]; |
| 279 if (!egl.eglChooseConfig( |
| 280 eglDisplay, configAttributes, configs, configs.length, numConfigs)) { |
| 281 throw new RuntimeException("Unable to find any matching EGL config"); |
| 282 } |
| 283 return configs[0]; |
| 284 } |
| 285 |
| 286 // Return an EGLConfig, or die trying. |
| 287 private EGLContext createEglContext( |
| 288 Context sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) { |
| 289 int[] contextAttributes = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE}; |
| 290 EGLContext rootContext = |
| 291 sharedContext == null ? EGL10.EGL_NO_CONTEXT : sharedContext.eglContext; |
| 292 EGLContext eglContext = |
| 293 egl.eglCreateContext(eglDisplay, eglConfig, rootContext, contextAttribut
es); |
| 294 if (eglContext == EGL10.EGL_NO_CONTEXT) { |
| 295 throw new RuntimeException("Failed to create EGL context"); |
| 296 } |
| 297 return eglContext; |
| 298 } |
| 299 } |
OLD | NEW |