Home | History | Annotate | Download | only in power
      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