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