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