1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.power; 18 19 import java.io.PrintWriter; 20 import java.nio.ByteBuffer; 21 import java.nio.ByteOrder; 22 import java.nio.FloatBuffer; 23 24 import android.graphics.PixelFormat; 25 import android.graphics.SurfaceTexture; 26 import android.opengl.EGL14; 27 import android.opengl.EGLConfig; 28 import android.opengl.EGLContext; 29 import android.opengl.EGLDisplay; 30 import android.opengl.EGLSurface; 31 import android.opengl.GLES10; 32 import android.opengl.GLES11Ext; 33 import android.os.Looper; 34 import android.util.FloatMath; 35 import android.util.Slog; 36 import android.view.Display; 37 import android.view.DisplayInfo; 38 import android.view.Surface; 39 import android.view.SurfaceControl; 40 import android.view.SurfaceSession; 41 42 import com.android.server.display.DisplayManagerService; 43 import com.android.server.display.DisplayTransactionListener; 44 45 /** 46 * Bzzzoooop! *crackle* 47 * <p> 48 * Animates a screen transition from on to off or off to on by applying 49 * some GL transformations to a screenshot. 50 * </p><p> 51 * This component must only be created or accessed by the {@link Looper} thread 52 * that belongs to the {@link DisplayPowerController}. 53 * </p> 54 */ 55 final class ElectronBeam { 56 private static final String TAG = "ElectronBeam"; 57 58 private static final boolean DEBUG = false; 59 60 // The layer for the electron beam surface. 61 // This is currently hardcoded to be one layer above the boot animation. 62 private static final int ELECTRON_BEAM_LAYER = 0x40000001; 63 64 // The relative proportion of the animation to spend performing 65 // the horizontal stretch effect. The remainder is spent performing 66 // the vertical stretch effect. 67 private static final float HSTRETCH_DURATION = 0.5f; 68 private static final float VSTRETCH_DURATION = 1.0f - HSTRETCH_DURATION; 69 70 // The number of frames to draw when preparing the animation so that it will 71 // be ready to run smoothly. We use 3 frames because we are triple-buffered. 72 // See code for details. 73 private static final int DEJANK_FRAMES = 3; 74 75 // Set to true when the animation context has been fully prepared. 76 private boolean mPrepared; 77 private int mMode; 78 79 private final DisplayManagerService mDisplayManager; 80 private int mDisplayLayerStack; // layer stack associated with primary display 81 private int mDisplayWidth; // real width, not rotated 82 private int mDisplayHeight; // real height, not rotated 83 private SurfaceSession mSurfaceSession; 84 private SurfaceControl mSurfaceControl; 85 private Surface mSurface; 86 private NaturalSurfaceLayout mSurfaceLayout; 87 private EGLDisplay mEglDisplay; 88 private EGLConfig mEglConfig; 89 private EGLContext mEglContext; 90 private EGLSurface mEglSurface; 91 private boolean mSurfaceVisible; 92 private float mSurfaceAlpha; 93 94 // Texture names. We only use one texture, which contains the screenshot. 95 private final int[] mTexNames = new int[1]; 96 private boolean mTexNamesGenerated; 97 private float mTexMatrix[] = new float[16]; 98 99 // Vertex and corresponding texture coordinates. 100 // We have 4 2D vertices, so 8 elements. The vertices form a quad. 101 private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8); 102 private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8); 103 104 /** 105 * Animates an electron beam warming up. 106 */ 107 public static final int MODE_WARM_UP = 0; 108 109 /** 110 * Animates an electron beam shutting off. 111 */ 112 public static final int MODE_COOL_DOWN = 1; 113 114 /** 115 * Animates a simple dim layer to fade the contents of the screen in or out progressively. 116 */ 117 public static final int MODE_FADE = 2; 118 119 120 public ElectronBeam(DisplayManagerService displayManager) { 121 mDisplayManager = displayManager; 122 } 123 124 /** 125 * Warms up the electron beam in preparation for turning on or off. 126 * This method prepares a GL context, and captures a screen shot. 127 * 128 * @param mode The desired mode for the upcoming animation. 129 * @return True if the electron beam is ready, false if it is uncontrollable. 130 */ 131 public boolean prepare(int mode) { 132 if (DEBUG) { 133 Slog.d(TAG, "prepare: mode=" + mode); 134 } 135 136 mMode = mode; 137 138 // Get the display size and layer stack. 139 // This is not expected to change while the electron beam surface is showing. 140 DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY); 141 mDisplayLayerStack = displayInfo.layerStack; 142 mDisplayWidth = displayInfo.getNaturalWidth(); 143 mDisplayHeight = displayInfo.getNaturalHeight(); 144 145 // Prepare the surface for drawing. 146 if (!tryPrepare()) { 147 dismiss(); 148 return false; 149 } 150 151 // Done. 152 mPrepared = true; 153 154 // Dejanking optimization. 155 // Some GL drivers can introduce a lot of lag in the first few frames as they 156 // initialize their state and allocate graphics buffers for rendering. 157 // Work around this problem by rendering the first frame of the animation a few 158 // times. The rest of the animation should run smoothly thereafter. 159 // The frames we draw here aren't visible because we are essentially just 160 // painting the screenshot as-is. 161 if (mode == MODE_COOL_DOWN) { 162 for (int i = 0; i < DEJANK_FRAMES; i++) { 163 draw(1.0f); 164 } 165 } 166 return true; 167 } 168 169 private boolean tryPrepare() { 170 if (createSurface()) { 171 if (mMode == MODE_FADE) { 172 return true; 173 } 174 return createEglContext() 175 && createEglSurface() 176 && captureScreenshotTextureAndSetViewport(); 177 } 178 return false; 179 } 180 181 /** 182 * Dismisses the electron beam animation surface and cleans up. 183 * 184 * To prevent stray photons from leaking out after the electron beam has been 185 * turned off, it is a good idea to defer dismissing the animation until the 186 * electron beam has been turned back on fully. 187 */ 188 public void dismiss() { 189 if (DEBUG) { 190 Slog.d(TAG, "dismiss"); 191 } 192 193 destroyScreenshotTexture(); 194 destroyEglSurface(); 195 destroySurface(); 196 mPrepared = false; 197 } 198 199 /** 200 * Draws an animation frame showing the electron beam activated at the 201 * specified level. 202 * 203 * @param level The electron beam level. 204 * @return True if successful. 205 */ 206 public boolean draw(float level) { 207 if (DEBUG) { 208 Slog.d(TAG, "drawFrame: level=" + level); 209 } 210 211 if (!mPrepared) { 212 return false; 213 } 214 215 if (mMode == MODE_FADE) { 216 return showSurface(1.0f - level); 217 } 218 219 if (!attachEglContext()) { 220 return false; 221 } 222 try { 223 // Clear frame to solid black. 224 GLES10.glClearColor(0f, 0f, 0f, 1f); 225 GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT); 226 227 // Draw the frame. 228 if (level < HSTRETCH_DURATION) { 229 drawHStretch(1.0f - (level / HSTRETCH_DURATION)); 230 } else { 231 drawVStretch(1.0f - ((level - HSTRETCH_DURATION) / VSTRETCH_DURATION)); 232 } 233 if (checkGlErrors("drawFrame")) { 234 return false; 235 } 236 237 EGL14.eglSwapBuffers(mEglDisplay, mEglSurface); 238 } finally { 239 detachEglContext(); 240 } 241 return showSurface(1.0f); 242 } 243 244 /** 245 * Draws a frame where the content of the electron beam is collapsing inwards upon 246 * itself vertically with red / green / blue channels dispersing and eventually 247 * merging down to a single horizontal line. 248 * 249 * @param stretch The stretch factor. 0.0 is no collapse, 1.0 is full collapse. 250 */ 251 private void drawVStretch(float stretch) { 252 // compute interpolation scale factors for each color channel 253 final float ar = scurve(stretch, 7.5f); 254 final float ag = scurve(stretch, 8.0f); 255 final float ab = scurve(stretch, 8.5f); 256 if (DEBUG) { 257 Slog.d(TAG, "drawVStretch: stretch=" + stretch 258 + ", ar=" + ar + ", ag=" + ag + ", ab=" + ab); 259 } 260 261 // set blending 262 GLES10.glBlendFunc(GLES10.GL_ONE, GLES10.GL_ONE); 263 GLES10.glEnable(GLES10.GL_BLEND); 264 265 // bind vertex buffer 266 GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer); 267 GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY); 268 269 // set-up texturing 270 GLES10.glDisable(GLES10.GL_TEXTURE_2D); 271 GLES10.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES); 272 273 // bind texture and set blending for drawing planes 274 GLES10.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]); 275 GLES10.glTexEnvx(GLES10.GL_TEXTURE_ENV, GLES10.GL_TEXTURE_ENV_MODE, 276 mMode == MODE_WARM_UP ? GLES10.GL_MODULATE : GLES10.GL_REPLACE); 277 GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 278 GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR); 279 GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 280 GLES10.GL_TEXTURE_MIN_FILTER, GLES10.GL_LINEAR); 281 GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 282 GLES10.GL_TEXTURE_WRAP_S, GLES10.GL_CLAMP_TO_EDGE); 283 GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 284 GLES10.GL_TEXTURE_WRAP_T, GLES10.GL_CLAMP_TO_EDGE); 285 GLES10.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES); 286 GLES10.glTexCoordPointer(2, GLES10.GL_FLOAT, 0, mTexCoordBuffer); 287 GLES10.glEnableClientState(GLES10.GL_TEXTURE_COORD_ARRAY); 288 289 // draw the red plane 290 setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ar); 291 GLES10.glColorMask(true, false, false, true); 292 GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4); 293 294 // draw the green plane 295 setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag); 296 GLES10.glColorMask(false, true, false, true); 297 GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4); 298 299 // draw the blue plane 300 setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ab); 301 GLES10.glColorMask(false, false, true, true); 302 GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4); 303 304 // clean up after drawing planes 305 GLES10.glDisable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES); 306 GLES10.glDisableClientState(GLES10.GL_TEXTURE_COORD_ARRAY); 307 GLES10.glColorMask(true, true, true, true); 308 309 // draw the white highlight (we use the last vertices) 310 if (mMode == MODE_COOL_DOWN) { 311 GLES10.glColor4f(ag, ag, ag, 1.0f); 312 GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4); 313 } 314 315 // clean up 316 GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY); 317 GLES10.glDisable(GLES10.GL_BLEND); 318 } 319 320 /** 321 * Draws a frame where the electron beam has been stretched out into 322 * a thin white horizontal line that fades as it expands outwards. 323 * 324 * @param stretch The stretch factor. 0.0 is no stretch / no fade, 325 * 1.0 is maximum stretch / maximum fade. 326 */ 327 private void drawHStretch(float stretch) { 328 // compute interpolation scale factor 329 final float ag = scurve(stretch, 8.0f); 330 if (DEBUG) { 331 Slog.d(TAG, "drawHStretch: stretch=" + stretch + ", ag=" + ag); 332 } 333 334 if (stretch < 1.0f) { 335 // bind vertex buffer 336 GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer); 337 GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY); 338 339 // draw narrow fading white line 340 setHStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag); 341 GLES10.glColor4f(1.0f - ag, 1.0f - ag, 1.0f - ag, 1.0f); 342 GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4); 343 344 // clean up 345 GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY); 346 } 347 } 348 349 private static void setVStretchQuad(FloatBuffer vtx, float dw, float dh, float a) { 350 final float w = dw + (dw * a); 351 final float h = dh - (dh * a); 352 final float x = (dw - w) * 0.5f; 353 final float y = (dh - h) * 0.5f; 354 setQuad(vtx, x, y, w, h); 355 } 356 357 private static void setHStretchQuad(FloatBuffer vtx, float dw, float dh, float a) { 358 final float w = dw + (dw * a); 359 final float h = 1.0f; 360 final float x = (dw - w) * 0.5f; 361 final float y = (dh - h) * 0.5f; 362 setQuad(vtx, x, y, w, h); 363 } 364 365 private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) { 366 if (DEBUG) { 367 Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h); 368 } 369 vtx.put(0, x); 370 vtx.put(1, y); 371 vtx.put(2, x); 372 vtx.put(3, y + h); 373 vtx.put(4, x + w); 374 vtx.put(5, y + h); 375 vtx.put(6, x + w); 376 vtx.put(7, y); 377 } 378 379 private boolean captureScreenshotTextureAndSetViewport() { 380 if (!attachEglContext()) { 381 return false; 382 } 383 try { 384 if (!mTexNamesGenerated) { 385 GLES10.glGenTextures(1, mTexNames, 0); 386 if (checkGlErrors("glGenTextures")) { 387 return false; 388 } 389 mTexNamesGenerated = true; 390 } 391 392 final SurfaceTexture st = new SurfaceTexture(mTexNames[0]); 393 final Surface s = new Surface(st); 394 try { 395 SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay( 396 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), s); 397 } finally { 398 s.release(); 399 } 400 401 st.updateTexImage(); 402 st.getTransformMatrix(mTexMatrix); 403 404 // Set up texture coordinates for a quad. 405 // We might need to change this if the texture ends up being 406 // a different size from the display for some reason. 407 mTexCoordBuffer.put(0, 0f); mTexCoordBuffer.put(1, 0f); 408 mTexCoordBuffer.put(2, 0f); mTexCoordBuffer.put(3, 1f); 409 mTexCoordBuffer.put(4, 1f); mTexCoordBuffer.put(5, 1f); 410 mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f); 411 412 // Set up our viewport. 413 GLES10.glViewport(0, 0, mDisplayWidth, mDisplayHeight); 414 GLES10.glMatrixMode(GLES10.GL_PROJECTION); 415 GLES10.glLoadIdentity(); 416 GLES10.glOrthof(0, mDisplayWidth, 0, mDisplayHeight, 0, 1); 417 GLES10.glMatrixMode(GLES10.GL_MODELVIEW); 418 GLES10.glLoadIdentity(); 419 GLES10.glMatrixMode(GLES10.GL_TEXTURE); 420 GLES10.glLoadIdentity(); 421 GLES10.glLoadMatrixf(mTexMatrix, 0); 422 } finally { 423 detachEglContext(); 424 } 425 return true; 426 } 427 428 private void destroyScreenshotTexture() { 429 if (mTexNamesGenerated) { 430 mTexNamesGenerated = false; 431 if (attachEglContext()) { 432 try { 433 GLES10.glDeleteTextures(1, mTexNames, 0); 434 checkGlErrors("glDeleteTextures"); 435 } finally { 436 detachEglContext(); 437 } 438 } 439 } 440 } 441 442 private boolean createEglContext() { 443 if (mEglDisplay == null) { 444 mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); 445 if (mEglDisplay == EGL14.EGL_NO_DISPLAY) { 446 logEglError("eglGetDisplay"); 447 return false; 448 } 449 450 int[] version = new int[2]; 451 if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) { 452 mEglDisplay = null; 453 logEglError("eglInitialize"); 454 return false; 455 } 456 } 457 458 if (mEglConfig == null) { 459 int[] eglConfigAttribList = new int[] { 460 EGL14.EGL_RED_SIZE, 8, 461 EGL14.EGL_GREEN_SIZE, 8, 462 EGL14.EGL_BLUE_SIZE, 8, 463 EGL14.EGL_ALPHA_SIZE, 8, 464 EGL14.EGL_NONE 465 }; 466 int[] numEglConfigs = new int[1]; 467 EGLConfig[] eglConfigs = new EGLConfig[1]; 468 if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0, 469 eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) { 470 logEglError("eglChooseConfig"); 471 return false; 472 } 473 mEglConfig = eglConfigs[0]; 474 } 475 476 if (mEglContext == null) { 477 int[] eglContextAttribList = new int[] { 478 EGL14.EGL_NONE 479 }; 480 mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig, 481 EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0); 482 if (mEglContext == null) { 483 logEglError("eglCreateContext"); 484 return false; 485 } 486 } 487 return true; 488 } 489 490 /* not used because it is too expensive to create / destroy contexts all of the time 491 private void destroyEglContext() { 492 if (mEglContext != null) { 493 if (!EGL14.eglDestroyContext(mEglDisplay, mEglContext)) { 494 logEglError("eglDestroyContext"); 495 } 496 mEglContext = null; 497 } 498 }*/ 499 500 private boolean createSurface() { 501 if (mSurfaceSession == null) { 502 mSurfaceSession = new SurfaceSession(); 503 } 504 505 SurfaceControl.openTransaction(); 506 try { 507 if (mSurfaceControl == null) { 508 try { 509 int flags; 510 if (mMode == MODE_FADE) { 511 flags = SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN; 512 } else { 513 flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN; 514 } 515 mSurfaceControl = new SurfaceControl(mSurfaceSession, 516 "ElectronBeam", mDisplayWidth, mDisplayHeight, 517 PixelFormat.OPAQUE, flags); 518 } catch (SurfaceControl.OutOfResourcesException ex) { 519 Slog.e(TAG, "Unable to create surface.", ex); 520 return false; 521 } 522 } 523 524 mSurfaceControl.setLayerStack(mDisplayLayerStack); 525 mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight); 526 mSurface = new Surface(); 527 mSurface.copyFrom(mSurfaceControl); 528 529 mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManager, mSurfaceControl); 530 mSurfaceLayout.onDisplayTransaction(); 531 } finally { 532 SurfaceControl.closeTransaction(); 533 } 534 return true; 535 } 536 537 private boolean createEglSurface() { 538 if (mEglSurface == null) { 539 int[] eglSurfaceAttribList = new int[] { 540 EGL14.EGL_NONE 541 }; 542 // turn our SurfaceControl into a Surface 543 mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, 544 eglSurfaceAttribList, 0); 545 if (mEglSurface == null) { 546 logEglError("eglCreateWindowSurface"); 547 return false; 548 } 549 } 550 return true; 551 } 552 553 private void destroyEglSurface() { 554 if (mEglSurface != null) { 555 if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) { 556 logEglError("eglDestroySurface"); 557 } 558 mEglSurface = null; 559 } 560 } 561 562 private void destroySurface() { 563 if (mSurfaceControl != null) { 564 mSurfaceLayout.dispose(); 565 mSurfaceLayout = null; 566 SurfaceControl.openTransaction(); 567 try { 568 mSurfaceControl.destroy(); 569 mSurface.release(); 570 } finally { 571 SurfaceControl.closeTransaction(); 572 } 573 mSurfaceControl = null; 574 mSurfaceVisible = false; 575 mSurfaceAlpha = 0f; 576 } 577 } 578 579 private boolean showSurface(float alpha) { 580 if (!mSurfaceVisible || mSurfaceAlpha != alpha) { 581 SurfaceControl.openTransaction(); 582 try { 583 mSurfaceControl.setLayer(ELECTRON_BEAM_LAYER); 584 mSurfaceControl.setAlpha(alpha); 585 mSurfaceControl.show(); 586 } finally { 587 SurfaceControl.closeTransaction(); 588 } 589 mSurfaceVisible = true; 590 mSurfaceAlpha = alpha; 591 } 592 return true; 593 } 594 595 private boolean attachEglContext() { 596 if (mEglSurface == null) { 597 return false; 598 } 599 if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 600 logEglError("eglMakeCurrent"); 601 return false; 602 } 603 return true; 604 } 605 606 private void detachEglContext() { 607 if (mEglDisplay != null) { 608 EGL14.eglMakeCurrent(mEglDisplay, 609 EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); 610 } 611 } 612 613 /** 614 * Interpolates a value in the range 0 .. 1 along a sigmoid curve 615 * yielding a result in the range 0 .. 1 scaled such that: 616 * scurve(0) == 0, scurve(0.5) == 0.5, scurve(1) == 1. 617 */ 618 private static float scurve(float value, float s) { 619 // A basic sigmoid has the form y = 1.0f / FloatMap.exp(-x * s). 620 // Here we take the input datum and shift it by 0.5 so that the 621 // domain spans the range -0.5 .. 0.5 instead of 0 .. 1. 622 final float x = value - 0.5f; 623 624 // Next apply the sigmoid function to the scaled value 625 // which produces a value in the range 0 .. 1 so we subtract 626 // 0.5 to get a value in the range -0.5 .. 0.5 instead. 627 final float y = sigmoid(x, s) - 0.5f; 628 629 // To obtain the desired boundary conditions we need to scale 630 // the result so that it fills a range of -1 .. 1. 631 final float v = sigmoid(0.5f, s) - 0.5f; 632 633 // And finally remap the value back to a range of 0 .. 1. 634 return y / v * 0.5f + 0.5f; 635 } 636 637 private static float sigmoid(float x, float s) { 638 return 1.0f / (1.0f + FloatMath.exp(-x * s)); 639 } 640 641 private static FloatBuffer createNativeFloatBuffer(int size) { 642 ByteBuffer bb = ByteBuffer.allocateDirect(size * 4); 643 bb.order(ByteOrder.nativeOrder()); 644 return bb.asFloatBuffer(); 645 } 646 647 private static void logEglError(String func) { 648 Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable()); 649 } 650 651 private static boolean checkGlErrors(String func) { 652 return checkGlErrors(func, true); 653 } 654 655 private static boolean checkGlErrors(String func, boolean log) { 656 boolean hadError = false; 657 int error; 658 while ((error = GLES10.glGetError()) != GLES10.GL_NO_ERROR) { 659 if (log) { 660 Slog.e(TAG, func + " failed: error " + error, new Throwable()); 661 } 662 hadError = true; 663 } 664 return hadError; 665 } 666 667 public void dump(PrintWriter pw) { 668 pw.println(); 669 pw.println("Electron Beam State:"); 670 pw.println(" mPrepared=" + mPrepared); 671 pw.println(" mMode=" + mMode); 672 pw.println(" mDisplayLayerStack=" + mDisplayLayerStack); 673 pw.println(" mDisplayWidth=" + mDisplayWidth); 674 pw.println(" mDisplayHeight=" + mDisplayHeight); 675 pw.println(" mSurfaceVisible=" + mSurfaceVisible); 676 pw.println(" mSurfaceAlpha=" + mSurfaceAlpha); 677 } 678 679 /** 680 * Keeps a surface aligned with the natural orientation of the device. 681 * Updates the position and transformation of the matrix whenever the display 682 * is rotated. This is a little tricky because the display transaction 683 * callback can be invoked on any thread, not necessarily the thread that 684 * owns the electron beam. 685 */ 686 private static final class NaturalSurfaceLayout implements DisplayTransactionListener { 687 private final DisplayManagerService mDisplayManager; 688 private SurfaceControl mSurfaceControl; 689 690 public NaturalSurfaceLayout(DisplayManagerService displayManager, SurfaceControl surfaceControl) { 691 mDisplayManager = displayManager; 692 mSurfaceControl = surfaceControl; 693 mDisplayManager.registerDisplayTransactionListener(this); 694 } 695 696 public void dispose() { 697 synchronized (this) { 698 mSurfaceControl = null; 699 } 700 mDisplayManager.unregisterDisplayTransactionListener(this); 701 } 702 703 @Override 704 public void onDisplayTransaction() { 705 synchronized (this) { 706 if (mSurfaceControl == null) { 707 return; 708 } 709 710 DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY); 711 switch (displayInfo.rotation) { 712 case Surface.ROTATION_0: 713 mSurfaceControl.setPosition(0, 0); 714 mSurfaceControl.setMatrix(1, 0, 0, 1); 715 break; 716 case Surface.ROTATION_90: 717 mSurfaceControl.setPosition(0, displayInfo.logicalHeight); 718 mSurfaceControl.setMatrix(0, -1, 1, 0); 719 break; 720 case Surface.ROTATION_180: 721 mSurfaceControl.setPosition(displayInfo.logicalWidth, displayInfo.logicalHeight); 722 mSurfaceControl.setMatrix(-1, 0, 0, -1); 723 break; 724 case Surface.ROTATION_270: 725 mSurfaceControl.setPosition(displayInfo.logicalWidth, 0); 726 mSurfaceControl.setMatrix(0, 1, -1, 0); 727 break; 728 } 729 } 730 } 731 } 732 } 733